BPM:完善 task 在通过、不通过、取消等情况下的 reason 和 comment 逻辑

This commit is contained in:
YunaiV 2024-03-18 22:43:58 +08:00
parent bc4427aca5
commit 0a7f94dd5f
9 changed files with 100 additions and 185 deletions

View File

@ -13,10 +13,10 @@ import lombok.Getter;
@AllArgsConstructor
public enum BpmCommentTypeEnum {
APPROVE("1", "审批通过", ""), // 理由直接使用用户的评论
REJECT("2", "不通过", ""),
CANCEL("3", "已取消", ""),
BACK("4", "退回", "{}"), // 直接使用用户填写的原因
APPROVE("1", "审批通过", "审批通过,原因是:{}"),
REJECT("2", "不通过", "审批不通过:原因是:{}"),
CANCEL("3", "已取消", "系统自动取消,原因是:{}"),
RETURN("4", "退回", "任务被退回,原因是:{}"),
DELEGATE_START("5", "委派发起", "[{}]将任务委派给[{}],委派理由为:{}"),
DELEGATE_END("6", "委派完成", "[{}]完成委派任务,任务重新回到[{}]手中,审批建议为:{}"),
TRANSFER("7", "转派", "[{}]将任务转派给[{}],转派理由为:{}"),

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.bpm.enums.task;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 流程实例/任务的删除原因枚举
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum BpmDeleteReasonEnum {
// ========== 流程实例的独有原因 ==========
REJECT_TASK("审批不通过任务,原因:{}"), // 场景用户审批不通过任务修改文案时需要注意 isRejectReason 方法
CANCEL_PROCESS_INSTANCE("用户主动取消流程,原因:{}"), // 场景用户主动取消流程
// ========== 流程任务的独有原因 ==========
CANCEL_SYSTEM("系统自动取消"), // 场景非常多比如说1多任务审批已经满足条件无需审批该任务2流程实例被取消无需审批该任务等等
;
private final String reason;
/**
* 格式化理由
*
* @param args 参数
* @return 理由
*/
public String format(Object... args) {
return StrUtil.format(reason, args);
}
// ========== 逻辑 ==========
public static boolean isRejectReason(String reason) {
return StrUtil.startWith(reason, "审批不通过任务,原因:");
}
}

View File

@ -1,58 +0,0 @@
package cn.iocoder.yudao.module.bpm.enums.task;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 流程实例的删除原因
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum BpmProcessInstanceDeleteReasonEnum {
REJECT_TASK("不通过任务,原因:{}"), // 修改文案时需要注意 isRejectReason 方法
CANCEL_TASK("主动取消任务,原因:{}"),
// ========== 流程任务的独有原因 ==========
MULTI_TASK_END("系统自动取消,原因:多任务审批已经满足条件,无需审批该任务"), // 多实例满足 condition 而结束时其它任务实例任务会被取消对应的删除原因是 MI_END
;
private final String reason;
/**
* 格式化理由
*
* @param args 参数
* @return 理由
*/
public String format(Object... args) {
return StrUtil.format(reason, args);
}
// ========== 逻辑 ==========
public static boolean isRejectReason(String reason) {
return StrUtil.startWith(reason, "不通过任务,原因:");
}
/**
* Flowable 的删除原因翻译成对应的中文原因
*
* @param reason 原始原因
* @return 原因
*/
public static String translateReason(String reason) {
if (StrUtil.isEmpty(reason)) {
return reason;
}
switch (reason) {
case "MI_END": return MULTI_TASK_END.getReason();
default: return reason;
}
}
}

View File

@ -36,12 +36,12 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent
@Override
protected void processCancelled(FlowableCancelledEvent event) {
processInstanceService.updateProcessInstanceExtCancel(event);
processInstanceService.updateProcessInstanceWhenCancel(event);
}
@Override
protected void processCompleted(FlowableEngineEntityEvent event) {
processInstanceService.updateProcessInstanceExtComplete((ProcessInstance)event.getEntity());
processInstanceService.updateProcessInstanceWhenApprove((ProcessInstance)event.getEntity());
}
}

View File

@ -31,7 +31,6 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
@Resource
@Lazy // 解决循环依赖
private BpmTaskService taskService;
@Resource
@Lazy // 解决循环依赖
private BpmActivityService activityService;
@ -39,7 +38,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
public static final Set<FlowableEngineEventType> TASK_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
.add(FlowableEngineEventType.TASK_CREATED)
.add(FlowableEngineEventType.TASK_ASSIGNED)
.add(FlowableEngineEventType.TASK_COMPLETED)
// .add(FlowableEngineEventType.TASK_COMPLETED) // 由于审批通过时已经记录了 task status 为通过所以不需要监听了
.add(FlowableEngineEventType.ACTIVITY_CANCELLED)
.build();
@ -49,12 +48,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
@Override
protected void taskCreated(FlowableEngineEntityEvent event) {
taskService.createTaskExt((Task) event.getEntity());
}
@Override
protected void taskCompleted(FlowableEngineEntityEvent event) {
taskService.updateTaskExtComplete((Task)event.getEntity());
taskService.updateTaskStatusWhenCreated((Task) event.getEntity());
}
@Override
@ -74,7 +68,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
if (StrUtil.isEmpty(activity.getTaskId())) {
return;
}
taskService.updateTaskExtCancel(activity.getTaskId());
taskService.updateTaskStatusWhenCanceled(activity.getTaskId());
});
}

View File

@ -136,14 +136,14 @@ public interface BpmProcessInstanceService {
*
* @param event 流程取消事件
*/
void updateProcessInstanceExtCancel(FlowableCancelledEvent event);
void updateProcessInstanceWhenCancel(FlowableCancelledEvent event);
/**
* 更新 ProcessInstance 拓展记录为完成
*
* @param instance 流程任务
*/
void updateProcessInstanceExtComplete(ProcessInstance instance);
void updateProcessInstanceWhenApprove(ProcessInstance instance);
/**
* 更新 ProcessInstance 拓展记录为不通过
@ -151,7 +151,7 @@ public interface BpmProcessInstanceService {
* @param id 流程编号
* @param reason 理由例如说审批不通过时需要传递该值
*/
void updateProcessInstanceExtReject(String id, String reason);
void updateProcessInstanceReject(String id, String reason);
// TODO @hai改成 getProcessInstanceAssigneesByTaskDefinitionKey(String id, String taskDefinitionKey)
/**

View File

@ -90,25 +90,18 @@ public interface BpmTaskService {
void transferTask(Long userId, BpmTaskTransferReqVO reqVO);
/**
* 创建 Task 拓展记录
* 更新 Task 状态在创建时
*
* @param task 任务实体
*/
void createTaskExt(Task task);
void updateTaskStatusWhenCreated(Task task);
/**
* 更新 Task 拓展记录为完成
*
* @param task 任务实体
*/
void updateTaskExtComplete(Task task);
/**
* 更新 Task 拓展记录为已取消
* 更新 Task 状态在取消时
*
* @param taskId 任务的编号
*/
void updateTaskExtCancel(String taskId);
void updateTaskStatusWhenCanceled(String taskId);
/**
* 更新 Task 拓展记录并发送通知
@ -117,6 +110,12 @@ public interface BpmTaskService {
*/
void updateTaskExtAssign(Task task);
/**
* 获取任务
*
* @param id 任务编号
* @return 任务
*/
Task getTask(String id);
/**

View File

@ -13,9 +13,7 @@ import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatustEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskAddSignTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.task.*;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants;
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
@ -181,8 +179,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// 3.1 更新 task 状态原因
updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus(), reqVO.getReason());
// 3.2 添加评论
taskService.addComment(task.getId(), task.getProcessInstanceId(),
BpmCommentTypeEnum.APPROVE.getType(), reqVO.getReason());
taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(),
BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason()));
// 3.3 调用 BPM complete 去完成任务
taskService.complete(task.getId(), instance.getProcessVariables());
@ -300,21 +298,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
@Override
@Transactional(rollbackFor = Exception.class)
public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) {
// 1.1 校验任务存在
Task task = validateTask(userId, reqVO.getId());
// 校验流程实例存在
// 1.2 校验流程实例存在
ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
if (instance == null) {
throw exception(PROCESS_INSTANCE_NOT_EXISTS);
}
// 更新流程实例为不通过
updateTaskStatus(task.getId(), BpmTaskStatustEnum.REJECT.getStatus());
processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason());
// 2.1 更新流程实例为不通过
updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.REJECT.getStatus(), reqVO.getReason());
// 2.2 添加评论
taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(),
BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason()));
// // 更新任务拓展表为不通过
// taskExtMapper.updateByTaskId(
// new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
// .setEndTime(LocalDateTime.now()).setReason(reqVO.getReason()));
// 3. 更新流程实例审批不通过
processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason());
}
/**
@ -354,112 +353,49 @@ public class BpmTaskServiceImpl implements BpmTaskService {
}
@Override
public void createTaskExt(Task task) {
// BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
// .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
// // 向后加签生成的任务状态不能为进行中需要等前面父任务完成
// if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) {
// taskExtDO.setResult(BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult());
// }
// taskExtMapper.insert(taskExtDO);
// Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
// if (status != null) {
// return;
// }
//
// status = BpmProcessInstanceResultEnum.RUNNING.getResult();
// 向后加签生成的任务状态不能为进行中需要等前面父任务完成
// if (BpmTaskAddSignTypeEnum.AFTER_CHILDREN_TASK.getType().equals(task.getScopeType())) {
// status = BpmProcessInstanceResultEnum.WAIT_BEFORE_TASK.getResult();
// }
public void updateTaskStatusWhenCreated(Task task) {
Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
if (status != null) {
log.error("[updateTaskStatusWhenCreated][taskId({}) 已经有状态({})]", task.getId(), status);
return;
}
updateTaskStatus(task.getId(), BpmTaskStatustEnum.RUNNING.getStatus());
}
@Override
public void updateTaskExtComplete(Task task) {
// BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
// .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大因为 Complete 一般是审核通过已经设置
// .setEndTime(LocalDateTime.now());
// taskExtMapper.updateByTaskId(taskExtDO);
updateTaskStatus(task.getId(), BpmTaskStatustEnum.APPROVE.getStatus());
}
@Override
public void updateTaskExtCancel(String taskId) {
public void updateTaskStatusWhenCanceled(String taskId) {
Task task = getTask(taskId);
// 可能只是活动不是任务所以查询不到
// 1. 可能只是活动不是任务所以查询不到
if (task == null) {
log.error("[updateTaskExtCancel][taskId({}) 任务不存在]", taskId);
log.error("[updateTaskStatusWhenCanceled][taskId({}) 任务不存在]", taskId);
return;
}
// 2. 更新 task 状态 + 原因
Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
if (BpmTaskStatustEnum.isEndStatus(status)) {
log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, status);
log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status);
return;
}
updateTaskStatus(taskId, BpmTaskStatustEnum.CANCEL.getStatus());
if (true) {
return;
}
// 需要在事务提交后才进行查询不然查询不到历史的原因
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
// 可能只是活动不是任务所以查询不到
HistoricTaskInstance task = getHistoricTask(taskId);
if (task == null) {
return;
}
// // 如果任务拓展表已经是完成的状态则跳过
// BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId);
// if (taskExt == null) {
// log.error("[updateTaskExtCancel][taskId({}) 查找不到对应的记录,可能存在问题]", taskId);
// return;
// }
// // 如果已经是最终的结果则跳过
// if (BpmProcessInstanceResultEnum.isEndResult(taskExt.getResult())) {
// log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, taskExt.getResult());
// return;
// }
Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
if (BpmTaskStatustEnum.isEndStatus(status)) {
log.error("[updateTaskExtCancel][taskId({}) 处于结果({}),无需进行更新]", taskId, status);
return;
}
// 更新任务
// taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
// .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason())));
updateTaskStatus(taskId, BpmTaskStatustEnum.CANCEL.getStatus());
}
});
updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_SYSTEM.getReason());
// 补充说明由于 Task 被删除成 HistoricTask 无法通过 taskService.addComment 添加理由所以无法存储具体的取消理由
}
@Override
public void updateTaskExtAssign(Task task) {
// BpmTaskExtDO taskExtDO =
// new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId());
// taskExtMapper.updateByTaskId(taskExtDO);
// 发送通知在事务提交时批量执行操作所以直接查询会无法查询到 ProcessInstance所以这里是通过监听事务的提交来实现
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
if (StrUtil.isNotEmpty(task.getAssignee())) {
ProcessInstance processInstance =
processInstanceService.getProcessInstance(task.getProcessInstanceId());
AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
messageService.sendMessageWhenTaskAssigned(
BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
return;
}
ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
}
});
}
@ -567,8 +503,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
return;
}
// 2.1 添加评论
taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.BACK.getType(),
BpmCommentTypeEnum.BACK.formatComment(reqVO.getReason()));
taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.RETURN.getType(),
BpmCommentTypeEnum.RETURN.formatComment(reqVO.getReason()));
// 2.2 更新 task 状态 + 原因
updateTaskStatusAndReason(task.getId(), BpmTaskStatustEnum.RETURN.getStatus(), reqVO.getReason());
});