diff --git a/src/views/flow/admin/def-editor/components/ApprovalDrawer.vue b/src/views/flow/admin/def-editor/components/ApprovalDrawer.vue index 56034da..fa3d691 100644 --- a/src/views/flow/admin/def-editor/components/ApprovalDrawer.vue +++ b/src/views/flow/admin/def-editor/components/ApprovalDrawer.vue @@ -29,6 +29,11 @@ const form = reactive({ countersign: "ANY" as "ALL" | "ANY", deadlineHours: null as number | null, multiOutlet: false, + assignEnabled: false, + assignMode: "MULTI" as "SINGLE" | "MULTI", + assignMin: 1, + assignMax: null as number | null, + assignRequired: false, }); const userCheckModal = ref(); @@ -49,6 +54,11 @@ function syncFromNode(): void { form.countersign = n.countersign; form.deadlineHours = n.deadlineHours; form.multiOutlet = !!(n.outlets && n.outlets.length >= 2); + form.assignEnabled = !!n.assignPolicy; + form.assignMode = n.assignPolicy?.mode === "SINGLE" ? "SINGLE" : "MULTI"; + form.assignMin = n.assignPolicy?.min ?? 1; + form.assignMax = n.assignPolicy?.max ?? null; + form.assignRequired = !!n.assignPolicy?.required; } watch( @@ -127,6 +137,13 @@ function onOk(): void { n.outlets = ["同意", "退回"]; n.branches = [[createApproval()], [createApproval()]]; } + n.assignPolicy = form.assignEnabled + ? { + mode: form.assignMode, + ...(form.assignMode === "MULTI" ? { min: form.assignMin || 1, max: form.assignMax ?? undefined } : {}), + required: form.assignRequired, + } + : undefined; emit("update:modelValue", false); } @@ -200,6 +217,32 @@ function onRemove(): void { +
+ +
+ + 允许发起人在提交时指定本节点审批人 +
+ +
开启后,发起人在子应用提交时可从本节点候选审批人中指定实际审核人;未指定则全体候选按上方方式审批。或签/会签语义不变,仅收窄人选
+
+
diff --git a/src/views/flow/admin/def-editor/convert.ts b/src/views/flow/admin/def-editor/convert.ts index 5871211..139343b 100644 --- a/src/views/flow/admin/def-editor/convert.ts +++ b/src/views/flow/admin/def-editor/convert.ts @@ -92,6 +92,7 @@ export function toContentJson(model: EditorModel): DefJson { }; if (item.countersign === "ANY") node.countersign = "ANY"; if (item.deadlineHours) node.deadlineHours = item.deadlineHours; + if (item.assignPolicy) node.assignPolicy = { ...item.assignPolicy }; nodes.push(node); linkTo(id); if (item.outlets && item.outlets.length >= 2 && item.branches) { @@ -487,6 +488,7 @@ function toApprovalNode(n: any): ApprovalNode { assignee: n.assignee ? cloneAssignee(n.assignee as Assignee) : null, countersign, deadlineHours: n.deadlineHours ? Number(n.deadlineHours) : null, + assignPolicy: n.assignPolicy ? { ...n.assignPolicy } : undefined, }; } diff --git a/src/views/flow/admin/def-editor/model.ts b/src/views/flow/admin/def-editor/model.ts index 8646fce..7dff7a7 100644 --- a/src/views/flow/admin/def-editor/model.ts +++ b/src/views/flow/admin/def-editor/model.ts @@ -19,6 +19,14 @@ export interface AssigneeUsers { } export type Assignee = AssigneeDept | AssigneeUsers; +/** 发起时指派:mode SINGLE=恰 1 人|MULTI=min~max;required 仅子应用 UI 必选提示 */ +export interface AssignPolicy { + mode: "SINGLE" | "MULTI"; + min?: number | null; + max?: number | null; + required?: boolean; +} + export interface ApprovalNode { uid: string; kind: "approval"; @@ -28,6 +36,8 @@ export interface ApprovalNode { countersign: Countersign; /** 办理时限(小时):null=不限,生成 JSON 时省略 */ deadlineHours: number | null; + /** 发起时指派策略:存在即允许指派;生成 JSON 时关闭则不写字段(与 countersign 省略风格一致) */ + assignPolicy?: AssignPolicy | null; /** 多出口(≥2 才有多出口语义):出口按钮文案,办理人按下哪个按钮走哪条泳道;单出口不写字段 */ outlets?: string[]; /** 各出口泳道(与 outlets 一一对应);分支尾隐式汇合到后继节点(同条件分支,无 JOIN) */ @@ -117,6 +127,8 @@ export interface DefNodeJson { countersign?: Countersign; waitFor?: string; deadlineHours?: number; + /** 发起时指派策略(审批节点可选,2026-10-13;关闭态不写字段) */ + assignPolicy?: AssignPolicy; } export interface DefEdgeJson { @@ -324,6 +336,7 @@ export function assigneeText(a: Assignee | null, depts: DeptOption[], userNames: /** 卡片标签行(会签/或签 + 时限) */ export function nodeTags(n: ApprovalNode): string[] { const tags = [n.countersign === "ANY" ? "或签" : "会签"]; + if (n.assignPolicy) tags.push("可指派"); if (n.deadlineHours) tags.push(`${n.deadlineHours} 小时时限`); return tags; }