Commit 36a77251af93c0bc0013d2d9969f7c25a7c2711f

Authored by YunaiV
1 parent 32804d3e

【代码优化】工作流:BpmTaskService、BpmProcessInstanceService 区分读方法、写、event 方法的区域,提升可阅读性

yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java
... ... @@ -34,7 +34,7 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent
34 34  
35 35 @Override
36 36 protected void processCompleted(FlowableEngineEntityEvent event) {
37   - processInstanceService.updateProcessInstanceWhenCompleted((ProcessInstance)event.getEntity());
  37 + processInstanceService.processProcessInstanceCompleted((ProcessInstance)event.getEntity());
38 38 }
39 39  
40 40 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
... ... @@ -48,17 +48,16 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
48 48  
49 49 @Override
50 50 protected void taskCreated(FlowableEngineEntityEvent event) {
51   - taskService.updateTaskStatusWhenCreated((Task) event.getEntity());
  51 + taskService.processTaskCreated((Task) event.getEntity());
52 52 }
53 53  
54 54 @Override
55 55 protected void taskAssigned(FlowableEngineEntityEvent event) {
56   - taskService.updateTaskExtAssign((Task) event.getEntity());
  56 + taskService.processTaskAssigned((Task) event.getEntity());
57 57 }
58 58  
59 59 @Override
60 60 protected void activityCancelled(FlowableActivityCancelledEvent event) {
61   - // TODO @jason:如果用户主动取消,可能需要考虑这个
62 61 List<HistoricActivityInstance> activityList = activityService.getHistoricActivityListByExecutionId(event.getExecutionId());
63 62 if (CollUtil.isEmpty(activityList)) {
64 63 log.error("[activityCancelled][使用 executionId({}) 查找不到对应的活动实例]", event.getExecutionId());
... ... @@ -69,7 +68,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
69 68 if (StrUtil.isEmpty(activity.getTaskId())) {
70 69 return;
71 70 }
72   - taskService.updateTaskStatusWhenCanceled(activity.getTaskId());
  71 + taskService.processTaskCanceled(activity.getTaskId());
73 72 });
74 73 }
75 74  
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTimerFiredEventListener.java
... ... @@ -42,7 +42,6 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe
42 42 @Resource
43 43 @Lazy // 延迟加载,避免循环依赖
44 44 private BpmModelService bpmModelService;
45   -
46 45 @Resource
47 46 @Lazy // 延迟加载,避免循环依赖
48 47 private BpmTaskService bpmTaskService;
... ... @@ -67,7 +66,7 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe
67 66 // 如果是定时器边界事件
68 67 if (element instanceof BoundaryEvent) {
69 68 BoundaryEvent boundaryEvent = (BoundaryEvent) element;
70   - String boundaryEventType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent, BpmnModelConstants.BOUNDARY_EVENT_TYPE);
  69 + String boundaryEventType = BpmnModelUtils.parseBoundaryEventExtensionElement(boundaryEvent, BpmnModelConstants.BOUNDARY_EVENT_TYPE);
71 70 BpmBoundaryEventType bpmTimerBoundaryEventType = BpmBoundaryEventType.typeOf(NumberUtils.parseInt(boundaryEventType));
72 71 // 类型为用户任务超时未处理的情况
73 72 if (bpmTimerBoundaryEventType == BpmBoundaryEventType.USER_TASK_TIMEOUT) {
... ... @@ -81,8 +80,7 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe
81 80 BpmUserTaskTimeoutActionEnum userTaskTimeoutAction = BpmUserTaskTimeoutActionEnum.actionOf(timeoutAction);
82 81 if (userTaskTimeoutAction != null) {
83 82 // 查询超时未处理的任务 TODO 加签的情况会不会有问题 ???
84   - List<Task> taskList = bpmTaskService.getRunningTaskListByProcessInstanceId(processInstanceId, true,
85   - null, taskDefKey);
  83 + List<Task> taskList = bpmTaskService.getRunningTaskListByProcessInstanceId(processInstanceId, true, taskDefKey);
86 84 taskList.forEach(task -> {
87 85 // 自动提醒
88 86 if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.REMINDER) {
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java
... ... @@ -22,6 +22,8 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
22 22 */
23 23 public interface BpmProcessInstanceService {
24 24  
  25 + // ========== Query 查询相关方法 ==========
  26 +
25 27 /**
26 28 * 获得流程实例
27 29 *
... ... @@ -74,6 +76,8 @@ public interface BpmProcessInstanceService {
74 76 return convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId);
75 77 }
76 78  
  79 + // ========== Update 写入相关方法 ==========
  80 +
77 81 /**
78 82 * 获得流程实例的分页
79 83 *
... ... @@ -126,11 +130,13 @@ public interface BpmProcessInstanceService {
126 130 */
127 131 void updateProcessInstanceReject(ProcessInstance processInstance, String reason);
128 132  
  133 + // ========== Event 事件相关方法 ==========
  134 +
129 135 /**
130   - * 处理 ProcessInstance 完成(审批通过、不通过、取消)
  136 + * 处理 ProcessInstance 完成事件,例如说:审批通过、不通过、取消
131 137 *
132 138 * @param instance 流程任务
133 139 */
134   - void updateProcessInstanceWhenCompleted(ProcessInstance instance);
  140 + void processProcessInstanceCompleted(ProcessInstance instance);
135 141  
136 142 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
1   -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource @Lazy // 避免循环依赖 private BpmTaskService taskService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .processInstanceTenantId(FlowableUtils.getTenantId()) .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List<HistoricProcessInstance> processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getStartUserSelectAssignees()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getStartUserSelectAssignees()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey, Map<String, List<Long>> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 1.2 校验发起人自选审批人 validateStartUserSelectAssignees(definition, startUserSelectAssignees); // 2. 创建流程实例 if (variables == null) { variables = new HashMap<>(); } FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); if (CollUtil.isNotEmpty(startUserSelectAssignees)) { variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } private void validateStartUserSelectAssignees(ProcessDefinition definition, Map<String, List<Long>> startUserSelectAssignees) { // 1. 获得发起人自选审批人的 UserTask 列表 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); if (CollUtil.isEmpty(userTaskList)) { return; } // 2. 校验发起人自选审批人的 UserTask 是否都配置了 userTaskList.forEach(userTask -> { List<Long> assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(userTask.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, userTask.getName()); } Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assignees); assignees.forEach(assignee -> { if (userMap.get(assignee) == null) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, userTask.getName(), assignee); } }); }); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 取消流程 updateProcessInstanceCancel(cancelReqVO.getId(), BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 2. 取消流程 AdminUserRespDTO user = adminUserApi.getUser(userId); updateProcessInstanceCancel(cancelReqVO.getId(), BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); } private void updateProcessInstanceCancel(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason); // 2. 结束流程 taskService.moveTaskToEnd(id); } @Override public void updateProcessInstanceReject(ProcessInstance processInstance, String reason) { runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_REASON, BpmReasonEnum.REJECT_TASK.format(reason)); } @Override public void updateProcessInstanceWhenCompleted(ProcessInstance instance) { // 1.1 获取当前状态 Integer status = (Integer) instance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS); String reason = (String) instance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_REASON); // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态 // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了 if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { status = BpmProcessInstanceStatusEnum.APPROVE.getStatus(); runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, status); } // 2. 发送对应的消息通知 if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) { messageService.sendMessageWhenProcessInstanceReject( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason)); } // 3. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status)); } }
2 1 \ No newline at end of file
  2 +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource @Lazy // 避免循环依赖 private BpmTaskService taskService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; // ========== Query 查询相关方法 ========== @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .processInstanceTenantId(FlowableUtils.getTenantId()) .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List<HistoricProcessInstance> processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } // ========== Update 写入相关方法 ========== @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getStartUserSelectAssignees()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getStartUserSelectAssignees()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey, Map<String, List<Long>> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 1.2 校验发起人自选审批人 validateStartUserSelectAssignees(definition, startUserSelectAssignees); // 2. 创建流程实例 if (variables == null) { variables = new HashMap<>(); } FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); if (CollUtil.isNotEmpty(startUserSelectAssignees)) { variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } private void validateStartUserSelectAssignees(ProcessDefinition definition, Map<String, List<Long>> startUserSelectAssignees) { // 1. 获得发起人自选审批人的 UserTask 列表 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); if (CollUtil.isEmpty(userTaskList)) { return; } // 2. 校验发起人自选审批人的 UserTask 是否都配置了 userTaskList.forEach(userTask -> { List<Long> assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(userTask.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, userTask.getName()); } Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assignees); assignees.forEach(assignee -> { if (userMap.get(assignee) == null) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, userTask.getName(), assignee); } }); }); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 取消流程 updateProcessInstanceCancel(cancelReqVO.getId(), BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 2. 取消流程 AdminUserRespDTO user = adminUserApi.getUser(userId); updateProcessInstanceCancel(cancelReqVO.getId(), BpmReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); } private void updateProcessInstanceCancel(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason); // 2. 结束流程 taskService.moveTaskToEnd(id); } @Override public void updateProcessInstanceReject(ProcessInstance processInstance, String reason) { runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_REASON, BpmReasonEnum.REJECT_TASK.format(reason)); } // ========== Event 事件相关方法 ========== @Override public void processProcessInstanceCompleted(ProcessInstance instance) { // 1.1 获取当前状态 Integer status = (Integer) instance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS); String reason = (String) instance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_REASON); // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态 // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了 if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { status = BpmProcessInstanceStatusEnum.APPROVE.getStatus(); runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, status); } // 2. 发送对应的消息通知 if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) { messageService.sendMessageWhenProcessInstanceReject( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason)); } // 3. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status)); } }
3 3 \ No newline at end of file
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
... ... @@ -20,6 +20,8 @@ import java.util.Map;
20 20 */
21 21 public interface BpmTaskService {
22 22  
  23 + // ========== Query 查询相关方法 ==========
  24 +
23 25 /**
24 26 * 获得待办的流程任务分页
25 27 *
... ... @@ -75,85 +77,80 @@ public interface BpmTaskService {
75 77 List<HistoricTaskInstance> getTaskListByProcessInstanceId(String processInstanceId);
76 78  
77 79 /**
78   - * 通过任务
  80 + * 获取任务
79 81 *
80   - * @param userId 用户编号
81   - * @param reqVO 通过请求
  82 + * @param id 任务编号
  83 + * @return 任务
82 84 */
83   - void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO);
  85 + Task getTask(String id);
84 86  
85 87 /**
86   - * 不通过任务
  88 + * 根据条件查询正在进行中的任务
87 89 *
88   - * @param userId 用户编号
89   - * @param reqVO 不通过请求
  90 + * @param processInstanceId 流程实例编号,不允许为空
  91 + * @param assigned 是否分配了审批人,允许空
  92 + * @param taskDefineKey 任务定义 Key,允许空
90 93 */
91   - void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
  94 + List<Task> getRunningTaskListByProcessInstanceId(String processInstanceId,
  95 + Boolean assigned,
  96 + String taskDefineKey);
92 97  
93 98 /**
94   - * 将流程任务分配给指定用户
  99 + * 获取当前任务的可回退的 UserTask 集合
95 100 *
96   - * @param userId 用户编号
97   - * @param reqVO 分配请求
  101 + * @param id 当前的任务 ID
  102 + * @return 可以回退的节点列表
98 103 */
99   - void transferTask(Long userId, BpmTaskTransferReqVO reqVO);
  104 + List<UserTask> getUserTaskListByReturn(String id);
100 105  
101 106 /**
102   - * 将指定流程实例的、进行中的流程任务,移动到结束节点
  107 + * 获取指定任务的子任务列表
103 108 *
104   - * @param processInstanceId 流程编号
  109 + * @param parentTaskId 父任务ID
  110 + * @return 子任务列表
105 111 */
106   - void moveTaskToEnd(String processInstanceId);
  112 + List<Task> getTaskListByParentTaskId(String parentTaskId);
107 113  
108 114 /**
109   - * 更新 Task 状态,在创建时
  115 + * 通过任务 ID,查询任务名 Map
110 116 *
111   - * @param task 任务实体
  117 + * @param taskIds 任务 ID
  118 + * @return 任务 ID 与名字的 Map
112 119 */
113   - void updateTaskStatusWhenCreated(Task task);
  120 + Map<String, String> getTaskNameByTaskIds(Collection<String> taskIds);
114 121  
115   - /**
116   - * 更新 Task 状态,在取消时
117   - *
118   - * @param taskId 任务的编号
119   - */
120   - void updateTaskStatusWhenCanceled(String taskId);
  122 + // ========== Update 写入相关方法 ==========
121 123  
122 124 /**
123   - * 更新 Task 拓展记录,并发送通知
  125 + * 通过任务
124 126 *
125   - * @param task 任务实体
  127 + * @param userId 用户编号
  128 + * @param reqVO 通过请求
126 129 */
127   - void updateTaskExtAssign(Task task);
  130 + void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO);
128 131  
129 132 /**
130   - * 获取任务
  133 + * 不通过任务
131 134 *
132   - * @param id 任务编号
133   - * @return 任务
  135 + * @param userId 用户编号
  136 + * @param reqVO 不通过请求
134 137 */
135   - Task getTask(String id);
  138 + void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
136 139  
137 140 /**
138   - * 根据条件查询正在进行中的任务
  141 + * 将流程任务分配给指定用户
139 142 *
140   - * @param processInstanceId 流程实例编号,不允许为空
141   - * @param assigned 是否分配了审批人,允许空
142   - * @param executionId execution Id,允许空
143   - * @param taskDefineKey 任务定义 Key,允许空
  143 + * @param userId 用户编号
  144 + * @param reqVO 分配请求
144 145 */
145   - List<Task> getRunningTaskListByProcessInstanceId(String processInstanceId,
146   - Boolean assigned,
147   - String executionId,
148   - String taskDefineKey);
  146 + void transferTask(Long userId, BpmTaskTransferReqVO reqVO);
149 147  
150 148 /**
151   - * 获取当前任务的可回退的 UserTask 集合
  149 + * 将指定流程实例的、进行中的流程任务,移动到结束节点
152 150 *
153   - * @param id 当前的任务 ID
154   - * @return 可以回退的节点列表
  151 + * @param processInstanceId 流程编号
155 152 */
156   - List<UserTask> getUserTaskListByReturn(String id);
  153 + void moveTaskToEnd(String processInstanceId);
157 154  
158 155 /**
159 156 * 将任务回退到指定的 targetDefinitionKey 位置
... ... @@ -187,20 +184,27 @@ public interface BpmTaskService {
187 184 */
188 185 void deleteSignTask(Long userId, BpmTaskSignDeleteReqVO reqVO);
189 186  
  187 + // ========== Event 事件相关方法 ==========
  188 +
190 189 /**
191   - * 获取指定任务的子任务列表
  190 + * 处理 Task 创建事件,目前是更新它的状态为审批中
192 191 *
193   - * @param parentTaskId 父任务ID
194   - * @return 子任务列表
  192 + * @param task 任务实体
195 193 */
196   - List<Task> getTaskListByParentTaskId(String parentTaskId);
  194 + void processTaskCreated(Task task);
197 195  
198 196 /**
199   - * 通过任务 ID,查询任务名 Map
  197 + * 处理 Task 取消事件,目前是更新它的状态为已取消
200 198 *
201   - * @param taskIds 任务 ID
202   - * @return 任务 ID 与名字的 Map
  199 + * @param taskId 任务的编号
203 200 */
204   - Map<String, String> getTaskNameByTaskIds(Collection<String> taskIds);
  201 + void processTaskCanceled(String taskId);
  202 +
  203 + /**
  204 + * 处理 Task 设置审批人事件,目前是发送审批消息
  205 + *
  206 + * @param task 任务实体
  207 + */
  208 + void processTaskAssigned(Task task);
205 209  
206 210 }
... ...
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -84,6 +84,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
84 84 @Resource
85 85 private AdminUserApi adminUserApi;
86 86  
  87 + // ========== Query 查询相关方法 ==========
  88 +
87 89 @Override
88 90 public PageResult<Task> getTaskTodoPage(Long userId, BpmTaskPageReqVO pageVO) {
89 91 TaskQuery taskQuery = taskService.createTaskQuery()
... ... @@ -172,6 +174,156 @@ public class BpmTaskServiceImpl implements BpmTaskService {
172 174 return tasks;
173 175 }
174 176  
  177 + /**
  178 + * 校验任务是否存在,并且是否是分配给自己的任务
  179 + *
  180 + * @param userId 用户 id
  181 + * @param taskId task id
  182 + */
  183 + private Task validateTask(Long userId, String taskId) {
  184 + Task task = validateTaskExist(taskId);
  185 + if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
  186 + throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF);
  187 + }
  188 + return task;
  189 + }
  190 +
  191 + private Task validateTaskExist(String id) {
  192 + Task task = getTask(id);
  193 + if (task == null) {
  194 + throw exception(TASK_NOT_EXISTS);
  195 + }
  196 + return task;
  197 + }
  198 +
  199 + @Override
  200 + public Task getTask(String id) {
  201 + return taskService.createTaskQuery().taskId(id).includeTaskLocalVariables().singleResult();
  202 + }
  203 +
  204 + @Override
  205 + public List<Task> getRunningTaskListByProcessInstanceId(String processInstanceId, Boolean assigned, String defineKey) {
  206 + Assert.notNull(processInstanceId, "processInstanceId 不能为空");
  207 + TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(processInstanceId).active()
  208 + .includeTaskLocalVariables();
  209 + if (BooleanUtil.isTrue(assigned)) {
  210 + taskQuery.taskAssigned();
  211 + } else if (BooleanUtil.isFalse(assigned)) {
  212 + taskQuery.taskUnassigned();
  213 + }
  214 + if (StrUtil.isNotEmpty(defineKey)) {
  215 + taskQuery.taskDefinitionKey(defineKey);
  216 + }
  217 + return taskQuery.list();
  218 + }
  219 +
  220 + private HistoricTaskInstance getHistoricTask(String id) {
  221 + return historyService.createHistoricTaskInstanceQuery().taskId(id).includeTaskLocalVariables().singleResult();
  222 + }
  223 +
  224 + @Override
  225 + public List<UserTask> getUserTaskListByReturn(String id) {
  226 + // 1.1 校验当前任务 task 存在
  227 + Task task = validateTaskExist(id);
  228 + // 1.2 根据流程定义获取流程模型信息
  229 + BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
  230 + FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
  231 + if (source == null) {
  232 + throw exception(TASK_NOT_EXISTS);
  233 + }
  234 +
  235 + // 2.1 查询该任务的前置任务节点的 key 集合
  236 + List<UserTask> previousUserList = BpmnModelUtils.getPreviousUserTaskList(source, null, null);
  237 + if (CollUtil.isEmpty(previousUserList)) {
  238 + return Collections.emptyList();
  239 + }
  240 + // 2.2 过滤:只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回
  241 + previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null));
  242 + return previousUserList;
  243 + }
  244 +
  245 + /**
  246 + * 获得所有子任务列表
  247 + *
  248 + * @param parentTask 父任务
  249 + * @return 所有子任务列表
  250 + */
  251 + private List<Task> getAllChildTaskList(Task parentTask) {
  252 + List<Task> result = new ArrayList<>();
  253 + // 1. 递归获取子级
  254 + Stack<Task> stack = new Stack<>();
  255 + stack.push(parentTask);
  256 + // 2. 递归遍历
  257 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  258 + if (stack.isEmpty()) {
  259 + break;
  260 + }
  261 + // 2.1 获取子任务们
  262 + Task task = stack.pop();
  263 + List<Task> childTaskList = getTaskListByParentTaskId(task.getId());
  264 + // 2.2 如果非空,则添加到 stack 进一步递归
  265 + if (CollUtil.isNotEmpty(childTaskList)) {
  266 + stack.addAll(childTaskList);
  267 + result.addAll(childTaskList);
  268 + }
  269 + }
  270 + return result;
  271 + }
  272 +
  273 + @Override
  274 + public List<Task> getTaskListByParentTaskId(String parentTaskId) {
  275 + String tableName = managementService.getTableName(TaskEntity.class);
  276 + // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询
  277 + String sql = "select ID_,NAME_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
  278 + return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
  279 + }
  280 +
  281 + /**
  282 + * 获取子任务个数
  283 + *
  284 + * @param parentTaskId 父任务 ID
  285 + * @return 剩余子任务个数
  286 + */
  287 + private Long getTaskCountByParentTaskId(String parentTaskId) {
  288 + String tableName = managementService.getTableName(TaskEntity.class);
  289 + String sql = "SELECT COUNT(1) from " + tableName + " WHERE PARENT_TASK_ID_=#{parentTaskId}";
  290 + return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count();
  291 + }
  292 +
  293 + /**
  294 + * 获得任务根任务的父任务编号
  295 + *
  296 + * @param task 任务
  297 + * @return 根任务的父任务编号
  298 + */
  299 + private String getTaskRootParentId(Task task) {
  300 + if (task == null || task.getParentTaskId() == null) {
  301 + return null;
  302 + }
  303 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  304 + Task parentTask = getTask(task.getParentTaskId());
  305 + if (parentTask == null) {
  306 + return null;
  307 + }
  308 + if (parentTask.getParentTaskId() == null) {
  309 + return parentTask.getId();
  310 + }
  311 + task = parentTask;
  312 + }
  313 + throw new IllegalArgumentException(String.format("Task(%s) 层级过深,无法获取父节点编号", task.getId()));
  314 + }
  315 +
  316 + @Override
  317 + public Map<String, String> getTaskNameByTaskIds(Collection<String> taskIds) {
  318 + if (CollUtil.isEmpty(taskIds)) {
  319 + return Collections.emptyMap();
  320 + }
  321 + List<Task> tasks = taskService.createTaskQuery().taskIds(taskIds).list();
  322 + return convertMap(tasks, Task::getId, Task::getName);
  323 + }
  324 +
  325 + // ========== Update 写入相关方法 ==========
  326 +
175 327 @Override
176 328 @Transactional(rollbackFor = Exception.class)
177 329 public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) {
... ... @@ -382,132 +534,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
382 534 taskService.setVariableLocal(id, BpmConstants.TASK_VARIABLE_REASON, reason);
383 535 }
384 536  
385   - /**
386   - * 校验任务是否存在,并且是否是分配给自己的任务
387   - *
388   - * @param userId 用户 id
389   - * @param taskId task id
390   - */
391   - private Task validateTask(Long userId, String taskId) {
392   - Task task = validateTaskExist(taskId);
393   - if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
394   - throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF);
395   - }
396   - return task;
397   - }
398   -
399   - @Override
400   - public void updateTaskStatusWhenCreated(Task task) {
401   - Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
402   - if (status != null) {
403   - log.error("[updateTaskStatusWhenCreated][taskId({}) 已经有状态({})]", task.getId(), status);
404   - return;
405   - }
406   - updateTaskStatus(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus());
407   - }
408   -
409   - /**
410   - * 重要补充说明:该方法目前主要有两个情况会调用到:
411   - *
412   - * 1. 或签场景 + 审批通过:一个或签有多个审批时,如果 A 审批通过,其它或签 B、C 等任务会被 Flowable 自动删除,此时需要通过该方法更新状态为已取消
413   - * 2. 审批不通过:在 {@link #rejectTask(Long, BpmTaskRejectReqVO)} 不通过时,对于加签的任务,不会被 Flowable 删除,此时需要通过该方法更新状态为已取消
414   - */
415   - @Override
416   - public void updateTaskStatusWhenCanceled(String taskId) {
417   - Task task = getTask(taskId);
418   - // 1. 可能只是活动,不是任务,所以查询不到
419   - if (task == null) {
420   - log.error("[updateTaskStatusWhenCanceled][taskId({}) 任务不存在]", taskId);
421   - return;
422   - }
423   -
424   - // 2. 更新 task 状态 + 原因
425   - Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
426   - if (BpmTaskStatusEnum.isEndStatus(status)) {
427   - log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status);
428   - return;
429   - }
430   - updateTaskStatusAndReason(taskId, BpmTaskStatusEnum.CANCEL.getStatus(), BpmReasonEnum.CANCEL_BY_SYSTEM.getReason());
431   - // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由
432   - }
433   -
434   - @Override
435   - public void updateTaskExtAssign(Task task) {
436   - // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。
437   - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
438   -
439   - @Override
440   - public void afterCommit() {
441   - if (StrUtil.isEmpty(task.getAssignee())) {
442   - return;
443   - }
444   - ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
445   - if (processInstance != null) {
446   - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
447   - messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
448   - }
449   - }
450   -
451   - });
452   - }
453   -
454   - private Task validateTaskExist(String id) {
455   - Task task = getTask(id);
456   - if (task == null) {
457   - throw exception(TASK_NOT_EXISTS);
458   - }
459   - return task;
460   - }
461   -
462   - @Override
463   - public Task getTask(String id) {
464   - return taskService.createTaskQuery().taskId(id).includeTaskLocalVariables().singleResult();
465   - }
466   -
467   - @Override
468   - public List<Task> getRunningTaskListByProcessInstanceId(String processInstanceId, Boolean assigned, String executionId, String defineKey) {
469   - Assert.notNull(processInstanceId, "processInstanceId 不能为空");
470   - TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(processInstanceId).active()
471   - .includeTaskLocalVariables();
472   - if (BooleanUtil.isTrue(assigned)) {
473   - taskQuery.taskAssigned();
474   - } else if (BooleanUtil.isFalse(assigned)) {
475   - taskQuery.taskUnassigned();
476   - }
477   - if (StrUtil.isNotEmpty(executionId)) {
478   - taskQuery.executionId(executionId);
479   - }
480   - if (StrUtil.isNotEmpty(defineKey)) {
481   - taskQuery.taskDefinitionKey(defineKey);
482   - }
483   - return taskQuery.list();
484   - }
485   -
486   - private HistoricTaskInstance getHistoricTask(String id) {
487   - return historyService.createHistoricTaskInstanceQuery().taskId(id).includeTaskLocalVariables().singleResult();
488   - }
489   -
490   - @Override
491   - public List<UserTask> getUserTaskListByReturn(String id) {
492   - // 1.1 校验当前任务 task 存在
493   - Task task = validateTaskExist(id);
494   - // 1.2 根据流程定义获取流程模型信息
495   - BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
496   - FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
497   - if (source == null) {
498   - throw exception(TASK_NOT_EXISTS);
499   - }
500   -
501   - // 2.1 查询该任务的前置任务节点的 key 集合
502   - List<UserTask> previousUserList = BpmnModelUtils.getPreviousUserTaskList(source, null, null);
503   - if (CollUtil.isEmpty(previousUserList)) {
504   - return Collections.emptyList();
505   - }
506   - // 2.2 过滤:只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回
507   - previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null));
508   - return previousUserList;
509   - }
510   -
511 537 @Override
512 538 @Transactional(rollbackFor = Exception.class)
513 539 public void returnTask(Long userId, BpmTaskReturnReqVO reqVO) {
... ... @@ -645,7 +671,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
645 671  
646 672 @Override
647 673 public void moveTaskToEnd(String processInstanceId) {
648   - List<Task> taskList = getRunningTaskListByProcessInstanceId(processInstanceId, null, null, null);
  674 + List<Task> taskList = getRunningTaskListByProcessInstanceId(processInstanceId, null, null);
649 675 if (CollUtil.isEmpty(taskList)) {
650 676 return;
651 677 }
... ... @@ -658,7 +684,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
658 684 if (BpmTaskStatusEnum.isEndStatus(otherTaskStatus)) {
659 685 return;
660 686 }
661   - updateTaskStatusWhenCanceled(task.getId());
  687 + processTaskCanceled(task.getId());
662 688 });
663 689  
664 690 // 2. 终止流程
... ... @@ -842,84 +868,61 @@ public class BpmTaskServiceImpl implements BpmTaskService {
842 868 return task;
843 869 }
844 870  
845   - /**
846   - * 获得所有子任务列表
847   - *
848   - * @param parentTask 父任务
849   - * @return 所有子任务列表
850   - */
851   - private List<Task> getAllChildTaskList(Task parentTask) {
852   - List<Task> result = new ArrayList<>();
853   - // 1. 递归获取子级
854   - Stack<Task> stack = new Stack<>();
855   - stack.push(parentTask);
856   - // 2. 递归遍历
857   - for (int i = 0; i < Short.MAX_VALUE; i++) {
858   - if (stack.isEmpty()) {
859   - break;
860   - }
861   - // 2.1 获取子任务们
862   - Task task = stack.pop();
863   - List<Task> childTaskList = getTaskListByParentTaskId(task.getId());
864   - // 2.2 如果非空,则添加到 stack 进一步递归
865   - if (CollUtil.isNotEmpty(childTaskList)) {
866   - stack.addAll(childTaskList);
867   - result.addAll(childTaskList);
868   - }
869   - }
870   - return result;
871   - }
  871 + // ========== Event 事件相关方法 ==========
872 872  
873 873 @Override
874   - public List<Task> getTaskListByParentTaskId(String parentTaskId) {
875   - String tableName = managementService.getTableName(TaskEntity.class);
876   - // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询
877   - String sql = "select ID_,NAME_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
878   - return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
879   - }
880   -
881   - /**
882   - * 获取子任务个数
883   - *
884   - * @param parentTaskId 父任务 ID
885   - * @return 剩余子任务个数
886   - */
887   - private Long getTaskCountByParentTaskId(String parentTaskId) {
888   - String tableName = managementService.getTableName(TaskEntity.class);
889   - String sql = "SELECT COUNT(1) from " + tableName + " WHERE PARENT_TASK_ID_=#{parentTaskId}";
890   - return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count();
  874 + public void processTaskCreated(Task task) {
  875 + Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
  876 + if (status != null) {
  877 + log.error("[updateTaskStatusWhenCreated][taskId({}) 已经有状态({})]", task.getId(), status);
  878 + return;
  879 + }
  880 + updateTaskStatus(task.getId(), BpmTaskStatusEnum.RUNNING.getStatus());
891 881 }
892 882  
893 883 /**
894   - * 获得任务根任务的父任务编号
  884 + * 重要补充说明:该方法目前主要有两个情况会调用到:
895 885 *
896   - * @param task 任务
897   - * @return 根任务的父任务编号
  886 + * 1. 或签场景 + 审批通过:一个或签有多个审批时,如果 A 审批通过,其它或签 B、C 等任务会被 Flowable 自动删除,此时需要通过该方法更新状态为已取消
  887 + * 2. 审批不通过:在 {@link #rejectTask(Long, BpmTaskRejectReqVO)} 不通过时,对于加签的任务,不会被 Flowable 删除,此时需要通过该方法更新状态为已取消
898 888 */
899   - private String getTaskRootParentId(Task task) {
900   - if (task == null || task.getParentTaskId() == null) {
901   - return null;
  889 + @Override
  890 + public void processTaskCanceled(String taskId) {
  891 + Task task = getTask(taskId);
  892 + // 1. 可能只是活动,不是任务,所以查询不到
  893 + if (task == null) {
  894 + log.error("[updateTaskStatusWhenCanceled][taskId({}) 任务不存在]", taskId);
  895 + return;
902 896 }
903   - for (int i = 0; i < Short.MAX_VALUE; i++) {
904   - Task parentTask = getTask(task.getParentTaskId());
905   - if (parentTask == null) {
906   - return null;
907   - }
908   - if (parentTask.getParentTaskId() == null) {
909   - return parentTask.getId();
910   - }
911   - task = parentTask;
  897 +
  898 + // 2. 更新 task 状态 + 原因
  899 + Integer status = (Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
  900 + if (BpmTaskStatusEnum.isEndStatus(status)) {
  901 + log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status);
  902 + return;
912 903 }
913   - throw new IllegalArgumentException(String.format("Task(%s) 层级过深,无法获取父节点编号", task.getId()));
  904 + updateTaskStatusAndReason(taskId, BpmTaskStatusEnum.CANCEL.getStatus(), BpmReasonEnum.CANCEL_BY_SYSTEM.getReason());
  905 + // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由
914 906 }
915 907  
916 908 @Override
917   - public Map<String, String> getTaskNameByTaskIds(Collection<String> taskIds) {
918   - if (CollUtil.isEmpty(taskIds)) {
919   - return Collections.emptyMap();
920   - }
921   - List<Task> tasks = taskService.createTaskQuery().taskIds(taskIds).list();
922   - return convertMap(tasks, Task::getId, Task::getName);
  909 + public void processTaskAssigned(Task task) {
  910 + // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。
  911 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  912 +
  913 + @Override
  914 + public void afterCommit() {
  915 + if (StrUtil.isEmpty(task.getAssignee())) {
  916 + return;
  917 + }
  918 + ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
  919 + if (processInstance != null) {
  920 + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
  921 + messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
  922 + }
  923 + }
  924 +
  925 + });
923 926 }
924 927  
925 928 }
... ...