树结构CURD

50 阅读1分钟
<template>
  <div id="add-dept-post-dialog">
    <el-button
      class="addBtn"
      type="primary"
      size="small"
      @click="openAddTop"
    >添加顶级节点</el-button>
    <el-input
      placeholder="输入关键字进行过滤"
      v-model="filterText"
    >
    </el-input>
    <el-tree
      ref="SlotTree"
      :data="setTree"
      :props="defaultProps"
      :expand-on-click-node="false"
      highlight-current
      :node-key="NODE_KEY"
    >
      <div
        class="comp-tr-node"
        slot-scope="{ node, data }"
      >
        <!-- 编辑状态 -->
        <template v-if="node.isEdit">
          <el-input
            v-model="data.label"
            autofocus
            size="mini"
            :ref="'slotTreeInput' + data[NODE_KEY]"
            @blur.stop="handleInput(node, data)"
            @keyup.enter.native="handleInput(node, data)"
          ></el-input>
        </template>
        <!-- 非编辑状态 -->
        <template v-else>
          <!-- 名称: 新增节点增加class(is-new) -->
          <span :class="[
            data[NODE_KEY] < NODE_ID_START ? 'is-new' : '',
            'comp-tr-node--name',
          ]">
            {{ node.label }}
          </span>

          <!-- 按钮 -->
          <span class="comp-tr-node--btns">
            <!-- 新增 -->
            <el-button
              type="text"
              size="mini"
              @click="appendChild(node, data)"
            >新增</el-button>

            <!-- 编辑 -->
            <el-button
              size="mini"
              type="text"
              @click="handleEdit(node, data)"
            >编辑</el-button>

            <!-- 删除 -->
            <el-button
              size="mini"
              type="text"
              @click="handleDelete(node, data)"
            >删除</el-button>
          </span>
        </template>
      </div>
    </el-tree>
    <el-dialog
      :close-on-click-modal="false"
      :append-to-body="true"
      :visible.sync="addDialogVisible"
      width="30%"
      top="5vh"
      :show-close="true"
      :before-close="addHandleClose"
      :title="addDialogTitle == 'edit' ? '编辑名称' : '新增名称'"
    >
      <el-form
        :model="addForm"
        :rules="addRules"
        label-width="80px"
        ref="addRef"
      >
        <el-form-item
          label="名称"
          prop="name"
        >
          <el-input
            size="medium"
            v-model="addForm.name"
            placeholder="名称"
          />
        </el-form-item>
      </el-form>
      <span class="dialog-footer">
        <el-button
          size="small"
          @click="addHandleClose"
        >取 消</el-button>
        <el-button
          size="small"
          type="primary"
          @click="addData"
        >确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
export default {
  data() {
    return {
      filterText: '',
      addType: 1,
      addNode: '',
      startId: null,
      setTree: [{
        id: 1,
        label: '一级 1',
        children: [{
          id: 4,
          label: '二级 1-1',
          children: [{
            id: 9,
            label: '三级 1-1-1'
          }, {
            id: 10,
            label: '三级 1-1-2'
          }]
        }]
      }, {
        id: 2,
        label: '一级 2',
        children: [{
          id: 5,
          label: '二级 2-1'
        }, {
          id: 6,
          label: '二级 2-2'
        }]
      }, {
        id: 3,
        label: '一级 3',
        children: [{
          id: 7,
          label: '二级 3-1'
        }, {
          id: 8,
          label: '二级 3-2'
        }]
      }], // tree数据
      NODE_KEY: "id", // id对应字段
      MAX_LEVEL: 3, // 设定最大层级
      NODE_ID_START: 0, // 新增节点id,逐次递减
      defaultProps: {
        // 默认设置
        children: "children",
        label: "label",
      },
      addDataList: "",
      addForm: {
        name: "",
      },
      addRules: {
        name: [{ required: true, message: "请输入名称", trigger: "blur" }],
      },
      addDialogTitle: "new",
      addDialogVisible: false,
      // 之前遗忘了这个参数 重新补发
      initParam: {
        // 新增参数
        name: "",
        id: 0,
        children: [],
      },
    }
  },
  watch: {
    watch: {
      filterText(val) {
        this.$refs.tree.filter(val);
      }
    },
  },
  created() {
    // 初始值
    this.startId = this.NODE_ID_START;
  },
  methods: {
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    handleDelete(_node, _data) {
      // 删除节点
      console.log(_node, _data);
      // 判断是否存在子节点
      if (_data.children && _data.children.length !== 0) {
        this.$message.error("此节点有子级,不可删除!");
        return false;
      } else {
        // 删除操作
        let DeletOprate = () => {
          this.$nextTick(() => {
            if (this.$refs.SlotTree) {
              this.$refs.SlotTree.remove(_data);
              this.$message.success("删除成功!");
            }
          });
        };
        // 二次确认
        let ConfirmFun = () => {
          this.$confirm("是否删除此节点?", "提示", {
            confirmButtonText: "确认",
            cancelButtonText: "取消",
            type: "warning",
          })
            .then(() => {
              DeletOprate();
            })
            .catch(() => { });
        };
        // 判断是否新增: 新增节点直接删除,已存在的节点要二次确认
        _data[this.NODE_KEY] < this.NODE_ID_START
          ? DeletOprate()
          : ConfirmFun();
      }
    },
    handleInput(_node, _data) {
      // 修改节点
      console.log(_node, _data);
      // 退出编辑状态
      if (_node.isEdit) {
        this.$set(_node, "isEdit", false);
      }
    },
    handleEdit(_node, _data) {
      // 编辑节点
      console.log(_node, _data);
      // 设置编辑状态
      if (!_node.isEdit) {
        this.$set(_node, "isEdit", true);
      }
      // 输入框聚焦
      this.$nextTick(() => {
        if (this.$refs["slotTreeInput" + _data[this.NODE_KEY]]) {
          this.$refs["slotTreeInput" + _data[this.NODE_KEY]].$refs.input.focus();
        }
      });
    },
    // 新增子级节点打开事件
    appendChild(node, data) {
      this.addForm.name = "";
      this.addDialogVisible = true;
      this.addDialogTitle = "new";
      this.addDataList = data;
      this.addNode = node
      this.addType = 2;
    },
    // 新增子级节点
    handleAdd(_node, _data, _name) {
      // 新增节点
      console.log(_node, _data);
      // 判断层级
      if (_node.level >= this.MAX_LEVEL) {
        this.$message.warning("当前已达到" + this.MAX_LEVEL + "级,无法新增!");
        return false;
      }
      // 参数修改
      let obj = JSON.parse(JSON.stringify(this.initParam)); // copy参数
      obj.id = _data[this.NODE_KEY]; // 父id
      obj[this.NODE_KEY] = ++this.startId; // 节点id:逐次递减id
      obj.label = _name
      // 判断字段是否存在
      if (!_data.children) {
        this.$set(_data, "children", []);
      }
      // 新增数据
      _data.children.push(obj);
      // 展开节点
      if (!_node.expanded) {
        _node.expanded = true;
      }
    },
    // 新增顶级结点打开事件
    handleAddTop() {
      // 添加顶部节点
      let obj = JSON.parse(JSON.stringify(this.initParam)); // copy参数
      console.log(obj);
      obj[this.NODE_KEY] = ++this.startId; // 节点id:逐次递减id
      obj.label = this.addForm.name;
      console.log(obj.label)
      this.setTree.push(obj);
    },
    // 新增顶级结点
    openAddTop() {
      this.addForm.name = "";
      this.addDialogVisible = true;
      this.addDialogTitle = "new";
      this.addType = 1;
    },
    // 点击确定 新增子级菜单
    addData() {
      var t = this;
      this.$refs.addRef.validate(async (valid) => {
        if (valid) {
          if (t.addType == 1) {
            t.handleAddTop();
            this.addDialogVisible = false;
          } else if (t.addType == 2) {
            const obj = JSON.parse(JSON.stringify(t.addForm));
            // 需要判断新增还是编辑
            t.handleAdd(t.addNode, t.addDataList, obj.name)
            this.addDialogVisible = false;
          }
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    addHandleClose() {
      this.addDialogVisible = false;
      this.$refs.addRef.resetFields();
    },
  }

}
</script>

<style lang="scss" scoped>
</style>