流程审批通知
这篇解决什么
审批状态一变,要把短信发给申请人或办理人。读完能对上四个场景、BpmMessageService 怎么调 SmsSendApi,以及短信模板编码为什么必须写成 bpm_*。
默认端口 48080,管理端前缀 /admin-api。PC 开发页 http://127.0.0.1:5800。改文案去系统管理 → 消息中心 → 短信管理 → 短信模板,不要在流程模型里找「通知配置」页。
示意图:办理和办结在 BPM 里触发;真正发短信走 system 的发送 API。
从哪改
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 消息接口 | 通过、不通过、任务分配、超时四条 | ruoyi-office/yudao-module-bpm/.../service/message/BpmMessageService.java |
| 发送实现 | 只调 SmsSendApi.sendSingleSmsToAdmin | .../service/message/BpmMessageServiceImpl.java |
| 场景编码 | BpmMessageEnum 对短信 code | yudao-module-bpm-api/.../enums/message/BpmMessageEnum.java |
| 入参 DTO | 实例名、任务名、意见、办理人 | .../service/message/dto/ |
| 短信 RPC | Feign 名 system-server,/rpc-api/system/sms/send | yudao-module-system-api/.../api/sms/SmsSendApi.java |
| BPM 声明 | @EnableFeignClients 只挂了 SmsSendApi | .../framework/rpc/config/RpcConfiguration.java |
| 详情链接 | yudao.web.admin-ui.url + /bpm/process-instance/detail?id= | yudao-server/src/main/resources/application.yaml |
| 短信模板页 | 路由 /system/messages/sms/sms-template | ruoyi-office-vben/apps/web-antd/src/views/system/sms/template/ |
官方菜单:1093 短信管理,1100 短信模板。按钮 system:sms-template:query / update。流程中心没有单独的「审批通知」菜单。
5800 没有流程通知配置页
管理端「消息定义」是统一消息中心的场景表,当前没有 bpm_* 行。BpmMessageServiceImpl 也没有调 MessageSendApi。改审批短信,只改 system_sms_template。
四个场景
四个枚举值对应四条短信模板。改编码要两边一起改,否则发送时找不到模板。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
PROCESS_INSTANCE_APPROVE | 整单通过,发给发起人 | BpmMessageEnum → bpm_process_instance_approve |
PROCESS_INSTANCE_REJECT | 整单不通过,发给发起人 | 同上 → bpm_process_instance_reject |
TASK_ASSIGNED | 任务落到办理人,发给审批人 | 同上 → bpm_task_assigned |
TASK_TIMEOUT | 节点超时且动作为「自动提醒」 | 同上 → bpm_task_timeout |
调用点:
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 整单通过 / 不通过 | updateProcessInstanceStatus 里按实例状态分支 | BpmProcessInstanceServiceImpl |
| 任务分配 | processTaskAssigned 末尾,带上发起人昵称 | BpmTaskServiceImpl |
| 分配监听 | Flowable TASK_ASSIGNED | BpmTaskEventListener |
| 超时提醒 | processTaskTimeout,handlerType = 1 | BpmTaskServiceImpl |
通过、不通过只看实例终态,不是每个节点批一次都发。任务分配在指派办理人之后发。超时只有节点配了「自动提醒」才会走短信;「自动同意 / 自动拒绝」直接批掉,不发 bpm_task_timeout。
示意图:四条方法最后都进 sendSmsSafely。
短信模板
交付库已经写入四条,类型是通知(SmsTemplateTypeEnum.NOTICE = 2),渠道默认「调试(钉钉)」。

本系统截图:系统管理 → 消息中心 → 短信管理 → 短信模板。编号 17 / 11 / 10 / 9 就是四条 bpm_*。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
bpm_task_assigned | 新待办:{processInstanceName}-{taskName},申请人 {startUserNickname},链接 {detailUrl} | system_sms_template |
bpm_process_instance_reject | 不通过:{processInstanceName},原因 {reason},链接 {detailUrl} | 同上 |
bpm_process_instance_approve | 通过:{processInstanceName},链接 {detailUrl} | 同上 |
bpm_task_timeout | 超时待办:{processInstanceName}-{taskName},链接 {detailUrl} | 同上 |
占位符必须和 BpmMessageServiceImpl 放进 templateParams 的 key 一致。保存模板时,SmsTemplateService 用 \{(.*?)\} 扫正文,写入 params JSON;发送缺 key 会失败。
detailUrl 拼的是 yudao.web.admin-ui.url。单体默认 http://127.0.0.1:5800。生产改成实际管理端域名,否则短信里的链接打不开。
改文案不用发版
业务代码只认 BpmMessageEnum 的 code。换句子、换渠道、换平台模板编号,改 system_sms_template 一行即可。
发送链路
BpmMessageConvert 只填 userId、templateCode、templateParams,mobile 留空。sendSingleSmsToAdmin 再用用户编号去 system_users 取手机号。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 转换 | MapStruct,忽略 mobile | .../convert/message/BpmMessageConvert.java |
| 分配入参 | 实例、任务、发起人、办理人 | BpmTaskConvert#convert |
| 通过入参 | 实例编号、名称、发起人 | BpmProcessInstanceConvert#buildProcessInstanceApproveMessage |
| 安全发送 | 失败只打 error,不回滚审批 | BpmMessageServiceImpl#sendSmsSafely |
示意图:BPM 同步调到落日志为止;打短信平台在异步线程。渠道、日志字段见 短信配置。
没有手机号就发不出去
管理员 mobile 为空会抛 SMS_SEND_MOBILE_NOT_EXISTS。sendSmsSafely 吃掉异常,审批照样过,只在日志里看到失败。联调先看用户有没有手机号,再看模板、渠道是不是启用。
生产不要继续用「调试(钉钉)」。那条渠道只往群机器人丢文本,手机收不到真短信。换阿里云 / 腾讯云等渠道的步骤在短信篇。
超时提醒
超时不是默认开启。简易设计器在审批人节点「审批人超时未处理时」打开开关;BPMN 设计器写在边界定时事件上。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 处理类型 | 1 自动提醒,2 自动同意,3 自动拒绝 | BpmUserTaskTimeoutHandlerTypeEnum |
| 简易节点 | timeoutHandler.enable / type / timeDuration | .../views/bpm/components/simple-process-design/components/nodes-config/user-task-node-config.vue |
| BPMN 边界 | 扩展属性 timeoutHandlerType | .../bpmn-process-designer/package/penal/custom-config/components/BoundaryEventTimer.vue |
| 引擎落地 | 用户任务加 Timer Boundary Event | SimpleModelUtils#buildUserTaskTimeoutBoundaryEvent |
| 触发 | TIMER_FIRED → processTaskTimeout | BpmTaskEventListener |
提醒可以配 maxRemindCount。次数大于 1 时,边界事件用 cycle,到期再发 bpm_task_timeout。自动同意 / 拒绝走 approveTask / rejectTask,意见写成超时原因,不再发超时短信。
站内信与邮件
当前实现只发短信。顶栏铃铛、邮箱要另接 API,仍建议在 BpmMessageServiceImpl 四个方法里并发送,不要另起一套监听去拆场景。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 站内信 | sendSingleMessageToAdmin,模板 code 建议 bpm_ 开头 | NotifyMessageSendApi |
| 邮件 | sendSingleMailToAdmin,用户邮箱空则按 userId 取 | MailSendApi |
| 统一消息 | 一次调用可走站内信 / 短信 / 邮件渠道 | MessageSendApi |
| 消息定义 | 路由 /system/messages/scene,现有场景不含流程 | ruoyi-office-vben/.../views/system/msg/scene/ |
| 铃铛跳转 | templateCode 以 bpm_ 开头时读 detailUrl | ruoyi-office-vben/apps/web-antd/src/views/oa/im/helper.ts |

本系统截图:消息中心 → 消息定义。行是会议、工单、项目、资产,没有流程审批场景。
接站内信时,templateParams 带上 detailUrl 或 processInstanceId。parseNotifyNavigationMeta 已经按 bpm_ 前缀拼流程详情路由。
微服务还要把 NotifyMessageSendApi / MailSendApi 写进 BPM 的 RpcConfiguration,只加 @Resource 不够。
多渠道优先走消息中心
新场景(抄送、加签、催办)不要再往 BpmMessageEnum 堆短信编码。在「消息定义」建场景,渠道勾站内信 / 短信 / 邮件,业务调 MessageSendApi。渠道适配器仍复用 system_notify_template、system_sms_template、system_mail_template。
跨模块回写不是人信
BpmNotificationManager 名字带 Notification,发的是给业务模块的状态事件,不是给用户的短信。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 管理器 | 按流程 key 选 local / mq / feign | .../service/notification/BpmNotificationManager.java |
| 本地事件 | 同一 JVM,单据回写 | BpmLocalEventNotificationHandler |
| MQ | 异步解耦 | BpmMqNotificationHandler |
| Feign | 跨进程同步 | BpmFeignNotificationHandler |
| 配置 | yudao.bpm.notification.default-type | application-notification.yaml |
updateProcessInstanceStatus 会先发人信,再调 sendProcessStatusNotification。改短信模板不会影响 OA / HRM 的 updateProcessStatus。
更多办理动作见 审批通过、不通过、驳回。
配置与操作
管理员到 系统管理 → 短信模板 改 bpm_process_instance_approve 等四条编码的文案和渠道账号。流程模型里没有「通知配置」页。改完立刻对后续办理生效,不必再发布模型。
BpmNotificationManager 是给业务模块的状态事件,不是给人的短信。改模板不会改变 OA / HRM 的 updateProcessStatus。
开启见 流程功能设计。截图见上文模板列表。
