From fa9d138094e2ffabf7b053e73779d1204097ce75 Mon Sep 17 00:00:00 2001
From: zhaowei <zhaowei>
Date: 星期二, 11 二月 2025 11:49:46 +0800
Subject: [PATCH] 产品结构树: 1、实现文档功能的删除功能 设备结构树: 1、实现获取对应设备的已发送的NC程序列表 2、实现设备层级导入NC程序功能 3、实现设备关联的已发送NC程序功能的删除功能

---
 src/views/dnc/base/DeviceStructure.vue                                          |   40 +
 src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainBottom.vue        |  134 ++++
 src/views/dnc/common/DocumentModal.vue                                          |    0 
 src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainTop.vue           |  377 ++++++++++++
 src/views/dnc/base/modules/DeviceStructure/HasSentDocumentTableList.vue         |  133 ++++
 src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue      |    6 
 src/views/dnc/base/modules/DeviceStructure/Document/OtherDocumentTableList.vue  |  121 ++++
 src/views/dnc/common/DocumentInfo.vue                                           |   40 +
 src/views/dnc/base/modules/DeviceStructure/Document/NcDocumentTableList.vue     |  126 ++++
 src/views/dnc/base/modules/DeviceStructure/Workshop/WorkshopInfo.vue            |   29 
 src/views/dnc/common/DocumentBatchDeleteModal.vue                               |    0 
 src/store/modules/Production.js                                                 |    4 
 src/views/dnc/common/FilePreview.vue                                            |    0 
 src/views/dnc/common/TableContextMenu.vue                                       |   19 
 src/views/dnc/base/modules/DeviceStructure/Device/DeviceInfo.vue                |   37 +
 src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue    |    8 
 src/views/dnc/base/modules/DeviceStructure/DeviceStructureTreeContextMenu.vue   |   80 ++
 src/views/dnc/common/ImportFileModal.vue                                        |   14 
 src/views/dnc/common/DocumentVersionTableList.vue                               |    0 
 src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue |    8 
 src/api/dnc.js                                                                  |    8 
 src/views/dnc/base/modules/DeviceStructure/HasReceivedDocumentTableList.vue     |  133 ++++
 src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue         |   96 ++
 src/views/dnc/common/DocumentModalForm.vue                                      |    0 
 src/views/dnc/common/FileCompareModal.vue                                       |    0 
 src/views/dnc/common/SelectFileCompareModal.vue                                 |    0 
 src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue              |  295 +++++++++
 src/views/dnc/base/modules/DeviceStructure/DeviceStructureMain.vue              |   65 ++
 28 files changed, 1,737 insertions(+), 36 deletions(-)

diff --git a/src/api/dnc.js b/src/api/dnc.js
index 2ee2cf5..e25ffbd 100644
--- a/src/api/dnc.js
+++ b/src/api/dnc.js
@@ -27,6 +27,8 @@
   assignDocumentToDeviceApi: params => postAction('/nc/activit/assign/file/apply', params),
   // 涓嬭浇鏂囨。
   downloadDocumentApi: ({ docId, docName }) => downloadFile(`/nc/doc/download/${docId}`, docName),
+  // 鍒犻櫎鏂囨。
+  deleteDocumentApi: docId => deleteAction(`/nc/doc/delete?id=${docId}`),
   // 鏂囨。鍑哄簱
   documentOutboundApi: ({ docId, docName }) => requestGetDownLoad(`/nc/doc/pull/${docId}`, docName),
   // 鏂囨。鍙栨秷鍑哄簱
@@ -70,5 +72,9 @@
   // 绉婚櫎閮ㄩ棬鏉冮檺
   removePermissionFromUser: ({ treeNodeType, treeNodeId, isAssignSonNode, userIdArray }) => {
     return postAction(`/nc/product/assign/remove/user/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, userIdArray)
-  }
+  },
+
+  //-------------------------璁惧缁撴瀯鏍�------------------------------------------------
+  // 鍒犻櫎鏂囨。
+  deleteDeviceRelativeDocumentApi: ({ docId, attributionId }) => deleteAction(`doc/relative/delete/device/${docId}/${attributionId}`)
 }
\ No newline at end of file
diff --git a/src/store/modules/Production.js b/src/store/modules/Production.js
index 883a3f5..f848422 100644
--- a/src/store/modules/Production.js
+++ b/src/store/modules/Production.js
@@ -21,9 +21,9 @@
 
   actions: {
     // 浜х嚎鏍�
-      QueryProduction({ commit }) {
+      QueryProduction({ commit },type='MDC') {
       return new Promise((resolve, reject) => {
-        getAction("/mdc/mdcEquipment/queryTreeListByProduction").then(response => {
+        getAction("/mdc/mdcEquipment/queryTreeListByProduction",{type}).then(response => {
           if(response.success){
             const result = response.result
             Vue.ls.set(SYS_PRODUCTION, result)
diff --git a/src/views/dnc/base/DeviceStructure.vue b/src/views/dnc/base/DeviceStructure.vue
new file mode 100644
index 0000000..2fca966
--- /dev/null
+++ b/src/views/dnc/base/DeviceStructure.vue
@@ -0,0 +1,40 @@
+<template>
+  <a-card :bordered="false">
+    <a-row type="flex" :gutter="16">
+      <a-col :md="5">
+        <DeviceStructureTree/>
+      </a-col>
+      <a-col :md="19">
+        <DeviceStructureMain/>
+      </a-col>
+    </a-row>
+
+    <!--瀵煎叆鏂囦欢鍏叡寮圭獥-->
+    <ImportFileModal/>
+  </a-card>
+</template>
+
+<script>
+  import DeviceStructureTree from './modules/DeviceStructure/DeviceStructureTree'
+  import DeviceStructureMain from './modules/DeviceStructure/DeviceStructureMain'
+  import ImportFileModal from '../common/ImportFileModal'
+
+  export default {
+    name: 'DeviceStructure',
+    components: {
+      DeviceStructureTree,
+      DeviceStructureMain,
+      ImportFileModal
+    },
+    data() {
+      return {}
+    },
+    methods: {}
+  }
+</script>
+
+<style scoped lang="less">
+  /deep/ .ant-card-body {
+    padding: 8px;
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/Device/DeviceInfo.vue b/src/views/dnc/base/modules/DeviceStructure/Device/DeviceInfo.vue
new file mode 100644
index 0000000..1fec255
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/Device/DeviceInfo.vue
@@ -0,0 +1,37 @@
+<template>
+  <a-descriptions bordered :size="size">
+    <a-descriptions-item label="璁惧缂栧彿">{{currentLevelDetails.equipmentId}}</a-descriptions-item>
+    <a-descriptions-item label="璁惧鍚嶇О">{{currentLevelDetails.equipmentName}}</a-descriptions-item>
+    <a-descriptions-item label="鏁版帶绯荤粺	">{{currentLevelDetails.driveType}}</a-descriptions-item>
+    <a-descriptions-item label="璁惧鍨嬪彿">{{currentLevelDetails.equipmentModel}}</a-descriptions-item>
+    <a-descriptions-item label="閾炬帴IP">{{currentLevelDetails.equipmentIp}}</a-descriptions-item>
+    <a-descriptions-item label="閾炬帴绔彛">{{currentLevelDetails.dataPort}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓浜�">{{currentLevelDetails.createBy}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓鏃堕棿" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
+    <a-descriptions-item label="淇敼浜�">{{currentLevelDetails.updateBy}}</a-descriptions-item>
+    <a-descriptions-item label="淇敼鏃堕棿" :span="2">{{currentLevelDetails.updateTime}}</a-descriptions-item>
+  </a-descriptions>
+</template>
+
+<script>
+  export default {
+    name: 'DeviceInfo',
+    components: {},
+    props: {
+      currentLevelDetails: {
+        type: Object
+      },
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {}
+    },
+    methods: {}
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMain.vue b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMain.vue
new file mode 100644
index 0000000..81ecbcd
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMain.vue
@@ -0,0 +1,65 @@
+<template>
+  <div style="height: 100%;max-height: 748px">
+    <template v-if="+currentTreeNodeInfo.type===2">
+      <div style="height: 100%;max-height: 748px">
+        <!--浜у搧缁撴瀯鏍戝彸渚ч《閮ㄥ尯鍩�-->
+        <div style="height: 45%;overflow: hidden">
+          <DeviceStructureMainTop :size="containerSize" ref="mainTopRef" :currentTreeNodeInfo="currentTreeNodeInfo"/>
+        </div>
+
+        <!--浜у搧缁撴瀯鏍戝彸渚у簳閮ㄥ尯鍩�-->
+        <div style="height: 55%;overflow: hidden">
+          <DeviceStructureMainBottom :size="containerSize" :currentTreeNodeInfo="currentTreeNodeInfo"/>
+        </div>
+      </div>
+    </template>
+
+    <template v-else>
+      <a-tabs>
+        <a-tab-pane :key="1" tab="杞﹂棿灞炴��">
+          <WorkshopInfo :currentLevelDetails="currentTreeNodeInfo" :size="containerSize"/>
+        </a-tab-pane>
+      </a-tabs>
+    </template>
+  </div>
+</template>
+
+<script>
+  import DeviceStructureMainTop from './DeviceStructureMainTop'
+  import DeviceStructureMainBottom from './DeviceStructureMainBottom'
+  import WorkshopInfo from './Workshop/WorkshopInfo'
+
+  export default {
+    name: 'DeviceStructureMain',
+    components: {
+      WorkshopInfo,
+      DeviceStructureMainTop,
+      DeviceStructureMainBottom
+    },
+    created() {
+      this.$bus.$on('sendCurrentTreeNodeInfo', this.receiveCurrentTreeNodeInfo)
+    },
+    data() {
+      return {
+        containerSize: 'small',
+        currentTreeNodeInfo: {}
+      }
+    },
+    methods: {
+      /**
+       * 鎺ユ敹鏍戠粍浠朵紶鏉ョ殑褰撳墠閫変腑鐨勬爲鑺傜偣淇℃伅
+       * @param treeNodeInfo 鏍戣妭鐐逛俊鎭�
+       */
+      receiveCurrentTreeNodeInfo(treeNodeInfo) {
+        // 浠庢爲缁勪欢鎺ュ彈鏍戣妭鐐逛俊鎭悗浠庣埗缁勪欢娴佸叆瀛愮粍浠�
+        this.currentTreeNodeInfo = treeNodeInfo
+        if (treeNodeInfo.equipmentId) {
+          this.$nextTick(() => {
+            if (this.$refs.mainTopRef) this.$refs.mainTopRef.loadHasSentDocumentListData()
+          })
+        }
+        console.log('currentTreeNodeInfo------------------', this.currentTreeNodeInfo)
+      }
+    }
+  }
+</script>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainBottom.vue b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainBottom.vue
new file mode 100644
index 0000000..308ce66
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainBottom.vue
@@ -0,0 +1,134 @@
+<template>
+  <a-tabs style="height: 100%" v-model="activeTabKey" @change="handleTabChange">
+    <a-tab-pane :key="1" tab="璁惧灞炴��" v-if="currentTreeNodeInfo.equipmentId">
+      <DeviceInfo :currentLevelDetails="currentTreeNodeInfo.entity" :size="containerSize"/>
+    </a-tab-pane>
+
+    <template v-else>
+      <a-tab-pane :key="1" tab="鏂囨。灞炴��">
+        <DocumentInfo :currentLevelDetails="currentDocumentInfo" :size="containerSize"/>
+      </a-tab-pane>
+
+      <a-tab-pane :key="2" tab="棰勮">
+        <FilePreview ref="filePreviewRef" :currentDocumentInfo="currentDocumentInfo"/>
+      </a-tab-pane>
+
+      <a-tab-pane :key="3" tab="鏂囨。鐗堟湰">
+        <DocumentVersionTableList ref="documentVersionTableRef" :currentDocumentInfo="currentDocumentInfo"
+                                  @handleTableContextMenuOpen="handleTableContextMenuOpen"
+                                  @releaseFilePreviewApi="releaseFilePreviewApi"
+                                  :size="containerSize"/>
+      </a-tab-pane>
+    </template>
+
+    <TableContextMenu :tableRowInfo="currentRightClickedTableRowInfo" ref="tableContextMenuRef"/>
+  </a-tabs>
+</template>
+
+<script>
+  import DeviceInfo from './Device/DeviceInfo'
+  import DocumentInfo from '../../../common/DocumentInfo'
+  import FilePreview from '../../../common/FilePreview'
+  import TableContextMenu from '../../../common/TableContextMenu'
+  import DocumentVersionTableList from '../../../common/DocumentVersionTableList'
+
+  export default {
+    name: 'DeviceStructureMainBottom',
+    components: {
+      TableContextMenu,
+      DeviceInfo,
+      DocumentInfo,
+      FilePreview,
+      DocumentVersionTableList
+    },
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      }
+    },
+    data() {
+      return {
+        activeTabKey: 1,
+        containerSize: 'small',
+        currentDocumentInfo: {},
+        currentRightClickedTableRowInfo: {},
+        hasLoadedDataTabKeyArray: []
+      }
+    },
+    created() {
+      this.$bus.$on('sendCurrentClickedDocumentInfo', this.receiveCurrentDocumentInfo)
+      this.$bus.$on('reloadMainBottomTableData', this.reloadMainBottomTableData)
+    },
+    methods: {
+      /**
+       * 鎺ユ敹琛ㄦ牸浼犳潵鐨勫綋鍓嶉�変腑鎴栫偣鍑荤殑椤逛俊鎭�
+       * @param documentInfo 褰撳墠灞傜骇淇℃伅
+       */
+      receiveCurrentDocumentInfo(documentInfo) {
+        this.currentDocumentInfo = documentInfo
+        this.activeTabKey = 1
+        this.hasLoadedDataTabKeyArray = []
+      },
+
+      handleTabChange(activeTabKey) {
+        if (!this.hasLoadedDataTabKeyArray.includes(activeTabKey)) {
+          switch (activeTabKey) {
+            case 2:
+              this.$nextTick(() => this.$refs.filePreviewRef.getFilePreviewByApi())
+              break
+            case 3:
+              this.$nextTick(() => this.$refs.documentVersionTableRef.loadData())
+              break
+            case 4:
+              this.$nextTick(() => this.$refs.useDocumentEquipmentTableRef.loadData())
+              break
+            default:
+          }
+          // 闃绘鎺ュ彛鍦ㄥ悓涓�鏂囨。涓�娆$偣鍑诲唴澶氭瑙﹀彂
+          this.hasLoadedDataTabKeyArray.push(activeTabKey)
+        }
+      },
+
+      // 閲婃斁鏂囦欢棰勮鎺ュ彛
+      releaseFilePreviewApi() {
+        // 濡傛灉宸茬粡棰勮杩囨鏂囨。锛屽彲鍦ㄦ鏂囨。褰撳墠鐗堟湰鍙戠敓鏀瑰彉鍚庡啀娆¢瑙堟柊鐗堟湰鍐呭
+        if (this.hasLoadedDataTabKeyArray.includes(2)) this.hasLoadedDataTabKeyArray = this.hasLoadedDataTabKeyArray.filter(item => item !== 2)
+      },
+
+      /**
+       * 鎺у埗鍙抽敭鑿滃崟寮�鍚�
+       * @param record 褰撳墠琛ㄦ牸琛屼俊鎭�
+       */
+      handleTableContextMenuOpen(record) {
+        this.currentRightClickedTableRowInfo = Object.assign({}, record)
+        this.$refs.tableContextMenuRef.currentMenuLevel = record.param
+        this.$refs.tableContextMenuRef.menuStyle.top = event.clientY + 'px'
+        this.$refs.tableContextMenuRef.menuStyle.left = event.clientX + 'px'
+        this.$refs.tableContextMenuRef.menuVisible = true
+        document.body.addEventListener('click', this.handleMenuClose)
+      },
+
+      /**
+       * 鎺у埗鍙抽敭鑿滃崟鐐瑰嚮鍏抽棴
+       */
+      handleMenuClose() {
+        this.$refs.tableContextMenuRef.menuVisible = false
+        document.body.removeEventListener('click', this.handleMenuClose)
+      },
+
+      reloadMainBottomTableData(tableName) {
+        if (this.$refs[tableName + 'TableRef']) this.$refs[tableName + 'TableRef'].loadData()
+      }
+    }
+  }
+</script>
+
+<style scoped>
+  /deep/ .ant-tabs-content {
+    height: calc(100% - 65px);
+  }
+
+  /deep/ .ant-tabs-tabpane {
+    overflow: auto;
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainTop.vue b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainTop.vue
new file mode 100644
index 0000000..d5ae553
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureMainTop.vue
@@ -0,0 +1,377 @@
+<template>
+  <a-tabs v-model="activeTabKey" @contextmenu.native="e=>e.preventDefault()"
+          v-if="Object.keys(currentTreeNodeInfo).length!==0">
+    <a-tab-pane :key="1" tab="鍙戦��">
+      <!--<NcDocumentTableList ref="ncDocumentTableListRef" />-->
+      <HasSentDocumentTableList ref="hasSentDocumentTableListRef" :currentTreeNodeInfo="currentTreeNodeInfo"
+                                @handleTableContextMenuOpen="handleTableContextMenuOpen" :size="tableContainerSize"/>
+    </a-tab-pane>
+
+    <a-tab-pane :key="2" tab="鎺ユ敹">
+      <!--<OtherDocumentTableList ref="otherDocumentTableListRef" :currentTreeNodeInfo="currentTreeNodeInfo"-->
+      <!--@handleTableContextMenuOpen="handleTableContextMenuOpen" :size="tableContainerSize"/>-->
+    </a-tab-pane>
+
+    <TableContextMenu :tableRowInfo="currentRightClickedTableRowInfo" ref="tableContextMenuRef"/>
+  </a-tabs>
+</template>
+
+<script>
+  import dncApi from '@/api/dnc'
+  import TableContextMenu from '../../../common/TableContextMenu'
+  import HasSentDocumentTableList from './HasSentDocumentTableList'
+
+  export default {
+    name: 'DeviceStructureMainTop',
+    components: { HasSentDocumentTableList, TableContextMenu },
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      }
+    },
+    data() {
+      return {
+        activeTabKey: 1,
+        tableContainerSize: 'small',
+        currentRightClickedTableRowInfo: {}
+      }
+    },
+    created() {
+      this.$bus.$on('reloadDocumentListData', this.reloadDocumentListData)
+      this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      /**
+       * 鎺у埗鍙抽敭鑿滃崟寮�鍚�
+       * @param record 褰撳墠琛ㄦ牸琛屼俊鎭�
+       */
+      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'
+        this.$refs.tableContextMenuRef.menuVisible = true
+        document.body.addEventListener('click', this.handleMenuClose)
+      },
+
+      /**
+       * 褰撴爲缁勪欢閫変腑璁惧灞傜骇鑺傜偣鏃惰Е鍙戣幏鍙栧凡鍙戦�佹枃妗e垪琛�
+       * @param treeNodeInfo 鏍戣妭鐐逛俊鎭�
+       */
+      loadHasSentDocumentListData(treeNodeInfo) {
+        this.$nextTick(() => {
+          if (this.$refs.hasSentDocumentTableListRef) this.$refs.hasSentDocumentTableListRef.loadData(1)
+        })
+      },
+
+      /**
+       * 鏂囨。浠ュ強NC绋嬪簭瀵煎叆/鍑哄簱/鍏ュ簱/鍒犻櫎鎴愬姛鍚庤Е鍙戦噸鏂板姞杞芥枃妗e垪琛�
+       * @param docClassCode 鏂囨。绫诲埆
+       * @param attributionId 鑺傜偣Id
+       */
+      reloadDocumentListData({ docClassCode, attributionId }) {
+        // 濡傛灉涓婁紶鐨勬枃妗d笉鏄墍灞炰簬褰撳墠鎵�灞曠ず鑺傜偣鐨勬枃妗e垯涓嶉噸鏂拌幏鍙栨枃妗e垪琛�
+        if (this.currentTreeNodeInfo.key !== attributionId) return
+        if (docClassCode === 'SEND') {
+          if (this.$refs.hasSentDocumentTableListRef) this.$refs.hasSentDocumentTableListRef.loadData(1)
+        }
+      },
+
+      // 涓嬭浇褰撳墠鍙抽敭閫変腑鏂囨。
+      handleDownload() {
+        const that = this
+        const { docId, docName } = this.currentRightClickedTableRowInfo
+        dncApi.downloadDocumentApi({ docId, docName })
+          .then(res => {
+            if (res && !res.success) {
+              that.$notification.error({
+                message: '娑堟伅',
+                description: res.message
+              })
+            }
+          })
+          .catch(err => {
+            that.$notification.error({
+              message: '娑堟伅',
+              description: err.message
+            })
+          })
+      },
+
+      // 鍒犻櫎褰撳墠鍙抽敭閫変腑鏂囨。
+      handleDelete() {
+        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
+        const that = this
+        that.$confirm({
+          title: '鎻愮ず',
+          content: `鍒犻櫎鍚庝笉鍙彇娑堬紝纭鍒犻櫎鍚楋紵`,
+          okText: '纭',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            dncApi.deleteDeviceRelativeDocumentApi({ docId, attributionId })
+              .then((res) => {
+                if (res.success) {
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                  that.reloadDocumentListData({ docClassCode: param, attributionId })
+                } else {
+                  that.$notification.warning({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel: () => {
+            that.$destroyAll()
+          }
+        })
+      },
+
+      /**
+       * 鍑哄簱褰撳墠鍙抽敭閫変腑鏂囨。
+       * @param menuLabel
+       */
+      handlePull(menuLabel) {
+        const that = this
+        const { docId, docName, param, attributionId } = this.currentRightClickedTableRowInfo
+        that.$confirm({
+          title: '鎻愮ず',
+          content: `纭${menuLabel}鍚楋紵`,
+          okText: '纭',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            dncApi.documentOutboundApi({ docId, docName })
+              .then(res => {
+                console.log('res------------------', res)
+                if (res.success) {
+                  this.reloadDocumentListData({ docClassCode: param, attributionId })
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: `${menuLabel}鎴愬姛`
+                  })
+                } else {
+                  that.$notification.error({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+              .catch(err => {
+                that.$notification.error({
+                  message: '娑堟伅',
+                  description: err.message
+                })
+              })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel: () => {
+            that.$destroyAll()
+          }
+        })
+      },
+
+      /**
+       * 鍙戝竷褰撳墠鍙抽敭閫変腑鏂囨。
+       * @param menuLabel
+       */
+      handleCancelPull(menuLabel) {
+        const that = this
+        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
+        that.$confirm({
+          title: '鎻愮ず',
+          content: `纭${menuLabel}鍚楋紵`,
+          okText: '纭',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            dncApi.documentCancelOutboundApi(docId)
+              .then(res => {
+                if (res.success) {
+                  this.reloadDocumentListData({ docClassCode: param, attributionId })
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                } else {
+                  that.$notification.error({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+              .catch(err => {
+                that.$notification.error({
+                  message: '娑堟伅',
+                  description: err.message
+                })
+              })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel: () => {
+            that.$destroyAll()
+          }
+        })
+      },
+
+
+      /**
+       * 鐐瑰嚮鍙戝竷鏃惰Е鍙戝綋鍓嶆枃妗e彂甯�
+       * @param menuLabel
+       */
+      handlePublish(menuLabel) {
+        const that = this
+        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
+        that.$confirm({
+          title: '鎻愮ず',
+          content: `纭${menuLabel}鍚楋紵`,
+          okText: '纭',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            dncApi.documentPublishApi(docId)
+              .then(res => {
+                if (res.success) {
+                  this.reloadDocumentListData({ docClassCode: param, attributionId })
+                  this.$bus.$emit('reloadMainBottomTableData', 'documentVersion')
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                } else {
+                  that.$notification.error({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+              .catch(err => {
+                that.$notification.error({
+                  message: '娑堟伅',
+                  description: err.message
+                })
+              })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel: () => {
+            that.$destroyAll()
+          }
+        })
+      },
+
+      /**
+       * 閲嶆柊鍙戝竷褰撳墠鍙抽敭閫変腑鏂囨。骞堕噸鏂板彂甯冮��鍥炰笂涓�鏂囨。鐗堟湰
+       * @param menuLabel
+       */
+      handleRepublish(menuLabel) {
+        const that = this
+        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
+        that.$confirm({
+          title: '鎻愮ず',
+          content: `纭${menuLabel}鍚楋紵`,
+          okText: '纭',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            dncApi.documentRepublishApi(docId)
+              .then(res => {
+                if (res.success) {
+                  this.reloadDocumentListData({ docClassCode: param, attributionId })
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                } else {
+                  that.$notification.error({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+              .catch(err => {
+                that.$notification.error({
+                  message: '娑堟伅',
+                  description: err.message
+                })
+              })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel: () => {
+            that.$destroyAll()
+          }
+        })
+      },
+
+      /**
+       * 閲嶅綊妗e綋鍓嶅彸閿�変腑鏂囨。涓斿悗缁棤娉曠户缁彂甯冩垨褰掓。
+       * @param menuLabel
+       */
+      handlePigeonhole(menuLabel) {
+        const that = this
+        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
+        that.$confirm({
+          title: '鎻愮ず',
+          content: `${menuLabel}鍚庝笉鍙彇娑堬紝纭${menuLabel}鍚楋紵`,
+          okText: '纭',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            dncApi.documentPigeonholeApi(docId)
+              .then(res => {
+                if (res.success) {
+                  this.reloadDocumentListData({ docClassCode: param, attributionId })
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                } else {
+                  that.$notification.error({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+              .catch(err => {
+                that.$notification.error({
+                  message: '娑堟伅',
+                  description: err.message
+                })
+              })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel: () => {
+            that.$destroyAll()
+          }
+        })
+      },
+
+      // 鎺у埗鍙抽敭鑿滃崟鍏抽棴
+      handleMenuClose() {
+        this.$refs.tableContextMenuRef.menuVisible = false
+        document.body.removeEventListener('click', this.handleMenuClose)
+      },
+
+      triggerCorrespondingMethod({ methodName, modalTitle }) {
+        if (this[methodName]) this[methodName](modalTitle)
+      }
+    }
+  }
+</script>
+
+<style scoped>
+  /deep/ .ant-table-tbody .ant-table-row {
+    cursor: pointer;
+  }
+</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
new file mode 100644
index 0000000..56c7ec9
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTree.vue
@@ -0,0 +1,295 @@
+<template>
+  <a-card class="tree_con" :loading="cardLoading" :bordered="false" @contextmenu.native="e=>e.preventDefault()">
+    <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>
+        </div>
+
+        <!--璁惧缁撴瀯鏍�-->
+        <div 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">
+            <template slot="title" slot-scope="{ title, parentId, entity, key:treeKey,equipmentId}">
+              <DeviceStructureTreeContextMenu ref="contextMenuRef"
+                                              :treeParams="{title,treeKey,searchValue,equipmentId,entity}"/>
+            </template>
+
+            <a-icon slot="switcherIcon" type="down"/>
+            <a-icon slot="workshop" type="bank"/>
+            <a-icon slot="device" type="laptop"/>
+          </a-tree>
+        </div>
+      </div>
+    </a-spin>
+  </a-card>
+</template>
+
+<script>
+  import { mapActions } from 'vuex'
+  import { deleteAction } from '@/api/manage'
+  import DeviceStructureTreeContextMenu from './DeviceStructureTreeContextMenu'
+
+  export default {
+    name: 'DeviceStructureTree',
+    components: {
+      DeviceStructureTreeContextMenu
+    },
+    data() {
+      return {
+        searchInput: '',
+        cardLoading: false,
+        loading: false,
+        treeDataSource: [],
+        selectedKeys: [],
+        expandedKeys: [],
+        searchValue: '',
+        dataList: [],
+        autoExpandParent: true,
+        checkStrictly: true,
+        allTreeKeys: [],
+        currentSelected: {},
+        rightClickSelected: {},
+        url: {
+          delete: '/nc/product/delete'
+        }
+      }
+    },
+    created() {
+      this.getTreeDataByApi()
+      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      ...mapActions(['QueryProduction']),
+
+      getTreeDataByApi() {
+        this.loading = true
+        this.cardLoading = true
+        this.QueryProduction('DNC').then(res => {
+          if (res.success) {
+            this.dataList = []
+            this.allTreeKeys = []
+            this.treeDataSource = res.result
+            this.generateList(this.treeDataSource)
+            this.expandedKeys = this.allTreeKeys
+            this.$bus.$emit('sendCurrentTreeNodeInfo', this.treeDataSource[0])
+          } else {
+            this.$message.warn(res.message)
+          }
+        }).finally(() => {
+          this.loading = false
+          this.cardLoading = false
+        })
+      },
+
+      /**
+       * 鏍戣妭鐐归�変腑鏃惰Е鍙�
+       * @param selectedKeys 閫変腑鑺傜偣key
+       * @param {node} node 鑺傜偣瀵硅薄
+       */
+      handleTreeSelect(selectedKeys, { node }) {
+        let record = node.dataRef
+        this.currentSelected = Object.assign({}, record)
+        this.selectedKeys = selectedKeys
+        // 鍚戝彸渚х埗绾х粍浠跺彂閫佸綋鍓嶉�変腑鏍戣妭鐐逛俊鎭�
+        this.$bus.$emit('sendCurrentTreeNodeInfo', this.currentSelected)
+      },
+
+      /**
+       * 鏍戣妭鐐瑰彸閿崟鍑昏妭鐐规椂瑙﹀彂
+       * @param event 浜嬩欢瀵硅薄
+       * @param node 鑺傜偣瀵硅薄
+       */
+      handleTreeRightClick({ event, node }) {
+        const record = node.dataRef
+        this.rightClickSelected = Object.assign({}, record)
+      },
+
+      // 鏍戣妭鐐瑰彸閿崟鍑昏彍鍗曚腑鍒犻櫎鎸夐挳鏃惰Е鍙�
+      handleDelete() {
+        this.$confirm({
+          title: '鎻愮ず',
+          content: '纭鍒犻櫎姝ゆ潯璁板綍鍚楋紵',
+          okText: '纭',
+          okType: 'danger',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            console.log('this.rightClickSelected.id', this.rightClickSelected.id)
+            if (!this.url.delete) {
+              this.$message.error('璇疯缃畊rl.delete灞炴��!')
+              return
+            }
+            const that = this
+            deleteAction(that.url.delete, { id: this.rightClickSelected.id })
+              .then((res) => {
+                if (res.success) {
+                  that.getTreeDataByApi()
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                } else {
+                  that.$notification.warning({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+          }
+        })
+      },
+
+      /**
+       * 鑷姩灞曞紑娣诲姞涓嬬骇鑺傜偣鐨勭埗鑺傜偣
+       */
+      modalFormSubmitSuccess(isAddNextLevel) {
+        // 鍒ゆ柇鏄惁涓烘坊鍔犱笅绾у苟涓斿垽鏂埗鑺傜偣鏄惁灞曞紑
+        if (isAddNextLevel && !this.expandedKeys.includes(this.rightClickSelected.id)) this.expandedKeys.push(this.rightClickSelected.id)
+        this.getTreeDataByApi()
+      },
+
+      /**
+       * 鏍戣妭鐐瑰睍寮�鍚堝苟鏃惰Е鍙�
+       * @param expandedKeys 灞曞紑椤筴ey
+       */
+      handleTreeExpand(expandedKeys) {
+        this.expandedKeys = expandedKeys
+        this.autoExpandParent = false
+      },
+
+      /* 杈撳叆鏌ヨ鍐呭鍙樺寲鏃惰Е鍙� */
+      handleSearchInputChange() {
+        let search = this.searchInput
+        let 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)
+        Object.assign(this, {
+          expandedKeys,
+          searchValue: search,
+          autoExpandParent: true
+        })
+      },
+
+      /**
+       * 閫掑綊鑾峰緱杈撳叆椤圭殑鐖剁骇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' }
+        }
+      }
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+  /deep/ .ant-card-body {
+    padding: 0 12px 0 0;
+  }
+
+  /deep/ .ant-card-body, /deep/ .ant-spin-nested-loading, /deep/ .ant-spin-container {
+    height: 100%;
+  }
+
+  /deep/ .ant-tree-title, .ant-tree-title .ant-dropdown-trigger {
+    display: inline-block;
+    width: calc(100% - 24px) !important;
+  }
+
+  ::-webkit-scrollbar {
+    width: 8px;
+  }
+
+  @media screen and (min-width: 1920px) {
+    .tree_con {
+      height: 748px !important;
+    }
+  }
+
+  @media screen and (min-width: 1680px) and (max-width: 1920px) {
+    .tree_con {
+      height: 748px !important;
+    }
+  }
+
+  @media screen and (min-width: 1400px) and (max-width: 1680px) {
+    .tree_con {
+      height: 600px !important;
+    }
+  }
+
+  @media screen and (min-width: 1280px) and (max-width: 1400px) {
+    .tree_con {
+      height: 501px !important;
+    }
+  }
+
+  @media screen and (max-width: 1280px) {
+    .tree_con {
+      height: 501px !important;
+    }
+  }
+</style>
diff --git a/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTreeContextMenu.vue b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTreeContextMenu.vue
new file mode 100644
index 0000000..001b2db
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/DeviceStructureTreeContextMenu.vue
@@ -0,0 +1,80 @@
+<template>
+  <a-dropdown :trigger="['contextmenu']">
+    <span v-if="treeParams.title.indexOf(treeParams.searchValue) > -1">{{ treeParams.title.substr(0, treeParams.title.indexOf(treeParams.searchValue)) }}<span
+      class="replaceSearch">{{ treeParams.searchValue }}</span>{{ treeParams.title.substr(treeParams.title.indexOf(treeParams.searchValue) + treeParams.searchValue.length) }}</span>
+    <span v-else>{{ treeParams.title }}</span>
+    <template #overlay>
+      <a-menu @click="({ key: menuKey }) => onContextMenuClick(treeParams.treeKey, menuKey)"
+              @contextmenu="event=>event.preventDefault()">
+        <a-menu-item v-for="item in defaultContextMenuList[getCurrentMenuLevel]" :key="item.code" v-has="item.code">
+          <a-icon :type="item.icon"/>
+          {{item.label}}
+        </a-menu-item>
+      </a-menu>
+    </template>
+  </a-dropdown>
+</template>
+
+<script>
+  export default {
+    name: 'DeviceStructureTreeContextMenu',
+    components: {},
+    props: {
+      treeParams: {
+        type: Object
+      }
+    },
+    data() {
+      return {
+        defaultContextMenuList: {
+          //杞﹂棿
+          workshop: [
+            { label: '鏉冮檺閰嶇疆', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
+          ],
+          //璁惧
+          device: [
+            { label: '瀵煎叆NC鏂囨。', code: 'device_import', icon: 'import', isCommonMethod: true },
+            { label: '鏉冮檺閰嶇疆', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
+          ]
+        }
+      }
+    },
+    computed: {
+      getCurrentMenuLevel() {
+        if (!this.treeParams.equipmentId) return 'workshop'
+        else return 'device'
+      }
+    },
+    methods: {
+      onContextMenuClick(treeKey, menuKey) {
+        const level = this.getCurrentMenuLevel
+        const treeNodeInfo = Object.assign({}, this.treeParams)
+        if (treeNodeInfo.equipmentId) treeNodeInfo.type = 4
+        const menuKeyArray = menuKey.split('_')
+        const isCommonMethod = this.defaultContextMenuList[level].find(item => item.code === menuKey).isCommonMethod
+        // 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('')
+        }
+        console.log('methodName------------------------------------', methodName)
+        console.log('treeParams------------------------------------', this.treeParams)
+        const modalTitle = this.defaultContextMenuList[level].find(item => item.code === menuKey).label
+
+        this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle, treeNodeInfo })
+      }
+    }
+  }
+</script>
+
+<style scoped>
+  .replaceSearch {
+    color: #40a9ff;
+    font-weight: bold;
+    background-color: rgb(204, 204, 204);
+  }
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/Document/NcDocumentTableList.vue b/src/views/dnc/base/modules/DeviceStructure/Document/NcDocumentTableList.vue
new file mode 100644
index 0000000..1e80a84
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/Document/NcDocumentTableList.vue
@@ -0,0 +1,126 @@
+<template>
+  <div>
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+             :scroll="{y:189}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange"/>
+
+    <DocumentModal ref="modalForm" @ok="modalFormOk"/>
+  </div>
+</template>
+
+<script>
+  import { getAction } from '@/api/manage'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import DocumentModal from '../../../../common/DocumentModal'
+
+  export default {
+    name: 'NcDocumentTableList',
+    components: {  DocumentModal },
+    mixins: [JeecgListMixin],
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      },
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {
+        disableMixinCreated: true,
+        columns: [
+          {
+            title: '搴忓彿',
+            dataIndex: 'rowIndex',
+            key: 'rowIndex',
+            width: 65,
+            align: 'center',
+            customRender: function(t, r, index) {
+              return parseInt(index) + 1
+            }
+          },
+          { title: '鏂囦欢鍚嶇О', dataIndex: 'docName', align: 'center' },
+          { title: '浠g爜鐗堟湰', dataIndex: 'docAlias', align: 'center' },
+          { title: '鍑哄簱鐘舵��', dataIndex: 'pullStatus_dictText', align: 'center' },
+          { title: '鐘�  鎬�', dataIndex: 'docStatus_dictText', align: 'center' },
+          { title: '绯荤粺鎸囧畾鐗堟湰', dataIndex: 'publishVersion', align: 'center' },
+          { title: '涓婁紶鏃堕棿', dataIndex: 'createTime', align: 'center' }
+        ],
+        dataSource: [],
+        currentRightClickedDocumentInfo: {},
+        currentClickedDocumentInfo: {},
+        url: {
+          list: '/nc/doc/find/page'
+        }
+      }
+    },
+    created() {
+      this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      loadData(arg) {
+        if (!this.url.list) {
+          this.$message.error('璇疯缃畊rl.list灞炴��!')
+          return
+        }
+        //鍔犺浇鏁版嵁 鑻ヤ紶鍏ュ弬鏁�1鍒欏姞杞界涓�椤电殑鍐呭
+        if (arg === 1) this.ipagination.current = 1
+        var params = this.getQueryParams()//鏌ヨ鏉′欢
+        params.attributionId = this.currentTreeNodeInfo.id
+        params.attributionType = this.currentTreeNodeInfo.type
+        params.docClassCode = 'NC'
+        if (!params) return false
+        this.dataSource = []
+        this.loading = true
+        getAction(this.url.list + `/${this.ipagination.current}/${this.ipagination.pageSize}`, params).then((res) => {
+          if (res.success) {
+            this.dataSource = res.result.records
+            if (res.result.total) {
+              this.ipagination.total = res.result.total
+            } else {
+              this.ipagination.total = 0
+            }
+          } else {
+            this.$message.warning(res.message)
+          }
+        }).finally(() => {
+          this.loading = false
+        })
+      },
+
+      customRow(record) {
+        return {
+          on: {
+            contextmenu: event => {
+              event.preventDefault()
+              this.currentRightClickedDocumentInfo = Object.assign({ param: 'NC' }, record)
+              this.$emit('handleTableContextMenuOpen', this.currentRightClickedDocumentInfo)
+            },
+            click: () => {
+              if (this.currentClickedDocumentInfo.docId === record.docId) return
+              this.currentClickedDocumentInfo = Object.assign({}, record)
+              this.$bus.$emit('sendCurrentClickedDocumentInfo', record)
+            }
+          }
+        }
+      },
+
+      handleDocumentEdit(record, modalTitle) {
+        this.$refs.modalForm.edit(record)
+        this.$refs.modalForm.title = modalTitle
+      },
+
+      handleDocumentAssign(record, modalTitle) {
+        this.$refs.documentAssignModalRef.title = modalTitle
+        this.$refs.documentAssignModalRef.visible = true
+      },
+
+      triggerCorrespondingMethod({ methodName, level, modalTitle, tableRowInfo }) {
+        if (this[methodName]) this[methodName](tableRowInfo, modalTitle)
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/Document/OtherDocumentTableList.vue b/src/views/dnc/base/modules/DeviceStructure/Document/OtherDocumentTableList.vue
new file mode 100644
index 0000000..242ec75
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/Document/OtherDocumentTableList.vue
@@ -0,0 +1,121 @@
+<template>
+  <div>
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+             :scroll="{y:189}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange">
+
+    </a-table>
+
+    <DocumentModal ref="modalForm" @ok="modalFormOk"/>
+  </div>
+</template>
+
+<script>
+  import { getAction } from '@/api/manage'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import DocumentModal from '../../../../common/DocumentModal'
+
+  export default {
+    name: 'OtherDocumentTableList',
+    components: { DocumentModal },
+    mixins: [JeecgListMixin],
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      },
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {
+        disableMixinCreated: true,
+        columns: [
+          {
+            title: '搴忓彿',
+            dataIndex: 'rowIndex',
+            key: 'rowIndex',
+            width: 65,
+            align: 'center',
+            customRender: function(t, r, index) {
+              return parseInt(index) + 1
+            }
+          },
+          { title: '鏂囦欢鍚嶇О', dataIndex: 'docName', align: 'center' },
+          { title: '璁惧缂栧彿', dataIndex: 'docCode', align: 'center' },
+          { title: '鍑哄簱鐘舵��', dataIndex: 'pullStatus_dictText', align: 'center' },
+          { title: '鐘�  鎬�', dataIndex: 'docStatus_dictText', align: 'center' },
+          { title: '绯荤粺鎸囧畾鐗堟湰', dataIndex: 'publishVersion', align: 'center' },
+          { title: '涓婁紶鏃堕棿', dataIndex: 'createTime', align: 'center' }
+        ],
+        dataSource: [],
+        currentDocumentInfo: {},
+        url: {
+          list: '/nc/doc/find/page'
+        }
+      }
+    },
+    created() {
+      this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      loadData(arg) {
+        if (!this.url.list) {
+          this.$message.error('璇疯缃畊rl.list灞炴��!')
+          return
+        }
+        //鍔犺浇鏁版嵁 鑻ヤ紶鍏ュ弬鏁�1鍒欏姞杞界涓�椤电殑鍐呭
+        if (arg === 1) this.ipagination.current = 1
+        var params = this.getQueryParams()//鏌ヨ鏉′欢
+        params.attributionId = this.currentTreeNodeInfo.id
+        params.attributionType = this.currentTreeNodeInfo.type
+        params.docClassCode = 'OTHER'
+        if (!params) return false
+        this.dataSource = []
+        this.loading = true
+        getAction(this.url.list + `/${this.ipagination.current}/${this.ipagination.pageSize}`, params).then((res) => {
+          if (res.success) {
+            this.dataSource = res.result.records
+            if (res.result.total) {
+              this.ipagination.total = res.result.total
+            } else {
+              this.ipagination.total = 0
+            }
+          } else {
+            this.$message.warning(res.message)
+          }
+        }).finally(() => {
+          this.loading = false
+        })
+      },
+
+      customRow(record) {
+        return {
+          on: {
+            contextmenu: event => {
+              event.preventDefault()
+              this.$emit('handleTableContextMenuOpen', { ...record, param: 'OTHER' })
+            },
+            click: () => {
+              if (this.currentDocumentInfo.docId === record.docId) return
+              this.currentDocumentInfo = Object.assign({}, record)
+              this.$bus.$emit('sendCurrentClickedDocumentInfo', record)
+            }
+          }
+        }
+      },
+
+      handleDocumentEdit(record, modalTitle) {
+        this.$refs.modalForm.edit(record)
+        this.$refs.modalForm.title = modalTitle
+      },
+
+      triggerCorrespondingMethod({ methodName, level, modalTitle, tableRowInfo }) {
+        if (this[methodName] && tableRowInfo.attributionType === 1) this[methodName](tableRowInfo, modalTitle)
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/HasReceivedDocumentTableList.vue b/src/views/dnc/base/modules/DeviceStructure/HasReceivedDocumentTableList.vue
new file mode 100644
index 0000000..fa63c2f
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/HasReceivedDocumentTableList.vue
@@ -0,0 +1,133 @@
+<template>
+  <div>
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+             :scroll="{y:189}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange">
+
+    </a-table>
+
+    <DocumentModal ref="modalForm" @ok="modalFormOk"/>
+  </div>
+</template>
+
+<script>
+  import { getAction } from '@/api/manage'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import DocumentModal from '../../../common/DocumentModal.vue'
+
+  export default {
+    name: 'HasSentDocumentTableList',
+    components: { DocumentModal },
+    mixins: [JeecgListMixin],
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      },
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {
+        disableMixinCreated: true,
+        columns: [
+          {
+            title: '搴忓彿',
+            dataIndex: 'rowIndex',
+            key: 'rowIndex',
+            width: 65,
+            align: 'center',
+            customRender: function(t, r, index) {
+              return parseInt(index) + 1
+            }
+          },
+          { title: '鏂囦欢鍚嶇О', dataIndex: 'docName', align: 'center' },
+          { title: '浠g爜鐗堟湰', dataIndex: 'docAlias', align: 'center' },
+          { title: '鍑哄簱鐘舵��', dataIndex: 'pullStatus_dictText', align: 'center' },
+          { title: '鐘�  鎬�', dataIndex: 'docStatus_dictText', align: 'center' },
+          { title: '绯荤粺鎸囧畾鐗堟湰', dataIndex: 'publishVersion', align: 'center' },
+          { title: '涓婁紶鏃堕棿', dataIndex: 'createTime', align: 'center' }
+        ],
+        dataSource: [],
+        currentRightClickedDocumentInfo: {},
+        currentClickedDocumentInfo: {},
+        url: {
+          list: '/nc/doc/find/page/device'
+        }
+      }
+    },
+    created() {
+      this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      loadData(arg) {
+        if (!this.url.list) {
+          this.$message.error('璇疯缃畊rl.list灞炴��!')
+          return
+        }
+        //鍔犺浇鏁版嵁 鑻ヤ紶鍏ュ弬鏁�1鍒欏姞杞界涓�椤电殑鍐呭
+        if (arg === 1) this.ipagination.current = 1
+        var params = this.getQueryParams()//鏌ヨ鏉′欢
+        console.log('currentTreeNodeInfo', this.currentTreeNodeInfo)
+        params.attributionId = this.currentTreeNodeInfo.key
+        params.attributionType = 4
+        params.docClassCode = 'SEND'
+        if (!params) return false
+        this.dataSource = []
+        this.loading = true
+        getAction(this.url.list + `/${this.ipagination.current}/${this.ipagination.pageSize}`, params).then((res) => {
+          if (res.success) {
+            this.dataSource = res.result.records
+            if (res.result.total) {
+              this.ipagination.total = res.result.total
+            } else {
+              this.ipagination.total = 0
+            }
+          } else {
+            this.$message.warning(res.message)
+          }
+        }).finally(() => {
+          this.loading = false
+        })
+      },
+
+      customRow(record) {
+        return {
+          on: {
+            contextmenu: event => {
+              event.preventDefault()
+              this.currentRightClickedDocumentInfo = Object.assign({ param: 'SEND' }, record)
+              this.$emit('handleTableContextMenuOpen', this.currentRightClickedDocumentInfo)
+            },
+            click: () => {
+              if (this.currentClickedDocumentInfo.docId === record.docId) return
+              this.currentClickedDocumentInfo = Object.assign({}, record)
+              this.$bus.$emit('sendCurrentClickedDocumentInfo', record)
+            }
+          }
+        }
+      },
+
+      handleDocumentEdit(record, modalTitle) {
+        this.$refs.modalForm.edit(record)
+        this.$refs.modalForm.title = modalTitle
+      },
+
+      handleDocumentAssign(record, modalTitle) {
+        this.$refs.documentAssignModalRef.title = modalTitle
+        this.$refs.documentAssignModalRef.visible = true
+      },
+
+      handleDelete() {
+        // 姝ゅ鍑芥暟涓哄睆钄絤ixins涓殑鍚屽悕鍑芥暟锛岄�氱敤鍑芥暟鍐欏湪鐖剁骇涓�
+      },
+
+      triggerCorrespondingMethod({ methodName, level, modalTitle, tableRowInfo }) {
+        if (this[methodName] && tableRowInfo.param === 'SEND') this[methodName](tableRowInfo, modalTitle)
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/HasSentDocumentTableList.vue b/src/views/dnc/base/modules/DeviceStructure/HasSentDocumentTableList.vue
new file mode 100644
index 0000000..fa63c2f
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/HasSentDocumentTableList.vue
@@ -0,0 +1,133 @@
+<template>
+  <div>
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+             :scroll="{y:189}" :customRow="customRow" :size="size" rowKey="docId" @change="handleTableChange">
+
+    </a-table>
+
+    <DocumentModal ref="modalForm" @ok="modalFormOk"/>
+  </div>
+</template>
+
+<script>
+  import { getAction } from '@/api/manage'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import DocumentModal from '../../../common/DocumentModal.vue'
+
+  export default {
+    name: 'HasSentDocumentTableList',
+    components: { DocumentModal },
+    mixins: [JeecgListMixin],
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      },
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {
+        disableMixinCreated: true,
+        columns: [
+          {
+            title: '搴忓彿',
+            dataIndex: 'rowIndex',
+            key: 'rowIndex',
+            width: 65,
+            align: 'center',
+            customRender: function(t, r, index) {
+              return parseInt(index) + 1
+            }
+          },
+          { title: '鏂囦欢鍚嶇О', dataIndex: 'docName', align: 'center' },
+          { title: '浠g爜鐗堟湰', dataIndex: 'docAlias', align: 'center' },
+          { title: '鍑哄簱鐘舵��', dataIndex: 'pullStatus_dictText', align: 'center' },
+          { title: '鐘�  鎬�', dataIndex: 'docStatus_dictText', align: 'center' },
+          { title: '绯荤粺鎸囧畾鐗堟湰', dataIndex: 'publishVersion', align: 'center' },
+          { title: '涓婁紶鏃堕棿', dataIndex: 'createTime', align: 'center' }
+        ],
+        dataSource: [],
+        currentRightClickedDocumentInfo: {},
+        currentClickedDocumentInfo: {},
+        url: {
+          list: '/nc/doc/find/page/device'
+        }
+      }
+    },
+    created() {
+      this.$bus.$on('tableMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      loadData(arg) {
+        if (!this.url.list) {
+          this.$message.error('璇疯缃畊rl.list灞炴��!')
+          return
+        }
+        //鍔犺浇鏁版嵁 鑻ヤ紶鍏ュ弬鏁�1鍒欏姞杞界涓�椤电殑鍐呭
+        if (arg === 1) this.ipagination.current = 1
+        var params = this.getQueryParams()//鏌ヨ鏉′欢
+        console.log('currentTreeNodeInfo', this.currentTreeNodeInfo)
+        params.attributionId = this.currentTreeNodeInfo.key
+        params.attributionType = 4
+        params.docClassCode = 'SEND'
+        if (!params) return false
+        this.dataSource = []
+        this.loading = true
+        getAction(this.url.list + `/${this.ipagination.current}/${this.ipagination.pageSize}`, params).then((res) => {
+          if (res.success) {
+            this.dataSource = res.result.records
+            if (res.result.total) {
+              this.ipagination.total = res.result.total
+            } else {
+              this.ipagination.total = 0
+            }
+          } else {
+            this.$message.warning(res.message)
+          }
+        }).finally(() => {
+          this.loading = false
+        })
+      },
+
+      customRow(record) {
+        return {
+          on: {
+            contextmenu: event => {
+              event.preventDefault()
+              this.currentRightClickedDocumentInfo = Object.assign({ param: 'SEND' }, record)
+              this.$emit('handleTableContextMenuOpen', this.currentRightClickedDocumentInfo)
+            },
+            click: () => {
+              if (this.currentClickedDocumentInfo.docId === record.docId) return
+              this.currentClickedDocumentInfo = Object.assign({}, record)
+              this.$bus.$emit('sendCurrentClickedDocumentInfo', record)
+            }
+          }
+        }
+      },
+
+      handleDocumentEdit(record, modalTitle) {
+        this.$refs.modalForm.edit(record)
+        this.$refs.modalForm.title = modalTitle
+      },
+
+      handleDocumentAssign(record, modalTitle) {
+        this.$refs.documentAssignModalRef.title = modalTitle
+        this.$refs.documentAssignModalRef.visible = true
+      },
+
+      handleDelete() {
+        // 姝ゅ鍑芥暟涓哄睆钄絤ixins涓殑鍚屽悕鍑芥暟锛岄�氱敤鍑芥暟鍐欏湪鐖剁骇涓�
+      },
+
+      triggerCorrespondingMethod({ methodName, level, modalTitle, tableRowInfo }) {
+        if (this[methodName] && tableRowInfo.param === 'SEND') this[methodName](tableRowInfo, modalTitle)
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/DeviceStructure/Workshop/WorkshopInfo.vue b/src/views/dnc/base/modules/DeviceStructure/Workshop/WorkshopInfo.vue
new file mode 100644
index 0000000..13531a1
--- /dev/null
+++ b/src/views/dnc/base/modules/DeviceStructure/Workshop/WorkshopInfo.vue
@@ -0,0 +1,29 @@
+<template>
+  <a-descriptions bordered :size="size">
+    <a-descriptions-item label="杞﹂棿鍚嶇О">{{currentLevelDetails.title}}</a-descriptions-item>
+    <a-descriptions-item label="澶囨敞">{{currentLevelDetails.memo}}</a-descriptions-item>
+  </a-descriptions>
+</template>
+
+<script>
+  export default {
+    name: 'WorkshopInfo',
+    components: {},
+    props: {
+      currentLevelDetails: {
+        type: Object
+      },
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {}
+    },
+    methods: {}
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue b/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue
index 791e2ae..d3cd229 100644
--- a/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue
+++ b/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue
@@ -15,7 +15,7 @@
 <script>
   import { getAction } from '@/api/manage'
   import { JeecgListMixin } from '@/mixins/JeecgListMixin'
-  import DocumentModal from './DocumentModal'
+  import DocumentModal from '../../../../common/DocumentModal'
   import NcDocumentAssignModal from './NcDocumentAssignModal'
 
   export default {
@@ -121,8 +121,12 @@
         this.$refs.documentAssignModalRef.visible = true
       },
 
+      handleDelete() {
+        // 姝ゅ鍑芥暟涓哄睆钄絤ixins涓殑鍚屽悕鍑芥暟锛岄�氱敤鍑芥暟鍐欏湪鐖剁骇涓�
+      },
+
       triggerCorrespondingMethod({ methodName, level, modalTitle, tableRowInfo }) {
-        if (this[methodName]) this[methodName](tableRowInfo, modalTitle)
+        if (this[methodName] && tableRowInfo.param === 'NC') this[methodName](tableRowInfo, modalTitle)
       }
     }
   }
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue b/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue
index e4191af..d305e4e 100644
--- a/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue
+++ b/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue
@@ -12,7 +12,7 @@
 <script>
   import { getAction } from '@/api/manage'
   import { JeecgListMixin } from '@/mixins/JeecgListMixin'
-  import DocumentModal from './DocumentModal'
+  import DocumentModal from '../../../../common/DocumentModal'
 
   export default {
     name: 'OtherDocumentTableList',
@@ -110,8 +110,12 @@
         this.$refs.modalForm.title = modalTitle
       },
 
+      handleDelete() {
+        // 姝ゅ鍑芥暟涓哄睆钄絤ixins涓殑鍚屽悕鍑芥暟锛岄�氱敤鍑芥暟鍐欏湪鐖剁骇涓�
+      },
+
       triggerCorrespondingMethod({ methodName, level, modalTitle, tableRowInfo }) {
-        if (this[methodName] && tableRowInfo.attributionType === 1) this[methodName](tableRowInfo, modalTitle)
+        if (this[methodName] && tableRowInfo.param === 'OTHER') this[methodName](tableRowInfo, modalTitle)
       }
     }
   }
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue
index 4d36158..661bbb0 100644
--- a/src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue
@@ -52,11 +52,11 @@
   import ComponentInfo from './Component/ComponentInfo'
   import PartInfo from './Part/PartInfo'
   import ProcessInfo from './Process/ProcessInfo'
-  import DocumentInfo from './Document/DocumentInfo'
-  import DocumentVersionTableList from './Document/DocumentVersionTableList'
+  import DocumentInfo from '../../../common/DocumentInfo'
+  import DocumentVersionTableList from '../../../common/DocumentVersionTableList'
   import UseDocumentEquipmentTableList from './Document/UseNcDocumentEquipmentTableList'
   import ProcessStepInfo from './ProcessStep/ProcessStepInfo'
-  import FilePreview from './Document/FilePreview'
+  import FilePreview from '../../../common/FilePreview'
   import TableContextMenu from '../../../common/TableContextMenu'
 
   export default {
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
index d53279f..151b5d4 100644
--- a/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
@@ -86,9 +86,7 @@
         }
       },
 
-      /**
-       * 鐐瑰嚮涓嬭浇鏃惰Е鍙戜笅杞藉綋鍓嶆枃妗�
-       */
+      // 涓嬭浇褰撳墠鍙抽敭閫変腑鏂囨。
       handleDownload() {
         const that = this
         const { docId, docName } = this.currentRightClickedTableRowInfo
@@ -109,14 +107,49 @@
           })
       },
 
+      // 鍒犻櫎褰撳墠鍙抽敭閫変腑鏂囨。
+      handleDelete() {
+        const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
+        const that = this
+        that.$confirm({
+          title: '鎻愮ず',
+          content: `鍒犻櫎鍚庝笉鍙彇娑堬紝纭鍒犻櫎鍚楋紵`,
+          okText: '纭',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            dncApi.deleteDocumentApi(docId)
+              .then((res) => {
+                if (res.success) {
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                  that.reloadDocumentListData({ docClassCode: param, attributionId })
+                } else {
+                  that.$notification.warning({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel: () => {
+            that.$destroyAll()
+          }
+        })
+      },
+
       /**
-       * 鐐瑰嚮鍑哄簱鏃惰Е鍙戝綋鍓嶆枃妗e嚭搴�
+       * 鍑哄簱褰撳墠鍙抽敭閫変腑鏂囨。
        * @param menuLabel
        */
       handlePull(menuLabel) {
         const that = this
         const { docId, docName, param, attributionId } = this.currentRightClickedTableRowInfo
-        this.$confirm({
+        that.$confirm({
           title: '鎻愮ず',
           content: `纭${menuLabel}鍚楋紵`,
           okText: '纭',
@@ -126,7 +159,7 @@
               .then(res => {
                 console.log('res------------------', res)
                 if (res.success) {
-                  this.reloadDocumentListData({ docClassCode: param, attributionId })
+                  that.reloadDocumentListData({ docClassCode: param, attributionId })
                   that.$notification.success({
                     message: '娑堟伅',
                     description: `${menuLabel}鎴愬姛`
@@ -144,18 +177,24 @@
                   description: err.message
                 })
               })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel: () => {
+            that.$destroyAll()
           }
         })
       },
 
       /**
-       * 鐐瑰嚮鍙栨秷鍑哄簱鏃惰Е鍙戝綋鍓嶆枃妗e彇娑堝嚭搴�
+       * 鍙栨秷鍑哄簱褰撳墠鍙抽敭閫変腑鏂囨。
        * @param menuLabel
        */
       handleCancelPull(menuLabel) {
         const that = this
         const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
-        this.$confirm({
+        that.$confirm({
           title: '鎻愮ず',
           content: `纭${menuLabel}鍚楋紵`,
           okText: '纭',
@@ -182,19 +221,24 @@
                   description: err.message
                 })
               })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel() {
+            that.$destroyAll()
           }
         })
       },
 
-
       /**
-       * 鐐瑰嚮鍙戝竷鏃惰Е鍙戝綋鍓嶆枃妗e彂甯�
+       * 鍙戝竷褰撳墠鍙抽敭閫変腑鏂囨。
        * @param menuLabel
        */
       handlePublish(menuLabel) {
         const that = this
         const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
-        this.$confirm({
+        that.$confirm({
           title: '鎻愮ず',
           content: `纭${menuLabel}鍚楋紵`,
           okText: '纭',
@@ -222,18 +266,24 @@
                   description: err.message
                 })
               })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel() {
+            that.$destroyAll()
           }
         })
       },
 
       /**
-       * 鐐瑰嚮閲嶆柊鍙戝竷鏃惰Е鍙戝綋鍓嶆枃妗i噸鏂板彂甯冮��鍥炰笂涓�鐗堟湰
+       * 閲嶆柊鍙戝竷褰撳墠鍙抽敭閫変腑鏂囨。骞堕噸鏂板彂甯冮��鍥炰笂涓�鏂囨。鐗堟湰
        * @param menuLabel
        */
       handleRepublish(menuLabel) {
         const that = this
         const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
-        this.$confirm({
+        that.$confirm({
           title: '鎻愮ず',
           content: `纭${menuLabel}鍚楋紵`,
           okText: '纭',
@@ -260,18 +310,24 @@
                   description: err.message
                 })
               })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel() {
+            that.$destroyAll()
           }
         })
       },
 
       /**
-       * 鐐瑰嚮褰掓。鏃惰Е鍙戝綋鍓嶆枃妗e綊妗d笖鍚庣画鏃犳硶缁х画鍙戝竷鎴栧綊妗�
+       * 閲嶅綊妗e綋鍓嶅彸閿�変腑鏂囨。涓斿悗缁棤娉曠户缁彂甯冩垨褰掓。
        * @param menuLabel
        */
       handlePigeonhole(menuLabel) {
         const that = this
         const { docId, param, attributionId } = this.currentRightClickedTableRowInfo
-        this.$confirm({
+        that.$confirm({
           title: '鎻愮ず',
           content: `${menuLabel}鍚庝笉鍙彇娑堬紝纭${menuLabel}鍚楋紵`,
           okText: '纭',
@@ -298,13 +354,17 @@
                   description: err.message
                 })
               })
+              .finally(() => {
+                that.$destroyAll()
+              })
+          },
+          onCancel() {
+            that.$destroyAll()
           }
         })
       },
 
-      /**
-       * 鎺у埗鍙抽敭鑿滃崟鐐瑰嚮鍏抽棴
-       */
+      // 鎺у埗鍙抽敭鑿滃崟鍏抽棴
       handleMenuClose() {
         this.$refs.tableContextMenuRef.menuVisible = false
         document.body.removeEventListener('click', this.handleMenuClose)
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/DocumentBatchDeleteModal.vue b/src/views/dnc/common/DocumentBatchDeleteModal.vue
similarity index 100%
rename from src/views/dnc/base/modules/ProductStructure/Document/DocumentBatchDeleteModal.vue
rename to src/views/dnc/common/DocumentBatchDeleteModal.vue
diff --git a/src/views/dnc/common/DocumentInfo.vue b/src/views/dnc/common/DocumentInfo.vue
new file mode 100644
index 0000000..218d3e0
--- /dev/null
+++ b/src/views/dnc/common/DocumentInfo.vue
@@ -0,0 +1,40 @@
+<template>
+  <a-descriptions bordered :size="size">
+    <a-descriptions-item label="鏂囨。鍚嶇О">{{currentLevelDetails.docName}}</a-descriptions-item>
+    <a-descriptions-item label="浠g爜鐗堟湰">{{currentLevelDetails.docAlias}}</a-descriptions-item>
+    <a-descriptions-item label="璁惧缂栧彿	">{{currentLevelDetails.docCode}}</a-descriptions-item>
+    <a-descriptions-item label="鏂囨。鍚庣紑">{{currentLevelDetails.docSuffix}}</a-descriptions-item>
+    <a-descriptions-item label="鏂囨。鐘舵��">{{currentLevelDetails.docStatus_dictText}}</a-descriptions-item>
+    <a-descriptions-item label="绯荤粺鎸囧畾鐗堟湰">{{currentLevelDetails.publishVersion}}</a-descriptions-item>
+    <a-descriptions-item label="鍑哄簱鐘舵��">{{currentLevelDetails.pullStatus_dictText}}</a-descriptions-item>
+    <a-descriptions-item label="鍑哄簱浜�" :span="2">{{currentLevelDetails.pullUser_dictText}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓浜�">{{currentLevelDetails.createBy_dictText}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓鏃堕棿" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
+    <a-descriptions-item label="淇敼浜�">{{currentLevelDetails.updateBy_dictText}}</a-descriptions-item>
+    <a-descriptions-item label="淇敼鏃堕棿" :span="2">{{currentLevelDetails.updateTime}}</a-descriptions-item>
+    <a-descriptions-item label="鎻忚堪" :span="3">{{currentLevelDetails.description}}</a-descriptions-item>
+  </a-descriptions>
+</template>
+
+<script>
+  export default {
+    name: 'DocumentInfo',
+    components: {},
+    props: {
+      currentLevelDetails: {
+        type: Object
+      },
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {}
+    },
+    methods: {}
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/DocumentModal.vue b/src/views/dnc/common/DocumentModal.vue
similarity index 100%
rename from src/views/dnc/base/modules/ProductStructure/Document/DocumentModal.vue
rename to src/views/dnc/common/DocumentModal.vue
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/DocumentModalForm.vue b/src/views/dnc/common/DocumentModalForm.vue
similarity index 100%
rename from src/views/dnc/base/modules/ProductStructure/Document/DocumentModalForm.vue
rename to src/views/dnc/common/DocumentModalForm.vue
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/DocumentVersionTableList.vue b/src/views/dnc/common/DocumentVersionTableList.vue
similarity index 100%
rename from src/views/dnc/base/modules/ProductStructure/Document/DocumentVersionTableList.vue
rename to src/views/dnc/common/DocumentVersionTableList.vue
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/FileCompareModal.vue b/src/views/dnc/common/FileCompareModal.vue
similarity index 100%
rename from src/views/dnc/base/modules/ProductStructure/Document/FileCompareModal.vue
rename to src/views/dnc/common/FileCompareModal.vue
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/FilePreview.vue b/src/views/dnc/common/FilePreview.vue
similarity index 100%
rename from src/views/dnc/base/modules/ProductStructure/Document/FilePreview.vue
rename to src/views/dnc/common/FilePreview.vue
diff --git a/src/views/dnc/common/ImportFileModal.vue b/src/views/dnc/common/ImportFileModal.vue
index 585022f..b058e42 100644
--- a/src/views/dnc/common/ImportFileModal.vue
+++ b/src/views/dnc/common/ImportFileModal.vue
@@ -59,12 +59,14 @@
         if (treeNodeInfo) {
           attributionId = treeNodeInfo.treeKey
           attributionType = treeNodeInfo.type
+          if (attributionType === 5 || attributionType === 6) docClassCode = 'NC'
+          else if (attributionType === 4) docClassCode = 'SEND'
+          else docClassCode = 'OTHER'
         } else {
           attributionId = tableRowInfo.attributionId
           attributionType = tableRowInfo.attributionType
+          docClassCode = tableRowInfo.param
         }
-        if (attributionType === 5 || attributionType === 6) docClassCode = 'NC'
-        else docClassCode = 'OTHER'
         this.uploadParams = Object.assign({}, { attributionId, attributionType, docClassCode })
         this.visible = true
       },
@@ -97,9 +99,7 @@
         return false
       },
 
-      /**
-       * 鐐瑰嚮涓婁紶鑷虫湇鍔″櫒鎸夐挳鏃惰Е鍙�
-       */
+      // 鐐瑰嚮涓婁紶鑷虫湇鍔″櫒鎸夐挳鏃惰Е鍙�
       handleUpload() {
         const { fileList, $notification, isUploadMultiple, uploadParams, $bus, handleModalClose } = this
         this.uploading = true
@@ -171,9 +171,7 @@
         this.fileList = newFileList
       },
 
-      /**
-       * 鎺у埗鏂囦欢涓婁紶绐楀彛鍏抽棴骞舵竻绌烘枃浠跺垪琛�
-       */
+      // 鎺у埗鏂囦欢涓婁紶绐楀彛鍏抽棴骞舵竻绌烘枃浠跺垪琛�
       handleModalClose() {
         this.visible = false
         this.fileList = []
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/SelectFileCompareModal.vue b/src/views/dnc/common/SelectFileCompareModal.vue
similarity index 100%
rename from src/views/dnc/base/modules/ProductStructure/Document/SelectFileCompareModal.vue
rename to src/views/dnc/common/SelectFileCompareModal.vue
diff --git a/src/views/dnc/common/TableContextMenu.vue b/src/views/dnc/common/TableContextMenu.vue
index 96406b6..6a6385e 100644
--- a/src/views/dnc/common/TableContextMenu.vue
+++ b/src/views/dnc/common/TableContextMenu.vue
@@ -81,6 +81,25 @@
               icon: 'hourglass'
             }
           ],
+          SEND: [
+            { label: '缂栬緫鏂囨。淇℃伅', code: 'document_edit', subMenu: [], icon: 'edit', isCommonMethod: false },
+            { label: '瀵煎叆NC绋嬪簭', code: 'document_import', subMenu: [], icon: 'import', isCommonMethod: true },
+            { label: '涓嬭浇', code: 'document_download', subMenu: [], icon: 'download', isCommonMethod: true },
+            { label: '鍒犻櫎', code: 'document_delete', subMenu: [], icon: 'delete', isCommonMethod: true },
+            { label: '鎵归噺鍒犻櫎', code: 'document_batch_remove', subMenu: [], icon: 'delete', isCommonMethod: false },
+            {
+              label: '鐢熷懡鍛ㄦ湡',
+              subMenu: [
+                { label: '鍑哄簱', code: 'document_pull', icon: 'export', isCommonMethod: true },
+                { label: '鍙栨秷鍑哄簱', code: 'document_cancel_pull', icon: 'stop', isCommonMethod: true },
+                { label: '鍏ュ簱', code: 'document_push', icon: 'import', isCommonMethod: true },
+                { label: '鍙戝竷', code: 'document_publish', icon: 'flag', isCommonMethod: true },
+                { label: '閲嶆柊鍙戝竷', code: 'document_republish', icon: 'reload', isCommonMethod: true },
+                { label: '褰掓。', code: 'document_pigeonhole', icon: 'database', isCommonMethod: true }
+              ],
+              icon: 'hourglass'
+            }
+          ],
           //鏂囦欢
           file: [
             { label: '鎸囧畾褰撳墠鐗堟湰', code: 'file_assign', subMenu: [], icon: 'highlight', isCommonMethod: false },//鏂囦欢-鎸囧畾褰撳墠鐗堟湰

--
Gitblit v1.9.3