From c5605aafbbb7678d91cefac28b3b6c1524809b46 Mon Sep 17 00:00:00 2001
From: zhaowei <zhaowei>
Date: 星期三, 22 一月 2025 16:48:11 +0800
Subject: [PATCH] 产品结构树: 1、新增树节点数据权限配置功能

---
 src/api/dnc.js                                                                      |   26 +++
 src/views/dnc/base/modules/ProductStructure/Permission/UserPermissionTransfer.vue   |  111 +++++++++++++++
 src/views/dnc/common/TableContextMenu.vue                                           |    4 
 src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue                |   24 +-
 src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue     |    6 
 src/views/dnc/base/modules/ProductStructure/Permission/DepartPermissionTransfer.vue |  104 ++++++++++++++
 src/views/dnc/base/modules/ProductStructure/Permission/AssignPermissionModal.vue    |  120 +++++++++++++++++
 7 files changed, 379 insertions(+), 16 deletions(-)

diff --git a/src/api/dnc.js b/src/api/dnc.js
index c165520..2ee2cf5 100644
--- a/src/api/dnc.js
+++ b/src/api/dnc.js
@@ -46,5 +46,29 @@
   // 鎸囧畾褰撳墠鏂囨。鐗堟湰
   appointCurrentDocumentVersionApi: fileId => putAction(`/nc/file/assign/version/${fileId}`),
   // 鏂囨。姣斿
-  fileCompareApi: fileIdArray => getAction(`/nc/file/comparison/${fileIdArray[0]}/${fileIdArray[1]}`)
+  fileCompareApi: fileIdArray => getAction(`/nc/file/comparison/${fileIdArray[0]}/${fileIdArray[1]}`),
+  // 鑾峰彇鎵�鏈夐儴闂ㄥ垪琛�
+  getAllDepartmentsListApi: () => getAction('/ucenter/depart/list/all'),
+  // 鑾峰彇鎵�鏈夌敤鎴峰垪琛�
+  getAllUsersListApi: () => getAction('/sys/user/list'),
+  // 鑾峰彇鏈夋潈闄愮殑閮ㄩ棬鍒楄〃
+  getHasPermissionDepartApi: ({ type, id }) => getAction(`/nc/product/get/perm/depart/${type}/${id}`),
+  // 鑾峰彇鏈夋潈闄愮殑鐢ㄦ埛鍒楄〃
+  getHasPermissionUserApi: ({ type, id }) => getAction(`/nc/product/get/perm/user/${type}/${id}`),
+  // 鍒嗛厤閮ㄩ棬鏉冮檺
+  assignPermissionToDepart: ({ treeNodeType, treeNodeId, isAssignSonNode, departIdArray }) => {
+    return postAction(`/nc/product/assign/add/department/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, departIdArray)
+  },
+  // 绉婚櫎閮ㄩ棬鏉冮檺
+  removePermissionFromDepart: ({ treeNodeType, treeNodeId, isAssignSonNode, departIdArray }) => {
+    return postAction(`/nc/product/assign/remove/department/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, departIdArray)
+  },
+  // 鍒嗛厤鐢ㄦ埗鏉冮檺
+  assignPermissionToUser: ({ treeNodeType, treeNodeId, isAssignSonNode, userIdArray }) => {
+    return postAction(`/nc/product/assign/add/user/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, userIdArray)
+  },
+  // 绉婚櫎閮ㄩ棬鏉冮檺
+  removePermissionFromUser: ({ treeNodeType, treeNodeId, isAssignSonNode, userIdArray }) => {
+    return postAction(`/nc/product/assign/remove/user/${treeNodeType}/${treeNodeId}/${isAssignSonNode}`, userIdArray)
+  }
 }
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Permission/AssignPermissionModal.vue b/src/views/dnc/base/modules/ProductStructure/Permission/AssignPermissionModal.vue
new file mode 100644
index 0000000..d9851a5
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Permission/AssignPermissionModal.vue
@@ -0,0 +1,120 @@
+<template>
+  <a-modal :visible="visible" :title="title" width="50%" :maskClosable="false" @cancel="handleModalClose"
+           :footer="null">
+    <a-form-model layout="inline">
+      <a-form-item label="鍚嶇О">
+        <a-input readOnly :value="currentTreeNodeInfo.label"></a-input>
+      </a-form-item>
+      <a-form-item label="鏄惁鍒嗛厤瀛愯妭鐐�">
+        <a-switch v-model="isAssignSonNode"></a-switch>
+      </a-form-item>
+    </a-form-model>
+
+    <a-tabs v-model="activeTabKey">
+      <a-tab-pane :key="1" tab="鍒嗛厤閮ㄩ棬">
+        <DepartPermissionTransfer ref="departPermissionTransferRef" :currentTreeNodeInfo="currentTreeNodeInfo"
+                                      :dataSource="allDepartmentsList" :isAssignSonNode="isAssignSonNode"/>
+      </a-tab-pane>
+
+      <a-tab-pane :key="2" tab="鍒嗛厤鐢ㄦ埛">
+        <UserPermissionTransfer ref="userPermissionTransferRef" :currentTreeNodeInfo="currentTreeNodeInfo"
+                                :dataSource="allUsersList" :isAssignSonNode="isAssignSonNode"/>
+      </a-tab-pane>
+    </a-tabs>
+  </a-modal>
+</template>
+
+<script>
+  import dncApi from '@/api/dnc'
+  import DepartPermissionTransfer from './DepartPermissionTransfer'
+  import UserPermissionTransfer from './UserPermissionTransfer'
+
+  export default {
+    name: 'AssignPermissionModal',
+    components: { UserPermissionTransfer, DepartPermissionTransfer },
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      }
+    },
+    data() {
+      return {
+        visible: false,
+        title: '',
+        isAssignSonNode: true,
+        activeTabKey: 1,
+        allDepartmentsList: [],
+        allUsersList: [],
+        hasLoadedDataTabKeyArray: []
+      }
+    },
+    watch: {
+      visible: {
+        handler(value) {
+          if (value) {
+            this.activeTabKey = 1
+            this.isAssignSonNode = true
+            this.getAllDepartmentsListByApi()
+          }
+        }
+      },
+      activeTabKey: {
+        handler(value) {
+          if (this.hasLoadedDataTabKeyArray.includes(value)) return
+          if (value === 2) this.getAllUsersListByApi()
+          this.hasLoadedDataTabKeyArray.push(value)
+        }
+      }
+    },
+    created() {
+      this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
+    },
+    methods: {
+      // 鐐瑰嚮鏍戣妭鐐瑰彸閿彍鍗曟潈闄愰厤缃寜閽悗瑙﹀彂
+      handleAssignPermission() {
+        this.visible = true
+      },
+
+      // 璋冪敤鎺ュ彛鑾峰彇鎵�鏈夐儴闂ㄥ垪琛�
+      getAllDepartmentsListByApi() {
+        dncApi.getAllDepartmentsListApi()
+          .then(res => {
+            if (res.success) {
+              this.allDepartmentsList = res.list
+              this.$nextTick(() => this.$refs.departPermissionTransferRef.getHasPermissionDepartByApi())
+              // 鍙湁涓婃閫�鍑烘椂鍦ㄩ儴闂ㄥ垎閰峵ab鐣岄潰鎵嶄細杩涘叆姝ゅ垽鏂�
+              // 鑻ヤ笂娆¢��鍑烘椂鍦ㄧ敤鎴峰垎閰峵ab鐣岄潰鍒欏啀娆¤繘鍏ユ椂key鐢�2鍙樹负1鏃朵細瑙﹀彂watch鐩戞祴activeTabKey鍙樺寲鍒欎細灏唊ey:1鍔犲叆hasLoadedDataTabKeyArray锛屽洜姝ゆ棤闇�鍐嶆鍔犲叆key:1
+              if (!this.hasLoadedDataTabKeyArray.includes(this.activeTabKey)) this.hasLoadedDataTabKeyArray.push(this.activeTabKey)
+            }
+          })
+      },
+
+      // 璋冪敤鎺ュ彛鑾峰彇鎵�鏈夌敤鎴峰垪琛�
+      getAllUsersListByApi() {
+        dncApi.getAllUsersListApi()
+          .then(res => {
+            if (res.success) {
+              this.allUsersList = res.result.records
+              this.$nextTick(() => this.$refs.userPermissionTransferRef.getHasPermissionUserByApi())
+            }
+          })
+      },
+
+      handleModalClose() {
+        this.visible = false
+        this.hasLoadedDataTabKeyArray = []
+      },
+
+      triggerCorrespondingMethod({ methodName, modalTitle }) {
+        if (this[methodName]) {
+          this[methodName]()
+          this.title = modalTitle
+        }
+      }
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Permission/DepartPermissionTransfer.vue b/src/views/dnc/base/modules/ProductStructure/Permission/DepartPermissionTransfer.vue
new file mode 100644
index 0000000..3315fef
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Permission/DepartPermissionTransfer.vue
@@ -0,0 +1,104 @@
+<template>
+  <a-spin :spinning="spinning">
+    <a-transfer
+      class="transfer-container"
+      :data-source="dataSource"
+      show-search
+      :list-style="{flex:1,height: '500px'}"
+      :titles="['鏈垎閰嶉儴闂�', '宸插垎閰嶉儴闂�']"
+      :operations="['鍒嗛厤閮ㄩ棬', '绉婚櫎閮ㄩ棬']"
+      :target-keys="targetKeys"
+      :render="item => `${item.departName}`"
+      @change="handleChange"
+      :rowKey="record => record.departId"
+    >
+
+      <span slot="notFoundContent">鏆傛棤鏁版嵁</span>
+    </a-transfer>
+  </a-spin>
+</template>
+
+<script>
+  import dncApi from '@/api/dnc'
+
+  export default {
+    name: 'DepartPermissionTransfer',
+    components: {},
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      },
+      dataSource: {
+        type: Array
+      },
+      isAssignSonNode: {
+        type: Boolean
+      }
+    },
+    data() {
+      return {
+        targetKeys: [],
+        spinning: false
+      }
+    },
+    methods: {
+      getHasPermissionDepartByApi() {
+        dncApi.getHasPermissionDepartApi(this.currentTreeNodeInfo)
+          .then(res => {
+            if (res.success) this.targetKeys = res.list.map(item => item.departId)
+          })
+      },
+
+      handleChange(targetKeys, direction, moveKeys) {
+        const { currentTreeNodeInfo: { type, id }, isAssignSonNode, $notification } = this
+        const that = this
+        let method
+        const params = {
+          treeNodeType: type,
+          treeNodeId: id,
+          isAssignSonNode: isAssignSonNode ? 1 : 2,
+          departIdArray: moveKeys
+        }
+        console.log('params--------------------------', params)
+        console.log(targetKeys, direction, moveKeys)
+        if (direction === 'right') {
+          method = dncApi.assignPermissionToDepart
+        } else {
+          method = dncApi.removePermissionFromDepart
+        }
+        that.spinning = true
+        method(params)
+          .then(res => {
+            if (res.success) {
+              $notification.success({
+                message: '娑堟伅',
+                description: res.message
+              })
+              this.targetKeys = targetKeys
+            } else {
+              $notification.error({
+                message: '娑堟伅',
+                description: res.message
+              })
+            }
+          })
+          .catch(err => {
+            $notification.error({
+              message: '娑堟伅',
+              description: err.message
+            })
+          })
+          .finally(() => {
+            that.spinning = false
+          })
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  .transfer-container {
+    display: flex;
+    align-items: center;
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/Permission/UserPermissionTransfer.vue b/src/views/dnc/base/modules/ProductStructure/Permission/UserPermissionTransfer.vue
new file mode 100644
index 0000000..4521965
--- /dev/null
+++ b/src/views/dnc/base/modules/ProductStructure/Permission/UserPermissionTransfer.vue
@@ -0,0 +1,111 @@
+<template>
+  <a-spin :spinning="spinning">
+    <a-transfer
+      class="transfer-container"
+      :data-source="dataSource"
+      show-search
+      :list-style="{flex:1,height: '500px'}"
+      :titles="['鏈垎閰嶇敤鎴�', '宸插垎閰嶇敤鎴�']"
+      :operations="['鍒嗛厤鐢ㄦ埛', '绉婚櫎鐢ㄦ埛']"
+      :target-keys="targetKeys"
+      :render="item => `${item.realname}`"
+      @change="handleChange"
+      :rowKey="record => record.id"
+    >
+      <span slot="notFoundContent">鏆傛棤鏁版嵁</span>
+    </a-transfer>
+  </a-spin>
+</template>
+
+<script>
+  import dncApi from '@/api/dnc'
+
+  export default {
+    name: 'UserPermissionTransfer',
+    components: {},
+    props: {
+      currentTreeNodeInfo: {
+        type: Object
+      },
+      dataSource: {
+        type: Array
+      },
+      isAssignSonNode: {
+        type: Boolean
+      }
+    },
+    data() {
+      return {
+        targetKeys: [],
+        spinning: false
+      }
+    },
+    methods: {
+      getHasPermissionUserByApi() {
+        dncApi.getHasPermissionUserApi(this.currentTreeNodeInfo)
+          .then(res => {
+            if (res.success) this.targetKeys = res.list.map(item => item.id)
+          })
+      },
+
+      handleChange(targetKeys, direction, moveKeys) {
+        const { currentTreeNodeInfo: { type, id }, isAssignSonNode, $notification, dataSource } = this
+        const that = this
+        let method
+        const params = {
+          treeNodeType: type,
+          treeNodeId: id,
+          isAssignSonNode: isAssignSonNode ? 1 : 2,
+          userIdArray: moveKeys
+        }
+        console.log('params--------------------------', params)
+        console.log(targetKeys, direction, moveKeys)
+        if (direction === 'right') {
+          method = dncApi.assignPermissionToUser
+        } else {
+          method = dncApi.removePermissionFromUser
+          const adminId = dataSource.find(item => item.username === 'admin').id
+          if (moveKeys.includes(adminId)) {
+            $notification.warning({
+              message: '娑堟伅',
+              description: '涓嶈兘绉婚櫎绠$悊鍛樻潈闄�'
+            })
+            return
+          }
+        }
+        that.spinning = true
+        method(params)
+          .then(res => {
+            if (res.success) {
+              $notification.success({
+                message: '娑堟伅',
+                description: res.message
+              })
+              this.targetKeys = targetKeys
+            } else {
+              $notification.error({
+                message: '娑堟伅',
+                description: res.message
+              })
+            }
+          })
+          .catch(err => {
+            $notification.error({
+              message: '娑堟伅',
+              description: err.message
+            })
+          })
+          .finally(() => {
+            that.spinning = false
+          })
+      }
+    }
+  }
+</script>
+
+<style scoped lang="less">
+  .transfer-container {
+    display: flex;
+    align-items: center;
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue
index 328e26f..5a995f9 100644
--- a/src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureTree.vue
@@ -9,7 +9,7 @@
             <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-item key="3" @click="getTreeDataByApi">鍒锋柊</a-menu-item>
             </a-menu>
             <a-button>
               <a-icon type="bars"/>
@@ -45,7 +45,7 @@
 
     <!--浜у搧寮圭獥-->
     <ProductModal ref="productModalFormRef" :currentTreeNodeInfo="rightClickSelected"
-                  @submitSuccess="queryTreeData"/>
+                  @submitSuccess="getTreeDataByApi"/>
     <!--閮ㄤ欢寮圭獥-->
     <ComponentModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
     <!--闆朵欢寮圭獥-->
@@ -54,6 +54,8 @@
     <ProcessModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
     <!--宸ユ寮圭獥-->
     <ProcessStepModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
+    <!--鏉冮檺閰嶇疆寮圭獥-->
+    <AssignPermissionModal :currentTreeNodeInfo="rightClickSelected" @submitSuccess="modalFormSubmitSuccess"/>
   </a-card>
 </template>
 
@@ -66,10 +68,12 @@
   import PartModal from './Part/PartModal'
   import ProcessModal from './Process/ProcessModal'
   import ProcessStepModal from './ProcessStep/ProcessStepModal'
+  import AssignPermissionModal from './Permission/AssignPermissionModal'
 
   export default {
     name: 'ProductStructureTree',
     components: {
+      AssignPermissionModal,
       ProcessStepModal,
       ProcessModal,
       PartModal,
@@ -98,11 +102,11 @@
       }
     },
     created() {
-      this.queryTreeData()
+      this.getTreeDataByApi()
       this.$bus.$on('treeMenuItemMethodTrigger', this.triggerCorrespondingMethod)
     },
     methods: {
-      queryTreeData() {
+      getTreeDataByApi() {
         this.loading = true
         this.cardLoading = true
         dncApi.getProductStructureTreeApi().then(res => {
@@ -145,9 +149,7 @@
         this.rightClickSelected = Object.assign({}, record)
       },
 
-      /**
-       * 鏍戣妭鐐瑰彸閿崟鍑昏彍鍗曚腑鍒犻櫎鎸夐挳鏃惰Е鍙�
-       */
+      // 鏍戣妭鐐瑰彸閿崟鍑昏彍鍗曚腑鍒犻櫎鎸夐挳鏃惰Е鍙�
       handleDelete() {
         this.$confirm({
           title: '鎻愮ず',
@@ -165,7 +167,7 @@
             deleteAction(that.url.delete, { id: this.rightClickSelected.id })
               .then((res) => {
                 if (res.success) {
-                  that.queryTreeData()
+                  that.getTreeDataByApi()
                   that.$notification.success({
                     message: '娑堟伅',
                     description: res.message
@@ -187,7 +189,7 @@
       modalFormSubmitSuccess(isAddNextLevel) {
         // 鍒ゆ柇鏄惁涓烘坊鍔犱笅绾у苟涓斿垽鏂埗鑺傜偣鏄惁灞曞紑
         if (isAddNextLevel && !this.expandedKeys.includes(this.rightClickSelected.id)) this.expandedKeys.push(this.rightClickSelected.id)
-        this.queryTreeData()
+        this.getTreeDataByApi()
       },
 
       /**
@@ -257,8 +259,8 @@
         }
       },
 
-      triggerCorrespondingMethod({ methodName, modalTitle }) {
-        if (this[methodName]) this[methodName](modalTitle)
+      triggerCorrespondingMethod({ methodName }) {
+        if (this[methodName]) this[methodName]()
       },
 
       /**
diff --git a/src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue b/src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue
index f8c9010..8f3ff1d 100644
--- a/src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue
+++ b/src/views/dnc/base/modules/ProductStructure/ProductStructureTreeContextMenu.vue
@@ -65,7 +65,8 @@
             { label: '缂栬緫宸ュ簭淇℃伅', code: 'process_edit', icon: 'edit', isCommonMethod: false },
             { label: '鍒犻櫎', code: 'process_delete', icon: 'delete', isCommonMethod: true },
             // {  label: '瀵煎嚭NC绋嬪簭', code: 'process_export', icon: 'import', isCommonMethod: true },
-            { label: '瀵煎叆NC绋嬪簭', code: 'process_import', icon: 'export', isCommonMethod: true }
+            { label: '瀵煎叆NC绋嬪簭', code: 'process_import', icon: 'export', isCommonMethod: true },
+            { label: '鏉冮檺閰嶇疆', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
           ],
           //宸ユ
           processStep: [
@@ -73,7 +74,8 @@
             { label: '缂栬緫宸ユ淇℃伅', code: 'processStep_edit', icon: 'edit', isCommonMethod: false },
             { label: '鍒犻櫎', code: 'processStep_delete', icon: 'delete', isCommonMethod: true },
             // {  label: '瀵煎嚭NC绋嬪簭', code: 'processStep_export', icon: 'import', isCommonMethod: true },
-            { label: '瀵煎叆NC绋嬪簭', code: 'processStep_import', icon: 'export', isCommonMethod: true }
+            { label: '瀵煎叆NC绋嬪簭', code: 'processStep_import', icon: 'export', isCommonMethod: true },
+            { label: '鏉冮檺閰嶇疆', code: 'public_assign_permission', icon: 'idcard', isCommonMethod: true }
           ]
         }
       }
diff --git a/src/views/dnc/common/TableContextMenu.vue b/src/views/dnc/common/TableContextMenu.vue
index 7b50a4b..96406b6 100644
--- a/src/views/dnc/common/TableContextMenu.vue
+++ b/src/views/dnc/common/TableContextMenu.vue
@@ -83,8 +83,8 @@
           ],
           //鏂囦欢
           file: [
-            { label: '鎸囧畾褰撳墠鐗堟湰', code: 'file_assign', subMenu: [], icon: 'export', isCommonMethod: false },//鏂囦欢-鎸囧畾褰撳墠鐗堟湰
-            { label: '姣斿', code: 'file_add_relative', subMenu: [], icon: 'export', isCommonMethod: false }//姣斿
+            { label: '鎸囧畾褰撳墠鐗堟湰', code: 'file_assign', subMenu: [], icon: 'highlight', isCommonMethod: false },//鏂囦欢-鎸囧畾褰撳墠鐗堟湰
+            { label: '姣斿', code: 'file_add_relative', subMenu: [], icon: 'interaction', isCommonMethod: false }//姣斿
           ]
         }
       }

--
Gitblit v1.9.3