流程发起、取消、重新发起
这篇解决什么
改发起大厅、我的流程、管理员流程实例,以及详情里的取消、再次提交。读完能对上 BpmProcessInstanceController 的创建 / 取消 / 重提接口,分清「撤回」和「取消」,以及结束后再开一张单为什么只适用于流程表单。
默认端口 48080,管理端前缀 /admin-api。PC 开发页 http://127.0.0.1:5800。入口在流程中心。
示意图:大厅和列表都打 /bpm/process-instance/*,真正起停实例交给 Flowable。业务单据另走 submitProcessInstance,见 业务表单开发。
从哪改
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 实例接口 | @RequestMapping("/bpm/process-instance") | ruoyi-office/yudao-module-bpm/yudao-module-bpm-server/.../controller/admin/task/BpmProcessInstanceController.java |
| 实例实现 | 创建、提交、取消、删除、重提 | .../service/task/BpmProcessInstanceServiceImpl.java |
| 实例状态 | BpmProcessInstanceStatusEnum | ruoyi-office/yudao-module-bpm/yudao-module-bpm-api/.../enums/task/BpmProcessInstanceStatusEnum.java |
| 状态变量名 | 实例变量 PROCESS_STATUS | .../framework/flowable/core/enums/BpmnVariableConstants.java |
| 完成监听 | 创建 / 完成 / 取消后回写状态 | .../framework/flowable/core/listener/BpmProcessInstanceEventListener.java |
| PC API | createProcessInstance / cancelProcessInstanceByStartUser | ruoyi-office-vben/apps/web-antd/src/api/bpm/processInstance/index.ts |
| 发起大厅 | 路由 /bpm/start-process | .../src/views/bpm/processInstance/create/index.vue |
| 卡片墙 | 分类 + 最近使用 | .../create/modules/process-picker.vue |
| 我的流程 | 路由 /bpm/task/my | .../src/views/bpm/processInstance/index.vue |
| 管理员实例 | 路由 /bpm/manager/process-instance/manager | .../src/views/bpm/processInstance/manager/index.vue |
| 详情按钮 | 取消 / 再次提交 | .../detail/modules/operation-button.vue |
官方菜单:1185 流程中心,2720 发起流程,1200 任务管理,1201 我的流程,1186 流程设置,2721 流程实例。按钮 1219 bpm:process-instance:create,1220 bpm:process-instance:cancel,2722 bpm:process-instance:manager-query,2723 bpm:process-instance:cancel-by-admin。
我的流程分页登录即可查,只看当前人发起的。创建要 bpm:process-instance:create。发起人取消要 bpm:process-instance:cancel。管理员取消另走 cancel-by-admin。
发起流程
菜单 流程中心 → 发起流程。未选流程时是卡片墙:左侧分类,右侧按分类铺已发布定义。选中流程表单后切到填写页;业务表单直接跳单据 info。

本系统截图:流程中心 → 发起流程。分类在左,卡片在右,搜索框按流程名称过滤。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 可发起列表 | GET /bpm/process-definition/list,suspensionState=1,client=pc | BpmProcessDefinitionController#getProcessDefinitionList |
| 分类 | 简单列表,给左侧导航排序 | GET /bpm/category/simple-list |
| 最近使用 | 浏览器本地记录,不是后端接口 | create/modules/process-recent.ts |
大厅只留同时满足这些条件的定义:已激活、visible 不为 false、当前人 canUserStartProcessDefinition 通过。开了发起权限后,再按关联菜单的 client_type 滤 PC / App。
点卡片之后
create/index.vue 的 handleSelect 按 formType 分叉。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
流程表单 10 | 本页打开 form.vue,字段进流程变量 | BpmModelFormType.NORMAL |
业务表单 20 | router.push(formCustomCreatePath) | 用印 /oa/seal/seal-apply-info |
| 绑定物理表 | 流程表单且 formCategory=bound,先落业务表再起实例 | saveAndStartProcessV2 → BpmFormDataController |
| 创建入参 | processDefinitionId 必填;variables / businessKey / startUserSelectAssignees | BpmProcessInstanceCreateReqVO |
标准流程表单点提交走 POST /bpm/process-instance/create。业务单据不走大厅这条,走各模块 submit,内部调 BpmProcessInstanceApi.submitProcessInstance。
示意图:大厅创建只认定义 id。业务单据那条认 processDefinitionKey + businessKey。
代他人发起会跳过大厅权限
needCheckStartPermission 只在「登录人就是发起人」时校验菜单和组织范围。定时任务、MQ、绩效考核代发起没有登录人或操作人不是发起人,不会被大厅权限挡住。业务单据提审时登录人就是发起人,校验仍在。
引擎怎么起实例
createProcessInstance0 先校验定义存在、未挂起、有扩展信息、能发起、自选审批人合法。有 businessKey 时会清掉同 key 的历史实例,避免重提撞旧数据。
然后往变量里写入系统字段,再 RuntimeService.createProcessInstanceBuilder().start()。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
PROCESS_STATUS | 写成审批中 1 | BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS |
PROCESS_START_USER_ID | 发起人 | 同上 |
_FLOWABLE_SKIP_EXPRESSION_ENABLED | 打开跳过表达式,没配的节点不受影响 | 同上 |
PROCESS_START_USER_SELECT_ASSIGNEES | 发起人自选审批人 | 同上 |
deptId / companyId | 变量里没有时,按发起人部门补 | BpmProcessVariableConstants |
billCode | 流程表单按 billCodePrefix 生成;业务主键是纯数字时不当单号 | processIdRedisDAO.generateBillCode |
Flowable 运行实例在 ACT_RU_EXECUTION。引擎表没有「审批中 / 已取消」列,状态和意见放在 ACT_RU_VARIABLE,名字是 PROCESS_STATUS、PROCESS_REASON。
submitProcessInstance 按 businessKey 找还活着的实例:找到且发起人有待办,就改变量并代批那条任务;找不到再走 createProcessInstance0。退回、撤回后同一张单据再点提交,走这条,不会再开一个实例。
流程状态
BpmProcessInstanceStatusEnum 写在 api 模块。大厅、我的流程、详情都读这个整数。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
NOT_START -1 | 未提交 | BpmProcessInstanceStatusEnum |
RUNNING 1 | 审批中 | 同上 |
APPROVE 2 | 审批通过 | 同上 |
REJECT 3 | 审批不通过 | 同上 |
CANCEL 4 | 已取消 | 同上 |
WITHDRAW 10 | 已撤回 | 同上 |
isProcessEndStatus 只把通过、不通过、取消当成终态。isResubmittable 是未提交、不通过、已撤回(null 当未提交)。isDeletable 再加上已取消。
实例完成后,运行表里的执行行会删掉,只能到 ACT_HI_PROCINST、ACT_HI_VARINST 查。这是冷热分离,不是丢了。
BpmProcessInstanceEventListener 听 PROCESS_CREATED / PROCESS_COMPLETED / PROCESS_CANCELLED。完成时若状态还是审批中,监听器改成通过。删除实例触发的 CANCELLED 会被 isDeletionCancelReason 滤掉,避免误写成通过。
我的流程
菜单 流程中心 → 任务管理 → 我的流程。查当前人发起的全部实例,含进行中和已结束,所以读历史表,不读 ACT_RU_EXECUTION。

本系统截图:任务管理 → 我的流程。筛选是分类、单据类型、单号、状态。审批中行的操作是详情和撤回。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 我的分页 | GET /bpm/process-instance/my-page,startedBy 当前人 | BpmProcessInstanceController#getProcessInstanceMyPage |
| 办事汇总 | GET /bpm/process-instance/my-summary | #getMyProcessInstanceSummary |
| 查询条件 | 名称、流程 key、分类、状态、起止时间、单号、公司、部门 | .../vo/instance/BpmProcessInstancePageReqVO.java |
ACT_HI_PROCINST | 历史实例。BUSINESS_KEY_、START_USER_ID_、END_TIME_ | Flowable 历史表 |
ACT_HI_VARINST | 历史变量,含当时的 PROCESS_STATUS | 同上 |
| 列表撤回 | PUT /bpm/task/withdraw-to-start | BpmTaskController#withdrawProcessToStart |
| 列表删除 | DELETE /bpm/process-instance/delete | #deleteProcessInstance |
列表「撤回」不是取消。它把运行中的实例拉回开始节点,状态写成 WITHDRAW,单据还能改完再提。模型扩展信息 allowWithdrawTask 为 false,或当前是子流程,会拒。
删除只允许未提交、不通过、已取消、已撤回,且必须是自己发起的。删除会先通知业务模块删单,再清 Flowable 运行/历史和抄送。
列表撤回不会结束实例
详情里的「取消」才把整单标成已取消并走到结束。把列表撤回当成取消,业务回写会走到 onProcessCancelled 对不上,单据还会停在可重提。
取消流程
详情里,发起人在实例未结束时能看到「取消」。管理员在流程实例列表取消,走另一条接口。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 发起人取消 | DELETE /bpm/process-instance/cancel-by-start-user | BpmProcessInstanceController#cancelProcessInstanceByStartUser |
| 管理员取消 | DELETE /bpm/process-instance/cancel-by-admin | #cancelProcessInstanceByManager |
| 取消入参 | id + reason 都必填 | .../vo/instance/BpmProcessInstanceCancelReqVO.java |
| 允许取消 | 模型 allowCancelRunningProcess,未配当允许 | BpmProcessDefinitionInfoDO |
发起人取消还要满足:实例还在运行、发起人是自己、定义允许取消、不是子流程。管理员取消不验本人,但仍要实例存在。
示意图:先落取消状态和原因,再把任务迁到结束。子流程会跟着取消。
updateProcessInstanceCancel 先 setVariable 写成 CANCEL,再查 superProcessInstanceId 等于自己的子实例递归取消,最后 taskService.moveTaskToEnd。监听器收到取消后走 processProcessInstanceCompleted,业务模块的 FlowBillService.onProcessCancelled 在这条链上被通知。
子流程不能由发起人取消
superExecutionId 非空会抛「子流程不允许取消」。要停子流程,从主流程取消,或让管理员在流程实例里操作。
重新发起
这里有两套,不要混。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 再次提交 | 终态后再开一张新实例,把旧表单值填回去 | 详情 handleReCreate |
| 重新提交 | 同一实例撤回后,发起人待办再批一次 | PUT /bpm/process-instance/resubmit |
详情「再次提交」只在同时满足时出现:当前人是发起人、状态是通过 / 不通过 / 取消、模型 formType === 10(流程表单)。业务表单结束后应回自己的 list / info 再开单,不要走大厅这条。
大厅若带 ?processInstanceId=,会 getProcessInstance 取出 formVariables,按定义 key 选中卡片,再交给 form.vue 的 initProcessInfo。过滤掉不在 formFields 里的键,避免把审批人一类系统变量重新提交进去。
最终仍调用 POST /bpm/process-instance/create,得到新的实例 id。旧单保持原状态,不会复活。
resubmitProcessInstance 校验实例还在、操作人是发起人、发起人确有待办,然后改变量、把状态改回审批中,再 approveTask。退回、撤回后的流程表单走它;业务单据走各模块 submit → submitProcessInstance。
再次提交的跳转路径
详情 handleReCreate 现在写的是 /bpm/task/create。现网大厅是 /bpm/start-process(菜单 2720)。二开时改成 /bpm/start-process,并带上 processInstanceId,否则点「再次提交」会 404。
重填只要表单字段
formVariables 里常有节点审批人、PROCESS_STATUS 这类键。原样 POST 会让创建接口校验失败。只保留设计器里的 field。
管理员看全站实例
菜单 流程中心 → 流程设置 → 流程实例。不限发起人,同样读 ACT_HI_PROCINST。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 管理分页 | GET /bpm/process-instance/manager-page,userId 传 null | BpmProcessInstanceController#getProcessInstanceManagerPage |
| 页面权限 | bpm:process-instance:manager-query | 同上 @PreAuthorize |
| 管理取消 | 行内取消,调 cancelProcessInstanceByAdmin | manager/index.vue |
查询条件比「我的流程」多一个发起人。运维停单、查别人的在途,用这一页,不要改 my-page 放开 startedBy。
配置与操作
员工从 发起流程 选已发布定义,或从业务列表进 info 再提交。取消只在「我的流程」或详情里由发起人点;管理员在 流程实例 用管理取消。
再次提交只适用于流程表单:把当时字段再 POST 一次。业务表单结束后再开,走业务列表新建,不要复用实例重提。
开启见 流程功能设计。截图见上文大厅和我的流程。
