Bladeren bron

仿钉钉流程设计器- 新增审批类型

jason 1 jaar geleden
bovenliggende
commit
eb7e9397f5

+ 40 - 16
src/components/SimpleProcessDesignerV2/src/consts.ts

@@ -62,6 +62,8 @@ export interface SimpleFlowNode {
   childNode?: SimpleFlowNode
   // 条件节点
   conditionNodes?: SimpleFlowNode[]
+  // 审批类型
+  approveType?: ApproveType
   // 候选人策略
   candidateStrategy?: number
   // 候选人参数
@@ -249,7 +251,23 @@ export enum AssignStartUserHandlerType {
   /**
    * 转交给部门负责人审批
    */
-  ASSIGN_DEPT_LEADER
+  ASSIGN_DEPT_LEADER = 3
+}
+
+// 用户任务的审批类型。 【参考飞书】
+export enum ApproveType {
+  /**
+   * 人工审批
+   */
+  USER = 1,
+  /**
+   * 自动通过
+   */
+  AUTO_APPROVE = 2,
+  /**
+   * 自动拒绝
+   */
+  AUTO_REJECT = 3
 }
 
 // 时间单位枚举
@@ -285,13 +303,13 @@ export enum ConditionConfigType {
  * 操作按钮权限结构定义
  */
 export type ButtonSetting = {
-  id: OpsButtonType
+  id: OperationButtonType
   displayName: string
   enable: boolean
 }
 
-// 操作按钮类型枚举 (用于审批节点) // TODO @jason:建议不缩写哈
-export enum OpsButtonType {
+// 操作按钮类型枚举 (用于审批节点)
+export enum OperationButtonType {
   /**
    * 通过
    */
@@ -371,6 +389,12 @@ export const CANDIDATE_STRATEGY: DictDataVO[] = [
   { label: '用户组', value: CandidateStrategy.USER_GROUP },
   { label: '流程表达式', value: CandidateStrategy.EXPRESSION }
 ]
+// 审批节点 的审批类型
+export const APPROVE_TYPE: DictDataVO[] = [
+  { label: '人工审批', value: ApproveType.USER },
+  { label: '自动通过', value: ApproveType.AUTO_APPROVE },
+  { label: '自动拒绝', value: ApproveType.AUTO_REJECT }
+]
 
 export const APPROVE_METHODS: DictDataVO[] = [
   { label: '随机挑选一人审批', value: ApproveMethodType.RRANDOM_SELECT_ONE_APPROVE },
@@ -442,21 +466,21 @@ export const COMPARISON_OPERATORS: DictDataVO = [
 ]
 // 审批操作按钮名称
 export const OPERATION_BUTTON_NAME = new Map<number, string>()
-OPERATION_BUTTON_NAME.set(OpsButtonType.APPROVE, '通过')
-OPERATION_BUTTON_NAME.set(OpsButtonType.REJECT, '拒绝')
-OPERATION_BUTTON_NAME.set(OpsButtonType.TRANSFER, '转办')
-OPERATION_BUTTON_NAME.set(OpsButtonType.DELEGATE, '委派')
-OPERATION_BUTTON_NAME.set(OpsButtonType.ADD_SIGN, '加签')
-OPERATION_BUTTON_NAME.set(OpsButtonType.RETURN, '回退')
+OPERATION_BUTTON_NAME.set(OperationButtonType.APPROVE, '通过')
+OPERATION_BUTTON_NAME.set(OperationButtonType.REJECT, '拒绝')
+OPERATION_BUTTON_NAME.set(OperationButtonType.TRANSFER, '转办')
+OPERATION_BUTTON_NAME.set(OperationButtonType.DELEGATE, '委派')
+OPERATION_BUTTON_NAME.set(OperationButtonType.ADD_SIGN, '加签')
+OPERATION_BUTTON_NAME.set(OperationButtonType.RETURN, '回退')
 
 // 默认的按钮权限设置
 export const DEFAULT_BUTTON_SETTING: ButtonSetting[] = [
-  { id: OpsButtonType.APPROVE, displayName: '通过', enable: true },
-  { id: OpsButtonType.REJECT, displayName: '拒绝', enable: true },
-  { id: OpsButtonType.TRANSFER, displayName: '转办', enable: false },
-  { id: OpsButtonType.DELEGATE, displayName: '委派', enable: false },
-  { id: OpsButtonType.ADD_SIGN, displayName: '加签', enable: false },
-  { id: OpsButtonType.RETURN, displayName: '回退', enable: false }
+  { id: OperationButtonType.APPROVE, displayName: '通过', enable: true },
+  { id: OperationButtonType.REJECT, displayName: '拒绝', enable: true },
+  { id: OperationButtonType.TRANSFER, displayName: '转办', enable: false },
+  { id: OperationButtonType.DELEGATE, displayName: '委派', enable: false },
+  { id: OperationButtonType.ADD_SIGN, displayName: '加签', enable: false },
+  { id: OperationButtonType.RETURN, displayName: '回退', enable: false }
 ]
 
 export const MULTI_LEVEL_DEPT: DictDataVO = [

+ 6 - 9
src/components/SimpleProcessDesignerV2/src/node.ts

@@ -293,9 +293,9 @@ export function useNodeForm(nodeType: NodeType) {
         break
       // 指定连续多级部门的负责人
       case CandidateStrategy.MULTI_LEVEL_DEPT_LEADER: {
-        // 候选人参数格式 ,分隔。 被分隔的最后一个为部门层级
+        // 候选人参数格式: | 分隔 。左边为部门(多个部门用 , 分隔)。 右边为部门层级
         const deptIds = configForm.value.deptIds!.join(',')
-        candidateParam = deptIds.concat(',' + configForm.value.deptLevel + '')
+        candidateParam = deptIds.concat('|' + configForm.value.deptLevel + '')
         break
       }
       default:
@@ -341,13 +341,10 @@ export function useNodeForm(nodeType: NodeType) {
         break
       // 指定连续多级部门的负责人
       case CandidateStrategy.MULTI_LEVEL_DEPT_LEADER: {
-        // 候选人参数格式 ,分隔。 被分隔的最后一个为部门层级
-        const paramArray = candidateParam.split(',')
-        configForm.value.deptIds = []
-        for (let i = 0; i < paramArray.length - 1; i++) {
-          configForm.value.deptIds.push(+paramArray[i])
-        }
-        configForm.value.deptLevel = +paramArray[paramArray.length - 1]
+        // 候选人参数格式: | 分隔 。左边为部门(多个部门用 , 分隔)。 右边为部门层级
+        const paramArray = candidateParam.split('|')
+        configForm.value.deptIds = paramArray[0].split(',').map((item) => +item)
+        configForm.value.deptLevel = +paramArray[1]
         break
       }
       default:

+ 1 - 2
src/components/SimpleProcessDesignerV2/src/nodes-config/CopyTaskNodeConfig.vue

@@ -181,7 +181,6 @@
 </template>
 <script setup lang="ts">
 import { SimpleFlowNode, CandidateStrategy, NodeType, CANDIDATE_STRATEGY } from '../consts'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import {
   useWatchNode,
   useDrawer,
@@ -261,7 +260,7 @@ const saveConfig = async () => {
   const showText = getShowText()
   if (!showText) return false
   currentNode.value.name = nodeName.value!
-  handleCandidateParam()
+  currentNode.value.candidateParam = handleCandidateParam()
   currentNode.value.candidateStrategy = configForm.value.candidateStrategy
   currentNode.value.showText = showText
   currentNode.value.fieldsPermission = fieldsPermissionConfig.value

+ 46 - 14
src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue

@@ -24,7 +24,20 @@
         <div class="divide-line"></div>
       </div>
     </template>
-    <el-tabs type="border-card" v-model="activeTabName">
+    <div class="flex flex-items-center mb-3">
+      <span class="font-size-4 mr-3">审批类型 :</span>
+      <el-radio-group v-model="approveType">
+        <el-radio
+          v-for="(item, index) in APPROVE_TYPE"
+          :key="index"
+          :value="item.value"
+          :label="item.value"
+        >
+          {{ item.label }}
+        </el-radio>
+      </el-radio-group>
+    </div>
+    <el-tabs type="border-card" v-model="activeTabName" v-if="approveType === ApproveType.USER">
       <el-tab-pane label="审批人" name="user">
         <div>
           <el-form ref="formRef" :model="configForm" label-position="top" :rules="formRules">
@@ -58,7 +71,6 @@
                 />
               </el-select>
             </el-form-item>
-            <!-- TODO @jason:指定部门的选择,不用联动父子。例如说:可能就是想某个比较高级别的部门审批。 -->
             <el-form-item
               v-if="
                 configForm.candidateStrategy == CandidateStrategy.DEPT_MEMBER ||
@@ -77,7 +89,7 @@
                 empty-text="加载中,请稍后"
                 multiple
                 node-key="id"
-                check-strictly
+                :check-strictly="true"
                 style="width: 100%"
                 show-checkbox
               />
@@ -404,6 +416,8 @@
 <script setup lang="ts">
 import {
   SimpleFlowNode,
+  APPROVE_TYPE,
+  ApproveType,
   APPROVE_METHODS,
   CandidateStrategy,
   NodeType,
@@ -434,7 +448,7 @@ import {
 } from '../node'
 import { defaultProps } from '@/utils/tree'
 import { cloneDeep } from 'lodash-es'
-import { convertTimeUnit } from '../utils'
+import { convertTimeUnit, getApproveTypeText } from '../utils'
 defineOptions({
   name: 'UserTaskNodeConfig'
 })
@@ -469,7 +483,7 @@ const { formType, fieldsPermissionConfig, getNodeConfigFormFields } = useFormFie
 // 操作按钮设置
 const { buttonsSetting, btnDisplayNameEdit, changeBtnDisplayName, btnDisplayNameBlurEvent } =
   useButtonsSetting()
-
+const approveType = ref(ApproveType.USER)
 // 审批人表单设置
 const formRef = ref() // 表单 Ref
 // 表单校验规则
@@ -563,12 +577,23 @@ const {
 // 保存配置
 const saveConfig = async () => {
   activeTabName.value = 'user'
+  // 设置审批节点名称
+  currentNode.value.name = nodeName.value!
+  // 设置审批类型
+  currentNode.value.approveType = approveType.value
+  // 如果不是人工审批。返回
+  if (approveType.value !== ApproveType.USER) {
+    currentNode.value.showText = getApproveTypeText(approveType.value)
+    settingVisible.value = false
+    return true
+  }
+
   if (!formRef) return false
   const valid = await formRef.value.validate()
   if (!valid) return false
   const showText = getShowText()
   if (!showText) return false
-  currentNode.value.name = nodeName.value!
+
   currentNode.value.candidateStrategy = configForm.value.candidateStrategy
   // 处理 candidateParam 参数
   currentNode.value.candidateParam = handleCandidateParam()
@@ -612,7 +637,14 @@ const saveConfig = async () => {
 // 显示审批节点配置, 由父组件传过来
 const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
   nodeName.value = node.name
-  //1.1 审批人设置
+  // 1 审批类型
+  approveType.value = node.approveType ? node.approveType : ApproveType.USER
+  // 如果审批类型不是人工审批返回
+  if (approveType.value !== ApproveType.USER) {
+    return
+  }
+
+  //2.1 审批人设置
   configForm.value.candidateStrategy = node.candidateStrategy!
   // 解析候选人参数
   parseCandidateParam(node.candidateStrategy!, node?.candidateParam)
@@ -621,18 +653,18 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
   } else {
     notAllowedMultiApprovers.value = false
   }
-  // 1.2 设置审批方式
+  // 2.2 设置审批方式
   configForm.value.approveMethod = node.approveMethod!
   if (node.approveMethod == ApproveMethodType.APPROVE_BY_RATIO) {
     configForm.value.approveRatio = node.approveRatio!
   }
-  // 1.3 设置审批拒绝处理
+  // 2.3 设置审批拒绝处理
   configForm.value.rejectHandlerType = node.rejectHandler!.type
   configForm.value.returnNodeId = node.rejectHandler?.returnNodeId
   const matchNodeList = []
   emits('find:returnTaskNodes', matchNodeList)
   returnTaskList.value = matchNodeList
-  // 1.4 设置审批超时处理
+  // 2.4 设置审批超时处理
   configForm.value.timeoutHandlerEnable = node.timeoutHandler!.enable
   if (node.timeoutHandler?.enable && node.timeoutHandler?.timeDuration) {
     const strTimeDuration = node.timeoutHandler.timeDuration
@@ -643,14 +675,14 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => {
   }
   configForm.value.timeoutHandlerType = node.timeoutHandler?.type
   configForm.value.maxRemindCount = node.timeoutHandler?.maxRemindCount
-  // 1.5 设置审批人为空时
+  // 2.5 设置审批人为空时
   configForm.value.assignEmptyHandlerType = node.assignEmptyHandler?.type
   configForm.value.assignEmptyHandlerUserIds = node.assignEmptyHandler?.userIds
-  // 1.6 设置用户任务的审批人与发起人相同时
+  // 2.6 设置用户任务的审批人与发起人相同时
   configForm.value.assignStartUserHandlerType = node.assignStartUserHandlerType
-  // 2. 操作按钮设置
+  // 3. 操作按钮设置
   buttonsSetting.value = cloneDeep(node.buttonsSetting) || DEFAULT_BUTTON_SETTING
-  // 3. 表单字段权限配置
+  // 4. 表单字段权限配置
   getNodeConfigFormFields(node.fieldsPermission)
 }
 

+ 12 - 1
src/components/SimpleProcessDesignerV2/src/utils.ts

@@ -1,4 +1,4 @@
-import { TimeUnitType } from './consts'
+import { TimeUnitType, ApproveType, APPROVE_TYPE } from './consts'
 
 // 获取条件节点默认的名称
 export const getDefaultConditionNodeName = (index: number, defaultFlow: boolean): string => {
@@ -20,3 +20,14 @@ export const convertTimeUnit = (strTimeUnit: string) => {
   }
   return TimeUnitType.HOUR
 }
+
+export const getApproveTypeText = (approveType: ApproveType): string => {
+  let approveTypeText = ''
+  APPROVE_TYPE.forEach((item) => {
+    if (item.value === approveType) {
+      approveTypeText = item.label
+      return
+    }
+  })
+  return approveTypeText
+}

+ 19 - 19
src/views/bpm/processInstance/detail/index.vue

@@ -59,69 +59,69 @@
           <!-- TODO @jason:建议搞个 if 来判断,替代现有的 !item.buttonsSetting || item.buttonsSetting[OpsButtonType.APPROVE]?.enable -->
           <el-button
             type="success"
-            v-if="!item.buttonsSetting || item.buttonsSetting[OpsButtonType.APPROVE]?.enable"
+            v-if="!item.buttonsSetting || item.buttonsSetting[OperationButtonType.APPROVE]?.enable"
             @click="handleAudit(item, true)"
           >
             <Icon icon="ep:select" />
             <!-- TODO @jason:这个也是类似哈,搞个方法来生成名字 -->
             {{
-              item.buttonsSetting?.[OpsButtonType.APPROVE]?.displayName ||
-              OPERATION_BUTTON_NAME.get(OpsButtonType.APPROVE)
+              item.buttonsSetting?.[OperationButtonType.APPROVE]?.displayName ||
+              OPERATION_BUTTON_NAME.get(OperationButtonType.APPROVE)
             }}
           </el-button>
           <el-button
-            v-if="!item.buttonsSetting || item.buttonsSetting[OpsButtonType.REJECT]?.enable"
+            v-if="!item.buttonsSetting || item.buttonsSetting[OperationButtonType.REJECT]?.enable"
             type="danger"
             @click="handleAudit(item, false)"
           >
             <Icon icon="ep:close" />
             {{
-              item.buttonsSetting?.[OpsButtonType.REJECT].displayName ||
-              OPERATION_BUTTON_NAME.get(OpsButtonType.REJECT)
+              item.buttonsSetting?.[OperationButtonType.REJECT].displayName ||
+              OPERATION_BUTTON_NAME.get(OperationButtonType.REJECT)
             }}
           </el-button>
           <el-button
-            v-if="!item.buttonsSetting || item.buttonsSetting[OpsButtonType.TRANSFER]?.enable"
+            v-if="!item.buttonsSetting || item.buttonsSetting[OperationButtonType.TRANSFER]?.enable"
             type="primary"
             @click="openTaskUpdateAssigneeForm(item.id)"
           >
             <Icon icon="ep:edit" />
             {{
-              item.buttonsSetting?.[OpsButtonType.TRANSFER]?.displayName ||
-              OPERATION_BUTTON_NAME.get(OpsButtonType.TRANSFER)
+              item.buttonsSetting?.[OperationButtonType.TRANSFER]?.displayName ||
+              OPERATION_BUTTON_NAME.get(OperationButtonType.TRANSFER)
             }}
           </el-button>
           <el-button
-            v-if="!item.buttonsSetting || item.buttonsSetting[OpsButtonType.DELEGATE]?.enable"
+            v-if="!item.buttonsSetting || item.buttonsSetting[OperationButtonType.DELEGATE]?.enable"
             type="primary"
             @click="handleDelegate(item)"
           >
             <Icon icon="ep:position" />
             {{
-              item.buttonsSetting?.[OpsButtonType.DELEGATE]?.displayName ||
-              OPERATION_BUTTON_NAME.get(OpsButtonType.DELEGATE)
+              item.buttonsSetting?.[OperationButtonType.DELEGATE]?.displayName ||
+              OPERATION_BUTTON_NAME.get(OperationButtonType.DELEGATE)
             }}
           </el-button>
           <el-button
-            v-if="!item.buttonsSetting || item.buttonsSetting[OpsButtonType.ADD_SIGN]?.enable"
+            v-if="!item.buttonsSetting || item.buttonsSetting[OperationButtonType.ADD_SIGN]?.enable"
             type="primary"
             @click="handleSign(item)"
           >
             <Icon icon="ep:plus" />
             {{
-              item.buttonsSetting?.[OpsButtonType.ADD_SIGN]?.displayName ||
-              OPERATION_BUTTON_NAME.get(OpsButtonType.ADD_SIGN)
+              item.buttonsSetting?.[OperationButtonType.ADD_SIGN]?.displayName ||
+              OPERATION_BUTTON_NAME.get(OperationButtonType.ADD_SIGN)
             }}
           </el-button>
           <el-button
-            v-if="!item.buttonsSetting || item.buttonsSetting[OpsButtonType.RETURN]?.enable"
+            v-if="!item.buttonsSetting || item.buttonsSetting[OperationButtonType.RETURN]?.enable"
             type="warning"
             @click="handleBack(item)"
           >
             <Icon icon="ep:back" />
             {{
-              item.buttonsSetting?.[OpsButtonType.RETURN]?.displayName ||
-              OPERATION_BUTTON_NAME.get(OpsButtonType.RETURN)
+              item.buttonsSetting?.[OperationButtonType.RETURN]?.displayName ||
+              OPERATION_BUTTON_NAME.get(OperationButtonType.RETURN)
             }}
           </el-button>
         </div>
@@ -192,7 +192,7 @@ import { registerComponent } from '@/utils/routerHelper'
 import { isEmpty } from '@/utils/is'
 import * as UserApi from '@/api/system/user'
 import {
-  OpsButtonType,
+  OperationButtonType,
   OPERATION_BUTTON_NAME
 } from '@/components/SimpleProcessDesignerV2/src/consts'