Skip to content

规范 02 · 流程定义格式

流程定义 = LogicFlow JSON。同一份 JSON 在所有语言实现中必须产生一致的执行结果。

顶层结构

json5
{
  "name": "leave",           // 流程编码(唯一)
  "displayName": "请假审批",  // 流程显示名称
  "type": "approval",        // 流程类型
  "nodes": [...],
  "edges": [...]
}

流程级 properties

来源:mldong 框架 process-drawer-schema.ts

字段类型引擎
namestring
displayNamestring
instanceUrlstring计划
instanceNoClassstring计划
expireTimestring
preInterceptorsarray✅ Registry
postInterceptorsarray✅ Registry
selectUserOnInitiateint❌ 前端
selectUserApistring❌ 前端
enableCcActorsint❌ 前端
enableApplyReasonint❌ 前端
enableAttachmentint❌ 前端
enableFieldPermint❌ 前端

节点类型总览

type说明必填
snaker:start开始-
snaker:end结束(全流程只能有一个-
snaker:task任务assigneeassignmentHandler
snaker:decision条件分支出边 expr
snaker:fork并行分支-
snaker:join并行合并-
snaker:custom自定义customClass
snaker:subprocess子流程subProcessKey

发起申请节点约定(mldong 框架契约):每个流程的 start 后第一个任务节点必须是 "发起申请"节点,assignee 使用特殊值 "applicant"——引擎在解析参与者时将其替换为 流程发起人(instance.operator)。引擎本身不自动执行该节点,由调用方(demo 的 startAndExecute)在启动后自动完成,从而把流程推进到真正的审批节点。 契约动机见 设计原理 06 · 契约约定

任务节点 properties

来源:mldong 框架 prop-config/task-form/*.vue

字段类型引擎说明
namestring节点唯一编码 → taskName
displayNamestring显示名称
formstring表单标识 → formKey
assigneestring固定参与者,逗号分隔 → actor;每个 token 优先按流程变量 key 解析(见 参与者解析
assignmentHandlerstring动态参与者类名 → Registry
candidateUsersstring⚠️候选人列表 → candidatePage API
candidateGroupsstring⚠️候选组 → candidatePage API
candidateHandlerstring⚠️动态候选人处理类 → candidatePage API
taskTypeint0=主办 1=协办
performTypeint0=普通 1=会签
countersignTypestringPARALLEL/SEQUENTIAL/RATIO(0.5)
countersignCompletionConditionstring会签完成条件(如 #nrOfCompletedInstances>=2
actionBtnsarray审批按钮配置
expireTimestring期望完成时间
reminderTimestring计划提醒时间
reminderRepeatstring计划重复提醒间隔
autoExecuteint计划自动完成
callbackstring计划回调处理类
preInterceptorsarray节点前置拦截器
postInterceptorsarray节点后置拦截器

⚠️ candidate* 系列不生成 actor 记录,但引擎通过 candidatePage API 返回候选人列表, 供前端"指定下一节点参与人"时使用。

参与者解析(assignee)

v1.0.1(集成反馈③):对齐 mldong 框架 boot2/boot3 语义——"token 即变量 key, 能替换就换,换不了就是字面量"

解析顺序(引擎创建任务时):

  1. tf_nextNodeOperator 优先:流程变量中存在 tf_nextNodeOperator(下一节点处理人, 由前端/上一步动态指定)时直接采用,不再看 assignee。值为 String 按逗号分割; 值为 Collection/数组 原样展开。
  2. assignee 逐 token:按英文逗号分割,逐个处理:
    • token = applicant → 流程发起人(instance.operator)——mldong 契约特殊值
    • 其他 token → 先查流程变量(token 作为 key):命中 → 用变量值(值为集合则展开为多人); 未命中 → token 本身作为参与者(静态用户 ID 写法)
    • 不做 ${...} 剥壳——${deptLeader} 与 boot2/boot3 行为一致:按 key 查不到 → 字面量
  3. assignmentHandler 兜底:assignee 为空/解析结果为空时,按类名反射调用动态参与者处理器。

对齐说明:boot2/boot3 的 getTaskActors 语义为 args.get(token, token)——token 当 key 查流程变量,命中用值、未命中用字面量;applicant 为 jeeflow 增强(boot2/boot3 的"发起人" 靠 assignmentHandler=OperatorAssignmentHandler 实现,二者等价)。

决策节点 properties

字段位置引擎说明
expr节点节点级决策表达式
decisionHandler节点自定义决策类名 → Registry
expr出边分支条件表达式
text.value出边分支标签(钉钉模式渲染)

其他节点 properties

节点字段引擎说明
customcustomClass自定义处理器类名
subprocesssubProcessKey子流程编码
subprocesssubProcessName前端显示

完整示例

json
{
  "name": "leave",
  "displayName": "请假审批",
  "type": "approval",
  "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":"t1", "type":"snaker:task", "x":400, "y":200,
      "properties":{ "form":"leave-form", "assignee":"leader", "taskType":0, "performType":0 },
      "text":{"value":"组长审批"} },
    { "id":"end", "type":"snaker:end", "x":550, "y":200, "properties":{}, "text":{"value":"结束"} }
  ],
  "edges": [
    { "id":"e1", "sourceNodeId":"start", "targetNodeId":"apply", "properties":{} },
    { "id":"e2", "sourceNodeId":"apply", "targetNodeId":"t1", "properties":{} },
    { "id":"e3", "sourceNodeId":"t1", "targetNodeId":"end", "properties":{} }
  ]
}

决策分支边必须带 text.value 分支标签(钉钉模式渲染在分支线上):

json
{ "id":"e4", "sourceNodeId":"decision1", "targetNodeId":"t2",
  "properties":{"expr":"amount > 1000"}, "text":{"value":"金额>1000"} }

jeeflow · 轻量级多语言工作流引擎