package org.springblade.mdm.flow.service; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.runtime.Execution; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Map; @Service public class FlowableBackWithAssigneeService { @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @Autowired private HistoryService historyService; /** * 将流程退回到指定任务节点并指定新的处理人 * @param currentTaskId 当前任务ID * @param targetActivityId 目标活动节点ID * @param newAssignee 新的处理人 * @param comment 退回意见 * @param variables 流程变量 */ @Transactional public void backToTaskWithNewAssignee(String currentTaskId, String targetActivityId, String newAssignee, String comment, Map variables) { // 获取当前任务 Task currentTask = taskService.createTaskQuery() .taskId(currentTaskId) .singleResult(); if (currentTask == null) { throw new RuntimeException("当前任务不存在"); } String processInstanceId = currentTask.getProcessInstanceId(); // 添加评论 if (comment != null && !comment.trim().isEmpty()) { taskService.addComment(currentTaskId, processInstanceId, comment); } // 验证目标节点是否存在 validateTargetActivity(processInstanceId, targetActivityId); // 使用运行时服务跳转到目标节点 runtimeService.createChangeActivityStateBuilder() .processInstanceId(processInstanceId) .moveActivityIdTo(currentTask.getTaskDefinitionKey(), targetActivityId) .changeState(); // 获取新创建的任务(退回后产生的任务) Task newTask = taskService.createTaskQuery() .processInstanceId(processInstanceId) .taskDefinitionKey(targetActivityId) .singleResult(); if (newTask != null) { // 设置新的处理人 if (newAssignee != null && !newAssignee.trim().isEmpty()) { taskService.setAssignee(newTask.getId(), newAssignee); } // 设置流程变量 if (variables != null && !variables.isEmpty()) { taskService.setVariables(newTask.getId(), variables); } } // 删除当前任务 taskService.deleteTask(currentTaskId, "退回流程并指定新处理人: " + newAssignee); } /** * 退回并保留原处理人信息(记录历史) */ @Transactional public void backToTaskWithOriginalAssignee(String currentTaskId, String targetActivityId, String comment) { Task currentTask = taskService.createTaskQuery() .taskId(currentTaskId) .singleResult(); if (currentTask == null) { throw new RuntimeException("当前任务不存在"); } String processInstanceId = currentTask.getProcessInstanceId(); // 获取目标节点的历史任务信息 HistoricTaskInstance historicTask = historyService.createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId) .taskDefinitionKey(targetActivityId) .orderByHistoricTaskInstanceEndTime().desc() .list() .stream() .findFirst() .orElse(null); String originalAssignee = historicTask != null ? historicTask.getAssignee() : null; // 执行退回操作 backToTaskWithNewAssignee(currentTaskId, targetActivityId, originalAssignee, comment, null); } /** * 验证目标活动节点是否存在 */ private void validateTargetActivity(String processInstanceId, String targetActivityId) { List targetActivities = historyService .createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId) .activityId(targetActivityId) .list(); if (targetActivities.isEmpty()) { throw new RuntimeException("目标节点不存在于流程实例中"); } } /** * 获取可退回的节点列表(用户任务节点) */ public List getBackableUserTasks(String processInstanceId) { return historyService.createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId) .activityType("userTask") .orderByHistoricActivityInstanceStartTime().desc() .list(); } /** * 获取指定节点的历史处理人 */ public String getHistoricAssignee(String processInstanceId, String activityId) { HistoricTaskInstance historicTask = historyService.createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId) .taskDefinitionKey(activityId) .orderByHistoricTaskInstanceEndTime().desc() .list() .stream() .findFirst() .orElse(null); return historicTask != null ? historicTask.getAssignee() : null; } }