This commit is contained in:
oneao committed 2026-10-13 22:32:50 +08:00
1 parent f3936cec61
commit 15e0ae5b67
115 files changed
+11399 -2741

No files matched your search

@@ -0,0 +1,382 @@
---
title: 流程运行
description: 送审、审批动作、转派加签、审批中心与进度查询
pageClass: g3-api
---
# 流程运行
运行侧接口,前缀 `/workflow/runtime/**`。前端**只能提交意图**:改状态、建实例、推进节点、写待办全部在后端一个事务里完成;前端不允许直接改 `wf_instance` / `wf_task` / `wf_cc` 或业务表状态。
流程的**读取**走通用接口(待办/已办/进度这类有专门的运行侧查询接口,见下)。
> 前置:模块要先有**启用的流程绑定**(见[流程配置](/api/workflow)),否则送审会直接报「没有匹配到流程绑定」。
## 送审
### `POST` `/workflow/runtime/submit`
按模块 + 业务事件匹配绑定,建实例并激活首个节点。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `moduleId` | string | 是 | 模块编码 |
| `businessId` | string | 是 | 业务主键(**按字符串传**,不依赖业务表主键类型) |
| `businessNo` | string | | 业务单号,仅用于展示 |
| `event` | string | | 业务事件,默认 `submit`;可选 `submit` / `resubmit` / `change` |
| `context` | object | | 业务字段,参与条件分支与审批人解析(如金额、部门) |
| `idempotencyKey` | string | | 幂等键,重复提交返回同一实例 |
</G3ApiParams>
<G3ApiPayload title="请求体">
```json
{
"moduleId": "v_b_othercompany",
"businessId": "1234567890",
"businessNo": "HT-2026-001",
"event": "submit",
"context": { "b_amount": 3200, "b_dept_id": "D002" },
"idempotencyKey": "submit-1234567890-v1"
}
```
</G3ApiPayload>
<G3ApiPayload title="响应" :code="0">
```json
{
"code": 0,
"message": "已提交",
"data": {
"instanceId": "01a134fe-bde5-7058-a6b9-5f7e4f86b991",
"status": "running",
"currentSummary": { "summary": "待审批:部门负责人审批" },
"pendingTaskCount": 1,
"duplicated": false
}
}
```
</G3ApiPayload>
- `duplicated` 为 `true` 表示**这次请求被判为重复**(幂等键已存在),没有产生新副作用,`instanceId` 是既有实例。
- 送审时会把发起人、机构写进运行变量;审批人解析为空时实例直接进入 `error`,不会跳过节点。
## 审批动作
### `POST` `/workflow/runtime/task/action`
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `taskId` | string | 是 | 待办任务 ID |
| `action` | string | 是 | `approve` / `reject` / `return` |
| `comment` | string | | 审批意见 |
| `idempotencyKey` | string | | 幂等键,重复审批只生效一次 |
</G3ApiParams>
三个动作的差异:
| action | 节点内是否立即生效 | 结果 |
|---|---|---|
| `approve` | 否,凑够应签人数才完成节点 | 节点完成后继续路由;全部走完则实例 `approved` |
| `reject` | 是,第一票即生效 | 按节点配置的驳回策略走:终止 / 退回 / 退回上一节点 |
| `return` | 是 | 直接退回发起人,实例 `returned` |
<G3ApiPayload title="响应" :code="0">
```json
{
"code": 0,
"message": "处理成功",
"data": {
"instanceId": "01a134fe-bde5-7058-a6b9-5f7e4f86b991",
"status": "running",
"currentSummary": { "summary": "审批中:部门负责人审批" },
"pendingTaskCount": 0,
"duplicated": false
}
}
```
</G3ApiPayload>
> **注意 `status` 是实例状态**,不是本次动作的结果。同一节点还有其他人待签时,状态仍是 `running`。
### `POST` `/workflow/runtime/task/claim`
抢占待办。仅当节点配置了 `allowClaim` 且调用者**确实是该任务的候选审批人**时可用。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `taskId` | string | 是 | 待办任务 ID |
</G3ApiParams>
候选审批人取自任务生成时落下的**审批人快照**,不是当前任务表——所以组织架构后来变了也不会影响已产生任务的归属判定。不是候选人会被拒绝。
### `POST` `/workflow/runtime/task/transfer`
转交待办给他人。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `taskId` | string | 是 | 待办任务 ID |
| `toUserId` | string | 是 | 接收人(必须是存在且启用的用户) |
| `comment` | string | | 转交说明 |
</G3ApiParams>
原任务被取消,**新建一条任务**给接收人,并记录转交动作与通知事件。
### `POST` `/workflow/runtime/task/add-approver`
加签:给当前节点追加审批人。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `taskId` | string | 是 | 同节点任一任务,用于定位节点 |
| `userIds` | string[] | 是 | 追加的审批人 |
| `comment` | string | | 说明 |
</G3ApiParams>
已是该节点活动审批人的会被跳过;加签会自动顺延应签人数,不会让节点永远凑不满票。
### `POST` `/workflow/runtime/task/urge`
催办:**只发提醒,不改任务状态**(也不要求调用者是审批人,凭动作权限即可)。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `taskId` | string | 是 | 待办任务 ID |
| `comment` | string | | 催办说明 |
</G3ApiParams>
## 实例操作
### `POST` `/workflow/runtime/instance/withdraw`
撤回。发起人撤回运行中的实例。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `instanceId` | string | 是 | 流程实例 ID |
| `comment` | string | | 撤回原因 |
</G3ApiParams>
- 只能撤回**运行中**的实例;实例进入 `withdrawn`,全部未完成待办被取消。
- 发起人撤回自己发起的实例不需要额外权限;非发起人需要 `withdraw` 动作权限。
- 撤回后重新提交会产生**新实例**与新快照。
### `POST` `/workflow/runtime/instance/cancel`
取消(管理员)。需要 `workflow_admin` 动作权限。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `instanceId` | string | 是 | 流程实例 ID |
| `comment` | string | | 取消原因 |
</G3ApiParams>
实例进入 `cancelled`,其中明原因会写入实例摘要与取消动作。
## 审批中心
### `POST` `/workflow/runtime/todo/list`
我的待办:分配给我(含已抢占)且未处理完的任务。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `pageNo` | int | | 页码,默认 1 |
| `pageSize` | int | | 每页条数,默认 50,**上限 200** |
</G3ApiParams>
<G3ApiPayload title="响应" :code="0">
```json
{
"code": 0,
"message": "操作成功",
"data": {
"rows": [
{
"task_id": "01a134fe-...",
"node_key": "dept_manager",
"task_status": "pending",
"b_seq": 10,
"b_due_at": "2026-10-14T02:00:00Z",
"instance_id": "01a134ff-...",
"b_business_id": "1234567890",
"b_business_no": "HT-2026-001",
"instance_status": "running",
"initiator_name": "G3Soft",
"definition_name": "费用报销审批",
"node_name": "部门负责人审批"
}
],
"total": 1,
"pageNo": 1,
"pageSize": 50
}
}
```
</G3ApiPayload>
> **分页字段名是 `pageNo` / `pageSize`**,响应里也是这两个键(不是 `page` / `size`)。
> **排序**:按应处理时间升序,**没有时限的排在最后** —— 别拿第一行的 `b_due_at` 当作全表最小值。
### `POST` `/workflow/runtime/done/list`
我已处理:我实际处理过的任务(含通过、驳回、转交前的处理)。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `pageNo` / `pageSize` | int | | 分页,默认 1 / 50,`pageSize` 上限 200 |
</G3ApiParams>
### `POST` `/workflow/runtime/instance/mine`
我发起的流程实例。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `pageNo` / `pageSize` | int | | 分页,默认 1 / 50,`pageSize` 上限 200 |
</G3ApiParams>
### `POST` `/workflow/runtime/cc/list`
抄送我的。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `pageNo` / `pageSize` | int | | 分页,默认 1 / 50,`pageSize` 上限 200 |
</G3ApiParams>
### `POST` `/workflow/runtime/cc/read`
批量标记抄送已读。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `ccIds` | string[] | 是 | 抄送记录 ID **数组**(注意是复数) |
</G3ApiParams>
<G3ApiPayload title="请求体">
```json
{ "ccIds": ["01a134fe-bde5-7058-a6b9-5f7e4f86b991"] }
```
</G3ApiPayload>
只允许标记**属于当前用户**的抄送记录,且会记录已读时间。数组为空时报 `1000`「请选择要标记的抄送记录」。
## 进度与详情
### `POST` `/workflow/runtime/instance/graph`
实例图:节点与连线的状态 + 时间线,用于「查看审批进度」。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `instanceId` | string | 是 | 流程实例 ID |
</G3ApiParams>
返回内容包含:
| 项 | 说明 |
|---|---|
| 节点列表 | 每个节点的状态、应签/已签人数、审批人快照 |
| 连线状态 | 哪些连线走过 |
| 时间线 | 动作历史(`wf_action`),按发生时间排列 |
| `timing` | 节点耗时 `elapsedMs` 与进出时间 |
> **超时判定在前端做**:后端只返回节点已耗时与节点配置的 `b_due_hours`,**不判断是否超期、也不算剩余时间**。
> 另外,任务超时被标记为 `expired` 后,会从待办列表移除,但**实例仍保持 `running`**(超时只标记任务,不改流程)。
### `POST` `/workflow/runtime/instance/by-business`
按业务单据查审批状态:业务详情页的状态条用。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `moduleId` | string | 是 | 模块编码 |
| `businessId` | string | 是 | 业务主键 |
</G3ApiParams>
返回:最近一次实例、**当前用户在该单据上的待办**、以及该模块是否已配置绑定。
> 即使模块**没有**配置绑定也会正常返回(提示未接入审批),不会报错——业务详情页可以无脑调用。
### `POST` `/workflow/runtime/task/detail`
任务详情:任务 + 实例 + 节点配置(含表单策略)。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `taskId` | string | 是 | 待办任务 ID |
</G3ApiParams>
返回节点配置里的表单策略(哪些字段只读、哪些必填),审批页据此渲染表单。
## 常见错误
| 场景 | 表现 |
|---|---|
| 模块没有启用的绑定 | `1000`,`message` 形如「模块「x」的事件「submit」没有匹配到流程绑定」 |
| `event` 不合法 | `1000`,只接受 `submit` / `resubmit` / `change` |
| 任务已被他人处理 | `1000`,状态已不是 `pending` / `claimed` |
| 流程已结束 | `1000`,实例状态不是 `running` |
| 不是候选审批人却抢占 | `1000`,「你不是该任务的候选审批人,无法抢占」 |
| 缺少动作权限 | `1000`,「没有模块「x」的动作权限「y」,请联系管理员授权」 |
| 并发推进实例 | `1000`,「流程实例已被并发推进(版本不匹配),请刷新后重试」 |
| 重复请求(带幂等键) | **不是错误**:`code: 0` + `duplicated: true` |