Эх сурвалжийг харах

!614 bpm设计器优化
Merge pull request !614 from Lesan/feature/bpm

芋道源码 8 сар өмнө
parent
commit
bfb9e2e77f

+ 34 - 68
src/components/bpmnProcessDesigner/package/penal/custom-config/components/UserTaskCustomConfig.vue

@@ -4,9 +4,24 @@
      3. 审批人为空时
      4. 操作按钮
      5. 字段权限
+     6. 审批类型
 -->
 <template>
   <div>
+    <el-divider content-position="left">审批类型</el-divider>
+    <el-form-item prop="approveType">
+      <el-radio-group v-model="approveType.value">
+        <el-radio
+          v-for="(item, index) in APPROVE_TYPE"
+          :key="index"
+          :value="item.value"
+          :label="item.value"
+        >
+          {{ item.label }}
+        </el-radio>
+      </el-radio-group>
+    </el-form-item>
+
     <el-divider content-position="left">审批人拒绝时</el-divider>
     <el-form-item prop="rejectHandlerType">
       <el-radio-group
@@ -158,10 +173,13 @@ import {
   AssignEmptyHandlerType,
   OPERATION_BUTTON_NAME,
   DEFAULT_BUTTON_SETTING,
-  FieldPermissionType
+  FieldPermissionType,
+  APPROVE_TYPE,
+  ApproveType,
+  ButtonSetting
 } from '@/components/SimpleProcessDesignerV2/src/consts'
 import * as UserApi from '@/api/system/user'
-import { cloneDeep } from 'lodash-es'
+import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node'
 
 defineOptions({ name: 'ElementCustomConfig4UserTask' })
 const props = defineProps({
@@ -189,8 +207,7 @@ const assignEmptyUserIds = ref()
 
 // 操作按钮
 const buttonsSettingEl = ref()
-const { buttonsSetting, btnDisplayNameEdit, changeBtnDisplayName, btnDisplayNameBlurEvent } =
-  useButtonsSetting()
+const { btnDisplayNameEdit, changeBtnDisplayName, btnDisplayNameBlurEvent } = useButtonsSetting()
 
 // 字段权限
 const fieldsPermissionEl = ref([])
@@ -198,6 +215,9 @@ const { formType, fieldsPermissionConfig, getNodeConfigFormFields } = useFormFie
   FieldPermissionType.READ
 )
 
+// 审批类型
+const approveType = ref({ value: ApproveType.USER })
+
 const elExtensionElements = ref()
 const otherExtensions = ref()
 const bpmnElement = ref()
@@ -217,6 +237,11 @@ const resetCustomConfigList = () => {
     bpmnElement.value.businessObject?.extensionElements ??
     bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
 
+  // 审批类型
+  approveType.value =
+    elExtensionElements.value.values?.filter((ex) => ex.$type === `${prefix}:ApproveType`)?.[0] ||
+    bpmnInstances().moddle.create(`${prefix}:ApproveType`, { value: ApproveType.USER })
+
   // 审批人与提交人为同一人时
   assignStartUserHandlerTypeEl.value =
     elExtensionElements.value.values?.filter(
@@ -275,6 +300,8 @@ const resetCustomConfigList = () => {
     )
     fieldsPermissionEl.value = []
     getNodeConfigFormFields()
+    // 由于默认添加了发起人元素,这里需要删掉
+    fieldsPermissionConfig.value = fieldsPermissionConfig.value.slice(1)
     fieldsPermissionConfig.value.forEach((element) => {
       element.permission =
         fieldsPermissionList?.find((obj) => obj.field === element.field)?.permission ?? '1'
@@ -294,7 +321,8 @@ const resetCustomConfigList = () => {
         ex.$type !== `${prefix}:AssignEmptyHandlerType` &&
         ex.$type !== `${prefix}:AssignEmptyUserIds` &&
         ex.$type !== `${prefix}:ButtonsSetting` &&
-        ex.$type !== `${prefix}:FieldsPermission`
+        ex.$type !== `${prefix}:FieldsPermission` &&
+        ex.$type !== `${prefix}:ApproveType`
     ) ?? []
 
   // 更新元素扩展属性,避免后续报错
@@ -343,6 +371,7 @@ const updateElementExtensions = () => {
       returnNodeIdEl.value,
       assignEmptyHandlerTypeEl.value,
       assignEmptyUserIdsEl.value,
+      approveType.value,
       ...buttonsSettingEl.value,
       ...fieldsPermissionEl.value
     ]
@@ -427,69 +456,6 @@ function useButtonsSetting() {
   }
 }
 
-// 表单字段权限设置
-function useFormFieldsPermission(defaultPermission) {
-  // 字段权限配置. 需要有 field, title,  permissioin 属性
-  const fieldsPermissionConfig = ref<Array<Record<string, string>>>([])
-
-  const formType = inject<Ref<number>>('formType') // 表单类型
-
-  const formFields = inject<Ref<string[]>>('formFields') // 流程表单字段
-
-  const getNodeConfigFormFields = (nodeFormFields?: Array<Record<string, string>>) => {
-    nodeFormFields = toRaw(nodeFormFields)
-    fieldsPermissionConfig.value =
-      cloneDeep(nodeFormFields) || getDefaultFieldsPermission(unref(formFields))
-  }
-  // 默认的表单权限: 获取表单的所有字段,设置字段默认权限为只读
-  const getDefaultFieldsPermission = (formFields?: string[]) => {
-    const defaultFieldsPermission: Array<Record<string, string>> = []
-    if (formFields) {
-      formFields.forEach((fieldStr: string) => {
-        parseFieldsSetDefaultPermission(JSON.parse(fieldStr), defaultFieldsPermission)
-      })
-    }
-    return defaultFieldsPermission
-  }
-  // 解析字段。赋给默认权限
-  const parseFieldsSetDefaultPermission = (
-    rule: Record<string, any>,
-    fieldsPermission: Array<Record<string, string>>,
-    parentTitle: string = ''
-  ) => {
-    const { /**type,*/ field, title: tempTitle, children } = rule
-    if (field && tempTitle) {
-      let title = tempTitle
-      if (parentTitle) {
-        title = `${parentTitle}.${tempTitle}`
-      }
-      fieldsPermission.push({
-        field,
-        title,
-        permission: defaultPermission
-      })
-      // TODO 子表单 需要处理子表单字段
-      // if (type === 'group' && rule.props?.rule && Array.isArray(rule.props.rule)) {
-      //   // 解析子表单的字段
-      //   rule.props.rule.forEach((item) => {
-      //     parseFieldsSetDefaultPermission(item, fieldsPermission, title)
-      //   })
-      // }
-    }
-    if (children && Array.isArray(children)) {
-      children.forEach((rule) => {
-        parseFieldsSetDefaultPermission(rule, fieldsPermission)
-      })
-    }
-  }
-
-  return {
-    formType,
-    fieldsPermissionConfig,
-    getNodeConfigFormFields
-  }
-}
-
 const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
 onMounted(async () => {
   // 获得用户列表

+ 164 - 13
src/components/bpmnProcessDesigner/package/penal/task/task-components/UserTask.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-form label-width="100px">
+  <el-form label-width="120px">
     <el-form-item label="规则类型" prop="candidateStrategy">
       <el-select
         v-model="userTaskForm.candidateStrategy"
@@ -8,15 +8,15 @@
         @change="changeCandidateStrategy"
       >
         <el-option
-          v-for="dict in getIntDictOptions(DICT_TYPE.BPM_TASK_CANDIDATE_STRATEGY)"
-          :key="dict.value"
+          v-for="(dict, index) in CANDIDATE_STRATEGY"
+          :key="index"
           :label="dict.label"
           :value="dict.value"
         />
       </el-select>
     </el-form-item>
     <el-form-item
-      v-if="userTaskForm.candidateStrategy == 10"
+      v-if="userTaskForm.candidateStrategy == CandidateStrategy.ROLE"
       label="指定角色"
       prop="candidateParam"
     >
@@ -31,7 +31,11 @@
       </el-select>
     </el-form-item>
     <el-form-item
-      v-if="userTaskForm.candidateStrategy == 20 || userTaskForm.candidateStrategy == 21"
+      v-if="
+        userTaskForm.candidateStrategy == CandidateStrategy.DEPT_MEMBER ||
+        userTaskForm.candidateStrategy == CandidateStrategy.DEPT_LEADER ||
+        userTaskForm.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
+      "
       label="指定部门"
       prop="candidateParam"
       span="24"
@@ -49,7 +53,7 @@
       />
     </el-form-item>
     <el-form-item
-      v-if="userTaskForm.candidateStrategy == 22"
+      v-if="userTaskForm.candidateStrategy == CandidateStrategy.POST"
       label="指定岗位"
       prop="candidateParam"
       span="24"
@@ -65,7 +69,7 @@
       </el-select>
     </el-form-item>
     <el-form-item
-      v-if="userTaskForm.candidateStrategy == 30"
+      v-if="userTaskForm.candidateStrategy == CandidateStrategy.USER"
       label="指定用户"
       prop="candidateParam"
       span="24"
@@ -86,7 +90,7 @@
       </el-select>
     </el-form-item>
     <el-form-item
-      v-if="userTaskForm.candidateStrategy === 40"
+      v-if="userTaskForm.candidateStrategy === CandidateStrategy.USER_GROUP"
       label="指定用户组"
       prop="candidateParam"
     >
@@ -106,7 +110,67 @@
       </el-select>
     </el-form-item>
     <el-form-item
-      v-if="userTaskForm.candidateStrategy === 60"
+      v-if="userTaskForm.candidateStrategy === CandidateStrategy.FORM_USER"
+      label="表单内用户字段"
+      prop="formUser"
+    >
+      <el-select
+        v-model="userTaskForm.candidateParam"
+        clearable
+        style="width: 100%"
+        @change="handleFormUserChange"
+      >
+        <el-option
+          v-for="(item, idx) in userFieldOnFormOptions"
+          :key="idx"
+          :label="item.title"
+          :value="item.field"
+          :disabled="!item.required"
+        />
+      </el-select>
+    </el-form-item>
+    <el-form-item
+      v-if="userTaskForm.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER"
+      label="表单内部门字段"
+      prop="formDept"
+    >
+      <el-select
+        v-model="userTaskForm.candidateParam"
+        clearable
+        style="width: 100%"
+        @change="updateElementTask"
+      >
+        <el-option
+          v-for="(item, idx) in deptFieldOnFormOptions"
+          :key="idx"
+          :label="item.title"
+          :value="item.field"
+          :disabled="!item.required"
+        />
+      </el-select>
+    </el-form-item>
+    <el-form-item
+      v-if="
+        userTaskForm.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
+        userTaskForm.candidateStrategy == CandidateStrategy.START_USER_DEPT_LEADER ||
+        userTaskForm.candidateStrategy == CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER ||
+        userTaskForm.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
+      "
+      :label="deptLevelLabel!"
+      prop="deptLevel"
+      span="24"
+    >
+      <el-select v-model="deptLevel" clearable @change="updateElementTask">
+        <el-option
+          v-for="(item, index) in MULTI_LEVEL_DEPT"
+          :key="index"
+          :label="item.label"
+          :value="item.value"
+        />
+      </el-select>
+    </el-form-item>
+    <el-form-item
+      v-if="userTaskForm.candidateStrategy === CandidateStrategy.EXPRESSION"
       label="流程表达式"
       prop="candidateParam"
     >
@@ -127,7 +191,12 @@
 </template>
 
 <script lang="ts" setup>
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import {
+  CANDIDATE_STRATEGY,
+  CandidateStrategy,
+  FieldPermissionType,
+  MULTI_LEVEL_DEPT
+} from '@/components/SimpleProcessDesignerV2/src/consts'
 import { defaultProps, handleTree } from '@/utils/tree'
 import * as RoleApi from '@/api/system/role'
 import * as DeptApi from '@/api/system/dept'
@@ -136,6 +205,7 @@ import * as UserApi from '@/api/system/user'
 import * as UserGroupApi from '@/api/bpm/userGroup'
 import ProcessExpressionDialog from './ProcessExpressionDialog.vue'
 import { ProcessExpressionVO } from '@/api/bpm/processExpression'
+import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node'
 
 defineOptions({ name: 'UserTask' })
 const props = defineProps({
@@ -155,6 +225,30 @@ const deptTreeOptions = ref() // 部门树
 const postOptions = ref<PostApi.PostVO[]>([]) // 岗位列表
 const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
 const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
+
+const { formFieldOptions } = useFormFieldsPermission(FieldPermissionType.READ)
+// 表单内用户字段选项, 必须是必填和用户选择器
+const userFieldOnFormOptions = computed(() => {
+  return formFieldOptions.filter((item) => item.type === 'UserSelect')
+})
+// 表单内部门字段选项, 必须是必填和部门选择器
+const deptFieldOnFormOptions = computed(() => {
+  return formFieldOptions.filter((item) => item.type === 'DeptSelect')
+})
+
+const deptLevel = ref(1)
+const deptLevelLabel = computed(() => {
+  let label = '部门负责人来源'
+  if (userTaskForm.value.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER) {
+    label = label + '(指定部门向上)'
+  } else if (userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER) {
+    label = label + '(表单内部门向上)'
+  } else {
+    label = label + '(发起人部门向上)'
+  }
+  return label
+})
+
 const otherExtensions = ref()
 
 const resetTaskForm = () => {
@@ -163,7 +257,9 @@ const resetTaskForm = () => {
     return
   }
 
-  const extensionElements = businessObject?.extensionElements ?? bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
+  const extensionElements =
+    businessObject?.extensionElements ??
+    bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
   userTaskForm.value.candidateStrategy = extensionElements.values?.filter(
     (ex) => ex.$type === `${prefix}:CandidateStrategy`
   )?.[0]?.value
@@ -171,9 +267,29 @@ const resetTaskForm = () => {
     (ex) => ex.$type === `${prefix}:CandidateParam`
   )?.[0]?.value
   if (candidateParamStr && candidateParamStr.length > 0) {
-    if (userTaskForm.value.candidateStrategy === 60) {
+    if (userTaskForm.value.candidateStrategy === CandidateStrategy.EXPRESSION) {
       // 特殊:流程表达式,只有一个 input 输入框
       userTaskForm.value.candidateParam = [candidateParamStr]
+    } else if (userTaskForm.value.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER) {
+      // 特殊:多级不部门负责人,需要通过'|'分割
+      userTaskForm.value.candidateParam = candidateParamStr
+        .split('|')[0]
+        .split(',')
+        .map((item) => {
+          // 如果数字超出了最大安全整数范围,则将其作为字符串处理
+          let num = Number(item)
+          return num > Number.MAX_SAFE_INTEGER || num < -Number.MAX_SAFE_INTEGER ? item : num
+        })
+      deptLevel.value = +candidateParamStr.split('|')[1]
+    } else if (
+      userTaskForm.value.candidateStrategy == CandidateStrategy.START_USER_DEPT_LEADER ||
+      userTaskForm.value.candidateStrategy == CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
+    ) {
+      userTaskForm.value.candidateParam = +candidateParamStr
+      deptLevel.value = +candidateParamStr
+    } else if (userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER) {
+      userTaskForm.value.candidateParam = candidateParamStr.split('|')[0]
+      deptLevel.value = +candidateParamStr.split('|')[1]
     } else {
       userTaskForm.value.candidateParam = candidateParamStr.split(',').map((item) => {
         // 如果数字超出了最大安全整数范围,则将其作为字符串处理
@@ -214,11 +330,38 @@ const resetTaskForm = () => {
 /** 更新 candidateStrategy 字段时,需要清空 candidateParam,并触发 bpmn 图更新 */
 const changeCandidateStrategy = () => {
   userTaskForm.value.candidateParam = []
+  deptLevel.value = 1
+  if (userTaskForm.value.candidateStrategy === CandidateStrategy.FORM_USER) {
+    // 特殊处理表单内用户字段,当只有发起人选项时应选中发起人
+    if (!userFieldOnFormOptions.value || userFieldOnFormOptions.value.length <= 1) {
+      userTaskForm.value.candidateStrategy = CandidateStrategy.START_USER
+    }
+  }
   updateElementTask()
 }
 
 /** 选中某个 options 时候,更新 bpmn 图  */
 const updateElementTask = () => {
+  let candidateParam =
+    userTaskForm.value.candidateParam instanceof Array
+      ? userTaskForm.value.candidateParam.join(',')
+      : userTaskForm.value.candidateParam
+
+  // 特殊处理多级部门情况
+  if (
+    userTaskForm.value.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
+    userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
+  ) {
+    candidateParam += '|' + deptLevel.value
+  }
+  // 特殊处理发起人部门负责人、发起人连续部门负责人
+  if (
+    userTaskForm.value.candidateStrategy == CandidateStrategy.START_USER_DEPT_LEADER ||
+    userTaskForm.value.candidateStrategy == CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
+  ) {
+    candidateParam = deptLevel.value + ''
+  }
+
   const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
     values: [
       ...otherExtensions.value,
@@ -226,7 +369,7 @@ const updateElementTask = () => {
         value: userTaskForm.value.candidateStrategy
       }),
       bpmnInstances().moddle.create(`${prefix}:CandidateParam`, {
-        value: userTaskForm.value.candidateParam.join(',')
+        value: candidateParam
       })
     ]
   })
@@ -252,6 +395,14 @@ const selectProcessExpression = (expression: ProcessExpressionVO) => {
   updateElementTask()
 }
 
+const handleFormUserChange = (e) => {
+  if (e === 'PROCESS_START_USER_ID') {
+    userTaskForm.value.candidateParam = []
+    userTaskForm.value.candidateStrategy = CandidateStrategy.START_USER
+  }
+  updateElementTask()
+}
+
 watch(
   () => props.id,
   () => {