123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- <template>
- <div>
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button type="primary" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">展开/折叠</el-button>
- </el-col>
- </el-row>
- <el-input v-model="filterText" placeholder="输入关键字过滤" />
- <el-tree v-if="refreshTable" ref="tree" :data="treeData" :props="defaultProps" node-key="fieldId"
- :default-expanded-keys="[0,100]" @node-click="handleNodeClick" :highlight-current="true"
- :filter-node-method="filterNode" :default-expand-all="isExpandAll" :expand-on-click-node="false">
- <!-- 自定义节点样式 -->
- <span class="custom-tree-node" slot-scope="{ node, data }">
- <span>{{ node.label }}</span>
- <span v-if="isModify">
- <el-button v-hasPermi="['oa:resource:edit']" type="text" icon="el-icon-plus" size="mini"
- @click="() => append(data)">
- 新增
- </el-button>
- <el-button v-hasPermi="['oa:resource:remove']" type="text" icon="el-icon-delete" size="mini"
- @click="() => remove(node, data)">
- 删除
- </el-button>
- </span>
- </span>
- </el-tree>
- <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
- <el-form ref="formRef" :model="form" :rules="rules">
- <el-form-item label="父级专业" prop="parentId">
- <treeselect v-model="form.parentId" :options="treeData" :normalizer="normalizer" :show-count="true"
- placeholder="选择上级专业" />
- </el-form-item>
- <el-form-item label="专业名称" prop="field">
- <el-input v-model="form.field" placeholder="请输入专业名称" />
- </el-form-item>
- </el-form>
- <div slot="footer" class="dialog-footer">
- <el-button @click="open = false">取 消</el-button>
- <el-button type="primary" @click="submitForm">确 定</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
-
- <script>
- import { listResource, getResource, delResource, addResource, updateResource } from "@/api/oa/study/resource";
- import Treeselect from "@riophae/vue-treeselect";
- import "@riophae/vue-treeselect/dist/vue-treeselect.css";
- export default {
- components: { Treeselect },
- props: {
- isModify: {
- type: Boolean,
- default: false
- },
- fields: {
- type: Array,
- default: []
- }
- },
- data() {
- return {
- treeData: [], // 树形结构数据
- defaultProps: { // 树形组件配置
- children: 'children',
- label: 'field'
- },
- filterText: '',
- isExpandAll: false,
- refreshTable: true,
- title: '',
- open: false,
- form: {
- fieldId: undefined,
- field: "",
- parentId: undefined,
- },
- rules: {
- field: [
- { required: true, message: "专业名称不能为空", trigger: "blur" }
- ],
- parentId: [
- { required: true, message: "父级专业不能为空", trigger: "change" }
- ]
- },
- // 菜单树选项
- menuOptions: [],
- }
- },
- watch: {
- filterText(val) {
- this.$refs.tree.filter(val);
- },
- // 监听父组件传入的 fields
- fields: {
- immediate: true,
- handler(newVal) {
- this.initTree(newVal || []);
- }
- }
- },
- methods: {
- async initTree(fields) {
- // 空数据保护
- if (!fields || fields.length === 0) {
- this.treeData = [{
- fieldId: 0,
- field: undefined,
- children: []
- }];
- this.$emit('getTreeData', []);
- return;
- }
-
- const built = this.buildTree(fields);
- // 根节点按首项规则决定标题和 id
- if (fields[0].fieldId === 0) {
- this.treeData = [{
- fieldId: 0,
- field: '全部专业',
- children: built
- }];
- } else {
- this.treeData = [{
- fieldId: 100,
- field: '全部学习',
- children: built
- }];
- }
- this.$emit('getTreeData', built);
- },
- buildTree(items) {
- const map = {}; // 哈希表存储所有节点
- const roots = []; // 存储根节点
- // 先遍历所有项,存入哈希表
- items.forEach(item => {
- map[item.fieldId] = { ...item, children: [] };
- });
- // 再次遍历建立父子关系
- items.forEach(item => {
- const node = map[item.fieldId];
- if (item.parentId === 0 || item.parentId === 100) {
- roots.push(node);
- }
- else {
- const parent = map[item.parentId];
- if (parent) {
- parent.children.push(node);
- }
- }
- });
- return roots;
- },
- filterNode(value, data) {
- if (!value) return true;
- return data.field.indexOf(value) !== -1;
- },
- async loadNode(node, resolve) {
- if (node.level === 0) {
- // 加载根节点
- return resolve(await this.fetchRootNodes());
- }
- // 加载子节点
- resolve(await this.fetchChildNodes(node.key));
- },
- handleNodeClick(data) {
- this.$emit('clickNode', data)
- },
- append(data) {
- this.resetForm();
- this.title = "新增专业";
- this.open = true;
- this.form.parentId = data.fieldId; // 设置父节点为当前节点
- },
- async remove(node, data) {
- if (!data.children) {
- data.children = []
- }
- let list = await listResource({ fieldId: data.fieldId });
- this.$confirm('确定删除该专业吗?', "警告", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning"
- }).then(() => {
- if (data.children.length > 0) {
- this.$message.error("删除失败,存在子专业,无法删除!");
- return
- }
- if (list.total > 0) {
- this.$message.error("删除失败,存在资料数据,无法删除!");
- return
- }
- delField(data.fieldId).then(() => {
- this.$message.success("删除成功");
- this.initTree();
- // 如果删除的是当前选中节点,清空选择
- if (this.$refs.tree.getCurrentKey() === data.fieldId) {
- this.$emit("clickNode", {});
- }
- });
- });
- },
- /** 展开/折叠操作 */
- toggleExpandAll() {
- this.refreshTable = false;
- this.isExpandAll = !this.isExpandAll;
- this.$nextTick(() => {
- this.refreshTable = true;
- });
- },
- // 表单提交
- submitForm() {
- this.$refs.formRef.validate(valid => {
- if (valid) {
- if (this.form.fieldId) {
- updateField(this.form).then(() => {
- this.$message.success("修改成功");
- this.open = false;
- this.initTree();
- });
- } else {
- addField(this.form).then(() => {
- this.$message.success("新增成功");
- this.open = false;
- this.initTree();
- });
- }
- }
- });
- },
- // 重置表单
- resetForm() {
- this.form = {
- fieldId: undefined,
- field: "",
- parentId: undefined
- };
- if (this.$refs.formRef) {
- this.$refs.formRef.resetFields();
- }
- },
-
- /** 转换菜单数据结构 */
- normalizer(node) {
- if (node.children && !node.children.length) {
- delete node.children;
- }
- return {
- id: node.fieldId,
- label: node.field,
- children: node.children
- };
- },
- },
- }
- </script>
-
- <style lang="scss" scoped>
- .tree-container {
- width: 300px;
- padding: 20px;
- }
-
- .custom-tree-node {
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: space-between;
- font-size: 14px;
- padding: 8px 0;
- }
- </style>
|