REQ-3626 增加回退至指定节点通用能力

This commit is contained in:
yangqicheng 2025-02-23 23:02:28 +08:00
parent a5000681b2
commit 0c77f34dfb
7 changed files with 248 additions and 72 deletions

View File

@ -89,6 +89,15 @@ public interface ProcessTaskApi {
@PostMapping("/api/process/task/back") @PostMapping("/api/process/task/back")
CommonResponse<Boolean> backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto); CommonResponse<Boolean> backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto);
/**
* 用于系统内部操作跳转到指定节点
* @param dto 请求参数
* @return 是否成功
*/
@Operation(summary = "系统操作回退任务到指定节点")
@PostMapping("/system/back")
CommonResponse<Boolean> systemBackTask(@Validated @RequestBody BpmnNodeBackSystemOperateDTO dto);
/** /**
* 驳回 * 驳回
* *

View File

@ -0,0 +1,61 @@
package cn.axzo.workflow.common.model.request.bpmn.task;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.List;
/**
* 审批节点退回模型
*
*/
@ApiModel("审批节点退回模型")
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class BpmnNodeBackSystemOperateDTO implements Serializable {
private static final long serialVersionUID = -4160538355403179298L;
@ApiModelProperty(value = "流程实例id", required = true)
@NotBlank(message = "流程实例id不能为空")
private String processInstanceId;
@ApiModelProperty(value = "当前流程节点id", required = true)
@NotBlank(message = "当前节点id不能为空")
private String currentActivityId;
@ApiModelProperty(value = "目标流程节点id", required = true)
@NotBlank(message = "目标流程节点id不能为空")
private String toActivityId;
@ApiModelProperty(value = "意见")
private String advice;
@ApiModelProperty(value = "操作描述")
private String operationDesc;
/**
* 附件列表
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
private List<AttachmentDTO> attachmentList;
}

View File

@ -1,7 +1,8 @@
package cn.axzo.workflow.core.engine.cmd; package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO;
import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.utils.BpmnModelUtils; import cn.axzo.workflow.core.common.utils.BpmnModelUtils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -15,26 +16,18 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil; import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.ProcessDefinitionUtil; import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.TaskService; import org.flowable.task.service.TaskService;
import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.util.StringUtils;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collections; import java.util.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.BACKED;
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE; import static cn.axzo.workflow.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE;
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.BACK_TARGET_ACTIVITY_NOT_EXISTS; import static cn.axzo.workflow.common.code.BpmnTaskRespCode.BACK_TARGET_ACTIVITY_NOT_EXISTS;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment; import static cn.axzo.workflow.common.constant.BpmnConstants.*;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment; import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.BACKED;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask; import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.*;
/** /**
* 回退命令 * 回退命令
@ -43,65 +36,94 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
public class CustomBackTaskCmd extends AbstractCommand<Void> implements Serializable { public class CustomBackTaskCmd extends AbstractCommand<Void> implements Serializable {
private static final long serialVersionUID = -1241290344311892346L; private static final long serialVersionUID = -1241290344311892346L;
private final BpmnTaskBackAuditDTO dto;
private final List<String> targetTaskIds;
private final String advice;
private final String operationDesc;
private final List<AttachmentDTO> attachmentList;
private final BpmnTaskDelegateAssigner approver;
private final String processInstanceId;
private final String currentActivityId;
private final String toActivityId;
private final boolean validateApprover;
private static final String OPERATION_DESC = "回退至"; private static final String OPERATION_DESC = "回退至";
public CustomBackTaskCmd(List<String> targetTaskIds,
String advice,
String operationDesc,
List<AttachmentDTO> attachmentList,
BpmnTaskDelegateAssigner approver,
String processInstanceId,
String currentActivityId,
String toActivityId,
boolean validateApprover) {
this.targetTaskIds = targetTaskIds;
this.advice = advice;
this.operationDesc = operationDesc;
this.attachmentList = attachmentList;
this.approver = approver;
this.processInstanceId = processInstanceId;
this.currentActivityId = currentActivityId;
this.toActivityId = toActivityId;
this.validateApprover = validateApprover;
}
@Override @Override
public String paramToJsonString() { public String paramToJsonString() {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("taskId", dto.getTaskId()); params.put("targetTaskIds", JSON.toJSONString(this.targetTaskIds));
params.put("advice", dto.getAdvice()); params.put("advice", advice);
params.put("operationDesc", OPERATION_DESC); params.put("operationDesc", OPERATION_DESC);
params.put("attachmentList", JSON.toJSONString(dto.getAttachmentList())); params.put("attachmentList", JSON.toJSONString(attachmentList));
params.put("approver", JSON.toJSONString(dto.getApprover())); params.put("approver", JSON.toJSONString(approver));
params.put("nodeTypes", JSON.toJSONString(dto.getNodeTypes())); params.put("toActivityId", JSON.toJSONString(this.toActivityId));
params.put("processInstanceId", JSON.toJSONString(this.processInstanceId));
params.put("validateApprover", validateApprover);
return JSON.toJSONString(params); return JSON.toJSONString(params);
} }
public CustomBackTaskCmd(BpmnTaskBackAuditDTO dto) {
this.dto = dto;
}
@Override @Override
public Void execute(CommandContext commandContext) { public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration = ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext); CommandContextUtil.getProcessEngineConfiguration(commandContext);
HistoricTaskInstanceQuery taskQuery = List<HistoricTaskInstance> taskList = processEngineConfiguration.getHistoryService()
processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery(); .createHistoricTaskInstanceQuery()
.taskDefinitionId(currentActivityId)
.processInstanceId(processInstanceId)
.list();
TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService(); TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService();
if (validateApprover) {
HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult(); taskList.forEach(hi -> validTask(hi, taskService.getTask(hi.getId()), approver, null));
TaskEntity task = taskService.getTask(dto.getTaskId());
validTask(historicTaskInstance, task, dto.getApprover(), dto.getNodeTypes());
Process process = ProcessDefinitionUtil.getProcess(task.getProcessDefinitionId());
FlowElement targetFlowElement = process.getFlowElement(dto.getToActivityId(), true);
if (Objects.isNull(targetFlowElement)) {
throw new WorkflowEngineException(BACK_TARGET_ACTIVITY_NOT_EXISTS, dto.getToActivityId());
} }
FlowElement sourceFlowElement = process.getFlowElement(task.getTaskDefinitionKey(), true);
String processDefinitionId = taskList.get(0).getProcessDefinitionId();
Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
FlowElement targetFlowElement = process.getFlowElement(toActivityId, true);
if (Objects.isNull(targetFlowElement)) {
throw new WorkflowEngineException(BACK_TARGET_ACTIVITY_NOT_EXISTS, toActivityId);
}
FlowElement sourceFlowElement = process.getFlowElement(currentActivityId, true);
// 退回节点到当前节点不可达到不允许退回 // 退回节点到当前节点不可达到不允许退回
if (!BpmnModelUtils.isReachable(process, (FlowNode) targetFlowElement, (FlowNode) sourceFlowElement)) { if (!BpmnModelUtils.isReachable(process, (FlowNode) targetFlowElement, (FlowNode) sourceFlowElement)) {
throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, toActivityId);
} }
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, dto.getAttachmentList(), dto.getApprover());
Authentication.setAuthenticatedUserId(dto.getApprover().buildAssigneeId());
addComment(commandContext, task, COMMENT_TYPE_ADVICE, dto.getAdvice());
addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, OPERATION_DESC + targetFlowElement.getName());
Authentication.setAuthenticatedUserId(null);
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + dto.getTaskId(), BACKED.getStatus()); taskList.forEach(th -> {
TaskEntity task = taskService.getTask(th.getId());
batchAddAttachment(commandContext, processInstanceId, task, attachmentList, approver);
Authentication.setAuthenticatedUserId(approver.buildAssigneeId());
addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice);
addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, StringUtils.hasText(operationDesc) ? operationDesc : OPERATION_DESC + targetFlowElement.getName());
Authentication.setAuthenticatedUserId(null);
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), BACKED.getStatus());
});
// 移除回退到的指定节点的变量 EngineExecutionStartListener 重新计算该节点的人 // 移除回退到的指定节点的变量 EngineExecutionStartListener 重新计算该节点的人
runtimeService.removeVariable(task.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + dto.getToActivityId()); runtimeService.removeVariable(processInstanceId, INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + toActivityId);
runtimeService.createChangeActivityStateBuilder() runtimeService.createChangeActivityStateBuilder()
.processInstanceId(task.getProcessInstanceId()) .processInstanceId(processInstanceId)
.moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId()) .moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId), toActivityId)
.changeState(); .changeState();
return null; return null;
} }

View File

@ -12,6 +12,7 @@ import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.task.api.Task; import org.flowable.task.api.Task;
import org.flowable.variable.api.delegate.VariableScope; import org.flowable.variable.api.delegate.VariableScope;
import java.util.Collections;
import java.util.Objects; import java.util.Objects;
@Slf4j @Slf4j
@ -35,7 +36,16 @@ public class AsyncBackTaskJobHandler extends AbstractExecuteWithLockJobHandler i
if (Objects.isNull(task)) { if (Objects.isNull(task)) {
return; return;
} }
processEngineConfiguration.getCommandExecutor().execute(new CustomBackTaskCmd(dto)); processEngineConfiguration.getCommandExecutor().execute(new CustomBackTaskCmd(
Collections.singletonList(dto.getTaskId()),
dto.getAdvice(),
dto.getOperationDesc(),
dto.getAttachmentList(),
dto.getApprover(),
task.getProcessInstanceId(),
task.getTaskDefinitionKey(),
dto.getToActivityId(),
true));
} }
} }

View File

@ -29,11 +29,18 @@ public interface BpmnProcessTaskService {
void approveTask(BpmnTaskAuditDTO taskAuditDTO); void approveTask(BpmnTaskAuditDTO taskAuditDTO);
void approveTaskWithForm(BpmnTaskAuditWithFormDTO taskAuditDto); void approveTaskWithForm(BpmnTaskAuditWithFormDTO taskAuditDto);
/** /**
* 回退 * 回退
*/ */
void backTask(BpmnTaskBackAuditDTO taskAuditDTO); void backTask(BpmnTaskBackAuditDTO taskAuditDTO);
/**
* 用于系统内部回退操作
* @param taskAuditDTO 请求参数
*/
void systemBackTask(BpmnNodeBackSystemOperateDTO taskAuditDTO);
/** /**
* 批量同意 * 批量同意
* *
@ -43,9 +50,10 @@ public interface BpmnProcessTaskService {
/** /**
* 回退到指定节点可以回退节点选项 * 回退到指定节点可以回退节点选项
* @param taskId 任务id * @param processInstanceId 流程实例id
* @param currentActivityId 当前节点定义id
*/ */
List<BpmnOptionalNodeDTO> getBackOptionalNodes(String taskId); List<BpmnOptionalNodeDTO> getBackOptionalNodes(String processInstanceId, String currentActivityId);
/** /**
* 驳回 * 驳回

View File

@ -5,14 +5,11 @@ import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
import cn.axzo.workflow.common.enums.BpmnFlowNodeType; import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum; import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.exception.WorkflowEngineException; import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.BpmnApproveConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf; import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
import cn.axzo.workflow.common.model.request.bpmn.task.*; import cn.axzo.workflow.common.model.request.bpmn.task.*;
import cn.axzo.workflow.common.model.response.BpmPageResult; import cn.axzo.workflow.common.model.response.BpmPageResult;
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationItemResultVO; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationItemResultVO;
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO;
import cn.axzo.workflow.common.model.response.bpmn.task.*; import cn.axzo.workflow.common.model.response.bpmn.task.*;
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper; import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
import cn.axzo.workflow.core.engine.cmd.*; import cn.axzo.workflow.core.engine.cmd.*;
@ -20,14 +17,12 @@ import cn.axzo.workflow.core.engine.event.MessagePushEventBuilder;
import cn.axzo.workflow.core.engine.event.MessagePushEventImpl; import cn.axzo.workflow.core.engine.event.MessagePushEventImpl;
import cn.axzo.workflow.core.engine.event.MessagePushEventType; import cn.axzo.workflow.core.engine.event.MessagePushEventType;
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst; import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
import cn.axzo.workflow.core.service.BpmnProcessDefinitionService; import cn.axzo.workflow.core.service.BpmnProcessDefinitionService;
import cn.axzo.workflow.core.service.BpmnProcessTaskService; import cn.axzo.workflow.core.service.BpmnProcessTaskService;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService; import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import cn.axzo.workflow.core.service.ExtAxProcessLogService; import cn.axzo.workflow.core.service.ExtAxProcessLogService;
import cn.axzo.workflow.core.service.converter.*; import cn.axzo.workflow.core.service.converter.*;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -79,8 +74,6 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.*;
import static cn.axzo.workflow.common.util.BpmnNativeQueryUtil.countSql; import static cn.axzo.workflow.common.util.BpmnNativeQueryUtil.countSql;
import static cn.axzo.workflow.common.util.BpmnNativeQueryUtil.sqlConnectors; import static cn.axzo.workflow.common.util.BpmnNativeQueryUtil.sqlConnectors;
import static cn.axzo.workflow.core.common.utils.BpmnCollectionUtils.convertSet; import static cn.axzo.workflow.core.common.utils.BpmnCollectionUtils.convertSet;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getButtonConfig;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getProcessApproveConf;
@Service @Service
@Slf4j @Slf4j
@ -295,7 +288,11 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void backTask(BpmnTaskBackAuditDTO dto) { public void backTask(BpmnTaskBackAuditDTO dto) {
List<BpmnOptionalNodeDTO> backOptionalNodes = getBackOptionalNodes(dto.getTaskId()); Task task = processEngineConfiguration.getTaskService().createTaskQuery().taskId(dto.getTaskId()).singleResult();
if (task == null) {
throw new WorkflowEngineException(PROCESS_TASK_NOT_EXISTS);
}
List<BpmnOptionalNodeDTO> backOptionalNodes = getBackOptionalNodes(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
if (CollectionUtils.isEmpty(backOptionalNodes)) { if (CollectionUtils.isEmpty(backOptionalNodes)) {
throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId()); throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId());
} }
@ -324,17 +321,73 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
if (Boolean.TRUE.equals(dto.getAsync())) { if (Boolean.TRUE.equals(dto.getAsync())) {
commandExecutor.execute(new CustomBackTaskAsyncCmd(dto)); commandExecutor.execute(new CustomBackTaskAsyncCmd(dto));
} else { } else {
commandExecutor.execute(new CustomBackTaskCmd(dto)); commandExecutor.execute(new CustomBackTaskCmd(Collections.singletonList(dto.getTaskId()),
dto.getAdvice(),
dto.getOperationDesc(),
dto.getAttachmentList(),
dto.getApprover(),
task.getProcessInstanceId(),
task.getTaskDefinitionKey(),
dto.getToActivityId(),
true));
} }
} }
@Override @Override
public List<BpmnOptionalNodeDTO> getBackOptionalNodes(String taskId) { public void systemBackTask(BpmnNodeBackSystemOperateDTO dto) {
Task task = processEngineConfiguration.getTaskService().createTaskQuery().taskId(taskId).singleResult(); //需要查询当前流程是否停留在当前节点
if (task == null) { //需要查询退回的节点是否可达
throw new WorkflowEngineException(PROCESS_TASK_NOT_EXISTS); //然后进行退回操作
ProcessEngineConfigurationImpl pcConfiguration = CommandContextUtil.getProcessEngineConfiguration();
HistoricTaskInstanceQuery taskQuery = pcConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
List<HistoricTaskInstance> taskList = taskQuery.processInstanceId(dto.getProcessInstanceId())
.taskDefinitionId(dto.getCurrentActivityId())
.list();
List<HistoricTaskInstance> valuableTasks;
if (CollectionUtils.isEmpty(taskList) || CollectionUtils.isEmpty((valuableTasks = taskList.stream()
.filter(t -> Objects.nonNull(t.getEndTime()))
.collect(Collectors.toList())))) {
throw new WorkflowEngineException(TASK_HAS_BEEN_COMPLETE);
} }
String processInstanceId = task.getProcessInstanceId(); List<BpmnOptionalNodeDTO> backOptionalNodes = getBackOptionalNodes(valuableTasks.get(0).getProcessInstanceId(), valuableTasks.get(0).getTaskDefinitionKey());
if (CollectionUtils.isEmpty(backOptionalNodes)) {
throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId());
}
List<String> activityList = backOptionalNodes.stream().map(BpmnOptionalNodeDTO::getProcessActivityId).collect(Collectors.toList());
if (!activityList.contains(dto.getToActivityId())) {
throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId());
}
Optional<String> instOpt = backOptionalNodes.stream()
.map(BpmnOptionalNodeDTO::getProcessInstanceId)
.filter(StringUtils::hasText)
.findAny();
if (instOpt.isPresent()) {
ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO();
searchDTO.setProcessInstanceId(instOpt.get());
List<ExtAxHiTaskInst> extAxHiTaskInsts = extAxHiTaskInstService.queryList(searchDTO);
if (CollectionUtils.isNotEmpty(extAxHiTaskInsts)) {
long backOpeCount = extAxHiTaskInsts.stream()
.filter(ext -> BACKED.getStatus().equals(ext.getStatus()))
.count();
if (backOpeCount > MAX_BACKED_OPERATE_COUNT) {
throw new WorkflowEngineException(REACHED_BACKED_MAXIMUM_NUM, String.valueOf(MAX_BACKED_OPERATE_COUNT));
}
}
}
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
commandExecutor.execute(new CustomBackTaskCmd(valuableTasks.stream().map(TaskInfo::getId).collect(Collectors.toList()),
dto.getAdvice(),
dto.getOperationDesc(),
dto.getAttachmentList(),
null,
valuableTasks.get(0).getProcessInstanceId(),
dto.getToActivityId(),
dto.getCurrentActivityId(),
false));
}
@Override
public List<BpmnOptionalNodeDTO> getBackOptionalNodes(String processInstanceId, String currentActivityId) {
//1.获取当前的流程实例 //1.获取当前的流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (processInstance == null) { if (processInstance == null) {
@ -393,7 +446,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
AtomicInteger index = new AtomicInteger(0); AtomicInteger index = new AtomicInteger(0);
List<BpmnOptionalNodeDTO> resultList = valuableList List<BpmnOptionalNodeDTO> resultList = valuableList
.stream() .stream()
.filter(pair -> !task.getTaskDefinitionKey().equals(pair.getLeft())) //排除当前节点 .filter(pair -> !currentActivityId.equals(pair.getLeft())) //排除当前节点
.map(pair -> flowElementMap.get(pair.getLeft())) .map(pair -> flowElementMap.get(pair.getLeft()))
.filter(flowElement -> { .filter(flowElement -> {
BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY); BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY);
@ -402,8 +455,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
.filter(flowElement -> !NODE_STARTER.getType().equals(flowElement.getId())) .filter(flowElement -> !NODE_STARTER.getType().equals(flowElement.getId()))
.map(flowElement -> BpmnOptionalNodeDTO .map(flowElement -> BpmnOptionalNodeDTO
.builder() .builder()
.processInstanceId(task.getProcessInstanceId()) .processInstanceId(processInstanceId)
.processDefinitionId(task.getProcessDefinitionId()) .processDefinitionId(processInstance.getProcessDefinitionId())
.processActivityId(flowElement.getId()) .processActivityId(flowElement.getId())
.processActivityName(flowElement.getName()) .processActivityName(flowElement.getName())
.processNodeDesc(flowElement.getName()) .processNodeDesc(flowElement.getName())

View File

@ -152,6 +152,19 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp
return success(true); return success(true);
} }
/**
* 回退到指定节点
*/
@Operation(summary = "系统操作回退任务到指定节点")
@PostMapping("/system/back")
@RepeatSubmit
@Override
public CommonResponse<Boolean> systemBackTask(@Validated @RequestBody BpmnNodeBackSystemOperateDTO dto) {
log.info("系统回退 systemBackTask===>>>参数:{}", JSON.toJSONString(dto));
bpmnProcessTaskService.systemBackTask(dto);
return success(true);
}
/** /**
* 驳回 * 驳回
*/ */