HtMenuTree.vue 5.47 KB
<template>
  <el-scrollbar style="height:100%">
    <ht-tree
      :data="data"
      :props="defaultProps"
      :support-filter="supportFilter"
      :highlight-current="highlightCurrent"
      :default-expand-all="defaultExpandAll"
      :default-expanded-keys="defaultExpandedKeys"
      :default-checked-keys="defaultCheckedKeys"
      :defaultIsOpenKeys="defaultIsOpenKeys"
      :node-key="nodeKey"
      :show-checkbox="showCheckbox"
      :render-content="renderContent"
      :expand-on-click-node="false"
      @node-click="handleNodeClick"
      @node-expand="handleNodeExpand"
      @refresh="loadData"
      @node-drop="handleDrop"
      :filter-node-method="filterNodeMethod"
      :allow-drop="allowDrop"
      draggable
      ref="htMenuTree"
      @node-collapse="nodeCollapse"
      :check-strictly="false"
    >
      <!-- 作用域插槽:插槽prop -->
      <slot slot-scope="{node, data}" :node="node" :data="data"></slot>
    </ht-tree>
  </el-scrollbar>
</template>

<script>
import req from '@/request.js'
export default {
  name: 'ht-menu-tree',
  props: {
    supportFilter: {
      type: Boolean,
      default: false
    },
    highlightCurrent: {
      type: Boolean,
      default: false
    },
    defaultExpandAll: {
      type: Boolean,
      default: false
    },
    showCheckbox: {
      type: Boolean,
      default: false
    },
    renderContent: {
      type: Function
    },
    defaultCheckedKeys: {
      type: Array
    },
    defaultIsOpenKeys: {
      type: Array
    },
    nodeKey: {
      type: String,
      default: 'alias'
    },
    data: {
      type: Array,
      default: () => {
        return []
      }
    },
    defaultExpandedKeys: {
      type: Array,
      default: () => {
        return ['-1', '1', '3']
      }
    }
  },
  data() {
    return {
      treeData: [],
      defaultProps: {
        children: 'children',
        label: 'name',
        isOpen: 'isOpen',
        disabled: 'disabled',
        expanded: 'expanded'
      }
    }
  },
  methods: {
    allowDrop(draggingNode, dropNode, type) {
      let draggingRoot = this.getParent(draggingNode)
      let dropRoot = this.getParent(dropNode)
      //前端菜单只能拖到前端,后端拖到后端
      if (draggingRoot.id != dropRoot.id) {
        return false
      }
      if (
        draggingNode.level >= 3 &&
        draggingNode.level == dropNode.level &&
        // draggingNode.data.parentId != dropNode.data.parentId &&
        draggingNode.parent.id == dropNode.parent.id &&
        type != 'inner' &&
        !draggingNode.data.href &&
        !dropNode.data.href
      ) {
        return true
      } else {
        return false
      }
    },
    getParent(data) {
      let res = true
      let _menus = data
      while (res) {
        if (
          _menus.parent &&
          _menus.data.alias != 'manage_menu' &&
          _menus.data.alias != 'front_menu'
        ) {
          _menus = _menus.parent
        } else {
          _menus = _menus.data
          res = false
        }
      }
      return _menus
    },
    handleDrop(draggingNode, dropNode, dropType, ev) {
      //执行拖拽保存的方法
      let data = _.cloneDeep(draggingNode.data)
      delete data.isOpen //剔除多余入参
      let target = dropNode.data
      data.parentId = dropNode.parent.data.id
      if ('after' == dropType) {
        data.sn = target.sn + 1
      } else if ('before' == dropType) {
        data.sn = target.sn - 1
      }
      req.post('${portal}/sys/sysMenu/v1/save', data).then(response => {
        this.$message({
          showClose: true,
          message: '保存成功,重新登录之后生效',
          type: 'success'
        })
      })
    },
    handleNodeClick(data, node) {
      this.nodeClick(data, node)
      this.$emit('node-click', data, node)
    },
    //记录展开的节点,刷新时树不会收缩
    handleNodeExpand(node) {
      if (!this.defaultExpandedKeys.includes(node[this.nodeKey])) {
        this.defaultExpandedKeys.push(node[this.nodeKey])
      }
    },
    loadData(cb) {
      this.$emit('load', cb)
    },
    nodeCollapse(data) {
      this.defaultExpandedKeys.splice(
        this.defaultExpandedKeys.indexOf(data[this.nodeKey]),
        1
      )
    },
    filterNodeMethod(value, data, node) {
      console.log(value, data, node)
      const {name, alias} = data
      return name.includes(value) || alias.includes(value)
    },
    nodeClick(data, node) {
      //这个方法是勾选父级子级也默认勾选 取消子级不影响父级
      this.childNodesChange(node)
      // 这个方法是勾选子级默认把父级也勾选上
      this.parentNodesChange(node)
    },
    childNodesChange(node) {
      let len = node.childNodes.length
      if (len > 0) {
        for (let i = 0; i < len; i++) {
          if (!node.checked) {
            node.childNodes[i].checked = false
          } else {
            node.childNodes[i].checked = true
          }
          this.childNodesChange(node.childNodes[i])
        }
      }
    },
    parentNodesChange(node) {
      if (node.parent) {
        for (let key in node) {
          if (key == 'parent') {
            node[key].checked = true
            this.parentNodesChange(node[key])
          }
        }
      }
    }
  },
  mounted() {
    this.loadData()
  }
}
</script>
<style lang="scss" scoped>
/deep/ .el-tree .el-tree__empty-block {
  margin: 20px 20px;
  width: calc(100% - 40px);
}

/deep/ .el-tree {
  width: 100%;
}

/deep/ .el-scrollbar__wrap {
  overflow-x: hidden;
  margin-bottom: 0 !important;
}
</style>