Files
pigx/docs/design/workflow-dynamic-add-sign.md
T

230 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 工作流动态加签设计
> 状态:已实现(2026-07-16)
## 目标
为运行中的并行会签节点动态追加一名或多名独立审批人。新增审批人与原审批人并行处理,并进入同一会签完成条件。
首版不实现前加签、后加签、撤销加签或减签;现有 `delegateTask` 继续表示委托,不复用为加签。
## 业务规则
1. 仅配置为并行会签且开启“允许审批人加签”的节点可用。
2. 只有仍持有未完成待办的原始审批人可以发起;加签审批人、转办接手人、已完成审批人、流程发起人和普通管理员均不可以发起。
3. 加签不完成或暂停发起人的待办;所有待办继续并行处理。
4. 同一轮节点执行中,每个用户最多参与一次。已有原始审批人、已有加签审批人及曾经接手过该轮任务的用户均不可再次加入。
5. 一次可以选择多人,整批校验、整批成功或整批失败。
6. 原始审批人在自己的待办完成前可以多次加签。
7. 加签原因必填,长度为 2~100 字。
8. 加签审批人可以转办,但不能继续加签;转办不改变会签实例总数。
9. 任意新增审批人拒绝时,继续执行当前会签的拒绝规则;全部参与人同意后节点才通过。
10. 加签与节点完成竞争时,以先提交成功的事务为准,不重新打开已完成节点。
## 配置模型
在 `Node` 增加:
```java
private Boolean allowAddSign;
```
- 设计器仅在多人审批模式为会签时显示开关。
- 新节点默认 `false`;字段为空时后端也按 `false` 处理。
- 开关直接保存在现有 `process_node_data.data` JSON 中。
- 为保持实现简单,不提供发布版本隔离;修改节点配置可能影响正在运行的实例。
## 接口设计
### 查询任务详情
扩展现有 `GET /task/task/queryTask` 响应:
```json
{
"canAddSign": true,
"participantUserIds": [1, 2, 3]
}
```
`canAddSign` 必须由后端根据当前登录人、活动任务、原始分配关系、节点模式和开关综合计算,前端不能自行推导权限。
### 发起加签
新增 `POST /task/task/addSign`:
```json
{
"taskId": "12501",
"targetUserIdList": [31, 32],
"reason": "需要法务和财务共同确认"
}
```
客户端不提交操作人、流程实例或节点 ID;这些值由后端根据登录人和 `taskId` 获取,避免越权和参数篡改。
成功返回本次加签记录 ID 和新增任务摘要;业务校验失败时整批不产生任务。
## 后端处理流程
```mermaid
flowchart TD
A["接收 taskId、目标用户、原因"] --> B["查询当前登录人的活动任务"]
B --> C["锁定当前 ProcessNodeRecord"]
C --> D["校验原始审批人、会签模式和允许加签开关"]
D --> E["批量校验租户用户、输入重复和节点参与历史"]
E --> F["创建一条批次加签审计记录"]
F --> G["逐人调用 addMultiInstanceExecution"]
G --> H["任务监听器写入执行人记录"]
H --> I["保存变更后参与人快照并提交事务"]
```
核心调用使用 Flowable 8 的:
```java
runtimeService.addMultiInstanceExecution(nodeId, parentExecutionId, executionVariables);
```
处理要点:
- 通过当前任务 `executionId` 找到并行多实例父执行实例。
- `executionVariables` 写入模型已有的 `${nodeId}_assignee_temp` 执行人变量。
- 同时写入 `assignmentOrigin=ADD_SIGN`、`initialUserId`、`addSignRecordId` 和 `addedByUserId` 等局部元数据。
- Flowable 负责增加 `nrOfInstances`、创建任务和计算节点完成状态。
- 不手工修改 Flowable 运行表,不在业务表中另造可完成的审批任务。
## 数据记录
### 执行人记录扩展
在 `process_node_record_assign_user` 增加:
- `node_record_id`:本轮节点执行记录 ID,用于区分退回后再次进入同一节点。
- `assignment_origin`:`ORIGINAL` 或 `ADD_SIGN`。
- `initial_user_id`:本份待办最初分配的用户;转办后保持不变。
- `add_sign_record_id`:加签产生的任务关联到对应批次记录,原始任务为空。
为新记录建立 `(tenant_id, node_record_id, user_id)` 唯一约束,配合节点行锁保证同一轮节点内人员唯一。历史兼容和数据回填不在本次范围内。
权限判断同时要求:
- `assignment_origin = ORIGINAL`;
- 当前登录人等于 `initial_user_id`;
- 当前登录人仍是任务现任 `assignee`;
- 任务和节点都处于活动状态。
因此原始任务转办给其他用户后,接手人不能发起加签。
### 加签审计记录
新增 `process_task_add_sign_record`,一批操作一条记录,保存:
- 租户、流程、流程实例、本轮节点记录、节点和来源任务;
- 发起人、加签原因、操作时间;
- 本次目标用户快照;
- 操作前和操作后的参与人快照。
只记录事务成功的加签;失败请求记录应用日志,不生成半成品审计数据。
## 并发与事务
- `addSign` 与会签任务 `completeTask` 在操作同一节点前,锁定相同的活动 `process_node_record` 行。
- 所有目标用户先完成校验,再创建任何多实例执行。
- 批次记录、Flowable 多实例、任务监听记录处于同一事务;任一步失败全部回滚。
- 两个审批人同时加签同一用户时,一个成功,另一个在获得锁后因重复参与失败。
- 节点先完成时返回“当前审批节点已结束,无法加签”;不做节点重开或补偿任务。
- Flowable 乐观锁异常转换为明确的并发操作提示,不向前端暴露引擎异常文本。
## 转办约束
现有转办接口应收紧为单目标用户,并增加当前节点参与人校验:
- 转办目标不得在本轮节点参与历史中出现。
- 转办沿用原任务的 `assignment_origin`、`initial_user_id` 和 `add_sign_record_id`。
- 加签任务转办后仍是加签任务;原始任务转办后,接手人不获得加签权限。
## 前端设计
### 流程设计器
在审批人抽屉的“多人审批方式”下增加“允许审批人加签”开关。切换到或签、依次审批或单人审批时隐藏并重置为 `false`。
### 桌面待办
- 在“提交、拒绝、转办”操作区增加“加签”。
- 仅当后端返回 `canAddSign=true` 时显示。
- 弹窗复用组织选择器,支持多选,过滤 `participantUserIds`。
- 原因输入 2~100 字;提交期间禁用重复点击。
- 成功后关闭弹窗、刷新任务详情与流程进度。
### 移动端待办
移动端使用相同接口和规则,增加“加签”入口及适配小屏的底部弹层;成功后刷新当前任务,不改变原待办的可审批状态。
## 审批记录展示
在流程进度时间线中增加独立事件:
> 张三加签李四、王五:需要法务和财务共同确认
新增审批人的任务处理记录继续按普通会签任务展示,并标注“加签”。转办时继续展示完整的处理人变化轨迹。
## 错误提示
- 当前节点未开启加签
- 仅并行会签节点支持加签
- 当前任务已完成或已转办
- 只有未完成审批的原始审批人可以加签
- 请选择加签人员
- 加签原因需为 2~100 字
- 用户已参与当前会签:{姓名}
- 当前审批节点已结束,无法加签
- 节点状态已变化,请刷新后重试
## 验收矩阵
### 后端
1. A、B 会签,A 加签 C 后产生三份并行待办,A 的原待办保持活动。
2. A、B、C 全部同意后节点通过;C 拒绝时执行当前拒绝策略。
3. A 一次加签 C、D,任一目标不合法时 C、D 都不产生任务。
4. A 可以在完成前多次加签,完成后再次请求被拒绝。
5. C 不能继续加签;C 可转办给未参与的 D,实例总数不变。
6. 原始任务 A 转办给 D 后,D 不能加签。
7. 重复用户、跨租户用户、无效用户、空原因和超长原因均被拒绝。
8. 或签、依次审批、单人审批及未开启开关的节点均被拒绝。
9. 并发加签同一用户只允许一个请求成功。
10. 加签与最后审批并发时符合先提交者生效规则,不出现孤儿任务或节点重开。
11. 审计记录、执行人记录与 Flowable 活动任务一致。
### 前端
1. 设计器开关仅在会签配置下可见并正确保存。
2. 桌面端和移动端均按 `canAddSign` 控制入口。
3. 已参与人员不可选择,批量选择和原因校验一致。
4. 加签成功后流程进度、待办列表和审批记录即时刷新。
5. 后端拒绝并发或越权请求时,页面保留输入并显示明确原因。
## 主要改动位置
后端集中在:
- `pigx-flow-api/.../dto/Node.java`
- `pigx-flow-api/.../entity/ProcessNodeRecordAssignUser.java`
- `pigx-flow-biz/.../controller/ProcessTaskController.java`
- `pigx-flow-biz/.../service/ITaskService.java`
- `pigx-flow-biz/.../service/impl/TaskServiceImpl.java`
- `pigx-flow-biz/.../service/impl/FlowableEngineServiceImpl.java`
- `pigx-flow-biz/.../support/listeners/FlowProcessEventListener.java`
- `db/3pigxx_flow.sql` 与 `db/0pigxx_boot.sql`
- `db/upgrade/20260716_dynamic_add_sign.sql`(存量数据库升级)
前端集中在:
- `src/views/flow/workflow/components/drawer/approverDrawer.vue`
- `src/views/flow/workflow/components/addNode.vue`
- `src/api/flow/task/index.ts`
- `src/views/flow/task/pending.vue`
- `src/views/flow/task/handler/`
- `src/views/flow/mobile/task.vue`