1、优化产品结构树以及设备结构树、列表右键菜单重复右键后出现window菜单问题
2、优化产品结构树节点删除后的loading展示时机
3、优化产品以及设备结构树权限配置获取列表时的loading展示时机
已修改9个文件
1212 ■■■■ 文件已修改
src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue 538 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/DeviceStructure/DeviceStructureTreeContextMenu.vue 61 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/DeviceStructure/Permission/AssignPermissionModal.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Permission/AssignPermissionModal.vue 214 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/Permission/DepartPermissionTransfer.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureBaseContextMenu.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue 324 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dnc/common/TableContextMenu.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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>
src/views/dnc/base/modules/DeviceStructure/DeviceStructureTreeContextMenu.vue
@@ -1,18 +1,12 @@
<template>
  <a-dropdown :trigger="['contextmenu']">
    <span v-if="treeParams.title.indexOf(treeParams.searchValue) > -1">{{ treeParams.title.substr(0, treeParams.title.indexOf(treeParams.searchValue)) }}<span
      class="replaceSearch">{{ treeParams.searchValue }}</span>{{ treeParams.title.substr(treeParams.title.indexOf(treeParams.searchValue) + treeParams.searchValue.length) }}</span>
    <span v-else>{{ treeParams.title }}</span>
    <template #overlay>
      <a-menu @click="({ key: menuKey }) => onContextMenuClick(treeParams.treeKey, menuKey)"
              @contextmenu="event=>event.preventDefault()">
        <a-menu-item v-for="item in defaultContextMenuList[getCurrentMenuLevel]" :key="item.code" v-has="item.code">
          <a-icon :type="item.icon"/>
          {{item.label}}
        </a-menu-item>
      </a-menu>
  <a-menu :style="menuStyle" @click="menuItemClick" v-if="menuVisible" mode="vertical" @contextmenu="menuContextMenu">
    <template v-for="menuItem in defaultContextMenuList[getCurrentMenuLevel]">
      <a-menu-item :key="menuItem.code" v-has="menuItem.code">
        <a-icon :type="menuItem.icon"/>
        {{ menuItem.label }}
      </a-menu-item>
    </template>
  </a-dropdown>
  </a-menu>
</template>
<script>
@@ -26,6 +20,15 @@
    },
    data() {
      return {
        menuVisible: false,
        menuStyle: {
          position: 'fixed',
          top: 0,
          left: 0,
          border: '1px solid #eee',
          boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
          zIndex: 999
        },
        defaultContextMenuList: {
          //车间
          workshop: [
@@ -41,16 +44,15 @@
    },
    computed: {
      getCurrentMenuLevel() {
        if (this.treeParams.type===1) return 'workshop'
        if (this.treeParams.type === 1) return 'workshop'
        else return 'device'
      }
    },
    methods: {
      onContextMenuClick(treeKey, menuKey) {
      menuItemClick({ key }) {
        const menuKey = key
        const level = this.getCurrentMenuLevel
        const { param } = this.treeParams
        const treeNodeInfo = Object.assign({}, this.treeParams, { param })
        console.log('treeNodeInfo++++++++++++++++++++++++++++', treeNodeInfo)
        const treeNodeInfo = Object.assign({ treeKey: this.treeParams.key }, this.treeParams)
        if (treeNodeInfo.type === 2) treeNodeInfo.type = 7
        // 设备结构树节点中的设备层级为2,但在产品结构树中将设备层级的type设置为7,因此在此处设置为7
        const menuKeyArray = menuKey.split('_')
@@ -63,21 +65,18 @@
        } else {
          methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).join('')
        }
        console.log('methodName------------------------------------', methodName)
        console.log('treeParams------------------------------------', this.treeParams)
        const modalTitle = this.defaultContextMenuList[level].find(item => item.code === menuKey).label
        this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle, treeNodeInfo })
      },
      /**
       * 避免单次重复右键后关闭菜单或打开window菜单
       * @param event 事件对象
       */
      menuContextMenu(event) {
        event.preventDefault()
        event.stopPropagation()
      }
    }
  }
</script>
<style scoped>
  .replaceSearch {
    color: #40a9ff;
    font-weight: bold;
    background-color: rgb(204, 204, 204);
  }
</style>
</script>
src/views/dnc/base/modules/DeviceStructure/Permission/AssignPermissionModal.vue
@@ -66,6 +66,11 @@
      // 调用接口获取所有用户列表
      getAllUsersListByApi() {
        this.$nextTick(() => {
          this.$refs.userPermissionTransferRef.spinning = true
          this.allUsersList = []
          this.$refs.userPermissionTransferRef.targetKeys = []
        })
        dncApi.getAllUsersListApi()
          .then(res => {
            if (res.success) {
src/views/dnc/base/modules/ProductStructure/Permission/AssignPermissionModal.vue
@@ -27,123 +27,131 @@
</template>
<script>
import dncApi from '@/api/dnc'
import DepartPermissionTransfer from './DepartPermissionTransfer'
import UserPermissionTransfer from './UserPermissionTransfer'
  import dncApi from '@/api/dnc'
  import DepartPermissionTransfer from './DepartPermissionTransfer'
  import UserPermissionTransfer from './UserPermissionTransfer'
export default {
  name: 'AssignPermissionModal',
  components: { UserPermissionTransfer, DepartPermissionTransfer },
  props: {
    currentTreeNodeInfo: {
      type: Object
    }
  },
  data() {
    return {
      visible: false,
      title: '',
      isAssignSonNode: true,
      activeTabKey: 1,
      allDepartmentsList: [],
      allUsersList: [],
      allTreeKeys: [],
      hasLoadedDataTabKeyArray: []
    }
  },
  watch: {
    visible: {
      handler(value) {
        if (value) {
          this.activeTabKey = 1
          this.isAssignSonNode = true
          this.getAllDepartmentsListByApi()
  export default {
    name: 'AssignPermissionModal',
    components: { UserPermissionTransfer, DepartPermissionTransfer },
    props: {
      currentTreeNodeInfo: {
        type: Object
      }
    },
    data() {
      return {
        visible: false,
        title: '',
        isAssignSonNode: true,
        activeTabKey: 1,
        allDepartmentsList: [],
        allUsersList: [],
        allTreeKeys: [],
        hasLoadedDataTabKeyArray: []
      }
    },
    watch: {
      visible: {
        handler(value) {
          if (value) {
            this.activeTabKey = 1
            this.isAssignSonNode = true
            this.getAllDepartmentsListByApi()
          }
        }
      },
      activeTabKey: {
        handler(value) {
          if (this.hasLoadedDataTabKeyArray.includes(value)) return
          if (value === 2) this.getAllUsersListByApi()
          this.hasLoadedDataTabKeyArray.push(value)
        }
      }
    },
    activeTabKey: {
      handler(value) {
        if (this.hasLoadedDataTabKeyArray.includes(value)) return
        if (value === 2) this.getAllUsersListByApi()
        this.hasLoadedDataTabKeyArray.push(value)
      }
    }
  },
  created() {
    this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
  },
  methods: {
    // 点击树节点右键菜单权限配置按钮后触发
    handleAssignPermission() {
      this.visible = true
    created() {
      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
    },
    methods: {
      // 点击树节点右键菜单权限配置按钮后触发
      handleAssignPermission() {
        this.visible = true
      },
    // 调用接口获取所有车间列表
    getAllDepartmentsListByApi() {
      this.allTreeKeys = []
      dncApi.getAllDepartmentsListApi()
        .then(res => {
          if (res.success) {
            this.allDepartmentsList = res.result
            this.generateList(this.allDepartmentsList)
            this.$nextTick(() => {
              this.$refs.departPermissionTransferRef.getHasPermissionDepartByApi()
              this.$refs.departPermissionTransferRef.expandedKeys = this.allTreeKeys
              this.$refs.departPermissionTransferRef.flatten(JSON.parse(JSON.stringify(this.allDepartmentsList)))
            })
            // 只有上次退出时在车间分配tab界面才会进入此判断
            // 若上次退出时在用户分配tab界面则再次进入时key由2变为1时会触发watch监测activeTabKey变化则会将key:1加入hasLoadedDataTabKeyArray,因此无需再次加入key:1
            if (!this.hasLoadedDataTabKeyArray.includes(this.activeTabKey)) this.hasLoadedDataTabKeyArray.push(this.activeTabKey)
          }
      // 调用接口获取所有车间列表
      getAllDepartmentsListByApi() {
        this.allTreeKeys = this.allDepartmentsList = []
        this.$nextTick(() => {
          this.$refs.departPermissionTransferRef.targetKeys = this.$refs.departPermissionTransferRef.dataSource = []
          this.$refs.departPermissionTransferRef.spinning = true
        })
    },
        dncApi.getAllDepartmentsListApi()
          .then(res => {
            if (res.success) {
              this.allDepartmentsList = res.result
              this.generateList(this.allDepartmentsList)
              this.$nextTick(() => {
                this.$refs.departPermissionTransferRef.getHasPermissionDepartByApi()
                this.$refs.departPermissionTransferRef.expandedKeys = this.allTreeKeys
                this.$refs.departPermissionTransferRef.flatten(JSON.parse(JSON.stringify(this.allDepartmentsList)))
              })
              // 只有上次退出时在车间分配tab界面才会进入此判断
              // 若上次退出时在用户分配tab界面则再次进入时key由2变为1时会触发watch监测activeTabKey变化则会将key:1加入hasLoadedDataTabKeyArray,因此无需再次加入key:1
              if (!this.hasLoadedDataTabKeyArray.includes(this.activeTabKey)) this.hasLoadedDataTabKeyArray.push(this.activeTabKey)
            }
          })
      },
    /**
     * 递归获得所有树节点key
     * @param data
     */
    generateList(data) {
      for (let i = 0; i < data.length; i++) {
        const node = data[i]
        const key = node.key
        this.allTreeKeys.push(key)
        if (node.children) this.generateList(node.children)
      }
    },
    // 调用接口获取所有用户列表
    getAllUsersListByApi() {
      dncApi.getAllUsersListApi()
        .then(res => {
          if (res.success) {
            this.allUsersList = res.result
            this.$nextTick(() => this.$refs.userPermissionTransferRef.getHasPermissionUserByApi())
          }
        })
    },
    setAdminDisabled() {
      this.allUsersList = this.allUsersList.map(item => {
        return {
          ...item,
          disabled: item.username === 'admin'
      /**
       * 递归获得所有树节点key
       * @param data
       */
      generateList(data) {
        for (let i = 0; i < data.length; i++) {
          const node = data[i]
          const key = node.key
          this.allTreeKeys.push(key)
          if (node.children) this.generateList(node.children)
        }
      })
    },
      },
    handleModalClose() {
      this.visible = false
      this.hasLoadedDataTabKeyArray = []
    },
      // 调用接口获取所有用户列表
      getAllUsersListByApi() {
        this.$nextTick(() => {
          this.allUsersList = []
          this.$refs.userPermissionTransferRef.spinning = true
        })
        dncApi.getAllUsersListApi()
          .then(res => {
            if (res.success) {
              this.allUsersList = res.result
              this.$nextTick(() => this.$refs.userPermissionTransferRef.getHasPermissionUserByApi())
            }
          })
      },
    triggerCorrespondingMethod({ methodName, modalTitle }) {
      if (this[methodName]) {
        this[methodName]()
        this.title = modalTitle
      setAdminDisabled() {
        this.allUsersList = this.allUsersList.map(item => {
          return {
            ...item,
            disabled: item.username === 'admin'
          }
        })
      },
      handleModalClose() {
        this.visible = false
        this.hasLoadedDataTabKeyArray = []
      },
      triggerCorrespondingMethod({ methodName, modalTitle }) {
        if (this[methodName]) {
          this[methodName]()
          this.title = modalTitle
        }
      }
    }
  }
}
</script>
<style scoped>
src/views/dnc/base/modules/ProductStructure/Permission/DepartPermissionTransfer.vue
@@ -48,8 +48,6 @@
<script>
  import dncApi from '@/api/dnc'
  const transferDataSource = []
  export default {
    name: 'DepartPermissionTransfer',
    components: {},
src/views/dnc/base/modules/ProductStructure/ProductStructureBaseContextMenu.vue
@@ -18,11 +18,6 @@
export default {
  name: 'ProductStructureBaseContextMenu',
  components: {},
  props: {
    tableRowInfo: {
      type: Object
    }
  },
  data() {
    return {
      menuVisible: false,
@@ -34,7 +29,6 @@
        boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
        zIndex: 999
      },
      currentMenuLevel: '',
      baseContextMenuList: [
        { label: '刷新', code: 'tree_reload', icon: 'reload', isHasPermission: false, isCommonMethod: false },
        { label: '添加产品', code: 'product_add', icon: 'plus', isHasPermission: true, isCommonMethod: false }
@@ -43,7 +37,6 @@
  },
  methods: {
    menuItemClick({ key }) {
      console.log('menuKey', key)
      const isCommonMethod = this.baseContextMenuList.find(item => item.code === key).isCommonMethod
      const modalTitle = this.baseContextMenuList.find(item => item.code === key).label
      const menuKeyArray = key.split('_')
src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue
@@ -30,8 +30,12 @@
                  :selectedKeys="selectedKeys" :treeData="treeDataSource" :autoExpandParent="autoExpandParent"
                  @select="handleTreeSelect" @expand="handleTreeExpand" @rightClick="handleTreeRightClick">
            <template slot="title" slot-scope="{ label, parentId, key:treeKey,type}">
              <ProductStructureTreeContextMenu ref="contextMenuRef"
                                               :treeParams="{label,treeKey,searchValue,type}"/>
              <span v-if="label.indexOf(searchValue) > -1">
                {{label.substr(0, label.indexOf(searchValue))}}
                <span class="replaceSearch">{{searchValue}}</span>
                {{label.substr(label.indexOf(searchValue) + searchValue.length)}}
              </span>
              <span v-else>{{ label }}</span>
            </template>
            <a-icon slot="switcherIcon" type="down"/>
@@ -68,6 +72,10 @@
                             @submitSuccess="modalFormSubmitSuccess"/>
    <!--引用部件-->
    <NcComponentBorrowModal :currentBorrowInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
    <!--产品结构树右键菜单(树节点触发)-->
    <product-structure-tree-context-menu ref="mainContextmenuRef" :treeParams="rightClickSelected"/>
    <!--产品结构树基本右键菜单(空白处触发)-->
    <ProductStructureBaseContextMenu ref="baseContextmenuRef"/>
@@ -204,9 +212,10 @@
      /**
       * 树节点右键单击节点时触发
       * @param event 事件对象
       * @param node 节点对象
       */
      handleTreeRightClick({ node }) {
      handleTreeRightClick({ event, node }) {
        if (this.$refs.baseContextmenuRef) this.$refs.baseContextmenuRef.menuVisible = false
        const that = this
        const record = node.dataRef
@@ -222,7 +231,9 @@
                  message: '消息',
                  description: '暂无该节点详细信息'
                })
                return
              }
              this.openMainContextMenu(event)
            } else {
              that.$notification.error({
                message: '消息',
@@ -243,10 +254,7 @@
          okType: 'danger',
          cancelText: '取消',
          onOk: () => {
            if (!url.delete) {
              this.$message.error('请设置url.delete属性!')
              return
            }
            that.loading = true
            deleteAction(url.delete + `/${id}/${type}`)
              .then((res) => {
                if (res.success) {
@@ -272,7 +280,7 @@
        })
      },
      // 树节点右键单击菜单中删除按钮时触发
      // 发送nc程序至三维工艺
      handleSendNcToPlm() {
        const that = this
        const { rightClickSelected: { id, type }, $confirm, url, $notification } = that
@@ -287,7 +295,7 @@
              this.$message.error('请设置url.webServiceDNCToPlm!')
              return
            }
            getAction(url.webServiceDNCToPlm, {id: id})
            getAction(url.webServiceDNCToPlm, { id: id })
              .then((res) => {
                if (res.success) {
                  that.getTreeDataByApi()
@@ -446,12 +454,24 @@
      },
      /**
       * 打开树节点菜单事件
       * @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
@@ -484,6 +504,12 @@
            break
          default:
        }
      },
      // 控制主要右键菜单关闭
      handleMainContextMenuClose() {
        if (this.$refs.mainContextmenuRef) this.$refs.mainContextmenuRef.menuVisible = false
        document.body.removeEventListener('click', this.handleMainContextMenuClose)
      },
      // 控制基础右键菜单关闭
@@ -537,6 +563,12 @@
    align-items: center;
  }
  .replaceSearch {
    color: #40a9ff;
    font-weight: bold;
    background-color: rgb(204, 204, 204);
  }
  @media screen and (min-width: 1920px) {
    .tree_con {
      height: 748px !important;
src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue
@@ -1,183 +1,171 @@
<template>
  <a-dropdown :trigger="['contextmenu']">
    <span v-if="treeParams.label.indexOf(treeParams.searchValue) > -1">{{
        treeParams.label.substr(0, treeParams.label.indexOf(treeParams.searchValue))
      }}<span
        class="replaceSearch">{{
          treeParams.searchValue
        }}</span>{{
        treeParams.label.substr(treeParams.label.indexOf(treeParams.searchValue) + treeParams.searchValue.length)
      }}</span>
    <span v-else>{{ treeParams.label }}</span>
    <template #overlay>
      <a-menu @click="({ key: menuKey }) => onContextMenuClick(treeParams.treeKey, menuKey)"
              @contextmenu="event=>event.preventDefault()">
        <a-menu-item v-for="item in defaultContextMenuList[getCurrentMenuLevel]" :key="item.code" v-has="item.code">
          <a-icon :type="item.icon"/>
          {{ item.label }}
        </a-menu-item>
      </a-menu>
  <a-menu :style="menuStyle" @click="menuItemClick" v-if="menuVisible" mode="vertical" @contextmenu="menuContextMenu">
    <template v-for="menuItem in defaultContextMenuList[getCurrentMenuLevel]">
      <a-menu-item :key="menuItem.code" v-has="menuItem.code">
        <a-icon :type="menuItem.icon"/>
        {{ menuItem.label }}
      </a-menu-item>
    </template>
  </a-dropdown>
  </a-menu>
</template>
<script>
export default {
  name: 'ProductStructureTreeContextMenu',
  components: {},
  props: {
    treeParams: {
      type: Object
    }
  },
  data() {
    return {
      defaultContextMenuList: {
        //产品
        product: [
          { label: '添加产品', code: 'product_add', icon: 'plus', isCommonMethod: false },
          { label: '添加部件', code: 'product_add_child', icon: 'plus', isCommonMethod: false },
          { label: '编辑产品信息', code: 'product_edit', icon: 'edit', isCommonMethod: false },
          // {  label: '导出文档', code: 'product_export', icon: 'export', isCommonMethod: true },
          { label: '导入其他文档', code: 'product_other_import', icon: 'import', isCommonMethod: true },
          { label: '检索电子样板', code: 'product_search', icon: 'search', isCommonMethod: true },
          { label: '检索NC文件', code: 'product_search_nc', icon: 'search', isCommonMethod: true },
          { label: '删除', code: 'product_delete', icon: 'delete', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //部件
        component: [
          { label: '添加子部件', code: 'component_add', icon: 'plus', isCommonMethod: false },
          { label: '添加零件', code: 'component_add_child', icon: 'plus', isCommonMethod: false },
          { label: '创建工序', code: 'component_add_relative', icon: 'plus', isCommonMethod: false },
          { label: '编辑部件信息', code: 'component_edit', icon: 'edit', isCommonMethod: false },
          // {  label: '导出文档', code: 'component_export', icon: 'export', isCommonMethod: true },
          { label: '导入其他文档', code: 'component_other_import', icon: 'import', isCommonMethod: true },
          { label: '检索电子样板', code: 'component_search', icon: 'search', isCommonMethod: true },
          { label: '检索NC文件', code: 'component_search_nc', icon: 'search', isCommonMethod: true },
          { label: '引用部件',code: 'component_borrow',icon: 'plus',isCommonMethod: false},
          { label: '删除', code: 'component_delete', icon: 'delete', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //零件
        part: [
          { label: '添加零件', code: 'parts_add', icon: 'plus', isCommonMethod: false },
          { label: '创建工艺规程版本', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
          // { label: '创建工序', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
          { label: '编辑零件信息', code: 'parts_edit', icon: 'edit', isCommonMethod: false },
          // {  label: '导出文档', code: 'parts_export', icon: 'export', isCommonMethod: true },
          { label: '导入其他文档', code: 'parts_other_import', icon: 'import', isCommonMethod: true },
          { label: '检索电子样板', code: 'parts_search', icon: 'search', isCommonMethod: true },
          { label: '检索NC文件', code: 'parts_search_nc', icon: 'search', isCommonMethod: true },
          { label: '删除', code: 'parts_delete', icon: 'delete', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //工艺规程版本
        processSpecVersion: [
          { label: '创建工艺规程版本', code: 'version_add', icon: 'plus', isCommonMethod: false },
          { label: '创建工序', code: 'version_add_child', icon: 'plus', isCommonMethod: false },
          { label: '编辑工艺规程版本信息', code: 'version_edit', icon: 'edit', isCommonMethod: false },
          { label: '导入其他文档', code: 'version_other_import', icon: 'import', isCommonMethod: true },
          { label: '检索电子样板', code: 'version_search', icon: 'search', isCommonMethod: true },
          { label: '检索NC文件', code: 'version_search_nc', icon: 'search', isCommonMethod: true },
          { label: '删除', code: 'version_delete', icon: 'delete', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
        ],
        //工序
        process: [
          { label: '创建工序', code: 'process_add', icon: 'plus', isCommonMethod: false },
          { label: '创建工步', code: 'process_add_child', icon: 'plus', isCommonMethod: false },
          { label: '添加设备类', code: 'process_add_type', icon: 'plus', isCommonMethod: true },
          { label: '编辑工序信息', code: 'process_edit', icon: 'edit', isCommonMethod: false },
          { label: '删除', code: 'process_delete', icon: 'delete', isCommonMethod: true },
          // {  label: '导出NC程序', code: 'process_export', icon: 'export', isCommonMethod: true },
          { label: '导入NC程序', code: 'process_nc_import', icon: 'import', isCommonMethod: true },
          { label: '导入其他文档', code: 'process_other_import', icon: 'import', isCommonMethod: true },
          { label: '检索电子样板', code: 'process_search', icon: 'search', isCommonMethod: true },
          { label: '检索NC文件', code: 'process_search_nc', icon: 'search', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true },
          { label: '发送nc程序至三维工艺', code: 'process_send_nc_to_plm', icon: 'import', isCommonMethod: true }
        ],
        //工步
        processStep: [
          { label: '创建工步', code: 'processStep_add', icon: 'plus', isCommonMethod: false },
          { label: '编辑工步信息', code: 'processStep_edit', icon: 'edit', isCommonMethod: false },
          { label: '添加设备类', code: 'processStep_add_type', icon: 'plus', isCommonMethod: true },
          { label: '删除', code: 'processStep_delete', icon: 'delete', isCommonMethod: true },
          // {  label: '导出NC程序', code: 'processStep_export', icon: 'import', isCommonMethod: true },
          { label: '导入NC程序', code: 'processStep_nc_import', icon: 'import', isCommonMethod: true },
          { label: '导入其他文档', code: 'processStep_other_import', icon: 'import', isCommonMethod: true },
          { label: '检索电子样板', code: 'processStep_search', icon: 'search', isCommonMethod: true },
          { label: '检索NC文件', code: 'processStep_search_nc', icon: 'search', isCommonMethod: true },
          { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true },
          { label: '发送nc程序至三维工艺', code: 'processStep_send_nc_to_plm', icon: 'import', isCommonMethod: true }
        ]
      }
    }
  },
  computed: {
    getCurrentMenuLevel() {
      switch (+this.treeParams.type) {
        case 1:
          return 'product'
        case 2:
          return 'component'
        case 3:
          return 'part'
        case 4:
          return 'processSpecVersion'
        case 5:
          return 'process'
        case 6:
          return 'processStep'
  export default {
    name: 'ProductStructureTreeContextMenu',
    components: {},
    props: {
      treeParams: {
        type: Object
      }
    },
    // getCurrentDocClassCode() {
    //   switch (+this.treeParams.type) {
    //     case 1:
    //       return 'OTHER'
    //     case 2:
    //       return 'OTHER'
    //     case 3:
    //       return 'OTHER'
    //     case 4:
    //       return 'OTHER'
    //     case 5:
    //       return 'NC'
    //     case 6:
    //       return 'NC'
    //   }
    // }
  },
  methods: {
    onContextMenuClick(treeKey, menuKey) {
      const level = this.getCurrentMenuLevel
      console.log('level---------------------', level)
      const treeNodeInfo = Object.assign({}, this.treeParams)
      console.log('treeNodeInfo******************', treeNodeInfo)
      const menuKeyArray = menuKey.split('_')
      const isCommonMethod = this.defaultContextMenuList[level].find(item => item.code === menuKey).isCommonMethod
      // product_add => handleAdd 触发对应组件事件
      let methodName
      // 判断是否为公共方法,如果为公共方法则截取专有属性product/component/part/process等字段
      if (isCommonMethod) {
        methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).slice(1).join('')
      } else {
        methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).join('')
    data() {
      return {
        menuVisible: false,
        menuStyle: {
          position: 'fixed',
          top: 0,
          left: 0,
          border: '1px solid #eee',
          boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
          zIndex: 999
        },
        defaultContextMenuList: {
          //产品
          product: [
            { label: '添加产品', code: 'product_add', icon: 'plus', isCommonMethod: false },
            { label: '添加部件', code: 'product_add_child', icon: 'plus', isCommonMethod: false },
            { label: '编辑产品信息', code: 'product_edit', icon: 'edit', isCommonMethod: false },
            // {  label: '导出文档', code: 'product_export', icon: 'export', isCommonMethod: true },
            { label: '导入其他文档', code: 'product_other_import', icon: 'import', isCommonMethod: true },
            { label: '检索电子样板', code: 'product_search', icon: 'search', isCommonMethod: true },
            { label: '检索NC文件', code: 'product_search_nc', icon: 'search', isCommonMethod: true },
            { label: '删除', code: 'product_delete', icon: 'delete', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //部件
          component: [
            { label: '添加子部件', code: 'component_add', icon: 'plus', isCommonMethod: false },
            { label: '添加零件', code: 'component_add_child', icon: 'plus', isCommonMethod: false },
            { label: '创建工序', code: 'component_add_relative', icon: 'plus', isCommonMethod: false },
            { label: '编辑部件信息', code: 'component_edit', icon: 'edit', isCommonMethod: false },
            // {  label: '导出文档', code: 'component_export', icon: 'export', isCommonMethod: true },
            { label: '导入其他文档', code: 'component_other_import', icon: 'import', isCommonMethod: true },
            { label: '检索电子样板', code: 'component_search', icon: 'search', isCommonMethod: true },
            { label: '检索NC文件', code: 'component_search_nc', icon: 'search', isCommonMethod: true },
            { label: '引用部件', code: 'component_borrow', icon: 'plus', isCommonMethod: false },
            { label: '删除', code: 'component_delete', icon: 'delete', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //零件
          part: [
            { label: '添加零件', code: 'parts_add', icon: 'plus', isCommonMethod: false },
            { label: '创建工艺规程版本', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
            // { label: '创建工序', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
            { label: '编辑零件信息', code: 'parts_edit', icon: 'edit', isCommonMethod: false },
            // {  label: '导出文档', code: 'parts_export', icon: 'export', isCommonMethod: true },
            { label: '导入其他文档', code: 'parts_other_import', icon: 'import', isCommonMethod: true },
            { label: '检索电子样板', code: 'parts_search', icon: 'search', isCommonMethod: true },
            { label: '检索NC文件', code: 'parts_search_nc', icon: 'search', isCommonMethod: true },
            { label: '删除', code: 'parts_delete', icon: 'delete', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //工艺规程版本
          processSpecVersion: [
            { label: '创建工艺规程版本', code: 'version_add', icon: 'plus', isCommonMethod: false },
            { label: '创建工序', code: 'version_add_child', icon: 'plus', isCommonMethod: false },
            { label: '编辑工艺规程版本信息', code: 'version_edit', icon: 'edit', isCommonMethod: false },
            { label: '导入其他文档', code: 'version_other_import', icon: 'import', isCommonMethod: true },
            { label: '检索电子样板', code: 'version_search', icon: 'search', isCommonMethod: true },
            { label: '检索NC文件', code: 'version_search_nc', icon: 'search', isCommonMethod: true },
            { label: '删除', code: 'version_delete', icon: 'delete', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
          ],
          //工序
          process: [
            { label: '创建工序', code: 'process_add', icon: 'plus', isCommonMethod: false },
            { label: '创建工步', code: 'process_add_child', icon: 'plus', isCommonMethod: false },
            { label: '添加设备类', code: 'process_add_type', icon: 'plus', isCommonMethod: true },
            { label: '编辑工序信息', code: 'process_edit', icon: 'edit', isCommonMethod: false },
            { label: '删除', code: 'process_delete', icon: 'delete', isCommonMethod: true },
            // {  label: '导出NC程序', code: 'process_export', icon: 'export', isCommonMethod: true },
            { label: '导入NC程序', code: 'process_nc_import', icon: 'import', isCommonMethod: true },
            { label: '导入其他文档', code: 'process_other_import', icon: 'import', isCommonMethod: true },
            { label: '检索电子样板', code: 'process_search', icon: 'search', isCommonMethod: true },
            { label: '检索NC文件', code: 'process_search_nc', icon: 'search', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true },
            { label: '发送nc程序至三维工艺', code: 'process_send_nc_to_plm', icon: 'import', isCommonMethod: true }
          ],
          //工步
          processStep: [
            { label: '创建工步', code: 'processStep_add', icon: 'plus', isCommonMethod: false },
            { label: '编辑工步信息', code: 'processStep_edit', icon: 'edit', isCommonMethod: false },
            { label: '添加设备类', code: 'processStep_add_type', icon: 'plus', isCommonMethod: true },
            { label: '删除', code: 'processStep_delete', icon: 'delete', isCommonMethod: true },
            // {  label: '导出NC程序', code: 'processStep_export', icon: 'import', isCommonMethod: true },
            { label: '导入NC程序', code: 'processStep_nc_import', icon: 'import', isCommonMethod: true },
            { label: '导入其他文档', code: 'processStep_other_import', icon: 'import', isCommonMethod: true },
            { label: '检索电子样板', code: 'processStep_search', icon: 'search', isCommonMethod: true },
            { label: '检索NC文件', code: 'processStep_search_nc', icon: 'search', isCommonMethod: true },
            { label: '权限配置', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true },
            { label: '发送nc程序至三维工艺', code: 'processStep_send_nc_to_plm', icon: 'import', isCommonMethod: true }
          ]
        }
      }
      console.log('methodName', methodName)
      const modalTitle = this.defaultContextMenuList[level].find(item => item.code === menuKey).label
      this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle, treeNodeInfo })
    },
    computed: {
      getCurrentMenuLevel() {
        switch (+this.treeParams.type) {
          case 1:
            return 'product'
          case 2:
            return 'component'
          case 3:
            return 'part'
          case 4:
            return 'processSpecVersion'
          case 5:
            return 'process'
          case 6:
            return 'processStep'
        }
      }
    },
    methods: {
      menuItemClick({ key }) {
        const menuKey = key
        const level = this.getCurrentMenuLevel
        const treeNodeInfo = Object.assign({ treeKey: this.treeParams.key }, this.treeParams)
        console.log('treeNodeInfo', treeNodeInfo)
        const menuKeyArray = menuKey.split('_')
        const isCommonMethod = this.defaultContextMenuList[level].find(item => item.code === menuKey).isCommonMethod
        // product_add => handleAdd 触发对应组件事件
        let methodName
        // 判断是否为公共方法,如果为公共方法则截取专有属性product/component/part/process等字段
        if (isCommonMethod) {
          methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).slice(1).join('')
        } else {
          methodName = 'handle' + menuKeyArray.map(item => item[0].toUpperCase() + item.slice(1)).join('')
        }
        const modalTitle = this.defaultContextMenuList[level].find(item => item.code === menuKey).label
        this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle, treeNodeInfo })
      },
      /**
       * 避免单次重复右键后关闭菜单或打开window菜单
       * @param event 事件对象
       */
      menuContextMenu(event) {
        event.preventDefault()
        event.stopPropagation()
      }
    }
  }
}
</script>
<style scoped>
.replaceSearch {
  color: #40a9ff;
  font-weight: bold;
  background-color: rgb(204, 204, 204);
}
  /deep/ .ant-menu-item {
    height: 32px;
    line-height: 32px;
  }
</style>
src/views/dnc/common/TableContextMenu.vue
@@ -1,5 +1,5 @@
<template>
  <a-menu :style="menuStyle" @click="menuItemClick" v-if="menuVisible" mode="vertical">
  <a-menu :style="menuStyle" @click="menuItemClick" v-if="menuVisible" mode="vertical" @contextmenu="menuContextMenu">
    <template v-for="menuItem in defaultContextMenuList[tableRowInfo.param]">
      <a-menu-item :key="menuItem.code" v-has="menuItem.code" v-if="menuItem.subMenu.length===0">
        <a-icon :type="menuItem.icon"/>
@@ -168,6 +168,15 @@
          modalTitle,
          tableRowInfo: this.tableRowInfo
        })
      },
      /**
       * 避免单次重复右键后关闭菜单或打开window菜单
       * @param event 事件对象
       */
      menuContextMenu(event) {
        event.preventDefault()
        event.stopPropagation()
      }
    }
  }