流程与审批前端
在现代企业级应用中,工作流引擎(如 Flowable、Activiti)的前端集成是 B 端系统的核心需求之一。本文介绍流程引擎的前端集成方案、BPMN.js 流程图渲染原理以及审批面板的设计实现。
流程引擎简介
Flowable 与 Activiti
| 特性 | Flowable | Activiti |
|---|---|---|
| 开源协议 | Apache 2.0 | Apache 2.0 |
| BPMN 支持 | BPMN 2.0 完整支持 | BPMN 2.0 完整支持 |
| 最新版本 | Flowable 7.x | Activiti 8.x (基于 Spring) |
| 社区活跃度 | 高 | 高 |
| 轻量级 | 相对轻量 | 较重(深度集成 Spring) |
| Spring Boot 集成 | 自动配置 + Starter | 自动配置 + Starter |
| 前端集成 | REST API + BPMN.js | REST API + BPMN.js |
两者均支持:
- BPMN 2.0 标准流程图定义
- REST API 流程部署、启动、任务管理
- 历史数据查询:流程实例历史、活动历史
- 身份管理:用户、组、角色
- 表单集成:外置表单、内联表单
BPMN.js 流程图渲染原理
BPMN.js 是 bpmn.io 团队维护的 BPMN 2.0 流程图渲染工具包,是目前最流行的 BPMN 前端渲染方案。
架构
BPMN XML (流程定义文件)
↓
BpmnJS (核心引擎)
↓ ↘
Viewer Modeler
(只读渲染) (可编辑)核心组件
| 模块 | 功能 |
|---|---|
| BpmnJS | 核心引擎,解析 BPMN XML 并渲染 SVG |
| Viewer | 只读渲染模式,适合流程展示 |
| Modeler | 可编辑模式,支持拖拽、连线配置 |
| Properties Panel | 属性编辑面板 (bpmn-js-properties-panel) |
| Token Simulation | 流程模拟执行 (bpmn-js-token-simulation) |
渲染流程
BPMN XML
↓ 解析
DOM Structure (BPMN 语义树)
↓ 映射
Diagram Elements (图形元素)
↓ 渲染
SVG Graphics (矢量图形)
↓ 交互
User Interaction (拖拽、点击、编辑)基本使用
javascript
import BpmnModeler from 'bpmn-js/lib/Modeler';
const modeler = new BpmnModeler({
container: '#canvas',
propertiesPanel: {
parent: '#properties-panel',
},
});
// 加载 BPMN XML
const result = await modeler.importXML(bpmnXml);
// 获取流程定义数据
const elementRegistry = modeler.get('elementRegistry');
const elements = elementRegistry.getAll();
// 监听事件
modeler.on('element.click', (event) => {
const { element } = event;
console.log('Clicked:', element);
});BPMN XML 示例
xml
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:flowable="http://flowable.org/bpmn"
targetNamespace="http://flowable.org/bpmn">
<process id="leaveProcess" name="请假审批流程" isExecutable="true">
<startEvent id="startEvent" name="开始" />
<userTask id="approveTask" name="主管审批" flowable:assignee="manager" />
<exclusiveGateway id="conditionGateway" name="条件判断" />
<userTask id="hrApproveTask" name="HR 审批" flowable:assignee="hr" />
<endEvent id="endEvent" name="结束" />
<sequenceFlow id="flow1" sourceRef="startEvent" targetRef="approveTask" />
<sequenceFlow id="flow2" sourceRef="approveTask" targetRef="conditionGateway" />
<sequenceFlow id="flow3" sourceRef="conditionGateway" targetRef="hrApproveTask">
<conditionExpression xsi:type="tFormalExpression">
${days > 3}
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" sourceRef="conditionGateway" targetRef="endEvent">
<conditionExpression xsi:type="tFormalExpression">
${days <= 3}
</conditionExpression>
</sequenceFlow>
</process>
</definitions>审批面板设计
审批面板是流程前端的核心交互组件,通常包括以下功能模块:
功能架构
┌─────────────────────────────────────┐
│ 审批面板 │
├─────────────────────────────────────┤
│ ┌──────────┐ ┌─────────────────┐ │
│ │ 流程信息 │ │ 审批操作区 │ │
│ │ · 流程名称 │ │ [通过] [驳回] │ │
│ │ · 发起人 │ │ [转办] [加签] │ │
│ │ · 提交时间 │ │ ───────────── │ │
│ │ · 当前环节 │ │ 审批意见输入框 │ │
│ └──────────┘ └─────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ 审批历史列表 │ │
│ │ ✓ 赵主管 · 通过 · 10:00 │ │
│ │ ✗ 钱经理 · 驳回 · 15:30 │ │
│ │ ↷ 孙总监 · 转办给李副总 │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────┘审批操作类型
| 操作 | 说明 | API 对应 |
|---|---|---|
| 审批通过 | 同意当前任务,流程继续流转 | POST /runtime/tasks/{id} - complete |
| 驳回/退回 | 拒绝当前任务,退回上一节点或发起人 | POST /runtime/tasks/{id} - complete with feedback |
| 转办 | 将任务转给他人处理 | PUT /runtime/tasks/{id} - assign |
| 加签 | 增加额外审批人共同审批 | POST /runtime/tasks/{id} - addCandidateUser |
| 委派 | 委派他人代为审批 | PUT /runtime/tasks/{id} - delegate |
| 知会 | 抄送某人了解流程进度 | POST /runtime/tasks/{id}/identitylinks |
与后端流程引擎的 API 交互
典型接口设计
typescript
// 流程管理 API
interface FlowApi {
// 获取待办任务列表
getPendingTasks(userId: string): Promise<Task[]>;
// 获取流程历史
getHistory(processInstanceId: string): Promise<HistoricActivity[]>;
// 审批操作
approveTask(taskId: string, params: ApproveParams): Promise<void>;
rejectTask(taskId: string, params: RejectParams): Promise<void>;
transferTask(taskId: string, userId: string): Promise<void>;
// 获取流程图 XML
getProcessDiagram(processDefinitionId: string): Promise<string>;
// 获取高亮流程图
getHighlightedDiagram(processInstanceId: string): Promise<string>;
}
interface ApproveParams {
comment?: string;
variables?: Record<string, any>;
}
interface RejectParams {
comment: string;
targetActivityId?: string; // 退回目标节点
variables?: Record<string, any>;
}审批状态流转
┌─────────┐ 通过 ┌──────────┐
│ 待审批 │ ─────────→ │ 已通过 │
└─────────┘ └──────────┘
│ │
│ 驳回 │
↓ ↓
┌─────────┐ ┌──────────┐
│ 已驳回 │ │ 已归档 │
└─────────┘ └──────────┘
│
│ 转办
↓
┌─────────┐
│ 已转办 │
└─────────┘技术选型建议
方案对比
| 方案 | 适用场景 | 技术复杂度 |
|---|---|---|
| BPMN.js Modeler | 需要可视化流程设计 | 高 |
| BPMN.js Viewer | 只展示流程图,不可编辑 | 低 |
| 自绘流程图(SVG/Canvas) | 简单流程展示 | 低 |
| 第三方平台(钉钉/飞书审批) | 简单审批场景 | 极低 |
推荐组合
├── Flowable/Activiti (后端引擎)
├── BPMN.js Viewer (流程图只读展示)
├── 审批面板自研 (React/Vue 组件)
├── REST API 通信 (Axios/Fetch)
└── WebSocket 推送 (实时待办提醒)审批面板最佳实践
- 操作隔离:审批/驳回/转办操作为互斥状态,一次只能触发一种
- 意见必填:驳回操作必须填写原因,通过操作可填可不填
- 流程追踪:清晰展示当前所处节点、历史审批路径
- 附件支持:审批意见支持上传附件作为佐证材料
- 消息推送:审批状态变化通过 WebSocket 实时通知
- 并发审批:支持会签(多人审批,全部通过才算通过)
- 超时提醒:任务超时未处理自动提醒或转办