
一、前言
在使用 Flowable 7.0 开发工作流审批系统时,常见的审核操作不仅仅是“同意”和“拒绝”,还包括转办、委派、认领、取消认领、退回、驳回、撤销等操作。
这些操作看起来相似,但在业务含义、流程是否继续流转、任务办理人是否变化、流程实例是否结束、历史记录如何保存等方面都有明显区别。
本文结合 Flowable 7.0 的实际开发场景,对常见审核状态进行详细说明,方便在 OA、审批流、用章申请、报销申请、合同审批、请假审批等系统中使用。
二、Flowable 审核状态总览
常见审核操作可以分为以下几类:
| 操作 | 是否完成当前任务 | 是否改变办理人 | 是否继续流程 | 是否结束流程 | 常用 API |
|---|---|---|---|---|---|
| 通过 | 是 | 否 | 是 | 否 | taskService.complete |
| 驳回 | 是 | 否 | 一般否/或走驳回线 | 可结束/可退回 | complete + 流程变量 |
| 退回 | 是 | 否 | 回到指定节点 | 否 | changeState / 自定义跳转 |
| 转办 | 否 | 是 | 否 | 否 | taskService.setAssignee |
| 委派 | 否 | 是 | 否 | 否 | taskService.delegateTask |
| 完成委派 | 否/部分完成 | 是,交还原负责人 | 否 | 否 | taskService.resolveTask |
| 认领 | 否 | 是 | 否 | 否 | taskService.claim |
| 取消认领 | 否 | 是,清空办理人 | 否 | 否 | taskService.unclaim |
| 撤销 | 视业务而定 | 否 | 否 | 通常结束 | runtimeService.deleteProcessInstance |
| 取消 | 视业务而定 | 否 | 否 | 通常结束 | deleteProcessInstance / 自定义状态 |
三、通过
1. 业务含义
“通过”是最常见的审批操作,表示当前审批人同意当前节点的申请内容,当前任务完成,流程继续向下一个节点流转。
例如:
-
科室负责人审核通过
-
分管领导审核通过
-
财务审核通过
-
老板最终审批通过
2. 流程表现
当前任务会被完成,Flowable 会根据 BPMN 流程图中的连线条件,自动流转到下一个节点。
如果当前节点是最后一个审批节点,流程实例结束。
3. 常用 API
taskService.complete(taskId, variables);
4. 示例代码
Map<String, Object> variables = new HashMap<>();
variables.put("approved", true);
variables.put("approvalStatus", "PASS");
variables.put("approvalOpinion", "同意");
taskService.complete(taskId, variables);
5. 数据变化
通过后,通常会产生以下变化:
-
当前任务从运行时任务表中删除
-
当前任务进入历史任务表
-
流程继续流转到下一个节点
-
审批意见保存到流程变量或业务审批记录表
-
如果没有下一个节点,流程结束
常见相关表:
ACT_RU_TASK 当前运行任务表
ACT_HI_TASKINST 历史任务表
ACT_HI_ACTINST 历史节点表
ACT_HI_VARINST 历史变量表
ACT_RU_VARIABLE 运行时变量表
6. 适用场景
通过适合正常审批场景,例如:
-
申请内容无问题
-
当前节点审批人确认通过
-
流程继续进入下一审批环节
四、驳回
1. 业务含义
“驳回”表示当前审批人不同意申请内容,流程不再按照正常审批路径继续向后流转。
驳回通常有两种业务设计:
第一种:驳回后流程直接结束。
第二种:驳回后流程退回申请人修改,修改后可以重新提交。
2. 驳回和退回的区别
很多系统中,“驳回”和“退回”容易混用。
建议区分如下:
| 类型 | 含义 | 流程结果 |
|---|---|---|
| 驳回 | 审批不同意,申请失败 | 流程结束或进入驳回结束节点 |
| 退回 | 审批人要求修改材料 | 回到申请人或上一个节点 |
也就是说,驳回更偏向“否决”,退回更偏向“修改后再提交”。
3. 常用实现方式
方式一:通过流程变量走驳回线
在 BPMN 流程图中配置排他网关,根据变量判断走通过线还是驳回线。
Map<String, Object> variables = new HashMap<>();
variables.put("approved", false);
variables.put("approvalStatus", "REJECT");
variables.put("approvalOpinion", "材料不完整,驳回申请");
taskService.complete(taskId, variables);
BPMN 条件示例:
${approved == true} -> 通过
${approved == false} -> 驳回
方式二:直接终止流程实例
如果业务要求驳回后流程直接结束,也可以删除流程实例。
runtimeService.deleteProcessInstance(processInstanceId, "审批驳回,流程结束");
4. 建议状态值
REJECT
驳回
5. 适用场景
驳回适合以下场景:
-
申请内容明显不符合要求
-
审批人不同意该事项
-
不允许申请人继续修改提交
-
流程需要终止
五、退回
1. 业务含义
“退回”表示当前审批人认为申请内容需要修改,但不是彻底否决。
退回一般会把流程退回到:
-
发起人节点
-
上一个审批节点
-
指定审批节点
-
重新填写节点
例如:
-
材料缺失,退回申请人补充
-
金额填写错误,退回发起人修改
-
科室负责人填写意见不完整,退回科室负责人重新处理
2. 退回和驳回的区别
| 对比项 | 退回 | 驳回 |
|---|---|---|
| 业务含义 | 要求修改 | 不同意 |
| 流程是否结束 | 通常不结束 | 通常结束 |
| 是否允许再次提交 | 允许 | 不一定 |
| 常见目标节点 | 发起人/上一节点 | 结束节点/驳回节点 |
| 用户感知 | 修改后重新提交 | 申请失败 |
3. Flowable 实现思路
Flowable 原生没有一个简单的 rollback 方法专门表示退回,实际项目中通常使用以下方式:
方式一:流程图中提前设计退回线
在 BPMN 中通过排他网关配置“通过”和“退回”两条线。
Map<String, Object> variables = new HashMap<>();
variables.put("approvalStatus", "RETURN");
variables.put("approvalOpinion", "请补充附件后重新提交");
taskService.complete(taskId, variables);
然后 BPMN 中配置条件:
${approvalStatus == 'PASS'} -> 下一审批节点
${approvalStatus == 'RETURN'} -> 申请人修改节点
这种方式最稳定,也最容易维护。
方式二:动态跳转到指定节点
在复杂场景中,可以使用动态改变流程状态的方式,将当前任务跳转到指定节点。
伪代码示例:
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(processInstanceId)
.moveActivityIdTo(currentActivityId, targetActivityId)
.changeState();
这种方式适合自由退回、退回任意节点等复杂审批场景。
4. 建议状态值
RETURN
退回
5. 注意事项
退回操作建议记录以下信息:
当前节点ID
当前节点名称
当前审批人
退回目标节点ID
退回目标节点名称
退回原因
退回时间
流程实例ID
业务ID
否则后续查看流程轨迹时,很难知道是谁退回、退回到哪里、为什么退回。
六、转办
1. 业务含义
“转办”表示当前任务由当前办理人转交给另一个人办理。
转办后,原办理人不再处理该任务,新办理人成为当前任务的实际办理人。
例如:
-
张三当前有一个审批任务
-
张三因为请假,把任务转给李四
-
转办后,李四负责审批该任务
-
张三不再拥有这个待办任务
2. 流程表现
转办不会完成当前任务,也不会推动流程向下流转。
它只改变当前任务的办理人。
3. 常用 API
taskService.setAssignee(taskId, newUserId);
4. 示例代码
String taskId = "任务ID";
String newAssignee = "lisi";
taskService.setAssignee(taskId, newAssignee);
5. 数据变化
转办后,当前任务仍然存在,只是 ASSIGNEE_ 字段发生变化。
相关表:
ACT_RU_TASK.ASSIGNEE_
ACT_HI_TASKINST.ASSIGNEE_
6. 转办特点
不完成任务
不进入下一节点
不改变流程路线
只改变当前任务办理人
原办理人失去待办权限
新办理人获得待办任务
7. 适用场景
转办适合以下场景:
-
当前审批人无权限处理
-
当前审批人请假
-
当前审批人认为应该由别人审批
-
任务分配错误,需要改派
8. 转办建议记录业务日志
Flowable 自身只会修改任务办理人,业务系统最好额外记录转办日志。
建议记录字段:
taskId
processInstanceId
businessKey
oldAssignee
newAssignee
transferReason
transferTime
operator
9. 转办和委派的区别
| 对比项 | 转办 | 委派 |
|---|---|---|
| 原办理人是否还负责 | 不负责 | 仍然负责 |
| 新办理人处理后是否回到原办理人 | 不会 | 会 |
| 是否改变 assignee | 是 | 是 |
| 是否设置 owner | 一般不设置 | 通常设置原办理人为 owner |
| 适合场景 | 彻底交给别人 | 请别人协助处理 |
七、委派
1. 业务含义
“委派”表示当前办理人临时把任务交给别人处理,但任务最终责任人仍然是原办理人。
被委派人处理完成后,任务会回到原办理人,由原办理人继续最终审批。
例如:
-
张三是当前审批人
-
张三不确定某个问题,让李四协助确认
-
张三将任务委派给李四
-
李四处理后,任务回到张三
-
张三再最终审批通过或驳回
2. 流程表现
委派不会完成当前任务,也不会推动流程流转。
它只是把当前任务临时交给被委派人。
3. 常用 API
taskService.delegateTask(taskId, delegateUserId);
4. 示例代码
String taskId = "任务ID";
String delegateUserId = "lisi";
taskService.delegateTask(taskId, delegateUserId);
5. 委派后的任务状态
委派后,任务通常会出现以下变化:
owner = 原办理人
assignee = 被委派人
delegationState = PENDING
含义如下:
| 字段 | 含义 |
|---|---|
| owner | 原始负责人 |
| assignee | 当前被委派处理人 |
| delegationState | 委派状态 |
6. 被委派人处理完成
被委派人不能直接使用普通的 complete 结束任务,而应该使用:
taskService.resolveTask(taskId, variables);
示例:
Map<String, Object> variables = new HashMap<>();
variables.put("delegateOpinion", "已核实,建议通过");
taskService.resolveTask(taskId, variables);
执行后,任务会回到原办理人。
7. 原办理人最终审批
任务回到原办理人后,原办理人再执行:
taskService.complete(taskId, variables);
8. 委派适用场景
委派适合以下场景:
-
需要其他人协助确认
-
需要专业人员补充意见
-
领导让下属先处理,但最终仍由领导审批
-
审批人保留最终决定权
9. 委派和转办的核心区别
转办:我不管了,彻底交给你。
委派:你先帮我看看,最后还要回到我这里。
八、认领
1. 业务含义
“认领”通常用于候选人或候选组任务。
当一个任务没有明确办理人,而是分配给多个候选人或一个候选组时,需要某个人主动认领该任务。
认领后,该任务就归认领人处理。
例如:
-
一个任务分配给“财务组”
-
财务组有 A、B、C 三个人
-
A 点击认领
-
任务办理人变成 A
-
B、C 不再看到该任务为可办理状态
2. 流程表现
认领不会完成任务,也不会推动流程流转。
认领只是把“候选任务”变成“个人待办任务”。
3. 常用 API
taskService.claim(taskId, userId);
4. 示例代码
String taskId = "任务ID";
String userId = "zhangsan";
taskService.claim(taskId, userId);
5. 认领前后变化
认领前:
assignee = null
candidateUsers / candidateGroups = 有候选人或候选组
认领后:
assignee = zhangsan
6. 适用场景
认领适合以下场景:
-
多人共享一个任务池
-
谁先处理谁认领
-
客服工单
-
财务审核池
-
运维任务池
-
行政审批任务池
7. 注意事项
认领前最好判断任务是否已经被别人认领。
伪代码:
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
if (task.getAssignee() != null) {
throw new RuntimeException("任务已被其他人认领");
}
taskService.claim(taskId, userId);
九、取消认领
1. 业务含义
“取消认领”表示认领人放弃当前任务,任务重新回到候选任务池。
取消认领后,其他候选人可以重新认领该任务。
2. 常用 API
taskService.unclaim(taskId);
或者:
taskService.claim(taskId, null);
3. 示例代码
taskService.unclaim(taskId);
4. 流程表现
取消认领不会完成任务,不会推动流程流转。
它只是把任务办理人清空。
取消认领后:
assignee = null
如果任务仍然保留候选组或候选人,则其他人可以继续认领。
5. 适用场景
取消认领适合以下场景:
-
认领人发现自己无法处理
-
认领错误
-
工作量过大,需要释放任务
-
管理员要求重新分配
6. 注意事项
取消认领时要校验当前用户是否为任务认领人,避免别人取消别人的任务。
伪代码:
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
if (!currentUserId.equals(task.getAssignee())) {
throw new RuntimeException("只能取消自己认领的任务");
}
taskService.unclaim(taskId);
十、撤销
1. 业务含义
“撤销”一般是由流程发起人主动取消自己发起的流程。
例如:
-
发起人提交了用章申请
-
发现信息填写错误
-
在审批人未处理前,发起人主动撤销
-
流程结束或回到草稿状态
2. 撤销和驳回的区别
| 对比项 | 撤销 | 驳回 |
|---|---|---|
| 操作人 | 通常是发起人 | 通常是审批人 |
| 业务含义 | 发起人主动取消 | 审批人不同意 |
| 流程结果 | 通常结束 | 结束或退回 |
| 是否代表审批失败 | 不一定 | 是 |
3. 常用实现方式
方式一:直接删除流程实例
runtimeService.deleteProcessInstance(processInstanceId, "发起人撤销申请");
这种方式会终止正在运行的流程实例。
方式二:走撤销流程线
如果希望流程图上能看到撤销节点,可以在 BPMN 中设计“撤销”路径。
例如:
申请人提交 -> 审批中 -> 发起人撤销 -> 撤销结束
然后通过变量控制流程走向。
4. 建议状态值
CANCEL
撤销
或者:
REVOKE
撤销
5. 撤销权限建议
一般建议只有以下人员可以撤销:
流程发起人
系统管理员
特殊授权人员
并且需要限制撤销条件:
审批人未处理前可以撤销
流程未结束前可以撤销
已归档流程不允许撤销
已完成流程不允许撤销
十一、取消
1. 业务含义
“取消”通常表示系统或管理员主动取消流程。
取消和撤销类似,但操作主体不同。
撤销:一般是发起人主动操作
取消:一般是管理员或系统操作
例如:
-
管理员发现流程发起错误,取消流程
-
业务数据被删除,自动取消流程
-
重复发起的流程被系统取消
-
流程长时间异常,管理员手动取消
2. 常用 API
runtimeService.deleteProcessInstance(processInstanceId, "管理员取消流程");
3. 建议状态值
CANCELLED
已取消
4. 注意事项
取消流程时,建议同步更新业务表状态。
例如业务表:
update biz_apply
set process_status = 'CANCELLED',
update_time = now()
where process_instance_id = #{processInstanceId};
否则 Flowable 流程实例已经结束,但业务表仍然显示“审批中”,会造成数据不一致。
十二、加签
1. 业务含义
“加签”表示在当前审批流程中临时增加一个或多个审批人。
加签一般分为:
前加签
后加签
并行加签
2. 前加签
前加签表示当前审批人审批之前,先让其他人审批。
示例:
当前审批人 A
A 前加签 B
B 审批完成后,再回到 A
3. 后加签
后加签表示当前审批人审批之后,再增加一个审批人。
示例:
当前审批人 A
A 审批完成后,流转到临时审批人 B
B 审批完成后,再继续原流程
4. 并行加签
并行加签表示同时增加多个人共同审批。
示例:
当前节点需要 A 审批
临时增加 B、C 同时审批
A、B、C 都审批完成后,流程继续
5. Flowable 实现建议
加签属于复杂动态流程调整,建议根据业务复杂度选择:
| 方式 | 说明 |
|---|---|
| BPMN 预留加签节点 | 稳定、清晰 |
| 动态多实例任务 | 适合多人会签 |
| changeState 动态跳转 | 灵活,但维护复杂 |
| 自定义业务任务表 | 最灵活,适合复杂 OA |
十三、会签
1. 业务含义
会签表示多个审批人共同审批同一个节点。
常见会签规则:
全部通过才通过
任意一人通过即通过
超过半数通过即通过
一人驳回即驳回
2. Flowable 实现方式
Flowable 中通常使用多实例用户任务实现会签。
多实例类型包括:
并行多实例
串行多实例
3. 并行会签
所有审批人同时收到任务。
例如:
A、B、C 同时审批
三人全部完成后进入下一节点
4. 串行会签
审批人按顺序依次审批。
例如:
A 审批完成 -> B 审批 -> C 审批
5. 常用变量
nrOfInstances 总实例数
nrOfCompletedInstances 已完成实例数
nrOfActiveInstances 当前活动实例数
loopCounter 当前循环下标
十四、常见状态字段设计
在实际业务系统中,不建议只依赖 Flowable 自身表判断业务状态,建议在业务表中维护流程状态字段。
1. 业务表状态字段
process_status varchar(50) comment '流程状态'
2. 推荐状态枚举
public enum ProcessStatusEnum {
DRAFT("DRAFT", "草稿"),
RUNNING("RUNNING", "审批中"),
PASS("PASS", "审批通过"),
REJECT("REJECT", "驳回"),
RETURN("RETURN", "退回"),
REVOKE("REVOKE", "撤销"),
CANCELLED("CANCELLED", "已取消"),
TERMINATED("TERMINATED", "已终止");
private final String code;
private final String name;
ProcessStatusEnum(String code, String name) {
this.code = code;
this.name = name;
}
}
3. 任务操作状态枚举
public enum TaskOperateTypeEnum {
COMPLETE("COMPLETE", "通过"),
REJECT("REJECT", "驳回"),
RETURN("RETURN", "退回"),
TRANSFER("TRANSFER", "转办"),
DELEGATE("DELEGATE", "委派"),
RESOLVE("RESOLVE", "完成委派"),
CLAIM("CLAIM", "认领"),
UNCLAIM("UNCLAIM", "取消认领"),
REVOKE("REVOKE", "撤销"),
CANCEL("CANCEL", "取消");
private final String code;
private final String name;
TaskOperateTypeEnum(String code, String name) {
this.code = code;
this.name = name;
}
}
十五、审批操作日志表设计
为了方便展示审批记录,建议单独设计审批日志表,不要完全依赖 Flowable 历史表。
1. 审批日志表字段建议
CREATE TABLE wf_task_approve_record (
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
process_instance_id VARCHAR(64) NOT NULL COMMENT '流程实例ID',
task_id VARCHAR(64) DEFAULT NULL COMMENT '任务ID',
task_name VARCHAR(255) DEFAULT NULL COMMENT '任务名称',
business_key VARCHAR(100) DEFAULT NULL COMMENT '业务Key',
operate_type VARCHAR(50) NOT NULL COMMENT '操作类型:通过、驳回、退回、转办、委派等',
operate_user_id VARCHAR(64) NOT NULL COMMENT '操作人ID',
operate_user_name VARCHAR(100) DEFAULT NULL COMMENT '操作人名称',
old_assignee VARCHAR(64) DEFAULT NULL COMMENT '原办理人',
new_assignee VARCHAR(64) DEFAULT NULL COMMENT '新办理人',
target_activity_id VARCHAR(100) DEFAULT NULL COMMENT '目标节点ID',
target_activity_name VARCHAR(255) DEFAULT NULL COMMENT '目标节点名称',
comment VARCHAR(1000) DEFAULT NULL COMMENT '审批意见',
operate_time DATETIME NOT NULL COMMENT '操作时间',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) COMMENT='流程审批操作记录表';
2. 为什么要设计审批日志表
原因如下:
Flowable 历史表更偏引擎层,不完全适合业务展示
审批意见、转办原因、退回原因需要单独保存
前端审批轨迹需要统一展示
方便后期统计审批效率
方便排查流程问题
方便做待办、已办、我的申请展示
十六、常见操作代码汇总
1. 审批通过
public void pass(String taskId, String opinion) {
Map<String, Object> variables = new HashMap<>();
variables.put("approvalStatus", "PASS");
variables.put("approved", true);
variables.put("approvalOpinion", opinion);
taskService.complete(taskId, variables);
}
2. 驳回
public void reject(String taskId, String opinion) {
Map<String, Object> variables = new HashMap<>();
variables.put("approvalStatus", "REJECT");
variables.put("approved", false);
variables.put("approvalOpinion", opinion);
taskService.complete(taskId, variables);
}
3. 转办
public void transfer(String taskId, String newAssignee, String reason) {
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
if (task == null) {
throw new RuntimeException("任务不存在");
}
String oldAssignee = task.getAssignee();
taskService.setAssignee(taskId, newAssignee);
// 保存转办日志
// oldAssignee -> newAssignee
}
4. 委派
public void delegate(String taskId, String delegateUserId, String reason) {
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
if (task == null) {
throw new RuntimeException("任务不存在");
}
taskService.delegateTask(taskId, delegateUserId);
// 保存委派日志
}
5. 完成委派
public void resolveDelegateTask(String taskId, String opinion) {
Map<String, Object> variables = new HashMap<>();
variables.put("delegateOpinion", opinion);
taskService.resolveTask(taskId, variables);
}
6. 认领
public void claim(String taskId, String userId) {
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
if (task == null) {
throw new RuntimeException("任务不存在");
}
if (task.getAssignee() != null) {
throw new RuntimeException("任务已被认领");
}
taskService.claim(taskId, userId);
}
7. 取消认领
public void unclaim(String taskId, String currentUserId) {
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
if (task == null) {
throw new RuntimeException("任务不存在");
}
if (!currentUserId.equals(task.getAssignee())) {
throw new RuntimeException("只能取消自己认领的任务");
}
taskService.unclaim(taskId);
}
8. 撤销流程
public void revoke(String processInstanceId, String reason) {
runtimeService.deleteProcessInstance(processInstanceId, reason);
// 同步更新业务表状态为 REVOKE
}
十七、前端按钮显示建议
审批系统中,不同状态下应该显示不同按钮。
1. 我的待办
通过
驳回
退回
转办
委派
2. 候选任务
认领
3. 已认领任务
取消认领
通过
驳回
退回
4. 我的申请
撤销
查看进度
5. 管理员
取消流程
强制转办
查看流程变量
查看流程图
十八、推荐业务状态流转
1. 正常通过
草稿 -> 审批中 -> 审批通过
2. 驳回结束
草稿 -> 审批中 -> 驳回
3. 退回修改
草稿 -> 审批中 -> 退回修改 -> 重新提交 -> 审批中 -> 审批通过
4. 发起人撤销
草稿 -> 审批中 -> 已撤销
5. 转办
审批中 -> 转办给其他人 -> 审批中
6. 委派
审批中 -> 委派给其他人 -> 完成委派 -> 回到原审批人 -> 审批中
十九、开发注意事项
1. 不要把转办当成通过
转办只是换人处理,不会推动流程。
错误理解:
转办 = 当前人处理完了
正确理解:
转办 = 当前任务换一个办理人
2. 不要把委派当成转办
委派后任务最终还要回到原负责人。
委派 = 临时交给别人处理
转办 = 彻底交给别人处理
3. 退回最好在流程图中明确设计
如果业务比较固定,建议在 BPMN 中画出退回线。
优点:
流程清晰
历史轨迹清晰
方便维护
不容易出错
4. 自由退回要谨慎使用
动态跳转虽然灵活,但容易导致流程图轨迹复杂,后期维护成本较高。
5. 审批意见建议单独保存
不要只依赖流程变量保存审批意见。
建议同时保存到业务审批记录表,方便前端展示和后期统计。
6. 业务表状态必须同步更新
Flowable 只管理流程,业务系统仍然需要维护自己的业务状态。
例如:
审批中
审批通过
驳回
退回
撤销
取消
否则会出现流程已结束,但业务表仍然显示审批中的问题。
二十、总结
Flowable 7.0 中常见审核操作可以简单理解为:
通过:当前任务完成,流程继续向后走。
驳回:审批不同意,流程失败或进入驳回路径。
退回:要求修改,流程回到申请人或指定节点。
转办:当前任务换人处理,原办理人不再负责。
委派:临时交给别人处理,处理完还要回到原办理人。
认领:候选任务被某个人领取,变成个人待办。
取消认领:放弃已认领任务,任务回到候选池。
撤销:发起人主动取消流程。
取消:管理员或系统取消流程。
在实际项目中,建议做到以下几点:
1. Flowable 负责流程流转。
2. 业务表负责业务状态。
3. 审批记录表负责展示审批轨迹。
4. 流程变量负责控制流程走向。
5. 转办、委派、退回、驳回必须区分清楚。
只有把这些状态区分清楚,工作流系统的待办、已办、我的申请、审批记录、流程图追踪才能稳定、清晰、易维护。
1088



被折叠的 条评论
为什么被折叠?



