修复顺序流水线同部门内子任务并行逻辑
1. 修改TaskService创建子任务时的状态设置: - 第一个部门的所有子任务都设为pending(可接单) - 其他部门的子任务设为locked(锁定) 2. 修改TaskItemService子任务完成后的解锁逻辑: - 基于部门序号(从itemNo解析)而不是groupNo - 当前部门的所有子任务完成后,才解锁下一个部门的所有子任务 - 同一部门内的子任务并行执行 3. 新增parseDeptIndexFromItemNo辅助方法: - 从子任务编号解析部门序号 - 支持新格式(TASK...-01-02)和旧格式兼容
This commit is contained in:
parent
777658b72c
commit
9599cf74a8
@ -475,77 +475,82 @@ public class TaskItemService {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("completedItem", item);
|
||||
|
||||
// 6. 🔥 关键步骤:检查是否是顺序流水线,基于group_no解锁下一组
|
||||
// 6. 🔥 关键步骤:检查是否是顺序流水线,基于部门解锁下一个部门
|
||||
// 新逻辑:同一部门内的所有子任务并行,部门间串行
|
||||
Task mainTask = taskMapper.selectById(item.getTaskId());
|
||||
if (mainTask != null && "sequential".equals(mainTask.getPipelineMode())) {
|
||||
// 获取当前子任务的分组号
|
||||
Integer currentGroupNo = item.getGroupNo();
|
||||
if (currentGroupNo == null) {
|
||||
currentGroupNo = 1; // 兼容旧数据
|
||||
}
|
||||
// 从子任务编号解析部门序号(格式:TASK...-部门序号-部门内序号)
|
||||
int currentDeptIndex = parseDeptIndexFromItemNo(item.getItemNo());
|
||||
log.info("当前子任务 {} 属于第 {} 个部门", item.getItemNo(), currentDeptIndex);
|
||||
|
||||
// 检查当前组的所有子任务是否都已完成
|
||||
List<TaskItem> currentGroupItems = taskItemMapper.selectList(
|
||||
// 获取当前部门的所有子任务(通过编号匹配)
|
||||
List<TaskItem> allItems = taskItemMapper.selectList(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<TaskItem>()
|
||||
.eq(TaskItem::getTaskId, item.getTaskId())
|
||||
.eq(TaskItem::getGroupNo, currentGroupNo)
|
||||
);
|
||||
|
||||
boolean allGroupCompleted = currentGroupItems.stream()
|
||||
// 筛选出同一部门的子任务
|
||||
List<TaskItem> currentDeptItems = allItems.stream()
|
||||
.filter(i -> parseDeptIndexFromItemNo(i.getItemNo()) == currentDeptIndex)
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
|
||||
// 检查当前部门的所有子任务是否都已完成
|
||||
boolean allDeptCompleted = currentDeptItems.stream()
|
||||
.allMatch(i -> "completed".equals(i.getStatus()));
|
||||
|
||||
if (allGroupCompleted) {
|
||||
log.info("✅ 第 {} 组所有子任务已完成,准备解锁下一组", currentGroupNo);
|
||||
log.info("当前部门共 {} 个子任务,已完成: {}", currentDeptItems.size(),
|
||||
currentDeptItems.stream().filter(i -> "completed".equals(i.getStatus())).count());
|
||||
|
||||
if (allDeptCompleted) {
|
||||
log.info("✅ 第 {} 个部门的所有子任务已完成,准备解锁下一个部门", currentDeptIndex);
|
||||
|
||||
// 🔥 收集当前组所有子任务的下载链接,传递给下一组
|
||||
// 🔥 收集当前部门所有子任务的下载链接,传递给下一个部门
|
||||
StringBuilder prevDownloadUrls = new StringBuilder();
|
||||
for (TaskItem groupItem : currentGroupItems) {
|
||||
if (groupItem.getDownloadUrl() != null && !groupItem.getDownloadUrl().isEmpty()) {
|
||||
for (TaskItem deptItem : currentDeptItems) {
|
||||
if (deptItem.getDownloadUrl() != null && !deptItem.getDownloadUrl().isEmpty()) {
|
||||
if (prevDownloadUrls.length() > 0) {
|
||||
prevDownloadUrls.append(",");
|
||||
}
|
||||
prevDownloadUrls.append(groupItem.getDownloadUrl());
|
||||
prevDownloadUrls.append(deptItem.getDownloadUrl());
|
||||
}
|
||||
// 同时继承前面环节的下载链接
|
||||
if (groupItem.getPrevDownloadUrl() != null && !groupItem.getPrevDownloadUrl().isEmpty()) {
|
||||
if (deptItem.getPrevDownloadUrl() != null && !deptItem.getPrevDownloadUrl().isEmpty()) {
|
||||
if (prevDownloadUrls.length() > 0) {
|
||||
prevDownloadUrls.append(",");
|
||||
}
|
||||
prevDownloadUrls.append(groupItem.getPrevDownloadUrl());
|
||||
prevDownloadUrls.append(deptItem.getPrevDownloadUrl());
|
||||
}
|
||||
}
|
||||
String prevDownloadUrlStr = prevDownloadUrls.toString();
|
||||
log.info("前置环节素材下载链接: {}", prevDownloadUrlStr);
|
||||
log.info("前置部门素材下载链接: {}", prevDownloadUrlStr);
|
||||
|
||||
// 解锁下一组的所有子任务
|
||||
Integer nextGroupNo = currentGroupNo + 1;
|
||||
List<TaskItem> nextGroupItems = taskItemMapper.selectList(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<TaskItem>()
|
||||
.eq(TaskItem::getTaskId, item.getTaskId())
|
||||
.eq(TaskItem::getGroupNo, nextGroupNo)
|
||||
.eq(TaskItem::getStatus, "locked")
|
||||
);
|
||||
// 找出下一个部门的所有子任务(状态为locked)
|
||||
int nextDeptIndex = currentDeptIndex + 1;
|
||||
List<TaskItem> nextDeptItems = allItems.stream()
|
||||
.filter(i -> parseDeptIndexFromItemNo(i.getItemNo()) == nextDeptIndex)
|
||||
.filter(i -> "locked".equals(i.getStatus()))
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
|
||||
if (!nextGroupItems.isEmpty()) {
|
||||
// 批量解锁下一组的所有子任务,状态设为待审核,并传递前置环节的下载链接
|
||||
for (TaskItem nextItem : nextGroupItems) {
|
||||
if (!nextDeptItems.isEmpty()) {
|
||||
// 批量解锁下一个部门的所有子任务,状态设为待审核,并传递前置环节的下载链接
|
||||
for (TaskItem nextItem : nextDeptItems) {
|
||||
nextItem.setStatus("pending_approval"); // 待接单部门负责人审核
|
||||
nextItem.setIsLocked(0);
|
||||
nextItem.setPrevDownloadUrl(prevDownloadUrlStr); // 🔥 传递前置环节的下载链接
|
||||
nextItem.setUpdateTime(LocalDateTime.now());
|
||||
taskItemMapper.updateById(nextItem);
|
||||
|
||||
log.info("✅ 解锁子任务: {} (组号: {}, ID: {}),待接单部门负责人审核,已传递前置素材链接",
|
||||
nextItem.getItemNo(), nextGroupNo, nextItem.getId());
|
||||
log.info("✅ 解锁子任务: {} (部门序号: {}, ID: {}),待接单部门负责人审核,已传递前置素材链接",
|
||||
nextItem.getItemNo(), nextDeptIndex, nextItem.getId());
|
||||
}
|
||||
|
||||
result.put("unlockedGroupNo", nextGroupNo);
|
||||
result.put("unlockedCount", nextGroupItems.size());
|
||||
result.put("unlockedDeptIndex", nextDeptIndex);
|
||||
result.put("unlockedCount", nextDeptItems.size());
|
||||
|
||||
// 发送通知给接单部门负责人
|
||||
// 从子任务的任务类型配置中获取allowed_dept_ids
|
||||
Set<Long> notifiedLeaderIds = new HashSet<>();
|
||||
for (TaskItem nextItem : nextGroupItems) {
|
||||
for (TaskItem nextItem : nextDeptItems) {
|
||||
Long targetDeptId = getTargetDeptIdFromTaskType(nextItem.getTaskTypeId());
|
||||
if (targetDeptId != null) {
|
||||
com.designhub.entity.Department receiverDept = departmentMapper.selectById(targetDeptId);
|
||||
@ -557,29 +562,29 @@ public class TaskItemService {
|
||||
notification.setReceiverId(receiverDept.getLeaderId());
|
||||
notification.setNotificationType("task_approval");
|
||||
notification.setTitle("新子任务组待审核");
|
||||
notification.setContent("任务《" + mainTask.getTitle() + "》第 " + nextGroupNo + " 组共 " +
|
||||
nextGroupItems.size() + " 个子任务已解锁,请审核并分配!");
|
||||
notification.setContent("任务《" + mainTask.getTitle() + "》第 " + nextDeptIndex + " 个部门共 " +
|
||||
nextDeptItems.size() + " 个子任务已解锁,请审核并分配!");
|
||||
notification.setRelatedId(item.getTaskId());
|
||||
notification.setRelatedType("task");
|
||||
notification.setPriority(2); // 重要
|
||||
notification.setPushDingtalk(1); // 推送到钉钉
|
||||
notificationService.sendNotification(notification);
|
||||
|
||||
log.info("已通知接单部门负责人(部门: {}, 负责人ID: {})审核第 {} 组子任务",
|
||||
receiverDept.getDeptName(), receiverDept.getLeaderId(), nextGroupNo);
|
||||
log.info("已通知接单部门负责人(部门: {}, 负责人ID: {})审核第 {} 个部门子任务",
|
||||
receiverDept.getDeptName(), receiverDept.getLeaderId(), nextDeptIndex);
|
||||
}
|
||||
} else {
|
||||
log.warn("子任务 {} 的任务类型未配置接单部门", nextItem.getItemNo());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("第 {} 组 {} 个子任务已解锁,等待接单部门负责人审核,已通知 {} 个部门负责人",
|
||||
nextGroupNo, nextGroupItems.size(), notifiedLeaderIds.size());
|
||||
log.info("第 {} 个部门 {} 个子任务已解锁,等待接单部门负责人审核,已通知 {} 个部门负责人",
|
||||
nextDeptIndex, nextDeptItems.size(), notifiedLeaderIds.size());
|
||||
} else {
|
||||
log.info("没有更多子任务组需要解锁");
|
||||
log.info("没有更多部门的子任务需要解锁");
|
||||
}
|
||||
} else {
|
||||
log.info("当前组还有子任务未完成,暂不解锁下一组");
|
||||
log.info("当前部门还有子任务未完成,暂不解锁下一个部门");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1310,6 +1315,33 @@ public class TaskItemService {
|
||||
return new java.util.ArrayList<>(groupMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 从子任务编号解析部门序号
|
||||
* 编号格式:任务编号-部门序号-部门内序号,例如 TASK20260114-01-02
|
||||
* @param itemNo 子任务编号
|
||||
* @return 部门序号,解析失败返回1
|
||||
*/
|
||||
private int parseDeptIndexFromItemNo(String itemNo) {
|
||||
if (itemNo == null || itemNo.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
String[] parts = itemNo.split("-");
|
||||
if (parts.length >= 3) {
|
||||
try {
|
||||
// 新格式:TASK...-部门序号-部门内序号
|
||||
// 倒数第二段是部门序号
|
||||
return Integer.parseInt(parts[parts.length - 2]);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("解析子任务编号部门序号失败: {}", itemNo);
|
||||
}
|
||||
} else if (parts.length == 2) {
|
||||
// 旧格式:TASK...-序号,认为是第一个部门
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从任务类型配置中获取目标接单部门ID
|
||||
* 如果当前类型未配置,则递归向上查找父级类型的配置
|
||||
|
||||
@ -567,15 +567,18 @@ public class TaskService {
|
||||
|
||||
// 关键:根据流水线模式和分组设置初始状态
|
||||
if ("sequential".equals(dto.getPipelineMode())) {
|
||||
// 顺序流水线:只有第一个部门的第一个子任务可接单
|
||||
if (currentDeptIndex == 1 && subIndex == 1) {
|
||||
// 顺序流水线:第一个部门的所有子任务都可接单(部门内并行)
|
||||
// 只有当第一个部门的所有子任务完成后,才解锁下一个部门的子任务
|
||||
if (currentDeptIndex == 1) {
|
||||
item.setStatus("pending");
|
||||
item.setIsLocked(0);
|
||||
item.setPrevItemId(null);
|
||||
log.info("子任务 {} 属于第一个部门,设置为待接单状态", item.getItemNo());
|
||||
} else {
|
||||
// 其他子任务都是 locked(锁定)
|
||||
// 其他部门的子任务都是 locked(锁定),等待前一个部门完成后解锁
|
||||
item.setStatus("locked");
|
||||
item.setIsLocked(1);
|
||||
log.info("子任务 {} 属于第{}个部门,设置为锁定状态", item.getItemNo(), currentDeptIndex);
|
||||
}
|
||||
} else {
|
||||
// 并行流水线:全部待接单
|
||||
@ -1575,12 +1578,13 @@ public class TaskService {
|
||||
|
||||
// 根据流水线模式和分组设置初始状态
|
||||
if ("sequential".equals(dto.getPipelineMode())) {
|
||||
// 顺序流水线:只有第一个部门的第一个子任务可接单
|
||||
if (currentDeptIndex == 1 && subIndex == 1) {
|
||||
// 顺序流水线:第一个部门的所有子任务都可接单(部门内并行)
|
||||
if (currentDeptIndex == 1) {
|
||||
item.setStatus("pending");
|
||||
item.setIsLocked(0);
|
||||
item.setPrevItemId(null);
|
||||
} else {
|
||||
// 其他部门的子任务锁定,等待前一个部门完成
|
||||
item.setStatus("locked");
|
||||
item.setIsLocked(1);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user