Forráskód Böngészése

fix: 权限多加分级,工作流审批新增规则,工作流审批定时自动同意

tzx 5 napja
szülő
commit
1c360769a6

+ 87 - 4
src/components/processSubmitDialog/processSubmitDialog.vue

@@ -91,10 +91,10 @@
           fixed
         />
         <el-table-column
-          label="执行人"
+          label="需要审批的角色"
           align="center"
           prop="options"
-          min-width="140px"
+          min-width="200px"
         >
           <template v-slot="scope">
             <div
@@ -104,18 +104,21 @@
                 scope.row.type !== 71 &&
                 scope.row.options.length > 0
               "
+              style="display: flex; flex-wrap: wrap; gap: 4px; justify-content: center;"
             >
               <el-tag
-                size="medium"
+                size="small"
                 :key="option"
                 v-for="option in scope.row.options"
+                style="margin: 1px;"
+                hit
               >
                 {{ getAssignRuleOptionName(scope.row, option) }}
               </el-tag>
             </div>
 
             <el-tag
-              size="medium"
+              size="small"
               v-if="
                 scope.row.type === 60 ||
                 scope.row.type === 70 ||
@@ -127,6 +130,46 @@
             </el-tag>
           </template>
         </el-table-column>
+        <el-table-column
+          label="审批人选择"
+          align="center"
+          min-width="240px"
+        >
+          <template v-slot="scope">
+            <el-select
+              v-if="!isInitiatorNode(scope.row)"
+              v-model="scope.row.selectedUsers"
+              multiple
+              filterable
+              clearable
+              placeholder="请选择审批人"
+              style="width: 100%;"
+            >
+              <el-option
+                v-for="user in getFilteredUserOptions(scope.row)"
+                :key="user.id"
+                :label="user.nickname || user.name"
+                :value="user.id"
+              />
+            </el-select>
+            <span v-else style="color: #909399; font-size: 12px;">发起人</span>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="审批方式"
+          align="center"
+          prop="approvalType"
+          width="100"
+        >
+          <template v-slot="scope">
+            <el-tag
+              :type="scope.row.approvalType === 1 ? 'success' : 'warning'"
+              size="small"
+            >
+              {{ getApprovalTypeName(scope.row.approvalType) }}
+            </el-tag>
+          </template>
+        </el-table-column>
       </el-table>
       <my-process-viewer
         v-show="active == 0"
@@ -354,6 +397,21 @@
           modelId: find.modelId,
           processDefinitionId: find.processDefinitionId
         });
+        // 从 bpmnXML 解析每个节点是否是多实例,用于判断审批方式
+        this.datasource.forEach(row => {
+          row.approvalType = this.getApprovalTypeFromBpmn(row.taskDefinitionKey);
+        });
+      },
+      getApprovalTypeFromBpmn(taskDefinitionKey) {
+        // 如果 bpmnXML 不存在,默认单人审批
+        if (!this.bpmnXML) return 1;
+        // 在 BPMN XML 中找到该 userTask 节点的内容
+        const regex = new RegExp(
+          `<[^:]*:?userTask[^>]*\\s(id="${taskDefinitionKey}")[^>]*>[\\s\\S]*?</[^:]*:?userTask>`
+        );
+        const match = this.bpmnXML.match(regex);
+        // 没有匹配到或没有多实例配置 → 单人审批;有多实例配置 → 多人审批
+        return match && match[0].includes('multiInstanceLoopCharacteristics') ? 2 : 1;
       },
       getAssignRuleOptionName(row, option) {
         if (row.type == 10) {
@@ -404,6 +462,15 @@
         }
         return '未知(' + option + ')';
       },
+      isInitiatorNode(row) {
+        return row.type === 60;
+      },
+      getFilteredUserOptions(row) {
+        return this.userOptions;
+      },
+      getApprovalTypeName(type) {
+        return type === 1 ? '单人审批' : '多人审批';
+      },
       /**
        * 构造树型结构数据
        * @param {*} data 数据源
@@ -459,6 +526,14 @@
           text: '提交中',
           background: 'rgba(0, 0, 0, 0.7)'
         });
+        // 从表格中构建审批人映射: { taskDefinitionKey: [userId1, userId2] }
+        const assignee = {};
+        this.datasource.forEach(row => {
+          if (row.selectedUsers && row.selectedUsers.length > 0) {
+            assignee[row.taskDefinitionKey] = row.selectedUsers;
+          }
+        });
+        this.form.assignee = assignee;
         const submitPromise = this.customSubmit
           ? this.customSubmit(this.form.businessId, this.form)
           : processInstanceCreateAPI(this.form);
@@ -485,6 +560,14 @@
           approvalStatus: this.approvalStatus,
           ...this.form
         };
+        // 从表格中构建审批人映射
+        const assignee = {};
+        this.datasource.forEach(row => {
+          if (row.selectedUsers && row.selectedUsers.length > 0) {
+            assignee[row.taskDefinitionKey] = row.selectedUsers;
+          }
+        });
+        params.assignee = assignee;
         await this[this.apiFunName](params)
           .then((res) => {
             console.log(res, 'res');

+ 24 - 1
src/views/bpm/model/index.vue

@@ -92,6 +92,22 @@
             <el-radio :label="0">否</el-radio>
           </el-radio-group>
         </el-form-item>
+        <el-form-item label="超时自动同意" prop="timeoutAutoApprove">
+          <el-radio-group v-model="form.timeoutAutoApprove">
+            <el-radio :label="1">是</el-radio>
+            <el-radio :label="0">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="form.timeoutAutoApprove === 1" label="超时时间" prop="timeoutHours">
+          <el-input-number 
+            v-model="form.timeoutHours" 
+            :min="1" 
+            :max="720"
+            :step="1"
+            style="width: 200px;"
+          />
+          <div style="line-height: 1.5; color: #909399; font-size: 12px; margin-top: 4px;">单位:小时,超过此时间未处理将自动同意</div>
+        </el-form-item>
         <div v-if="form.id">
           <el-form-item label="表单路由" prop="formCustomCreatePath">
             <el-input v-model="form.formCustomCreatePath" placeholder="请按格式输入表单路由" style="width: 330px;"
@@ -245,6 +261,11 @@ export default {
         name: [{required: true, message: "流程名称不能为空", trigger: "blur"}],
         processTypeId: [{required: true, message: "流程分类不能为空", trigger: "change"}],
         autoSkipApprove: [{required: true, message: "请选择是否自动跳过审批", trigger: "change"}],
+        timeoutAutoApprove: [{required: true, message: "请选择是否开启超时自动同意", trigger: "change"}],
+        timeoutHours: [
+          {required: true, message: "请输入超时时间", trigger: "blur"},
+          {type: 'number', min: 1, message: '超时时间必须大于0', trigger: 'blur'}
+        ],
       },
       pageSize: this.$store.state.tablePageSize,
       cacheKeyUrl: '05790f5b-bpm-model'
@@ -318,7 +339,9 @@ export default {
         formId: undefined,
         formCustomCreatePath: undefined,
         formCustomViewPath: undefined,
-        autoSkipApprove: 0
+        autoSkipApprove: 0,
+        timeoutAutoApprove: 0,
+        timeoutHours: 24
       };
       console.log(this.$refs.form);
       this.$refs.form.resetFields();

+ 43 - 3
src/views/system/role/components/role-data-auth.vue

@@ -42,6 +42,24 @@
             :default-checked-keys="checkedKeys"
           />
         </el-scrollbar>
+        <!-- 指定工厂数据权限(7):勾选工厂(t_main_factory type=1),集合存 dataScopeDeptIds -->
+        <el-scrollbar
+          v-if="form.dataScope=='7'"
+          v-loading="authLoading"
+          style="height: 40vh"
+          wrap-style="overflow-x: hidden;">
+          <el-tree
+            ref="factoryTree"
+            :data="factoryData"
+            :check-strictly="true"
+            highlight-current
+            node-key="id"
+            :props="{ label: 'name' }"
+            :expand-on-click-node="false"
+            show-checkbox
+            :default-expand-all="true"
+          />
+        </el-scrollbar>
       </el-form-item>
     </el-form>
 
@@ -58,6 +76,7 @@
 <script>
 import {putRoles} from '@/api/system/role';
 import {listOrganizations} from "@/api/system/organization";
+import {getFactoryarea} from "@/api/factoryModel/index";
 
 export default {
   components: {},
@@ -74,6 +93,8 @@ export default {
       rules: {},
       // 权限数据
       deptData: [],
+      // 指定工厂(7)勾选用的工厂列表(t_main_factory type=1)
+      factoryData: [],
       // 权限数据请求状态
       authLoading: false,
       // 提交状态
@@ -85,6 +106,7 @@ export default {
   },
   created() {
    this.getListOrganizations()
+   this.getFactoryTreeData()
   },
   methods: {
 
@@ -92,13 +114,28 @@ export default {
     init(row) {
       this.form = row
       this.form.dataScope = this.form.dataScope + ''
+      console.log(this.form.dataScope,"scopeeeeee")
       this.$nextTick(()=>{
         if(this.form.dataScope=='2'){
-          this.$refs.tree.setCheckedKeys(this.form.dataScopeDeptIds.split(','))
+          this.$refs.tree.setCheckedKeys(this.form.dataScopeDeptIds ? this.form.dataScopeDeptIds.split(',') : [])
+        } else if(this.form.dataScope=='7'){
+          if(this.$refs.factoryTree){
+            this.$refs.factoryTree.setCheckedKeys(this.form.dataScopeDeptIds ? this.form.dataScopeDeptIds.split(',') : [])
+          }
         }
-
       })
-
+    },
+    /* 指定工厂(7):查询 type=1 工厂列表 */
+    getFactoryTreeData(){
+      this.authLoading = true;
+      getFactoryarea({ pageNum: 1, size: 999, type: 1 })
+        .then((res) => {
+          this.authLoading = false;
+          this.factoryData = (res && res.list) || [];
+        })
+        .catch(() => {
+          this.authLoading = false;
+        });
     },
     getListOrganizations(){
       this.authLoading = true;
@@ -123,6 +160,9 @@ export default {
       if(this.form.dataScope=='2'){
         const ids = this.$refs.tree.getCheckedKeys().concat(this.$refs.tree.getHalfCheckedKeys());
         this.form.dataScopeDeptIds = ids.join(',');
+      } else if(this.form.dataScope=='7'){
+        const factoryIds = this.$refs.factoryTree.getCheckedKeys();
+        this.form.dataScopeDeptIds = factoryIds.join(',');
       }
       putRoles(this.form)
         .then((msg) => {

+ 47 - 2
src/views/system/role/components/role-edit.vue

@@ -68,6 +68,25 @@
             :default-checked-keys="checkedKeys"
           />
         </el-scrollbar>
+        <!-- 指定工厂数据权限(7):勾选工厂(t_main_factory type=1),集合存 dataScopeDeptIds -->
+        <el-scrollbar
+          v-if="form.dataScope == '7'"
+          v-loading="authLoading"
+          style="height: 40vh"
+          wrap-style="overflow-x: hidden;"
+        >
+          <el-tree
+            ref="factoryTree"
+            :data="factoryData"
+            :check-strictly="true"
+            highlight-current
+            node-key="id"
+            :props="{ label: 'name' }"
+            :expand-on-click-node="false"
+            show-checkbox
+            :default-expand-all="true"
+          />
+        </el-scrollbar>
       </el-form-item>
     </el-form>
     <template v-slot:footer>
@@ -82,6 +101,7 @@
 <script>
   import { addRole, putRoles } from '@/api/system/role';
   import { listOrganizations } from '@/api/system/organization';
+  import { getFactoryarea } from '@/api/factoryModel/index';
   import { secretLevelList } from '@/enum/dict';
   import { getCode } from '@/api/codeManagement/index.js';
 
@@ -94,6 +114,7 @@
     },
     created() {
       this.getListOrganizations();
+      this.getFactoryTreeData();
     },
     data() {
       const defaultForm = {
@@ -132,7 +153,9 @@
         isUpdate: false,
         authLoading: false,
 
-        organizationList: []
+        organizationList: [],
+        // 指定工厂(7)勾选用的工厂列表(t_main_factory type=1)
+        factoryData: []
       };
     },
     methods: {
@@ -172,6 +195,19 @@
             // this.$message.error(e.message);
           });
       },
+      /* 指定工厂(7):查询 type=1 工厂列表 */
+      getFactoryTreeData() {
+        this.authLoading = true;
+        getFactoryarea({ pageNum: 1, size: 999, type: 1 })
+          .then((res) => {
+            this.authLoading = false;
+            this.factoryData = (res && res.list) || [];
+          })
+          .catch((e) => {
+            this.authLoading = false;
+            // this.$message.error(e.message);
+          });
+      },
       /* 保存编辑 */
       save() {
         this.$refs.form.validate((valid) => {
@@ -184,6 +220,9 @@
               .getCheckedKeys()
               .concat(this.$refs.tree.getHalfCheckedKeys());
             this.form.dataScopeDeptIds = ids.join(',');
+          } else if (this.form.dataScope == '7') {
+            const factoryIds = this.$refs.factoryTree.getCheckedKeys();
+            this.form.dataScopeDeptIds = factoryIds.join(',');
           }
           const saveOrUpdate = this.isUpdate ? putRoles : addRole;
           saveOrUpdate(this.form)
@@ -216,8 +255,14 @@
             this.$nextTick(() => {
               if (this.form.dataScope == '2') {
                 this.$refs.tree.setCheckedKeys(
-                  this.form.dataScopeDeptIds.split(',')
+                  this.form.dataScopeDeptIds ? this.form.dataScopeDeptIds.split(',') : []
                 );
+              } else if (this.form.dataScope == '7') {
+                if (this.$refs.factoryTree) {
+                  this.$refs.factoryTree.setCheckedKeys(
+                    this.form.dataScopeDeptIds ? this.form.dataScopeDeptIds.split(',') : []
+                  );
+                }
               }
             });
             this.isUpdate = true;