优化子任务编号格式为两级结构 - 新编号格式:任务编号-部门序号-部门内子任务序号 - 例如:TASK20260114-01-01 表示第1个部门的第1个子任务 - 同一部门内不同设计师的任务会有不同的部门内序号 - 支持创建和更新流水线任务时使用新编号格式
This commit is contained in:
parent
0030233062
commit
611677a93b
@ -420,36 +420,91 @@ public class TaskService {
|
||||
|
||||
log.info("分组完成,共 {} 个子任务组", currentGroupNo);
|
||||
|
||||
// **步骤2:按分组汇总,每个分组创建一个子任务**
|
||||
// 先按分组号收集任务类型
|
||||
Map<Integer, List<com.designhub.dto.PipelineTaskDTO.TaskItemDTO>> groupedItems = new java.util.LinkedHashMap<>();
|
||||
Map<Integer, Long> groupFirstTaskTypeId = new java.util.HashMap<>(); // 每组第一个任务类型ID
|
||||
// **步骤2:两级分组 - 先按部门分组,再按设计师分组**
|
||||
// 第一级:按部门分组(用于编号的第一段)
|
||||
// 第二级:同一部门内按设计师分组(用于编号的第二段)
|
||||
|
||||
// 收集所有分组键和对应的任务项
|
||||
Map<Integer, List<com.designhub.dto.PipelineTaskDTO.TaskItemDTO>> groupedItems = new java.util.LinkedHashMap<>();
|
||||
for (com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto : dto.getItems()) {
|
||||
int itemGroupNo = itemDto.getSortOrder() / 1000;
|
||||
groupedItems.computeIfAbsent(itemGroupNo, k -> new java.util.ArrayList<>()).add(itemDto);
|
||||
// 记录每组第一个任务类型ID
|
||||
if (!groupFirstTaskTypeId.containsKey(itemGroupNo)) {
|
||||
groupFirstTaskTypeId.put(itemGroupNo, itemDto.getTaskTypeId());
|
||||
}
|
||||
|
||||
// 按部门重新组织分组,计算部门序号
|
||||
// 格式:deptKey -> List<groupNo>
|
||||
Map<String, List<Integer>> deptToGroups = new java.util.LinkedHashMap<>();
|
||||
Map<Integer, String> groupToDeptKey = new java.util.HashMap<>();
|
||||
|
||||
for (int i = 0; i < dto.getItems().size(); i++) {
|
||||
com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto = dto.getItems().get(i);
|
||||
int itemGroupNo = itemDto.getSortOrder() / 1000;
|
||||
|
||||
// 获取部门键
|
||||
String deptKey;
|
||||
if (itemDto.getSelectedDeptId() != null) {
|
||||
deptKey = String.valueOf(itemDto.getSelectedDeptId());
|
||||
} else {
|
||||
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
|
||||
deptKey = demandType.getAllowedDeptIds();
|
||||
if (deptKey == null && demandType.getParentId() != null) {
|
||||
var parentType = configService.getDemandTypeById(demandType.getParentId());
|
||||
if (parentType != null) {
|
||||
deptKey = parentType.getAllowedDeptIds();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deptKey == null) deptKey = "null";
|
||||
|
||||
// 记录分组到部门的映射
|
||||
if (!groupToDeptKey.containsKey(itemGroupNo)) {
|
||||
groupToDeptKey.put(itemGroupNo, deptKey);
|
||||
deptToGroups.computeIfAbsent(deptKey, k -> new java.util.ArrayList<>()).add(itemGroupNo);
|
||||
}
|
||||
}
|
||||
|
||||
// 计算每个部门的序号
|
||||
Map<String, Integer> deptIndexMap = new java.util.LinkedHashMap<>();
|
||||
int deptIndex = 1;
|
||||
for (String deptKey : deptToGroups.keySet()) {
|
||||
deptIndexMap.put(deptKey, deptIndex++);
|
||||
}
|
||||
|
||||
// 计算每个分组在其部门内的子序号
|
||||
Map<Integer, Integer> groupSubIndexMap = new java.util.HashMap<>();
|
||||
for (Map.Entry<String, List<Integer>> entry : deptToGroups.entrySet()) {
|
||||
List<Integer> groups = entry.getValue();
|
||||
for (int subIdx = 0; subIdx < groups.size(); subIdx++) {
|
||||
groupSubIndexMap.put(groups.get(subIdx), subIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("部门分组统计: 共 {} 个部门, 各部门子任务数: {}", deptToGroups.size(),
|
||||
deptToGroups.entrySet().stream()
|
||||
.map(e -> e.getKey() + "=" + e.getValue().size())
|
||||
.collect(Collectors.joining(", ")));
|
||||
|
||||
// 为每个分组创建一个子任务
|
||||
int itemIndex = 1;
|
||||
for (Map.Entry<Integer, List<com.designhub.dto.PipelineTaskDTO.TaskItemDTO>> entry : groupedItems.entrySet()) {
|
||||
int groupNo = entry.getKey();
|
||||
List<com.designhub.dto.PipelineTaskDTO.TaskItemDTO> groupItems = entry.getValue();
|
||||
|
||||
// 获取该分组的部门序号和部门内子序号
|
||||
String deptKey = groupToDeptKey.get(groupNo);
|
||||
int currentDeptIndex = deptIndexMap.getOrDefault(deptKey, 1);
|
||||
int subIndex = groupSubIndexMap.getOrDefault(groupNo, 1);
|
||||
|
||||
// 汇总该分组的积分、工时、数量
|
||||
int groupTotalScore = 0;
|
||||
BigDecimal groupTotalHours = BigDecimal.ZERO;
|
||||
int groupTotalQuantity = 0;
|
||||
StringBuilder taskTypeIds = new StringBuilder();
|
||||
Long firstTaskTypeId = null;
|
||||
// 构建任务类型明细 JSON 数组
|
||||
java.util.List<java.util.Map<String, Object>> typeDetailsList = new java.util.ArrayList<>();
|
||||
|
||||
for (com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto : groupItems) {
|
||||
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
|
||||
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
|
||||
int itemScore = demandType.getUnitScore().multiply(BigDecimal.valueOf(itemDto.getQuantity())).intValue();
|
||||
BigDecimal itemHours = demandType.getEstimatedHours() != null
|
||||
? demandType.getEstimatedHours().multiply(BigDecimal.valueOf(itemDto.getQuantity()))
|
||||
@ -459,10 +514,9 @@ public class TaskService {
|
||||
groupTotalHours = groupTotalHours.add(itemHours);
|
||||
groupTotalQuantity += itemDto.getQuantity();
|
||||
|
||||
if (taskTypeIds.length() > 0) {
|
||||
taskTypeIds.append(",");
|
||||
if (firstTaskTypeId == null) {
|
||||
firstTaskTypeId = itemDto.getTaskTypeId();
|
||||
}
|
||||
taskTypeIds.append(itemDto.getTaskTypeId());
|
||||
|
||||
// 添加任务类型明细
|
||||
java.util.Map<String, Object> detail = new java.util.LinkedHashMap<>();
|
||||
@ -477,9 +531,10 @@ public class TaskService {
|
||||
// 创建子任务
|
||||
com.designhub.entity.TaskItem item = new com.designhub.entity.TaskItem();
|
||||
item.setTaskId(task.getId());
|
||||
item.setItemNo(generateTaskItemNo(task.getTaskNo(), itemIndex));
|
||||
// 使用新的编号格式:任务编号-部门序号-部门内子任务序号
|
||||
item.setItemNo(generateTaskItemNoWithDept(task.getTaskNo(), currentDeptIndex, subIndex));
|
||||
item.setGroupNo(groupNo);
|
||||
item.setTaskTypeId(groupFirstTaskTypeId.get(groupNo)); // 使用第一个任务类型ID
|
||||
item.setTaskTypeId(firstTaskTypeId);
|
||||
// 保存任务类型明细 JSON
|
||||
try {
|
||||
com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
|
||||
@ -488,7 +543,7 @@ public class TaskService {
|
||||
log.warn("序列化任务类型明细失败: {}", e.getMessage());
|
||||
}
|
||||
item.setQuantity(groupTotalQuantity);
|
||||
item.setUnitScore(groupTotalScore / groupTotalQuantity); // 平均单价
|
||||
item.setUnitScore(groupTotalScore / Math.max(groupTotalQuantity, 1)); // 平均单价
|
||||
item.setTotalScore(groupTotalScore);
|
||||
item.setEstimatedHours(groupTotalHours);
|
||||
item.setSortOrder(itemIndex);
|
||||
@ -500,40 +555,43 @@ public class TaskService {
|
||||
if (itemReceiverId != null) {
|
||||
item.setReceiverId(itemReceiverId);
|
||||
User itemReceiver = userService.getUserById(itemReceiverId);
|
||||
if (itemReceiver != null && itemReceiver.getDeptId() != null) {
|
||||
item.setReceiverDeptId(itemReceiver.getDeptId());
|
||||
if (itemReceiver != null) {
|
||||
item.setReceiverName(itemReceiver.getRealName());
|
||||
if (itemReceiver.getDeptId() != null) {
|
||||
item.setReceiverDeptId(itemReceiver.getDeptId());
|
||||
}
|
||||
}
|
||||
log.info("子任务组 {} 已预先指定设计师: {}", groupNo, itemReceiverId);
|
||||
log.info("子任务 {} 已预先指定设计师: {}", item.getItemNo(), itemReceiverId);
|
||||
}
|
||||
}
|
||||
|
||||
// 关键:根据流水线模式和分组设置初始状态
|
||||
if ("sequential".equals(dto.getPipelineMode())) {
|
||||
if (groupNo == 1) {
|
||||
// 顺序流水线:第一组待接单
|
||||
// 顺序流水线:只有第一个部门的第一个子任务可接单
|
||||
if (currentDeptIndex == 1 && subIndex == 1) {
|
||||
item.setStatus("pending");
|
||||
item.setIsLocked(0);
|
||||
item.setPrevItemId(null);
|
||||
} else {
|
||||
// 其他组的子任务都是 locked(锁定)
|
||||
// 其他子任务都是 locked(锁定)
|
||||
item.setStatus("locked");
|
||||
item.setIsLocked(1);
|
||||
}
|
||||
} else {
|
||||
// 并行流水线:全部待接单
|
||||
item.setStatus("pending");
|
||||
item.setStatus("pending");
|
||||
item.setIsLocked(0);
|
||||
}
|
||||
|
||||
taskItemMapper.insert(item);
|
||||
log.info("子任务创建成功,ID: {}, 编号: {}, 组号: {}, 积分: {}, 工时: {}, 状态: {}",
|
||||
item.getId(), item.getItemNo(), item.getGroupNo(), groupTotalScore, groupTotalHours, item.getStatus());
|
||||
log.info("子任务创建成功,ID: {}, 编号: {}, 部门序号: {}, 部门内序号: {}, 积分: {}, 工时: {}, 状态: {}",
|
||||
item.getId(), item.getItemNo(), currentDeptIndex, subIndex, groupTotalScore, groupTotalHours, item.getStatus());
|
||||
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
log.info("流水线任务创建完成,主任务ID: {}, 子任务数: {}, 分组数: {}",
|
||||
task.getId(), groupedItems.size(), currentGroupNo);
|
||||
log.info("流水线任务创建完成,主任务ID: {}, 子任务数: {}, 部门数: {}",
|
||||
task.getId(), groupedItems.size(), deptToGroups.size());
|
||||
|
||||
// 【两级审核流程】发送审核通知给部门负责人
|
||||
sendApprovalNotification(task);
|
||||
@ -542,11 +600,23 @@ public class TaskService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成子任务编号
|
||||
* 生成子任务编号(旧格式,保留兼容)
|
||||
* 格式:任务编号-子任务序号
|
||||
*/
|
||||
private String generateTaskItemNo(String taskNo, int itemIndex) {
|
||||
return taskNo + "-" + String.format("%02d", itemIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成子任务编号(新格式,支持部门内多子任务)
|
||||
* 格式:任务编号-部门序号-部门内子任务序号
|
||||
* @param taskNo 主任务编号
|
||||
* @param deptIndex 部门序号(从1开始)
|
||||
* @param subIndex 部门内子任务序号(从1开始)
|
||||
*/
|
||||
private String generateTaskItemNoWithDept(String taskNo, int deptIndex, int subIndex) {
|
||||
return taskNo + "-" + String.format("%02d", deptIndex) + "-" + String.format("%02d", subIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成任务编号
|
||||
@ -1375,15 +1445,55 @@ public class TaskService {
|
||||
lastGroupKey = currentGroupKey;
|
||||
}
|
||||
|
||||
// **步骤2:按分组汇总,每个分组创建一个子任务**
|
||||
// **步骤2:两级分组 - 先按部门分组,再按设计师分组**
|
||||
Map<Integer, List<com.designhub.dto.PipelineTaskDTO.TaskItemDTO>> groupedItems = new java.util.LinkedHashMap<>();
|
||||
Map<Integer, Long> groupFirstTaskTypeId = new java.util.HashMap<>();
|
||||
|
||||
for (com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto : dto.getItems()) {
|
||||
int itemGroupNo = itemDto.getSortOrder() / 1000;
|
||||
groupedItems.computeIfAbsent(itemGroupNo, k -> new java.util.ArrayList<>()).add(itemDto);
|
||||
if (!groupFirstTaskTypeId.containsKey(itemGroupNo)) {
|
||||
groupFirstTaskTypeId.put(itemGroupNo, itemDto.getTaskTypeId());
|
||||
}
|
||||
|
||||
// 按部门重新组织分组,计算部门序号
|
||||
Map<String, List<Integer>> deptToGroups = new java.util.LinkedHashMap<>();
|
||||
Map<Integer, String> groupToDeptKey = new java.util.HashMap<>();
|
||||
|
||||
for (int i = 0; i < dto.getItems().size(); i++) {
|
||||
com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto = dto.getItems().get(i);
|
||||
int itemGroupNo = itemDto.getSortOrder() / 1000;
|
||||
|
||||
String deptKey;
|
||||
if (itemDto.getSelectedDeptId() != null) {
|
||||
deptKey = String.valueOf(itemDto.getSelectedDeptId());
|
||||
} else {
|
||||
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
|
||||
deptKey = demandType.getAllowedDeptIds();
|
||||
if (deptKey == null && demandType.getParentId() != null) {
|
||||
var parentType = configService.getDemandTypeById(demandType.getParentId());
|
||||
if (parentType != null) {
|
||||
deptKey = parentType.getAllowedDeptIds();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deptKey == null) deptKey = "null";
|
||||
|
||||
if (!groupToDeptKey.containsKey(itemGroupNo)) {
|
||||
groupToDeptKey.put(itemGroupNo, deptKey);
|
||||
deptToGroups.computeIfAbsent(deptKey, k -> new java.util.ArrayList<>()).add(itemGroupNo);
|
||||
}
|
||||
}
|
||||
|
||||
// 计算每个部门的序号
|
||||
Map<String, Integer> deptIndexMap = new java.util.LinkedHashMap<>();
|
||||
int deptIndex = 1;
|
||||
for (String deptKey : deptToGroups.keySet()) {
|
||||
deptIndexMap.put(deptKey, deptIndex++);
|
||||
}
|
||||
|
||||
// 计算每个分组在其部门内的子序号
|
||||
Map<Integer, Integer> groupSubIndexMap = new java.util.HashMap<>();
|
||||
for (Map.Entry<String, List<Integer>> entry : deptToGroups.entrySet()) {
|
||||
List<Integer> groups = entry.getValue();
|
||||
for (int subIdx = 0; subIdx < groups.size(); subIdx++) {
|
||||
groupSubIndexMap.put(groups.get(subIdx), subIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1393,11 +1503,15 @@ public class TaskService {
|
||||
int groupNo = entry.getKey();
|
||||
List<com.designhub.dto.PipelineTaskDTO.TaskItemDTO> groupItems = entry.getValue();
|
||||
|
||||
String deptKey = groupToDeptKey.get(groupNo);
|
||||
int currentDeptIndex = deptIndexMap.getOrDefault(deptKey, 1);
|
||||
int subIndex = groupSubIndexMap.getOrDefault(groupNo, 1);
|
||||
|
||||
// 汇总该分组的积分、工时、数量
|
||||
int groupTotalScore = 0;
|
||||
BigDecimal groupTotalHours = BigDecimal.ZERO;
|
||||
int groupTotalQuantity = 0;
|
||||
StringBuilder taskTypeIds = new StringBuilder();
|
||||
Long firstTaskTypeId = null;
|
||||
java.util.List<java.util.Map<String, Object>> typeDetailsList = new java.util.ArrayList<>();
|
||||
|
||||
for (com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto : groupItems) {
|
||||
@ -1411,10 +1525,9 @@ public class TaskService {
|
||||
groupTotalHours = groupTotalHours.add(itemHours);
|
||||
groupTotalQuantity += itemDto.getQuantity();
|
||||
|
||||
if (taskTypeIds.length() > 0) {
|
||||
taskTypeIds.append(",");
|
||||
if (firstTaskTypeId == null) {
|
||||
firstTaskTypeId = itemDto.getTaskTypeId();
|
||||
}
|
||||
taskTypeIds.append(itemDto.getTaskTypeId());
|
||||
|
||||
java.util.Map<String, Object> detail = new java.util.LinkedHashMap<>();
|
||||
detail.put("typeId", itemDto.getTaskTypeId());
|
||||
@ -1428,9 +1541,10 @@ public class TaskService {
|
||||
// 创建子任务
|
||||
com.designhub.entity.TaskItem item = new com.designhub.entity.TaskItem();
|
||||
item.setTaskId(mainTask.getId());
|
||||
item.setItemNo(generateTaskItemNo(mainTask.getTaskNo(), itemIndex));
|
||||
// 使用新的编号格式:任务编号-部门序号-部门内子任务序号
|
||||
item.setItemNo(generateTaskItemNoWithDept(mainTask.getTaskNo(), currentDeptIndex, subIndex));
|
||||
item.setGroupNo(groupNo);
|
||||
item.setTaskTypeId(groupFirstTaskTypeId.get(groupNo));
|
||||
item.setTaskTypeId(firstTaskTypeId);
|
||||
try {
|
||||
com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
|
||||
item.setTypeDetails(objectMapper.writeValueAsString(typeDetailsList));
|
||||
@ -1438,7 +1552,7 @@ public class TaskService {
|
||||
log.warn("序列化任务类型明细失败: {}", e.getMessage());
|
||||
}
|
||||
item.setQuantity(groupTotalQuantity);
|
||||
item.setUnitScore(groupTotalScore / groupTotalQuantity);
|
||||
item.setUnitScore(groupTotalScore / Math.max(groupTotalQuantity, 1));
|
||||
item.setTotalScore(groupTotalScore);
|
||||
item.setEstimatedHours(groupTotalHours);
|
||||
item.setSortOrder(itemIndex);
|
||||
@ -1450,15 +1564,19 @@ public class TaskService {
|
||||
if (itemReceiverId != null) {
|
||||
item.setReceiverId(itemReceiverId);
|
||||
User itemReceiver = userService.getUserById(itemReceiverId);
|
||||
if (itemReceiver != null && itemReceiver.getDeptId() != null) {
|
||||
item.setReceiverDeptId(itemReceiver.getDeptId());
|
||||
if (itemReceiver != null) {
|
||||
item.setReceiverName(itemReceiver.getRealName());
|
||||
if (itemReceiver.getDeptId() != null) {
|
||||
item.setReceiverDeptId(itemReceiver.getDeptId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据流水线模式和分组设置初始状态
|
||||
if ("sequential".equals(dto.getPipelineMode())) {
|
||||
if (groupNo == 1) {
|
||||
// 顺序流水线:只有第一个部门的第一个子任务可接单
|
||||
if (currentDeptIndex == 1 && subIndex == 1) {
|
||||
item.setStatus("pending");
|
||||
item.setIsLocked(0);
|
||||
item.setPrevItemId(null);
|
||||
@ -1472,7 +1590,8 @@ public class TaskService {
|
||||
}
|
||||
|
||||
taskItemMapper.insert(item);
|
||||
log.info("子任务创建成功,ID: {}, 编号: {}, 组号: {}", item.getId(), item.getItemNo(), item.getGroupNo());
|
||||
log.info("子任务创建成功,ID: {}, 编号: {}, 部门序号: {}, 部门内序号: {}",
|
||||
item.getId(), item.getItemNo(), currentDeptIndex, subIndex);
|
||||
|
||||
itemIndex++;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user