From 0f576e006bfb33dd3cc2c80f1f816333b93d8b95 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Sat, 24 May 2025 23:02:24 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=B5=81=E7=A8=8B=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1-=20Simple=20=E6=A8=A1=E5=9E=8B=E8=AE=BE=E8=AE=A1=2020?= =?UTF-8?q?%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dept-select-modal/dept-select-modal.vue | 2 +- .../components/nodes/end-event-node.vue | 47 + .../components/nodes/node-handler.vue | 338 ++++++ .../components/nodes/start-user-node.vue | 119 ++ .../components/process-node-tree.vue | 147 +++ .../components/simple-process-designer.vue | 246 ++++ .../components/simple-process-model.vue | 286 +++++ .../simple-process-design/consts.ts | 1010 +++++++++++++++++ .../simple-process-design/helpers.ts | 739 ++++++++++++ .../components/simple-process-design/index.ts | 3 + .../simple-process-design/styles/iconfont.ttf | Bin 0 -> 4808 bytes .../styles/iconfont.woff | Bin 0 -> 3176 bytes .../styles/iconfont.woff2 | Bin 0 -> 2628 bytes .../styles/simple-process-designer.scss | 826 ++++++++++++++ .../styles/svg/simple-process-bg.svg | 1 + .../src/views/bpm/model/form/index.vue | 23 +- .../bpm/model/form/modules/basic-info.vue | 3 +- .../bpm/model/form/modules/process-design.vue | 67 ++ .../form/modules/simple-model-design.vue | 40 + .../modules/category-draggable-model.vue | 15 +- 20 files changed, 3898 insertions(+), 14 deletions(-) create mode 100644 apps/web-antd/src/components/simple-process-design/components/nodes/end-event-node.vue create mode 100644 apps/web-antd/src/components/simple-process-design/components/nodes/node-handler.vue create mode 100644 apps/web-antd/src/components/simple-process-design/components/nodes/start-user-node.vue create mode 100644 apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue create mode 100644 apps/web-antd/src/components/simple-process-design/components/simple-process-designer.vue create mode 100644 apps/web-antd/src/components/simple-process-design/components/simple-process-model.vue create mode 100644 apps/web-antd/src/components/simple-process-design/consts.ts create mode 100644 apps/web-antd/src/components/simple-process-design/helpers.ts create mode 100644 apps/web-antd/src/components/simple-process-design/index.ts create mode 100644 apps/web-antd/src/components/simple-process-design/styles/iconfont.ttf create mode 100644 apps/web-antd/src/components/simple-process-design/styles/iconfont.woff create mode 100644 apps/web-antd/src/components/simple-process-design/styles/iconfont.woff2 create mode 100644 apps/web-antd/src/components/simple-process-design/styles/simple-process-designer.scss create mode 100644 apps/web-antd/src/components/simple-process-design/styles/svg/simple-process-bg.svg create mode 100644 apps/web-antd/src/views/bpm/model/form/modules/process-design.vue create mode 100644 apps/web-antd/src/views/bpm/model/form/modules/simple-model-design.vue diff --git a/apps/web-antd/src/components/dept-select-modal/dept-select-modal.vue b/apps/web-antd/src/components/dept-select-modal/dept-select-modal.vue index 69968ce3c..7a36899ec 100644 --- a/apps/web-antd/src/components/dept-select-modal/dept-select-modal.vue +++ b/apps/web-antd/src/components/dept-select-modal/dept-select-modal.vue @@ -3,7 +3,7 @@ import type { DataNode } from 'ant-design-vue/es/tree'; import type { SystemDeptApi } from '#/api/system/dept'; -import { defineProps, ref } from 'vue'; +import { ref } from 'vue'; import { useVbenModal } from '@vben/common-ui'; import { handleTree } from '@vben/utils'; diff --git a/apps/web-antd/src/components/simple-process-design/components/nodes/end-event-node.vue b/apps/web-antd/src/components/simple-process-design/components/nodes/end-event-node.vue new file mode 100644 index 000000000..cccca4dbb --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/components/nodes/end-event-node.vue @@ -0,0 +1,47 @@ + + + diff --git a/apps/web-antd/src/components/simple-process-design/components/nodes/node-handler.vue b/apps/web-antd/src/components/simple-process-design/components/nodes/node-handler.vue new file mode 100644 index 000000000..01ab889dc --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/components/nodes/node-handler.vue @@ -0,0 +1,338 @@ + + + + diff --git a/apps/web-antd/src/components/simple-process-design/components/nodes/start-user-node.vue b/apps/web-antd/src/components/simple-process-design/components/nodes/start-user-node.vue new file mode 100644 index 000000000..748acef32 --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/components/nodes/start-user-node.vue @@ -0,0 +1,119 @@ + + + diff --git a/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue b/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue new file mode 100644 index 000000000..3e9e7de1e --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/components/process-node-tree.vue @@ -0,0 +1,147 @@ + + + diff --git a/apps/web-antd/src/components/simple-process-design/components/simple-process-designer.vue b/apps/web-antd/src/components/simple-process-design/components/simple-process-designer.vue new file mode 100644 index 000000000..f817963c0 --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/components/simple-process-designer.vue @@ -0,0 +1,246 @@ + + diff --git a/apps/web-antd/src/components/simple-process-design/components/simple-process-model.vue b/apps/web-antd/src/components/simple-process-design/components/simple-process-model.vue new file mode 100644 index 000000000..2495a68fd --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/components/simple-process-model.vue @@ -0,0 +1,286 @@ + + + diff --git a/apps/web-antd/src/components/simple-process-design/consts.ts b/apps/web-antd/src/components/simple-process-design/consts.ts new file mode 100644 index 000000000..74c910f60 --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/consts.ts @@ -0,0 +1,1010 @@ +// TODO 芋艿 这些 常量是不是可以共享 + +interface DictDataType { + label: string; + value: number | string; +} + +// 用户任务的审批类型。 【参考飞书】 +export enum ApproveType { + /** + * 自动通过 + */ + AUTO_APPROVE = 2, + /** + * 自动拒绝 + */ + AUTO_REJECT = 3, + /** + * 人工审批 + */ + USER = 1, +} + +// 多人审批方式类型枚举 ( 用于审批节点 ) +export enum ApproveMethodType { + /** + * 多人或签(通过只需一人,拒绝只需一人) + */ + ANY_APPROVE = 3, + + /** + * 多人会签(按通过比例) + */ + APPROVE_BY_RATIO = 2, + + /** + * 随机挑选一人审批 + */ + RANDOM_SELECT_ONE_APPROVE = 1, + /** + * 多人依次审批 + */ + SEQUENTIAL_APPROVE = 4, +} + +/** + * 任务状态枚举 + */ +export enum TaskStatusEnum { + /** + * 审批通过 + */ + APPROVE = 2, + + /** + * 审批通过中 + */ + APPROVING = 7, + /** + * 已取消 + */ + CANCEL = 4, + /** + * 未开始 + */ + NOT_START = -1, + + /** + * 审批不通过 + */ + REJECT = 3, + + /** + * 已退回 + */ + RETURN = 5, + /** + * 审批中 + */ + RUNNING = 1, + /** + * 待审批 + */ + WAIT = 0, +} + +/** + * 节点类型 + */ +export enum NodeType { + /** + * 子流程节点 + */ + CHILD_PROCESS_NODE = 20, + /** + * 条件分支节点 (对应排他网关) + */ + CONDITION_BRANCH_NODE = 51, + /** + * 条件节点 + */ + CONDITION_NODE = 50, + + /** + * 抄送人节点 + */ + COPY_TASK_NODE = 12, + + /** + * 延迟器节点 + */ + DELAY_TIMER_NODE = 14, + + /** + * 结束节点 + */ + END_EVENT_NODE = 1, + + /** + * 包容分支节点 (对应包容网关) + */ + INCLUSIVE_BRANCH_NODE = 53, + + /** + * 并行分支节点 (对应并行网关) + */ + PARALLEL_BRANCH_NODE = 52, + + /** + * 路由分支节点 + */ + ROUTER_BRANCH_NODE = 54, + /** + * 发起人节点 + */ + START_USER_NODE = 10, + /** + * 办理人节点 + */ + TRANSACTOR_NODE = 13, + + /** + * 触发器节点 + */ + TRIGGER_NODE = 15, + /** + * 审批人节点 + */ + USER_TASK_NODE = 11, +} + +export enum NodeId { + /** + * 发起人节点 Id + */ + END_EVENT_NODE_ID = 'EndEvent', + + /** + * 发起人节点 Id + */ + START_USER_NODE_ID = 'StartUserNode', +} + +// 条件配置类型 ( 用于条件节点配置 ) +export enum ConditionType { + /** + * 条件表达式 + */ + EXPRESSION = 1, + + /** + * 条件规则 + */ + RULE = 2, +} + +// 操作按钮类型枚举 (用于审批节点) +export enum OperationButtonType { + /** + * 加签 + */ + ADD_SIGN = 5, + /** + * 通过 + */ + APPROVE = 1, + /** + * 抄送 + */ + COPY = 7, + /** + * 委派 + */ + DELEGATE = 4, + /** + * 拒绝 + */ + REJECT = 2, + /** + * 退回 + */ + RETURN = 6, + /** + * 转办 + */ + TRANSFER = 3, +} + +// 审批拒绝类型枚举 +export enum RejectHandlerType { + /** + * 结束流程 + */ + FINISH_PROCESS = 1, + /** + * 驳回到指定节点 + */ + RETURN_USER_TASK = 2, +} + +// 用户任务超时处理类型枚举 +export enum TimeoutHandlerType { + /** + * 自动同意 + */ + APPROVE = 2, + /** + * 自动拒绝 + */ + REJECT = 3, + /** + * 自动提醒 + */ + REMINDER = 1, +} + +// 用户任务的审批人为空时,处理类型枚举 +export enum AssignEmptyHandlerType { + /** + * 自动通过 + */ + APPROVE = 1, + /** + * 转交给流程管理员 + */ + ASSIGN_ADMIN = 4, + /** + * 指定人员审批 + */ + ASSIGN_USER = 3, + /** + * 自动拒绝 + */ + REJECT = 2, +} + +// 用户任务的审批人与发起人相同时,处理类型枚举 +export enum AssignStartUserHandlerType { + /** + * 转交给部门负责人审批 + */ + ASSIGN_DEPT_LEADER = 3, + /** + * 自动跳过【参考飞书】:1)如果当前节点还有其他审批人,则交由其他审批人进行审批;2)如果当前节点没有其他审批人,则该节点自动通过 + */ + SKIP = 2, + /** + * 由发起人对自己审批 + */ + START_USER_AUDIT = 1, +} + +// 时间单位枚举 +export enum TimeUnitType { + /** + * 天 + */ + DAY = 3, + /** + * 小时 + */ + HOUR = 2, + /** + * 分钟 + */ + MINUTE = 1, +} + +/** + * 表单权限的枚举 + */ +export enum FieldPermissionType { + /** + * 隐藏 + */ + NONE = '3', + /** + * 只读 + */ + READ = '1', + /** + * 编辑 + */ + WRITE = '2', +} + +/** + * 延迟类型 + */ +export enum DelayTypeEnum { + /** + * 固定日期时间 + */ + FIXED_DATE_TIME = 2, + /** + * 固定时长 + */ + FIXED_TIME_DURATION = 1, +} + +/** + * 触发器类型枚举 + */ +export enum TriggerTypeEnum { + /** + * 表单数据删除触发器 + */ + FORM_DELETE = 11, + /** + * 表单数据更新触发器 + */ + FORM_UPDATE = 10, + /** + * 接收 HTTP 回调请求触发器 + */ + HTTP_CALLBACK = 2, + /** + * 发送 HTTP 请求触发器 + */ + HTTP_REQUEST = 1, +} + +export enum ChildProcessStartUserTypeEnum { + /** + * 表单 + */ + FROM_FORM = 2, + /** + * 同主流程发起人 + */ + MAIN_PROCESS_START_USER = 1, +} + +export enum ChildProcessStartUserEmptyTypeEnum { + /** + * 子流程管理员 + */ + CHILD_PROCESS_ADMIN = 2, + /** + * 主流程管理员 + */ + MAIN_PROCESS_ADMIN = 3, + /** + * 同主流程发起人 + */ + MAIN_PROCESS_START_USER = 1, +} + +export enum ChildProcessMultiInstanceSourceTypeEnum { + /** + * 固定数量 + */ + FIXED_QUANTITY = 1, + /** + * 多选表单 + */ + MULTIPLE_FORM = 3, + /** + * 数字表单 + */ + NUMBER_FORM = 2, +} + +// 候选人策略枚举 ( 用于审批节点。抄送节点 ) +export enum CandidateStrategy { + /** + * 审批人自选 + */ + APPROVE_USER_SELECT = 34, + /** + * 部门的负责人 + */ + DEPT_LEADER = 21, + /** + * 部门成员 + */ + DEPT_MEMBER = 20, + /** + * 流程表达式 + */ + EXPRESSION = 60, + /** + * 表单内部门负责人 + */ + FORM_DEPT_LEADER = 51, + /** + * 表单内用户字段 + */ + FORM_USER = 50, + /** + * 连续多级部门的负责人 + */ + MULTI_LEVEL_DEPT_LEADER = 23, + /** + * 指定岗位 + */ + POST = 22, + /** + * 指定角色 + */ + ROLE = 10, + /** + * 发起人自己 + */ + START_USER = 36, + /** + * 发起人部门负责人 + */ + START_USER_DEPT_LEADER = 37, + /** + * 发起人连续多级部门的负责人 + */ + START_USER_MULTI_LEVEL_DEPT_LEADER = 38, + /** + * 发起人自选 + */ + START_USER_SELECT = 35, + /** + * 指定用户 + */ + USER = 30, + /** + * 指定用户组 + */ + USER_GROUP = 40, +} + +export enum BpmHttpRequestParamTypeEnum { + /** + * 固定值 + */ + FIXED_VALUE = 1, + /** + * 表单 + */ + FROM_FORM = 2, +} + +// 这里定义 HTTP 请求参数类型 +export type HttpRequestParam = { + key: string; + type: number; + value: string; +}; + +// 监听器结构定义 +export type ListenerHandler = { + body?: HttpRequestParam[]; + enable: boolean; + header?: HttpRequestParam[]; + path?: string; +}; + +/** + * 条件规则结构定义 + */ +export type ConditionRule = { + leftSide: string; + opCode: string; + rightSide: string; +}; + +/** + * 条件结构定义 + */ +export type Condition = { + // 条件规则的逻辑关系是否为且 + and: boolean; + rules: ConditionRule[]; +}; + +/** + * 条件组结构定义 + */ +export type ConditionGroup = { + // 条件组的逻辑关系是否为且 + and: boolean; + // 条件数组 + conditions: Condition[]; +}; + +/** + * 条件节点设置结构定义,用于条件节点 + */ +export type ConditionSetting = { + // 条件表达式 + conditionExpression?: string; + // 条件组 + conditionGroups?: ConditionGroup; + // 条件类型 + conditionType?: ConditionType; + // 是否默认的条件 + defaultFlow?: boolean; +}; + +/** + * 审批拒绝结构定义 + */ +export type RejectHandler = { + // 退回节点 Id + returnNodeId?: string; + // 审批拒绝类型 + type: RejectHandlerType; +}; + +/** + * 审批超时结构定义 + */ +export type TimeoutHandler = { + // 是否开启超时处理 + enable: boolean; + // 执行动作是自动提醒, 最大提醒次数 + maxRemindCount?: number; + // 超时时间设置 + timeDuration?: string; + // 超时执行的动作 + type?: number; +}; + +/** + * 审批人为空的结构定义 + */ +export type AssignEmptyHandler = { + // 审批人为空的处理类型 + type: AssignEmptyHandlerType; + // 指定用户的编号数组 + userIds?: number[]; +}; + +/** + * 延迟设置 + */ +export type DelaySetting = { + // 延迟时间表达式 + delayTime: string; + // 延迟类型 + delayType: number; +}; + +/** + * 路由分支结构定义 + */ +export type RouterSetting = { + conditionExpression: string; + conditionGroups: ConditionGroup; + conditionType: ConditionType; + nodeId: string; +}; + +/** + * 操作按钮权限结构定义 + */ +export type ButtonSetting = { + displayName: string; + enable: boolean; + id: OperationButtonType; +}; + +/** + * HTTP 请求触发器结构定义 + */ +export type HttpRequestTriggerSetting = { + // 请求体参数设置 + body?: HttpRequestParam[]; + // 请求头参数设置 + header?: HttpRequestParam[]; + // 请求响应设置 + response?: Record[]; + // 请求 URL + url: string; +}; + +/** + * 流程表单触发器配置结构定义 + */ +export type FormTriggerSetting = { + // 条件表达式 + conditionExpression?: string; + // 条件组 + conditionGroups?: ConditionGroup; + // 条件类型 + conditionType?: ConditionType; + // 删除表单字段配置 + deleteFields?: string[]; + // 更新表单字段配置 + updateFormFields?: Record; +}; + +/** + * 触发器节点结构定义 + */ +export type TriggerSetting = { + formSettings?: FormTriggerSetting[]; + httpRequestSetting?: HttpRequestTriggerSetting; + type: TriggerTypeEnum; +}; + +export type IOParameter = { + source: string; + target: string; +}; + +export type StartUserSetting = { + emptyType?: ChildProcessStartUserEmptyTypeEnum; + formField?: string; + type: ChildProcessStartUserTypeEnum; +}; + +export type TimeoutSetting = { + enable: boolean; + timeExpression?: string; + type?: DelayTypeEnum; +}; + +export type MultiInstanceSetting = { + approveRatio?: number; + enable: boolean; + sequential?: boolean; + source?: string; + sourceType?: ChildProcessMultiInstanceSourceTypeEnum; +}; + +/** + * 子流程节点结构定义 + */ +export type ChildProcessSetting = { + async: boolean; + calledProcessDefinitionKey: string; + calledProcessDefinitionName: string; + inVariables?: IOParameter[]; + multiInstanceSetting: MultiInstanceSetting; + outVariables?: IOParameter[]; + skipStartUserNode: boolean; + startUserSetting: StartUserSetting; + timeoutSetting: TimeoutSetting; +}; + +/** + * 节点结构定义 + */ +export interface SimpleFlowNode { + id: string; + type: NodeType; + name: string; + showText?: string; + // 孩子节点 + childNode?: SimpleFlowNode; + // 条件节点 + conditionNodes?: SimpleFlowNode[]; + // 审批类型 + approveType?: ApproveType; + // 候选人策略 + candidateStrategy?: number; + // 候选人参数 + candidateParam?: string; + // 多人审批方式 + approveMethod?: ApproveMethodType; + // 通过比例 + approveRatio?: number; + // 审批按钮设置 + buttonsSetting?: any[]; + // 表单权限 + fieldsPermission?: Array>; + // 审批任务超时处理 + timeoutHandler?: TimeoutHandler; + // 审批任务拒绝处理 + rejectHandler?: RejectHandler; + // 审批人为空的处理 + assignEmptyHandler?: AssignEmptyHandler; + // 审批节点的审批人与发起人相同时,对应的处理类型 + assignStartUserHandlerType?: number; + // 创建任务监听器 + taskCreateListener?: ListenerHandler; + // 创建任务监听器 + taskAssignListener?: ListenerHandler; + // 创建任务监听器 + taskCompleteListener?: ListenerHandler; + // 条件设置 + conditionSetting?: ConditionSetting; + // 活动的状态,用于前端节点状态展示 + activityStatus?: TaskStatusEnum; + // 延迟设置 + delaySetting?: DelaySetting; + // 路由分支 + routerGroups?: RouterSetting[]; + defaultFlowId?: string; + // 签名 + signEnable?: boolean; + // 审批意见 + reasonRequire?: boolean; + // 触发器设置 + triggerSetting?: TriggerSetting; + // 子流程 + childProcessSetting?: ChildProcessSetting; +} + +/** + * 条件组默认值 + */ +export const DEFAULT_CONDITION_GROUP_VALUE = { + and: true, + conditions: [ + { + and: true, + rules: [ + { + opCode: '==', + leftSide: '', + rightSide: '', + }, + ], + }, + ], +}; + +export const NODE_DEFAULT_TEXT = new Map(); +NODE_DEFAULT_TEXT.set(NodeType.USER_TASK_NODE, '请配置审批人'); +NODE_DEFAULT_TEXT.set(NodeType.COPY_TASK_NODE, '请配置抄送人'); +NODE_DEFAULT_TEXT.set(NodeType.CONDITION_NODE, '请设置条件'); +NODE_DEFAULT_TEXT.set(NodeType.START_USER_NODE, '请设置发起人'); +NODE_DEFAULT_TEXT.set(NodeType.DELAY_TIMER_NODE, '请设置延迟器'); +NODE_DEFAULT_TEXT.set(NodeType.ROUTER_BRANCH_NODE, '请设置路由节点'); +NODE_DEFAULT_TEXT.set(NodeType.TRIGGER_NODE, '请设置触发器'); +NODE_DEFAULT_TEXT.set(NodeType.TRANSACTOR_NODE, '请设置办理人'); +NODE_DEFAULT_TEXT.set(NodeType.CHILD_PROCESS_NODE, '请设置子流程'); + +export const NODE_DEFAULT_NAME = new Map(); +NODE_DEFAULT_NAME.set(NodeType.USER_TASK_NODE, '审批人'); +NODE_DEFAULT_NAME.set(NodeType.COPY_TASK_NODE, '抄送人'); +NODE_DEFAULT_NAME.set(NodeType.CONDITION_NODE, '条件'); +NODE_DEFAULT_NAME.set(NodeType.START_USER_NODE, '发起人'); +NODE_DEFAULT_NAME.set(NodeType.DELAY_TIMER_NODE, '延迟器'); +NODE_DEFAULT_NAME.set(NodeType.ROUTER_BRANCH_NODE, '路由分支'); +NODE_DEFAULT_NAME.set(NodeType.TRIGGER_NODE, '触发器'); +NODE_DEFAULT_NAME.set(NodeType.TRANSACTOR_NODE, '办理人'); +NODE_DEFAULT_NAME.set(NodeType.CHILD_PROCESS_NODE, '子流程'); + +// 候选人策略。暂时不从字典中取。 后续可能调整。控制显示顺序 +export const CANDIDATE_STRATEGY: DictDataType[] = [ + { label: '指定成员', value: CandidateStrategy.USER as any }, + { label: '指定角色', value: CandidateStrategy.ROLE as any }, + { label: '指定岗位', value: CandidateStrategy.POST as any }, + { label: '部门成员', value: CandidateStrategy.DEPT_MEMBER as any }, + { label: '部门负责人', value: CandidateStrategy.DEPT_LEADER as any }, + { + label: '连续多级部门负责人', + value: CandidateStrategy.MULTI_LEVEL_DEPT_LEADER as any, + }, + { label: '发起人自选', value: CandidateStrategy.START_USER_SELECT as any }, + { label: '审批人自选', value: CandidateStrategy.APPROVE_USER_SELECT as any }, + { label: '发起人本人', value: CandidateStrategy.START_USER as any }, + { + label: '发起人部门负责人', + value: CandidateStrategy.START_USER_DEPT_LEADER as any, + }, + { + label: '发起人连续部门负责人', + value: CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER as any, + }, + { label: '用户组', value: CandidateStrategy.USER_GROUP as any }, + { label: '表单内用户字段', value: CandidateStrategy.FORM_USER as any }, + { + label: '表单内部门负责人', + value: CandidateStrategy.FORM_DEPT_LEADER as any, + }, + { label: '流程表达式', value: CandidateStrategy.EXPRESSION as any }, +]; +// 审批节点 的审批类型 +export const APPROVE_TYPE: DictDataType[] = [ + { label: '人工审批', value: ApproveType.USER as any }, + { label: '自动通过', value: ApproveType.AUTO_APPROVE as any }, + { label: '自动拒绝', value: ApproveType.AUTO_REJECT as any }, +]; + +export const APPROVE_METHODS: DictDataType[] = [ + { + label: '按顺序依次审批', + value: ApproveMethodType.SEQUENTIAL_APPROVE as any, + }, + { + label: '会签(可同时审批,至少 % 人必须审批通过)', + value: ApproveMethodType.APPROVE_BY_RATIO as any, + }, + { + label: '或签(可同时审批,有一人通过即可)', + value: ApproveMethodType.ANY_APPROVE as any, + }, + { + label: '随机挑选一人审批', + value: ApproveMethodType.RANDOM_SELECT_ONE_APPROVE as any, + }, +]; + +export const CONDITION_CONFIG_TYPES: DictDataType[] = [ + { label: '条件规则', value: ConditionType.RULE as any }, + { label: '条件表达式', value: ConditionType.EXPRESSION as any }, +]; + +// 时间单位类型 +export const TIME_UNIT_TYPES: DictDataType[] = [ + { label: '分钟', value: TimeUnitType.MINUTE as any }, + { label: '小时', value: TimeUnitType.HOUR as any }, + { label: '天', value: TimeUnitType.DAY as any }, +]; +// 超时处理执行动作类型 +export const TIMEOUT_HANDLER_TYPES: DictDataType[] = [ + { label: '自动提醒', value: 1 }, + { label: '自动同意', value: 2 }, + { label: '自动拒绝', value: 3 }, +]; +export const REJECT_HANDLER_TYPES: DictDataType[] = [ + { label: '终止流程', value: RejectHandlerType.FINISH_PROCESS as any }, + { label: '驳回到指定节点', value: RejectHandlerType.RETURN_USER_TASK as any }, + // { label: '结束任务', value: RejectHandlerType.FINISH_TASK } +]; +export const ASSIGN_EMPTY_HANDLER_TYPES: DictDataType[] = [ + { label: '自动通过', value: 1 }, + { label: '自动拒绝', value: 2 }, + { label: '指定成员审批', value: 3 }, + { label: '转交给流程管理员', value: 4 }, +]; +export const ASSIGN_START_USER_HANDLER_TYPES: DictDataType[] = [ + { label: '由发起人对自己审批', value: 1 }, + { label: '自动跳过', value: 2 }, + { label: '转交给部门负责人审批', value: 3 }, +]; + +// 比较运算符 +export const COMPARISON_OPERATORS: DictDataType[] = [ + { + value: '==', + label: '等于', + }, + { + value: '!=', + label: '不等于', + }, + { + value: '>', + label: '大于', + }, + { + value: '>=', + label: '大于等于', + }, + { + value: '<', + label: '小于', + }, + { + value: '<=', + label: '小于等于', + }, +]; +// 审批操作按钮名称 +export const OPERATION_BUTTON_NAME = new Map(); +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, '退回'); +OPERATION_BUTTON_NAME.set(OperationButtonType.COPY, '抄送'); + +// 默认的按钮权限设置 +export const DEFAULT_BUTTON_SETTING: ButtonSetting[] = [ + { id: OperationButtonType.APPROVE, displayName: '通过', enable: true }, + { id: OperationButtonType.REJECT, displayName: '拒绝', enable: true }, + { id: OperationButtonType.TRANSFER, displayName: '转办', enable: true }, + { id: OperationButtonType.DELEGATE, displayName: '委派', enable: true }, + { id: OperationButtonType.ADD_SIGN, displayName: '加签', enable: true }, + { id: OperationButtonType.RETURN, displayName: '退回', enable: true }, +]; + +// 办理人默认的按钮权限设置 +export const TRANSACTOR_DEFAULT_BUTTON_SETTING: ButtonSetting[] = [ + { id: OperationButtonType.APPROVE, displayName: '办理', enable: true }, + { id: OperationButtonType.REJECT, displayName: '拒绝', enable: false }, + { 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 START_USER_BUTTON_SETTING: ButtonSetting[] = [ + { id: OperationButtonType.APPROVE, displayName: '提交', enable: true }, + { id: OperationButtonType.REJECT, displayName: '拒绝', enable: false }, + { 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: DictDataType[] = [ + { label: '第 1 级部门', value: 1 }, + { label: '第 2 级部门', value: 2 }, + { label: '第 3 级部门', value: 3 }, + { label: '第 4 级部门', value: 4 }, + { label: '第 5 级部门', value: 5 }, + { label: '第 6 级部门', value: 6 }, + { label: '第 7 级部门', value: 7 }, + { label: '第 8 级部门', value: 8 }, + { label: '第 9 级部门', value: 9 }, + { label: '第 10 级部门', value: 10 }, + { label: '第 11 级部门', value: 11 }, + { label: '第 12 级部门', value: 12 }, + { label: '第 13 级部门', value: 13 }, + { label: '第 14 级部门', value: 14 }, + { label: '第 15 级部门', value: 15 }, +]; + +/** + * 流程实例的变量枚举 + */ +export enum ProcessVariableEnum { + /** + * 流程定义名称 + */ + PROCESS_DEFINITION_NAME = 'PROCESS_DEFINITION_NAME', + /** + * 发起时间 + */ + START_TIME = 'PROCESS_START_TIME', + /** + * 发起用户 ID + */ + START_USER_ID = 'PROCESS_START_USER_ID', +} + +export const DELAY_TYPE = [ + { label: '固定时长', value: DelayTypeEnum.FIXED_TIME_DURATION }, + { label: '固定日期', value: DelayTypeEnum.FIXED_DATE_TIME }, +]; + +export const BPM_HTTP_REQUEST_PARAM_TYPES = [ + { + value: 1, + label: '固定值', + }, + { + value: 2, + label: '表单', + }, +]; + +export const TRIGGER_TYPES: DictDataType[] = [ + { label: '发送 HTTP 请求', value: TriggerTypeEnum.HTTP_REQUEST as any }, + { label: '接收 HTTP 回调', value: TriggerTypeEnum.HTTP_CALLBACK as any }, + { label: '修改表单数据', value: TriggerTypeEnum.FORM_UPDATE as any }, + { label: '删除表单数据', value: TriggerTypeEnum.FORM_DELETE as any }, +]; + +export const CHILD_PROCESS_START_USER_TYPE = [ + { + label: '同主流程发起人', + value: ChildProcessStartUserTypeEnum.MAIN_PROCESS_START_USER, + }, + { label: '表单', value: ChildProcessStartUserTypeEnum.FROM_FORM }, +]; + +export const CHILD_PROCESS_START_USER_EMPTY_TYPE = [ + { + label: '同主流程发起人', + value: ChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER, + }, + { + label: '子流程管理员', + value: ChildProcessStartUserEmptyTypeEnum.CHILD_PROCESS_ADMIN, + }, + { + label: '主流程管理员', + value: ChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN, + }, +]; + +export const CHILD_PROCESS_MULTI_INSTANCE_SOURCE_TYPE = [ + { + label: '固定数量', + value: ChildProcessMultiInstanceSourceTypeEnum.FIXED_QUANTITY, + }, + { + label: '数字表单', + value: ChildProcessMultiInstanceSourceTypeEnum.NUMBER_FORM, + }, + { + label: '多选表单', + value: ChildProcessMultiInstanceSourceTypeEnum.MULTIPLE_FORM, + }, +]; diff --git a/apps/web-antd/src/components/simple-process-design/helpers.ts b/apps/web-antd/src/components/simple-process-design/helpers.ts new file mode 100644 index 000000000..281572815 --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/helpers.ts @@ -0,0 +1,739 @@ +import type { Ref } from 'vue'; + +import type { + ConditionGroup, + HttpRequestParam, + SimpleFlowNode, +} from './consts'; + +import type { BpmUserGroupApi } from '#/api/bpm/userGroup'; +import type { SystemDeptApi } from '#/api/system/dept'; +import type { SystemPostApi } from '#/api/system/post'; +import type { SystemRoleApi } from '#/api/system/role'; +import type { SystemUserApi } from '#/api/system/user'; + +import { inject, ref, toRaw, unref, watch } from 'vue'; + +import { + ApproveMethodType, + AssignEmptyHandlerType, + AssignStartUserHandlerType, + CandidateStrategy, + COMPARISON_OPERATORS, + ConditionType, + FieldPermissionType, + NODE_DEFAULT_NAME, + NodeType, + ProcessVariableEnum, + RejectHandlerType, + TaskStatusEnum, +} from './consts'; + +export function useWatchNode(props: { + flowNode: SimpleFlowNode; +}): Ref { + const node = ref(props.flowNode); + watch( + () => props.flowNode, + (newValue) => { + node.value = newValue; + }, + ); + return node; +} + +// 解析 formCreate 所有表单字段, 并返回 +const parseFormCreateFields = (formFields?: string[]) => { + const result: Array> = []; + if (formFields) { + formFields.forEach((fieldStr: string) => { + parseFormFields(JSON.parse(fieldStr), result); + }); + } + return result; +}; + +/** + * 解析表单组件的 field, title 等字段(递归,如果组件包含子组件) + * + * @param rule 组件的生成规则 https://www.form-create.com/v3/guide/rule + * @param fields 解析后表单组件字段 + * @param parentTitle 如果是子表单,子表单的标题,默认为空 + */ +export const parseFormFields = ( + rule: Record, + fields: Array> = [], + parentTitle: string = '', +) => { + const { type, field, $required, title: tempTitle, children } = rule; + if (field && tempTitle) { + let title = tempTitle; + if (parentTitle) { + title = `${parentTitle}.${tempTitle}`; + } + let required = false; + if ($required) { + required = true; + } + fields.push({ + field, + title, + type, + required, + }); + // TODO 子表单 需要处理子表单字段 + // if (type === 'group' && rule.props?.rule && Array.isArray(rule.props.rule)) { + // // 解析子表单的字段 + // rule.props.rule.forEach((item) => { + // parseFields(item, fieldsPermission, title) + // }) + // } + } + if (children && Array.isArray(children)) { + children.forEach((rule) => { + parseFormFields(rule, fields); + }); + } +}; + +/** + * @description 表单数据权限配置,用于发起人节点 、审批节点、抄送节点 + */ +export function useFormFieldsPermission( + defaultPermission: FieldPermissionType, +) { + // 字段权限配置. 需要有 field, title, permissioin 属性 + const fieldsPermissionConfig = ref>>([]); + + const formType = inject>('formType', ref()); // 表单类型 + + const formFields = inject>('formFields', ref([])); // 流程表单字段 + + const getNodeConfigFormFields = ( + nodeFormFields?: Array>, + ) => { + nodeFormFields = toRaw(nodeFormFields); + fieldsPermissionConfig.value = + !nodeFormFields || nodeFormFields.length === 0 + ? getDefaultFieldsPermission(unref(formFields)) + : mergeFieldsPermission(nodeFormFields, unref(formFields)); + }; + // 合并已经设置的表单字段权限,当前流程表单字段 (可能新增,或删除了字段) + const mergeFieldsPermission = ( + formFieldsPermisson: Array>, + formFields?: string[], + ) => { + let mergedFieldsPermission: Array> = []; + if (formFields) { + mergedFieldsPermission = parseFormCreateFields(formFields).map((item) => { + const found = formFieldsPermisson.find( + (fieldPermission) => fieldPermission.field === item.field, + ); + return { + field: item.field, + title: item.title, + permission: found ? found.permission : defaultPermission, + }; + }); + } + return mergedFieldsPermission; + }; + + // 默认的表单权限: 获取表单的所有字段,设置字段默认权限为只读 + const getDefaultFieldsPermission = (formFields?: string[]) => { + let defaultFieldsPermission: Array> = []; + if (formFields) { + defaultFieldsPermission = parseFormCreateFields(formFields).map( + (item) => { + return { + field: item.field, + title: item.title, + permission: defaultPermission, + }; + }, + ); + } + return defaultFieldsPermission; + }; + + // 获取表单的所有字段,作为下拉框选项 + const formFieldOptions = parseFormCreateFields(unref(formFields)); + + return { + formType, + fieldsPermissionConfig, + formFieldOptions, + getNodeConfigFormFields, + }; +} + +/** + * @description 获取流程表单的字段 + */ +export function useFormFields() { + const formFields = inject>('formFields', ref([])); // 流程表单字段 + return parseFormCreateFields(unref(formFields)); +} + +// TODO @芋艿:后续需要把各种类似 useFormFieldsPermission 的逻辑,抽成一个通用方法。 +/** + * @description 获取流程表单的字段和发起人字段 + */ +export function useFormFieldsAndStartUser() { + const injectFormFields = inject>('formFields', ref([])); // 流程表单字段 + const formFields = parseFormCreateFields(unref(injectFormFields)); + // 添加发起人 + formFields.unshift({ + field: ProcessVariableEnum.START_USER_ID, + title: '发起人', + required: true, + }); + return formFields; +} + +export type UserTaskFormType = { + approveMethod: ApproveMethodType; + approveRatio?: number; + assignEmptyHandlerType?: AssignEmptyHandlerType; + assignEmptyHandlerUserIds?: number[]; + assignStartUserHandlerType?: AssignStartUserHandlerType; + buttonsSetting: any[]; + candidateStrategy: CandidateStrategy; + deptIds?: number[]; // 部门 + deptLevel?: number; // 部门层级 + expression?: string; // 流程表达式 + formDept?: string; // 表单内部门字段 + formUser?: string; // 表单内用户字段 + maxRemindCount?: number; + postIds?: number[]; // 岗位 + reasonRequire: boolean; + rejectHandlerType?: RejectHandlerType; + returnNodeId?: string; + roleIds?: number[]; // 角色 + signEnable: boolean; + taskAssignListener?: { + body: HttpRequestParam[]; + header: HttpRequestParam[]; + }; + taskAssignListenerEnable?: boolean; + taskAssignListenerPath?: string; + taskCompleteListener?: { + body: HttpRequestParam[]; + header: HttpRequestParam[]; + }; + taskCompleteListenerEnable?: boolean; + taskCompleteListenerPath?: string; + taskCreateListener?: { + body: HttpRequestParam[]; + header: HttpRequestParam[]; + }; + taskCreateListenerEnable?: boolean; + taskCreateListenerPath?: string; + timeDuration?: number; + timeoutHandlerEnable?: boolean; + timeoutHandlerType?: number; + userGroups?: number[]; // 用户组 + userIds?: number[]; // 用户 +}; + +export type CopyTaskFormType = { + candidateStrategy: CandidateStrategy; + deptIds?: number[]; // 部门 + deptLevel?: number; // 部门层级 + expression?: string; // 流程表达式 + formDept?: string; // 表单内部门字段 + formUser?: string; // 表单内用户字段 + postIds?: number[]; // 岗位 + roleIds?: number[]; // 角色 + userGroups?: number[]; // 用户组 + userIds?: number[]; // 用户 +}; + +/** + * @description 节点表单数据。 用于审批节点、抄送节点 + */ +export function useNodeForm(nodeType: NodeType) { + const roleOptions = inject>('roleList', ref([])); // 角色列表 + const postOptions = inject>('postList', ref([])); // 岗位列表 + const userOptions = inject>('userList', ref([])); // 用户列表 + const deptOptions = inject>('deptList', ref([])); // 部门列表 + const userGroupOptions = inject>( + 'userGroupList', + ref([]), + ); // 用户组列表 + const deptTreeOptions = inject>( + 'deptTree', + ref([]), + ); // 部门树 + const formFields = inject>('formFields', ref([])); // 流程表单字段 + const configForm = ref(); + + // eslint-disable-next-line unicorn/prefer-ternary + if ( + nodeType === NodeType.USER_TASK_NODE || + nodeType === NodeType.TRANSACTOR_NODE + ) { + configForm.value = { + candidateStrategy: CandidateStrategy.USER, + approveMethod: ApproveMethodType.SEQUENTIAL_APPROVE, + approveRatio: 100, + rejectHandlerType: RejectHandlerType.FINISH_PROCESS, + assignStartUserHandlerType: AssignStartUserHandlerType.START_USER_AUDIT, + returnNodeId: '', + timeoutHandlerEnable: false, + timeoutHandlerType: 1, + timeDuration: 6, // 默认 6小时 + maxRemindCount: 1, // 默认 提醒 1次 + buttonsSetting: [], + }; + } else { + configForm.value = { + candidateStrategy: CandidateStrategy.USER, + }; + } + + const getShowText = (): string => { + let showText = ''; + // 指定成员 + if ( + configForm.value?.candidateStrategy === CandidateStrategy.USER && + configForm.value?.userIds?.length > 0 + ) { + const candidateNames: string[] = []; + userOptions?.value.forEach((item: any) => { + if (configForm.value?.userIds?.includes(item.id)) { + candidateNames.push(item.nickname); + } + }); + showText = `指定成员:${candidateNames.join(',')}`; + } + // 指定角色 + if ( + configForm.value?.candidateStrategy === CandidateStrategy.ROLE && + configForm.value.roleIds?.length > 0 + ) { + const candidateNames: string[] = []; + roleOptions?.value.forEach((item: any) => { + if (configForm.value?.roleIds?.includes(item.id)) { + candidateNames.push(item.name); + } + }); + showText = `指定角色:${candidateNames.join(',')}`; + } + // 指定部门 + if ( + (configForm.value?.candidateStrategy === CandidateStrategy.DEPT_MEMBER || + configForm.value?.candidateStrategy === CandidateStrategy.DEPT_LEADER || + configForm.value?.candidateStrategy === + CandidateStrategy.MULTI_LEVEL_DEPT_LEADER) && + configForm.value?.deptIds?.length > 0 + ) { + const candidateNames: string[] = []; + deptOptions?.value.forEach((item) => { + if (configForm.value?.deptIds?.includes(item.id)) { + candidateNames.push(item.name); + } + }); + if ( + configForm.value.candidateStrategy === CandidateStrategy.DEPT_MEMBER + ) { + showText = `部门成员:${candidateNames.join(',')}`; + } else if ( + configForm.value.candidateStrategy === CandidateStrategy.DEPT_LEADER + ) { + showText = `部门的负责人:${candidateNames.join(',')}`; + } else { + showText = `多级部门的负责人:${candidateNames.join(',')}`; + } + } + + // 指定岗位 + if ( + configForm.value?.candidateStrategy === CandidateStrategy.POST && + configForm.value.postIds?.length > 0 + ) { + const candidateNames: string[] = []; + postOptions?.value.forEach((item) => { + if (configForm.value?.postIds?.includes(item.id)) { + candidateNames.push(item.name); + } + }); + showText = `指定岗位: ${candidateNames.join(',')}`; + } + // 指定用户组 + if ( + configForm.value?.candidateStrategy === CandidateStrategy.USER_GROUP && + configForm.value?.userGroups?.length > 0 + ) { + const candidateNames: string[] = []; + userGroupOptions?.value.forEach((item) => { + if (configForm.value?.userGroups?.includes(item.id)) { + candidateNames.push(item.name); + } + }); + showText = `指定用户组: ${candidateNames.join(',')}`; + } + + // 表单内用户字段 + if (configForm.value?.candidateStrategy === CandidateStrategy.FORM_USER) { + const formFieldOptions = parseFormCreateFields(unref(formFields)); + const item = formFieldOptions.find( + (item) => item.field === configForm.value?.formUser, + ); + showText = `表单用户:${item?.title}`; + } + + // 表单内部门负责人 + if ( + configForm.value?.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER + ) { + showText = `表单内部门负责人`; + } + + // 审批人自选 + if ( + configForm.value?.candidateStrategy === + CandidateStrategy.APPROVE_USER_SELECT + ) { + showText = `审批人自选`; + } + + // 发起人自选 + if ( + configForm.value?.candidateStrategy === + CandidateStrategy.START_USER_SELECT + ) { + showText = `发起人自选`; + } + // 发起人自己 + if (configForm.value?.candidateStrategy === CandidateStrategy.START_USER) { + showText = `发起人自己`; + } + // 发起人的部门负责人 + if ( + configForm.value?.candidateStrategy === + CandidateStrategy.START_USER_DEPT_LEADER + ) { + showText = `发起人的部门负责人`; + } + // 发起人的部门负责人 + if ( + configForm.value?.candidateStrategy === + CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER + ) { + showText = `发起人连续部门负责人`; + } + // 流程表达式 + if (configForm.value?.candidateStrategy === CandidateStrategy.EXPRESSION) { + showText = `流程表达式:${configForm.value.expression}`; + } + return showText; + }; + + /** + * 处理候选人参数的赋值 + */ + const handleCandidateParam = () => { + let candidateParam: string | undefined; + if (!configForm.value) { + return candidateParam; + } + switch (configForm.value.candidateStrategy) { + case CandidateStrategy.DEPT_LEADER: + case CandidateStrategy.DEPT_MEMBER: { + candidateParam = configForm.value.deptIds?.join(','); + break; + } + case CandidateStrategy.EXPRESSION: { + candidateParam = configForm.value.expression; + break; + } + // 表单内部门的负责人 + case CandidateStrategy.FORM_DEPT_LEADER: { + // 候选人参数格式: | 分隔 。左边为表单内部门字段。 右边为部门层级 + const deptFieldOnForm = configForm.value.formDept; + candidateParam = deptFieldOnForm?.concat( + `|${configForm.value.deptLevel}`, + ); + break; + } + case CandidateStrategy.FORM_USER: { + candidateParam = configForm.value?.formUser; + break; + } + // 指定连续多级部门的负责人 + case CandidateStrategy.MULTI_LEVEL_DEPT_LEADER: { + // 候选人参数格式: | 分隔 。左边为部门(多个部门用 , 分隔)。 右边为部门层级 + const deptIds = configForm.value.deptIds?.join(','); + candidateParam = deptIds?.concat(`|${configForm.value.deptLevel}`); + break; + } + case CandidateStrategy.POST: { + candidateParam = configForm.value.postIds?.join(','); + break; + } + case CandidateStrategy.ROLE: { + candidateParam = configForm.value.roleIds?.join(','); + break; + } + // 发起人部门负责人 + case CandidateStrategy.START_USER_DEPT_LEADER: + case CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER: { + candidateParam = `${configForm.value.deptLevel}`; + break; + } + case CandidateStrategy.USER: { + candidateParam = configForm.value.userIds?.join(','); + break; + } + case CandidateStrategy.USER_GROUP: { + candidateParam = configForm.value.userGroups?.join(','); + break; + } + default: { + break; + } + } + return candidateParam; + }; + /** + * 解析候选人参数 + */ + const parseCandidateParam = ( + candidateStrategy: CandidateStrategy, + candidateParam: string | undefined, + ) => { + if (!configForm.value || !candidateParam) { + return; + } + switch (candidateStrategy) { + case CandidateStrategy.DEPT_LEADER: + case CandidateStrategy.DEPT_MEMBER: { + configForm.value.deptIds = candidateParam + .split(',') + .map((item) => +item); + break; + } + case CandidateStrategy.EXPRESSION: { + configForm.value.expression = candidateParam; + break; + } + // 表单内的部门负责人 + case CandidateStrategy.FORM_DEPT_LEADER: { + // 候选人参数格式: | 分隔 。左边为表单内的部门字段。 右边为部门层级 + const paramArray = candidateParam.split('|'); + if (paramArray.length > 1) { + configForm.value.formDept = paramArray[0]; + if (paramArray[1]) configForm.value.deptLevel = +paramArray[1]; + } + break; + } + case CandidateStrategy.FORM_USER: { + configForm.value.formUser = candidateParam; + break; + } + // 指定连续多级部门的负责人 + case CandidateStrategy.MULTI_LEVEL_DEPT_LEADER: { + // 候选人参数格式: | 分隔 。左边为部门(多个部门用 , 分隔)。 右边为部门层级 + const paramArray = candidateParam.split('|') as string[]; + if (paramArray.length > 1) { + configForm.value.deptIds = paramArray[0] + ?.split(',') + .map((item) => +item); + if (paramArray[1]) configForm.value.deptLevel = +paramArray[1]; + } + break; + } + case CandidateStrategy.POST: { + configForm.value.postIds = candidateParam + .split(',') + .map((item) => +item); + break; + } + case CandidateStrategy.ROLE: { + configForm.value.roleIds = candidateParam + .split(',') + .map((item) => +item); + break; + } + // 发起人部门负责人 + case CandidateStrategy.START_USER_DEPT_LEADER: + case CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER: { + configForm.value.deptLevel = +candidateParam; + break; + } + case CandidateStrategy.USER: { + configForm.value.userIds = candidateParam + .split(',') + .map((item) => +item); + break; + } + case CandidateStrategy.USER_GROUP: { + configForm.value.userGroups = candidateParam + .split(',') + .map((item) => +item); + break; + } + default: { + break; + } + } + }; + return { + configForm, + roleOptions, + postOptions, + userOptions, + userGroupOptions, + deptTreeOptions, + handleCandidateParam, + parseCandidateParam, + getShowText, + }; +} + +/** + * @description 抽屉配置 + */ +export function useDrawer() { + // 抽屉配置是否可见 + const settingVisible = ref(false); + // 关闭配置抽屉 + const closeDrawer = () => { + settingVisible.value = false; + }; + // 打开配置抽屉 + const openDrawer = () => { + settingVisible.value = true; + }; + return { + settingVisible, + closeDrawer, + openDrawer, + }; +} + +/** + * @description 节点名称配置 + */ +export function useNodeName(nodeType: NodeType) { + // 节点名称 + const nodeName = ref(); + // 节点名称输入框 + const showInput = ref(false); + // 点击节点名称编辑图标 + const clickIcon = () => { + showInput.value = true; + }; + // 节点名称输入框失去焦点 + const blurEvent = () => { + showInput.value = false; + nodeName.value = + nodeName.value || (NODE_DEFAULT_NAME.get(nodeType) as string); + }; + return { + nodeName, + showInput, + clickIcon, + blurEvent, + }; +} + +export function useNodeName2(node: Ref, nodeType: NodeType) { + // 显示节点名称输入框 + const showInput = ref(false); + // 节点名称输入框失去焦点 + const blurEvent = () => { + showInput.value = false; + node.value.name = + node.value.name || (NODE_DEFAULT_NAME.get(nodeType) as string); + }; + // 点击节点标题进行输入 + const clickTitle = () => { + showInput.value = true; + }; + return { + showInput, + clickTitle, + blurEvent, + }; +} + +/** + * @description 根据节点任务状态,获取节点任务状态样式 + */ +export function useTaskStatusClass( + taskStatus: TaskStatusEnum | undefined, +): string { + if (!taskStatus) { + return ''; + } + if (taskStatus === TaskStatusEnum.APPROVE) { + return 'status-pass'; + } + if (taskStatus === TaskStatusEnum.RUNNING) { + return 'status-running'; + } + if (taskStatus === TaskStatusEnum.REJECT) { + return 'status-reject'; + } + if (taskStatus === TaskStatusEnum.CANCEL) { + return 'status-cancel'; + } + return ''; +} + +/** 条件组件文字展示 */ +export function getConditionShowText( + conditionType: ConditionType | undefined, + conditionExpression: string | undefined, + conditionGroups: ConditionGroup | undefined, + fieldOptions: Array>, +) { + let showText: string | undefined; + if (conditionType === ConditionType.EXPRESSION && conditionExpression) { + showText = `表达式:${conditionExpression}`; + } + if (conditionType === ConditionType.RULE) { + // 条件组是否为与关系 + const groupAnd = conditionGroups?.and; + let warningMessage: string | undefined; + const conditionGroup = conditionGroups?.conditions.map((item) => { + return `(${item.rules + .map((rule) => { + if (rule.leftSide && rule.rightSide) { + return `${getFormFieldTitle( + fieldOptions, + rule.leftSide, + )} ${getOpName(rule.opCode)} ${rule.rightSide}`; + } else { + // 有一条规则不完善。提示错误 + warningMessage = '请完善条件规则'; + return ''; + } + }) + .join(item.and ? ' 且 ' : ' 或 ')} ) `; + }); + showText = warningMessage + ? '' + : conditionGroup?.join(groupAnd ? ' 且 ' : ' 或 '); + } + return showText; +} + +/** 获取表单字段名称*/ +const getFormFieldTitle = ( + fieldOptions: Array>, + field: string, +) => { + const item = fieldOptions.find((item) => item.field === field); + return item?.title; +}; + +/** 获取操作符名称 */ +const getOpName = (opCode: string): string | undefined => { + const opName = COMPARISON_OPERATORS.find( + (item: any) => item.value === opCode, + ); + return opName?.label; +}; diff --git a/apps/web-antd/src/components/simple-process-design/index.ts b/apps/web-antd/src/components/simple-process-design/index.ts new file mode 100644 index 000000000..05fee448b --- /dev/null +++ b/apps/web-antd/src/components/simple-process-design/index.ts @@ -0,0 +1,3 @@ +import './styles/simple-process-designer.scss'; + +export { default as SimpleProcessDesigner } from './components/simple-process-designer.vue'; diff --git a/apps/web-antd/src/components/simple-process-design/styles/iconfont.ttf b/apps/web-antd/src/components/simple-process-design/styles/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..06f4e31c4b4ce9868cd39b25f6beb1fd5884ff9c GIT binary patch literal 4808 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 literal 0 HcmV?d00001 diff --git a/apps/web-antd/src/components/simple-process-design/styles/iconfont.woff b/apps/web-antd/src/components/simple-process-design/styles/iconfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..0724e75054dc761f7cec794944cc140f3056bebf GIT binary patch literal 3176 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 \ No newline at end of file diff --git a/apps/web-antd/src/views/bpm/model/form/index.vue b/apps/web-antd/src/views/bpm/model/form/index.vue index 6d86eeb0e..c7483a2a5 100644 --- a/apps/web-antd/src/views/bpm/model/form/index.vue +++ b/apps/web-antd/src/views/bpm/model/form/index.vue @@ -29,6 +29,7 @@ import { getSimpleUserList } from '#/api/system/user'; import BasicInfo from './modules/basic-info.vue'; import FormDesign from './modules/form-design.vue'; +import ProcessDesign from './modules/process-design.vue'; defineOptions({ name: 'BpmModelCreate' }); @@ -68,6 +69,8 @@ const userStore = useUserStore(); const basicInfoRef = ref>(); // 表单设计组件引用 const formDesignRef = ref>(); +// 流程设计组件引用 +const processDesignRef = ref>(); /** 步骤校验函数 */ const validateBasic = async () => { @@ -81,7 +84,7 @@ const validateForm = async () => { /** 流程设计校验 */ const validateProcess = async () => { - // TODO + await processDesignRef.value?.validate(); }; const currentStep = ref(-1); // 步骤控制。-1 用于,一开始全部不展示等当前页面数据初始化完成 @@ -101,7 +104,7 @@ const formData: any = ref({ category: undefined, icon: undefined, description: '', - type: BpmModelType.BPMN, + type: BpmModelType.SIMPLE, formType: BpmModelFormType.NORMAL, formId: '', formCustomCreatePath: '', @@ -189,7 +192,7 @@ const initData = async () => { } else { // 情况三:新增场景 formData.value.startUserType = 0; // 全体 - formData.value.managerUserIds.push(userStore.userInfo?.userId); + formData.value.managerUserIds.push(userStore.userInfo?.id); } // 获取表单列表 @@ -351,6 +354,7 @@ const handleDeploy = async () => { /** 步骤切换处理 */ const handleStepClick = async (index: number) => { try { + console.warn('handleStepClick', index); if (index !== 0) { await validateBasic(); } @@ -400,7 +404,7 @@ onBeforeUnmount(() => { // 清理所有的引用 basicInfoRef.value = undefined; formDesignRef.value = undefined; - // processDesignRef.value = null; + processDesignRef.value = undefined; }); @@ -485,7 +489,7 @@ onBeforeUnmount(() => { /> -
+
{ />
- + + -
+
diff --git a/apps/web-antd/src/views/bpm/model/form/modules/basic-info.vue b/apps/web-antd/src/views/bpm/model/form/modules/basic-info.vue index 2e246141e..f31ad4d7c 100644 --- a/apps/web-antd/src/views/bpm/model/form/modules/basic-info.vue +++ b/apps/web-antd/src/views/bpm/model/form/modules/basic-info.vue @@ -65,7 +65,6 @@ const rules: Record = { category: [{ required: true, message: '流程分类不能为空', trigger: 'blur' }], type: [{ required: true, message: '流程类型不能为空', trigger: 'blur' }], visible: [{ required: true, message: '是否可见不能为空', trigger: 'blur' }], - // TODO 这个的校验好像没有起作用 managerUserIds: [ { required: true, message: '流程管理员不能为空', trigger: 'blur' }, ], @@ -282,10 +281,12 @@ defineExpose({ validate }); + {{ dict.label }} diff --git a/apps/web-antd/src/views/bpm/model/form/modules/process-design.vue b/apps/web-antd/src/views/bpm/model/form/modules/process-design.vue new file mode 100644 index 000000000..10f99f8d0 --- /dev/null +++ b/apps/web-antd/src/views/bpm/model/form/modules/process-design.vue @@ -0,0 +1,67 @@ + + diff --git a/apps/web-antd/src/views/bpm/model/form/modules/simple-model-design.vue b/apps/web-antd/src/views/bpm/model/form/modules/simple-model-design.vue new file mode 100644 index 000000000..fb606c048 --- /dev/null +++ b/apps/web-antd/src/views/bpm/model/form/modules/simple-model-design.vue @@ -0,0 +1,40 @@ + + + diff --git a/apps/web-antd/src/views/bpm/model/modules/category-draggable-model.vue b/apps/web-antd/src/views/bpm/model/modules/category-draggable-model.vue index 7b005fcf6..2583fc867 100644 --- a/apps/web-antd/src/views/bpm/model/modules/category-draggable-model.vue +++ b/apps/web-antd/src/views/bpm/model/modules/category-draggable-model.vue @@ -54,35 +54,39 @@ const columns = [ dataIndex: 'name', key: 'name', align: 'left' as const, - minWidth: 250, + ellipsis: true, + width: 250, }, { title: '可见范围', dataIndex: 'startUserIds', key: 'startUserIds', align: 'center' as const, - minWidth: 150, + ellipsis: true, + width: 150, }, { title: '流程类型', dataIndex: 'type', key: 'type', align: 'center' as const, - minWidth: 120, + ellipsis: true, + width: 120, }, { title: '表单信息', dataIndex: 'formType', key: 'formType', align: 'center' as const, - minWidth: 150, + ellipsis: true, + width: 150, }, { title: '最后发布', dataIndex: 'deploymentTime', key: 'deploymentTime', align: 'center' as const, - minWidth: 250, + width: 250, }, { title: '操作', @@ -316,6 +320,7 @@ const handleRenameSuccess = () => { :columns="columns" :pagination="false" :custom-row="customRow" + :scroll="{ x: '100%' }" row-key="id" >