|
@@ -0,0 +1,189 @@
|
|
|
+package com.flow.flowable.cmd;
|
|
|
+
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.flowable.bpmn.model.*;
|
|
|
+import org.flowable.common.engine.api.FlowableException;
|
|
|
+import org.flowable.common.engine.api.FlowableObjectNotFoundException;
|
|
|
+import org.flowable.common.engine.impl.interceptor.Command;
|
|
|
+import org.flowable.common.engine.impl.interceptor.CommandContext;
|
|
|
+import org.flowable.common.engine.impl.util.CollectionUtil;
|
|
|
+import org.flowable.engine.HistoryService;
|
|
|
+import org.flowable.engine.RuntimeService;
|
|
|
+import org.flowable.engine.history.HistoricActivityInstance;
|
|
|
+import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
|
|
+import org.flowable.engine.impl.persistence.entity.HistoricActivityInstanceEntityManager;
|
|
|
+import org.flowable.engine.impl.util.CommandContextUtil;
|
|
|
+import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
|
|
+import org.flowable.engine.runtime.Execution;
|
|
|
+import org.flowable.engine.runtime.ProcessInstance;
|
|
|
+import org.flowable.task.api.history.HistoricTaskInstance;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+public class TaskRecallCmd implements Command<Void> {
|
|
|
+ protected final String taskId;
|
|
|
+
|
|
|
+ public TaskRecallCmd(String taskId) {
|
|
|
+ this.taskId = taskId;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Void execute(CommandContext commandContext) {
|
|
|
+ if (StringUtils.isBlank(this.taskId)) {
|
|
|
+ throw new FlowableException("taskId is null");
|
|
|
+ }
|
|
|
+ ProcessEngineConfigurationImpl processEngineConf = CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
|
|
+ RuntimeService runtimeService = processEngineConf.getRuntimeService();
|
|
|
+ HistoryService historyService = processEngineConf.getHistoryService();
|
|
|
+ HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery()
|
|
|
+ .taskId(this.taskId)
|
|
|
+ .singleResult();
|
|
|
+ basicCheek(runtimeService, task);
|
|
|
+ BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(task.getProcessDefinitionId());
|
|
|
+ FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
|
|
|
+ List<String> nextUserTaskIdList = new ArrayList<>();
|
|
|
+ List<UserTask> nextUserTaskList = new ArrayList<>();
|
|
|
+ // 先获取后续节点信息
|
|
|
+ getNextElementInfo(bpmnModel, flowElement, nextUserTaskIdList, nextUserTaskList);
|
|
|
+ // 再校验后续节点任务是否已经办理完成
|
|
|
+ existNextFinishedTaskCheck(historyService, task, nextUserTaskList);
|
|
|
+ // 清理节点历史
|
|
|
+ deleteHistoricActivityInstance(processEngineConf, historyService, task);
|
|
|
+ // 执行跳转
|
|
|
+ List<String> recallElementIdList = getRecallElementIdList(runtimeService, task, nextUserTaskIdList);
|
|
|
+ runtimeService.createChangeActivityStateBuilder()
|
|
|
+ .processInstanceId(task.getProcessInstanceId())
|
|
|
+ .moveActivityIdsToSingleActivityId(recallElementIdList, task.getTaskDefinitionKey())
|
|
|
+ .changeState();
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 任务校验
|
|
|
+ *
|
|
|
+ * @param runtimeService
|
|
|
+ * @param task
|
|
|
+ */
|
|
|
+ private void basicCheek(RuntimeService runtimeService, HistoricTaskInstance task) {
|
|
|
+ if (Objects.isNull(task)) {
|
|
|
+ throw new FlowableObjectNotFoundException("任务不存在");
|
|
|
+ }
|
|
|
+ if (Objects.isNull(task.getEndTime())) {
|
|
|
+ throw new FlowableException("任务正在执行,不需要回退");
|
|
|
+ }
|
|
|
+ ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
|
|
+ .processInstanceId(task.getProcessInstanceId()).singleResult();
|
|
|
+ if (Objects.isNull(processInstance)) {
|
|
|
+ throw new FlowableException("该流程已经结束,无法进行任务回退");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取后续节点信息
|
|
|
+ *
|
|
|
+ * @param bpmnModel
|
|
|
+ * @param currentNode
|
|
|
+ * @param nextNodeIdList
|
|
|
+ * @param nextUserTaskList
|
|
|
+ */
|
|
|
+ private void getNextElementInfo(BpmnModel bpmnModel, FlowElement currentNode, List<String> nextNodeIdList, List<UserTask> nextUserTaskList) {
|
|
|
+ // 查询当前节点所有流出顺序流
|
|
|
+ List<SequenceFlow> outgoingFlows = ((FlowNode) currentNode).getOutgoingFlows();
|
|
|
+ for (SequenceFlow flow : outgoingFlows) {
|
|
|
+ // 后续节点
|
|
|
+ FlowElement targetNode = bpmnModel.getFlowElement(flow.getTargetRef());
|
|
|
+ nextNodeIdList.add(targetNode.getId());
|
|
|
+ if (targetNode instanceof UserTask) {
|
|
|
+ nextUserTaskList.add((UserTask) targetNode);
|
|
|
+ } else if (targetNode instanceof Gateway) {
|
|
|
+ Gateway gateway = (Gateway) targetNode;
|
|
|
+ // 网关节点执行递归操作
|
|
|
+ getNextElementInfo(bpmnModel, gateway, nextNodeIdList, nextUserTaskList);
|
|
|
+ } else {
|
|
|
+ // 其他节点不处理
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验后续节点任务是否已经办理完成
|
|
|
+ * @param historyService 历史服务
|
|
|
+ * @param currentTaskInstance 当前任务实例
|
|
|
+ * @param nextUserTaskList 后续用户
|
|
|
+ */
|
|
|
+ private void existNextFinishedTaskCheck(HistoryService historyService, HistoricTaskInstance currentTaskInstance, List<UserTask> nextUserTaskList) {
|
|
|
+ List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery()
|
|
|
+ .processInstanceId(currentTaskInstance.getProcessInstanceId())
|
|
|
+ .taskCompletedAfter(currentTaskInstance.getEndTime())
|
|
|
+ .list();
|
|
|
+ List<String> nextUserTaskIdList = nextUserTaskList.stream().map(UserTask::getId).collect(Collectors.toList());
|
|
|
+ if (!hisTaskList.isEmpty()) {
|
|
|
+ hisTaskList.forEach(obj -> {
|
|
|
+ if (nextUserTaskIdList.contains(obj.getTaskDefinitionKey())) {
|
|
|
+ throw new FlowableException("存在已完成下个节点任务");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取可撤回的节点列表
|
|
|
+ *
|
|
|
+ * @param runtimeService
|
|
|
+ * @param currentTaskInstance 任务实例
|
|
|
+ * @param nextElementIdList 后续节点列表
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<String> getRecallElementIdList(RuntimeService runtimeService, HistoricTaskInstance currentTaskInstance, List<String> nextElementIdList) {
|
|
|
+ List<String> recallElementIdList = new ArrayList<>();
|
|
|
+ List<Execution> executions = runtimeService.createExecutionQuery()
|
|
|
+ .processInstanceId(currentTaskInstance.getProcessInstanceId())
|
|
|
+ .onlyChildExecutions()
|
|
|
+ .list();
|
|
|
+ if (!executions.isEmpty()) {
|
|
|
+ executions.forEach(obj -> {
|
|
|
+ if (nextElementIdList.contains(obj.getActivityId())) {
|
|
|
+ recallElementIdList.add(obj.getActivityId());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return recallElementIdList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 清理节点历史
|
|
|
+ *
|
|
|
+ * @param processEngineConf
|
|
|
+ * @param historyService
|
|
|
+ * @param task
|
|
|
+ */
|
|
|
+ private void deleteHistoricActivityInstance(ProcessEngineConfigurationImpl processEngineConf, HistoryService historyService, HistoricTaskInstance task) {
|
|
|
+ // 删除要撤回的节点历史
|
|
|
+ List<HistoricActivityInstance> allHisActivityList = historyService.createHistoricActivityInstanceQuery()
|
|
|
+ .processInstanceId(task.getProcessInstanceId())
|
|
|
+ .activityId(task.getTaskDefinitionKey())
|
|
|
+ .list();
|
|
|
+ HistoricActivityInstance hisActivity = allHisActivityList.stream().filter(obj -> task.getId().equals(obj.getTaskId())).findFirst().get();
|
|
|
+ HistoricActivityInstanceEntityManager hisActivityEntityManager = processEngineConf.getHistoricActivityInstanceEntityManager();
|
|
|
+ hisActivityEntityManager.delete(hisActivity.getId());
|
|
|
+ // 删除被撤回的节点的历史
|
|
|
+ List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery()
|
|
|
+ .processInstanceId(task.getProcessInstanceId())
|
|
|
+ .startedAfter(hisActivity.getEndTime())
|
|
|
+ .orderByHistoricActivityInstanceStartTime()
|
|
|
+ .asc().list();
|
|
|
+ List<String> deleteHisActivityIdList = new ArrayList<>();
|
|
|
+ if (!CollectionUtil.isEmpty(hisActivityList)) {
|
|
|
+ hisActivityList.forEach(obj -> {
|
|
|
+ if (!deleteHisActivityIdList.contains(obj.getActivityId())) {
|
|
|
+ deleteHisActivityIdList.add(obj.getId());
|
|
|
+ hisActivityEntityManager.delete(obj.getId());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|