Merge remote-tracking branch 'origin/master' into feature/REQ-3581
This commit is contained in:
commit
79150dedf7
@ -89,6 +89,15 @@ public interface ProcessTaskApi {
|
||||
@PostMapping("/api/process/task/back")
|
||||
CommonResponse<Boolean> backTask(@Validated @RequestBody BpmnTaskBackAuditDTO dto);
|
||||
|
||||
/**
|
||||
* 用于系统内部操作,跳转到指定节点
|
||||
* @param dto 请求参数
|
||||
* @return 是否成功
|
||||
*/
|
||||
@Operation(summary = "系统操作回退任务到指定节点")
|
||||
@PostMapping("/api/process/task/system/back")
|
||||
CommonResponse<Boolean> systemBackTask(@Validated @RequestBody BpmnNodeBackSystemOperateDTO dto);
|
||||
|
||||
/**
|
||||
* 驳回
|
||||
*
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
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 = "可以指定任务处理", required = true)
|
||||
private List<String> targetTaskIds;
|
||||
|
||||
@ApiModelProperty(value = "意见")
|
||||
private String advice;
|
||||
|
||||
@ApiModelProperty(value = "操作描述")
|
||||
private String operationDesc;
|
||||
|
||||
@ApiModelProperty(value = "操作人")
|
||||
private BpmnTaskDelegateAssigner operator;
|
||||
|
||||
/**
|
||||
* 附件列表
|
||||
*/
|
||||
@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;
|
||||
|
||||
}
|
||||
@ -1,9 +1,14 @@
|
||||
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.model.request.bpmn.task.AttachmentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnModelUtils;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.FlowNode;
|
||||
@ -15,23 +20,27 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
||||
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.impl.persistence.entity.TaskEntity;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.TASK_COMPLETE_FAIL_NOT_EXISTS;
|
||||
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_TARGET_ACTIVITY_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
|
||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
|
||||
@ -43,66 +52,122 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
|
||||
public class CustomBackTaskCmd extends AbstractCommand<Void> implements Serializable {
|
||||
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 operator;
|
||||
private final String processInstanceId;
|
||||
private final String currentActivityId;
|
||||
private final String toActivityId;
|
||||
private final boolean validateApprover;
|
||||
|
||||
private static final String OPERATION_DESC = "回退至";
|
||||
|
||||
public CustomBackTaskCmd(CustomBackParamsDto customBackParamsDto) {
|
||||
if (customBackParamsDto == null) {
|
||||
throw new NullPointerException("customBackParamsDto is null");
|
||||
}
|
||||
if (customBackParamsDto.getOperator() == null) {
|
||||
throw new NullPointerException("operator is null");
|
||||
}
|
||||
this.targetTaskIds = customBackParamsDto.getTargetTaskIds();
|
||||
this.advice = customBackParamsDto.getAdvice();
|
||||
this.operationDesc = customBackParamsDto.getOperationDesc();
|
||||
this.attachmentList = customBackParamsDto.getAttachmentList();
|
||||
this.operator = customBackParamsDto.getOperator();
|
||||
this.processInstanceId = customBackParamsDto.getProcessInstanceId();
|
||||
this.currentActivityId = customBackParamsDto.getCurrentActivityId();
|
||||
this.toActivityId = customBackParamsDto.getToActivityId();
|
||||
this.validateApprover = customBackParamsDto.isValidateApprover();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String paramToJsonString() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("taskId", dto.getTaskId());
|
||||
params.put("advice", dto.getAdvice());
|
||||
params.put("targetTaskIds", JSON.toJSONString(this.targetTaskIds));
|
||||
params.put("advice", advice);
|
||||
params.put("operationDesc", OPERATION_DESC);
|
||||
params.put("attachmentList", JSON.toJSONString(dto.getAttachmentList()));
|
||||
params.put("approver", JSON.toJSONString(dto.getApprover()));
|
||||
params.put("nodeTypes", JSON.toJSONString(dto.getNodeTypes()));
|
||||
params.put("attachmentList", JSON.toJSONString(attachmentList));
|
||||
params.put("operator", JSON.toJSONString(operator));
|
||||
params.put("toActivityId", JSON.toJSONString(this.toActivityId));
|
||||
params.put("processInstanceId", JSON.toJSONString(this.processInstanceId));
|
||||
params.put("validateApprover", validateApprover);
|
||||
return JSON.toJSONString(params);
|
||||
}
|
||||
|
||||
public CustomBackTaskCmd(BpmnTaskBackAuditDTO dto) {
|
||||
this.dto = dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void execute(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
HistoricTaskInstanceQuery taskQuery =
|
||||
processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
|
||||
TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService();
|
||||
|
||||
HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult();
|
||||
|
||||
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());
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
List<HistoricTaskInstance> taskList = processEngineConfiguration.getHistoryService()
|
||||
.createHistoricTaskInstanceQuery()
|
||||
.taskDefinitionKey(currentActivityId)
|
||||
.processInstanceId(processInstanceId)
|
||||
.list();
|
||||
List<HistoricTaskInstance> valueableTaskList = taskList.stream()
|
||||
.filter(hi -> {
|
||||
if (hi.getEndTime() != null) {
|
||||
return false;
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(targetTaskIds)) {
|
||||
return targetTaskIds.contains(hi.getId());
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(valueableTaskList)) {
|
||||
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_NOT_EXISTS);
|
||||
}
|
||||
FlowElement sourceFlowElement = process.getFlowElement(task.getTaskDefinitionKey(), true);
|
||||
TaskService taskService = processEngineConfiguration.getTaskServiceConfiguration().getTaskService();
|
||||
if (validateApprover) {
|
||||
valueableTaskList.forEach(hi -> validTask(hi, taskService.getTask(hi.getId()), operator, null));
|
||||
}
|
||||
String processDefinitionId = valueableTaskList.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)) {
|
||||
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();
|
||||
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + dto.getTaskId(), BACKED.getStatus());
|
||||
|
||||
valueableTaskList.forEach(th -> {
|
||||
TaskEntity task = taskService.getTask(th.getId());
|
||||
Authentication.setAuthenticatedUserId(operator.buildAssigneeId());
|
||||
batchAddAttachment(commandContext, processInstanceId, task, attachmentList, operator);
|
||||
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 重新计算该节点的人
|
||||
runtimeService.removeVariable(task.getProcessInstanceId(), INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + dto.getToActivityId());
|
||||
runtimeService.removeVariable(processInstanceId, INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + toActivityId);
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveActivityIdsToSingleActivityId(Collections.singletonList(task.getTaskDefinitionKey()), dto.getToActivityId())
|
||||
.changeState();
|
||||
.processInstanceId(processInstanceId)
|
||||
.moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId), toActivityId)
|
||||
.changeState();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public static final class CustomBackParamsDto {
|
||||
private List<String> targetTaskIds;
|
||||
private String advice;
|
||||
private String operationDesc;
|
||||
private List<AttachmentDTO> attachmentList;
|
||||
private BpmnTaskDelegateAssigner operator;
|
||||
private String processInstanceId;
|
||||
private String currentActivityId;
|
||||
private String toActivityId;
|
||||
private boolean validateApprover;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.variable.api.delegate.VariableScope;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@ -35,7 +36,17 @@ public class AsyncBackTaskJobHandler extends AbstractExecuteWithLockJobHandler i
|
||||
if (Objects.isNull(task)) {
|
||||
return;
|
||||
}
|
||||
processEngineConfiguration.getCommandExecutor().execute(new CustomBackTaskCmd(dto));
|
||||
processEngineConfiguration.getCommandExecutor().execute(new CustomBackTaskCmd(
|
||||
CustomBackTaskCmd.CustomBackParamsDto.builder()
|
||||
.targetTaskIds(Collections.singletonList(dto.getTaskId()))
|
||||
.advice(dto.getAdvice())
|
||||
.operationDesc(dto.getOperationDesc())
|
||||
.attachmentList(dto.getAttachmentList())
|
||||
.operator(dto.getApprover())
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.currentActivityId(task.getTaskDefinitionKey())
|
||||
.toActivityId(dto.getToActivityId())
|
||||
.validateApprover(true)
|
||||
.build()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -29,11 +29,18 @@ public interface BpmnProcessTaskService {
|
||||
void approveTask(BpmnTaskAuditDTO taskAuditDTO);
|
||||
|
||||
void approveTaskWithForm(BpmnTaskAuditWithFormDTO taskAuditDto);
|
||||
|
||||
/**
|
||||
* 回退
|
||||
*/
|
||||
void backTask(BpmnTaskBackAuditDTO taskAuditDTO);
|
||||
|
||||
/**
|
||||
* 用于系统内部回退操作
|
||||
* @param taskAuditDTO 请求参数
|
||||
*/
|
||||
void systemBackTask(BpmnNodeBackSystemOperateDTO taskAuditDTO);
|
||||
|
||||
/**
|
||||
* 批量同意
|
||||
*
|
||||
@ -43,9 +50,16 @@ public interface BpmnProcessTaskService {
|
||||
|
||||
/**
|
||||
* 回退到指定节点,可以回退节点选项
|
||||
* @param taskId 任务id
|
||||
* @param taskId 流程任务id
|
||||
*/
|
||||
List<BpmnOptionalNodeDTO> getBackOptionalNodes(String taskId);
|
||||
List<BpmnOptionalNodeDTO> getBackOptionalNodesByTaskId(String taskId);
|
||||
|
||||
/**
|
||||
* 回退到指定节点,可以回退节点选项
|
||||
* @param processInstanceId 流程实例id
|
||||
* @param currentActivityId 当前节点定义id
|
||||
*/
|
||||
List<BpmnOptionalNodeDTO> getBackOptionalNodes(String processInstanceId, String currentActivityId);
|
||||
|
||||
/**
|
||||
* 驳回
|
||||
|
||||
@ -20,6 +20,21 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnNodeBackSystemOperateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditWithFormDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO;
|
||||
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.BatchOperationResultVO;
|
||||
@ -143,6 +158,35 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETE
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.valueOfStatus;
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_TASK_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.FIND_TASK_BY_PERSON_ID_ERROR;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.REACHED_BACKED_MAXIMUM_NUM;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_HAS_BEEN_COMPLETE;
|
||||
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.TASK_REMIND_ERROR_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_COMMENT_EXT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.MAX_BACKED_OPERATE_COUNT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_BUSINESS;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CARBON_COPY;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.BACKED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.DELETED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.valueOfStatus;
|
||||
import static cn.axzo.workflow.common.util.BpmnNativeQueryUtil.countSql;
|
||||
import static cn.axzo.workflow.common.util.BpmnNativeQueryUtil.sqlConnectors;
|
||||
import static cn.axzo.workflow.core.common.utils.BpmnCollectionUtils.convertSet;
|
||||
@ -361,7 +405,11 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
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.getProcessInstanceId(), task.getTaskDefinitionKey());
|
||||
if (CollectionUtils.isEmpty(backOptionalNodes)) {
|
||||
throw new WorkflowEngineException(BACK_NODE_CANNOT_REACHABLE, dto.getToActivityId());
|
||||
}
|
||||
@ -390,17 +438,98 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
if (Boolean.TRUE.equals(dto.getAsync())) {
|
||||
commandExecutor.execute(new CustomBackTaskAsyncCmd(dto));
|
||||
} else {
|
||||
commandExecutor.execute(new CustomBackTaskCmd(dto));
|
||||
commandExecutor.execute(new CustomBackTaskCmd(CustomBackTaskCmd.CustomBackParamsDto.builder()
|
||||
.targetTaskIds(Collections.singletonList(dto.getTaskId()))
|
||||
.advice(dto.getAdvice())
|
||||
.operationDesc(dto.getOperationDesc())
|
||||
.attachmentList(dto.getAttachmentList())
|
||||
.operator(dto.getApprover())
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.currentActivityId(task.getTaskDefinitionKey())
|
||||
.toActivityId(dto.getToActivityId())
|
||||
.validateApprover(true)
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmnOptionalNodeDTO> getBackOptionalNodes(String taskId) {
|
||||
public void systemBackTask(BpmnNodeBackSystemOperateDTO dto) {
|
||||
//需要查询当前流程是否停留在当前节点
|
||||
//需要查询退回的节点是否可达
|
||||
//然后进行退回操作
|
||||
List<HistoricTaskInstance> taskList = processEngineConfiguration.getHistoryService()
|
||||
.createHistoricTaskInstanceQuery()
|
||||
.taskDefinitionKey(dto.getCurrentActivityId())
|
||||
.processInstanceId(dto.getProcessInstanceId())
|
||||
.list();
|
||||
if (CollectionUtils.isEmpty(taskList)) {
|
||||
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_NOT_EXISTS);
|
||||
}
|
||||
List<HistoricTaskInstance> valuableTasks = taskList.stream()
|
||||
.filter(t -> Objects.isNull(t.getEndTime()))
|
||||
.filter(t -> {
|
||||
if (CollectionUtils.isNotEmpty(dto.getTargetTaskIds())) {
|
||||
return dto.getTargetTaskIds().contains(t.getId());
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(valuableTasks)) {
|
||||
throw new WorkflowEngineException(TASK_HAS_BEEN_COMPLETE);
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
BpmnTaskDelegateAssigner operator = dto.getOperator();
|
||||
if (operator == null) {
|
||||
operator = new BpmnTaskDelegateAssigner("系统", "system", taskList.get(0).getTenantId());
|
||||
}
|
||||
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
|
||||
commandExecutor.execute(new CustomBackTaskCmd(CustomBackTaskCmd.CustomBackParamsDto.builder()
|
||||
.targetTaskIds(valuableTasks.stream().map(TaskInfo::getId).collect(Collectors.toList()))
|
||||
.advice(dto.getAdvice())
|
||||
.operationDesc(dto.getOperationDesc())
|
||||
.attachmentList(dto.getAttachmentList())
|
||||
.operator(operator)
|
||||
.processInstanceId(valuableTasks.get(0).getProcessInstanceId())
|
||||
.currentActivityId(dto.getCurrentActivityId())
|
||||
.toActivityId(dto.getToActivityId())
|
||||
.build()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmnOptionalNodeDTO> getBackOptionalNodesByTaskId(String taskId) {
|
||||
Task task = processEngineConfiguration.getTaskService().createTaskQuery().taskId(taskId).singleResult();
|
||||
if (task == null) {
|
||||
throw new WorkflowEngineException(PROCESS_TASK_NOT_EXISTS);
|
||||
}
|
||||
String processInstanceId = task.getProcessInstanceId();
|
||||
return this.getBackOptionalNodes(task.getProcessInstanceId(), task.getTaskDefinitionKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmnOptionalNodeDTO> getBackOptionalNodes(String processInstanceId, String currentActivityId) {
|
||||
//1.获取当前的流程实例
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
if (processInstance == null) {
|
||||
@ -459,7 +588,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
AtomicInteger index = new AtomicInteger(0);
|
||||
List<BpmnOptionalNodeDTO> resultList = valuableList
|
||||
.stream()
|
||||
.filter(pair -> !task.getTaskDefinitionKey().equals(pair.getLeft())) //排除当前节点
|
||||
.filter(pair -> !currentActivityId.equals(pair.getLeft())) //排除当前节点
|
||||
.map(pair -> flowElementMap.get(pair.getLeft()))
|
||||
.filter(flowElement -> {
|
||||
BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(flowElement).orElse(NODE_EMPTY);
|
||||
@ -468,8 +597,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
.filter(flowElement -> !NODE_STARTER.getType().equals(flowElement.getId()))
|
||||
.map(flowElement -> BpmnOptionalNodeDTO
|
||||
.builder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.processDefinitionId(task.getProcessDefinitionId())
|
||||
.processInstanceId(processInstanceId)
|
||||
.processDefinitionId(processInstance.getProcessDefinitionId())
|
||||
.processActivityId(flowElement.getId())
|
||||
.processActivityName(flowElement.getName())
|
||||
.processNodeDesc(flowElement.getName())
|
||||
|
||||
@ -139,7 +139,7 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp
|
||||
@GetMapping("/back/optional/nodes")
|
||||
@Override
|
||||
public CommonResponse<List<BpmnOptionalNodeDTO>> getBackOptionalNodes(@RequestParam @NotBlank(message = "任务id不能为空") String taskId) {
|
||||
List<BpmnOptionalNodeDTO> approveOptionalNodes = bpmnProcessTaskService.getBackOptionalNodes(taskId);
|
||||
List<BpmnOptionalNodeDTO> approveOptionalNodes = bpmnProcessTaskService.getBackOptionalNodesByTaskId(taskId);
|
||||
return success(approveOptionalNodes);
|
||||
}
|
||||
|
||||
@ -157,6 +157,19 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user