--- title: 流程配置 description: 流程定义、版本草稿、发布校验与模块绑定 pageClass: g3-api --- # 流程配置 配置侧接口,前缀 `/workflow/**`。 **读取走通用接口**(列表用 `v_wf_definition` / `v_wf_version` / `v_wf_binding` 视图,设计器读回草稿用 `/data/loaddata` 查 `wf_*` 表);**写入一律走这里**——发布校验、版本快照、「已发布不可改」这些约束必须在后端一个事务内完成,通用保存接口不参与。 > 运行侧(送审、审批动作、待办、抄送)见[流程运行](/api/workflow-runtime)。 ## 流程定义 ### `POST` `/workflow/definition/save` 新建或修改流程定义。**新建时同时落一条空草稿的 v1 版本**,保证设计器一进去就有可保存的目标。 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `definitionId` | string | 是 | 流程编码。新建时校验:**字母开头**,仅字母/数字/下划线,≤ 50 字符 | | `name` | string | 是 | 流程名称 | | `i18n` | string | | 多语言资源键 | | `bz` | string | | 备注 | | `canuse` | bool | | 是否启用,默认 `true` | ```json { "definitionId": "expense_approval", "name": "费用报销审批", "i18n": "workflow.expense_approval", "canuse": true } ``` ```json { "code": 0, "message": "保存成功", "data": { "definitionId": "expense_approval", "versionId": "expense_approval_v1", "created": true } } ``` - `created` 为 `true` 表示**新建**(同时建了 v1 草稿);`false` 表示改的是已存在的定义。 - 修改已存在的定义时,`versionId` 返回该定义**当前最新的草稿版本**(没有草稿则为 `null`)。 ### `POST` `/workflow/definition/delete` 删除流程定义,连同它的版本、节点、连线、审批人规则与绑定**一起删**。 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `definitionId` | string | 是 | 流程编码 | ```json { "code": 0, "message": "删除成功", "data": { "versions": 2, "bindings": 1 } } ``` > **有未结束实例时会拒绝删除**:`1000`「该流程还有 N 个未结束的实例,不能删除」。 > 运行历史必须能追溯到版本,不能留下悬空引用。未结束指状态为 `running` / `returned` / `error`。 ## 版本与草稿 ### `POST` `/workflow/version/draft/save` 保存草稿:**全量替换**该版本的节点 / 连线 / 审批人规则(幂等)。 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `definitionId` | string | 是 | 流程编码 | | `versionId` | string | | 目标版本;**留空则取该定义的草稿,没有就新建** | | `draft` | object | 是 | 草稿内容 `{ nodes, edges }`,见下 | | `canvas` | object | | 画布布局(只存不参与执行) | `draft` 的结构与前端设计器的领域模型一致: ```json { "nodes": [ { "nodeKey": "start", "nodeType": "start", "name": "开始", "config": {}, "actorRules": [] }, { "nodeKey": "dept_manager", "nodeType": "user_task", "name": "部门负责人审批", "config": { "approvalMode": "any", "rejectMode": "return_initiator", "dueHours": 24, "allowClaim": true, "allowInitiator": false, "excludePreviousActors": true }, "actorRules": [ { "actorType": "dept_manager", "fallbackType": "admin" } ] } ], "edges": [ { "edgeKey": "e1", "from": "start", "to": "dept_manager" } ] } ``` **字段说明**: | 位置 | 字段 | 说明 | |---|---|---| | node | `nodeKey` | 版本内稳定编码,≤ 50 字符,**不可跨版本改**(运行时连线状态按它映射) | | node | `nodeType` | `start` / `end` / `user_task` / `cc_task` / `service_task` / `exclusive_gateway` / `parallel_gateway` | | node | `config.approvalMode` | `single` / `any` / `all` / `serial` / `n_of_m` / `percentage`。**留空按 `single` 处理**;无法识别的取值也按 1 票通过 | | node | `config.rejectMode` | `terminate` / `return_initiator` / `return_previous` | | node | `config.dueHours` | 审批时限(小时);**不配则任务没有应处理时间,永不超时** | | node | `config.requiredCount` / `requiredRatio` | 配合 `n_of_m` / `percentage` 用 | | node | `config.allowInitiator` | **显式 `false`** 才排除发起人(缺省允许) | | node | `config.excludeCreator` | 排除创建人(当前以发起人近似) | | node | `config.excludePreviousActors` | 排除此前节点出现过的人 | | node | `config.allowClaim` | 是否允许抢占待办 | | edge | `condition` | 条件 AST;**留空 = 无条件(默认边)** | | rule | `actorType` | `user` / `initiator` / `field_user` / `dept_manager` / `initiator_manager` / `position` / `org_role` | | rule | `fallbackType` | 解析为空时的兜底:`admin` / `initiator` | > **`condition` 必须是对象或留空**。给了值却不是对象会直接报错——把脏条件静默当成「无条件边」会让流程走错分支,所以发布期就拒绝。 > **`actorRules` 的数组顺序就是串行会签的先后顺序**。 ```json { "code": 0, "message": "草稿已保存", "data": { "versionId": "expense_approval_v1", "versionNo": 1, "issues": [], "edgeKeyMap": {} } } ``` - `issues` 是**保存时顺带做的校验提示**(不阻断保存)。 - `edgeKeyMap` 只在连线编码因与其它版本冲突而被换新 ID 时出现,前端据此把本地 `edgeKey` 对齐到库里。 > 已发布版本**一律拒绝**保存草稿(`1000`)——改流程要复制新版本。 ### `POST` `/workflow/version/validate` 校验草稿。传 `draft` 校验内存草稿(设计器边改边校验),传 `versionId` 读库校验。 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `draft` | object | 二选一 | 内存草稿 | | `versionId` | string | 二选一 | 读库校验的版本 | ```json { "code": 0, "message": "操作成功", "data": { "issues": [ { "level": "error", "message": "节点「部门负责人审批」没有配置审批人规则" }, { "level": "warn", "message": "节点「财务复核」没有配置审批时限" } ], "errorCount": 1, "warnCount": 1 } } ``` ### `POST` `/workflow/version/publish` 发布版本:校验必须**零 error**,然后计算配置摘要并锁定节点与连线。 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `versionId` | string | 是 | 要发布的草稿版本 | ```json { "code": 0, "message": "发布成功", "data": { "published": true, "checksum": "3f2a...", "definitionId": "expense_approval", "issues": [] } } ``` ```json { "code": 0, "message": "发布校验未通过", "data": { "published": false, "issues": [ { "level": "error", "message": "流程缺少结束节点" } ] } } ``` > **校验不通过不是错误**:HTTP 与 `code` 都是成功,要靠 `data.published` 判断。 > 这样调用方能**一次看到全部问题**,而不是改一个报一个。 ### `POST` `/workflow/version/retire` 停用版本:`published` → `retired`,不再接受新实例;**已有实例继续用原版本跑完**。 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `versionId` | string | 是 | 要停用的已发布版本 | ### `POST` `/workflow/version/copy` 以某个版本为模板复制出一条**新草稿**(版本号 = 当前最大值 + 1)。 | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `versionId` | string | 是 | 源版本(可以是已发布版本) | ```json { "code": 0, "message": "已复制为新草稿", "data": { "versionId": "expense_approval_v3", "versionNo": 3 } } ``` > **同一定义同时只允许一条草稿**。已有草稿时会报 `1000`「该流程已有草稿版本「x」,请先发布或删除它」——避免「改的是哪一条」说不清。 ## 流程绑定 绑定决定「哪个模块的哪个业务事件走哪个流程版本」。 ### `POST` `/workflow/binding/save` | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `moduleId` | string | 是 | 模块编码 | | `event` | string | 是 | 业务事件:`submit` / `resubmit` / `change` | | `versionId` | string | 是 | 目标版本,**必须是已发布版本** | | `bindingId` | string | | 留空=新建,传值=修改 | | `match` | object | | 匹配条件(条件 AST),决定业务上下文是否走这个流程 | | `orgScope` | object | | 组织范围 | | `statusField` | string | | 业务表上的**状态列名**(状态投影写这一列) | | `statusMap` | object | | 流程状态 → 业务状态值的映射 | | `priority` | int | | 优先级,默认 0,**小的先匹配** | | `effectiveFrom` / `effectiveTo` | string | | 生效区间 | | `canuse` | bool | | 是否启用,默认 `true` | | `bz` | string | | 备注 | ```json { "moduleId": "v_b_othercompany", "event": "submit", "versionId": "expense_approval_v1", "match": { "field": "b_amount", "operator": "gt", "value": 0 }, "statusField": "b_status", "statusMap": { "approved": 2, "rejected": 3, "returned": 4 }, "priority": 10, "canuse": true } ``` ```json { "code": 0, "message": "保存成功", "data": { "bindingId": "1234567890123", "created": true } } ``` **几条硬规则**: - **绑定只能指向已发布版本**(`1000`,提示当前版本状态)。 - **同一模块 + 同一事件下,不能有两条同优先级的启用绑定**(`1000`)——否则无法确定用哪个流程。冲突时调整 `priority` 或停用其中一条。 - **保存绑定会顺带备好该模块的动作权限点**:否则管理员在用户权限页看不到可授权的权限点,非管理员送审会被白名单拒绝。这一步是幂等的,不会覆盖管理员改过的名称。 > `match` 留空表示**该模块该事件一律走这个流程**。`statusMap` 决定审批结果如何写回业务表状态列;不配 `statusField` 则跳过状态投影(只读模块的正常情况)。 ### `POST` `/workflow/binding/delete` | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `bindingId` | string | 是 | 绑定 ID | ## 常见错误 | 场景 | 表现 | |---|---| | 流程编码非法 | `1000`「流程编码只能以字母开头,由字母、数字、下划线组成,且不超过 50 个字符」 | | 版本不存在 | `1000`「版本「x」不存在」 | | 非草稿版本发布 | `1000`「只有草稿版本可以发布,当前版本状态:published」 | | 非已发布版本停用 | `1000`「只有已发布版本可以停用,当前版本状态:draft」 | | 绑定指向非已发布版本 | `1000`「绑定只能指向已发布版本,当前版本状态:draft」 | | 同优先级启用绑定冲突 | `1000`「同一模块同一事件下已存在同优先级的启用绑定「x」」 | | 删除有未结束实例的定义 | `1000`「该流程还有 N 个未结束的实例,不能删除」 | | 连线/审批人规则条件不是对象 | `1000`,指明是「审批人规则」还是「连线「x」」的条件 |