业务系统里最容易变复杂的模块之一,就是审批。
最开始可能只是一个请假审批:
员工提交 -> 主管审批 -> 结束后来加了采购审批:
申请人提交 -> 部门负责人审批 -> 财务审批 -> 总经理审批再后来又有合同审批、报销审批、工单流转、用章审批、付款审批。每个流程都有不同的表单、审批人、按钮、退回逻辑、状态展示和消息提醒。
如果每个业务模块都自己写一套审批逻辑,代码很快会变成这样:
if 金额小于 5000,主管审批 if 金额大于 5000,经理审批 if 是合同,走法务 if 是采购,走采购负责人 if 是报销,走财务短期能上线,长期很难维护。流程一改,业务代码就要改;审批人一变,系统就要发版;按钮权限一调整,前后端都要跟着动。
这也是为什么很多业务系统需要把审批能力抽成流程引擎。
1. 审批流不应该绑死在业务模块里
比较理想的拆分是:
| 层 | 职责 |
| 业务表单 | 保存请假单、采购单、合同单等业务数据 |
| BPM 流程引擎 | 负责流程定义、节点流转、待办任务、流程状态 |
| 业务回调 | 在流程前后校验和同步业务状态 |
| 前端运行入口 | 提供发起流程、我的待办、我的申请等统一入口 |
这样做以后,业务模块不需要自己造一套待办中心,流程引擎也不需要理解每张业务表的所有字段。
Open BPM Flow Engine 这次整理开源时,重点就是把这条链路补齐。
项目地址:
https://gitee.com/luotianding/open-project2. 一个业务审批的最小闭环
业务系统接审批流,至少需要下面 6 步:
| 步骤 | 动作 |
| 1 | 配置流程图 |
| 2 | 配置流程关联业务表单 |
| 3 | 用户填写业务单据 |
| 4 | 调用流程发起接口 |
| 5 | 审批人进入我的待办办理 |
| 6 | 流程回调业务服务,同步业务状态 |
Open BPM Flow Engine 里提供的请假 Demo,就是为了演示这个闭环。
正文配图建议:
3. 业务表单怎么和流程关联
流程引擎不应该写死“请假表单”“采购表单”“合同表单”。更好的方式是通过配置把流程和表单关联。
示例配置:
| 配置项 | 示例 |
| 流程 Key | `demo_leave_process` |
| 流程名称 | `演示请假审批流程` |
| 发起表单地址 | `/demo/leave-form` |
| 回调类 | `cn.icepanda.bpm.demo.service.DemoLeaveFlowService` |
这样发起页只需要读取已发布流程,再根据流程读取对应表单地址。
前端逻辑可以理解为:
用户打开发起流程页 -> 查询可发起流程 -> 读取流程关联表单 -> 跳转到业务表单如果业务系统要二次开发接入,可以照着这个清单走:
| 开发对象 | 采购审批示例 | 说明 |
| 业务表 | `purchase_apply` | 保存采购金额、供应商、原因、业务状态、流程实例 ID |
| 后端实体 | `PurchaseApply` | 映射采购业务表 |
| 后端接口 | `PurchaseApplyController` | 提供草稿、发起前保存、详情、待办上下文、列表 |
| 业务服务 | `PurchaseApplyServiceImpl` | 保存业务单、查业务单、同步流程状态 |
| 流程回调 | `PurchaseFlowService` | `before` 校验金额,`after` 同步审批状态 |
| 前端表单 | `PurchaseForm.vue` | 支持发起、办理、查看三种模式 |
| 前端路由 | `/demo/purchase-form` | 要和流程关联业务里的表单地址一致 |
| 流程配置 | `purchase_approval` | 配流程图、节点处理人、按钮和回调类 |
普通开发者可以先不管复杂组织架构,先按“固定审批人或固定流程角色”跑通。等流程闭环跑通后,再逐步接部门负责人、岗位、角色、金额条件和消息通知。
4. 业务状态怎么同步
流程状态和业务状态不是一回事。
流程状态关注的是:
当前节点是谁 任务有没有办 流程有没有结束 流程有没有退回业务状态关注的是:
请假单是草稿还是审批中 合同是待审还是已通过 采购单是否允许下单 报销单是否允许付款所以项目里用业务回调类做状态同步。
请假 Demo 的回调类:
@Service public class DemoLeaveFlowService implements BpmBizInvoke<DemoLeaveApply> { public BpmResult before(FlowContext context, DemoLeaveApply apply) { if (apply == null) { return BpmResult.failure("请假申请数据不能为空"); } if (apply.getDays() == null || apply.getDays() <= 0) { return BpmResult.failure("请假天数必须大于 0"); } return BpmResult.success(); } public BpmResult after(FlowContext context, DemoLeaveApply apply) { return BpmResult.success(leaveApplyService.syncByFlowCallback(context, apply)); } }业务系统只关心自己的业务校验和状态同步,流程推进由 BPM 引擎完成。
5. 我的待办和我的申请为什么重要
很多业务系统刚开始只做“提交审批”,但没有统一待办。审批人只能从消息里找链接,或者回到业务列表里筛选待处理数据。
这会带来几个问题:
1. 审批人不知道自己还有多少任务没处理。
2. 发起人不知道流程走到哪一步。
3. 管理员不知道流程卡在哪个节点。
4. 多个业务模块各自实现待办,体验不统一。
所以开源版提供:
/#/runtime/myTask 我的待办 /#/runtime/myApply 我的申请 /#/runtime/taskPool 任务池 /#/runtime/myDeliver 我的抄送正文配图建议:
6. 适合接哪些业务
这类流程引擎适合:
| 业务 | 示例流程 |
| 请假审批 | 员工 -> 主管 |
| 采购审批 | 申请人 -> 部门 -> 财务 -> 总经理 |
| 合同审批 | 业务 -> 法务 -> 财务 -> 负责人 |
| 报销审批 | 员工 -> 主管 -> 财务 |
| 工单流转 | 客服 -> 技术 -> 复核 |
| 用章审批 | 申请人 -> 部门 -> 行政 |
如果你的业务有“多人协作、状态流转、审批留痕、节点权限”,都可以考虑抽成流程。
7. 开源项目能提供什么
Open BPM Flow Engine 当前提供:
1. 流程设计器。
2. 流程定义管理。
3. 流程属性配置。
4. 发起流程入口。
5. 我的待办。
6. 我的申请。
7. 任务池。
8. 我的抄送。
9. 流程实例和任务监控。
10. 请假申请 Demo。
11. MySQL 初始化脚本。
12. 图文说明文档。
它适合作为学习、二次开发和项目选型参考,不建议不改造就直接用于复杂生产场景。
二次开发时建议按这个顺序落地:
先接一个最简单的业务单 -> 再加一个审批节点 -> 再加一个条件网关 -> 再加角色和人员规则 -> 再加审批意见和流程轨迹 -> 最后接消息通知和组织架构不要一上来就把所有复杂规则都放进去。流程系统最怕“第一版就想做成万能平台”,这样很容易把业务表、流程表、权限表和消息表缠在一起。
完整二次开发指南:
bpm-project/docs/secondary-development-guide.md接口清单和关键代码索引:
bpm-project/docs/api-and-code-map.md如果企业准备基于这套开源项目做二次开发,可以按 4 个阶段落地:
| 阶段 | 目标 | 验收方式 |
| 第一阶段 | 本地启动后端、前端和数据库 | 能访问流程设计器、发起流程、我的待办 |
| 第二阶段 | 跑通请假 Demo | 能完成“发起 -> 待办 -> 办理 -> 我的申请” |
| 第三阶段 | 新增一个真实业务,例如采购审批 | 有采购表、采购表单、采购接口、采购回调 |
| 第四阶段 | 接组织、角色、消息和流程监控 | 审批人规则、提醒、追踪、异常处理符合企业规则 |
这个路线的好处是每一步都能验证,不会陷入“先搭一个大平台,最后发现闭环没跑通”的问题。
8. 总结
审批流的本质不是“某个页面上多一个同意按钮”,而是把业务状态和流程状态连接起来。
如果业务系统里审批越来越多,不要继续在各个模块里复制 if else。更合理的方式是抽出统一流程引擎,让业务模块只关心业务数据,让 BPM 引擎处理流程流转。
项目地址:
https://gitee.com/luotianding/open-project关键词:BPM流程引擎、工作流引擎、Flowable、Spring Boot工作流、业务审批、OA审批、表单流转。