Appearance
规范 02 · 流程定义配置项完整参考(属性字典)
流程定义 = LogicFlow JSON。同一份 JSON 在所有语言实现(Java/Go/Python/Node/PHP/Rust)中 必须产生一致的执行结果。
本文档是流程定义所有配置项的权威参考(事实来源:Java 参考实现的
ModelParser/NodeParser系列解析器,六语言行为对齐):
- "引擎"列:✅ = 引擎已实现(解析并影响行为);「前端」= 仅设计器/发起页使用,引擎忽略
- 未列出的
properties键 = 引擎不识别,原样存入节点扩展属性ext(任务变量可回显,不参与执行)- 前端设计器属性面板字段与本表的关系见 用户指南 11 · 流程设计器
1. JSON 结构总览
json5
{
// ── 顶层(引擎解析)──
"name": "leave", // 流程编码(唯一,deploy 版本管理键)
"displayName": "请假审批", // 流程显示名称
"type": "approval", // 流程类型
"expireTime": "2026-12-31", // 流程期望完成时间
"relTableName": "biz_leave",// 关联业务表名(bizData 回显)
"persistMode": "ARCHIVE", // 业务落表模式(persist)
"postInterceptors": ["..."],// 流程级后置拦截器
"preInterceptors": ["..."], // 流程级前置拦截器
"instanceUrl": "...", // 实例详情 URL(预留)
"instanceNoClass": "...", // 业务号生成类(预留)
// ── LogicFlow 图 ──
"nodes": [ /* 见 §3 */ ],
"edges": [ /* 见 §9 */ ]
}节点(LogicFlow 标准字段):
json5
{
"id": "apply", // 节点唯一编码 → 任务名 taskName(全流程唯一)
"type": "snaker:task", // 节点类型(接受带/不带前缀两种写法,见 §3)
"x": 250, "y": 200, // 画布坐标(设计器布局,引擎不参与执行)
"text": { "value": "发起申请" }, // 显示名称 displayName(引擎读取位置)
"properties": { /* 引擎扩展属性,见 §4~§8 */ }
}兼容:
type接受snaker:task与task两种写法(设计器导出带前缀,手动编写可省略)。
2. 顶层属性(流程级)
| 字段 | 类型 | 引擎 | 说明 |
|---|---|---|---|
name | string | ✅ | 流程编码(唯一)——deploy 版本管理键(同 name 从 0 递增);bizData 表名回落 |
displayName | string | ✅ | 流程显示名称 |
type | string | ✅ | 流程类型(listByType 分组键) |
expireTime | string | ✅ | 流程期望完成时间 |
relTableName | string | ✅ | 关联业务表名——bizData 回显定位表;缺省回落 name |
persistMode | string | ✅ | 业务落表模式:ARCHIVE(缺省,流程结束归档)/ SYNC(发起 INSERT → 节点 UPDATE → 定稿),见 指南 08 persist |
preInterceptors | string[] | ✅ | 流程级前置拦截器注册名(逗号分隔/数组) |
postInterceptors | string[] | ✅ | 流程级后置拦截器注册名——persist 的办理节点权限判定路径,必须配置 |
instanceUrl | string | 预留 | 实例详情 URL(前端用) |
instanceNoClass | string | 预留 | 业务号生成类(前端/集成方用) |
selectUserOnInitiate | int | 前端 | 发起时选择处理人(0/1) |
enableCcActors | int | 前端 | 发起页抄送开关(0/1) |
enableApplyReason | int | 前端 | 发起页申请理由开关(0/1) |
enableAttachment | int | 前端 | 发起页附件开关(0/1) |
enableFieldPerm | int | 前端 | 字段权限开关(0/1) |
3. 节点公共属性(全部节点通用)
| 字段 | 引擎 | 说明 |
|---|---|---|
id | ✅ | 节点唯一编码 → 任务名 taskName |
type | ✅ | 节点类型(8 种,见下) |
text.value | ✅ | 显示名称 displayName |
properties.name | ✅ | 唯一编码(钉钉模式设计器写入,与 id 对应) |
preInterceptors | ✅ | 节点前置拦截器注册名(逗号分隔多注册名) |
postInterceptors | ✅ | 节点后置拦截器注册名(persist 模型级执行后触发) |
x / y / layout | 布局 | 画布坐标/布局(引擎不参与执行) |
节点类型总览:
| type(兼容写法) | 说明 | 必填 properties |
|---|---|---|
snaker:start / start | 开始 | - |
snaker:end / end | 结束(全流程只能有一个) | - |
snaker:task / task | 任务节点 | assignee 或 assignmentHandler |
snaker:decision / decision | 条件分支 | 出边 expr |
snaker:fork / fork | 并行分支 | - |
snaker:join / join | 并行合并 | - |
snaker:custom / custom | 自定义节点 | clazz |
snaker:subprocess / subprocess | 子流程 | form |
发起申请节点约定(mldong 框架契约):start 后第一个任务节点必须是"发起申请"节点,
assignee = "applicant"(引擎解析为流程发起人)。引擎不自动执行该节点,由调用方 (startAndExecute)启动后自动完成,流程推进到真正的审批节点。
4. 任务节点 properties 完整字典(snaker:task)
| 字段 | 类型 | 引擎 | 说明 |
|---|---|---|---|
assignee | string | ✅ | 固定参与者:逗号分隔多人;applicant = 发起人;token 优先按流程变量 key 解析(见 参与者解析) |
assignmentHandler | string | ✅ | 动态参与者注册名(内置清单见 指南 07) |
form | string | ✅ | 表单标识 → formKey(发起页/办理页表单定位) |
taskType | int | ✅ | 0=主办 1=协办 |
performType | int/string | ✅ | 0=普通参与(多人任一完成即可)1=会签(每人独立任务);兼容字符串 '1'/'ALL'/'COUNTERSIGN' |
countersignType | string | ✅ | 会签模式:PARALLEL(并行,全部完成推进)/ SEQUENTIAL(串行,依次流转)/ RATIO(阈值完成,配合 countersignCompletionCondition) |
countersignCompletionCondition | string | ✅ | 会签完成条件表达式(如 #nrOfCompletedInstances>=2);特殊值 ONE_VOTE_VETO(忽略大小写)= 开启一票否决,见 §4.2 |
candidateUsers | string | ⚠️ | 候选人 userId 列表(逗号分隔)——不生成 actor,供 candidatePage 选人 |
candidateGroups | string | ⚠️ | 候选角色标识(逗号分隔) |
candidateHandler | string | ⚠️ | 动态候选人处理注册名 |
reminderTime | string | ✅ | 提醒时间(如 10:00) |
reminderRepeat | string | ✅ | 重复提醒间隔 |
expireTime | string | ✅ | 期望完成时间 |
autoExecute | string | ✅ | 自动执行配置 |
callback | string | ✅ | 回调处理注册名(任务完成回调) |
preInterceptors | string[] | ✅ | 前置拦截器 |
postInterceptors | string[] | ✅ | 后置拦截器(persist 写库/权限判定) |
field | object | ✅ | 字段权限声明(见 §4.1) |
| 其他任意键 | any | ext | 不识别 → 存入节点扩展属性 ext(任务变量回显,不参与执行) |
4.1 字段权限(field,SYNC persist 用)
- 声明位置:任务节点
properties.field - 键格式(双兼容):
PERMISSION_{表单字段全名}(含f_前缀,前端 vben5-wf 约定,优先) 与PERMISSION_{去前缀名}(旧格式) - 值:
1=只读 /2=可编辑 /3=隐藏(缺省=可编辑) - 办理入口过滤:按任务节点权限过滤后再入流程变量——上游只读不可被下游绕过
- 状态列:优先
{节点ID}_{状态码}列,无则{节点ID}列
4.2 会签(countersign)行为
| 模式 | 行为 | 推进条件 |
|---|---|---|
PARALLEL | 每个参与者一个独立任务 | 全部完成 |
SEQUENTIAL | 一次一个任务,完成后流转给下一个参与者 | 全部完成 |
RATIO | 每人一个任务 | 完成数满足 countersignCompletionCondition |
一票否决(ONE_VOTE_VETO) | countersignCompletionCondition 设为 ONE_VOTE_VETO(忽略大小写)时,任一成员 submitType=20 会签不同意 → 节点立即推进 | 否决者提交即合并 |
会签推进/否决后的残留处理:节点合并(merged)推进下一节点时,该节点仍 DOING 的会签任务一律废弃(taskState=99),不留孤儿待办——并行会签下其余成员的待办即被清空(对齐 mldong 内置引擎 abandonProcessTask 行为)。
会签拒绝(submitType=20)的默认语义 = 软拒绝:未配置 ONE_VOTE_VETO 时,否决者任务正常完成、countersignDisagreeFlag=1 记录为流程变量(供下游节点作参考),流程不阻断,按常规模式(全部完成 / 表达式)等待推进——会签意见默认只作参考、不阻断流程。
5. 决策节点 properties(snaker:decision)
| 字段 | 位置 | 引擎 | 说明 |
|---|---|---|---|
expr | 节点 | ✅ | 节点级默认表达式(可选) |
handleClass | 节点 | ✅ | 自定义决策器处理类注册名 |
expr | 出边 | ✅ | 分支条件表达式——决策出边必填(首条满足者胜) |
text.value | 出边 | ✅ | 分支标签(钉钉模式渲染在线上) |
决策路由规则:引擎按出边顺序求值,第一条 expr 为真的边获胜; 无 expr 的出边作为默认分支(兜底)。表达式语法见 指南 02 §5。
6. 自定义节点 properties(snaker:custom)
| 字段 | 引擎 | 说明 |
|---|---|---|
clazz | ✅ | 处理器类路径(必填) |
methodName | ✅ | 方法名 |
args | ✅ | 参数变量(逗号分隔的变量 key) |
val | ✅ | 返回值写入的变量 key |
7. 子流程节点 properties(snaker:subprocess)
| 字段 | 引擎 | 说明 |
|---|---|---|
form | ✅ | 子流程表单标识 |
version | ✅ | 子流程版本号 |
8. 开始 / 结束 / 并行节点
snaker:start/snaker:end:无专属属性(仅公共属性)snaker:fork/snaker:join:无专属属性——fork 出边建议写text.value分支标签
9. 边属性(edges)
json5
{
"id": "e1",
"sourceNodeId": "start", // 起点节点 id
"targetNodeId": "apply", // 终点节点 id
"properties": { "expr": "amount > 1000" }, // 决策分支条件
"text": { "value": "金额>1000" } // 分支标签(决策/fork 边建议必填)
}| 字段 | 引擎 | 说明 |
|---|---|---|
sourceNodeId / targetNodeId | ✅ | 起止节点 |
properties.expr | ✅ | 决策出边条件表达式 |
text.value | ✅ | 分支标签(钉钉模式渲染在线上,决策/fork 边建议必填) |
10. 完整示例(标准骨架)
json
{
"name": "leave",
"displayName": "请假审批",
"type": "approval",
"relTableName": "biz_leave",
"persistMode": "SYNC",
"nodes": [
{ "id": "start", "type": "snaker:start", "x": 100, "y": 200, "properties": {}, "text": { "value": "开始" } },
{ "id": "apply", "type": "snaker:task", "x": 250, "y": 200,
"properties": { "form": "apply-form", "assignee": "applicant", "taskType": 0, "performType": 0 },
"text": { "value": "发起申请" } },
{ "id": "leader", "type": "snaker:task", "x": 400, "y": 200,
"properties": { "form": "leave-form", "assignee": "leader", "taskType": 0, "performType": 0,
"postInterceptors": ["jeeflowPersistPostInterceptor"] },
"text": { "value": "组长审批" } },
{ "id": "decision1", "type": "snaker:decision", "x": 550, "y": 200, "properties": {}, "text": { "value": "金额判断" } },
{ "id": "end", "type": "snaker:end", "x": 700, "y": 200, "properties": {}, "text": { "value": "结束" } }
],
"edges": [
{ "id": "e1", "sourceNodeId": "start", "targetNodeId": "apply", "properties": {} },
{ "id": "e2", "sourceNodeId": "apply", "targetNodeId": "leader", "properties": {} },
{ "id": "e3", "sourceNodeId": "leader", "targetNodeId": "decision1", "properties": {} },
{ "id": "e4", "sourceNodeId": "decision1", "targetNodeId": "end",
"properties": { "expr": "amount > 1000" }, "text": { "value": "金额>1000" } },
{ "id": "e5", "sourceNodeId": "decision1", "targetNodeId": "end",
"properties": {}, "text": { "value": "默认" } }
]
}11. 常见错误对照
| 错误 | 现象 | 修复 |
|---|---|---|
| 多个 end 节点 | 分支各自结束 | 汇合到同一个 end |
| 申请节点缺 assignee | 启动后无任务 | 加 "assignee": "applicant" |
| 决策出边缺 expr | 走默认分支(第一条无 expr 边) | 每条出边补 expr |
| 决策/fork 边缺 text | 线上无标签 | 补 text.value |
| 节点 id 重复 | 任务名冲突 | 保证 id 全流程唯一 |
custom 写 customClass | 解析不出 clazz,节点不执行 | 用 clazz(旧文档字段名,引擎不识别) |
| 属性拼写错误 | 静默进 ext,行为不生效 | 对照本表逐键核对 |