From 8fbfac872e852a0ad0dbe04f2b7b69e4cff3c85c Mon Sep 17 00:00:00 2001
From: zhaowei <zhaowei>
Date: 星期三, 19 三月 2025 11:26:24 +0800
Subject: [PATCH] 1、MDC零件加工管理和OEE页面开发100% 2、DNC结构树取消搜索框侧边下拉菜单改为树组件空白处右键菜单

---
 src/views/dnc/base/modules/DeviceStructure/DeviceStructureBaseContextMenu.vue                          |   68 +
 src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue                                   |   54 +
 src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue                           |    4 
 src/views/dnc/common/ImportFileModal.vue                                                               |  362 ++++----
 src/views/mdc/base/PartsMatchingManagement.vue                                                         |   82 ++
 src/views/dnc/base/modules/ProductStructure/DeviceCustomType/UseDeviceCustomTypeEquipmentTableList.vue |  133 +-
 src/views/mdc/base/OEEAnalysis.vue                                                                     |   82 ++
 src/views/dnc/base/modules/DeviceStructure/Document/HasReceivedDocumentTableList.vue                   |    2 
 src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingList.vue                               |  321 ++++++++
 src/views/dnc/base/modules/DeviceStructure/Document/HasSentDocumentTableList.vue                       |    2 
 src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue                        |    2 
 src/views/dnc/base/modules/ProductStructure/ProductStructureBaseContextMenu.vue                        |   69 +
 src/views/mdc/base/modules/OEEAnalysis/OEEAnalysisList.vue                                             |  304 +++++++
 src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingForm.vue                               |  191 ++++
 src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingModal.vue                              |   64 +
 src/api/mdc.js                                                                                         |   17 
 src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue                                |   32 
 src/views/mdc/base/modules/OEEAnalysis/ComputeOeeModal.vue                                             |   88 ++
 src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue                                     |  495 ++++++-----
 19 files changed, 1,854 insertions(+), 518 deletions(-)

diff --git a/src/api/mdc.js b/src/api/mdc.js
index c1d0fd0..3511070 100644
--- a/src/api/mdc.js
+++ b/src/api/mdc.js
@@ -20,16 +20,6 @@
   addWorkshopApi: params => postAction('/mdc/mdcWorkshopInfo/add', params),
   // 缂栬緫杞﹂棿淇℃伅
   editWorkshopApi: params => putAction('/mdc/mdcWorkshopInfo/edit', params),
-  // 鍒犻櫎鍗曚釜杞﹂棿淇℃伅
-  deleteSingleWorkshopApi: id => deleteAction('/mdc/mdcWorkshopInfo/delete', { id }),
-  // 鎵归噺鍒犻櫎杞﹂棿淇℃伅
-  deleteBatchWorkshopApi: ids => deleteAction('/mdc/mdcWorkshopInfo/deleteBatch', { ids }),
-  // 鏂板澶у睆杞﹂棿鍜岃澶囧叧绯�
-  addDeviceInWorkshopApi: params => postAction('/mdc/mdcWorkshopInfo/addWorkshopEquipment', params),
-  // 鍒犻櫎鍗曚釜澶у睆杞﹂棿鍜岃澶囧叧绯�
-  deleteSingleDeviceInWorkshopApi: params => deleteAction('/mdc/mdcWorkshopInfo/deleteWorkshopEquipment', params),
-  // 鎵归噺鍒犻櫎澶у睆杞﹂棿鍜岃澶囧叧绯�
-  deleteBatchDeviceInWorkshopApi: params => deleteAction('/mdc/mdcWorkshopInfo/deleteWorkshopEquipmentBatch', params),
   // -------------------------------------璁惧鍙傛暟闃堝�肩鐞嗛〉闈�--------------------------------------------
   // 鏍规嵁椹卞姩绫诲瀷鑾峰彇鍙傛暟
   getParamListByDriveTypeApi: controlSystemType => getAction(`/mdc/mdcDriveTypeParamConfig/getDriveParamOptionsByType?controlSystemType=${controlSystemType}`),
@@ -37,8 +27,7 @@
   addParamThresholdApi: params => postAction('/mdc/mdcEquipmentThreshold/add', params),
   // 缂栬緫璁惧鍙傛暟闃堝��
   editParamThresholdApi: params => postAction('/mdc/mdcEquipmentThreshold/edit', params),
-  // 鍒犻櫎璁惧鍙傛暟闃堝��
-  deleteParamThresholdApi: id => deleteAction('/mdc/mdcEquipmentThreshold/delete', { id }),
-  // 鍒犻櫎璁惧鍙傛暟闃堝��
-  deleteBatchParamThresholdApi: ids => deleteAction('/mdc/mdcEquipmentThreshold/deleteBatch', { ids })
+  // -------------------------------------OEE椤甸潰--------------------------------------------
+  // 璁$畻OEE
+  computeOeeApi: params => postAction('/mdc/mdcOeeInfo/computeOee', params),
 }
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureBaseContextMenu.vue b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureBaseContextMenu.vue
new file mode 100644
index 0000000..a0aeb78
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureBaseContextMenu.vue
@@ -0,0 +1,68 @@
+<template>
+  <a-menu :style="menuStyle" @click="menuItemClick" v-if="menuVisible" mode="vertical">
+    <template v-for="menuItem in baseContextMenuList">
+      <a-menu-item :key="menuItem.code" v-has="menuItem.code" v-if="menuItem.isHasPermission">
+        <a-icon :type="menuItem.icon"/>
+        {{ menuItem.label }}
+      </a-menu-item>
+
+      <a-menu-item :key="menuItem.code" v-else>
+        <a-icon :type="menuItem.icon"/>
+        {{ menuItem.label }}
+      </a-menu-item>
+    </template>
+  </a-menu>
+</template>
+
+<script>
+export default {
+  name: 'DeviceStructureBaseContextMenu',
+  components: {},
+  props: {
+    tableRowInfo: {
+      type: Object
+    }
+  },
+  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
+      },
+      currentMenuLevel: '',
+      baseContextMenuList: [
+        { label: '鍒锋柊', code: 'tree_reload', icon: 'reload', isHasPermission: false, isCommonMethod: false },
+      ]
+    }
+  },
+  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('_')
+      // product_add => handleAdd 瑙﹀彂瀵瑰簲缁勪欢浜嬩欢
+      let methodName
+      // 鍒ゆ柇鏄惁涓哄叕鍏辨柟娉曪紝濡傛灉涓哄叕鍏辨柟娉曞垯鎴彇涓撴湁灞炴�roduct/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('')
+      }
+      this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/deep/ .ant-menu-item {
+  height: 32px;
+  line-height: 32px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
index 11ff894..3003661 100644
--- a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
+++ b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
@@ -1,24 +1,24 @@
 <template>
-  <a-card class="tree_con" :loading="cardLoading" :bordered="false" @contextmenu.native="e=>e.preventDefault()">
+  <a-card class="tree_con" :loading="cardLoading" :bordered="false" @contextmenu.native.stop="openBaseContextMenu">
     <a-spin :spinning="loading">
       <div style="display: flex;flex-direction: column;height: 100%">
         <div style="display: flex">
           <a-input placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�" allowClear v-model="searchInput"
                    @change="handleSearchInputChange"/>
-          <a-dropdown :trigger="['click']" placement="bottomCenter" style="margin: 0 8px">
-            <a-menu slot="overlay">
-              <a-menu-item key="1" @click="expandedKeys = allTreeKeys">灞曞紑鎵�鏈�</a-menu-item>
-              <a-menu-item key="2" @click="expandedKeys = ['-1']">鍚堝苟鎵�鏈�</a-menu-item>
-              <a-menu-item key="3" @click="getTreeDataByApi">鍒锋柊</a-menu-item>
-            </a-menu>
-            <a-button>
-              <a-icon type="bars"/>
-            </a-button>
-          </a-dropdown>
+          <!--          <a-dropdown :trigger="['click']" placement="bottomCenter" style="margin: 0 8px">-->
+          <!--            <a-menu slot="overlay">-->
+          <!--              <a-menu-item key="1" @click="expandedKeys = allTreeKeys">灞曞紑鎵�鏈�</a-menu-item>-->
+          <!--              <a-menu-item key="2" @click="expandedKeys = ['-1']">鍚堝苟鎵�鏈�</a-menu-item>-->
+          <!--              <a-menu-item key="3" @click="getTreeDataByApi">鍒锋柊</a-menu-item>-->
+          <!--            </a-menu>-->
+          <!--            <a-button>-->
+          <!--              <a-icon type="bars"/>-->
+          <!--            </a-button>-->
+          <!--          </a-dropdown>-->
         </div>
 
         <!--璁惧缁撴瀯鏍�-->
-        <div style="flex: 1;overflow:auto;margin-top: 10px">
+        <div id="tree-container" style="flex: 1;overflow:auto;margin-top: 10px">
           <a-tree blockNode show-icon :expandedKeys.sync="expandedKeys"
                   :selectedKeys="selectedKeys" :treeData="treeDataSource" :autoExpandParent="autoExpandParent"
                   @select="handleTreeSelect" @expand="handleTreeExpand" @rightClick="handleTreeRightClick">
@@ -37,246 +37,281 @@
 
     <!--鏉冮檺閰嶇疆寮圭獥-->
     <AssignPermissionModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="getTreeDataByApi"/>
+    <!--浜у搧缁撴瀯鏍戝熀鏈彸閿彍鍗�(绌虹櫧澶勮Е鍙�)-->
+    <DeviceStructureBaseContextMenu ref="baseContextmenuRef"/>
   </a-card>
 </template>
 
 <script>
-  import dncApi from '@/api/dnc'
-  import DeviceStructureTreeContextMenu from './DeviceStructureTreeContextMenu'
-  import AssignPermissionModal from './Permission/AssignPermissionModal'
+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: {
-      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
-          })
-      },
-
-      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 }) {
-        const record = node.dataRef
-        // 鑻ュ彸閿椂褰撳墠鍙充晶灞曠ず灞傜骇涓鸿澶囧眰绾т笖褰撳墠鍙抽敭鏍戝眰绾у悓涓鸿澶囧眰绾ф椂鍒欏湪瑙﹀彂鍙抽敭鑿滃崟鍔熻兘鏃跺悓鏃惰Е鍙戝乏閿�変腑鍔熻兘
-        if (this.currentSelected.type === 2 && record.type === 2) this.handleTreeSelect([record.key], { node })
-        this.rightClickSelected = Object.assign({}, record)
-      },
-
-      /**
-       * 鏍戣妭鐐瑰睍寮�鍚堝苟鏃惰Е鍙�
-       * @param expandedKeys 灞曞紑椤筴ey
-       */
-      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)
-            }
-          }
-        }
-        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)
-        }
-      },
-
-      triggerCorrespondingMethod({ methodName }) {
-        if (this[methodName]) this[methodName]()
-      },
-
-      /**
-       * 璁剧疆鏍戣妭鐐瑰浘鏍�
-       * @param treeNode
-       */
-      setTreeNodeIcon(treeNode) {
-        if (!treeNode.equipmentId) {
-          treeNode.slots = { icon: 'workshop' }
-        } else {
-          treeNode.slots = { icon: 'device' }
-        }
+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
+        })
+    },
+
+    /**
+     * 閫氳繃鍙充晶tab鏍忔墍鍦╝ctiveKey璁剧疆褰撳墠璁惧鐨凬C鏂囨。绫诲瀷
+     * @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 灞曞紑椤筴ey
+     */
+    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)
+          }
+        }
+      }
+      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.equipmentId) {
+        treeNode.slots = { icon: 'workshop' }
+      } else {
+        treeNode.slots = { icon: 'device' }
+      }
+    },
+
+    // 鎺у埗鍩虹鍙抽敭鑿滃崟鍏抽棴
+    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 {
+  padding: 0 12px 0 0;
+}
 
-  /deep/ .ant-card-body, /deep/ .ant-spin-nested-loading, /deep/ .ant-spin-container {
-    height: 100%;
-  }
+/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;
-  }
+/deep/ .ant-tree-title, .ant-tree-title .ant-dropdown-trigger {
+  display: inline-block;
+  width: calc(100% - 24px) !important;
+}
 
-  ::-webkit-scrollbar {
-    width: 8px;
-  }
+::-webkit-scrollbar {
+  width: 8px;
+}
 
-  @media screen and (min-width: 1920px) {
-    .tree_con {
-      height: 748px !important;
-    }
+@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: 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: 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 (min-width: 1280px) and (max-width: 1400px) {
+  .tree_con {
+    height: 501px !important;
   }
+}
 
-  @media screen and (max-width: 1280px) {
-    .tree_con {
-      height: 501px !important;
-    }
+@media screen and (max-width: 1280px) {
+  .tree_con {
+    height: 501px !important;
   }
+}
 </style>
diff --git a/src/views/dnc/base/modules/DeviceStructure/Document/HasReceivedDocumentTableList.vue b/src/views/dnc/base/modules/DeviceStructure/Document/HasReceivedDocumentTableList.vue
index 64dbc46..e643836 100644
--- a/src/views/dnc/base/modules/DeviceStructure/Document/HasReceivedDocumentTableList.vue
+++ b/src/views/dnc/base/modules/DeviceStructure/Document/HasReceivedDocumentTableList.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination" :loading="loading"
              :scroll="{y:265}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange">
 
     </a-table>
diff --git a/src/views/dnc/base/modules/DeviceStructure/Document/HasSentDocumentTableList.vue b/src/views/dnc/base/modules/DeviceStructure/Document/HasSentDocumentTableList.vue
index ff4f57e..c1d74bd 100644
--- a/src/views/dnc/base/modules/DeviceStructure/Document/HasSentDocumentTableList.vue
+++ b/src/views/dnc/base/modules/DeviceStructure/Document/HasSentDocumentTableList.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination" :loading="loading"
              :scroll="{y:265}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange">
 
     </a-table>
diff --git a/src/views/dnc/base/modules/ProductStructure/DeviceCustomType/UseDeviceCustomTypeEquipmentTableList.vue b/src/views/dnc/base/modules/ProductStructure/DeviceCustomType/UseDeviceCustomTypeEquipmentTableList.vue
index 76e9649..45ea27b 100644
--- a/src/views/dnc/base/modules/ProductStructure/DeviceCustomType/UseDeviceCustomTypeEquipmentTableList.vue
+++ b/src/views/dnc/base/modules/ProductStructure/DeviceCustomType/UseDeviceCustomTypeEquipmentTableList.vue
@@ -1,81 +1,82 @@
 <template>
-  <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false" :size="size" rowKey="id" :scroll="{y:189}">
+  <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false" :loading="loading" :size="size"
+           rowKey="id" :scroll="{y:189}">
 
   </a-table>
 </template>
 
 <script>
-  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+import { JeecgListMixin } from '@/mixins/JeecgListMixin'
 
-  export default {
-    name: 'UseDeviceCustomTypeEquipmentTableList',
-    components: {},
-    mixins: [JeecgListMixin],
-    props: {
-      currentLevelDetails: {
-        type: Object
-      },
-      size: {
-        type: String
-      }
+export default {
+  name: 'UseDeviceCustomTypeEquipmentTableList',
+  components: {},
+  mixins: [JeecgListMixin],
+  props: {
+    currentLevelDetails: {
+      type: Object
     },
-    data() {
-      return {
-        disableMixinCreated: true,
-        columns: [
-          {
-            title: '璁惧缂栧彿',
-            align: 'center',
-            dataIndex: 'equipmentId',
-            width:250
-          },
-          {
-            title: '璁惧鍚嶇О',
-            align: 'center',
-            dataIndex: 'equipmentName',
-            width:250
-          },
-          {
-            title: '璁惧鍨嬪彿',
-            align: 'center',
-            dataIndex: 'equipmentModel',
-            width:250
-          },
-          {
-            title: '鏈哄簥IP',
-            align: 'center',
-            dataIndex: 'equipmentIp',
-            width:200
-          },
-          {
-            title: '椹卞姩绫诲瀷',
-            align: 'center',
-            dataIndex: 'driveType'
-          },
-          {
-            title: '绔彛',
-            align: 'center',
-            dataIndex: 'dataPort'
-          },
-          {
-            title: '鏁版帶绯荤粺',
-            align: 'center',
-            dataIndex: 'controlSystem'
-          }
-        ],
-        url: {
-          list: '/nc/deviceManagement/getEquipmentListById'
+    size: {
+      type: String
+    }
+  },
+  data() {
+    return {
+      disableMixinCreated: true,
+      columns: [
+        {
+          title: '璁惧缂栧彿',
+          align: 'center',
+          dataIndex: 'equipmentId',
+          width: 250
+        },
+        {
+          title: '璁惧鍚嶇О',
+          align: 'center',
+          dataIndex: 'equipmentName',
+          width: 250
+        },
+        {
+          title: '璁惧鍨嬪彿',
+          align: 'center',
+          dataIndex: 'equipmentModel',
+          width: 250
+        },
+        {
+          title: '鏈哄簥IP',
+          align: 'center',
+          dataIndex: 'equipmentIp',
+          width: 200
+        },
+        {
+          title: '椹卞姩绫诲瀷',
+          align: 'center',
+          dataIndex: 'driveType'
+        },
+        {
+          title: '绔彛',
+          align: 'center',
+          dataIndex: 'dataPort'
+        },
+        {
+          title: '鏁版帶绯荤粺',
+          align: 'center',
+          dataIndex: 'controlSystem'
         }
+      ],
+      url: {
+        list: '/nc/deviceManagement/getEquipmentListById'
       }
-    },
-    methods: {
-      setQueryParamAndLoadData() {
-        const { deviceManagementId } = this.currentLevelDetails
-        this.queryParam = Object.assign({}, { id: deviceManagementId })
-        this.loadData()
-      },
+    }
+  },
+  methods: {
+    setQueryParamAndLoadData() {
+      const { deviceManagementId } = this.currentLevelDetails
+      this.queryParam = Object.assign({}, { id: deviceManagementId })
+      this.loadData()
     }
   }
+}
 </script>
 
 <style scoped>
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue b/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue
index 8afb748..af502ae 100644
--- a/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue
+++ b/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue
@@ -1,6 +1,6 @@
 <template>
   <div style="flex: 1">
-    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination" :loading="loading"
              :scroll="{y:265}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange">
 
     </a-table>
@@ -94,7 +94,7 @@
   watch: {
     currentNCDocumentAttributionInfo: {
       handler(value) {
-        this.currentClickedDocumentInfo = {}
+        this.currentClickedDocumentInfo = this.currentRightClickedDocumentInfo = {}
       },
       immediate: true
     }
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue b/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue
index 70f8f75..2e12839 100644
--- a/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue
+++ b/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination" :loading="loading"
              :scroll="{y:265}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange">
 
     </a-table>
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureBaseContextMenu.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureBaseContextMenu.vue
new file mode 100644
index 0000000..c5a1cc2
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureBaseContextMenu.vue
@@ -0,0 +1,69 @@
+<template>
+  <a-menu :style="menuStyle" @click="menuItemClick" v-if="menuVisible" mode="vertical">
+    <template v-for="menuItem in baseContextMenuList">
+      <a-menu-item :key="menuItem.code" v-has="menuItem.code" v-if="menuItem.isHasPermission">
+        <a-icon :type="menuItem.icon"/>
+        {{ menuItem.label }}
+      </a-menu-item>
+
+      <a-menu-item :key="menuItem.code" v-else>
+        <a-icon :type="menuItem.icon"/>
+        {{ menuItem.label }}
+      </a-menu-item>
+    </template>
+  </a-menu>
+</template>
+
+<script>
+export default {
+  name: 'ProductStructureBaseContextMenu',
+  components: {},
+  props: {
+    tableRowInfo: {
+      type: Object
+    }
+  },
+  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
+      },
+      currentMenuLevel: '',
+      baseContextMenuList: [
+        { label: '鍒锋柊', code: 'tree_reload', icon: 'reload', isHasPermission: false, isCommonMethod: false },
+        { label: '娣诲姞浜у搧', code: 'product_add', icon: 'plus', isHasPermission: true, isCommonMethod: false }
+      ]
+    }
+  },
+  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('_')
+      // product_add => handleAdd 瑙﹀彂瀵瑰簲缁勪欢浜嬩欢
+      let methodName
+      // 鍒ゆ柇鏄惁涓哄叕鍏辨柟娉曪紝濡傛灉涓哄叕鍏辨柟娉曞垯鎴彇涓撴湁灞炴�roduct/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('')
+      }
+      this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/deep/ .ant-menu-item {
+  height: 32px;
+  line-height: 32px;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
index 7655c68..bfff7df 100644
--- a/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
@@ -96,15 +96,16 @@
     receiveCurrentTreeNodeInfo(treeNodeInfo) {
       console.log('treeNodeInfo', treeNodeInfo)
       const { id, type } = treeNodeInfo
-      // 浠庢爲缁勪欢鎺ュ彈鏍戣妭鐐逛俊鎭悗浠庣埗缁勪欢娴佸叆瀛愮粍浠�
+      // 浠庢爲缁勪欢鎺ュ彈鏍戣妭鐐逛俊鎭悗浠庣埗缁勪欢娴佸叆瀛愮粍浠跺苟閲嶇疆鏁版嵁
+      this.currentClickedTypeInfo = this.currentRightClickedTableRowInfo = {}
       this.currentTreeNodeInfo = treeNodeInfo
       this.currentNCDocumentAttributionInfo = Object.assign({}, {
         attributionId: id,
         attributionType: type,
         docClassCode: 'NC'
       })
-      // 娓呯┖涓婁竴鑺傜偣宸茬粡鍔犺浇杩囧緱鏂囨。鍒楄〃tabKey
       this.hasLoadedDataTabKeyArray = []
+
       if (+type === 5 || +type === 6) {
         this.activeTabKey = 1
         this.$nextTick(() => {
@@ -123,6 +124,10 @@
       this.hasLoadedDataTabKeyArray.push(this.activeTabKey)
     },
 
+    /**
+     * 鎺ュ彈褰撳墠鐐瑰嚮鐨勮澶囩被淇℃伅
+     * @param record 褰撳墠鐐瑰嚮鐨勮澶囩被琛屼俊鎭�
+     */
     receiveCurrentClickedTypeInfo(record) {
       const { id, attributionType } = record
       this.currentClickedTypeInfo = Object.assign({}, record)
@@ -142,7 +147,6 @@
      */
     handleTableContextMenuOpen(record) {
       this.currentRightClickedTableRowInfo = Object.assign({}, record)
-      console.log('currentRightClickedTableRowInfo', this.currentRightClickedTableRowInfo)
       this.$refs.tableContextMenuRef.currentMenuLevel = record.param
       this.$refs.tableContextMenuRef.menuStyle.top = event.clientY + 'px'
       this.$refs.tableContextMenuRef.menuStyle.left = event.clientX + 'px'
@@ -163,8 +167,9 @@
         this.hasLoadedDataTabKeyArray.push(activeTabKey)
       }
     },
+
     /**
-     * 鏂囨。浠ュ強NC绋嬪簭瀵煎叆/鍑哄簱/鍏ュ簱鎴愬姛鍚庤Е鍙戦噸鏂板姞杞芥枃妗e垪琛�
+     * 鏂囨。浠ュ強NC绋嬪簭瀵煎叆/鍑哄簱/鍏ュ簱/鍙栨秷鍑哄簱/鍙戝竷/褰掓。鎴愬姛鍚庤Е鍙戦噸鏂板姞杞芥枃妗e垪琛�
      * @param docClassCode 鏂囨。绫诲埆
      * @param attributionType 鏂囨。鐖剁骇type绫诲瀷
      * @param attributionId 鏂囨。鐖剁骇Id
@@ -173,12 +178,19 @@
       console.log('docClassCode, attributionType, attributionId', docClassCode, attributionType, attributionId)
       // 鍦ㄦ澶勮澶嘚C鏂囨。鐖剁骇鍙傛暟鏄彲姝ゆ柟娉曟槸缁撴瀯鏍戜互鍙婅澶囩被涓ょ涓嶅悓瀵煎叆鏂瑰紡鐨勫叡鍚屽嚭鍙�
       this.currentNCDocumentAttributionInfo = Object.assign({}, { docClassCode, attributionId, attributionType })
-      // 鑻ュ紩鍏ヨ澶囩被鍒欏彧闇�瑕佸垽鏂綋鍓嶅嚭鐜扮殑鏂囨。鎵�灞炴槸鍚︽槸褰撳墠宸﹂敭閫変腑鐨勬枃妗o紝鑻ヤ笉鏄綋鍓嶉�変腑鐨勬枃妗e垯涓嶅埛鏂版枃妗e垪琛�(閬垮厤鏃犳晥鍒锋柊)
-      if (this.currentRightClickedTableRowInfo.hasOwnProperty('deviceManagementId')) {
-        if (this.currentClickedTypeInfo.id !== attributionId) return
-      } else {
-        if (this.currentTreeNodeInfo.id !== attributionId) return
+
+      // 鍒ゆ柇褰撳墠鍙充晶灞曠ず鐨勬枃妗g殑鎵�灞炴槸鍚︽槸褰撳墠宸﹂敭閫変腑鏍戣妭鐐规垨璁惧绫伙紝鑻ヤ笉鏄綋鍓嶅乏閿�変腑鐨勫垯鍦ㄥ鍏ュ悗涓嶅埛鏂板彸渚х殑鏂囨。鍒楄〃(閬垮厤鏃犳晥鍒锋柊)
+      // 鍒ゆ柇鏄惁鏄湪鏂囨。鍒楄〃涓繘琛屽嚭搴�/鍏ュ簱/鍙戝竷/褰掓。绛夋搷浣�,鑻ユ槸鍦ㄦ枃妗e垪琛ㄤ腑鎿嶄綔鍒欐搷浣滄垚鍔熷悗鐩存帴鍒锋柊鏂囨。鍒楄〃
+      if (!this.currentRightClickedTableRowInfo.hasOwnProperty('docId')) {
+        if (this.currentRightClickedTableRowInfo.hasOwnProperty('deviceManagementId')) {
+          // 姝ょ鎯呭喌鏄湪寮曞叆璁惧绫诲苟鍦ㄨ澶囩被鍒楄〃涓繘琛孨C鏂囨。瀵煎叆
+          if (this.currentClickedTypeInfo.id !== attributionId) return
+        } else {
+          // 姝ょ鎯呭喌鏄湪缁撴瀯鏍戣妭鐐逛笂杩涜鏂囨。瀵煎叆
+          if (this.currentTreeNodeInfo.id !== attributionId) return
+        }
       }
+
       if (docClassCode === 'NC') {
         this.$nextTick(() => {
           if (this.$refs.ncDocumentTableListRef) this.$refs.ncDocumentTableListRef.loadData(1)
@@ -432,7 +444,7 @@
     },
 
     /**
-     * 閲嶅綊妗e綋鍓嶅彸閿�変腑鏂囨。涓斿悗缁棤娉曠户缁彂甯冩垨褰掓。
+     * 褰掓。褰撳墠鍙抽敭閫変腑鏂囨。涓斿悗缁棤娉曠户缁彂甯冩垨褰掓。
      * @param menuLabel
      */
     handlePigeonhole(menuLabel) {
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue
index 3fea23d..7e5bd4b 100644
--- a/src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue
@@ -1,17 +1,17 @@
 <template>
-  <a-card class="tree_con" :loading="cardLoading" :bordered="false" @contextmenu.native="e=>e.preventDefault()">
+  <a-card class="tree_con" :loading="cardLoading" :bordered="false" @contextmenu.native.stop="openBaseContextMenu">
     <a-spin :spinning="loading">
       <div style="display: flex;flex-direction: column;height: 100%">
         <div style="display: flex;justify-content: space-between">
           <a-input placeholder="杈撳叆鍏抽敭瀛楄繘琛屾悳绱�" allowClear v-model="searchInput"
                    @change="handleSearchInputChange"/>
-          <a-tooltip title="鍒锋柊">
-            <a-button icon="reload" @click="getTreeDataByApi" style="width: 18%;margin-left: 8px"></a-button>
-          </a-tooltip>
-          <a-button type="primary" v-has="'product_add'" icon="plus" style="margin-left: 8px"
-                    @click="$refs.productModalFormRef.triggerCorrespondingMethod({modalTitle:'娣诲姞浜у搧',methodName:'handleProductAdd'})">
-            浜у搧
-          </a-button>
+          <!--          <a-tooltip title="鍒锋柊">-->
+          <!--            <a-button icon="reload" @click="handleTreeReload" style="width: 18%;margin-left: 8px"></a-button>-->
+          <!--          </a-tooltip>-->
+          <!--          <a-button type="primary" v-has="'product_add'" icon="plus" style="margin-left: 8px"-->
+          <!--                    @click="$refs.productModalFormRef.triggerCorrespondingMethod({modalTitle:'娣诲姞浜у搧',methodName:'handleProductAdd'})">-->
+          <!--            浜у搧-->
+          <!--          </a-button>-->
           <!--          <a-dropdown :trigger="['click']" placement="bottomCenter" style="margin: 0 8px">-->
           <!--            <a-menu slot="overlay">-->
           <!--              <a-menu-item key="1" @click="expandedKeys = allTreeKeys">灞曞紑鎵�鏈�</a-menu-item>-->
@@ -25,7 +25,7 @@
         </div>
 
         <!--浜у搧缁撴瀯鏍�-->
-        <div style="flex: 1;overflow:auto;margin-top: 10px">
+        <div id="tree-container" style="flex: 1;overflow:auto;margin-top: 10px">
           <a-tree blockNode show-icon :expandedKeys.sync="expandedKeys"
                   :selectedKeys="selectedKeys" :treeData="treeDataSource" :autoExpandParent="autoExpandParent"
                   @select="handleTreeSelect" @expand="handleTreeExpand" @rightClick="handleTreeRightClick">
@@ -61,6 +61,8 @@
     <ProcessStepModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
     <!--鏉冮檺閰嶇疆寮圭獥-->
     <AssignPermissionModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
+    <!--浜у搧缁撴瀯鏍戝熀鏈彸閿彍鍗�(绌虹櫧澶勮Е鍙�)-->
+    <ProductStructureBaseContextMenu ref="baseContextmenuRef"/>
   </a-card>
 </template>
 
@@ -76,10 +78,13 @@
 import ProcessStepModal from './ProcessStep/ProcessStepModal'
 import AssignPermissionModal from './Permission/AssignPermissionModal'
 import DeviceCustomTypeModal from '@views/dnc/base/modules/ProductStructure/DeviceCustomType/DeviceCustomTypeModal.vue'
+import ProductStructureBaseContextMenu
+  from '@views/dnc/base/modules/ProductStructure/ProductStructureBaseContextMenu.vue'
 
 export default {
   name: 'ProductStructureTree',
   components: {
+    ProductStructureBaseContextMenu,
     DeviceCustomTypeModal,
     AssignPermissionModal,
     ProcessStepModal,
@@ -118,6 +123,7 @@
     this.$bus.$off('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
   },
   methods: {
+    // 璋冪敤鎺ュ彛鑾峰彇鏍戠殑鏁版嵁
     getTreeDataByApi() {
       this.loading = true
       this.cardLoading = true
@@ -180,6 +186,7 @@
      * @param node 鑺傜偣瀵硅薄
      */
     handleTreeRightClick({ node }) {
+      if (this.$refs.baseContextmenuRef) this.$refs.baseContextmenuRef.menuVisible = false
       const that = this
       const record = node.dataRef
       const { id, type } = record
@@ -339,8 +346,17 @@
       }
     },
 
-    triggerCorrespondingMethod({ methodName }) {
-      if (this[methodName]) this[methodName]()
+    /**
+     * 鏍戞墍鍦ㄧ埗鍏冪礌鐨勫彸閿簨浠�
+     * @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)
     },
 
     /**
@@ -369,7 +385,23 @@
           break
         default:
       }
+    },
+
+    // 鎺у埗鍩虹鍙抽敭鑿滃崟鍏抽棴
+    handleBaseContextMenuClose() {
+      this.$refs.baseContextmenuRef.menuVisible = false
+      document.body.removeEventListener('click', this.handleBaseContextMenuClose)
+    },
+
+    // 鍒锋柊閲嶆柊鑾峰彇鏍戠殑鏁版嵁
+    handleTreeReload() {
+      this.getTreeDataByApi()
+    },
+
+    triggerCorrespondingMethod({ methodName }) {
+      if (this[methodName]) this[methodName]()
     }
+
   }
 }
 </script>
diff --git a/src/views/dnc/common/ImportFileModal.vue b/src/views/dnc/common/ImportFileModal.vue
index 250c3b4..10be07c 100644
--- a/src/views/dnc/common/ImportFileModal.vue
+++ b/src/views/dnc/common/ImportFileModal.vue
@@ -7,7 +7,7 @@
       </a-button>
     </a-upload>
 
-    <div style="margin-top: 16px">宸查�夋嫨{{fileList.length}}涓枃浠�</div>
+    <div style="margin-top: 16px">宸查�夋嫨{{ fileList.length }}涓枃浠�</div>
 
     <template slot="footer">
       <a-button @click="handleModalClose">鍙栨秷</a-button>
@@ -26,197 +26,195 @@
 </template>
 
 <script>
-  import dncApi from '@/api/dnc'
+import dncApi from '@/api/dnc'
 
-  export default {
-    name: 'ImportFileModal',
-    components: {},
-    data() {
-      return {
-        visible: false,
-        title: '',
-        fileList: [],
-        uploadParams: {},
-        uploading: false,
-        isUploadMultiple: true,
-        currentDeviceDocClassCode: 'SEND',
-        currentTitleAfterClass: ''
+export default {
+  name: 'ImportFileModal',
+  components: {},
+  data() {
+    return {
+      visible: false,
+      title: '',
+      fileList: [],
+      uploadParams: {},
+      uploading: false,
+      isUploadMultiple: true,
+      currentDeviceDocClassCode: 'SEND',
+      currentTitleAfterClass: ''
+    }
+  },
+  created() {
+    this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+  },
+  methods: {
+    /**
+     * 鐐瑰嚮瀵煎叆鏂囨。鎴朜C绋嬪簭鏃惰Е鍙�
+     * @param treeNodeInfo 鐐瑰嚮鏍戣妭鐐瑰彸閿彍鍗曞鍏ョ▼搴忔椂浼犲叆鏍戣妭鐐逛俊鎭�
+     * @param tableRowInfo 鍙抽敭琛ㄦ牸琛屾椂浼犲叆琛屼俊鎭�
+     * @param modalTitle 寮圭獥鏍囬
+     */
+    handleImport(treeNodeInfo, tableRowInfo, modalTitle) {
+      this.isUploadMultiple = true
+      let attributionId // 鏂囨。鎵�灞炲眰绾d
+      let attributionType  // 鏂囨。鎵�灞炲眰绾х被鍨�
+      let docClassCode // 鏂囨。绫诲瀷
+      if (treeNodeInfo) {
+        attributionId = treeNodeInfo.treeKey
+        attributionType = treeNodeInfo.type
+        docClassCode = treeNodeInfo.param
+      } else {
+        // 鑻ュ伐搴忓強宸ユ灞傜骇涓嬫湁璁惧绫绘椂鍒欏鍏C鐨勫弬鏁伴渶瑕佽皟鏁�
+        attributionId = tableRowInfo.param === 'deviceCustomType' ? tableRowInfo.id : tableRowInfo.attributionId
+        attributionType = tableRowInfo.attributionType
+        docClassCode = tableRowInfo.param === 'deviceCustomType' ? 'NC' : tableRowInfo.param
+      }
+      this.setModalTitle(modalTitle, docClassCode)
+      this.uploadParams = Object.assign({}, { attributionId, attributionType, docClassCode })
+      console.log('uploadParams=====================', this.uploadParams)
+      this.visible = true
+    },
+
+    /**
+     * 鐐瑰嚮鏂囨。鐢熷懡鍛ㄦ湡鐨勫叆搴撴椂瑙﹀彂
+     * @param _
+     * @param tableRowInfo 鍙抽敭琛ㄦ牸琛屾椂浼犲叆琛屼俊鎭�
+     */
+    handlePush(_, tableRowInfo) {
+      this.isUploadMultiple = false
+      const { docId, attributionId, attributionType, param } = tableRowInfo
+      this.uploadParams = Object.assign({}, {
+        docId,
+        attributionId,
+        attributionType,
+        docClassCode: param
+      })
+      this.visible = true
+    },
+
+    /**
+     * 閫夋嫨濂芥枃浠剁偣鍑荤‘瀹氬悗
+     * @param file 鏂囦欢瀵硅薄
+     */
+    beforeUpload(file) {
+      if (this.isUploadMultiple) {
+        if (!this.fileList.find(item => item.name === file.name)) this.fileList = [...this.fileList, file]
+      } else this.fileList.splice(0, 1, file)
+      return false
+    },
+
+    // 鐐瑰嚮涓婁紶鑷虫湇鍔″櫒鎸夐挳鏃惰Е鍙�
+    handleUpload() {
+      const { fileList, $notification, isUploadMultiple, uploadParams, $bus, handleModalClose } = this
+      this.uploading = true
+      let uploadedFileCount = 0
+      let uploadSuccessFileCount = 0
+      let apiMethod,params
+
+      fileList.forEach((file, index) => {
+        const formData = new FormData()
+        formData.append('file', file)
+        file.status = 'uploading'
+        // 鐩墠鏍规嵁鏄惁涓婁紶澶氫釜鏂囦欢鍒ゆ柇涓や釜鍔熻兘锛岃嫢鍚庣画澧炲姞鍔熻兘鎴栬皟鏁撮渶姹傚垯璋冩暣鍒ゆ柇鏉′欢
+        if (isUploadMultiple) {
+          apiMethod = dncApi.importDocumentFromLocalApi
+          params = Object.assign({}, { params: uploadParams, formData })
+        } else {
+          apiMethod = dncApi.documentVersionUpdateApi
+          params = Object.assign({}, { docId: uploadParams.docId, formData })
+        }
+        apiMethod(params)
+          .then(res => {
+            if (res.success) {
+              file.status = 'done'
+              uploadSuccessFileCount++
+              $notification.success({
+                message: '娑堟伅',
+                description: res.message
+              })
+            } else {
+              file.status = 'error'
+              $notification.error({
+                message: '娑堟伅',
+                description: res.message
+              })
+            }
+          })
+          .catch(err => {
+            file.status = 'error'
+          })
+          .finally(() => {
+            uploadedFileCount++
+            fileList.splice(index, 1, file)
+            // 褰撴枃浠跺叏閮ㄤ笂浼犲畬鎴愬悗
+            if (uploadedFileCount === fileList.length) {
+              // 鑷冲皯鏈変竴涓枃浠朵笂浼犳垚鍔熷悗灏遍渶瑕侀噸鏂板姞杞芥枃妗e垪琛�
+              if (uploadSuccessFileCount > 0) {
+                $bus.$emit('reloadDocumentListData', uploadParams)
+                if (!isUploadMultiple) {
+                  $bus.$emit('reloadMainBottomTableData', 'documentVersion')
+                  handleModalClose() //鏃犳硶杩炵画鍏ュ簱澶氫釜鐗堟湰鍥犳鍏ュ簱鎴愬姛鍚庡嵆鍙��鍑虹獥鍙�
+                }
+              }
+              this.uploading = false
+            }
+          })
+      })
+    },
+
+    /**
+     * 鍒犻櫎鏂囦欢鍒楄〃椤规椂瑙﹀彂
+     * @param file 鏂囦欢瀵硅薄
+     */
+    handleRemove(file) {
+      const index = this.fileList.indexOf(file)
+      const newFileList = this.fileList.slice()
+      newFileList.splice(index, 1)
+      this.fileList = newFileList
+    },
+
+    // 鎺у埗鏂囦欢涓婁紶绐楀彛鍏抽棴骞舵竻绌烘枃浠跺垪琛�
+    handleModalClose() {
+      this.visible = false
+      this.fileList = []
+    },
+
+    /**
+     * 璁剧疆寮圭獥鏍囬
+     * @param modalTitle 寮圭獥鏍囬
+     * @param docClassCode 鏂囨。绫诲瀷
+     */
+    setModalTitle(modalTitle, docClassCode) {
+      switch (docClassCode) {
+        case 'SEND':
+          this.title = modalTitle + '锛堝彂閫侊級'
+          break
+        case 'REC':
+          this.title = modalTitle + '锛堟帴鏀讹級'
+          break
       }
     },
-    created() {
-      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
-      this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
-    },
-    methods: {
-      /**
-       * 鐐瑰嚮瀵煎叆鏂囨。鎴朜C绋嬪簭鏃惰Е鍙�
-       * @param treeNodeInfo 鐐瑰嚮鏍戣妭鐐瑰彸閿彍鍗曞鍏ョ▼搴忔椂浼犲叆鏍戣妭鐐逛俊鎭�
-       * @param tableRowInfo 鍙抽敭琛ㄦ牸琛屾椂浼犲叆琛屼俊鎭�
-       * @param modalTitle 寮圭獥鏍囬
-       */
-      handleImport(treeNodeInfo, tableRowInfo, modalTitle) {
-        this.isUploadMultiple = true
-        let attributionId // 鏂囨。鎵�灞炲眰绾d
-        let attributionType  // 鏂囨。鎵�灞炲眰绾х被鍨�
-        let docClassCode // 鏂囨。绫诲瀷
-        if (treeNodeInfo) {
-          attributionId = treeNodeInfo.treeKey
-          attributionType = treeNodeInfo.type
-          docClassCode = treeNodeInfo.param
-        } else {
-          // 鑻ュ伐搴忓強宸ユ灞傜骇涓嬫湁璁惧绫绘椂鍒欏鍏C鐨勫弬鏁伴渶瑕佽皟鏁�
-          attributionId = tableRowInfo.param==='deviceCustomType'?tableRowInfo.id:tableRowInfo.attributionId
-          attributionType = tableRowInfo.attributionType
-          docClassCode = tableRowInfo.param==='deviceCustomType'?'NC':tableRowInfo.param
-        }
-        this.setModalTitle(modalTitle, docClassCode)
-        this.uploadParams = Object.assign({}, { attributionId, attributionType, docClassCode })
-        console.log('uploadParams=====================', this.uploadParams)
-        this.visible = true
-      },
 
-      /**
-       * 鐐瑰嚮鏂囨。鐢熷懡鍛ㄦ湡鐨勫叆搴撴椂瑙﹀彂
-       * @param _
-       * @param tableRowInfo 鍙抽敭琛ㄦ牸琛屾椂浼犲叆琛屼俊鎭�
-       */
-      handlePush(_, tableRowInfo) {
-        this.isUploadMultiple = false
-        console.log('tableRowInfo', tableRowInfo)
-        this.uploadParams = Object.assign({}, {
-          docId: tableRowInfo.docId,
-          attributionId: tableRowInfo.attributionId,
-          docClassCode: tableRowInfo.param
-        })
-        this.visible = true
-      },
-
-      /**
-       * 閫夋嫨濂芥枃浠剁偣鍑荤‘瀹氬悗
-       * @param file 鏂囦欢瀵硅薄
-       */
-      beforeUpload(file) {
-        if (this.isUploadMultiple) {
-          if (!this.fileList.find(item => item.name === file.name)) this.fileList = [...this.fileList, file]
-        }
-        else this.fileList.splice(0, 1, file)
-        return false
-      },
-
-      // 鐐瑰嚮涓婁紶鑷虫湇鍔″櫒鎸夐挳鏃惰Е鍙�
-      handleUpload() {
-        const { fileList, $notification, isUploadMultiple, uploadParams, $bus, handleModalClose } = this
-        this.uploading = true
-        let uploadedFileCount = 0
-        let uploadSuccessFileCount = 0
-        let apiMethod
-        let params
-
-        fileList.forEach((file, index) => {
-          const formData = new FormData()
-          formData.append('file', file)
-          file.status = 'uploading'
-          // 鐩墠鏍规嵁鏄惁涓婁紶澶氫釜鏂囦欢鍒ゆ柇涓や釜鍔熻兘锛岃嫢鍚庣画澧炲姞鍔熻兘鎴栬皟鏁撮渶姹傚垯璋冩暣鍒ゆ柇鏉′欢
-          if (isUploadMultiple) {
-            apiMethod = dncApi.importDocumentFromLocalApi
-            params = Object.assign({}, { params: uploadParams, formData })
-          } else {
-            apiMethod = dncApi.documentVersionUpdateApi
-            params = Object.assign({}, { docId: uploadParams.docId, formData })
-          }
-          apiMethod(params)
-            .then(res => {
-              if (res.success) {
-                file.status = 'done'
-                uploadSuccessFileCount++
-                console.log('uploadSuccessFileCount++', uploadSuccessFileCount)
-                $notification.success({
-                  message: '娑堟伅',
-                  description: res.message
-                })
-              } else {
-                file.status = 'error'
-                $notification.error({
-                  message: '娑堟伅',
-                  description: res.message
-                })
-              }
-            })
-            .catch(err => {
-              file.status = 'error'
-            })
-            .finally(() => {
-              uploadedFileCount++
-              fileList.splice(index, 1, file)
-              // 褰撴枃浠跺叏閮ㄤ笂浼犲畬鎴愬悗
-              if (uploadedFileCount === fileList.length) {
-                // 鑷冲皯鏈変竴涓枃浠朵笂浼犳垚鍔熷悗灏遍渶瑕侀噸鏂板姞杞芥枃妗e垪琛�
-                if (uploadSuccessFileCount > 0) {
-                  $bus.$emit('reloadDocumentListData', uploadParams)
-                  if (!isUploadMultiple) {
-                    $bus.$emit('reloadMainBottomTableData', 'documentVersion')
-                    handleModalClose() //鏃犳硶杩炵画鍏ュ簱澶氫釜鐗堟湰鍥犳鍏ュ簱鎴愬姛鍚庡嵆鍙��鍑虹獥鍙�
-                  }
-                }
-                this.uploading = false
-              }
-            })
-        })
-      },
-
-      /**
-       * 鍒犻櫎鏂囦欢鍒楄〃椤规椂瑙﹀彂
-       * @param file 鏂囦欢瀵硅薄
-       */
-      handleRemove(file) {
-        const index = this.fileList.indexOf(file)
-        const newFileList = this.fileList.slice()
-        newFileList.splice(index, 1)
-        this.fileList = newFileList
-      },
-
-      // 鎺у埗鏂囦欢涓婁紶绐楀彛鍏抽棴骞舵竻绌烘枃浠跺垪琛�
-      handleModalClose() {
-        this.visible = false
-        this.fileList = []
-      },
-
-      /**
-       * 璁剧疆寮圭獥鏍囬
-       * @param modalTitle 寮圭獥鏍囬
-       * @param docClassCode 鏂囨。绫诲瀷
-       */
-      setModalTitle(modalTitle, docClassCode) {
-        switch (docClassCode) {
-          case 'SEND':
-            this.title = modalTitle + '锛堝彂閫侊級'
-            break
-          case 'REC':
-            this.title = modalTitle + '锛堟帴鏀讹級'
-            break
-        }
-      },
-
-      triggerCorrespondingMethod({ methodName, modalTitle, treeNodeInfo, tableRowInfo }) {
-        if (this[methodName]) {
-          this.title = modalTitle
-          this[methodName](treeNodeInfo, tableRowInfo, modalTitle)
-        }
+    triggerCorrespondingMethod({ methodName, modalTitle, treeNodeInfo, tableRowInfo }) {
+      if (this[methodName]) {
+        this.title = modalTitle
+        this[methodName](treeNodeInfo, tableRowInfo, modalTitle)
       }
     }
   }
+}
 </script>
 
 <style scoped lang="less">
-  /deep/ .ant-btn-primary#custom-upload-button {
-    color: #fff;
-    background-color: #67C23A;
-    border-color: #67C23A;
+/deep/ .ant-btn-primary#custom-upload-button {
+  color: #fff;
+  background-color: #67C23A;
+  border-color: #67C23A;
 
-    &[disabled] {
-      color: rgba(0, 0, 0, 0.25);
-      background-color: #f5f5f5;
-      border-color: #d9d9d9;
-    }
+  &[disabled] {
+    color: rgba(0, 0, 0, 0.25);
+    background-color: #f5f5f5;
+    border-color: #d9d9d9;
   }
+}
 </style>
\ No newline at end of file
diff --git a/src/views/mdc/base/OEEAnalysis.vue b/src/views/mdc/base/OEEAnalysis.vue
new file mode 100644
index 0000000..28654a1
--- /dev/null
+++ b/src/views/mdc/base/OEEAnalysis.vue
@@ -0,0 +1,82 @@
+<template>
+  <div style="width: 100%; height: 100%;">
+    <a-card :bordered="false">
+      <a-row type="flex" :gutter="16">
+        <a-col :md="5">
+          <a-tabs :activeKey="activeKey" @change="tabChange">
+            <a-tab-pane key="1" tab="杞﹂棿灞傜骇" force-render>
+              <base-tree @getCurrSelected="changeSelectionNode"></base-tree>
+            </a-tab-pane>
+            <a-tab-pane v-if="isDepartType == 0" key="2" tab="閮ㄩ棬灞傜骇">,
+              <depart-tree @getCurrSelectedDD="changeSelectionNodedd"></depart-tree>
+            </a-tab-pane>
+          </a-tabs>
+        </a-col>
+        <a-col :md="19">
+          <OEEAnalysisList :nodePeople='selectPeople' :nodeTree='selectEquipment' :Type="selectTypeTree"/>
+        </a-col>
+      </a-row>
+    </a-card>
+  </div>
+
+</template>
+
+<script>
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import BaseTree from '../common/BaseTree'
+  import OEEAnalysisList from './modules/OEEAnalysis/OEEAnalysisList'
+  import DepartTree from './modules/DepartList/DepartListTree/DepartTree'
+  import { mapActions } from 'vuex'
+
+  export default {
+    name: 'OEEAnalysis',
+    components: {
+      BaseTree,
+      DepartTree,
+      OEEAnalysisList
+    },
+    data() {
+      return {
+        activeKey: '1',
+        selectEquipmentId: '',
+        selectEquipment: {},
+        selectPeople: {},
+        selectTypeTree: '',
+        isDepartType: ''
+      }
+    },
+    created() {
+      this.queryTreeData()
+    },
+    methods: {
+      ...mapActions(['QueryDepartTree']),
+      queryTreeData() {
+        this.QueryDepartTree().then(res => {
+          if (res.success) {
+            this.isDepartType = res.result[0].value
+          } else {
+            // this.$message.warn(res.message)
+            this.$notification.warning({
+              message: '娑堟伅',
+              description: res.message
+            })
+          }
+        }).finally(() => {
+        })
+      },
+      tabChange(val) {
+        this.activeKey = val
+        this.selectTypeTree = val
+      },
+      changeSelectionNode(val) {
+        this.selectEquipment = val
+        this.selectTypeTree = '1'
+      },
+      changeSelectionNodedd(val) {
+        this.selectPeople = val
+        this.selectTypeTree = '2'
+      }
+    }
+
+  }
+</script>
\ No newline at end of file
diff --git a/src/views/mdc/base/PartsMatchingManagement.vue b/src/views/mdc/base/PartsMatchingManagement.vue
new file mode 100644
index 0000000..c5f50a5
--- /dev/null
+++ b/src/views/mdc/base/PartsMatchingManagement.vue
@@ -0,0 +1,82 @@
+<template>
+  <div style="width: 100%; height: 100%;">
+    <a-card :bordered="false">
+      <a-row type="flex" :gutter="16">
+        <a-col :md="5">
+          <a-tabs :activeKey="activeKey" @change="tabChange">
+            <a-tab-pane key="1" tab="杞﹂棿灞傜骇" force-render>
+              <base-tree @getCurrSelected="changeSelectionNode"></base-tree>
+            </a-tab-pane>
+            <a-tab-pane v-if="isDepartType == 0" key="2" tab="閮ㄩ棬灞傜骇">,
+              <depart-tree @getCurrSelectedDD="changeSelectionNodedd"></depart-tree>
+            </a-tab-pane>
+          </a-tabs>
+        </a-col>
+        <a-col :md="19">
+          <PartsMatchingList :nodePeople='selectPeople' :nodeTree='selectEquipment' :Type="selectTypeTree"/>
+        </a-col>
+      </a-row>
+    </a-card>
+  </div>
+
+</template>
+
+<script>
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import BaseTree from '../common/BaseTree'
+  import PartsMatchingList from './modules/PartsMatchingManagement/PartsMatchingList'
+  import DepartTree from './modules/DepartList/DepartListTree/DepartTree'
+  import { mapActions } from 'vuex'
+
+  export default {
+    name: 'PartsMatchingManagement',
+    components: {
+      BaseTree,
+      DepartTree,
+      PartsMatchingList
+    },
+    data() {
+      return {
+        activeKey: '1',
+        selectEquipmentId: '',
+        selectEquipment: {},
+        selectPeople: {},
+        selectTypeTree: '',
+        isDepartType: ''
+      }
+    },
+    created() {
+      this.queryTreeData()
+    },
+    methods: {
+      ...mapActions(['QueryDepartTree']),
+      queryTreeData() {
+        this.QueryDepartTree().then(res => {
+          if (res.success) {
+            this.isDepartType = res.result[0].value
+          } else {
+            // this.$message.warn(res.message)
+            this.$notification.warning({
+              message: '娑堟伅',
+              description: res.message
+            })
+          }
+        }).finally(() => {
+        })
+      },
+      tabChange(val) {
+        this.activeKey = val
+        this.selectTypeTree = val
+      },
+      changeSelectionNode(val) {
+        this.selectEquipment = val
+        this.selectTypeTree = '1'
+      },
+      changeSelectionNodedd(val) {
+        this.selectPeople = val
+        this.selectTypeTree = '2'
+      }
+    }
+
+  }
+</script>
\ No newline at end of file
diff --git a/src/views/mdc/base/modules/OEEAnalysis/ComputeOeeModal.vue b/src/views/mdc/base/modules/OEEAnalysis/ComputeOeeModal.vue
new file mode 100644
index 0000000..1445eee
--- /dev/null
+++ b/src/views/mdc/base/modules/OEEAnalysis/ComputeOeeModal.vue
@@ -0,0 +1,88 @@
+<template>
+  <a-modal title="璁$畻OEE" :visible="visible" :width="550" @cancel="handleModalClose" @ok="handleComputeOee"
+           :maskClosable="false">
+    <a-form-model :model="model" :labelCol="labelColLong" :wrapperCol="wrapperColLong">
+      <a-row>
+        <a-col :span="24">
+          <a-form-model-item label="鏃ユ湡">
+            <a-range-picker v-model="dates" style="width: 100%" value-format="YYYY-MM-DD"
+                            @change="dateParamChange"></a-range-picker>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+    </a-form-model>
+  </a-modal>
+</template>
+
+<script>
+  import mdcApi from '@/api/mdc'
+
+  export default {
+    name: 'ComputeOeeModal',
+    components: {},
+    data() {
+      return {
+        visible: false,
+        model: {},
+        dates: [],
+        labelColLong: {
+          xs: { span: 24 },
+          sm: { span: 3 }
+        },
+        wrapperColLong: {
+          xs: { span: 24 },
+          sm: { span: 21 }
+        }
+      }
+    },
+    methods: {
+      handleComputeOee() {
+        console.log('model', this.model)
+        if (this.dates.length === 0) {
+          this.$notification.warning({
+            message: '娑堟伅',
+            description: '璇烽�夋嫨鏃堕棿'
+          })
+          return
+        }
+
+        mdcApi.computeOeeApi(this.model)
+          .then(res => {
+            if (res.success) {
+              this.$notification.success({
+                message: '娑堟伅',
+                description: res.message
+              })
+              this.visible = false
+            } else {
+              this.$notification.error({
+                message: '娑堟伅',
+                description: '璁$畻澶辫触'
+              })
+            }
+          })
+          .catch(err => {
+            this.$notification.error({
+              message: '娑堟伅',
+              description: '璁$畻澶辫触'
+            })
+          })
+      },
+
+      dateParamChange(value1, value2) {
+        this.model.startTime = value2[0]
+        this.model.endTime = value2[1]
+      },
+
+      handleModalClose() {
+        this.visible = false
+        this.model = {}
+        this.dates = []
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/mdc/base/modules/OEEAnalysis/OEEAnalysisList.vue b/src/views/mdc/base/modules/OEEAnalysis/OEEAnalysisList.vue
new file mode 100644
index 0000000..b09a6a0
--- /dev/null
+++ b/src/views/mdc/base/modules/OEEAnalysis/OEEAnalysisList.vue
@@ -0,0 +1,304 @@
+<template>
+  <div class="device_list">
+    <!-- 鏌ヨ鍖哄煙 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="searchQuery">
+        <a-row :gutter="24">
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="璁惧缂栧彿">
+              <a-input placeholder="璇疯緭鍏ヨ澶囩紪鍙�" v-model="queryParam.equipmentId"/>
+            </a-form-item>
+          </a-col>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="鏃ユ湡">
+              <a-range-picker v-model="dates" style="width: 100%" @change="dateParamChange"></a-range-picker>
+            </a-form-item>
+          </a-col>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-space>
+              <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload">閲嶇疆</a-button>
+            </a-space>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 鏌ヨ鍖哄煙-END -->
+
+    <!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
+    <div class="table-operator">
+      <a-button type="primary" icon="download" @click="handleExportXls('OEE')">瀵煎嚭</a-button>
+      <a-button type="primary" icon="edit" @click="handleComputeModalOpen">璁$畻</a-button>
+    </div>
+
+    <!-- table鍖哄煙-begin -->
+    <div id="DeviceList" style="flex: 1;overflow: hidden">
+      <a-table
+        ref="table"
+        size="middle"
+        :scroll="{x:'max-content',y:scrollY}"
+        bordered
+        rowKey="id"
+        :columns="columns"
+        :dataSource="dataSource"
+        :pagination="ipagination"
+        :loading="loading">
+        <template slot="percent" slot-scope="text">
+          {{text+'%'}}
+        </template>
+      </a-table>
+    </div>
+
+    <ComputeOeeModal ref="computeOeeModalRef"/>
+  </div>
+</template>
+
+<script>
+  import moment from 'moment'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import ComputeOeeModal from './ComputeOeeModal'
+
+  export default {
+    name: 'OEEAnalysisList',
+    mixins: [JeecgListMixin],
+    components: { ComputeOeeModal },
+    props: { nodeTree: '', Type: '', nodePeople: '' },
+    data() {
+      return {
+        description: 'OEE椤甸潰',
+        disableMixinCreated: true,
+        /* 鍒嗛〉鍙傛暟 */
+        ipagination: {
+          current: 1,
+          pageSize: 30,
+          pageSizeOptions: ['30', '50', '100'],
+          showTotal: (total, range) => {
+            return range[0] + '-' + range[1] + ' 鍏�' + total + '鏉�'
+          },
+          showQuickJumper: true,
+          showSizeChanger: true,
+          total: 0
+        },
+        dates: [moment().subtract(1, 'day'), moment()],
+        queryParam: {},
+        // 琛ㄥご
+        columns: [
+          {
+            title: '#',
+            dataIndex: '',
+            key: 'rowIndex',
+            width: 60,
+            align: 'center',
+            customRender: function(t, r, index) {
+              return parseInt(index) + 1
+            }
+          },
+          {
+            title: '璁惧缂栧彿',
+            align: 'center',
+            dataIndex: 'equipmentId',
+            width: 230
+          },
+          {
+            title: '鏃ユ湡',
+            align: 'center',
+            dataIndex: 'theDate',
+            width: 150
+          },
+          {
+            title: '鏃ュ巻宸ヤ綔鏃堕棿(min)',
+            align: 'center',
+            dataIndex: 'calendarLong',
+            width: 150
+          },
+          {
+            title: '璁″垝鍋滄満鏃堕棿(min)',
+            align: 'center',
+            dataIndex: 'planCloseLong',
+            width: 150
+          },
+          {
+            title: '璐熻嵎鏃堕棿(min)',
+            align: 'center',
+            dataIndex: 'loadLong',
+            width: 150
+          },
+          {
+            title: '闈炶鍒掑仠鏈烘椂闂�(min)',
+            align: 'center',
+            dataIndex: 'noplanCloseLong',
+            width: 150
+          },
+          {
+            title: '寮�鍔ㄦ椂闂�(min)',
+            align: 'center',
+            dataIndex: 'actuateLong',
+            width: 150
+          },
+          {
+            title: '鏃堕棿寮�鍔ㄧ巼',
+            align: 'center',
+            dataIndex: 'timeActuationRate',
+            width: 150,
+            scopedSlots: { customRender: 'percent' }
+          },
+          {
+            title: '鏈夋晥杩愯鏃堕棿(min)',
+            align: 'center',
+            dataIndex: 'effectiveRunLong',
+            width: 150
+          },
+          {
+            title: '鎬ц兘寮�鍔ㄧ巼',
+            align: 'center',
+            dataIndex: 'performanceRate',
+            width: 150,
+            scopedSlots: { customRender: 'percent' }
+          },
+          {
+            title: '鍔犲伐闆朵欢鏁伴噺',
+            align: 'center',
+            dataIndex: 'processCount',
+            width: 150
+          },
+          {
+            title: '鍚堟牸闆朵欢鏁伴噺',
+            align: 'center',
+            dataIndex: 'passCount',
+            width: 150
+          },
+          {
+            title: '涓�娆″悎鏍肩巼',
+            align: 'center',
+            dataIndex: 'passRate',
+            width: 150,
+            scopedSlots: { customRender: 'percent' }
+          },
+          {
+            title: 'OEE',
+            align: 'center',
+            dataIndex: 'oee',
+            width: 150,
+            scopedSlots: { customRender: 'percent' }
+          }
+        ],
+        scrollY: 465,
+        url: {
+          list: '/mdc/mdcOeeInfo/list',
+          exportXlsUrl: '/mdc/mdcOeeInfo/exportXls'
+        }
+      }
+    },
+    watch: {
+      Type(valmath) {
+        this.dataList = []
+        this.queryParam.typeTree = valmath
+        // console.log(this.queryParam.typeTree)
+      },
+      nodeTree(val) { //鐩戝惉currSelected 鍙樺寲锛屽皢鍙樺寲鍚庣殑鏁板�间紶閫掔粰 getCurrSelected 浜嬩欢
+        if (JSON.stringify(val) != '{}') {
+          if (val.equipmentId) {
+            this.queryParam.parentId = ''
+            this.queryParam.equipmentId = val.equipmentId
+          } else {
+            this.queryParam.parentId = val.key
+            this.queryParam.equipmentId = ''
+          }
+          this.searchQuery()
+        }
+      },
+      nodePeople(val) {
+        if (JSON.stringify(val) != '{}') {
+          if (val.equipmentId) {
+            this.queryParam.parentId = ''
+            this.queryParam.equipmentId = val.equipmentId
+          } else {
+            this.queryParam.parentId = val.key
+            this.queryParam.equipmentId = ''
+          }
+          this.searchQuery()
+        }
+      }
+    },
+    methods: {
+      handleComputeModalOpen() {
+        this.$refs.computeOeeModalRef.visible = true
+      },
+
+      dateParamChange(v1, v2) {
+        this.queryParam.startTime = v2[0]
+        this.queryParam.endTime = v2[1]
+        this.dates = [v1[0], v1[1]]
+      },
+
+      searchReset() {
+        this.dates = [moment().subtract(1, 'day'), moment()]
+        this.queryParam = {
+          startTime: this.dates[0].format('YYYY-MM-DD'),
+          endTime: this.dates[1].format('YYYY-MM-DD')
+        }
+        this.loadData(1)
+      },
+
+      /**
+       * 褰撴祻瑙堝櫒鍙绐楀彛灏哄鍙戠敓鏀瑰彉鏃惰Е鍙�
+       */
+      handleWindowResize() {
+        const boxHeight = +window.getComputedStyle(document.getElementById('DeviceList')).height.slice(0, -2)
+        const tableHeadHeight = +window.getComputedStyle(document.querySelector('.ant-table-thead th')).height.slice(0, -2)
+        this.scrollY = boxHeight - tableHeadHeight - 50
+      }
+    },
+    created() {
+      this.queryParam.startTime = this.dates[0].format('YYYY-MM-DD')
+      this.queryParam.endTime = this.dates[1].format('YYYY-MM-DD')
+      this.loadData()
+    },
+    mounted() {
+      window.addEventListener('resize', this.handleWindowResize)
+      this.handleWindowResize()
+    },
+    beforeDestroy() {
+      window.removeEventListener('resize', this.handleWindowResize)
+    }
+  }
+</script>
+<style scoped>
+  @import '~@assets/less/common.less';
+
+  .device_list {
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+  }
+
+  @media screen and (min-width: 1920px) {
+    .device_list {
+      height: 811px !important;
+    }
+  }
+
+  @media screen and (min-width: 1680px) and (max-width: 1920px) {
+    .device_list {
+      height: 811px !important;
+    }
+  }
+
+  @media screen and (min-width: 1400px) and (max-width: 1680px) {
+    .device_list {
+      height: 663px !important;
+    }
+  }
+
+  @media screen and (min-width: 1280px) and (max-width: 1400px) {
+    .device_list {
+      height: 564px !important;
+    }
+  }
+
+  @media screen and (max-width: 1280px) {
+    .device_list {
+      height: 564px !important;
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingForm.vue b/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingForm.vue
new file mode 100644
index 0000000..444bae8
--- /dev/null
+++ b/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingForm.vue
@@ -0,0 +1,191 @@
+<template>
+  <a-spin :spinning="confirmLoading">
+    <j-form-container :disabled="formDisabled">
+      <a-form-model ref="form" :model="model" :rules="validatorRules" slot="detail">
+        <a-row>
+          <a-col :span="24">
+            <a-form-model-item label="璁惧缁�" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="equipmentIds">
+              <a-input-search :readOnly="true" v-model="model.equipmentIds"
+                              @search="deviceSearch" :disabled="disableSelectDevice" enter-button
+                              placeholder="璇烽�夋嫨璁惧"></a-input-search>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="24">
+            <a-form-model-item label="闆朵欢鍙�" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="partId">
+              <a-input placeholder="璇疯緭鍏ラ浂浠跺彿" v-model="model.partId" allowClear/>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="24">
+            <a-form-model-item label="鏍囧噯鍔犲伐宸ユ椂(min)" :labelCol="labelCol" :wrapperCol="wrapperCol"
+                               prop="standardProcessLong">
+              <a-input-number :min="0" placeholder="璇疯緭鍏ユ爣鍑嗗姞宸ュ伐鏃�(min)" v-model="model.standardProcessLong"
+                              @change="inputNumberChange"/>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="24">
+            <a-form-model-item label="鍔犲伐闆朵欢鏁伴噺" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="processCount">
+              <a-input-number :min="0" v-model="model.processCount" placeholder="璇疯緭鍏ュ姞宸ラ浂浠舵暟閲�"
+                              @change="inputNumberChange"></a-input-number>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="24">
+            <a-form-model-item label="鍚堟牸闆朵欢鏁伴噺" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="passCount">
+              <a-input-number :min="0" v-model="model.passCount" placeholder="璇疯緭鍏ュ悎鏍奸浂浠舵暟閲�"></a-input-number>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="24">
+            <a-form-model-item label="鍔犲伐鎬绘椂闀�" :labelCol="labelCol" :wrapperCol="wrapperCol">
+              <a-input v-model="model.totalProcessLong" placeholder="鍔犲伐闆朵欢鏁伴噺 X 鏍囧噯鍔犲伐宸ユ椂" readOnly></a-input>
+            </a-form-model-item>
+          </a-col>
+          <a-col :span="24">
+            <a-form-model-item label="鏃ユ湡" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="theDate">
+              <a-date-picker v-model="model.theDate" :disabled="disabled" format="YYYY-MM-DD"
+                             value-format="YYYY-MM-DD" style="width: 100%"></a-date-picker>
+            </a-form-model-item>
+          </a-col>
+        </a-row>
+      </a-form-model>
+    </j-form-container>
+
+    <select-device-drawer ref="selectDeviceDrawer" @selectFinished="selectOK" :title="'閫夋嫨璁惧'"/>
+  </a-spin>
+</template>
+
+<script>
+  import { httpAction, getAction } from '@/api/manage'
+  import SelectDeviceDrawer from '@/views/system/modules/SelectDeviceDrawer'
+
+  export default {
+    name: 'PartsMatchingForm',
+    components: { SelectDeviceDrawer },
+    props: {
+      //琛ㄥ崟绂佺敤
+      disabled: {
+        type: Boolean,
+        default: false,
+        required: false
+      },
+      disableSelectDevice: {
+        type: Boolean,
+        default: false
+      }
+    },
+    data() {
+      return {
+        model: {
+          passCount: 0
+        },
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 5 }
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 16 }
+        },
+        confirmLoading: false,
+        validatorRules: {
+          equipmentIds: [
+            { required: true, message: '璇烽�夋嫨璁惧!' }
+          ],
+          partId: [
+            { required: true, message: '璇疯緭鍏ラ浂浠跺彿!' }
+          ],
+          standardProcessLong: [
+            { required: true, message: '璇疯緭鍏ユ爣鍑嗗姞宸ュ伐鏃�(min)!' }
+          ],
+          processCount: [
+            { required: true, message: '璇疯緭鍏ュ姞宸ラ浂浠舵暟閲�!' }
+          ],
+          passCount: [
+            { required: true, message: '璇疯緭鍏ュ悎鏍奸浂浠舵暟閲�!' }
+          ],
+          theDate: [
+            { required: true, message: '璇烽�夋嫨鏃ユ湡!' }
+          ]
+        },
+        url: {
+          add: '/mdc/mdcPartProcessInfo/add',
+          edit: '/mdc/mdcPartProcessInfo/edit'
+        }
+      }
+    },
+    computed: {
+      formDisabled() {
+        return this.disabled
+      }
+    },
+    created() {
+      //澶囦唤model鍘熷鍊�
+      this.modelDefault = JSON.parse(JSON.stringify(this.model))
+    },
+    methods: {
+      add() {
+        this.edit(this.modelDefault)
+      },
+      edit(record) {
+        this.model = Object.assign({}, { equipmentIds: record.equipmentId }, record)
+        console.log('model', this.model)
+        this.visible = true
+      },
+      inputNumberChange() {
+        if (this.model.standardProcessLong && this.model.processCount) {
+          this.model.totalProcessLong = this.model.standardProcessLong * this.model.processCount
+        }
+      },
+      submitForm() {
+        const that = this
+        // 瑙﹀彂琛ㄥ崟楠岃瘉
+        this.$refs.form.validate(valid => {
+          if (valid) {
+            that.confirmLoading = true
+            let httpUrl = ''
+            let method = 'post'
+            if (!this.model.id) {
+              httpUrl += this.url.add
+            } else {
+              httpUrl += this.url.edit
+            }
+            httpAction(httpUrl, this.model, method).then((res) => {
+              if (res.success) {
+                that.$notification.success({
+                  message: '娑堟伅',
+                  description: res.message
+                })
+                that.$emit('ok')
+              } else {
+                that.$notification.warning({
+                  message: '娑堟伅',
+                  description: res.message
+                })
+              }
+            }).finally(() => {
+              that.confirmLoading = false
+            })
+          }
+
+        })
+      },
+      deviceSearch() {
+        this.$refs.selectDeviceDrawer.visible = true
+        this.$refs.selectDeviceDrawer.selectedRowKeys = []
+        this.$refs.selectDeviceDrawer.selectedRows = []
+        this.$refs.selectDeviceDrawer.checkedKeys = this.model.equipmentIds ? this.model.equipmentIds.split(',') : []
+      },
+      /**
+       * 閫夋嫨宸叉湁璁惧鍚庣偣鍑荤‘瀹氭椂瑙﹀彂
+       * @param data 宸查�夋嫨鐨勮澶�
+       */
+      selectOK(data) {
+        this.$set(this.model, 'equipmentIds', data.join(','))
+        if (this.model.equipmentIds) this.$refs.form.clearValidate('equipmentIds')
+      }
+    }
+  }
+</script>
+<style scoped lang="less">
+  /deep/ .ant-input-number {
+    width: 100% !important;
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingList.vue b/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingList.vue
new file mode 100644
index 0000000..39c9988
--- /dev/null
+++ b/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingList.vue
@@ -0,0 +1,321 @@
+<template>
+  <div class="device_list">
+    <!-- 鏌ヨ鍖哄煙 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="searchQuery">
+        <a-row :gutter="24">
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="璁惧缂栧彿">
+              <a-input placeholder="璇疯緭鍏ヨ澶囩紪鍙�" v-model="queryParam.equipmentId"/>
+            </a-form-item>
+          </a-col>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="闆朵欢鍙�">
+              <a-input placeholder="璇疯緭鍏ラ浂浠跺彿" v-model="queryParam.partId" allowClear/>
+            </a-form-item>
+          </a-col>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="鏃ユ湡">
+              <a-range-picker v-model="dates" style="width: 100%" @change="dateParamChange"></a-range-picker>
+            </a-form-item>
+          </a-col>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-space>
+              <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload">閲嶇疆</a-button>
+            </a-space>
+          </a-col>
+        </a-row>
+      </a-form>
+    </div>
+    <!-- 鏌ヨ鍖哄煙-END -->
+
+    <!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
+    <div class="table-operator">
+      <a-button @click="handleAdd" type="primary" icon="plus">鏂板</a-button>
+      <a-button type="primary" icon="download" @click="importTemplate('闆朵欢鍔犲伐绠$悊')">瀵煎叆妯℃澘</a-button>
+      <a-button type="primary" icon="download" @click="handleExportXls('闆朵欢鍔犲伐绠$悊')">瀵煎嚭</a-button>
+      <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl"
+                @change="handleImportExcel">
+        <a-button type="primary" icon="import">瀵煎叆</a-button>
+      </a-upload>
+
+      <a-dropdown v-if="selectedRowKeys.length > 0">
+        <a-menu slot="overlay">
+          <a-menu-item key="1" @click="batchDel">
+            <a-icon type="delete"/>
+            鍒犻櫎
+          </a-menu-item>
+        </a-menu>
+        <a-button style="margin-left: 8px"> 鎵归噺鎿嶄綔
+          <a-icon type="down"/>
+        </a-button>
+      </a-dropdown>
+    </div>
+
+    <!-- table鍖哄煙-begin -->
+    <div id="DeviceList" style="flex: 1;overflow: hidden">
+      <a-table
+        ref="table"
+        size="middle"
+        :scroll="{x:'max-content',y:scrollY}"
+        bordered
+        rowKey="id"
+        :columns="columns"
+        :dataSource="dataSource"
+        :pagination="ipagination"
+        :loading="loading"
+        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+        class="j-table-force-nowrap"
+        @change="handleTableChange">
+
+        <span slot="action" slot-scope="text, record">
+          <a @click="handleEdit(record)">缂栬緫</a>
+
+          <a-divider type="vertical"/>
+          <a-dropdown>
+            <a class="ant-dropdown-link">鏇村 <a-icon type="down"/></a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a @click="handleDetail(record)">璇︽儏</a>
+              </a-menu-item>
+              <a-menu-item>
+                <a-popconfirm title="纭畾鍒犻櫎鍚�?" @confirm="() => handleDelete(record.id)">
+                  <a>鍒犻櫎</a>
+                </a-popconfirm>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+
+      </a-table>
+    </div>
+
+    <PartsMatchingModal ref="modalForm" @ok="modalFormOk"/>
+  </div>
+</template>
+
+<script>
+  import moment from 'moment'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import PartsMatchingModal from './PartsMatchingModal'
+
+  export default {
+    name: 'PartsMatchingList',
+    mixins: [JeecgListMixin],
+    components: {
+      PartsMatchingModal
+    },
+    props: { nodeTree: '', Type: '', nodePeople: '' },
+    data() {
+      return {
+        description: 'partsMatching绠$悊椤甸潰',
+        /* 鍒嗛〉鍙傛暟 */
+        ipagination: {
+          current: 1,
+          pageSize: 30,
+          pageSizeOptions: ['30', '50', '100'],
+          showTotal: (total, range) => {
+            return range[0] + '-' + range[1] + ' 鍏�' + total + '鏉�'
+          },
+          showQuickJumper: true,
+          showSizeChanger: true,
+          total: 0
+        },
+        queryParam: {},
+        disableMixinCreated: true,
+        dates: [moment().subtract(1, 'day'), moment()],
+        // 琛ㄥご
+        columns: [
+          {
+            title: '#',
+            dataIndex: '',
+            key: 'rowIndex',
+            width: 60,
+            align: 'center',
+            customRender: function(t, r, index) {
+              return parseInt(index) + 1
+            }
+          },
+          {
+            title: '鏃ユ湡',
+            align: 'center',
+            dataIndex: 'theDate',
+            width: 200
+          },
+          {
+            title: '璁惧缂栧彿',
+            align: 'center',
+            dataIndex: 'equipmentId',
+            width: 230
+          },
+          {
+            title: '闆朵欢鍙�',
+            align: 'center',
+            dataIndex: 'partId',
+            width: 150
+          },
+          {
+            title: '鏍囧噯鍔犲伐宸ユ椂(min)',
+            align: 'center',
+            dataIndex: 'standardProcessLong',
+            width: 150
+          },
+          {
+            title: '鍔犲伐闆朵欢鏁伴噺',
+            align: 'center',
+            dataIndex: 'processCount',
+            width: 150
+          },
+          {
+            title: '鍚堟牸闆朵欢鏁伴噺',
+            align: 'center',
+            dataIndex: 'passCount',
+            width: 150
+          },
+          {
+            title: '鍔犲伐鎬绘椂闀�',
+            align: 'center',
+            dataIndex: 'totalProcessLong',
+            width: 150
+          },
+          {
+            title: '鎿嶄綔',
+            dataIndex: 'action',
+            align: 'center',
+            fixed: 'right',
+            width: 150,
+            scopedSlots: { customRender: 'action' }
+          }
+        ],
+        scrollY: 465,
+        url: {
+          list: '/mdc/mdcPartProcessInfo/list',
+          delete: '/mdc/mdcPartProcessInfo/delete',
+          deleteBatch: '/mdc/mdcPartProcessInfo/deleteBatch',
+          exportXlsUrl: '/mdc/mdcPartProcessInfo/exportXls',
+          importExcelUrl: '/mdc/mdcPartProcessInfo/importExcel'
+        }
+      }
+    },
+    watch: {
+      Type(valmath) {
+        this.dataList = []
+        this.queryParam.typeTree = valmath
+        // console.log(this.queryParam.typeTree)
+      },
+      nodeTree(val) { //鐩戝惉currSelected 鍙樺寲锛屽皢鍙樺寲鍚庣殑鏁板�间紶閫掔粰 getCurrSelected 浜嬩欢
+        if (JSON.stringify(val) != '{}') {
+          if (val.equipmentId) {
+            this.queryParam.parentId = ''
+            this.queryParam.equipmentId = val.equipmentId
+          } else {
+            this.queryParam.parentId = val.key
+            this.queryParam.equipmentId = ''
+          }
+          this.searchQuery()
+        }
+      },
+      nodePeople(val) {
+        if (JSON.stringify(val) != '{}') {
+          if (val.equipmentId) {
+            this.queryParam.parentId = ''
+            this.queryParam.equipmentId = val.equipmentId
+          } else {
+            this.queryParam.parentId = val.key
+            this.queryParam.equipmentId = ''
+          }
+          this.searchQuery()
+        }
+      }
+    },
+    computed: {
+      importExcelUrl: function() {
+        return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`
+      }
+    },
+    methods: {
+      dateParamChange(v1, v2) {
+        this.queryParam.startTime = v2[0]
+        this.queryParam.endTime = v2[1]
+        this.dates = [v1[0], v1[1]]
+      },
+      importTemplate(fileName) {
+        var a = document.createElement('a')
+        a.href = `/static/${fileName}.xls`
+        a.download = `${fileName}.xls`
+        a.style.display = 'none'
+        document.body.appendChild(a)
+        a.click()
+        a.remove()
+      },
+      searchReset() {
+        this.dates = [moment().subtract(1, 'day'), moment()]
+        this.queryParam = {
+          startTime: this.dates[0].format('YYYY-MM-DD'),
+          endTime: this.dates[1].format('YYYY-MM-DD')
+        }
+        this.loadData(1)
+      },
+      /**
+       * 褰撴祻瑙堝櫒鍙绐楀彛灏哄鍙戠敓鏀瑰彉鏃惰Е鍙�
+       */
+      handleWindowResize() {
+        const boxHeight = +window.getComputedStyle(document.getElementById('DeviceList')).height.slice(0, -2)
+        const tableHeadHeight = +window.getComputedStyle(document.querySelector('.ant-table-thead th')).height.slice(0, -2)
+        this.scrollY = boxHeight - tableHeadHeight - 50
+      }
+    },
+    created() {
+      this.queryParam.startTime = this.dates[0].format('YYYY-MM-DD')
+      this.queryParam.endTime = this.dates[1].format('YYYY-MM-DD')
+      this.loadData()
+    },
+    mounted() {
+      window.addEventListener('resize', this.handleWindowResize)
+      this.handleWindowResize()
+    },
+    beforeDestroy() {
+      window.removeEventListener('resize', this.handleWindowResize)
+    }
+  }
+</script>
+<style scoped>
+  @import '~@assets/less/common.less';
+
+  .device_list {
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+  }
+
+  @media screen and (min-width: 1920px) {
+    .device_list {
+      height: 811px !important;
+    }
+  }
+
+  @media screen and (min-width: 1680px) and (max-width: 1920px) {
+    .device_list {
+      height: 811px !important;
+    }
+  }
+
+  @media screen and (min-width: 1400px) and (max-width: 1680px) {
+    .device_list {
+      height: 663px !important;
+    }
+  }
+
+  @media screen and (min-width: 1280px) and (max-width: 1400px) {
+    .device_list {
+      height: 564px !important;
+    }
+  }
+
+  @media screen and (max-width: 1280px) {
+    .device_list {
+      height: 564px !important;
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingModal.vue b/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingModal.vue
new file mode 100644
index 0000000..704d338
--- /dev/null
+++ b/src/views/mdc/base/modules/PartsMatchingManagement/PartsMatchingModal.vue
@@ -0,0 +1,64 @@
+<template>
+  <j-modal
+    :title="title"
+    :width="width"
+    :visible="visible"
+    switchFullscreen
+    @ok="handleOk"
+    :okButtonProps="{ class:{'jee-hidden': disableSubmit} }"
+    @cancel="handleCancel"
+    cancelText="鍏抽棴">
+    <PartsMatchingForm ref="realForm" @ok="submitCallback" :disabled="disableSubmit"
+                      :disableSelectDevice="disableSelectDevice"/>
+  </j-modal>
+</template>
+
+<script>
+  import PartsMatchingForm from './PartsMatchingForm'
+
+  export default {
+    name: 'PartsMatchingModal',
+    components: {
+      PartsMatchingForm
+    },
+    data() {
+      return {
+        title: '',
+        width: 800,
+        visible: false,
+        disableSubmit: false,
+        disableSelectDevice: false
+      }
+    },
+    methods: {
+      add() {
+        this.visible = true
+        this.disableSelectDevice = false
+        this.$nextTick(() => {
+          this.$refs.realForm.add()
+        })
+      },
+      edit(record) {
+        this.visible = true
+        this.disableSelectDevice = true
+        this.$nextTick(() => {
+          this.$refs.realForm.edit(record)
+        })
+      },
+      close() {
+        this.$emit('close')
+        this.visible = false
+      },
+      handleOk() {
+        this.$refs.realForm.submitForm()
+      },
+      submitCallback() {
+        this.$emit('ok')
+        this.visible = false
+      },
+      handleCancel() {
+        this.close()
+      }
+    }
+  }
+</script>
\ No newline at end of file

--
Gitblit v1.9.3