外观
业务表单示例
概述
业务表单示例是工作流(BPM)模块中一个端到端的业务表单样例,用于演示「业务表单 + 流程引擎」的完整接入方式:业务数据存储在独立的业务表中,审批流程由工作流引擎驱动,审批结果通过引擎事件回写到业务表。
业务表单示例——请假申请涉及三大部分:前端页面、业务接口、流程引擎。三者通过「流程定义标识 oa_leave」与「流程实例编号 process_instance_id」关联。
后端实现
后端代码位于 backend/app/api/v1/module_bpm/oa_leave/,采用与系统其它模块一致的分层结构:controller → service → crud + model + schema,并通过 listener.py 订阅引擎事件。
业务表与数据模型
业务表 bpm_oa_leave 记录一次请假申请的核心字段,并通过 process_instance_id 与流程实例绑定。
| 字段 | 说明 |
|---|---|
user_id | 申请人用户编号(数据权限按本人 OWN) |
type | 请假类型,字典 bpm_oa_leave_type(病假/事假/婚假…) |
reason | 请假原因 |
start_time / end_time | 起止时间(毫秒时间戳存取) |
day | 请假天数,由引擎计算 (end - start).days |
status | 审批结果,复用 BpmProcessInstanceStatusEnum(审批中/通过/不通过/取消) |
process_instance_id | 关联流程实例编号(核心外键) |
模型定义见 backend/app/api/v1/module_bpm/oa_leave/model.py
接口与权限
路由前缀 /bpm/oa/leave,标签「工作流-OA请假申请」,需登录鉴权:
| 接口 | 说明 | 权限码 |
|---|---|---|
POST /create | 创建请假申请并发起流程 | bpm:oa-leave:create |
GET /get | 获取请假申请详情 | bpm:oa-leave:query |
GET /page | 分页查询请假申请 | bpm:oa-leave:query |
创建并发起流程
BpmOALeaveService.create 是核心入口:先做基础校验(结束时间必须晚于开始时间),再查询 key=oa_leave 的最新激活版本流程定义,计算请假天数,调用引擎 create_instance 同事务发起流程,最后落库业务单。
python
# service.py(节选)
PROCESS_KEY = "oa_leave"
day = (data.end_time - data.start_time).days
engine = BpmProcessEngine(self.auth)
instance = await engine.create_instance(
definition,
{"day": day, "type": data.type, "reason": data.reason}, # 流程变量
data.start_user_select_assignees, # 发起人自选审批人
)
leave = BpmOALeaveModel(
user_id=self.auth.user.id,
type=data.type, reason=data.reason,
start_time=data.start_time, end_time=data.end_time,
day=day, status=BpmProcessInstanceStatusEnum.RUNNING,
process_instance_id=instance.id,
)其中 day 作为流程变量传入引擎,供条件分支节点求值使用(例如「请假天数 > 3 天需总监审批」)。start_user_select_assignees 对应前端「发起人自选审批人」策略,结构为 {节点ID: [用户编号]}。
审批结果回写(监听器)
流程审批结束时,引擎发布 PROCESS_INSTANCE_FINISH 事件,业务层订阅该事件将审批结果回写到请假单。模块导入时即完成订阅(见 router.py 中的 from ...oa_leave import listener)。
python
# listener.py(节选)
async def on_process_instance_finish(instance, status: int, reason: str | None = None, **_) -> None:
"""流程实例终态:按实例编号回写请假单审批结果"""
rows = (await session.execute(
select(BpmOALeaveModel).where(BpmOALeaveModel.process_instance_id == instance.id)
)).scalars().all()
for leave in rows:
leave.status = status
event.subscribe(event.BpmEventEnum.PROCESS_INSTANCE_FINISH, on_process_instance_finish)这种「事件解耦」设计让业务表与流程引擎互不侵入:业务无需感知审批节点细节,引擎也无需知道具体业务语义。
取消流程
当请假单处于「审批中」时,发起人可在前端取消。后端 process_instance 模块提供 cancel_by_start_user,并兼容以业务单据编号(即请假单 id)取消——内部通过 BpmOALeaveService.resolve_instance_id 回退解析出流程实例编号。
python
# process_instance/service.py(节选)
async def cancel_by_start_user(self, id: int, reason: str) -> None:
instance = await BpmProcessInstanceCRUD(self.auth).get(id=id)
if instance is None:
# 业务表单场景:兼容前端以业务单据编号取消流程
instance_id = await BpmOALeaveService(self.auth).resolve_instance_id(id)
...流程定义配置
请假流程在「流程模型」中维护,关键属性:
- 流程标识(Key):
oa_leave,与后端PROCESS_KEY一致,引擎据此查找定义。 - 表单类型:业务表单(自定义路由)。
- 条件分支:利用流程变量
day配置分支条件,例如天数较小时仅部门负责人审批,天数较大时追加总监审批。 - 发起人自选审批人:若某审批节点候选策略设为
START_USER_SELECT,前端会在发起页让用户选择具体审批人。
流程绘制与节点配置详见《流程模型》《流程框架》章节。
前端实现
页面结构
前端位于 apps/web-ele/src/views/bpm/oa/leave/,配套 API 在 apps/web-ele/src/api/bpm/oa/leave/index.ts。页面基于 Vben Admin 的 Page + VxeTable + useVbenForm 组件,并复用流程实例的「审批进度时间线」组件。

| 视图 | 文件 | 作用 |
|---|---|---|
| 请假列表 | index.vue | 分页列表、发起/详情/审批进度/取消/重新发起 |
| 发起 / 重新发起 | create.vue | 填写表单 + 实时预览审批流 |
| 请假详情 | detail.vue | 展示业务字段 |
| 表单与列定义 | data.ts | 表单项、搜索项、表格列、详情项 schema |
发起页与流程预览

create.vue 是体验的核心:左侧填写业务表单,右侧通过 ProcessInstanceTimeline 实时展示审批节点。发起页在 onMounted 时拉取 key=oa_leave 的流程定义,并调用审批详情接口预测节点。
关键交互:
- 表单中输入起止时间后,
watch会重新预测审批节点(因为条件分支依赖day)。 - 若存在「发起人自选审批人」节点,右侧时间线会提示用户选择具体审批人。
- 提交时把
startUserSelectAssignees一并传给后端。
ts
// create.vue(节选)
const processDefineKey = 'oa_leave'; // 流程定义 Key
const submitData: LeaveCreateData = {
...data,
startTime: Number(data.startTime),
endTime: Number(data.endTime),
};
if (startUserSelectTasks.value?.length > 0) {
submitData.startUserSelectAssignees = startUserSelectAssignees.value;
}
await createLeave(submitData);时间字段与字典
- 起止时间使用
DatePicker,valueFormat: 'x'(毫秒时间戳),与后端MillisecondDateTime类型互转保持一致。 - 请假类型、审批结果均用字典渲染:
BPM_OA_LEAVE_TYPE、BPM_PROCESS_INSTANCE_STATUS,在data.ts中通过getDictOptions与CellDict配置。
列表操作
index.vue 中的行操作根据状态动态展示:
- 审批中(
RUNNING):显示「取消」。 - 非审批中:显示「重新发起」。
- 始终提供「详情」「审批进度」,审批进度跳转到流程实例详情页查看时间线。
端到端流程演示
其它业务表单
若需把工作流接入其它业务(如报销、采购),可参照本示例:
- 新建业务表与
Model,通过process_instance_id关联流程实例,权限策略按需设置。 - 编写
Service:create中调用BpmProcessEngine.create_instance,并传入业务变量。 - 编写
listener:订阅PROCESS_INSTANCE_FINISH,按process_instance_id回写业务状态。 - 在
router.py中导入listener模块完成订阅注册。 - 前端仿照
views/bpm/oa/leave/,用processDefineKey+ 审批详情预测组件接入发起页。