mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-08 04:39:00 +08:00
feat(pigx-flow-biz): 新增流程撤回功能
- 在 ITaskService 接口中添加 withdrawProcessInstance 方法用于撤回流程实例 - 实现 TaskServiceImpl 中的撤回逻辑,包括权限校验和流程状态更新 - 新增 terminateProcessInstance 私有方法统一处理流程终止和撤回操作 - 在 ProcessInstanceRecordVo 中添加撤回相关字段 canWithdraw 和 withdrawDisabledReason - 优化 ProcessInstanceServiceImpl 查询逻辑,批量处理驳回状态和撤回状态判断 - 在 ProcessTaskController 中添加撤回流程实例的接口端点 - 定义流程撤回相关的常量,包括结束原因和执行人状态
This commit is contained in:
1 parent
b553787cfd
commit
f759865202
6 files changed
+354
-62
No files matched your search
+30
@@ -60,6 +60,36 @@ public class ProcessInstanceConstant {
|
||||
*/
|
||||
public static final String REJECT_TO_STARTER_VAR = "rejectToStarter";
|
||||
|
||||
/**
|
||||
* 流程结束原因:拒绝
|
||||
*/
|
||||
public static final String FINISH_REASON_REFUSE = "0";
|
||||
|
||||
/**
|
||||
* 流程结束原因:通过
|
||||
*/
|
||||
public static final String FINISH_REASON_PASS = "1";
|
||||
|
||||
/**
|
||||
* 流程结束原因:撤回
|
||||
*/
|
||||
public static final String FINISH_REASON_WITHDRAW = "3";
|
||||
|
||||
/**
|
||||
* 流程结束原因:终止
|
||||
*/
|
||||
public static final String FINISH_REASON_TERMINATE = "9";
|
||||
|
||||
/**
|
||||
* 流程节点执行人状态:撤回
|
||||
*/
|
||||
public static final int ASSIGN_USER_STATUS_WITHDRAW = 3;
|
||||
|
||||
/**
|
||||
* 流程节点执行人状态:终止
|
||||
*/
|
||||
public static final int ASSIGN_USER_STATUS_TERMINATE = 5;
|
||||
|
||||
/**
|
||||
* 多人审批模式:会签 所有审批人都必须同意才能通过,任何一人拒绝则不通过
|
||||
*/
|
||||
|
||||
+10
@@ -44,4 +44,14 @@ public class ProcessInstanceRecordVo extends ProcessInstanceRecord {
|
||||
*/
|
||||
private Boolean hasPrintTemplate;
|
||||
|
||||
/**
|
||||
* 是否允许撤回
|
||||
*/
|
||||
private Boolean canWithdraw;
|
||||
|
||||
/**
|
||||
* 不可撤回原因
|
||||
*/
|
||||
private String withdrawDisabledReason;
|
||||
|
||||
}
|
||||
+11
@@ -144,6 +144,17 @@ public class ProcessTaskController {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回流程实例
|
||||
*
|
||||
* @param taskParamDto 撤回参数,包含流程实例ID
|
||||
* @return R 统一响应对象,操作成功返回撤回信息
|
||||
*/
|
||||
@PostMapping("withdrawProcessInstance")
|
||||
public R withdrawProcessInstance(@RequestBody TaskParamDto taskParamDto) {
|
||||
return taskService.withdrawProcessInstance(taskParamDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退回任务
|
||||
* <p>
|
||||
|
||||
+8
@@ -87,6 +87,14 @@ public interface ITaskService {
|
||||
*/
|
||||
R stopProcessInstance(TaskParamDto taskParamDto);
|
||||
|
||||
/**
|
||||
* 撤回流程实例
|
||||
*
|
||||
* @param taskParamDto 任务参数,包含流程实例ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
R withdrawProcessInstance(TaskParamDto taskParamDto);
|
||||
|
||||
/**
|
||||
* 退回任务
|
||||
* <p>
|
||||
|
||||
+170
-27
@@ -18,11 +18,10 @@ import com.pig4cloud.pigx.common.security.service.PigxUser;
|
||||
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
|
||||
import com.pig4cloud.pigx.flow.constant.NodeStatusEnum;
|
||||
import com.pig4cloud.pigx.flow.constant.NodeUserTypeEnum;
|
||||
import com.pig4cloud.pigx.flow.constant.ProcessInstanceConstant;
|
||||
import com.pig4cloud.pigx.flow.dto.*;
|
||||
import com.pig4cloud.pigx.flow.entity.*;
|
||||
import com.pig4cloud.pigx.flow.entity.Process;
|
||||
import com.pig4cloud.pigx.flow.entity.ProcessCopy;
|
||||
import com.pig4cloud.pigx.flow.entity.ProcessInstanceRecord;
|
||||
import com.pig4cloud.pigx.flow.entity.ProcessNodeRecord;
|
||||
import com.pig4cloud.pigx.flow.service.*;
|
||||
import com.pig4cloud.pigx.flow.support.utils.NodeFormatUtil;
|
||||
import com.pig4cloud.pigx.flow.support.utils.NodeUtil;
|
||||
@@ -42,6 +41,7 @@ import org.flowable.engine.history.HistoricActivityInstanceQuery;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.task.api.Task;
|
||||
import org.flowable.task.api.TaskQuery;
|
||||
import org.flowable.variable.api.history.HistoricVariableInstance;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.ZoneId;
|
||||
@@ -82,6 +82,8 @@ public class ProcessInstanceServiceImpl implements IProcessInstanceService {
|
||||
|
||||
private final IProcessNodeRecordService processNodeRecordService;
|
||||
|
||||
private final IProcessNodeRecordAssignUserService processNodeRecordAssignUserService;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
@@ -374,36 +376,59 @@ public class ProcessInstanceServiceImpl implements IProcessInstanceService {
|
||||
.collect(Collectors.toSet());
|
||||
List<Process> processList = CollUtil.isEmpty(flowIds) ? Collections.emptyList()
|
||||
: processService.lambdaQuery().in(Process::getFlowId, flowIds).list();
|
||||
Set<String> processInstanceIds = voList.stream()
|
||||
.map(ProcessInstanceRecordVo::getProcessInstanceId)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
Map<String, List<ProcessNodeRecordAssignUser>> assignUserMap = queryAssignUserMap(processInstanceIds);
|
||||
|
||||
// 批量查询进行中流程的 rejectToStarter 变量,避免 N+1
|
||||
Set<String> runningInstanceIds = voList.stream()
|
||||
.filter(vo -> Objects.equals(vo.getStatus(), NodeStatusEnum.JXZ.getCode()))
|
||||
.map(ProcessInstanceRecordVo::getProcessInstanceId)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<String> rejectToStarterIds = batchQueryRejectToStarter(runningInstanceIds);
|
||||
|
||||
// 批量查询驳回待提交的 root 任务,避免 N+1
|
||||
Map<String, String> resubmitTaskMap = Collections.emptyMap();
|
||||
if (!rejectToStarterIds.isEmpty()) {
|
||||
resubmitTaskMap = taskService.createTaskQuery()
|
||||
.processInstanceIdIn(rejectToStarterIds)
|
||||
.taskDefinitionKey("root")
|
||||
.list()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Task::getProcessInstanceId, Task::getId, (a, b) -> a));
|
||||
}
|
||||
|
||||
// 构建打印模板 Map,避免循环内 stream 遍历
|
||||
Map<String, Process> processMap = processList.stream()
|
||||
.collect(Collectors.toMap(p -> p.getFlowId().toLowerCase(), p -> p, (a, b) -> a));
|
||||
|
||||
for (ProcessInstanceRecordVo vo : voList) {
|
||||
try {
|
||||
// 从 Flowable 变量中获取 rejectToStarter 状态
|
||||
Object rejectVar = runtimeService.getVariable(
|
||||
vo.getProcessInstanceId(),
|
||||
"rejectToStarter"
|
||||
);
|
||||
vo.setRejectToStarter(Boolean.TRUE.equals(rejectVar));
|
||||
boolean rejectToStarter = false;
|
||||
if (Objects.equals(vo.getStatus(), NodeStatusEnum.JXZ.getCode())) {
|
||||
rejectToStarter = rejectToStarterIds.contains(vo.getProcessInstanceId());
|
||||
vo.setRejectToStarter(rejectToStarter);
|
||||
|
||||
// 如果是驳回状态,获取 root 任务 ID 用于重新提交
|
||||
if (Boolean.TRUE.equals(vo.getRejectToStarter())) {
|
||||
Task task = taskService.createTaskQuery()
|
||||
.processInstanceId(vo.getProcessInstanceId())
|
||||
.taskDefinitionKey("root")
|
||||
.singleResult();
|
||||
if (task != null) {
|
||||
vo.setResubmitTaskId(task.getId());
|
||||
}
|
||||
if (rejectToStarter) {
|
||||
vo.setResubmitTaskId(resubmitTaskMap.get(vo.getProcessInstanceId()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 流程可能已结束,设置为 false
|
||||
} else {
|
||||
vo.setRejectToStarter(false);
|
||||
}
|
||||
|
||||
// 检查是否配置了打印模板(不依赖运行时变量,无需放在 try-catch 内)
|
||||
processList.stream()
|
||||
.filter(process -> process.getFlowId().equalsIgnoreCase(vo.getFlowId()))
|
||||
.findFirst()
|
||||
.ifPresent(process -> vo.setHasPrintTemplate(StrUtil.isNotBlank(process.getPrintTemplate())));
|
||||
WithdrawState withdrawState = buildWithdrawState(vo, vo.getRejectToStarter(),
|
||||
assignUserMap.getOrDefault(vo.getProcessInstanceId(), Collections.emptyList()));
|
||||
vo.setCanWithdraw(withdrawState.canWithdraw);
|
||||
vo.setWithdrawDisabledReason(withdrawState.disabledReason);
|
||||
|
||||
// 检查是否配置了打印模板
|
||||
Process matchedProcess = processMap.get(vo.getFlowId().toLowerCase());
|
||||
if (matchedProcess != null) {
|
||||
vo.setHasPrintTemplate(StrUtil.isNotBlank(matchedProcess.getPrintTemplate()));
|
||||
}
|
||||
}
|
||||
|
||||
// 构建返回的分页对象
|
||||
@@ -549,10 +574,128 @@ public class ProcessInstanceServiceImpl implements IProcessInstanceService {
|
||||
|
||||
Node nodeDto = objectMapper.readValue(process, Node.class);
|
||||
Map<String, String> formPerms1 = nodeDto.getFormPerms();
|
||||
boolean rejectToStarter = Objects.equals(processInstanceRecord.getStatus(), NodeStatusEnum.JXZ.getCode())
|
||||
&& isRejectToStarter(processInstanceId);
|
||||
WithdrawState withdrawState = buildWithdrawState(processInstanceRecord, rejectToStarter,
|
||||
queryAssignUserMap(Collections.singleton(processInstanceId))
|
||||
.getOrDefault(processInstanceId, Collections.emptyList()));
|
||||
|
||||
Dict set = Dict.create().set(ProcessInstanceRecord.Fields.processInstanceId, processInstanceId).set(ProcessInstanceRecord.Fields.status, processInstanceRecord.getStatus()).set("process", oaForms.getProcess()).set("formItems", oaForms.getFormItems()).set("formData", formData).set("formConfig", oaForms.getFormConfig()).set("formPerms", formPerms1);
|
||||
Dict set = Dict.create()
|
||||
.set(ProcessInstanceRecord.Fields.processInstanceId, processInstanceId)
|
||||
.set(ProcessInstanceRecord.Fields.status, processInstanceRecord.getStatus())
|
||||
.set("finishReason", processInstanceRecord.getFinishReason())
|
||||
.set("rejectToStarter", rejectToStarter)
|
||||
.set("canWithdraw", withdrawState.canWithdraw)
|
||||
.set("withdrawDisabledReason", withdrawState.disabledReason)
|
||||
.set("process", oaForms.getProcess())
|
||||
.set("formItems", oaForms.getFormItems())
|
||||
.set("formData", formData)
|
||||
.set("formConfig", oaForms.getFormConfig())
|
||||
.set("formPerms", formPerms1);
|
||||
|
||||
return R.ok(set);
|
||||
}
|
||||
|
||||
private Map<String, List<ProcessNodeRecordAssignUser>> queryAssignUserMap(Set<String> processInstanceIds) {
|
||||
if (CollUtil.isEmpty(processInstanceIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return processNodeRecordAssignUserService.lambdaQuery()
|
||||
.in(ProcessNodeRecordAssignUser::getProcessInstanceId, processInstanceIds)
|
||||
.ne(ProcessNodeRecordAssignUser::getNodeId, "root")
|
||||
.list()
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(ProcessNodeRecordAssignUser::getProcessInstanceId));
|
||||
}
|
||||
|
||||
private boolean isRejectToStarter(String processInstanceId) {
|
||||
try {
|
||||
Object rejectVar = runtimeService.getVariable(processInstanceId,
|
||||
ProcessInstanceConstant.REJECT_TO_STARTER_VAR);
|
||||
return Boolean.TRUE.equals(rejectVar);
|
||||
} catch (Exception e) {
|
||||
log.debug("查询驳回待提交状态失败: processInstanceId={}, error={}", processInstanceId, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询流程实例的驳回到发起人状态
|
||||
*
|
||||
* @param processInstanceIds 流程实例ID集合
|
||||
* @return 处于驳回待提交状态的流程实例ID集合
|
||||
*/
|
||||
private Set<String> batchQueryRejectToStarter(Set<String> processInstanceIds) {
|
||||
if (CollUtil.isEmpty(processInstanceIds)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
try {
|
||||
return historyService.createHistoricVariableInstanceQuery()
|
||||
.processInstanceIds(processInstanceIds)
|
||||
.variableName(ProcessInstanceConstant.REJECT_TO_STARTER_VAR)
|
||||
.list()
|
||||
.stream()
|
||||
.filter(v -> Boolean.TRUE.equals(v.getValue()))
|
||||
.map(HistoricVariableInstance::getProcessInstanceId)
|
||||
.collect(Collectors.toSet());
|
||||
} catch (Exception e) {
|
||||
log.warn("批量查询驳回状态失败,降级为逐条查询: {}", e.getMessage());
|
||||
return processInstanceIds.stream()
|
||||
.filter(this::isRejectToStarter)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
private WithdrawState buildWithdrawState(ProcessInstanceRecord processInstanceRecord, Boolean rejectToStarter,
|
||||
List<ProcessNodeRecordAssignUser> assignUsers) {
|
||||
if (!Objects.equals(processInstanceRecord.getStatus(), NodeStatusEnum.JXZ.getCode())) {
|
||||
return new WithdrawState(false, getFinishedProcessReason(processInstanceRecord.getFinishReason()));
|
||||
}
|
||||
|
||||
if (Boolean.TRUE.equals(rejectToStarter)) {
|
||||
return new WithdrawState(false, "驳回待提交状态不可撤回");
|
||||
}
|
||||
|
||||
boolean hasProcessedApproval = assignUsers.stream().anyMatch(this::isProcessedAssignUser);
|
||||
if (hasProcessedApproval) {
|
||||
return new WithdrawState(false, "首个审批节点已处理,无法撤回");
|
||||
}
|
||||
|
||||
return new WithdrawState(true, null);
|
||||
}
|
||||
|
||||
private boolean isProcessedAssignUser(ProcessNodeRecordAssignUser assignUser) {
|
||||
return assignUser.getEndTime() != null
|
||||
|| !Objects.equals(assignUser.getStatus(), NodeStatusEnum.JXZ.getCode());
|
||||
}
|
||||
|
||||
private String getFinishedProcessReason(String finishReason) {
|
||||
if (StrUtil.equals(finishReason, ProcessInstanceConstant.FINISH_REASON_WITHDRAW)) {
|
||||
return "流程已撤回";
|
||||
}
|
||||
if (StrUtil.equals(finishReason, ProcessInstanceConstant.FINISH_REASON_TERMINATE)) {
|
||||
return "流程已终止";
|
||||
}
|
||||
if (StrUtil.equals(finishReason, ProcessInstanceConstant.FINISH_REASON_PASS)) {
|
||||
return "流程已通过";
|
||||
}
|
||||
if (StrUtil.equals(finishReason, ProcessInstanceConstant.FINISH_REASON_REFUSE)) {
|
||||
return "流程已拒绝";
|
||||
}
|
||||
return "流程已结束";
|
||||
}
|
||||
|
||||
private static final class WithdrawState {
|
||||
|
||||
private final boolean canWithdraw;
|
||||
|
||||
private final String disabledReason;
|
||||
|
||||
private WithdrawState(boolean canWithdraw, String disabledReason) {
|
||||
this.canWithdraw = canWithdraw;
|
||||
this.disabledReason = disabledReason;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+125
-35
@@ -10,14 +10,13 @@ import com.pig4cloud.pigx.common.core.util.R;
|
||||
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
|
||||
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
|
||||
import com.pig4cloud.pigx.flow.constant.NodeStatusEnum;
|
||||
import com.pig4cloud.pigx.flow.constant.ProcessInstanceConstant;
|
||||
import com.pig4cloud.pigx.flow.dto.IndexPageStatistics;
|
||||
import com.pig4cloud.pigx.flow.dto.Node;
|
||||
import com.pig4cloud.pigx.flow.dto.TaskParamDto;
|
||||
import com.pig4cloud.pigx.flow.dto.TaskResultDto;
|
||||
import com.pig4cloud.pigx.flow.entity.*;
|
||||
import com.pig4cloud.pigx.flow.entity.Process;
|
||||
import com.pig4cloud.pigx.flow.entity.ProcessCopy;
|
||||
import com.pig4cloud.pigx.flow.entity.ProcessInstanceRecord;
|
||||
import com.pig4cloud.pigx.flow.entity.ProcessNodeRecordAssignUser;
|
||||
import com.pig4cloud.pigx.flow.service.*;
|
||||
import com.pig4cloud.pigx.flow.support.utils.NodeUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -67,6 +66,8 @@ public class TaskServiceImpl implements ITaskService {
|
||||
|
||||
private final IProcessInstanceRecordService processInstanceRecordService;
|
||||
|
||||
private final IProcessNodeRecordService processNodeRecordService;
|
||||
|
||||
private final IFlowableEngineService flowableEngineService;
|
||||
|
||||
private final TaskService taskService;
|
||||
@@ -476,39 +477,60 @@ public class TaskServiceImpl implements ITaskService {
|
||||
*/
|
||||
@Override
|
||||
public R stopProcessInstance(TaskParamDto taskParamDto) {
|
||||
String reqProcessInstanceId = taskParamDto.getProcessInstanceId();
|
||||
List<String> allStopProcessInstanceIdList = getAllStopProcessInstanceIdList(reqProcessInstanceId);
|
||||
CollUtil.reverse(allStopProcessInstanceIdList);
|
||||
allStopProcessInstanceIdList.add(reqProcessInstanceId);
|
||||
allStopProcessInstanceIdList.forEach(processInstanceId -> {
|
||||
// 查询流程实例
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(processInstanceId)
|
||||
.processInstanceTenantId(TenantContextHolder.getTenantId().toString())
|
||||
.singleResult();
|
||||
if (Optional.ofNullable(processInstance).isPresent()) {
|
||||
// 查询执行实例
|
||||
List<String> executionIds = runtimeService.createExecutionQuery()
|
||||
.parentId(processInstanceId)
|
||||
.list()
|
||||
.stream()
|
||||
.map(Execution::getId)
|
||||
.toList();
|
||||
// 更改活动状态为结束
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.moveExecutionsToSingleActivityId(executionIds, "end")
|
||||
.changeState();
|
||||
}
|
||||
});
|
||||
return terminateProcessInstance(taskParamDto.getProcessInstanceId(),
|
||||
ProcessInstanceConstant.FINISH_REASON_TERMINATE);
|
||||
}
|
||||
|
||||
// 停止流程实例后,更新流程实例记录状态
|
||||
processInstanceRecordService.lambdaUpdate()
|
||||
.set(ProcessInstanceRecord::getStatus, NodeStatusEnum.YJS.getCode())
|
||||
.set(ProcessInstanceRecord::getFinishReason, String.valueOf(NodeStatusEnum.YZZ.getCode()))
|
||||
.set(ProcessInstanceRecord::getEndTime, new Date())
|
||||
.eq(ProcessInstanceRecord::getProcessInstanceId, reqProcessInstanceId)
|
||||
.update(new ProcessInstanceRecord());
|
||||
return R.ok();
|
||||
/**
|
||||
* 撤回流程
|
||||
*
|
||||
* @param taskParamDto 任务参数,包含流程实例ID
|
||||
* @return R 操作结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R withdrawProcessInstance(TaskParamDto taskParamDto) {
|
||||
String processInstanceId = taskParamDto.getProcessInstanceId();
|
||||
if (StrUtil.isBlank(processInstanceId)) {
|
||||
return R.failed("流程实例ID不能为空");
|
||||
}
|
||||
|
||||
long userId = SecurityUtils.getUser().getId();
|
||||
ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery()
|
||||
.eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId)
|
||||
.one();
|
||||
if (processInstanceRecord == null
|
||||
|| !Objects.equals(processInstanceRecord.getStatus(), NodeStatusEnum.JXZ.getCode())) {
|
||||
return R.failed("流程不存在或已结束");
|
||||
}
|
||||
|
||||
if (!Objects.equals(processInstanceRecord.getUserId(), userId)) {
|
||||
return R.failed("仅发起人可撤回流程");
|
||||
}
|
||||
|
||||
try {
|
||||
Object rejectToStarter = runtimeService.getVariable(processInstanceId,
|
||||
ProcessInstanceConstant.REJECT_TO_STARTER_VAR);
|
||||
if (Boolean.TRUE.equals(rejectToStarter)) {
|
||||
return R.failed("驳回待提交状态不可撤回");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询撤回状态变量失败: processInstanceId={}, error={}", processInstanceId, e.getMessage());
|
||||
}
|
||||
|
||||
boolean hasProcessedApproval = processNodeRecordAssignUserService.lambdaQuery()
|
||||
.eq(ProcessNodeRecordAssignUser::getProcessInstanceId, processInstanceId)
|
||||
.ne(ProcessNodeRecordAssignUser::getNodeId, "root")
|
||||
.and(wrapper -> wrapper
|
||||
.isNotNull(ProcessNodeRecordAssignUser::getEndTime)
|
||||
.or()
|
||||
.ne(ProcessNodeRecordAssignUser::getStatus, NodeStatusEnum.JXZ.getCode()))
|
||||
.exists();
|
||||
if (hasProcessedApproval) {
|
||||
return R.failed("首个审批节点已处理,无法撤回");
|
||||
}
|
||||
|
||||
return terminateProcessInstance(processInstanceId, ProcessInstanceConstant.FINISH_REASON_WITHDRAW);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -626,4 +648,72 @@ public class TaskServiceImpl implements ITaskService {
|
||||
return collect;
|
||||
}
|
||||
|
||||
private R terminateProcessInstance(String reqProcessInstanceId, String finishReason) {
|
||||
if (StrUtil.isBlank(reqProcessInstanceId)) {
|
||||
return R.failed("流程实例ID不能为空");
|
||||
}
|
||||
|
||||
List<String> allStopProcessInstanceIdList = getAllStopProcessInstanceIdList(reqProcessInstanceId);
|
||||
CollUtil.reverse(allStopProcessInstanceIdList);
|
||||
allStopProcessInstanceIdList.add(reqProcessInstanceId);
|
||||
|
||||
Date now = new Date();
|
||||
int assignUserStatus = Objects.equals(finishReason, ProcessInstanceConstant.FINISH_REASON_WITHDRAW)
|
||||
? ProcessInstanceConstant.ASSIGN_USER_STATUS_WITHDRAW
|
||||
: ProcessInstanceConstant.ASSIGN_USER_STATUS_TERMINATE;
|
||||
|
||||
// 先更新本地记录,确保流程结束通知能拿到准确的 finishReason
|
||||
processInstanceRecordService.lambdaUpdate()
|
||||
.set(ProcessInstanceRecord::getStatus, NodeStatusEnum.YJS.getCode())
|
||||
.set(ProcessInstanceRecord::getFinishReason, finishReason)
|
||||
.set(ProcessInstanceRecord::getEndTime, now)
|
||||
.in(ProcessInstanceRecord::getProcessInstanceId, allStopProcessInstanceIdList)
|
||||
.update(new ProcessInstanceRecord());
|
||||
|
||||
processNodeRecordService.lambdaUpdate()
|
||||
.set(ProcessNodeRecord::getStatus, NodeStatusEnum.YJS.getCode())
|
||||
.set(ProcessNodeRecord::getEndTime, now)
|
||||
.in(ProcessNodeRecord::getProcessInstanceId, allStopProcessInstanceIdList)
|
||||
.eq(ProcessNodeRecord::getStatus, NodeStatusEnum.JXZ.getCode())
|
||||
.update(new ProcessNodeRecord());
|
||||
|
||||
processNodeRecordAssignUserService.lambdaUpdate()
|
||||
.set(ProcessNodeRecordAssignUser::getStatus, assignUserStatus)
|
||||
.set(ProcessNodeRecordAssignUser::getEndTime, Convert.toLocalDateTime(now))
|
||||
.set(ProcessNodeRecordAssignUser::getTaskType,
|
||||
Objects.equals(finishReason, ProcessInstanceConstant.FINISH_REASON_WITHDRAW)
|
||||
? "WITHDRAW"
|
||||
: "TERMINATE")
|
||||
.in(ProcessNodeRecordAssignUser::getProcessInstanceId, allStopProcessInstanceIdList)
|
||||
.eq(ProcessNodeRecordAssignUser::getStatus, NodeStatusEnum.JXZ.getCode())
|
||||
.update(new ProcessNodeRecordAssignUser());
|
||||
|
||||
allStopProcessInstanceIdList.forEach(processInstanceId -> {
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||
.processInstanceId(processInstanceId)
|
||||
.processInstanceTenantId(TenantContextHolder.getTenantId().toString())
|
||||
.singleResult();
|
||||
if (processInstance == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> executionIds = runtimeService.createExecutionQuery()
|
||||
.parentId(processInstanceId)
|
||||
.list()
|
||||
.stream()
|
||||
.map(Execution::getId)
|
||||
.toList();
|
||||
if (CollUtil.isEmpty(executionIds)) {
|
||||
log.warn("流程实例缺少可迁移执行流,跳过状态迁移: processInstanceId={}", processInstanceId);
|
||||
return;
|
||||
}
|
||||
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.moveExecutionsToSingleActivityId(executionIds, "end")
|
||||
.changeState();
|
||||
});
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user