SpringBoot3+Flowable+Vue3 流程评论:审批意见、单据备注和 IM 不要做成同一个盒子
2026/9/3 5:28:27 网站建设 项目流程

SpringBoot3+Flowable+Vue3 流程评论:审批意见、单据备注和 IM 不要做成同一个盒子

🌐文档地址:https://ruoyioffice.com
📦源码1·GitHub:https://github.com/yuqing2026/ruoyi-office
📦源码2·GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office
📦源码3·Gitee:https://gitee.com/yqzy1688/ruoyi-office
💬微信:17156169080(备注「RuoYi Office」)

审批人在用车单上想问一句「油费谁出」,最容易做错的是把这句话写进拒绝理由,或者丢到企业微信群里。前者会把流程打回,后者刷新页面就找不到。RuoYi Office 在同一张办理详情里拆成三套字:单据备注、流程评论、审批意见。发评论不结束任务;点拒绝才走意见;IM 开聊会离开单据。本文按能点的 Tab 和底栏按钮来配。

▲ 中间是用车申请单的 Tab 线框;沟通留在「流程评论」,结论仍走同意或拒绝;批量通过不发评论


引言:同一张单上的字,职责不一样

把「备注」做成一个大文本框,什么都往里堆,上线后会出现这些错位:

痛点常见做法后果
问一句补充材料点拒绝并写理由流程被打回,发起人以为被否了
催一下附件打开 IM 或群下次打开单据,对话不在现场
业务说明写在评论审批人当意见读轨迹里找不到「为什么用这辆车」
通过时顺手评论只调了评论接口任务还停在当前节点
批量通过想带一句复用评论接口评论不推动流程,意见又没落轨迹

一句话:备注说明业务,评论用来沟通,意见用来做结论。三套 API、三个落点,不要共用一个 textarea。

RuoYi Office 的办理页路径从待办点「办理」进入,BasicForm 上有单据信息 / 审批信息 / 流程图 / 流程评论四个 Tab,底栏有通过、拒绝、评论。下面按这几个能点的位置拆。


一、先给出可直接抽取的定义

1.1 单据备注

单据备注,是业务表单上的字段,随草稿保存、随提交进入流程变量或业务表,不是 Flowable 的 Task Comment。用车单上叫「备注」,也可能叫「说明」「申请说明」。发起人在「单据信息」里填写,审批人通常只读。

它回答的是:这张业务单据本身要交代什么。例如「去机场接客户,车辆已协调」。

1.2 流程评论

流程评论,是挂在流程实例上的沟通记录。发表时只addComment,不complete任务,不改流程状态。类型为评论枚举里的"0"。前端底栏按钮文案是「评论」,Tab 名是「流程评论」。

它回答的是:办理过程中谁对谁说了什么,下次打开还能看见。

1.3 审批意见

审批意见,是点通过、拒绝、退回、转办等结论操作时写入的reason,会进任务轨迹,并通过评论类型"1"/"2"等出现在同一条时间线上。节点可配置「意见是否必填」。拒绝在多数节点上按必填校验。评论区填了 500 字,也不算拒绝理由。

它回答的是:这个节点为什么过、为什么驳。

1.4 IM 为什么不能替代评论

IM 是顶栏会话,消息在聊天里,不绑定当前processInstanceId适合拉群、语音、不在单据现场的人。审批现场要留痕,用流程评论。两者可以并存,不要做成「有 IM 就删评论 Tab」。


二、办理页你能看见三处入口

待办列表/bpm/task/todo点「办理」,进入带流程实例的详情。以用车申请单为例,抬头有单据编号、申请人、审批中状态。

▲ 用车申请单 OA101,单据信息里有「备注」;底栏「评论」和「通过 / 拒绝」分开;右侧 Tab 还能切到流程评论、审批信息

请对照这一屏上的三个位置:

位置文案写的是什么
单据信息 → 基本信息备注业务说明,跟草稿走
底栏按钮评论打开气泡,发表流程评论
Tab流程评论时间线,看历史沟通和系统记录
Tab审批信息进度、任务列表,意见在轨迹里
底栏按钮通过 / 拒绝结论 + 审批意见

列表页本身不承载这三套字,本文不再配待办表格图。要看效果,一律进办理详情。


三、底栏「评论」:发表但不往下走

底栏「评论」和「通过」并排,颜色却不同:通过是实心主按钮,评论是描边。点开后是气泡表单,字段只有「评论内容」,最多 500 字,必填。提交文案是「评论成功」,页面不关、任务还在。

前端核心顺序:

asyncfunctionhandleComment(){formLoading.value=true;try{awaitcommentFormRef.value.validate();constcontent=commentForm.message.trim();if(!content){message.warning('评论内容不能为空');return;}awaitcreateComment(runningTask.value.id,content);commentFormRef.value.resetFields();popOverVisible.value.comment=false;message.success('评论成功');window.dispatchEvent(newCustomEvent('bpm-comment-refresh'));}finally{formLoading.value=false;}}

注意三点:

  1. 必须带当前运行中任务的taskId。没有在办任务时这个按钮不应出现。
  2. 成功后派发bpm-comment-refresh。流程评论 Tab 不必整页刷新,监听这个事件重新拉列表即可。
  3. 没有调用通过、拒绝、complete。这是和审批意见的产品边界。

接口:POST /bpm/comment/create,body 为{ taskId, message }。权限是「有任务更新权限,或当前用户是该任务参与人」。已办、抄送进来的人,只要是参与人,也可以留言——这是催办、补充说明的常见路径。

▲ 通过是结论,拒绝是结论,评论是沟通;抄送 / 转办 / 委派 / 加签是另一类操作,也不要写进备注字段


四、Tab「流程评论」:一条时间线多种颜色

Tab 在 BasicForm 里,和单据信息、审批信息、流程图并列。有流程实例且有流程状态才渲染,草稿未提交看不到这页。

列表组件按实例 id 拉取:GET /bpm/comment/list-by-process-instance-id。空态文案是「暂无评论」。有数据时每人一条:头像、昵称、字典标签、所属任务名、时间、正文。

真机里打开「流程评论」,即便谁都还没点过底栏「评论」,也可能已经有一条系统写入的通过记录。用车单 OA101 上能看到发起人节点自动通过的那句「审批通过,原因是:发起人节点首次自动通过」。这恰好说明:这个 Tab 是实例上的时间线,不是纯聊天室。

▲ 标题「流程评论 共 1 条」;记录带任务名「发起人」;正文是通过模板,不是底栏留言

类型不是前端写死的。字典bpm_comment_type决定标签文案和颜色。时间线左侧圆点取类型名的第一个字,例如「评」「通」「不」。

type名字典型来源会不会结束任务
0评论底栏「评论」
1审批通过点通过,意见写入 format 模板是(普通通过路径)
2不通过点拒绝是,流程走向拒绝
3已取消系统取消流程结束
4退回退回上一节点任务回到指定节点
5 / 6委派发起 / 完成委派来回委派态变化
7转派转办办理人变化
8 / 9加签 / 减签加签操作审批人集合变化
10撤回发起人撤回视流程配置

所以「流程评论」Tab 里看到的不全是人肉留言。通过、拒绝也会作为带类型的记录出现在同一条时间线。产品上仍要分开入口:人肉留言走底栏评论,结论走通过/拒绝。读者在 Tab 里能按颜色区分,不需要再开一张「系统日志」页。

后端创建人肉评论只有一行业务:

@Override@Transactional(rollbackFor=Exception.class)publicvoidcreateComment(BpmCommentCreateReqVOreqVO){Tasktask=bpmTaskService.validateTaskExists(reqVO.getTaskId());createComment(task.getId(),task.getProcessInstanceId(),BpmCommentTypeEnum.COMMENT,reqVO.getMessage());}@OverridepublicvoidcreateComment(StringtaskId,StringprocessInstanceId,BpmCommentTypeEnumtype,Object...params){taskService.addComment(taskId,processInstanceId,type.getType(),type.formatComment(params));}

addComment是引擎提供的评论 API,不是complete。message 上限 500,空串直接校验失败。


五、审批意见:通过和拒绝才写 reason

点「通过」打开的气泡里,字段名是「审批意见」,校验读节点配置reasonRequire。为 true 时,空意见不能过,错误码语义是「审批意见不能为空」。为 false 时可以空着过,轨迹里意见可空。

点「拒绝」同样走意见框。很多流程会把拒绝配成必填,避免「手滑点红按钮、理由没有」。意见会按模板格式化,例如「审批不通过:原因是:{}」,再以类型"2"写入同一套 Comment。

通过路径里,意见和完成任务是绑在一起的:

BooleanreasonRequire=parseReasonRequire(bpmnModel,task.getTaskDefinitionKey());if(reasonRequire&&StrUtil.isEmpty(reqVO.getReason())){throwexception(TASK_REASON_REQUIRE);}updateTaskStatusAndReason(task.getId(),BpmTaskStatusEnum.APPROVE.getStatus(),reqVO.getReason());taskService.addComment(task.getId(),task.getProcessInstanceId(),BpmCommentTypeEnum.APPROVE.getType(),BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason()));Map<String,Object>variables=validateAndSetNextAssignees(task.getTaskDefinitionKey(),processVariables,bpmnModel,reqVO.getNextAssignees(),instance);runtimeService.setVariables(task.getProcessInstanceId(),variables);taskService.complete(task.getId(),variables,true);

和人肉评论对比:

动作写 Commentcomplete 任务改业务单据
底栏评论type=0,原文
通过type=1,带「审批通过,原因是」仅当前节点允许改的字段
拒绝type=2否(走拒绝流转)通常只读
改单据备注是,写业务表

「审批信息」Tab 展示进度时间线和任务列表,意见出现在节点卡片和审批记录表里,而不是备注字段里。不要让实施把审批信息 Tab 理解成「第二个评论区」。

▲ 发起人已通过,当前停在部门负责人;审批记录里能看到「审批通过 / 审批中」,和流程评论 Tab 是同一批事实的两种排版

进度条回答「走到哪了」,记录表回答「谁在这个节点、状态是什么」,流程评论时间线回答「当场说过什么、系统记过什么」。三块看的都是这张单,盒子不能并成一个 textarea。


六、和批量通过、抄送、IM 的边界

上一篇讲过待办批量通过:预检不合格的节点不能勾,提交时同实例串行。批量通过可以带一句统一审批意见,但不会去调评论接口。需要沟通的单,请从批量里拿出去单条办理,用底栏评论问清楚再点通过。

抄送是另一颗底栏按钮:选人 + 可选抄送理由。抄送理由也不是流程评论,不会出现在评论时间线的 type=0 里。被抄送人打开单据,应能在审批信息或抄送记录里看到,而不是去评论区找。

转办、委派、加签各自有理由字段,对应类型 5~9。它们改变办理人集合,属于结论类操作的近亲,仍然不是「问一句油费谁出」。

IM:顶栏开聊会离开当前单据。适合把不在审批链上的人拉进来。谈完如果形成对单据有约束的结论,应回到评论或意见里落一行,否则审计只看得到聊天记录、看不到流程实例。


七、权限与参与人

评论列表:有bpm:task:query或者当前用户是该流程实例参与人。发起人、已办、抄送都能回看,避免「只有当前办理人看得见沟通」。

发表评论:有bpm:task:update或者是该任务参与人。这样已办的人仍可补充一句「发票已补传」,不必把任务抢回来。

不要把评论接口做成匿名留言板。taskId必须能校验到真实任务,防止拿别人的实例 id 灌水。


八、前端 Tab 为什么要拆四页

BasicForm 的 Tab 不是装饰:

key名称什么时候出现内容
1单据信息始终业务表单 + 明细 + 附件
2审批信息已有实例且有状态进度时间线 + 任务列表
3流程图同上简易查看器高亮当前节点
4流程评论同上评论时间线

草稿未提交:没有实例,后三个 Tab 不出现,备注仍可写在单据信息里。这正好说明备注属于业务表单,不属于引擎 Comment。

四个 Tab 共用同一套页头(单据编号、申请人、状态)和同一套底栏。底栏按钮按任务状态显隐:运行中才有通过/拒绝/评论。已结束只留关闭、打印一类。

评论列表用窗口事件刷新,而不是 provide/inject 整树,是因为底栏和 Tab 不在同一个子树深处,事件更不容易漏。

列表组件自己按processInstanceId拉数。实例 id 变化(从待办 A 跳到待办 B)会watch重拉;组件挂载时监听bpm-comment-refresh,卸载时摘掉,避免开着多个详情页签时互相刷新错实例。空态用「暂无评论」,不要用表格的「暂无数据」——读者会以为附件表坏了。

每一行的结构固定,方便以后加「回复」也不用改时间线轴:

区块数据来源说明
左侧圆点字字典 label 截第一字「评 / 通 / 不」一眼分类型
圆点颜色字典 cssClass 或 colorType与 DictTag 同一套色
头像昵称用户接口按 comment.userId 拼接系统记录也可能是发起人
字典标签bpm_comment_type不要前端写死中文
任务胶囊historic task name发起人自动通过会显示「发起人」
时间comment.createTime按统一日期时间格式
正文fullMessage预格式化空白,长文本换行

OA101 那条「审批通过,原因是:发起人节点首次自动通过」出现在这里,是因为通过路径写了 type=1。它不是底栏评论,也不是单据备注。把这张图给实施看,比口头解释「时间线会混系统记录」有效。


九、数据结构:用引擎 Comment,不另起业务表

人肉评论和通过/拒绝记录,都落在 Flowable 的 ACT_HI_COMMENT(或等价历史评论表)。字段够用:任务 id、实例 id、类型、全文、时间、用户 id。列表接口再拼用户昵称、头像、任务名。

不要为「流程评论」再新建业务评论表,除非已经确定要附件、@人、已读、回复树。当前产品是扁平时间线,500 字纯文本,引擎历史评论足够。多一张表就要考虑和 type=1/2 的轨迹如何去重,读者会问「为什么通过记录出现两次」。

列表接口会把fullMessage、时间、任务、用户拼成 VO。前端不要自己解析模板字符串去猜「这是通过还是留言」——用type和字典标签。发起人自动通过那条,正文带「审批通过,原因是:」,类型却不是 0,字典色也不同。

若节点开启签名,通过气泡里还会多一块签图片。签名属于结论操作的附件,不会写进评论内容字段。评论气泡只有一个 textarea,刻意不放上传,避免把沟通区做成第二个附件栏。

请求体很小:

字段约束说明
taskId非空当前运行任务
message非空,最长 500原文,不做模板包装

通过/拒绝的 reason 走任务接口,不走/bpm/comment/create。创建接口内部写死 type=评论,调用方不能自己传「我是通过」。这避免了前端拿评论接口伪造一条「审批通过」。

管理端两个接口放在/bpm/comment下,和任务通过/拒绝不在同一个 Controller,这是有意的:评论容量、审计、限流以后可以单独加,不必改审批主路径。

方法路径谁能调做什么
GET/bpm/comment/list-by-process-instance-id任务查询权限或实例参与人按实例拉全部类型的 Comment 并拼用户、任务名
POST/bpm/comment/create任务更新权限或该任务参与人只写 type=0

列表接口不会在服务端按类型过滤。前端如果只想展示人肉留言,可以自己判断type === '0',但产品选择全量展示、用颜色区分。过滤会让发起人自动通过从时间线消失,实施会以为「发起节点没留痕」。

前端封装也很薄:createComment(taskId, message)只 POST 这两个字段;列表 GET 只要processInstanceId。不要在前端拼「审批通过,原因是:」——那是后端模板的事。

类型枚举和模板长这样,抄的时候不要把 type 改成整数——引擎 Comment 类型是字符串:

COMMENT("0","评论","{}"),APPROVE("1","审批通过","审批通过,原因是:{}"),REJECT("2","不通过","审批不通过:原因是:{}"),CANCEL("3","已取消","系统自动取消,原因是:{}"),RETURN("4","退回","任务被退回,原因是:{}"),TRANSFER("7","转派","[{}]将任务转派给[{}],转派理由为:{}"),WITHDRAW("10","撤回","任务被撤回,原因是:{}");

人肉评论的 format 是"{}",所以正文就是用户原话。通过记录会带前缀「审批通过,原因是:」,和底栏留言一眼能分开。流程评论 Tab 里那条发起人自动通过,走的就是 APPROVE 模板,不是有人在气泡里打了这些字。


十、设计对照

决策点错法本方案理由
问一句材料点拒绝底栏评论不中断流程
业务说明写进评论单据备注草稿阶段就能存
为什么驳只发评论拒绝 + reason轨迹和状态一致
沟通是否离开单据只用 IM评论留在实例上刷新还在
评论是否推动节点调用 complete只 addComment职责单一
类型全当普通留言字典 0~10时间线可着色
批量通过循环发评论统一意见走 approve评论不推动流程

十一、技术亮点

设计要点实现方式价值
入口分离Tab + 底栏按钮 + 表单字段用户不会点错盒子
评论不 completeTaskService.addComment沟通与结论解耦
结论也进时间线通过/拒绝写 type=1/2一个 Tab 看完沟通和结论
意见可配必填节点扩展属性 reasonRequire关键节点不能空过
500 字上限VO@Size(max=500)+ 输入框计数防止把附件正文贴进来
参与人可读可写权限 or 参与人表达式已办仍能补充说明
刷新事件bpm-comment-refreshTab 不必整页重载
批量不发评论批量只走 approve和资格预检那套一致

十二、FAQ

Q1:评论里写了「不同意」,流程会驳回吗?
不会。驳回必须点「拒绝」并填写审批意见。评论只留痕。

Q2:发起人还没提交,能不能评论?
没有流程实例就没有评论 Tab。业务说明写在单据备注里,保存草稿即可。

Q3:审批意见必填的节点,能否用评论凑数?
不能。通过接口读的是reason,不是最新一条 type=0。节点配了必填,空意见会直接失败。

Q4:为什么通过记录也会出现在流程评论 Tab?
同一套引擎 Comment。用字典颜色区分「评」和「通」,避免再做一张系统日志。入口仍然分开。

Q5:批量通过那句统一意见算评论吗?
算审批意见,走批量通过接口,不走/bpm/comment/create。需要先问清再过的单,不要放进批量。

Q6:移动端只有一个输入框怎么办?
应对齐 PC:备注在表单字段,评论在详情底栏或独立面板,通过/拒绝弹意见。不要把 App 做成「一个聊天框代替审批」。

Q7:发起人自动通过为什么出现在评论里?
发起人节点首次自动通过会写一条 type=1 的评论,模板是「审批通过,原因是:{}」。它不是有人点了底栏评论。时间线要包含系统结论,审计才完整。

Q8:已结束的流程还能评论吗?
底栏评论按钮跟着运行中任务走,结束后通常只留关闭、打印。历史沟通仍可在流程评论 Tab 只读回看。不要在结束后再开放留言,除非产品明确要「归档后答疑」。

Q9:流程图 Tab 和评论有关系吗?
没有。流程图只看节点走到哪。不要把评论气泡画到 BPMN 图上,手机上点不准,PC 上也和「审批信息」进度条重复。

Q10:抄送理由会进流程评论吗?
不会。抄送是独立按钮和独立记录。被抄送人打开单据,应在审批信息或抄送区看理由。需要全员可见的说明,请再发一条流程评论。


十三、快速体验

在线演示:https://ruoyioffice.com/web/(账号 admin / admin123)

建议路径:

  1. 流程中心 → 待办任务 → 任选一条点「办理」(例如用车申请单)
  2. 在「单据信息」找到备注字段,确认它和底栏不是同一个输入框
  3. 点底栏「评论」,写一句不影响结论的话,提交后任务仍在
  4. 打开「流程评论」Tab:即便还没人肉留言,也可能看到发起人自动通过那条「审批通过,原因是:…」
  5. 点底栏「评论」再发一条,时间线应变成两条,颜色标签不同
  6. 打开「审批信息」Tab,看进度条和审批记录表,对照评论 Tab 是同一批事实的另一种排版
  7. 点「拒绝」看意见框(可取消,不必真驳),对比评论气泡只有内容、没有「驳回」语义
  8. (可选)待办列表试批量通过:弹窗里是统一审批意见,不会出现评论时间线入口

配节点时记得打开流程设计器,找到「审批意见是否必填」。关键财务节点建议打开;会签里随便问一句的节点可以关掉,避免人人都要编一句「同意」才能过。必填校验的是通过/拒绝的reason,与评论内容无关。

简易设计器和 BPMN 设计器都要能改到这个开关,不要只做在其中一套。节点 JSON 里对应扩展属性,列表预检批量通过时也会读:意见必填的节点不能勾批量。这和「评论区有没有字」仍然无关——批量看的是 reasonRequire,不是最新一条 type=0。

源码仓库:GitHub:https://github.com/yuqing2026/ruoyi-office | GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office | Gitee:https://gitee.com/yqzy1688/ruoyi-office


结语

审批现场最贵的不是再做一个输入框,而是让「问一句」和「驳回」抢同一个提交按钮。备注跟业务草稿走,评论跟流程实例走且不 complete,意见跟通过/拒绝走并改状态。IM 留给不在链上的人。把这三个盒子配清楚,待办积压时才敢让领导先评论、后结论,而不至于误驳一单用车。

同一套拆分还可以用在报销补票、用印问章面、合同问条款:沟通先留在实例上,条款变更再走退回或拒绝。

现场把三个盒子配错,通常是这五种,可以对着办理页逐项排除:

现场说法实际点了哪应该怎么做
「我评论了不同意,单怎么还在?」底栏评论要驳回请点拒绝
「备注里写了发票号,审批人说没看见」单据备注,审批人看的是评论 Tab补一句流程评论,或把发票放到附件
「通过必须填意见太烦」节点打开了意见必填非关键节点在设计器关掉 reasonRequire
「群里说了可以过,系统没记录」只用了 IM回到底栏评论或通过意见落一行
「批量过了但评论区没有」批量通过只写审批意见符合预期;要沟通请单条办理

配置侧再记两个开关:节点「审批意见是否必填」、底栏按钮显隐(运行中任务才有评论)。不要把评论按钮配进已结束的查看页,避免归档单据被灌水。

待办列表、站内信、企微通知里,摘要应继续用单据编号、节点名、发起人,不要截评论最后一句当待办标题。评论可能是「油费谁出」,出现在待办卡片上会像催办恐吓。待办字段怎么留,和评论不是同一件事。

打印审批单时,常见需求是把审批意见打进表格,而不是把全部 type=0 留言打进去。意见在审批记录里,留言在评论 Tab。套打模板应绑定「审批意见」字段;若客户坚持「沟通也要进附件 PDF」,做成可选页,默认关闭。

移动端对齐时,底栏仍应分开「通过 / 拒绝 / 评论」。小屏不要把三个入口收进同一个 ActionSheet 还共用一个输入框。PC 上已经证明分盒能减少误驳;App 上更需要分盒,因为误触面积更大。


💡想要体验 RuoYi Office 的强大功能?

🌐在线演示:https://ruoyioffice.com/web/(账号 admin / admin123)

📦源码仓库:GitHub:https://github.com/yuqing2026/ruoyi-office | GitCode:https://gitcode.com/zhouzhongyan/ruoyi-office | Gitee:https://gitee.com/yqzy1688/ruoyi-office

💬技术咨询:添加微信17156169080,备注「RuoYi Office」

如果觉得不错,请给个 Star 支持一下!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询