From 746977ae6cf544f92627bc3552763996025cb0b6 Mon Sep 17 00:00:00 2001
From: zhaowei <zhaowei>
Date: 星期五, 10 一月 2025 14:54:27 +0800
Subject: [PATCH] DNC产品结构树合并至MDC,已初步完成页面布局,现正在完善各个功能弹窗逻辑

---
 src/views/dnc/base/modules/ProductStructure/Document/DocumentInfo.vue                  |   36 
 src/views/dnc/base/modules/ProductStructure/ProcessStep/ProcessStepInfo.vue            |   20 
 src/views/dnc/base/modules/ProductStructure/Document/DocumentVersionTableList.vue      |   42 
 src/views/dnc/common/modules/ProductStructureTree/ProductStructureTreeContextMenu.vue  |  118 ++
 src/views/dnc/base/modules/ProductStructure/Document/UseDocumentEquipmentTableList.vue |   45 
 src/views/dnc/base/modules/ProductStructure/Process/ProcessModalForm.vue               |  196 ++++
 src/views/dnc/base/modules/ProductStructure/Process/ProcessTableList.vue               |  248 +++++
 src/views/dnc/base/modules/ProductStructure/ProductStructureMain.vue                   |   32 
 src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue             |   91 +
 src/views/dnc/common/ProductStructureTree.vue                                          |  644 +++++++++++++
 src/views/dnc/common/TableContextMenu.vue                                              |   87 +
 src/views/dnc/base/ProductStructure.vue                                                |   35 
 src/views/dnc/base/modules/ProductStructure/Component/ComponentModal.vue               |   92 +
 src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue           |  199 ++++
 src/views/dnc/common/ImportFileModal.vue                                               |  122 ++
 src/views/dnc/base/modules/ProductStructure/Process/ProcessInfo.vue                    |   44 
 src/views/dnc/base/modules/ProductStructure/Process/ProcessModal.vue                   |   56 +
 src/views/dnc/base/modules/ProductStructure/Product/ProductInfo.vue                    |   34 
 src/views/dnc/base/modules/ProductStructure/Component/ComponentInfo.vue                |   43 
 src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue        |  133 ++
 src/views/dnc/base/modules/ProductStructure/Product/ProductModal.vue                   |   70 +
 src/views/dnc/base/modules/ProductStructure/Product/ProductModalForm.vue               |  126 ++
 src/main.js                                                                            |    3 
 src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue                |   76 +
 src/views/dnc/base/modules/ProductStructure/Component/ComponentModalForm.vue           |  174 +++
 src/views/dnc/base/modules/ProductStructure/Part/PartInfo.vue                          |   43 
 26 files changed, 2,809 insertions(+), 0 deletions(-)

diff --git a/src/main.js b/src/main.js
index ebd34ec..5ce1354 100644
--- a/src/main.js
+++ b/src/main.js
@@ -80,6 +80,9 @@
   new Vue({
     router,
     store,
+    beforeCreate() {
+      Vue.prototype.$bus = new Vue()
+    },
     mounted () {
       store.commit('SET_SIDEBAR_TYPE', Vue.ls.get(SIDEBAR_TYPE, true))
       store.commit('TOGGLE_THEME', Vue.ls.get(DEFAULT_THEME, config.navTheme))
diff --git a/src/views/dnc/base/ProductStructure.vue b/src/views/dnc/base/ProductStructure.vue
new file mode 100644
index 0000000..0effc31
--- /dev/null
+++ b/src/views/dnc/base/ProductStructure.vue
@@ -0,0 +1,35 @@
+<template>
+  <a-card :bordered="false">
+    <a-row type="flex" :gutter="16">
+      <a-col :md="5">
+        <ProductStructureTree/>
+      </a-col>
+      <a-col :md="19">
+        <ProductStructureMain/>
+      </a-col>
+    </a-row>
+  </a-card>
+</template>
+
+<script>
+  import ProductStructureTree from '../common/ProductStructureTree'
+  import ProductStructureMain from './modules/ProductStructure/ProductStructureMain'
+
+  export default {
+    name: 'ProductStructure',
+    components: {
+      ProductStructureTree,
+      ProductStructureMain
+    },
+    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/ProductStructure/Component/ComponentInfo.vue b/src/views/dnc/base/modules/ProductStructure/Component/ComponentInfo.vue
new file mode 100644
index 0000000..84d9e3a
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Component/ComponentInfo.vue
@@ -0,0 +1,43 @@
+<template>
+  <a-descriptions bordered :size="size">
+    <a-descriptions-item label="閮ㄤ欢鍚嶇О">{{currentLevelDetails.componentName}}</a-descriptions-item>
+    <a-descriptions-item label="閮ㄤ欢浠e彿">{{currentLevelDetails.componentCode}}</a-descriptions-item>
+    <a-descriptions-item label="閮ㄤ欢鍨嬪彿	">{{currentLevelDetails.componentModel}}</a-descriptions-item>
+    <a-descriptions-item label="鐗╂枡缂栫爜">{{currentLevelDetails.materielCode}}</a-descriptions-item>
+    <a-descriptions-item label="鏉愭枡">{{currentLevelDetails.materielDesp}}</a-descriptions-item>
+    <a-descriptions-item label="瑙勬牸	">{{currentLevelDetails.componentScale}}</a-descriptions-item>
+    <a-descriptions-item label="瑁呴厤绫诲瀷">{{currentLevelDetails.assembleType}}</a-descriptions-item>
+    <a-descriptions-item label="鐢熶骇绫诲瀷">{{currentLevelDetails.produceType}}</a-descriptions-item>
+    <a-descriptions-item label="澶勭悊绫诲瀷	">{{currentLevelDetails.processType}}</a-descriptions-item>
+    <a-descriptions-item label="缁撴瀯绫诲瀷	">{{currentLevelDetails.structureType}}</a-descriptions-item>
+    <a-descriptions-item label="閲嶉噺" :span="2">{{currentLevelDetails.componentWeight}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓浜�">{{currentLevelDetails.createUser_dicText}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓鏃堕棿" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
+    <a-descriptions-item label="淇敼浜�">{{currentLevelDetails.updateUser_dicText}}</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: 'ComponentInfo',
+    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/Component/ComponentModal.vue b/src/views/dnc/base/modules/ProductStructure/Component/ComponentModal.vue
new file mode 100644
index 0000000..2b8c8f6
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Component/ComponentModal.vue
@@ -0,0 +1,92 @@
+<template>
+  <j-modal
+    :title="title"
+    :width="width"
+    :visible="visible"
+    switchFullscreen
+    :maskClosable="false"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="鍏抽棴">
+    <ComponentModalForm ref="realForm" @ok="submitCallback"/>
+  </j-modal>
+</template>
+
+<script>
+  import ComponentModalForm from './ComponentModalForm.vue'
+
+  export default {
+    name: 'ComponentModal',
+    components: {
+      ComponentModalForm
+    },
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      }
+    },
+    data() {
+      return {
+        title: '',
+        width: 700,
+        visible: false
+      }
+    },
+    created() {
+      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      /**
+       * 娣诲姞褰撳墠浜у搧閮ㄤ欢
+       * @param modalTitle
+       */
+      handleProductAddChild(modalTitle) {
+        this.title = modalTitle
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs.realForm.add()
+        })
+      },
+
+      /**
+       * 娣诲姞褰撳墠閮ㄤ欢鐨勫瓙閮ㄤ欢
+       * @param modalTitle
+       */
+      handleComponentAdd(modalTitle) {
+        this.title = modalTitle
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs.realForm.add()
+        })
+      },
+
+      handleComponentEdit(modalTitle) {
+        this.title = modalTitle
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs.realForm.edit(this.currentTreeNodeInfo.entity)
+        })
+      },
+
+      handleOk() {
+        this.$refs.realForm.submitForm()
+      },
+
+      submitCallback() {
+        this.$emit('ok')
+        this.visible = false
+      },
+
+      handleCancel() {
+        this.$emit('close')
+        this.visible = false
+      },
+
+      triggerCorrespondingMethod({ methodName, modalTitle }) {
+        console.log('methodName', methodName)
+        console.log('modalTitle', modalTitle)
+        if (this[methodName]) this[methodName](modalTitle)
+      }
+    }
+  }
+</script>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Component/ComponentModalForm.vue b/src/views/dnc/base/modules/ProductStructure/Component/ComponentModalForm.vue
new file mode 100644
index 0000000..b6e6eef
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Component/ComponentModalForm.vue
@@ -0,0 +1,174 @@
+<template>
+  <a-spin :spinning="confirmLoading">
+    <a-form-model ref="form" :model="model" :rules="validatorRules" :labelCol="labelCol" :wrapperCol="wrapperCol">
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="閮ㄤ欢鍚嶇О" prop="componentName">
+            <a-input v-model="model.componentName" placeholder="璇疯緭鍏ラ儴浠跺悕绉�"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="浠e彿" prop="componentCode">
+            <a-input v-model="model.componentCode" placeholder="璇疯緭鍏ヤ唬鍙�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="閮ㄤ欢鍨嬪彿">
+            <a-input v-model="model.componentModel" placeholder="璇疯緭鍏ラ儴浠跺瀷鍙�"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="瑙勬牸">
+            <a-input v-model="model.productName" placeholder="璇疯緭鍏ヨ鏍�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="瑁呴厤绫诲瀷" :labelCol="labelCol" :wrapperCol="wrapperCol">
+            <a-input v-model="model.assembleType" placeholder="璇疯緭鍏ヨ閰嶇被鍨�"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="閲嶉噺">
+            <a-input v-model="model.componentWeight" placeholder="璇疯緭鍏ラ噸閲�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="鐗╂枡缂栫爜">
+            <a-input v-model="model.materielCode" placeholder="璇疯緭鍏ョ墿鏂欑紪鐮�"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="缁撴瀯绫诲瀷">
+            <a-input v-model="model.structureType" placeholder="璇疯緭鍏ョ粨鏋勭被鍨�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="澶勭悊绫诲瀷">
+            <a-input v-model="model.processType" placeholder="璇疯緭鍏ュ鐞嗙被鍨�"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="鐢熶骇绫诲瀷">
+            <a-input v-model="model.produceType" placeholder="璇疯緭鍏ョ敓浜х被鍨�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="24">
+          <a-form-model-item label="鎻忚堪" :labelCol="labelColLong" :wrapperCol="wrapperColLong">
+            <a-textarea v-model="model.description" placeholder="璇疯緭鍏ユ弿杩�"></a-textarea>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+    </a-form-model>
+  </a-spin>
+</template>
+
+<script>
+  import { httpAction, getAction } from '@/api/manage'
+
+  export default {
+    name: 'ComponentModalForm',
+    components: {},
+    data() {
+      return {
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 8 }
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 14 }
+        },
+        labelColLong: {
+          xs: { span: 24 },
+          sm: { span: 4 }
+        },
+        wrapperColLong: {
+          xs: { span: 24 },
+          sm: { span: 19 }
+        },
+        confirmLoading: false,
+        validatorRules: {
+          componentName: [
+            { required: true, message: '璇疯緭鍏ラ儴浠跺悕绉�!' }
+          ],
+          componentCode: [
+            { 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({}, record)
+        console.log('model', this.model)
+        this.visible = true
+      },
+
+      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
+            })
+          }
+        })
+      }
+    }
+  }
+</script>
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/DocumentInfo.vue b/src/views/dnc/base/modules/ProductStructure/Document/DocumentInfo.vue
new file mode 100644
index 0000000..d100d67
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Document/DocumentInfo.vue
@@ -0,0 +1,36 @@
+<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}}</a-descriptions-item>
+    <a-descriptions-item label="绯荤粺鎸囧畾鐗堟湰">{{currentLevelDetails.publishVersion}}</a-descriptions-item>
+    <a-descriptions-item label="鍑哄簱鐘舵��">{{currentLevelDetails.pullStatus}}</a-descriptions-item>
+    <a-descriptions-item label="鍑哄簱浜�" :span="2">{{currentLevelDetails.pullUser}}</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/DocumentVersionTableList.vue b/src/views/dnc/base/modules/ProductStructure/Document/DocumentVersionTableList.vue
new file mode 100644
index 0000000..14f5344
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Document/DocumentVersionTableList.vue
@@ -0,0 +1,42 @@
+<template>
+  <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false">
+
+  </a-table>
+</template>
+
+<script>
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+
+  export default {
+    name: 'DocumentVersionTableList',
+    mixins: [JeecgListMixin],
+    components: {},
+    data() {
+      return {
+        columns: [
+          {
+            title: '搴忓彿',
+            dataIndex: 'rowIndex',
+            key: 'rowIndex',
+            width: 65,
+            align: 'center',
+            customRender: function(t, r, index) {
+              return parseInt(index) + 1
+            }
+          },
+          { title: '鏂囦欢鍚嶇О', dataIndex: 'fileName', align: 'center' },
+          { title: '鐗堟湰鍙�', dataIndex: 'docVersion', align: 'center' },
+          { title: '鏂囦欢澶у皬', dataIndex: 'fileSize', align: 'center' }
+        ],
+        url: {
+          list: ''
+        }
+      }
+    },
+    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
new file mode 100644
index 0000000..f4f7136
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Document/NcDocumentTableList.vue
@@ -0,0 +1,199 @@
+<template>
+  <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+           :scroll="{y:189}" :customRow="customRow" :size="size" rowKey="docId">
+
+  </a-table>
+</template>
+
+<script>
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+
+  export default {
+    name: 'NcDocumentTableList',
+    components: {},
+    mixins: [JeecgListMixin],
+    props: {
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {
+        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', align: 'center' },
+          { title: '鐘�  鎬�', dataIndex: 'docStatus', align: 'center' },
+          { title: '绯荤粺鎸囧畾鐗堟湰', dataIndex: 'publishVersion', align: 'center' },
+          { title: '涓婁紶鏃堕棿', dataIndex: 'createTime', align: 'center' }
+        ],
+        dataSource: [
+          {
+            'docId': '1876099281127645185',
+            'docName': 'avatar2.jpg',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'jpg',
+            'docStatus': 1,
+            'publishFileId': '1876099281458995202',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2025-01-06 10:51:40',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 5,
+            'attributionId': '1868504592315248641',
+            'classificationId': '1257965381181095938',
+            'syncStatus': null
+          },
+          {
+            'docId': '1876114720452943873',
+            'docName': 'color.less',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'less',
+            'docStatus': 1,
+            'publishFileId': '1876114720582967297',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2025-01-06 11:53:01',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 5,
+            'attributionId': '1868504592315248641',
+            'classificationId': '1257965381181095938',
+            'syncStatus': null
+          },
+          {
+            'docId': '1876114736512933889',
+            'docName': 'index.html',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'html',
+            'docStatus': 1,
+            'publishFileId': '1876114736705871874',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2025-01-06 11:53:05',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 5,
+            'attributionId': '1868504592315248641',
+            'classificationId': '1257965381181095938',
+            'syncStatus': null
+          },
+          {
+            'docId': '1876114746621206529',
+            'docName': 'logo.png',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'png',
+            'docStatus': 1,
+            'publishFileId': '1876114746818338818',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2025-01-06 11:53:07',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 5,
+            'attributionId': '1868504592315248641',
+            'classificationId': '1257965381181095938',
+            'syncStatus': null
+          },
+          {
+            'docId': '1876114758923100161',
+            'docName': 'lxzn.png',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'png',
+            'docStatus': 1,
+            'publishFileId': '1876114759111843842',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2025-01-06 11:53:10',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 5,
+            'attributionId': '1868504592315248641',
+            'classificationId': '1257965381181095938',
+            'syncStatus': null
+          },
+          {
+            'docId': '1876114776241381377',
+            'docName': 'v2.js',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'js',
+            'docStatus': 1,
+            'publishFileId': '1876114776438513666',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2025-01-06 11:53:14',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 5,
+            'attributionId': '1868504592315248641',
+            'classificationId': '1257965381181095938',
+            'syncStatus': null
+          }
+        ],
+        url: {
+          list: ''
+        }
+      }
+    },
+    methods: {
+      customRow(record) {
+        return {
+          on: {
+            contextmenu: event => {
+              event.preventDefault()
+              this.$emit('handleTableContextMenuOpen', { ...record, param: 'document' })
+            },
+            click: () => {
+              this.$bus.$emit('sendCurrentLevelInfo', record)
+            }
+          }
+        }
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue b/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue
new file mode 100644
index 0000000..7ba6363
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Document/OtherDocumentTableList.vue
@@ -0,0 +1,133 @@
+<template>
+  <a-table :columns="columns" :data-source="dataSource" bordered :pagination="ipagination"
+           :scroll="{y:189}" :customRow="customRow" :size="size">
+
+  </a-table>
+</template>
+
+<script>
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+
+  export default {
+    name: 'OtherDocumentTableList',
+    components: {},
+    mixins: [JeecgListMixin],
+    props: {
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {
+        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', align: 'center' },
+          { title: '鐘�  鎬�', dataIndex: 'docStatus', align: 'center' },
+          { title: '绯荤粺鎸囧畾鐗堟湰', dataIndex: 'publishVersion', align: 'center' },
+          { title: '涓婁紶鏃堕棿', dataIndex: 'createTime', align: 'center' }
+        ],
+        dataSource: [
+          {
+            'docId': '1868943615190044674',
+            'docName': '娴嬭瘯.nc',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'nc',
+            'docStatus': 1,
+            'publishFileId': '1868943615454285825',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2024-12-17 16:57:36',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 1,
+            'attributionId': '1326377675659276290',
+            'classificationId': '1257965467827027969',
+            'syncStatus': null
+          },
+          {
+            'docId': '1868946627732103170',
+            'docName': 'nacos-config.sh',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'sh',
+            'docStatus': 1,
+            'publishFileId': '1868946628004732930',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2024-12-17 17:09:34',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 1,
+            'attributionId': '1326377675659276290',
+            'classificationId': '1257965467827027969',
+            'syncStatus': null
+          },
+          {
+            'docId': '1868947564353740801',
+            'docName': 'dir.sql',
+            'docAlias': null,
+            'docCode': null,
+            'docSuffix': 'sql',
+            'docStatus': 1,
+            'publishFileId': '1868947564487958530',
+            'publishVersion': 'a.1',
+            'description': null,
+            'createTime': '2024-12-17 17:13:17',
+            'updateTime': null,
+            'createUser': '1254966905669160962',
+            'updateUser': null,
+            'docClassCode': null,
+            'pullStatus': 1,
+            'pullUser': null,
+            'attributionType': 1,
+            'attributionId': '1326377675659276290',
+            'classificationId': '1257965467827027969',
+            'syncStatus': null
+          }
+        ],
+        url: {
+          list: ''
+        }
+      }
+    },
+    methods: {
+      customRow(record) {
+        return {
+          on: {
+            contextmenu: event => {
+              event.preventDefault()
+              this.$emit('handleTableContextMenuOpen', { ...record, param: 'document' })
+            },
+            click: () => {
+              this.$bus.$emit('sendCurrentLevelInfo', record)
+            }
+          }
+        }
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Document/UseDocumentEquipmentTableList.vue b/src/views/dnc/base/modules/ProductStructure/Document/UseDocumentEquipmentTableList.vue
new file mode 100644
index 0000000..423f62c
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Document/UseDocumentEquipmentTableList.vue
@@ -0,0 +1,45 @@
+<template>
+  <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false">
+
+  </a-table>
+</template>
+
+<script>
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+
+  export default {
+    name: 'UseDocumentEquipmentTableList',
+    components: {},
+    mixins: [JeecgListMixin],
+    data() {
+      return {
+        columns: [
+          {
+            title: '搴忓彿',
+            dataIndex: 'rowIndex',
+            key: 'rowIndex',
+            width: 65,
+            align: 'center',
+            customRender: function(t, r, index) {
+              return parseInt(index) + 1
+            }
+          },
+          { title: '璁惧鍚嶇О', dataIndex: 'deviceName', align: 'center' },
+          { title: '璁惧缂栧彿', dataIndex: 'deviceNo', align: 'center' },
+          { title: '璁惧鍨嬪彿', dataIndex: 'deviceModel', align: 'center' },
+          { title: '鎵�灞為儴闂�', dataIndex: 'departName', align: 'center' },
+          { title: '璁惧鍒嗙粍', dataIndex: 'groupName', align: 'center' },
+          { title: '鎺у埗绯荤粺', dataIndex: 'controlSystem', align: 'center' }
+        ],
+        url: {
+          list: ''
+        }
+      }
+    },
+    methods: {}
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Part/PartInfo.vue b/src/views/dnc/base/modules/ProductStructure/Part/PartInfo.vue
new file mode 100644
index 0000000..5f43682
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Part/PartInfo.vue
@@ -0,0 +1,43 @@
+<template>
+  <a-descriptions bordered :size="size">
+    <a-descriptions-item label="闆朵欢鍚嶇О">{{currentLevelDetails.partsName}}</a-descriptions-item>
+    <a-descriptions-item label="闆朵欢浠e彿">{{currentLevelDetails.partsCode}}</a-descriptions-item>
+    <a-descriptions-item label="闆朵欢鍨嬪彿	">{{currentLevelDetails.partsModel}}</a-descriptions-item>
+    <a-descriptions-item label="鐗╂枡缂栫爜">{{currentLevelDetails.materielCode}}</a-descriptions-item>
+    <a-descriptions-item label="鏉愭枡">{{currentLevelDetails.materielDesp}}</a-descriptions-item>
+    <a-descriptions-item label="瑙勬牸	">{{currentLevelDetails.partsScale}}</a-descriptions-item>
+    <a-descriptions-item label="瑁呴厤绫诲瀷">{{currentLevelDetails.assembleType}}</a-descriptions-item>
+    <a-descriptions-item label="鐢熶骇绫诲瀷">{{currentLevelDetails.produceType}}</a-descriptions-item>
+    <a-descriptions-item label="澶勭悊绫诲瀷	">{{currentLevelDetails.processType}}</a-descriptions-item>
+    <a-descriptions-item label="缁撴瀯绫诲瀷	">{{currentLevelDetails.structureType}}</a-descriptions-item>
+    <a-descriptions-item label="閲嶉噺" :span="2">{{currentLevelDetails.partsWeight}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓浜�">{{currentLevelDetails.createUser_dicText}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓鏃堕棿" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
+    <a-descriptions-item label="淇敼浜�">{{currentLevelDetails.updateUser_dicText}}</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: 'PartInfo',
+    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/Process/ProcessInfo.vue b/src/views/dnc/base/modules/ProductStructure/Process/ProcessInfo.vue
new file mode 100644
index 0000000..e440a15
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Process/ProcessInfo.vue
@@ -0,0 +1,44 @@
+<template>
+  <a-descriptions bordered :size="size">
+    <a-descriptions-item label="宸ュ簭鍚嶇О">{{currentLevelDetails.processName|isValueNull}}</a-descriptions-item>
+    <a-descriptions-item label="宸ュ簭鍙�">{{currentLevelDetails.processCode|isValueNull}}</a-descriptions-item>
+    <a-descriptions-item label="宸ヨ壓缂栧彿	">{{currentLevelDetails.craftNo|isValueNull}}</a-descriptions-item>
+    <a-descriptions-item label="宸ュ簭绫诲瀷">{{currentLevelDetails.processType|isValueNull}}</a-descriptions-item>
+    <a-descriptions-item label="鍔犲伐璁惧鍨嬪彿">{{currentLevelDetails.processingEquipmentModel|isValueNull}}
+    </a-descriptions-item>
+    <a-descriptions-item label="鍔犲伐璁惧绫诲瀷">{{currentLevelDetails.processingEquipmentOs|isValueNull}}</a-descriptions-item>
+    <a-descriptions-item label="鍔犲伐璁惧缂栧彿">{{currentLevelDetails.processingEquipmentCode|isValueNull}}
+    </a-descriptions-item>
+    <a-descriptions-item label="宸ヨ缂栧彿">{{currentLevelDetails.assembleStep|isValueNull}}</a-descriptions-item>
+    <a-descriptions-item label="宸ヨ鍚嶇О	">{{currentLevelDetails.assembleName|isValueNull}}</a-descriptions-item>
+    <a-descriptions-item label="鎻忚堪" :span="3">{{currentLevelDetails.description|isValueNull}}</a-descriptions-item>
+  </a-descriptions>
+</template>
+
+<script>
+  export default {
+    name: 'ProcessInfo',
+    components: {},
+    props: {
+      currentLevelDetails: {
+        type: Object
+      },
+      size: {
+        type: String
+      }
+    },
+    filters: {
+      isValueNull(value) {
+        return !value || value == null ? '' : value
+      }
+    },
+    data() {
+      return {}
+    },
+    methods: {}
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Process/ProcessModal.vue b/src/views/dnc/base/modules/ProductStructure/Process/ProcessModal.vue
new file mode 100644
index 0000000..60bea4b
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Process/ProcessModal.vue
@@ -0,0 +1,56 @@
+<template>
+  <j-modal
+    :title="title"
+    :width="width"
+    :visible="visible"
+    switchFullscreen
+    :maskClosable="false"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="鍏抽棴">
+    <ProcessModalForm ref="realForm" @ok="submitCallback"/>
+  </j-modal>
+</template>
+
+<script>
+  import ProcessModalForm from './ProcessModalForm.vue'
+
+  export default {
+    name: 'ProcessModal',
+    components: {
+      ProcessModalForm
+    },
+    data() {
+      return {
+        title: '',
+        width: 700,
+        visible: false
+      }
+    },
+    methods: {
+      add() {
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs.realForm.add()
+        })
+      },
+      edit(record) {
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs.realForm.edit(record)
+        })
+      },
+      handleOk() {
+        this.$refs.realForm.submitForm()
+      },
+      submitCallback() {
+        this.$emit('ok')
+        this.visible = false
+      },
+      handleCancel() {
+        this.$emit('close')
+        this.visible = false
+      }
+    }
+  }
+</script>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Process/ProcessModalForm.vue b/src/views/dnc/base/modules/ProductStructure/Process/ProcessModalForm.vue
new file mode 100644
index 0000000..cd0e076
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Process/ProcessModalForm.vue
@@ -0,0 +1,196 @@
+<template>
+  <a-spin :spinning="confirmLoading">
+    <a-form-model ref="form" :model="model" :rules="validatorRules">
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="宸ュ簭鍙�" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="processCode">
+            <a-input v-model="model.processCode" placeholder="璇疯緭鍏ュ伐搴忓彿"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="宸ュ簭鍚嶇О" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="processName">
+            <a-input v-model="model.processName" placeholder="璇疯緭鍏ュ伐搴忓悕绉�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="24">
+          <a-form-model-item label="鍔犲伐璁惧缂栧彿" :labelCol="labelColLong" :wrapperCol="wrapperColLong">
+            <a-select v-model="model.processingEquipmentCode" placeholder="璇烽�夋嫨鍔犲伐璁惧缂栧彿"></a-select>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="宸ヨ壓缂栧彿" :labelCol="labelCol" :wrapperCol="wrapperCol">
+            <a-input v-model="model.craftNo" placeholder="璇疯緭鍏ュ伐鑹虹紪鍙�"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="宸ヨ壓瑙勭▼鐗堟湰" :labelCol="labelCol" :wrapperCol="wrapperCol">
+            <a-input v-model="model.craftVersion" placeholder="璇疯緭鍏ュ伐鑹鸿绋嬬増鏈�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="宸ュ簭绫诲瀷" :labelCol="labelCol" :wrapperCol="wrapperCol">
+            <a-input v-model="model.processType" placeholder="璇疯緭鍏ュ伐搴忕被鍨�"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="宸ュ簭鎻忚堪" :labelCol="labelCol" :wrapperCol="wrapperCol">
+            <a-input v-model="model.description" placeholder="璇疯緭鍏ュ伐搴忔弿杩�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="12">
+          <a-form-model-item label="宸ヨ缂栧彿" :labelCol="labelCol" :wrapperCol="wrapperCol">
+            <a-input v-model="model.assembleStep" placeholder="璇疯緭鍏ュ伐瑁呯紪鍙�"></a-input>
+          </a-form-model-item>
+        </a-col>
+        <a-col :span="12">
+          <a-form-model-item label="宸ヨ鍚嶇О" :labelCol="labelCol" :wrapperCol="wrapperCol">
+            <a-input v-model="model.assembleName" placeholder="璇疯緭鍏ュ伐瑁呭悕绉�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+    </a-form-model>
+
+    <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: 'ProcessModalForm',
+    components: { SelectDeviceDrawer },
+    data() {
+      return {
+        model: {
+          passCount: 0
+        },
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 8 }
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 14 }
+        },
+        labelColLong: {
+          xs: { span: 24 },
+          sm: { span: 4 }
+        },
+        wrapperColLong: {
+          xs: { span: 24 },
+          sm: { span: 19 }
+        },
+        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>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Process/ProcessTableList.vue b/src/views/dnc/base/modules/ProductStructure/Process/ProcessTableList.vue
new file mode 100644
index 0000000..142402e
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Process/ProcessTableList.vue
@@ -0,0 +1,248 @@
+<template>
+  <div>
+    <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false"
+             :scroll="{y:227}" :customRow="customRow" :size="size" rowKey="processId">
+
+    </a-table>
+
+    <ProcessModal ref="modalForm" @ok="modalFormOk"/>
+
+    <ImportFileModal ref="importFileModal"/>
+  </div>
+</template>
+
+<script>
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+  import ProcessModal from './ProcessModal'
+  import ImportFileModal from '../../../../common/ImportFileModal'
+
+  export default {
+    name: 'ProcessTableList',
+    components: { ImportFileModal, ProcessModal },
+    mixins: [JeecgListMixin],
+    props: {
+      size: {
+        type: String
+      }
+    },
+    data() {
+      return {
+        columns: [
+          {
+            title: '宸ュ簭鍙�',
+            dataIndex: 'processCode',
+            align: 'center',
+            sorter: (a, b) => a.processNo - b.processNo,
+            sortDirections: ['descend', 'ascend']
+          },
+          {
+            title: '宸ュ簭缂栧彿',
+            dataIndex: 'craftNo',
+            align: 'center',
+            sorter: (a, b) => a.processId - b.processId,
+            sortDirections: ['descend', 'ascend']
+          },
+          {
+            title: '宸ュ簭鍚嶇О',
+            dataIndex: 'processName',
+            align: 'center',
+            sorter: (a, b) => a.processName.length - b.processName.length,
+            sortDirections: ['descend', 'ascend']
+          }
+        ],
+        dataSource: [
+          {
+            'processId': '1327516286572163080',
+            'productId': '1326377675659276290',
+            'componentId': '1327516286505054210',
+            'partsId': null,
+            'processName': null,
+            'processCode': '1',
+            'craftNo': null,
+            'craftVersion': null,
+            'processType': null,
+            'processingEquipmentModel': null,
+            'processingEquipmentCode': null,
+            'assembleStep': null,
+            'assembleName': null,
+            'description': null
+          },
+          {
+            'processId': '1701841077007798274',
+            'productId': '1326377675659276290',
+            'componentId': '1327516286505054210',
+            'partsId': null,
+            'processName': '2113',
+            'processCode': '111',
+            'craftNo': '',
+            'craftVersion': '',
+            'processType': 0,
+            'processingEquipmentModel': '',
+            'processingEquipmentCode': '',
+            'assembleStep': '',
+            'assembleName': '',
+            'description': ''
+          },
+          {
+            'processId': '1875082575626289153',
+            'productId': '1326377675659276290',
+            'componentId': '1327516286505054210',
+            'partsId': null,
+            'processName': '333',
+            'processCode': '3213',
+            'craftNo': '',
+            'craftVersion': '',
+            'processType': 0,
+            'processingEquipmentModel': '',
+            'processingEquipmentCode': '',
+            'assembleStep': '',
+            'assembleName': '',
+            'description': ''
+          },
+          {
+            'processId': '1875082597210177537',
+            'productId': '1326377675659276290',
+            'componentId': '1327516286505054210',
+            'partsId': null,
+            'processName': '123',
+            'processCode': 'sd',
+            'craftNo': '',
+            'craftVersion': '',
+            'processType': 0,
+            'processingEquipmentModel': '',
+            'processingEquipmentCode': '',
+            'assembleStep': '',
+            'assembleName': '',
+            'description': ''
+          },
+          {
+            'processId': '1875082616835325954',
+            'productId': '1326377675659276290',
+            'componentId': '1327516286505054210',
+            'partsId': null,
+            'processName': 'dadas',
+            'processCode': 'sadsa',
+            'craftNo': '',
+            'craftVersion': '',
+            'processType': 0,
+            'processingEquipmentModel': '',
+            'processingEquipmentCode': '',
+            'assembleStep': '',
+            'assembleName': '',
+            'description': ''
+          },
+          {
+            'processId': '1875082638553432066',
+            'productId': '1326377675659276290',
+            'componentId': '1327516286505054210',
+            'partsId': null,
+            'processName': '1213',
+            'processCode': 'das',
+            'craftNo': '',
+            'craftVersion': '',
+            'processType': 0,
+            'processingEquipmentModel': '',
+            'processingEquipmentCode': '',
+            'assembleStep': '',
+            'assembleName': '',
+            'description': ''
+          },
+          {
+            'processId': '1875082668072943617',
+            'productId': '1326377675659276290',
+            'componentId': '1327516286505054210',
+            'partsId': null,
+            'processName': 'zxccz',
+            'processCode': 'asdasda',
+            'craftNo': '',
+            'craftVersion': '',
+            'processType': 0,
+            'processingEquipmentModel': '',
+            'processingEquipmentCode': '',
+            'assembleStep': '',
+            'assembleName': '',
+            'description': ''
+          }
+        ],
+        currentRowInfo: {},
+        url: {
+          list: '',
+          add: '',
+          edit: '',
+          delete: ''
+        }
+      }
+    },
+    created() {
+      this.$bus.$on('menuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      /**
+       * 鑷畾涔夎〃鏍艰鍔熻兘
+       * @param record 琛ㄦ牸琛屼俊鎭�
+       * @returns {{on: {contextmenu: on.contextmenu, click: on.click}}} 杩斿洖浜嬩欢鏂规硶瀵硅薄
+       */
+      customRow(record) {
+        return {
+          on: {
+            contextmenu: event => {
+              event.preventDefault()
+              this.currentRowInfo = Object.assign({}, record)
+              this.$emit('handleTableContextMenuOpen', { objectId: record.processId, param: 'process' })
+            },
+            click: () => {
+              this.$bus.$emit('sendCurrentLevelInfo', record)
+            }
+          }
+        }
+      },
+
+      /**
+       * 鐐瑰嚮鍒涘缓宸ュ簭鑿滃崟鏃惰Е鍙�
+       * @param modalTitle
+       */
+      handleProcessAdd(modalTitle) {
+        this.$refs.modalForm.add()
+        this.$refs.modalForm.title = modalTitle
+      },
+
+      /**
+       * 鐐瑰嚮缂栬緫宸ュ簭鑿滃崟鏃惰Е鍙�
+       * @param modalTitle
+       */
+      handleProcessEdit(modalTitle) {
+        this.$refs.modalForm.edit(this.currentRowInfo)
+        this.$refs.modalForm.title = modalTitle
+      },
+
+      /**
+       *  鐐瑰嚮鍒犻櫎鏃惰Е鍙�
+       */
+      handleProcessDelete() {
+        this.$confirm({
+          title: '鎻愮ず',
+          content: '纭鍒犻櫎姝ゆ潯璁板綍鍚楋紵',
+          okText: '纭',
+          okType: 'danger',
+          cancelText: '鍙栨秷',
+          onOk: () => {
+            this.handleDelete(this.currentRowInfo.processId)
+          }
+        })
+      },
+
+      handleProcessImport(modalTitle) {
+        this.$refs.importFileModal.visible = true
+        this.$refs.importFileModal.title = modalTitle
+      },
+
+      triggerCorrespondingMethod({ methodName, level, modalTitle }) {
+        if (level === 'process') this[methodName](modalTitle)
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/ProcessStep/ProcessStepInfo.vue b/src/views/dnc/base/modules/ProductStructure/ProcessStep/ProcessStepInfo.vue
new file mode 100644
index 0000000..07987c5
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/ProcessStep/ProcessStepInfo.vue
@@ -0,0 +1,20 @@
+<template>
+    <div>
+
+    </div>
+</template>
+
+<script>
+  export default {
+    name: 'ProcessStepInfo',
+    components: {},
+    data() {
+      return {}
+    },
+    methods: {}
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Product/ProductInfo.vue b/src/views/dnc/base/modules/ProductStructure/Product/ProductInfo.vue
new file mode 100644
index 0000000..da4feb0
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Product/ProductInfo.vue
@@ -0,0 +1,34 @@
+<template>
+  <a-descriptions bordered :size="size">
+    <a-descriptions-item label="浜у搧鍚嶇О">{{currentLevelDetails.productName}}</a-descriptions-item>
+    <a-descriptions-item label="浜у搧鍨嬪彿">{{currentLevelDetails.productModel}}</a-descriptions-item>
+    <a-descriptions-item label="浜у搧浠g爜	">{{currentLevelDetails.productNo}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓浜�">{{currentLevelDetails.createUser_dicText}}</a-descriptions-item>
+    <a-descriptions-item label="鍒涘缓鏃堕棿" :span="2">{{currentLevelDetails.createTime}}</a-descriptions-item>
+    <a-descriptions-item label="淇敼浜�">{{currentLevelDetails.updateUser_dicText}}</a-descriptions-item>
+    <a-descriptions-item label="淇敼鏃堕棿" :span="2">{{currentLevelDetails.updateTime}}</a-descriptions-item>
+  </a-descriptions>
+</template>
+
+<script>
+  export default {
+    name: 'ProductInfo',
+    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/Product/ProductModal.vue b/src/views/dnc/base/modules/ProductStructure/Product/ProductModal.vue
new file mode 100644
index 0000000..e808a87
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Product/ProductModal.vue
@@ -0,0 +1,70 @@
+<template>
+  <j-modal
+    :title="title"
+    :width="width"
+    :visible="visible"
+    switchFullscreen
+    :maskClosable="false"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="鍏抽棴">
+    <ProductModalForm ref="realForm" @ok="submitCallback"/>
+  </j-modal>
+</template>
+
+<script>
+  import ProductModalForm from './ProductModalForm.vue'
+
+  export default {
+    name: 'ProductModal',
+    components: {
+      ProductModalForm
+    },
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      }
+    },
+    data() {
+      return {
+        title: '',
+        width: 500,
+        visible: false
+      }
+    },
+    created() {
+      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      handleProductAdd(modalTitle) {
+        this.title = modalTitle
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs.realForm.add()
+        })
+      },
+      handleProductEdit(modalTitle) {
+        this.title = modalTitle
+        this.visible = true
+        this.$nextTick(() => {
+          this.$refs.realForm.edit(this.currentTreeNodeInfo.entity)
+        })
+      },
+      handleOk() {
+        this.$refs.realForm.submitForm()
+      },
+      submitCallback() {
+        this.$emit('ok')
+        this.visible = false
+      },
+      handleCancel() {
+        this.$emit('close')
+        this.visible = false
+      },
+
+      triggerCorrespondingMethod({ methodName, modalTitle }) {
+        if (this[methodName]) this[methodName](modalTitle)
+      }
+    }
+  }
+</script>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Product/ProductModalForm.vue b/src/views/dnc/base/modules/ProductStructure/Product/ProductModalForm.vue
new file mode 100644
index 0000000..83f50a6
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Product/ProductModalForm.vue
@@ -0,0 +1,126 @@
+<template>
+  <a-spin :spinning="confirmLoading">
+    <a-form-model ref="form" :model="model" :rules="validatorRules" :labelCol="labelColLong"
+                  :wrapperCol="wrapperColLong">
+      <a-row>
+        <a-col :span="24">
+          <a-form-model-item label="浜у搧鍚嶇О" prop="productName">
+            <a-input v-model="model.productName" placeholder="璇疯緭鍏ヤ骇鍝佸悕绉�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="24">
+          <a-form-model-item label="浜у搧浠e彿" prop="productNo">
+            <a-input v-model="model.productNo" placeholder="璇疯緭鍏ヤ骇鍝佷唬鍙�"></a-input>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+
+      <a-row>
+        <a-col :span="24">
+          <a-form-model-item label="浜у搧鍨嬪彿">
+            <a-textarea v-model="model.productModel" placeholder="璇疯緭鍏ヤ骇鍝佸瀷鍙�"></a-textarea>
+          </a-form-model-item>
+        </a-col>
+      </a-row>
+    </a-form-model>
+  </a-spin>
+</template>
+
+<script>
+  import { httpAction, getAction } from '@/api/manage'
+
+  export default {
+    name: 'ProductModalForm',
+    components: {},
+    data() {
+      return {
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 8 }
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 14 }
+        },
+        labelColLong: {
+          xs: { span: 24 },
+          sm: { span: 4 }
+        },
+        wrapperColLong: {
+          xs: { span: 24 },
+          sm: { span: 19 }
+        },
+        confirmLoading: false,
+        validatorRules: {
+          productName: [
+            { required: true, message: '璇疯緭鍏ヤ骇鍝佸悕绉�!' }
+          ],
+          productNo: [
+            { 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({}, record)
+        console.log('model', this.model)
+        this.visible = true
+      },
+
+      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
+            })
+          }
+        })
+      }
+    }
+  }
+</script>
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureMain.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureMain.vue
new file mode 100644
index 0000000..30e0928
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureMain.vue
@@ -0,0 +1,32 @@
+<template>
+  <div style="height: 100%;max-height: 748px">
+    <!--浜у搧缁撴瀯鏍戝彸渚ч《閮ㄥ尯鍩�-->
+    <div style="height: 45%;overflow: hidden">
+      <ProductStructureMainTop :size="tabContainerSize"/>
+    </div>
+
+    <!--浜у搧缁撴瀯鏍戝彸渚у簳閮ㄥ尯鍩�-->
+    <div style="height: 55%;overflow: hidden">
+      <ProductStructureMainBottom :size="tabContainerSize"/>
+    </div>
+  </div>
+</template>
+
+<script>
+  import ProductStructureMainTop from './ProductStructureMainTop'
+  import ProductStructureMainBottom from './ProductStructureMainBottom'
+
+  export default {
+    name: 'ProductStructureMain',
+    components: {
+      ProductStructureMainTop,
+      ProductStructureMainBottom
+    },
+    data() {
+      return {
+        tabContainerSize: 'small'
+      }
+    },
+    methods: {}
+  }
+</script>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue
new file mode 100644
index 0000000..8651ed1
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainBottom.vue
@@ -0,0 +1,91 @@
+<template>
+  <a-tabs style="height: 100%" v-model="activeTabKey" v-if="Object.keys(currentLevelInfo).length>0">
+    <a-tab-pane :key="1" tab="浜у搧灞炴��" v-if="currentLevelInfo.type===1">
+      <ProductInfo :currentLevelDetails="currentLevelInfo.entity" :size="descriptionsContainerSize"/>
+    </a-tab-pane>
+
+    <a-tab-pane :key="1" tab="閮ㄤ欢灞炴��" v-if="currentLevelInfo.type===2">
+      <ComponentInfo :currentLevelDetails="currentLevelInfo.entity" :size="descriptionsContainerSize"/>
+    </a-tab-pane>
+
+    <a-tab-pane :key="1" tab="闆朵欢灞炴��" v-if="currentLevelInfo.type===3">
+      <PartInfo :currentLevelDetails="currentLevelInfo.entity" :size="descriptionsContainerSize"/>
+    </a-tab-pane>
+
+    <a-tab-pane :key="1" tab="宸ュ簭灞炴��" v-if="currentLevelInfo.hasOwnProperty('processType')">
+      <ProcessInfo :currentLevelDetails="currentLevelInfo" :size="descriptionsContainerSize"/>
+    </a-tab-pane>
+
+    <template v-if="currentLevelInfo.hasOwnProperty('attributionType')">
+      <a-tab-pane :key="1" tab="鏂囨。灞炴��">
+        <DocumentInfo :currentLevelDetails="currentLevelInfo" :size="descriptionsContainerSize"/>
+      </a-tab-pane>
+
+      <a-tab-pane :key="2" tab="棰勮">
+
+      </a-tab-pane>
+
+      <a-tab-pane :key="3" tab="鏂囨。鐗堟湰">
+        <DocumentVersionTableList/>
+      </a-tab-pane>
+
+      <a-tab-pane :key="4" tab="浣跨敤璁惧" v-if="currentLevelInfo.attributionType===5">
+        <UseDocumentEquipmentTableList/>
+      </a-tab-pane>
+    </template>
+  </a-tabs>
+</template>
+
+<script>
+  import ProductInfo from './Product/ProductInfo'
+  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 UseDocumentEquipmentTableList from './Document/UseDocumentEquipmentTableList'
+
+  export default {
+    name: 'ProductStructureMainBottom',
+    components: {
+      UseDocumentEquipmentTableList,
+      DocumentVersionTableList,
+      DocumentInfo,
+      ProcessInfo,
+      PartInfo,
+      ProductInfo,
+      ComponentInfo
+    },
+    data() {
+      return {
+        activeTabKey: 1,
+        descriptionsContainerSize: 'small',
+        currentLevelInfo: {}
+      }
+    },
+    created() {
+      this.$bus.$on('sendCurrentLevelInfo', this.receiveCurrentLevelInfo)
+      this.$bus.$on('sendCurrentTreeNodeInfo', this.receiveCurrentLevelInfo)
+    },
+    methods: {
+      /**
+       * 鎺ユ敹鏍戠粍浠朵互鍙婅〃鏍间紶鏉ョ殑褰撳墠閫変腑鎴栫偣鍑荤殑椤逛俊鎭�
+       * @param levelInfo
+       */
+      receiveCurrentLevelInfo(levelInfo) {
+        this.currentLevelInfo = levelInfo
+        if (levelInfo.attributionType) this.activeTabKey = 1
+      }
+    }
+  }
+</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/ProductStructure/ProductStructureMainTop.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
new file mode 100644
index 0000000..9a6a8e1
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureMainTop.vue
@@ -0,0 +1,76 @@
+<template>
+  <a-tabs v-model="activeTabKey" @contextmenu.native="e=>e.preventDefault()"
+          v-if="Object.keys(currentTreeNodeInfo).length!==0">
+    <a-tab-pane :key="1" tab="NC鏂囨。" v-if="currentTreeNodeInfo.type!==1">
+      <NcDocumentTableList @handleTableContextMenuOpen="handleTableContextMenuOpen" :size="tableContainerSize"/>
+    </a-tab-pane>
+
+    <a-tab-pane :key="2" tab="鍏朵粬鏂囨。">
+      <OtherDocumentTableList @handleTableContextMenuOpen="handleTableContextMenuOpen" :size="tableContainerSize"/>
+    </a-tab-pane>
+
+    <TableContextMenu :currentTableRowInfo="currentTableRowInfo" ref="tableContextMenuRef"/>
+  </a-tabs>
+</template>
+
+<script>
+  import ProcessTableList from './Process/ProcessTableList'
+  import NcDocumentTableList from './Document/NcDocumentTableList'
+  import OtherDocumentTableList from './Document/OtherDocumentTableList'
+  import TableContextMenu from '../../../common/TableContextMenu'
+
+  export default {
+    name: 'ProductStructureMainTop',
+    components: { TableContextMenu, OtherDocumentTableList, NcDocumentTableList, ProcessTableList },
+    data() {
+      return {
+        activeTabKey: '1',
+        tableContainerSize: 'small',
+        currentTableRowInfo: {},
+        currentTreeNodeInfo: {}
+      }
+    },
+    created() {
+      this.$bus.$on('sendCurrentTreeNodeInfo', this.receiveCurrentTreeNodeInfo)
+    },
+    methods: {
+      /**
+       * 鎺у埗鍙抽敭鑿滃崟寮�鍚�
+       * @param record 褰撳墠琛ㄦ牸琛屼俊鎭�
+       */
+      handleTableContextMenuOpen(record) {
+        this.currentTableRowInfo = 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)
+      },
+
+      /**
+       * 鎺ユ敹鏍戠粍浠朵紶鏉ョ殑褰撳墠閫変腑鐨勬爲鑺傜偣淇℃伅
+       * @param treeNodeInfo
+       */
+      receiveCurrentTreeNodeInfo(treeNodeInfo) {
+        // 浠庢爲缁勪欢鎺ュ彈鏍戣妭鐐逛俊鎭悗浠庣埗缁勪欢娴佸叆瀛愮粍浠�
+        this.currentTreeNodeInfo = treeNodeInfo
+        if (treeNodeInfo.type !== 1) this.activeTabKey = 1
+        else this.activeTabKey = 2
+      },
+
+      /**
+       * 鎺у埗鍙抽敭鑿滃崟鐐瑰嚮鍏抽棴
+       */
+      handleMenuClose() {
+        this.$refs.tableContextMenuRef.menuVisible = false
+        document.body.removeEventListener('click', this.handleMenuClose)
+      }
+    }
+  }
+</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/common/ImportFileModal.vue b/src/views/dnc/common/ImportFileModal.vue
new file mode 100644
index 0000000..3ed0cb5
--- /dev/null
+++ b/src/views/dnc/common/ImportFileModal.vue
@@ -0,0 +1,122 @@
+<template>
+  <a-modal :title="title" :visible="visible" @cancel="handleModalClose" :maskClosable="false">
+    <a-upload :multiple="true" :file-list="fileList" :remove="handleRemove" :before-upload="beforeUpload">
+      <a-button type="primary">
+        <a-icon type="import"/>
+        閫夊彇鏂囦欢
+      </a-button>
+    </a-upload>
+
+    <div style="margin-top: 16px">宸查�夋嫨{{fileList.length}}涓枃浠�</div>
+
+    <template slot="footer">
+      <a-button @click="handleModalClose">鍙栨秷</a-button>
+      <a-button
+        id="custom-upload-button"
+        type="primary"
+        :disabled="fileList.length === 0"
+        :loading="uploading"
+        @click="handleUpload"
+      >
+        {{ uploading ? '涓婁紶涓�...' : '涓婁紶鑷虫湇鍔″櫒' }}
+      </a-button>
+    </template>
+
+  </a-modal>
+</template>
+
+<script>
+  export default {
+    name: 'ImportFileModal',
+    components: {},
+    data() {
+      return {
+        visible: false,
+        title: '',
+        fileList: [],
+        uploading: false
+      }
+    },
+    created() {
+      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      handleImport(modalTitle) {
+        this.handleModalOpen(modalTitle)
+      },
+
+      handleRemove(file) {
+        const index = this.fileList.indexOf(file)
+        const newFileList = this.fileList.slice()
+        newFileList.splice(index, 1)
+        this.fileList = newFileList
+      },
+
+      beforeUpload(file) {
+        this.fileList = [...this.fileList, file]
+        return false
+      },
+
+      handleUpload() {
+        const { fileList } = this
+        const formData = new FormData()
+        fileList.forEach(file => {
+          formData.append('files[]', file)
+        })
+        this.uploading = true
+
+        // You can use any AJAX library you like
+        request({
+          url: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
+          method: 'post',
+          processData: false,
+          data: formData,
+          success: () => {
+            this.fileList = []
+            this.uploading = false
+            this.$message.success('upload successfully.')
+          },
+          error: () => {
+            this.uploading = false
+            this.$message.error('upload failed.')
+          }
+        })
+      },
+
+      /**
+       * 鎺у埗鏂囦欢涓婁紶绐楀彛寮�鍚苟璁剧疆绐楀彛鏍囬
+       * @param modalTitle 绐楀彛鏍囬
+       */
+      handleModalOpen(modalTitle) {
+        this.title = modalTitle
+        this.visible = true
+      },
+
+      /**
+       * 鎺у埗鏂囦欢涓婁紶绐楀彛鍏抽棴骞舵竻绌烘枃浠跺垪琛�
+       */
+      handleModalClose() {
+        this.visible = false
+        this.fileList = []
+      },
+
+      triggerCorrespondingMethod({ methodName, modalTitle }) {
+        if (this[methodName]) this[methodName](modalTitle)
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  /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;
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/common/ProductStructureTree.vue b/src/views/dnc/common/ProductStructureTree.vue
new file mode 100644
index 0000000..2d85dbf
--- /dev/null
+++ b/src/views/dnc/common/ProductStructureTree.vue
@@ -0,0 +1,644 @@
+<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="queryTreeData">鍒锋柊</a-menu-item>
+            </a-menu>
+            <a-button>
+              <a-icon type="bars"/>
+            </a-button>
+          </a-dropdown>
+          <a-button type="primary" @click="$refs.productModalFormRef.handleProductAdd('娣诲姞浜у搧')">
+            <a-icon type="plus"></a-icon>
+            浜у搧
+          </a-button>
+        </div>
+
+        <!--浜у搧缁撴瀯鏍�-->
+        <div style="flex: 1;overflow:auto;margin-top: 10px">
+          <a-tree ref="tree" show-icon :checkStrictly="checkStrictly" :expandedKeys.sync="expandedKeys"
+                  :selectedKeys="selectedKeys" :treeData="treeDataSource" :autoExpandParent="autoExpandParent"
+                  @select="handleTreeSelect" @expand="handleTreeExpand" @rightClick="handleTreeRightClick">
+            <template slot="title" slot-scope="{ label, parentId, entity, key:treeKey,type}">
+              <ProductStructureTreeContextMenu ref="contextMenuRef"
+                                               :treeParams="{label,treeKey,searchValue,type,entity}"/>
+            </template>
+
+            <a-icon slot="switcherIcon" type="down"/>
+            <a-icon slot="product" type="shopping"/>
+            <a-icon slot="component" type="camera"/>
+            <a-icon slot="part" type="hdd"/>
+          </a-tree>
+        </div>
+      </div>
+    </a-spin>
+
+    <!--浜у搧寮圭獥-->
+    <ProductModal ref="productModalFormRef" :currentTreeNodeInfo="rightClickSelected"/>
+    <!--闆朵欢寮圭獥-->
+    <ComponentModal :currentTreeNodeInfo="rightClickSelected"/>
+    <!--瀵煎叆鏂囦欢鍏叡寮圭獥-->
+    <ImportFileModal/>
+  </a-card>
+</template>
+
+<script>
+  import { deleteAction } from '@/api/manage'
+  import { mapActions } from 'vuex'
+  import ProductStructureTreeContextMenu from './modules/ProductStructureTree/ProductStructureTreeContextMenu'
+  import ProductModal from '../base/modules/ProductStructure/Product/ProductModal'
+  import ImportFileModal from './ImportFileModal'
+  import ComponentModal from '../base/modules/ProductStructure/Component/ComponentModal'
+
+  export default {
+    name: 'ProductStructureTree',
+    components: {
+      ComponentModal,
+      ImportFileModal,
+      ProductModal,
+      ProductStructureTreeContextMenu
+    },
+    data() {
+      return {
+        searchInput: '',
+        cardLoading: false,
+        loading: false,
+        treeDataSource: [],
+        selectedKeys: [],
+        expandedKeys: [],
+        searchValue: '',
+        dataList: [],
+        autoExpandParent: true,
+        checkStrictly: true,
+        allTreeKeys: [],
+        currentSelected: {},
+        rightClickSelected: {},
+        url: {
+          delete: ''
+        }
+      }
+    },
+    created() {
+      this.queryTreeData()
+      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      ...mapActions(['QueryProduction']),
+
+      queryTreeData() {
+        this.loading = true
+        this.cardLoading = true
+        this.QueryProduction().then(res => {
+          if (res.success) {
+            this.dataList = []
+            this.allTreeKeys = []
+            // this.treeDataSource = res.result
+            this.treeDataSource = [
+              {
+                'id': '1869253349344432129',
+                'label': '[璁╁浜篯娴嬭瘯',
+                'iconClass': '',
+                'parentId': '1869253349344432129',
+                'children': [
+                  {
+                    'id': '1869254044432879617',
+                    'label': '[378]qgwqg',
+                    'iconClass': '',
+                    'parentId': '1869253349344432129',
+                    'children': [
+                      {
+                        'id': '1869260302133137410',
+                        'label': '[ggjuk]璋旇皵鍘�',
+                        'iconClass': '',
+                        'parentId': '1869254044432879617',
+                        'children': [
+                          {
+                            'id': '1869294654070075393',
+                            'label': '[8989]qwfq',
+                            'iconClass': '',
+                            'parentId': '1869260302133137410',
+                            'children': null,
+                            'type': 2,
+                            'entity': {
+                              'componentId': '1869294654070075393',
+                              'parentId': '1869260302133137410',
+                              'productId': '1869253349344432129',
+                              'componentName': 'qwfq',
+                              'materielCode': '',
+                              'materielDesp': '',
+                              'componentModel': '',
+                              'componentScale': '',
+                              'componentWeight': null,
+                              'rankLevel': 3,
+                              'assembleType': null,
+                              'produceType': null,
+                              'processType': null,
+                              'structureType': null,
+                              'componentCode': '8989',
+                              'componentStatus': 1,
+                              'description': '',
+                              'createTime': '2024-12-18 16:12:30',
+                              'updateTime': null,
+                              'createUser': '1254966905669160962',
+                              'updateUser': ''
+                            },
+                            'leaf': false,
+                            'rfield': '1869253349344432129'
+                          },
+                          {
+                            'id': '1869294701801254913',
+                            'label': '[888]7878',
+                            'iconClass': '',
+                            'parentId': '1869260302133137410',
+                            'children': null,
+                            'type': 2,
+                            'entity': {
+                              'componentId': '1869294701801254913',
+                              'parentId': '1869260302133137410',
+                              'productId': '1869253349344432129',
+                              'componentName': '7878',
+                              'materielCode': '',
+                              'materielDesp': '',
+                              'componentModel': '',
+                              'componentScale': '',
+                              'componentWeight': null,
+                              'rankLevel': 3,
+                              'assembleType': null,
+                              'produceType': null,
+                              'processType': null,
+                              'structureType': null,
+                              'componentCode': '888',
+                              'componentStatus': 1,
+                              'description': '',
+                              'createTime': '2024-12-18 16:12:41',
+                              'updateTime': null,
+                              'createUser': '1254966905669160962',
+                              'updateUser': ''
+                            },
+                            'leaf': false,
+                            'rfield': '1869253349344432129'
+                          },
+                          {
+                            'id': '1869294780935188482',
+                            'label': '[6855]ww',
+                            'iconClass': '',
+                            'parentId': '1869260302133137410',
+                            'children': null,
+                            'type': 2,
+                            'entity': {
+                              'componentId': '1869294780935188482',
+                              'parentId': '1869260302133137410',
+                              'productId': '1869253349344432129',
+                              'componentName': 'ww',
+                              'materielCode': '',
+                              'materielDesp': '',
+                              'componentModel': '',
+                              'componentScale': '',
+                              'componentWeight': null,
+                              'rankLevel': 3,
+                              'assembleType': null,
+                              'produceType': null,
+                              'processType': null,
+                              'structureType': null,
+                              'componentCode': '6855',
+                              'componentStatus': 1,
+                              'description': '',
+                              'createTime': '2024-12-18 16:13:00',
+                              'updateTime': null,
+                              'createUser': '1254966905669160962',
+                              'updateUser': ''
+                            },
+                            'leaf': false,
+                            'rfield': '1869253349344432129'
+                          },
+                          {
+                            'id': '1876199480437153794',
+                            'label': '[354]zzzzzzzzzzzzzzzzz',
+                            'iconClass': '',
+                            'parentId': '1869260302133137410',
+                            'children': null,
+                            'type': 3,
+                            'entity': {
+                              'partsId': '1876199480437153794',
+                              'partsName': 'zzzzzzzzzzzzzzzzz',
+                              'productId': '1869253349344432129',
+                              'componentId': '1869260302133137410',
+                              'materielCode': '',
+                              'materielDesp': '',
+                              'partsModel': '',
+                              'partsScale': '',
+                              'partsWeight': null,
+                              'assembleType': null,
+                              'produceType': null,
+                              'processType': null,
+                              'structureType': null,
+                              'partsCode': '354',
+                              'partsStatus': 1,
+                              'description': '',
+                              'createTime': '2025-01-06 17:29:49',
+                              'updateTime': null,
+                              'createUser': '1254966905669160962',
+                              'updateUser': ''
+                            },
+                            'leaf': false,
+                            'rfield': '1869260302133137410'
+                          }
+                        ],
+                        'type': 2,
+                        'entity': {
+                          'componentId': '1869260302133137410',
+                          'parentId': '1869254044432879617',
+                          'productId': '1869253349344432129',
+                          'componentName': '璋旇皵鍘�',
+                          'materielCode': '',
+                          'materielDesp': '',
+                          'componentModel': '',
+                          'componentScale': '',
+                          'componentWeight': null,
+                          'rankLevel': 2,
+                          'assembleType': null,
+                          'produceType': null,
+                          'processType': null,
+                          'structureType': null,
+                          'componentCode': 'ggjuk',
+                          'componentStatus': 1,
+                          'description': '',
+                          'createTime': '2024-12-18 13:56:00',
+                          'updateTime': null,
+                          'createUser': '1254966905669160962',
+                          'updateUser': ''
+                        },
+                        'leaf': false,
+                        'rfield': '1869253349344432129'
+                      }
+                    ],
+                    'type': 2,
+                    'entity': {
+                      'componentId': '1869254044432879617',
+                      'parentId': null,
+                      'productId': '1869253349344432129',
+                      'componentName': 'qgwqg',
+                      'materielCode': '',
+                      'materielDesp': '',
+                      'componentModel': '',
+                      'componentScale': '',
+                      'componentWeight': null,
+                      'rankLevel': 1,
+                      'assembleType': null,
+                      'produceType': null,
+                      'processType': null,
+                      'structureType': null,
+                      'componentCode': '378',
+                      'componentStatus': 1,
+                      'description': '88',
+                      'createTime': '2022-12-18 13:32:48',
+                      'updateTime': '2024-12-18 13:32:48',
+                      'createUser': '1254966905669160962',
+                      'updateUser': '1254966905669160962'
+                    },
+                    'leaf': false,
+                    'rfield': '1869253349344432129'
+                  },
+                  {
+                    'id': '1869253419041181697',
+                    'label': '[876]涓哄叏鍥藉墠浜旂粰',
+                    'iconClass': '',
+                    'parentId': '1869253349344432129',
+                    'children': null,
+                    'type': 2,
+                    'entity': {
+                      'componentId': '1869253419041181697',
+                      'parentId': null,
+                      'productId': '1869253349344432129',
+                      'componentName': '涓哄叏鍥藉墠浜旂粰',
+                      'materielCode': '',
+                      'materielDesp': '',
+                      'componentModel': '56',
+                      'componentScale': '',
+                      'componentWeight': null,
+                      'rankLevel': 1,
+                      'assembleType': null,
+                      'produceType': null,
+                      'processType': null,
+                      'structureType': null,
+                      'componentCode': '876',
+                      'componentStatus': 1,
+                      'description': '',
+                      'createTime': '2024-12-18 13:28:39',
+                      'updateTime': '2024-12-18 14:03:55',
+                      'createUser': '1254966905669160962',
+                      'updateUser': '1254966905669160962'
+                    },
+                    'leaf': false,
+                    'rfield': '1869253349344432129'
+                  },
+                  {
+                    'id': '1869294861876867073',
+                    'label': '[777]he',
+                    'iconClass': '',
+                    'parentId': '1869253349344432129',
+                    'children': [
+                      {
+                        'id': '1876087437913108481',
+                        'label': '[ddd]鍜岀淮鎶�',
+                        'iconClass': '',
+                        'parentId': '1869294861876867073',
+                        'children': null,
+                        'type': 2,
+                        'entity': {
+                          'componentId': '1876087437913108481',
+                          'parentId': '1869294861876867073',
+                          'productId': '1869253349344432129',
+                          'componentName': '鍜岀淮鎶�',
+                          'materielCode': '',
+                          'materielDesp': '',
+                          'componentModel': '',
+                          'componentScale': '',
+                          'componentWeight': null,
+                          'rankLevel': 2,
+                          'assembleType': null,
+                          'produceType': null,
+                          'processType': null,
+                          'structureType': null,
+                          'componentCode': 'ddd',
+                          'componentStatus': 1,
+                          'description': '',
+                          'createTime': '2025-01-06 10:04:36',
+                          'updateTime': null,
+                          'createUser': '1254966905669160962',
+                          'updateUser': ''
+                        },
+                        'leaf': false,
+                        'rfield': '1869253349344432129'
+                      }
+                    ],
+                    'type': 2,
+                    'entity': {
+                      'componentId': '1869294861876867073',
+                      'parentId': null,
+                      'productId': '1869253349344432129',
+                      'componentName': 'he',
+                      'materielCode': '',
+                      'materielDesp': '',
+                      'componentModel': '',
+                      'componentScale': '',
+                      'componentWeight': null,
+                      'rankLevel': 1,
+                      'assembleType': null,
+                      'produceType': null,
+                      'processType': null,
+                      'structureType': null,
+                      'componentCode': '777',
+                      'componentStatus': 1,
+                      'description': '',
+                      'createTime': '2024-12-18 16:13:20',
+                      'updateTime': null,
+                      'createUser': '1254966905669160962',
+                      'updateUser': ''
+                    },
+                    'leaf': false,
+                    'rfield': '1869253349344432129'
+                  }
+                ],
+                'type': 1,
+                'entity': {
+                  'productId': '1869253349344432129',
+                  'productNo': '璁╁浜�',
+                  'productModel': '',
+                  'productName': '娴嬭瘯',
+                  'productStatus': 1,
+                  'createTime': '2024-12-18 13:28:22',
+                  'updateTime': null,
+                  'createUser': '1254966905669160962',
+                  'updateUser': null
+                },
+                'leaf': false,
+                'rfield': null
+              }
+            ]
+            this.generateList(this.treeDataSource)
+            // this.expandedKeys = this.allTreeKeys
+            this.expandedKeys = [this.treeDataSource[0].id]
+            console.log('treeDataSource', this.treeDataSource)
+          } 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.queryTreeData()
+                  that.$notification.success({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                } else {
+                  that.$notification.warning({
+                    message: '娑堟伅',
+                    description: res.message
+                  })
+                }
+              })
+          }
+        })
+      },
+
+      /**
+       * 鏍戣妭鐐瑰睍寮�鍚堝苟鏃惰Е鍙�
+       * @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++) {
+          data[i].key = data[i].id
+          const node = data[i]
+          const key = node.id
+          const title = node.label
+          this.dataList.push({ key, title })
+          this.allTreeKeys.push(key)
+          this.setTreeNodeIcon(node)
+          if (node.children) this.generateList(node.children)
+        }
+      },
+
+      triggerCorrespondingMethod({ methodName, modalTitle }) {
+        if (this[methodName]) this[methodName](modalTitle)
+      },
+
+      /**
+       * 璁剧疆鏍戣妭鐐瑰浘鏍�
+       * @param treeNode
+       */
+      setTreeNodeIcon(treeNode) {
+        switch (treeNode.type) {
+          case 1:
+            treeNode.slots = { icon: 'product' }
+            break
+          case 2:
+            treeNode.slots = { icon: 'component' }
+            break
+          case 3:
+            treeNode.slots = { icon: 'part' }
+            break
+          default:
+        }
+      }
+    }
+  }
+</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-node-content-wrapper {
+    width: calc(100% - 24px);
+  }
+
+  /deep/ .ant-tree-title, .ant-tree-title .ant-dropdown-trigger {
+    display: inline-block;
+    width: calc(100% - 24px) !important;
+  }
+
+  .tree_con {
+    overflow: hidden;
+  }
+
+  @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/common/TableContextMenu.vue b/src/views/dnc/common/TableContextMenu.vue
new file mode 100644
index 0000000..dd10da2
--- /dev/null
+++ b/src/views/dnc/common/TableContextMenu.vue
@@ -0,0 +1,87 @@
+<template>
+  <a-menu :style="menuStyle" @click="menuItemClick" v-if="menuVisible" mode="vertical">
+    <template v-for="menuItem in defaultContextMenuList[currentMenuLevel]">
+      <a-menu-item :key="menuItem.code" v-if="menuItem.show&&menuItem.subMenu.length===0">
+        <a-icon :type="menuItem.icon"/>
+        {{menuItem.label}}
+      </a-menu-item>
+
+      <a-sub-menu v-if="menuItem.subMenu.length>0">
+        <span slot="title"><a-icon :type="menuItem.icon"/><span>{{menuItem.label}}</span></span>
+
+        <a-menu-item v-for="subMenuItem in menuItem.subMenu" :key="subMenuItem.code" v-if="subMenuItem.show"
+                     style="height: 32px;line-height: 32px">
+          <a-icon :type="subMenuItem.icon"/>
+          {{subMenuItem.label}}
+        </a-menu-item>
+      </a-sub-menu>
+    </template>
+  </a-menu>
+</template>
+
+<script>
+  export default {
+    name: 'TableContextMenu',
+    components: {},
+    props: {
+      currentTableRowInfo: {
+        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: '',
+        defaultContextMenuList: {
+          //鏂囨。
+          document: [
+            { show: true, label: '缂栬緫鏂囨。淇℃伅', code: 'document_edit', subMenu: [], icon: 'edit' },
+            { show: true, label: '鎸囨淳鍒拌澶�', code: 'document_assign', subMenu: [], icon: 'cluster' },
+            { show: false, label: '瀵煎嚭NC绋嬪簭', code: 'document_export', subMenu: [], icon: 'export' },
+            { show: true, label: '瀵煎叆NC绋嬪簭', code: 'document_import', subMenu: [], icon: 'import' },
+            { show: true, label: '涓嬭浇', code: 'document_download', subMenu: [], icon: 'download' },
+            { show: true, label: '鍒犻櫎', code: 'document_delete', subMenu: [], icon: 'delete' },
+            { show: true, label: '鎵归噺鍒犻櫎', code: 'document_batch_remove', subMenu: [], icon: 'delete' },
+            {
+              show: true,
+              label: '鐢熷懡鍛ㄦ湡',
+              subMenu: [
+                { show: true, label: '鍑哄簱', code: 'document_pull', icon: 'export' },
+                { show: true, label: '鍙栨秷鍑哄簱', code: 'document_cancel_pull', icon: 'stop' },
+                { show: true, label: '鍏ュ簱', code: 'document_push', icon: 'import' },
+                { show: true, label: '鍙戝竷', code: 'document_publish', icon: 'flag' },
+                { show: true, label: '閲嶆柊鍙戝竷', code: 'document_republish', icon: 'reload' },
+                { show: true, label: '褰掓。', code: 'document_pigeonhole', icon: 'database' }
+              ],
+              icon: 'delete'
+            }
+          ]
+        }
+      }
+    },
+    methods: {
+      menuItemClick({ item, key }) {
+        // process_add => handleProcessAdd 瑙﹀彂瀵瑰簲缁勪欢浜嬩欢
+        const methodName = 'handle' + key.split('_').map(item => item[0].toUpperCase() + item.slice(1)).join('')
+        const modalTitle = this.defaultContextMenuList[this.currentMenuLevel].find(item => item.code === key).label
+        console.log('key', key)
+        this.$bus.$emit('menuItemMethodTrigger', { level: this.currentMenuLevel, 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/common/modules/ProductStructureTree/ProductStructureTreeContextMenu.vue b/src/views/dnc/common/modules/ProductStructureTree/ProductStructureTreeContextMenu.vue
new file mode 100644
index 0000000..f8cdee9
--- /dev/null
+++ b/src/views/dnc/common/modules/ProductStructureTree/ProductStructureTreeContextMenu.vue
@@ -0,0 +1,118 @@
+<template>
+  <a-dropdown :trigger="['contextmenu']">
+    <span v-if="treeParams.label.indexOf(treeParams.searchValue) > -1">{{ treeParams.label.substr(0, treeParams.label.indexOf(treeParams.searchValue)) }}<span
+      class="replaceSearch">{{ treeParams.searchValue }}</span>{{ treeParams.label.substr(treeParams.label.indexOf(treeParams.searchValue) + treeParams.searchValue.length) }}</span>
+    <span v-else>{{ treeParams.label }}</span>
+    <template #overlay>
+      <a-menu @click="({ key: menuKey }) => onContextMenuClick(treeParams.treeKey, menuKey)"
+              @contextmenu="event=>event.preventDefault()">
+        <template v-for="item in defaultContextMenuList[getCurrentMenuLevel]">
+          <a-menu-item :key="item.code" v-if="item.show">
+            <a-icon :type="item.icon"/>
+            {{item.label}}
+          </a-menu-item>
+        </template>
+      </a-menu>
+    </template>
+  </a-dropdown>
+</template>
+
+<script>
+  export default {
+    name: 'ProductStructureTreeContextMenu',
+    components: {},
+    props: {
+      treeParams: {
+        type: Object
+      }
+    },
+    data() {
+      return {
+        defaultContextMenuList: {
+          //浜у搧
+          product: [
+            { show: true, label: '娣诲姞浜у搧', code: 'product_add', icon: 'plus', isCommonMethod: false },
+            { show: true, label: '娣诲姞閮ㄤ欢', code: 'product_add_child', icon: 'plus', isCommonMethod: false },
+            { show: true, label: '缂栬緫浜у搧淇℃伅', code: 'product_edit', icon: 'edit', isCommonMethod: false },
+            { show: false, label: '瀵煎嚭鏂囨。', code: 'product_export', icon: 'export', isCommonMethod: true },
+            { show: true, label: '瀵煎叆鍏朵粬鏂囨。', code: 'product_import', icon: 'import', isCommonMethod: true },
+            { show: true, label: '鍒犻櫎', code: 'product_delete', icon: 'delete', isCommonMethod: true },
+            { show: true, label: '鏉冮檺閰嶇疆', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
+          ],
+          //閮ㄤ欢
+          component: [
+            { show: true, label: '娣诲姞瀛愰儴浠�', code: 'component_add', icon: 'plus', isCommonMethod: false },
+            { show: true, label: '娣诲姞闆朵欢', code: 'component_add_child', icon: 'plus', isCommonMethod: false },
+            { show: true, label: '鍒涘缓宸ュ簭', code: 'component_add_relative', icon: 'plus', isCommonMethod: false },
+            { show: true, label: '缂栬緫閮ㄤ欢淇℃伅', code: 'component_edit', icon: 'edit', isCommonMethod: false },
+            { show: false, label: '瀵煎嚭鏂囨。', code: 'component_export', icon: 'export', isCommonMethod: true },
+            { show: true, label: '瀵煎叆鍏朵粬鏂囨。', code: 'component_import', icon: 'import', isCommonMethod: true },
+            { show: true, label: '鍒犻櫎', code: 'component_delete', icon: 'delete', isCommonMethod: true },
+            { show: true, label: '鏉冮檺閰嶇疆', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
+          ],
+          //闆朵欢
+          part: [
+            { show: true, label: '娣诲姞闆朵欢', code: 'parts_add', icon: 'plus', isCommonMethod: false },
+            { show: true, label: '鍒涘缓宸ュ簭', code: 'parts_add_relative', icon: 'plus', isCommonMethod: false },
+            { show: true, label: '缂栬緫闆朵欢淇℃伅', code: 'parts_edit', icon: 'edit', isCommonMethod: false },
+            { show: false, label: '瀵煎嚭鏂囨。', code: 'parts_export', icon: 'export', isCommonMethod: true },
+            { show: true, label: '瀵煎叆鍏朵粬鏂囨。', code: 'parts_import', icon: 'import', isCommonMethod: true },
+            { show: true, label: '鍒犻櫎', code: 'parts_delete', icon: 'delete', isCommonMethod: true },
+            { show: true, label: '鏉冮檺閰嶇疆', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
+          ],
+          //宸ュ簭
+          process: [
+            { show: true, label: '鍒涘缓宸ュ簭', code: 'process_add', icon: 'plus', isCommonMethod: false },
+            { show: true, label: '缂栬緫宸ュ簭淇℃伅', code: 'process_edit', icon: 'edit', isCommonMethod: false },
+            { show: true, label: '鍒犻櫎', code: 'process_delete', icon: 'delete', isCommonMethod: true },
+            { show: false, label: '瀵煎嚭NC绋嬪簭', code: 'process_export', icon: 'import', isCommonMethod: true },
+            { show: true, label: '瀵煎叆NC绋嬪簭', code: 'process_import', icon: 'export', isCommonMethod: true }
+          ]
+        }
+      }
+    },
+    computed: {
+      getCurrentMenuLevel() {
+        switch (this.treeParams.type) {
+          case 1:
+            return 'product'
+          case 2:
+            return 'component'
+          case 3:
+            return 'part'
+          case 4:
+            return 'process'
+          case 5:
+            return 'processStep'
+        }
+      }
+    },
+    methods: {
+      onContextMenuClick(treeKey, menuKey) {
+        const level = this.getCurrentMenuLevel
+        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)
+        const modalTitle = this.defaultContextMenuList[level].find(item => item.code === menuKey).label
+        this.$bus.$emit('treeMenuItemMethodTrigger', { methodName, modalTitle })
+      }
+    }
+  }
+</script>
+
+<style scoped>
+  .replaceSearch {
+    color: #40a9ff;
+    font-weight: bold;
+    background-color: rgb(204, 204, 204);
+  }
+
+</style>
\ No newline at end of file

--
Gitblit v1.9.3