feat(task): 添加持续步骤阻塞检查功能
- 在TaskLogQueryExe中新增checkBlockingStep方法,用于检查持续步骤阻塞 - 新增BlockingStepInfoCO客户端对象,用于传递阻塞步骤信息 - 修改任务流转逻辑,在激活下一步前检查阻塞条件 - 优化draft保存时info字段序列化方式 - 修正工作流状态变更逻辑,调整暂存和正式状态处理 - 更新待办统计查询,关联eightwork_info表过滤有效记录 - 添加阻塞信息检查和异常抛出机制,确保事务一致性master
parent
bf965d00e2
commit
b1df85b19f
|
|
@ -126,7 +126,7 @@ public class EightworkInfoSaveDraftExe {
|
||||||
eightworkInfo.setGasFlag(cmd.getGasFlag());
|
eightworkInfo.setGasFlag(cmd.getGasFlag());
|
||||||
eightworkInfo.setCheckNo(null); // 暂存不生成票号
|
eightworkInfo.setCheckNo(null); // 暂存不生成票号
|
||||||
eightworkInfo.setStatus(DRAFT_STATUS);
|
eightworkInfo.setStatus(DRAFT_STATUS);
|
||||||
eightworkInfo.setInfo(cmd.getInfo());
|
eightworkInfo.setInfo(cmd.getInfo().toJSONString());
|
||||||
eightworkInfo.setDepartmentId(cmd.getDepartmentId());
|
eightworkInfo.setDepartmentId(cmd.getDepartmentId());
|
||||||
|
|
||||||
eightworkInfoRepository.save(eightworkInfo);
|
eightworkInfoRepository.save(eightworkInfo);
|
||||||
|
|
@ -170,7 +170,7 @@ public class EightworkInfoSaveDraftExe {
|
||||||
);
|
);
|
||||||
|
|
||||||
// 暂存时申请步骤状态为进行中
|
// 暂存时申请步骤状态为进行中
|
||||||
taskLog.setStatus(IN_PROGRESS_STATUS);
|
taskLog.setStatus(DRAFT_STATUS);
|
||||||
|
|
||||||
log.info("申请步骤 task_log 创建成功: stepName={}", applyFlow.getStepName());
|
log.info("申请步骤 task_log 创建成功: stepName={}", applyFlow.getStepName());
|
||||||
return taskLog;
|
return taskLog;
|
||||||
|
|
@ -188,7 +188,7 @@ public class EightworkInfoSaveDraftExe {
|
||||||
existingInfo.setProjectId(cmd.getProjectId());
|
existingInfo.setProjectId(cmd.getProjectId());
|
||||||
existingInfo.setXgfId(cmd.getXgfId());
|
existingInfo.setXgfId(cmd.getXgfId());
|
||||||
existingInfo.setGasFlag(cmd.getGasFlag());
|
existingInfo.setGasFlag(cmd.getGasFlag());
|
||||||
existingInfo.setInfo(cmd.getInfo());
|
existingInfo.setInfo(cmd.getInfo().toJSONString());
|
||||||
existingInfo.setDepartmentId(cmd.getDepartmentId());
|
existingInfo.setDepartmentId(cmd.getDepartmentId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -226,12 +226,10 @@ public class EightworkInfoSaveDraftExe {
|
||||||
// 添加预设签字人信息到 info(格式同 updateEightworkInfo)
|
// 添加预设签字人信息到 info(格式同 updateEightworkInfo)
|
||||||
for (TaskSignStepInfoCmd signInfo : signLogs) {
|
for (TaskSignStepInfoCmd signInfo : signLogs) {
|
||||||
JSONObject stepInfo = new JSONObject();
|
JSONObject stepInfo = new JSONObject();
|
||||||
stepInfo.put("stepName", getStepNameBySignInfo(signInfo));
|
|
||||||
stepInfo.put("actUserDepartment", signInfo.getActUserDepartment());
|
stepInfo.put("actUserDepartment", signInfo.getActUserDepartment());
|
||||||
stepInfo.put("actUserDepartmentName", signInfo.getActUserDepartmentName());
|
stepInfo.put("actUserDepartmentName", signInfo.getActUserDepartmentName());
|
||||||
stepInfo.put("actUser", signInfo.getActUser());
|
stepInfo.put("actUser", signInfo.getActUser());
|
||||||
stepInfo.put("actUserName", signInfo.getActUserName());
|
stepInfo.put("actUserName", signInfo.getActUserName());
|
||||||
stepInfo.put("signTime", cn.hutool.core.date.DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));
|
|
||||||
stepInfo.put("status", TaskLogStatus.NOT_STARTED.getCode());
|
stepInfo.put("status", TaskLogStatus.NOT_STARTED.getCode());
|
||||||
|
|
||||||
infoJson.put("step_" + signInfo.getStepId(), stepInfo);
|
infoJson.put("step_" + signInfo.getStepId(), stepInfo);
|
||||||
|
|
@ -243,13 +241,4 @@ public class EightworkInfoSaveDraftExe {
|
||||||
|
|
||||||
log.info("预设签字人信息已保存: workId={}, count={}", workId, signLogs.size());
|
log.info("预设签字人信息已保存: workId={}, count={}", workId, signLogs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从签字信息中获取步骤名称
|
|
||||||
*/
|
|
||||||
private String getStepNameBySignInfo(TaskSignStepInfoCmd signInfo) {
|
|
||||||
// 这里可以通过 stepId 查询流程配置获取步骤名称
|
|
||||||
// 暂时返回空,由前端或后续处理填充
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ public class TaskLogAddExe {
|
||||||
log.info("暂存转正式(保持原票号): workId={}, checkNo={}", existingInfo.getWorkId(), checkNo);
|
log.info("暂存转正式(保持原票号): workId={}, checkNo={}", existingInfo.getWorkId(), checkNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
existingInfo.setStatus(TaskLogStatus.IN_PROGRESS.getCode());
|
existingInfo.setStatus(TaskLogStatus.APPROVED.getCode()); // 主表进行中=1
|
||||||
existingInfo.setInfo(processedInfo); // 设置处理后的 info(包含 rejectHistory)
|
existingInfo.setInfo(processedInfo); // 设置处理后的 info(包含 rejectHistory)
|
||||||
eightworkInfoRepository.updateById(existingInfo);
|
eightworkInfoRepository.updateById(existingInfo);
|
||||||
|
|
||||||
|
|
@ -285,7 +285,7 @@ public class TaskLogAddExe {
|
||||||
cmd.getProjectId(),
|
cmd.getProjectId(),
|
||||||
cmd.getXgfId(),
|
cmd.getXgfId(),
|
||||||
checkNo,
|
checkNo,
|
||||||
TaskLogStatus.IN_PROGRESS.getCode(), // 初始状态为进行中
|
TaskLogStatus.APPROVED.getCode(), // 主表进行中=1
|
||||||
cmd.getInfo(),
|
cmd.getInfo(),
|
||||||
cmd.getDepartmentId()
|
cmd.getDepartmentId()
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -179,13 +179,16 @@ public class TaskLogUpdateExe {
|
||||||
// 6. 处理其他安全措施
|
// 6. 处理其他安全措施
|
||||||
handleOtherMeasuresIfNeeded(currentLog, cmd);
|
handleOtherMeasuresIfNeeded(currentLog, cmd);
|
||||||
|
|
||||||
// 7. 流转到下一步
|
// 7. 在流转到下一步之前,检查是否被持续步骤阻塞(双重验证)
|
||||||
|
checkBlockingStepBeforeProceed(currentLog, logs);
|
||||||
|
|
||||||
|
// 8. 流转到下一步
|
||||||
if (shouldProceed) {
|
if (shouldProceed) {
|
||||||
proceedToNextStep(currentLog, actionLogs, logs);
|
proceedToNextStep(currentLog, actionLogs, logs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. 处理分支流程
|
// 9. 处理分支流程
|
||||||
handleBranchIfNeeded(currentLog, actionLogs, logs);
|
handleBranchIfNeeded(currentLog, actionLogs, logs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -440,6 +443,10 @@ public class TaskLogUpdateExe {
|
||||||
|
|
||||||
List<TaskLogE> nextSteps = findNextSteps(currentLog, allLogs);
|
List<TaskLogE> nextSteps = findNextSteps(currentLog, allLogs);
|
||||||
|
|
||||||
|
log.info("查找下一步: currentStepId={}, currentNextStep={}, foundNextStepsCount={}",
|
||||||
|
currentLog.getStepId(), currentLog.getNextStep(),
|
||||||
|
nextSteps != null ? nextSteps.size() : 0);
|
||||||
|
|
||||||
if (CollectionUtil.isEmpty(nextSteps)) {
|
if (CollectionUtil.isEmpty(nextSteps)) {
|
||||||
// 没有下一步,流程结束
|
// 没有下一步,流程结束
|
||||||
completeWorkflow(currentLog);
|
completeWorkflow(currentLog);
|
||||||
|
|
@ -448,6 +455,10 @@ public class TaskLogUpdateExe {
|
||||||
|
|
||||||
TaskLogE nextStep = nextSteps.get(0);
|
TaskLogE nextStep = nextSteps.get(0);
|
||||||
|
|
||||||
|
log.info("准备激活下一步: currentStepId={}, currentStepName={}, nextStepId={}, nextStepName={}, nextBranchFlag={}",
|
||||||
|
currentLog.getStepId(), currentLog.getStepName(),
|
||||||
|
nextStep.getStepId(), nextStep.getStepName(), nextStep.getBranchFlag());
|
||||||
|
|
||||||
// 判断下一步是否为跳过状态
|
// 判断下一步是否为跳过状态
|
||||||
if (TaskLogStatus.SKIPPED.equalsCode(nextStep.getStatus())) {
|
if (TaskLogStatus.SKIPPED.equalsCode(nextStep.getStatus())) {
|
||||||
log.info("下一步为跳过步骤,继续递归: {}", nextStep.getStepName());
|
log.info("下一步为跳过步骤,继续递归: {}", nextStep.getStepName());
|
||||||
|
|
@ -456,7 +467,10 @@ public class TaskLogUpdateExe {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断下一步是否为合并节点(需要等待所有前置步骤都完成)
|
// 判断下一步是否为合并节点(需要等待所有前置步骤都完成)
|
||||||
if (isMergeNode(nextStep)) {
|
boolean isMerge = isMergeNode(nextStep);
|
||||||
|
log.info("检查是否为合并节点: stepId={}, stepName={}, branchFlag={}, isMerge={}",
|
||||||
|
nextStep.getStepId(), nextStep.getStepName(), nextStep.getBranchFlag(), isMerge);
|
||||||
|
if (isMerge) {
|
||||||
if (!areAllBranchesCompleted(nextStep, allLogs)) {
|
if (!areAllBranchesCompleted(nextStep, allLogs)) {
|
||||||
List<TaskLogE> pendingSteps = getPendingBranches(nextStep, allLogs);
|
List<TaskLogE> pendingSteps = getPendingBranches(nextStep, allLogs);
|
||||||
log.info("合并节点等待其他前置步骤完成: mergeNode={}, waitingSteps={}",
|
log.info("合并节点等待其他前置步骤完成: mergeNode={}, waitingSteps={}",
|
||||||
|
|
@ -471,19 +485,19 @@ public class TaskLogUpdateExe {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断下一步是否被持续步骤阻塞(如气体检测必须填写指定次数)
|
// 判断下一步是否被持续步骤阻塞(如气体检测必须填写指定次数)
|
||||||
if (isBlockedByOngoingStep(nextStep, allLogs)) {
|
BlockingInfo blockingInfo = getBlockingInfo(nextStep, allLogs);
|
||||||
TaskLogE blockingStep = findBlockingStep(nextStep, allLogs);
|
if (blockingInfo != null && !blockingInfo.isCompleted) {
|
||||||
log.info("步骤被持续步骤阻塞: step={}, blockingStep={}, currentTimes={}, requiredTimes={}",
|
log.info("步骤被持续步骤阻塞: step={}, blockingStep={}, currentTimes={}, requiredTimes={}",
|
||||||
nextStep.getStepName(),
|
nextStep.getStepName(),
|
||||||
blockingStep != null ? blockingStep.getStepName() : "未知",
|
blockingInfo.blockingStep.getStepName(),
|
||||||
blockingStep != null ? blockingStep.getCurrentFillTimes() : 0,
|
blockingInfo.currentTimes,
|
||||||
blockingStep != null ? blockingStep.getMinFillTimes() : 0);
|
blockingInfo.requiredTimes);
|
||||||
// 不激活步骤,等待持续步骤填写足够次数
|
// 不激活步骤,等待持续步骤填写足够次数
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 激活下一步
|
// 激活下一步
|
||||||
activateNextSteps(nextSteps, actionLogs, currentLog);
|
activateNextSteps(nextSteps, actionLogs, currentLog, allLogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -534,24 +548,6 @@ public class TaskLogUpdateExe {
|
||||||
return pendingSteps;
|
return pendingSteps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断步骤是否被持续步骤阻塞
|
|
||||||
* 持续步骤(如气体检测)必须填写指定次数后,阻塞的步骤才能激活
|
|
||||||
*/
|
|
||||||
private boolean isBlockedByOngoingStep(TaskLogE step, List<TaskLogE> allLogs) {
|
|
||||||
// 找出阻塞当前步骤的持续步骤
|
|
||||||
TaskLogE blockingStep = findBlockingStep(step, allLogs);
|
|
||||||
if (blockingStep == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查填写次数是否满足要求
|
|
||||||
Integer currentTimes = blockingStep.getCurrentFillTimes();
|
|
||||||
Integer requiredTimes = blockingStep.getMinFillTimes();
|
|
||||||
|
|
||||||
return currentTimes == null || currentTimes < requiredTimes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找阻塞指定步骤的持续步骤
|
* 查找阻塞指定步骤的持续步骤
|
||||||
*/
|
*/
|
||||||
|
|
@ -566,12 +562,53 @@ public class TaskLogUpdateExe {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阻塞信息内部类
|
||||||
|
*/
|
||||||
|
private static class BlockingInfo {
|
||||||
|
TaskLogE blockingStep;
|
||||||
|
Integer currentTimes;
|
||||||
|
Integer requiredTimes;
|
||||||
|
boolean isCompleted;
|
||||||
|
|
||||||
|
BlockingInfo(TaskLogE blockingStep, Integer currentTimes, Integer requiredTimes) {
|
||||||
|
this.blockingStep = blockingStep;
|
||||||
|
this.currentTimes = currentTimes != null ? currentTimes : 0;
|
||||||
|
this.requiredTimes = requiredTimes != null ? requiredTimes : 0;
|
||||||
|
this.isCompleted = currentTimes != null && currentTimes >= requiredTimes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取阻塞信息(统一入口,避免重复判断)
|
||||||
|
*/
|
||||||
|
private BlockingInfo getBlockingInfo(TaskLogE step, List<TaskLogE> allLogs) {
|
||||||
|
TaskLogE blockingStep = findBlockingStep(step, allLogs);
|
||||||
|
if (blockingStep == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer currentTimes = blockingStep.getCurrentFillTimes();
|
||||||
|
Integer requiredTimes = blockingStep.getMinFillTimes();
|
||||||
|
|
||||||
|
return new BlockingInfo(blockingStep, currentTimes, requiredTimes);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找下一步骤
|
* 查找下一步骤
|
||||||
|
* 优先检查 nextStep,如果是分支结束节点则检查 branchMergeStep
|
||||||
*/
|
*/
|
||||||
private List<TaskLogE> findNextSteps(TaskLogE currentLog, List<TaskLogE> allLogs) {
|
private List<TaskLogE> findNextSteps(TaskLogE currentLog, List<TaskLogE> allLogs) {
|
||||||
|
Long targetStepId = currentLog.getNextStep();
|
||||||
|
|
||||||
|
// 如果 nextStep 为空,检查是否为分支结束节点(使用 branchMergeStep)
|
||||||
|
if (targetStepId == null && currentLog.getBranchMergeStep() != null) {
|
||||||
|
targetStepId = currentLog.getBranchMergeStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
Long finalTargetStepId = targetStepId;
|
||||||
return allLogs.stream()
|
return allLogs.stream()
|
||||||
.filter(log -> log.getStepId().equals(currentLog.getNextStep()))
|
.filter(log -> log.getStepId().equals(finalTargetStepId))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,11 +617,23 @@ public class TaskLogUpdateExe {
|
||||||
* - 设置状态为进行中
|
* - 设置状态为进行中
|
||||||
* - 发送待办通知
|
* - 发送待办通知
|
||||||
* - 更新作业当前步骤
|
* - 更新作业当前步骤
|
||||||
|
* - 如果有阻塞步骤已完成,标记为通过
|
||||||
*/
|
*/
|
||||||
private void activateNextSteps(List<TaskLogE> nextSteps, List<TaskLogDO> actionLogs, TaskLogE currentLog) {
|
private void activateNextSteps(List<TaskLogE> nextSteps, List<TaskLogDO> actionLogs, TaskLogE currentLog, List<TaskLogE> allLogs) {
|
||||||
Long workId = getWorkId(currentLog.getWorkId());
|
Long workId = getWorkId(currentLog.getWorkId());
|
||||||
|
|
||||||
for (TaskLogE next : nextSteps) {
|
for (TaskLogE next : nextSteps) {
|
||||||
|
// 使用统一的 getBlockingInfo 方法
|
||||||
|
BlockingInfo info = getBlockingInfo(next, allLogs);
|
||||||
|
|
||||||
|
if (info != null && !info.isCompleted) {
|
||||||
|
// 阻塞步骤未完成,不激活该步骤
|
||||||
|
log.info("步骤被持续步骤阻塞,跳过激活: step={}, blockingStep={}, currentTimes={}, requiredTimes={}",
|
||||||
|
next.getStepName(), info.blockingStep.getStepName(), info.currentTimes, info.requiredTimes);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 激活步骤
|
||||||
next.setStatus(TaskLogStatus.IN_PROGRESS.getCode());
|
next.setStatus(TaskLogStatus.IN_PROGRESS.getCode());
|
||||||
addActionLog(actionLogs, next);
|
addActionLog(actionLogs, next);
|
||||||
|
|
||||||
|
|
@ -592,14 +641,29 @@ public class TaskLogUpdateExe {
|
||||||
sendTodoAddEvent(workId, next, currentLog.getWorkType());
|
sendTodoAddEvent(workId, next, currentLog.getWorkType());
|
||||||
|
|
||||||
log.info("已激活下一步: {}", next.getStepName());
|
log.info("已激活下一步: {}", next.getStepName());
|
||||||
|
|
||||||
|
// 如果有阻塞步骤且已完成,标记为通过
|
||||||
|
if (info != null && info.isCompleted) {
|
||||||
|
completeBlockingStep(info.blockingStep, actionLogs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新作业当前步骤
|
// 如果有步骤被激活,更新作业当前步骤
|
||||||
eightworkInfoRepository.updateWorkStatus(
|
if (!actionLogs.isEmpty()) {
|
||||||
currentLog.getWorkId(),
|
// 找到第一个被激活的步骤
|
||||||
nextSteps.get(0).getStepName(),
|
TaskLogDO firstActivated = actionLogs.stream()
|
||||||
null
|
.filter(log -> log.getTaskLogId().equals(nextSteps.get(0).getTaskLogId()))
|
||||||
);
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (firstActivated != null) {
|
||||||
|
eightworkInfoRepository.updateWorkStatus(
|
||||||
|
currentLog.getWorkId(),
|
||||||
|
firstActivated.getStepName(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -819,12 +883,12 @@ public class TaskLogUpdateExe {
|
||||||
// 将 rejectInfo 放入主 info
|
// 将 rejectInfo 放入主 info
|
||||||
infoJson.put("rejectInfo", rejectInfo);
|
infoJson.put("rejectInfo", rejectInfo);
|
||||||
|
|
||||||
// 更新主表状态为暂存
|
// 更新主表状态为打回
|
||||||
infoDO.setStatus(DRAFT_STATUS);
|
infoDO.setStatus(TaskLogStatus.REJECTED.getCode());
|
||||||
infoDO.setInfo(infoJson.toJSONString());
|
infoDO.setInfo(infoJson.toJSONString());
|
||||||
eightworkInfoRepository.updateById(infoDO);
|
eightworkInfoRepository.updateById(infoDO);
|
||||||
|
|
||||||
log.info("主表已更新为暂存状态并添加打回信息: workId={}", workId);
|
log.info("主表已更新为打回状态并添加打回信息: workId={}", workId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -894,14 +958,6 @@ public class TaskLogUpdateExe {
|
||||||
signInfo.getActUserName()
|
signInfo.getActUserName()
|
||||||
);
|
);
|
||||||
|
|
||||||
// 如果步骤当前是未开始状态,需要激活它(设置签字人后应该变为进行中)
|
|
||||||
if (TaskLogStatus.NOT_STARTED.equalsCode(signStepLog.getStatus())) {
|
|
||||||
signStepLog.setStatus(TaskLogStatus.IN_PROGRESS.getCode());
|
|
||||||
// 发送待办通知
|
|
||||||
sendTodoAddEvent(getWorkId(signStepLog.getWorkId()), signStepLog, currentLog.getWorkType());
|
|
||||||
log.info("已激活签字步骤: {}", signStepLog.getStepName());
|
|
||||||
}
|
|
||||||
|
|
||||||
addActionLog(actionLogs, signStepLog);
|
addActionLog(actionLogs, signStepLog);
|
||||||
log.info("已设置签字人: step={}, user={}", signStepLog.getStepName(), signInfo.getActUserName());
|
log.info("已设置签字人: step={}, user={}", signStepLog.getStepName(), signInfo.getActUserName());
|
||||||
}
|
}
|
||||||
|
|
@ -1098,4 +1154,56 @@ public class TaskLogUpdateExe {
|
||||||
|
|
||||||
log.info("已批量更新步骤 info: workId={}, count={}", workId, actionLogs.size());
|
log.info("已批量更新步骤 info: workId={}, count={}", workId, actionLogs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在流转到下一步之前,检查是否被持续步骤阻塞(双重验证)
|
||||||
|
* 如果被阻塞且未完成,抛出异常回滚整个事务
|
||||||
|
*/
|
||||||
|
private void checkBlockingStepBeforeProceed(TaskLogE currentLog, List<TaskLogE> allLogs) {
|
||||||
|
List<TaskLogE> nextSteps = findNextSteps(currentLog, allLogs);
|
||||||
|
|
||||||
|
if (CollectionUtil.isEmpty(nextSteps)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskLogE nextStep = nextSteps.get(0);
|
||||||
|
|
||||||
|
// 使用统一的 getBlockingInfo 方法
|
||||||
|
BlockingInfo info = getBlockingInfo(nextStep, allLogs);
|
||||||
|
|
||||||
|
if (info != null && !info.isCompleted) {
|
||||||
|
// 阻塞步骤未完成,抛出异常回滚整个事务
|
||||||
|
String errorMsg = String.format("【%s】未完成,当前填写%d次,应填写%d次,无法流转到下一步",
|
||||||
|
info.blockingStep.getStepName(),
|
||||||
|
info.currentTimes,
|
||||||
|
info.requiredTimes);
|
||||||
|
|
||||||
|
log.warn("步骤被阻塞,阻止流转: stepId={}, stepName={}, blockingStep={}, currentTimes={}, requiredTimes={}",
|
||||||
|
nextStep.getStepId(), nextStep.getStepName(),
|
||||||
|
info.blockingStep.getStepName(), info.currentTimes, info.requiredTimes);
|
||||||
|
|
||||||
|
throw new BizException(errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成阻塞步骤
|
||||||
|
* 如果阻塞步骤填写次数已达标,标记为通过
|
||||||
|
*/
|
||||||
|
private void completeBlockingStep(TaskLogE blockingStep, List<TaskLogDO> actionLogs) {
|
||||||
|
// 检查阻塞步骤当前状态是否为进行中,如果是则标记为通过
|
||||||
|
if (TaskLogStatus.IN_PROGRESS.equalsCode(blockingStep.getStatus())) {
|
||||||
|
blockingStep.setStatus(TaskLogStatus.APPROVED.getCode());
|
||||||
|
addActionLog(actionLogs, blockingStep);
|
||||||
|
sendTodoCompleteEvent(blockingStep.getId());
|
||||||
|
|
||||||
|
Integer currentTimes = blockingStep.getCurrentFillTimes();
|
||||||
|
Integer requiredTimes = blockingStep.getMinFillTimes();
|
||||||
|
|
||||||
|
log.info("阻塞步骤已完成,标记为通过: stepId={}, stepName={}, currentTimes={}, requiredTimes={}",
|
||||||
|
blockingStep.getStepId(), blockingStep.getStepName(),
|
||||||
|
currentTimes != null ? currentTimes : 0,
|
||||||
|
requiredTimes != null ? requiredTimes : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.zcloud.eightwork.command.convertor.EightworkInfoCoConvertor;
|
||||||
import com.zcloud.eightwork.command.convertor.TaskLogCoConvertor;
|
import com.zcloud.eightwork.command.convertor.TaskLogCoConvertor;
|
||||||
import com.zcloud.eightwork.domain.model.TodoCountE;
|
import com.zcloud.eightwork.domain.model.TodoCountE;
|
||||||
import com.zcloud.eightwork.dto.TaskLogPageQry;
|
import com.zcloud.eightwork.dto.TaskLogPageQry;
|
||||||
|
import com.zcloud.eightwork.dto.clientobject.BlockingStepInfoCO;
|
||||||
import com.zcloud.eightwork.dto.clientobject.EightworkInfoCO;
|
import com.zcloud.eightwork.dto.clientobject.EightworkInfoCO;
|
||||||
import com.zcloud.eightwork.dto.clientobject.TaskLogCO;
|
import com.zcloud.eightwork.dto.clientobject.TaskLogCO;
|
||||||
import com.zcloud.eightwork.dto.clientobject.TodoCountCO;
|
import com.zcloud.eightwork.dto.clientobject.TodoCountCO;
|
||||||
|
|
@ -15,6 +16,7 @@ import com.zcloud.eightwork.persistence.repository.TaskLogRepository;
|
||||||
import com.zcloud.gbscommon.utils.PageQueryHelper;
|
import com.zcloud.gbscommon.utils.PageQueryHelper;
|
||||||
import com.alibaba.cola.dto.PageResponse;
|
import com.alibaba.cola.dto.PageResponse;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
@ -30,6 +32,7 @@ import java.util.stream.Collectors;
|
||||||
* @Author fangjiakai
|
* @Author fangjiakai
|
||||||
* @Date 2025-11-05 09:53:53
|
* @Date 2025-11-05 09:53:53
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class TaskLogQueryExe {
|
public class TaskLogQueryExe {
|
||||||
|
|
@ -37,6 +40,8 @@ public class TaskLogQueryExe {
|
||||||
private final TaskLogCoConvertor taskLogCoConvertor;
|
private final TaskLogCoConvertor taskLogCoConvertor;
|
||||||
private final EightworkInfoRepository eightworkInfoRepository;
|
private final EightworkInfoRepository eightworkInfoRepository;
|
||||||
private final EightworkInfoCoConvertor eightworkInfoCoConvertor;
|
private final EightworkInfoCoConvertor eightworkInfoCoConvertor;
|
||||||
|
/** 持续步骤标识 */
|
||||||
|
private static final Integer ONGOING_FLAG = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页
|
* 分页
|
||||||
|
|
@ -74,9 +79,52 @@ public class TaskLogQueryExe {
|
||||||
taskLogCO.setWorkInfo(eightworkInfoCoConvertor.converDOToCO(eightworkInfoRepository.getOne(
|
taskLogCO.setWorkInfo(eightworkInfoCoConvertor.converDOToCO(eightworkInfoRepository.getOne(
|
||||||
new LambdaQueryWrapper<EightworkInfoDO>().eq(EightworkInfoDO::getWorkId, taskLogDO.getWorkId())
|
new LambdaQueryWrapper<EightworkInfoDO>().eq(EightworkInfoDO::getWorkId, taskLogDO.getWorkId())
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
// 检查是否有持续步骤阻塞当前步骤
|
||||||
|
checkBlockingStep(taskLogDO, taskLogCO);
|
||||||
|
|
||||||
return taskLogCO;
|
return taskLogCO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否有持续步骤阻塞当前步骤
|
||||||
|
*/
|
||||||
|
private void checkBlockingStep(TaskLogDO currentStepDO, TaskLogCO taskLogCO) {
|
||||||
|
// 查询同一工作流的所有步骤
|
||||||
|
List<TaskLogDO> allSteps = taskLogRepository.listAllByWorkId(taskLogCO.getWorkId());
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(allSteps)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找阻塞当前步骤的持续步骤
|
||||||
|
for (TaskLogDO step : allSteps) {
|
||||||
|
// 检查是否为持续步骤且阻塞当前步骤
|
||||||
|
if (ONGOING_FLAG.equals(step.getOngoingFlag())
|
||||||
|
&& taskLogCO.getStepId().equals(step.getBlockingStepId())) {
|
||||||
|
// 检查填写次数是否达标
|
||||||
|
Integer currentTimes = step.getCurrentFillTimes();
|
||||||
|
Integer requiredTimes = step.getMinFillTimes();
|
||||||
|
|
||||||
|
boolean isCompleted = currentTimes != null && currentTimes >= requiredTimes;
|
||||||
|
|
||||||
|
// 设置阻塞信息
|
||||||
|
BlockingStepInfoCO blockingInfo = new BlockingStepInfoCO();
|
||||||
|
blockingInfo.setStepId(step.getStepId());
|
||||||
|
blockingInfo.setStepName(step.getStepName());
|
||||||
|
blockingInfo.setCurrentFillTimes(currentTimes != null ? currentTimes : 0);
|
||||||
|
blockingInfo.setMinFillTimes(requiredTimes != null ? requiredTimes : 0);
|
||||||
|
blockingInfo.setIsCompleted(isCompleted);
|
||||||
|
|
||||||
|
taskLogCO.setBlockingStepInfo(blockingInfo);
|
||||||
|
|
||||||
|
log.info("当前步骤被持续步骤阻塞: currentStepId={}, blockingStepId={}, currentTimes={}, requiredTimes={}",
|
||||||
|
taskLogCO.getStepId(), step.getStepId(), currentTimes, requiredTimes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<TaskLogCO> listAll(String workId) {
|
public List<TaskLogCO> listAll(String workId) {
|
||||||
return taskLogCoConvertor.converDOsToCOs(taskLogRepository.listAllByWorkId(workId));
|
return taskLogCoConvertor.converDOsToCOs(taskLogRepository.listAllByWorkId(workId));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.zcloud.eightwork.dto;
|
package com.zcloud.eightwork.dto;
|
||||||
|
|
||||||
import com.alibaba.cola.dto.Command;
|
import com.alibaba.cola.dto.Command;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -29,38 +30,31 @@ public class EightworkInfoSaveDraftCmd extends Command {
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "企业", name = "corpinfoId", required = true)
|
@ApiModelProperty(value = "企业", name = "corpinfoId", required = true)
|
||||||
@NotNull(message = "企业不能为空")
|
|
||||||
private Long corpinfoId;
|
private Long corpinfoId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "是否相关方1是", name = "xgfFlag", required = true)
|
@ApiModelProperty(value = "是否相关方1是", name = "xgfFlag", required = true)
|
||||||
@NotNull(message = "是否相关方1是不能为空")
|
|
||||||
private Integer xgfFlag;
|
private Integer xgfFlag;
|
||||||
|
|
||||||
@ApiModelProperty(value = "是否内部作业1是2否", name = "internalOperationFlag")
|
@ApiModelProperty(value = "是否内部作业1是2否", name = "internalOperationFlag")
|
||||||
private Integer internalOperationFlag;
|
private Integer internalOperationFlag;
|
||||||
|
|
||||||
@ApiModelProperty(value = "所属项目", name = "projectId", required = true)
|
@ApiModelProperty(value = "所属项目", name = "projectId", required = true)
|
||||||
@NotEmpty(message = "所属项目不能为空")
|
|
||||||
private String projectId;
|
private String projectId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "相关方id", name = "xgfId", required = true)
|
@ApiModelProperty(value = "相关方id", name = "xgfId", required = true)
|
||||||
@NotNull(message = "相关方id不能为空")
|
|
||||||
private Long xgfId;
|
private Long xgfId;
|
||||||
|
|
||||||
@ApiModelProperty(value = "是否需要气体检测1是2否", name = "gasFlag")
|
@ApiModelProperty(value = "是否需要气体检测1是2否", name = "gasFlag")
|
||||||
private Integer gasFlag;
|
private Integer gasFlag;
|
||||||
|
|
||||||
@ApiModelProperty(value = "工作类型", name = "workType", required = true)
|
@ApiModelProperty(value = "工作类型", name = "workType", required = true)
|
||||||
@NotEmpty(message = "工作类型不能为空")
|
|
||||||
private String workType;
|
private String workType;
|
||||||
|
|
||||||
@ApiModelProperty(value = "级别", name = "workLevel", required = true)
|
@ApiModelProperty(value = "级别", name = "workLevel", required = true)
|
||||||
@NotEmpty(message = "级别不能为空")
|
|
||||||
private String workLevel;
|
private String workLevel;
|
||||||
|
|
||||||
@ApiModelProperty(value = "详细信息", name = "info", required = true)
|
@ApiModelProperty(value = "详细信息", name = "info", required = true)
|
||||||
@NotEmpty(message = "详细信息不能为空")
|
private JSONObject info;
|
||||||
private String info;
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "签字步骤", name = "signLogs")
|
@ApiModelProperty(value = "签字步骤", name = "signLogs")
|
||||||
private java.util.List<TaskSignStepInfoCmd> signLogs;
|
private java.util.List<TaskSignStepInfoCmd> signLogs;
|
||||||
|
|
|
||||||
|
|
@ -148,5 +148,8 @@ public class TaskLogCO extends ClientObject {
|
||||||
|
|
||||||
@ApiModelProperty(value = "工作票信息")
|
@ApiModelProperty(value = "工作票信息")
|
||||||
private EightworkInfoCO workInfo;
|
private EightworkInfoCO workInfo;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "阻塞步骤信息(当前步骤被持续步骤阻塞时)")
|
||||||
|
private BlockingStepInfoCO blockingStepInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ public class TaskLogE extends BaseE {
|
||||||
this.multipleFlag = log.getMultipleFlag();
|
this.multipleFlag = log.getMultipleFlag();
|
||||||
this.stepType = log.getStepType();
|
this.stepType = log.getStepType();
|
||||||
this.signStepFlag = log.getSignStepFlag();
|
this.signStepFlag = log.getSignStepFlag();
|
||||||
|
this.selectLevel = log.getSelectLevel();
|
||||||
this.fileStepFlag = log.getFileStepFlag();
|
this.fileStepFlag = log.getFileStepFlag();
|
||||||
this.locateStepFlag = log.getLocateStepFlag();
|
this.locateStepFlag = log.getLocateStepFlag();
|
||||||
this.specialStepCode = log.getSpecialStepCode();
|
this.specialStepCode = log.getSpecialStepCode();
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,29 @@
|
||||||
<mapper namespace="com.zcloud.eightwork.persistence.mapper.TaskLogMapper">
|
<mapper namespace="com.zcloud.eightwork.persistence.mapper.TaskLogMapper">
|
||||||
|
|
||||||
<select id="getTodoCount" resultType="com.zcloud.eightwork.domain.model.TodoCountE">
|
<select id="getTodoCount" resultType="com.zcloud.eightwork.domain.model.TodoCountE">
|
||||||
select work_type,
|
select task_log.work_type,
|
||||||
count(1) as todoCount
|
count(1) as todoCount
|
||||||
from task_log
|
from task_log
|
||||||
where status = 0
|
left join eightwork_info on task_log.work_id = eightwork_info.work_id
|
||||||
and (act_user = #{userId}
|
where task_log.status = 0
|
||||||
or (act_user_department = #{orgId} and act_user is null))
|
and eightwork_info.status != 0
|
||||||
group by work_type
|
and (task_log.act_user = #{userId}
|
||||||
|
or (task_log.act_user_department = #{orgId} and task_log.act_user is null))
|
||||||
|
group by task_log.work_type
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getTodoCountForWork" resultType="com.zcloud.eightwork.domain.model.TodoCountE">
|
<select id="getTodoCountForWork" resultType="com.zcloud.eightwork.domain.model.TodoCountE">
|
||||||
select work_type,
|
select task_log.work_type,
|
||||||
step_id,
|
task_log.step_id,
|
||||||
count(1) as todoCount
|
count(1) as todoCount
|
||||||
from task_log
|
from task_log
|
||||||
where status = 0
|
where task_log.status = 0
|
||||||
and work_type = #{workType}
|
left join eightwork_info on task_log.work_id = eightwork_info.work_id
|
||||||
and (act_user = #{userId}
|
and task_log.work_type = #{workType}
|
||||||
or (act_user_department = #{orgId} and act_user is null))
|
and eightwork_info.status != 0
|
||||||
group by step_id
|
and (task_log.act_user = #{userId}
|
||||||
|
or (task_log.act_user_department = #{orgId} and task_log.act_user is null))
|
||||||
|
group by task_log.step_id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getByWorkIdAndStepId" resultType="com.zcloud.eightwork.persistence.dataobject.TaskLogDO">
|
<select id="getByWorkIdAndStepId" resultType="com.zcloud.eightwork.persistence.dataobject.TaskLogDO">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue