src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
@@ -22,9 +22,13 @@
          <a-tree blockNode show-icon :expandedKeys.sync="expandedKeys"
                  :selectedKeys="selectedKeys" :treeData="treeDataSource" :autoExpandParent="autoExpandParent"
                  @select="handleTreeSelect" @expand="handleTreeExpand" @rightClick="handleTreeRightClick">
            <template slot="title" slot-scope="{ title, parentId, entity, key:treeKey,equipmentId,type}">
              <DeviceStructureTreeContextMenu ref="contextMenuRef"
                                              :treeParams="{title,treeKey,searchValue,equipmentId,entity,type,param:currentDeviceDocClassCode}"/>
            <template slot="title" slot-scope="{ title }">
              <span v-if="title.indexOf(searchValue) > -1">
                {{ title.substr(0, title.indexOf(searchValue)) }}
                <span class="replaceSearch">{{ searchValue }}</span>
                {{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
              </span>
              <span v-else>{{ title }}</span>
            </template>
            <a-icon slot="switcherIcon" type="down"/>
@@ -37,281 +41,309 @@
    <!--权限配置弹窗-->
    <AssignPermissionModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="getTreeDataByApi"/>
    <!--产品结构树基本右键菜单(空白处触发)-->
    <!--设备结构树树节点右键菜单(树节点触发)-->
    <device-structure-tree-context-menu ref="mainContextmenuRef" :treeParams="rightClickSelected"/>
    <!--设备结构树基本右键菜单(空白处触发)-->
    <DeviceStructureBaseContextMenu ref="baseContextmenuRef"/>
  </a-card>
</template>
<script>
import dncApi from '@/api/dnc'
import DeviceStructureTreeContextMenu from './DeviceStructureTreeContextMenu'
import AssignPermissionModal from './Permission/AssignPermissionModal'
import DeviceStructureBaseContextMenu
  from '@views/dnc/base/modules/DeviceStructure/DeviceStructureBaseContextMenu.vue'
  import dncApi from '@/api/dnc'
  import DeviceStructureTreeContextMenu from './DeviceStructureTreeContextMenu'
  import AssignPermissionModal from './Permission/AssignPermissionModal'
  import DeviceStructureBaseContextMenu
    from '@views/dnc/base/modules/DeviceStructure/DeviceStructureBaseContextMenu.vue'
export default {
  name: 'DeviceStructureTree',
  components: {
    DeviceStructureBaseContextMenu,
    AssignPermissionModal,
    DeviceStructureTreeContextMenu
  },
  data() {
    return {
      searchInput: '',
      cardLoading: false,
      loading: false,
      treeDataSource: [],
      selectedKeys: [],
      expandedKeys: [],
      beforeSearchExpandedKeys: [],
      searchValue: '',
      dataList: [],
      autoExpandParent: true,
      checkStrictly: true,
      allTreeKeys: [],
      currentSelected: {},
      rightClickSelected: {},
      currentDeviceDocClassCode: 'SEND',
      url: {
        delete: '/nc/product/delete'
      }
    }
  },
  created() {
    this.getTreeDataByApi()
    this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    this.$bus.$on('handleSwitchDeviceDocClassCode', this.setCurrentDeviceDocClassCode)
  },
  beforeDestroy() {
    this.$bus.$off('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    this.$bus.$off('handleSwitchDeviceDocClassCode', this.setCurrentDeviceDocClassCode)
  },
  methods: {
    // 调用接口获取树的数据
    getTreeDataByApi() {
      this.loading = true
      this.cardLoading = true
      this.treeDataSource = []
      dncApi.getDeviceTreeDataApi()
        .then(res => {
          if (res.success) {
            this.dataList = []
            this.allTreeKeys = []
            this.treeDataSource = res.result
            this.generateList(this.treeDataSource)
            this.expandedKeys = this.beforeSearchExpandedKeys = this.allTreeKeys
            this.$bus.$emit('sendDeviceTreeNodeInfo', this.treeDataSource[0])
          } else {
            this.$message.warn(res.message)
          }
        })
        .finally(() => {
          this.loading = false
          this.cardLoading = false
        })
  export default {
    name: 'DeviceStructureTree',
    components: {
      DeviceStructureBaseContextMenu,
      AssignPermissionModal,
      DeviceStructureTreeContextMenu
    },
    /**
     * 通过右侧tab栏所在activeKey设置当前设备的NC文档类型
     * @param documentActiveTabKey 右侧tab栏的activeKey
     */
    setCurrentDeviceDocClassCode(documentActiveTabKey) {
      if (documentActiveTabKey === 1) this.currentDeviceDocClassCode = 'SEND'
      else this.currentDeviceDocClassCode = 'REC'
    },
    /**
     * 树节点选中时触发
     * @param selectedKeys 选中节点key
     * @param {node} node 节点对象
     */
    handleTreeSelect(selectedKeys, { node }) {
      let record = node.dataRef
      this.currentSelected = Object.assign({}, record)
      // 向右侧父级组件发送当前选中树节点信息
      this.$bus.$emit('sendDeviceTreeNodeInfo', this.currentSelected)
      if (selectedKeys.length === 0) return
      this.selectedKeys = selectedKeys
    },
    /**
     * 树节点右键单击节点时触发
     * @param event 事件对象
     * @param node 节点对象
     */
    handleTreeRightClick({ event, node }) {
      if (this.$refs.baseContextmenuRef) this.$refs.baseContextmenuRef.menuVisible = false
      const record = node.dataRef
      // 若右键时当前右侧展示层级为设备层级且当前右键树层级同为设备层级时则在触发右键菜单功能时同时触发左键选中功能
      if (this.currentSelected.type === 2 && record.type === 2) this.handleTreeSelect([record.key], { node })
      this.rightClickSelected = Object.assign({}, record)
    },
    /**
     * 树节点展开合并时触发
     * @param expandedKeys 展开项key
     */
    handleTreeExpand(expandedKeys) {
      this.expandedKeys = this.beforeSearchExpandedKeys = expandedKeys
      console.log('beforeSearchExpandedKeys', this.beforeSearchExpandedKeys)
      this.autoExpandParent = false
    },
    /* 输入查询内容变化时触发 */
    handleSearchInputChange() {
      let search = this.searchInput
      let expandedKeys
      let autoExpandParent
      if (search !== '') {
        expandedKeys = this.dataList
          .map(item => {
            if (item.title != null) {
              if (item.title.indexOf(search) > -1) {
                return this.getParentKey(item.key, this.treeDataSource)
              }
              return null
            }
          })
          .filter((item, i, self) => item && self.indexOf(item) === i)
        autoExpandParent = true
      } else {
        expandedKeys = this.beforeSearchExpandedKeys
        autoExpandParent = false
      }
      Object.assign(this, {
        expandedKeys,
        searchValue: search,
        autoExpandParent
      })
    },
    /**
     * 递归获得输入项的父级key
     * @param key 子项key
     * @param tree 子项
     */
    getParentKey(key, tree) {
      let parentKey
      for (let i = 0; i < tree.length; i++) {
        const node = tree[i]
        if (node.children) {
          if (node.children.some(item => item.key === key)) {
            parentKey = node.key
          } else if (
            this.getParentKey(key, node.children)) {
            parentKey = this.getParentKey(key, node.children)
          }
    data() {
      return {
        searchInput: '',
        cardLoading: false,
        loading: false,
        treeDataSource: [],
        selectedKeys: [],
        expandedKeys: [],
        beforeSearchExpandedKeys: [],
        searchValue: '',
        dataList: [],
        autoExpandParent: true,
        checkStrictly: true,
        allTreeKeys: [],
        currentSelected: {},
        rightClickSelected: {},
        currentDeviceDocClassCode: 'SEND',
        url: {
          delete: '/nc/product/delete'
        }
      }
      return parentKey
    },
    /**
     * 递归获得所有树节点key
     * @param data
     */
    generateList(data) {
      for (let i = 0; i < data.length; i++) {
        const node = data[i]
        const key = node.key
        const title = node.title
        this.dataList.push({ key, title })
        this.allTreeKeys.push(key)
        this.setTreeNodeIcon(node)
        if (node.children) this.generateList(node.children)
      }
    },
    /**
     * 树所在父元素的右键事件
     * @param event 事件对象
     */
    openBaseContextMenu(event) {
      event.preventDefault()
      if (event.target.id !== 'tree-container') return
      this.$refs.baseContextmenuRef.menuStyle.top = event.clientY + 'px'
      this.$refs.baseContextmenuRef.menuStyle.left = event.clientX + 'px'
      this.$refs.baseContextmenuRef.menuVisible = true
      document.body.addEventListener('click', this.handleBaseContextMenuClose)
    },
    /**
     * 设置树节点图标
     * @param treeNode
     */
    setTreeNodeIcon(treeNode) {
      if (+treeNode.type === 1) {
        treeNode.slots = { icon: 'workshop' }
      } else {
        treeNode.slots = { icon: 'device' }
      }
    },
    // 控制基础右键菜单关闭
    handleBaseContextMenuClose() {
      this.$refs.baseContextmenuRef.menuVisible = false
      document.body.removeEventListener('click', this.handleBaseContextMenuClose)
    },
    // 刷新重新获取树的数据
    handleTreeReload() {
    created() {
      this.getTreeDataByApi()
      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
      this.$bus.$on('handleSwitchDeviceDocClassCode', this.setCurrentDeviceDocClassCode)
    },
    beforeDestroy() {
      this.$bus.$off('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
      this.$bus.$off('handleSwitchDeviceDocClassCode', this.setCurrentDeviceDocClassCode)
    },
    methods: {
      // 调用接口获取树的数据
      getTreeDataByApi() {
        this.loading = true
        this.cardLoading = true
        this.treeDataSource = []
        dncApi.getDeviceTreeDataApi()
          .then(res => {
            if (res.success) {
              this.dataList = []
              this.allTreeKeys = []
              this.treeDataSource = res.result
              this.generateList(this.treeDataSource)
              this.expandedKeys = this.beforeSearchExpandedKeys = this.allTreeKeys
              this.$bus.$emit('sendDeviceTreeNodeInfo', this.treeDataSource[0])
            } else {
              this.$message.warn(res.message)
            }
          })
          .finally(() => {
            this.loading = false
            this.cardLoading = false
          })
      },
    triggerCorrespondingMethod({ methodName }) {
      if (this[methodName]) this[methodName]()
      /**
       * 通过右侧tab栏所在activeKey设置当前设备的NC文档类型
       * @param documentActiveTabKey 右侧tab栏的activeKey
       */
      setCurrentDeviceDocClassCode(documentActiveTabKey) {
        if (documentActiveTabKey === 1) this.currentDeviceDocClassCode = 'SEND'
        else this.currentDeviceDocClassCode = 'REC'
      },
      /**
       * 树节点选中时触发
       * @param selectedKeys 选中节点key
       * @param {node} node 节点对象
       */
      handleTreeSelect(selectedKeys, { node }) {
        let record = node.dataRef
        this.currentSelected = Object.assign({}, record)
        // 向右侧父级组件发送当前选中树节点信息
        this.$bus.$emit('sendDeviceTreeNodeInfo', this.currentSelected)
        if (selectedKeys.length === 0) return
        this.selectedKeys = selectedKeys
      },
      /**
       * 树节点右键单击节点时触发
       * @param event 事件对象
       * @param node 节点对象
       */
      handleTreeRightClick({ event, node }) {
        if (this.$refs.baseContextmenuRef) this.$refs.baseContextmenuRef.menuVisible = false
        const record = node.dataRef
        // 若右键时当前右侧展示层级为设备层级且当前右键树层级同为设备层级时则在触发右键菜单功能时同时触发左键选中功能
        if (this.currentSelected.type === 2 && record.type === 2) this.handleTreeSelect([record.key], { node })
        this.rightClickSelected = Object.assign({ param: this.currentDeviceDocClassCode }, record)
        this.openMainContextMenu(event)
      },
      /**
       * 树节点展开合并时触发
       * @param expandedKeys 展开项key
       */
      handleTreeExpand(expandedKeys) {
        this.expandedKeys = this.beforeSearchExpandedKeys = expandedKeys
        this.autoExpandParent = false
      },
      /* 输入查询内容变化时触发 */
      handleSearchInputChange() {
        let search = this.searchInput
        let expandedKeys
        let autoExpandParent
        if (search !== '') {
          expandedKeys = this.dataList
            .map(item => {
              if (item.title != null) {
                if (item.title.indexOf(search) > -1) {
                  return this.getParentKey(item.key, this.treeDataSource)
                }
                return null
              }
            })
            .filter((item, i, self) => item && self.indexOf(item) === i)
          autoExpandParent = true
        } else {
          expandedKeys = this.beforeSearchExpandedKeys
          autoExpandParent = false
        }
        Object.assign(this, {
          expandedKeys,
          searchValue: search,
          autoExpandParent
        })
      },
      /**
       * 递归获得输入项的父级key
       * @param key 子项key
       * @param tree 子项
       */
      getParentKey(key, tree) {
        let parentKey
        for (let i = 0; i < tree.length; i++) {
          const node = tree[i]
          if (node.children) {
            if (node.children.some(item => item.key === key)) {
              parentKey = node.key
            } else if (
              this.getParentKey(key, node.children)) {
              parentKey = this.getParentKey(key, node.children)
            }
          }
        }
        return parentKey
      },
      /**
       * 递归获得所有树节点key
       * @param data
       */
      generateList(data) {
        for (let i = 0; i < data.length; i++) {
          const node = data[i]
          const key = node.key
          const title = node.title
          this.dataList.push({ key, title })
          this.allTreeKeys.push(key)
          this.setTreeNodeIcon(node)
          if (node.children) this.generateList(node.children)
        }
      },
      /**
       * 打开树节点菜单事件
       * @param event 树节点事件对象
       */
      openMainContextMenu(event) {
        this.$refs.mainContextmenuRef.menuStyle.top = event.clientY + 'px'
        this.$refs.mainContextmenuRef.menuStyle.left = event.clientX + 'px'
        this.$refs.mainContextmenuRef.menuVisible = true
        document.body.addEventListener('click', this.handleMainContextMenuClose)
      },
      /**
       * 树所在父元素的右键事件
       * @param event 事件对象
       */
      openBaseContextMenu(event) {
        event.preventDefault()
        if (event.target.id !== 'tree-container') return
        if (this.$refs.mainContextmenuRef) this.$refs.mainContextmenuRef.menuVisible = false
        this.$refs.baseContextmenuRef.menuStyle.top = event.clientY + 'px'
        this.$refs.baseContextmenuRef.menuStyle.left = event.clientX + 'px'
        this.$refs.baseContextmenuRef.menuVisible = true
        document.body.addEventListener('click', this.handleBaseContextMenuClose)
      },
      /**
       * 设置树节点图标
       * @param treeNode
       */
      setTreeNodeIcon(treeNode) {
        if (+treeNode.type === 1) {
          treeNode.slots = { icon: 'workshop' }
        } else {
          treeNode.slots = { icon: 'device' }
        }
      },
      // 控制主要右键菜单关闭
      handleMainContextMenuClose() {
        if (this.$refs.mainContextmenuRef) this.$refs.mainContextmenuRef.menuVisible = false
        document.body.removeEventListener('click', this.handleMainContextMenuClose)
      },
      // 控制基础右键菜单关闭
      handleBaseContextMenuClose() {
        this.$refs.baseContextmenuRef.menuVisible = false
        document.body.removeEventListener('click', this.handleBaseContextMenuClose)
      },
      // 刷新重新获取树的数据
      handleTreeReload() {
        this.getTreeDataByApi()
      },
      triggerCorrespondingMethod({ methodName }) {
        if (this[methodName]) this[methodName]()
      }
    }
  }
}
</script>
<style lang="less" scoped>
/deep/ .ant-card-body {
  padding: 0 12px 0 0;
}
/deep/ .ant-card-body, /deep/ .ant-spin-nested-loading, /deep/ .ant-spin-container {
  height: 100%;
}
/deep/ .ant-tree-title, .ant-tree-title .ant-dropdown-trigger {
  display: inline-block;
  width: calc(100% - 24px) !important;
}
::-webkit-scrollbar {
  width: 8px;
}
@media screen and (min-width: 1920px) {
  .tree_con {
    height: 748px !important;
  /deep/ .ant-card-body {
    padding: 0 12px 0 0;
  }
}
@media screen and (min-width: 1680px) and (max-width: 1920px) {
  .tree_con {
    height: 748px !important;
  /deep/ .ant-card-body, /deep/ .ant-spin-nested-loading, /deep/ .ant-spin-container {
    height: 100%;
  }
}
@media screen and (min-width: 1400px) and (max-width: 1680px) {
  .tree_con {
    height: 600px !important;
  /deep/ .ant-tree-title, .ant-tree-title .ant-dropdown-trigger {
    display: inline-block;
    width: calc(100% - 24px) !important;
  }
}
@media screen and (min-width: 1280px) and (max-width: 1400px) {
  .tree_con {
    height: 501px !important;
  ::-webkit-scrollbar {
    width: 8px;
  }
}
@media screen and (max-width: 1280px) {
  .tree_con {
    height: 501px !important;
  .replaceSearch {
    color: #40a9ff;
    font-weight: bold;
    background-color: rgb(204, 204, 204);
  }
}
  @media screen and (min-width: 1920px) {
    .tree_con {
      height: 748px !important;
    }
  }
  @media screen and (min-width: 1680px) and (max-width: 1920px) {
    .tree_con {
      height: 748px !important;
    }
  }
  @media screen and (min-width: 1400px) and (max-width: 1680px) {
    .tree_con {
      height: 600px !important;
    }
  }
  @media screen and (min-width: 1280px) and (max-width: 1400px) {
    .tree_con {
      height: 501px !important;
    }
  }
  @media screen and (max-width: 1280px) {
    .tree_con {
      height: 501px !important;
    }
  }
</style>