vue动态新增、修改、编辑树

弹窗组件

<template>
  <div id="dialogCatalog">
    <el-dialog
      title="产品目录管理"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
      :visible.sync="dialogVisible"
      width="500px"
      :before-close="handleClose">
      <div v-loading="isLoading" class="comp-tree">
        <!-- <el-button class="comp-tr-top"
            type="primary"
            size="small"
            @click="handleAddTop">添加顶级节点</el-button> -->
        <!-- tree -->
        <el-tree ref="SlotTree"
          :data="setTree"
          :props="defaultProps"
          default-expand-all
          :expand-on-click-node="false"
          highlight-current
          :node-key="NODE_KEY">
          <div class="comp-tr-node" slot-scope="{ node, data }">
            <!-- 编辑状态 -->
            <template v-if="data.isEdit">
              <el-input v-model="data.name"
                autofocus
                size="mini"
                maxlength='20'
                :class="isClassName"
                @input="handleInput(node, data)"
                minlength='2'
                :ref="'slotTreeInput'+data[NODE_KEY]"
                @blur.stop="nodeEditPass(node, data)"
                @keyup.enter.native="$event.target.blur()"></el-input>
            </template>

            <!-- 非编辑状态 -->
            <template v-else>
              <!-- 名称: 新增节点增加class(is-new-->
              <span class="comp-tr-node--name">
                  {{ node.label }}
              </span>

              <!-- 按钮 -->
              <span class="comp-tr-node--btns">
                <!-- 新增 -->
                <el-button icon="el-icon-plus"
                  v-if="!(node.level ==2 && node.data.name=='default') && node.level !==3"
                  size="mini"
                  @click="handleAdd(node, data)"></el-button>

                <!-- 编辑 -->
                <el-button icon="el-icon-edit"
                  v-if="node.level !==1 &&!(node.level ==2 && node.data.name=='default')"
                  size="mini"
                  @click="handleEdit(node, data)"></el-button>

                <!-- 删除 -->
                <el-button icon="el-icon-delete"
                  v-if="node.level !==1&&!(node.level ==2 && node.data.name=='default')"
                  size="mini"
                  @click="handleDelete(node, data)"></el-button>
              </span>
            </template>
          </div>
        </el-tree>
      </div>
      <div>注意:删除目录后,该目录下的所有产品将移入default目录</div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="handleClose()">关闭</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import * as launch from '@/api/admin/launch.js'

export default {
  name: 'DialogCatalog',
  props: {
    isDialogCatalog: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    isDialogCatalog: function () {
      if (!this.isDialogCatalog) { return }
      this.getCatalogTree()
      this.dialogVisible = this.isDialogCatalog
      this.startId = this.NODE_ID_START
    }
  },
  data () {
    return {
      dialogVisible: false,
      parallelTree: [],
      choiseTree: {},
      isLoading: false, // 是否加载
      setTree: [], // tree数据
      NODE_KEY: 'id', // id对应字段
      MAX_LEVEL: 3, // 设定最大层级
      NODE_ID_START: 100, // 新增节点id,逐次递减
      startId: null,
      defaultProps: { // 默认设置
        children: 'children',
        label: 'name'
      },
      initParam: { // 新增参数
        name: '目录',
        pid: 0,
        isEdit: true,
        children: []
      },
      isClassName: '',
      isUpdata: false
    }
  },
  methods: {
    getCatalogTree () {
      launch.getCatalogTree().then(res => {
        this.setTree = JSON.parse(JSON.stringify(res.data))
      })
    },
    handleNodeClick (d, n, s) { // 点击节点
      d.isEdit = false// 放弃编辑状态
    },
    handleClose () {
      this.dialogVisible = false
      this.$emit('data_close')
    },
    handleInput (_node, _data) {
      if (_data.name.trim().length < 2 || _data.name.trim().length > 20 || _node.parent.data.children.some(x => x.name === _data.name && x.id !== _data.id)) {
        this.isClassName = 'is_error'
      } else {
        this.isClassName = ''
      }
    },
    handleDelete (_node, _data) { // 删除节点
      console.log(_node, _data)
      // 二次确认
      const ConfirmFun = () => {
        this.$confirm('是否删除此节点?', '提示', {
          confirmButtonText: '确认',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          launch.delMenu(_data.id).then(res => {
            this.getCatalogTree()
          })
        }).catch(() => {})
      }
      // // 判断是否新增: 新增节点直接删除,已存在的节点要二次确认
      // _data[this.NODE_KEY] < this.NODE_ID_START ? DeletOprate() : ConfirmFun()
      ConfirmFun()
    },
    // 退出编辑状态
    nodeEditPass (_node, _data) { // 修改节点
      if (this.isClassName.length !== 0) { return }

      console.log(_data)

      if (this.isUpdata) {
        const obj = {
          label: _data.label,
          isEdit: false,
          pid: _data.pid,
          children: []
        }
        launch.updataMenu(obj).then(res => {
          this.isUpdata = false
          if (_data.isEdit) {
            this.$set(_data, 'isEdit', false)
          }
        })
      } else {
        const obj = {
          id: _data.id,
          label: _data.label,
          isEdit: false,
          pid: _data.pid,
          children: _data.children
        }
        launch.addMenu(obj).then(res => {
          if (_data.isEdit) {
            this.$set(_data, 'isEdit', false)
          }
        })
      }

      if (_data.isEdit) {
        this.$set(_data, 'isEdit', false)
      }
    },
    handleEdit (_node, _data) { // 编辑节点
      this.isUpdata = true

      if (!_data.isEdit) {
        this.$set(_data, 'isEdit', true)
      }

      _data.isEdit = true
      // 输入框聚焦
      this.$nextTick(() => {
        if (this.$refs['slotTreeInput' + _data[this.NODE_KEY]]) {
          this.$refs['slotTreeInput' + _data[this.NODE_KEY]].$refs.input.focus()
        }
      })
    },
    handleAdd (_node, _data) { // 新增节点
      this.isUpdata = false
      // 判断层级
      if (_node.level >= this.MAX_LEVEL) {
        this.$message.warning('当前已达到' + this.MAX_LEVEL + '级,无法新增!')
        return false
      }
      // 判断是否存在
      // if (this.handleIsTreeItem(_data.name)) { return false }
      // 参数修改

      const obj = JSON.parse(JSON.stringify(this.initParam))// copy参数
      obj.pid = _data[this.NODE_KEY]// 父id
      obj[this.NODE_KEY] = ++this.startId// 节点id:逐次递减id

      // 判断是否存在
      console.log(_data.children)
      for (let i = 1; i < 100; i++) {
        obj.name = '目录' + i
        if (!_data.children.some(x => x.name === obj.name)) {
          break
        }
      }

      // 判断字段是否存在
      if (!_data.children) {
        this.$set(_data, 'children', [])
      }

      // 展开节点
      if (!_node.expanded) {
        _node.expanded = true
      }
      // 新增数据
      _data.children.push(obj)
    }

    // handleAddTop () { // 添加顶部节点
    //   const obj = JSON.parse(JSON.stringify(this.initParam))// copy参数
    //   obj[this.NODE_KEY] = --this.startId// 节点id:逐次递减id
    //   this.setTree.push(obj)
    // }
  }
}
</script>

<style lang="less" scoped>

.comp-tree .comp-tr-node .comp-tr-node--btns {
  margin-left: 10px;
  opacity: 0;
  transition: opacity 0.1s;
}

/* common */
.show-btns,
.comp-tree .is-current > .el-tree-node__content .comp-tr-node--btns,
.comp-tree .el-tree-node__content:hover .comp-tr-node--btns {
  opacity: 1;
}

/* common end */
.comp-tree {
  width: auto;
  max-width: 700px;
  max-height: 80vh;
  padding: 0;
  overflow: auto;
}

.comp-tree .comp-tr-top {
  width: 100px;
  margin-bottom: 2em;
}

.comp-tree .comp-tr-node .is_error .el-input__inner {
  border: 1px solid #ff2020;
}

.comp-tree .comp-tr-node .comp-tr-node--name {
  display: inline-block;
  line-height: 40px;
  min-height: 40px;
}

.comp-tree .comp-tr-node .comp-tr-node--btns .el-button {
  transform: scale(0.8);
  border: 0;
  padding: 0 5px;
  background: none;
}

.comp-tree .comp-tr-node .comp-tr-node--btns .el-button + .el-button {
  margin-left: -1px;
}

</style>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值