仿钉钉流程设计器- 新增审批类型
parent
996fe3329c
commit
eb7e9397f5
|
@ -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 = [
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
Loading…
Reference in New Issue