BPM Rule 示例

这页只讲 workflow-demo 里已经跑通的两条规则:

  • wd_leave_validation:提交请假前的前置校验,挡住年假余额不足和长病假无附件。
  • wd_leave_routing:流程内路由规则,把短假派给主管、长假派给 HR。

两条规则都在 plugins/workflow-demo/config/rules.json 声明,规则内容放在 plugins/workflow-demo/rules/*.drl,由 BPM Rule API 与 rule-task 节点调用。

规则清单

规则类型输入输出接入位置
wd_leave_validationVALIDATIONtype, days, balanceRemaining, attachmentCountvalid, reasonwd:submit_leave_request / wd:create_and_submit_leave_request 启动流程前
wd_leave_routingCONDITIONdaysapproverRolewd_leave_approvalsvc_rule_route rule-task

前置校验:wd_leave_validation

配置声明:

{
  "ruleCode": "wd_leave_validation",
  "ruleName:zh-CN": "请假申请前置校验",
  "ruleType": "VALIDATION",
  "enabled": true,
  "inputSchema": {
    "type": "object",
    "properties": {
      "type": { "type": "string", "enum": ["annual", "sick", "personal", "comp"] },
      "days": { "type": "number" },
      "balanceRemaining": { "type": "number" },
      "attachmentCount": { "type": "integer" }
    },
    "required": ["type", "days"]
  },
  "outputSchema": {
    "type": "object",
    "properties": {
      "valid": { "type": "boolean" },
      "reason": { "type": "string", "enum": ["annual_leave_insufficient", "sick_attachment_required"] }
    }
  },
  "ruleContentFile": "rules/wd_leave_validation.drl"
}

DRL 只写业务判定,结果通过 _ruleResult 这条输出通道返回:

rule "reject_insufficient_annual_balance"
    when
        $req: Map(
            this["type"] == "annual",
            ((Number) this["days"]).doubleValue() > ((Number) this["balanceRemaining"]).doubleValue()
        )
    then
        Map result = (Map) $req.get("_ruleResult");
        result.put("valid", Boolean.FALSE);
        result.put("reason", "annual_leave_insufficient");
end

写文档和测试时要注意三点:

  • inputSchema.required 只要求 type / days;余额和附件数量来自提交链路组装的上下文,不是用户表单必填字段。
  • 两条提交命令都会在流程启动前跑这条规则:wd:create_and_submit_leave_requestpayload.* 取事实,wd:submit_leave_requestcurrentRecord.* 取事实;二者都通过 contextLookup 查询 wd_leave_balance,并把 balance.wd_bal_annual_remaining 暴露成 balanceRemaining
  • reason 是错误码,不是最终中文提示。UI 层按 i18n 或命令错误处理展示给用户。
  • 下图展示同一请假表单的提交前错误摘要位置;annual_leave_insufficient 规则本身以 wd_leave_validation.drl、两条命令的 preActionsWorkflowDemoLeaveValidationRuleTestWorkflowDemoCommandConfigTestwd-leave-validation.spec.ts 作为事实源。

请假表单提交前的错误摘要

流程内路由:wd_leave_routing

流程图里的 svc_rule_route 节点引用这条规则:

{
  "id": "svc_rule_route",
  "type": "rule-task",
  "data": {
    "label:zh-CN": "路由规则",
    "ruleCode": "wd_leave_routing",
    "factsVars": "days,type"
  }
}

规则配置只需要 days,输出 approverRole:

{
  "ruleCode": "wd_leave_routing",
  "ruleName:zh-CN": "请假申请审批人分派",
  "ruleType": "CONDITION",
  "inputSchema": {
    "type": "object",
    "properties": { "days": { "type": "number" } },
    "required": ["days"]
  },
  "outputSchema": {
    "type": "object",
    "properties": {
      "approverRole": { "type": "string", "enum": ["manager", "hr"] }
    }
  },
  "ruleContentFile": "rules/wd_leave_routing.drl"
}

DRL 分支:

rule "route_short_to_manager"
    when
        $req: Map(((Number) this["days"]).doubleValue() < 3.0)
    then
        Map result = (Map) $req.get("_ruleResult");
        result.put("approverRole", "manager");
end

rule "route_long_to_hr"
    when
        $req: Map(((Number) this["days"]).doubleValue() >= 3.0)
    then
        Map result = (Map) $req.get("_ruleResult");
        result.put("approverRole", "hr");
end

后面的 gw_approver 不懂 Drools,只看流程变量:

变量网关条件分支
approverRole = manager${approverRole == 'manager'}task_manager_approve
approverRole = hr${approverRole == 'hr'}task_hr_approve

BPMN Designer 中的 svc_rule_route 路由规则节点与主管/HR 分支

当前设计器右侧面板只展示规则任务的节点名称;ruleCode: wd_leave_routingfactsVars: days,type 以流程定义 JSON/BPMN 和后端导入结果为准。

API 调试入口

后端控制器是 BpmRuleController,路径前缀是 /api/bpm/rules,需要 BPM_RULE_MANAGE

操作端点用途
列规则GET /api/bpm/rules?type=CONDITION只看某类规则
看规则GET /api/bpm/rules/{pid}查导入后的规则记录
校验 DRLPOST /api/bpm/rules/validate提交 { "drlContent": "..." },返回 valid/errors
试算规则POST /api/bpm/rules/{pid}/evaluate用 facts 直接试跑,不启动流程

试算路由规则时,facts 可以只给 days:

{
  "days": 2
}

期望输出里有:

{
  "approverRole": "manager"
}

与 E2E 对齐

web-admin/tests/e2e/workflow-demo 已经把规则路径写成真实产品路径:

  • R1 短假:提交 days=2,应出现 task_manager_approve,最终审批通过后业务记录回写 approved
  • R2 长假:提交 days=10,应出现 task_hr_approve,且不会出现在主管待办里。
  • R3 SLA:提交 days=1,确认先路由到主管任务,再观察 SLA 记录。
  • R4 年假余额不足:先把余额设成 2,再提交 days=64 的草稿,响应包含 annual_leave_insufficient,业务记录仍是 draft,且 wd_req_process_instance 为空。
  • R5 一步创建并提交:用 wd:create_and_submit_leave_request 提交 days=10、余额 1 的年假,响应同样包含 annual_leave_insufficient,证明创建即提交路径没有绕过前置规则。

截图和 seed

先在网站仓运行:

cd docs/screenshot-seeds
node seed_workflow_demo.mjs --base-url=http://127.0.0.1:5173 --storage-state=tests/storage/admin.json --min-requests=12

截图时至少保留三类数据:

  1. days < 3 的申请:证明 wd_leave_routing 输出 manager。
  2. days >= 3 的申请:证明同一流程进入 HR 分支。
  3. 年假余额不足或长病假无附件:证明 wd_leave_validation 在流程启动前挡住。

后续步骤