fix: 修复被驳回流水线任务无法重新编辑的问题,支持PipelineTaskDTO格式更新

This commit is contained in:
Your Name 2026-01-12 18:21:35 +08:00
parent 2f0ec3d622
commit ddb5e729b9
2 changed files with 315 additions and 4 deletions

View File

@ -95,13 +95,35 @@ public class TaskController {
return Result.success(task);
}
@Operation(summary = "更新任务", description = "更新任务信息")
@Operation(summary = "更新任务", description = "更新任务信息,支持普通任务和流水线任务")
@PutMapping("/{id}")
public Result<String> updateTask(@PathVariable Long id, @RequestBody Task task, @RequestHeader("Authorization") String authHeader) {
public Result<String> updateTask(@PathVariable Long id, @RequestBody Object taskData, @RequestHeader("Authorization") String authHeader) {
log.info("更新任务: {}", id);
String token = jwtUtil.extractTokenFromHeader(authHeader);
Long userId = jwtUtil.getUserIdFromToken(token);
taskService.updateTask(id, task, userId);
// 判断是否是流水线任务(检查是否有isPipeline字段或items字段)
try {
com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
String json = objectMapper.writeValueAsString(taskData);
com.fasterxml.jackson.databind.JsonNode jsonNode = objectMapper.readTree(json);
// 检查是否是流水线任务格式
if (jsonNode.has("isPipeline") && jsonNode.get("isPipeline").asBoolean() ||
jsonNode.has("items") && jsonNode.get("items").isArray()) {
// 流水线任务更新
com.designhub.dto.PipelineTaskDTO dto = objectMapper.convertValue(taskData, com.designhub.dto.PipelineTaskDTO.class);
taskService.updatePipelineTask(id, dto, userId);
} else {
// 普通任务更新
Task task = objectMapper.convertValue(taskData, Task.class);
taskService.updateTask(id, task, userId);
}
} catch (Exception e) {
log.error("解析任务数据失败", e);
throw new com.designhub.exception.BusinessException(com.designhub.common.ResultCode.PARAM_ERROR, "任务数据格式错误");
}
return Result.success("更新成功");
}

View File

@ -1098,7 +1098,7 @@ public class TaskService {
}
/**
* 更新任务
* 更新任务(普通任务)
*/
@Transactional(rollbackFor = Exception.class)
public void updateTask(Long id, Task task, Long userId) {
@ -1129,6 +1129,295 @@ public class TaskService {
log.info("任务更新成功: taskId={}, userId={}, isRejected={}", id, userId, isRejected);
}
/**
* 更新流水线任务
*/
@Transactional(rollbackFor = Exception.class)
public void updatePipelineTask(Long id, com.designhub.dto.PipelineTaskDTO dto, Long userId) {
Task existTask = getTaskById(id);
// 验证权限:只有任务发布人才能更新任务
boolean isAdmin = isAdminUser(userId);
if (!isAdmin && !userId.equals(existTask.getPublisherId())) {
throw new BusinessException(ResultCode.FORBIDDEN, "只有任务发布人可以更新任务");
}
// 验证任务是否是流水线任务
if (existTask.getIsPipeline() == null || existTask.getIsPipeline() != 1) {
throw new BusinessException(ResultCode.PARAM_ERROR, "该任务不是流水线任务");
}
// 允许更新被驳回的任务(approvalStatus包含rejected或status为draft)
boolean isRejected = (existTask.getApprovalStatus() != null &&
(existTask.getApprovalStatus().contains("rejected") ||
"draft".equals(existTask.getApprovalStatus()))) ||
"draft".equals(existTask.getStatus());
if (!isRejected) {
throw new BusinessException(ResultCode.PARAM_ERROR, "只能更新被驳回或草稿状态的任务");
}
// 验证流水线模式
if (!"sequential".equals(dto.getPipelineMode()) && !"parallel".equals(dto.getPipelineMode())) {
throw new BusinessException(ResultCode.PARAM_ERROR, "流水线模式必须是 sequential 或 parallel");
}
// 验证子任务列表
if (dto.getItems() == null || dto.getItems().isEmpty()) {
throw new BusinessException(ResultCode.PARAM_ERROR, "流水线任务至少需要一个子任务");
}
// 计算总积分和工时
int totalScore = 0;
double totalHours = 0;
for (com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto : dto.getItems()) {
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
if (demandType == null) {
throw new BusinessException(ResultCode.PARAM_ERROR, "任务类型ID无效: " + itemDto.getTaskTypeId());
}
int itemScore = demandType.getUnitScore().multiply(BigDecimal.valueOf(itemDto.getQuantity())).intValue();
double itemHours = demandType.getEstimatedHours() != null ?
demandType.getEstimatedHours().multiply(BigDecimal.valueOf(itemDto.getQuantity())).doubleValue() : 0;
totalScore += itemScore;
totalHours += itemHours;
}
// 检查部门积分是否充足(管理员跳过积分检查)
User user = userService.getUserById(userId);
if (!isAdmin && user.getDeptId() != null) {
if (!teamScorePoolService.checkBalance(user.getDeptId(), totalScore)) {
throw new BusinessException(ResultCode.INSUFFICIENT_SCORE, "部门积分余额不足");
}
if (!teamScorePoolService.checkPeriodLimit(user.getDeptId(), totalScore)) {
throw new BusinessException(ResultCode.SCORE_LIMIT_EXCEEDED, "超过本周期积分消耗限制");
}
}
// 更新主任务信息
existTask.setTitle(dto.getTitle());
existTask.setPipelineMode(dto.getPipelineMode());
existTask.setScore(totalScore);
existTask.setEstimatedHours(BigDecimal.valueOf(totalHours));
existTask.setBrandId(dto.getBrandId());
existTask.setCategoryId(dto.getCategoryId());
existTask.setPlatformId(dto.getPlatformId());
existTask.setSpuInfo(dto.getSpuInfo());
existTask.setTaskSubType(dto.getTaskSubType());
existTask.setAttachmentUrl(dto.getAttachmentUrl());
existTask.setPreviewImage(dto.getPreviewImage());
existTask.setRemark(dto.getRemark());
existTask.setPriority(dto.getPriority() != null ? dto.getPriority() : 1);
existTask.setReleaseType(dto.getReleaseType() != null ? dto.getReleaseType() : "recruitment");
// 设置商品条码列表
if (dto.getProductBarcodes() != null && !dto.getProductBarcodes().isEmpty()) {
existTask.setProductBarcodes(String.join(",", dto.getProductBarcodes()));
}
// 设置任务类型ID
if (dto.getItems() != null && !dto.getItems().isEmpty()) {
existTask.setTaskTypeId(dto.getItems().get(0).getTaskTypeId());
String taskTypeIds = dto.getItems().stream()
.map(item -> String.valueOf(item.getTaskTypeId()))
.collect(Collectors.joining(","));
existTask.setTaskTypeIds(taskTypeIds);
}
// 重置审核状态为draft,以便重新提交审核
existTask.setApprovalStatus("draft");
existTask.setStatus("draft");
existTask.setRejectReason(null); // 清空驳回原因
existTask.setCurrentApproverId(null);
existTask.setCurrentApproverRole(null);
existTask.setUpdateTime(LocalDateTime.now());
// 如果是assigned模式,设置接收人
Long mainReceiverId = dto.getReceiverId();
if ("assigned".equals(dto.getReleaseType()) && mainReceiverId == null && dto.getItems() != null && !dto.getItems().isEmpty()) {
mainReceiverId = dto.getItems().get(0).getReceiverId();
}
if ("assigned".equals(dto.getReleaseType()) && mainReceiverId != null) {
existTask.setReceiverId(mainReceiverId);
User receiver = userService.getUserById(mainReceiverId);
if (receiver != null && receiver.getDeptId() != null) {
existTask.setReceiverDeptId(receiver.getDeptId());
}
} else {
existTask.setReceiverId(null);
existTask.setReceiverDeptId(null);
}
// 更新主任务
taskMapper.updateById(existTask);
log.info("主任务更新成功: taskId={}, taskNo={}", existTask.getId(), existTask.getTaskNo());
// 删除旧的子任务
taskItemMapper.delete(new LambdaQueryWrapper<com.designhub.entity.TaskItem>()
.eq(com.designhub.entity.TaskItem::getTaskId, id));
log.info("已删除旧的子任务: taskId={}", id);
// 重新创建子任务(使用与createPipelineTask相同的逻辑)
createPipelineTaskItemsForUpdate(existTask, dto);
// 重新初始化审核状态并发送通知
initApprovalStatus(existTask);
sendApprovalNotification(existTask);
log.info("流水线任务更新成功: taskId={}, userId={}", id, userId);
}
/**
* 为更新操作创建流水线子任务(复用createPipelineTask的子任务创建逻辑)
*/
private void createPipelineTaskItemsForUpdate(Task mainTask, com.designhub.dto.PipelineTaskDTO dto) {
// **步骤1:按接单部门自动分组**
int currentGroupNo = 1;
String lastDeptKey = null;
for (int i = 0; i < dto.getItems().size(); i++) {
com.designhub.dto.PipelineTaskDTO.TaskItemDTO itemDto = dto.getItems().get(i);
var demandType = configService.getDemandTypeById(itemDto.getTaskTypeId());
// 获取当前任务类型的接单部门配置
String currentDeptKey;
if (itemDto.getSelectedDeptId() != null) {
currentDeptKey = String.valueOf(itemDto.getSelectedDeptId());
} else {
currentDeptKey = demandType.getAllowedDeptIds();
if (currentDeptKey == null && demandType.getParentId() != null) {
var parentType = configService.getDemandTypeById(demandType.getParentId());
if (parentType != null) {
currentDeptKey = parentType.getAllowedDeptIds();
}
}
}
// 判断是否需要创建新分组
boolean needNewGroup = false;
if (i > 0) {
if (currentDeptKey == null || lastDeptKey == null) {
needNewGroup = true;
} else if (!currentDeptKey.equals(lastDeptKey)) {
needNewGroup = true;
}
}
if (needNewGroup) {
currentGroupNo++;
}
itemDto.setSortOrder(currentGroupNo * 1000 + i);
lastDeptKey = currentDeptKey;
}
// **步骤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());
}
}
// 为每个分组创建一个子任务
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();
// 汇总该分组的积分、工时、数量
int groupTotalScore = 0;
BigDecimal groupTotalHours = BigDecimal.ZERO;
int groupTotalQuantity = 0;
StringBuilder taskTypeIds = new StringBuilder();
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());
int itemScore = demandType.getUnitScore().multiply(BigDecimal.valueOf(itemDto.getQuantity())).intValue();
BigDecimal itemHours = demandType.getEstimatedHours() != null
? demandType.getEstimatedHours().multiply(BigDecimal.valueOf(itemDto.getQuantity()))
: BigDecimal.ZERO;
groupTotalScore += itemScore;
groupTotalHours = groupTotalHours.add(itemHours);
groupTotalQuantity += itemDto.getQuantity();
if (taskTypeIds.length() > 0) {
taskTypeIds.append(",");
}
taskTypeIds.append(itemDto.getTaskTypeId());
java.util.Map<String, Object> detail = new java.util.LinkedHashMap<>();
detail.put("typeId", itemDto.getTaskTypeId());
detail.put("typeName", demandType.getName());
detail.put("quantity", itemDto.getQuantity());
detail.put("unitScore", demandType.getUnitScore());
detail.put("totalScore", itemScore);
typeDetailsList.add(detail);
}
// 创建子任务
com.designhub.entity.TaskItem item = new com.designhub.entity.TaskItem();
item.setTaskId(mainTask.getId());
item.setItemNo(generateTaskItemNo(mainTask.getTaskNo(), itemIndex));
item.setGroupNo(groupNo);
item.setTaskTypeId(groupFirstTaskTypeId.get(groupNo));
try {
com.fasterxml.jackson.databind.ObjectMapper objectMapper = new com.fasterxml.jackson.databind.ObjectMapper();
item.setTypeDetails(objectMapper.writeValueAsString(typeDetailsList));
} catch (Exception e) {
log.warn("序列化任务类型明细失败: {}", e.getMessage());
}
item.setQuantity(groupTotalQuantity);
item.setUnitScore(groupTotalScore / groupTotalQuantity);
item.setTotalScore(groupTotalScore);
item.setEstimatedHours(groupTotalHours);
item.setSortOrder(itemIndex);
item.setProgress(0);
// 如果是assigned模式,设置子任务的接收人
if ("assigned".equals(dto.getReleaseType()) && !groupItems.isEmpty()) {
Long itemReceiverId = groupItems.get(0).getReceiverId();
if (itemReceiverId != null) {
item.setReceiverId(itemReceiverId);
User itemReceiver = userService.getUserById(itemReceiverId);
if (itemReceiver != null && itemReceiver.getDeptId() != null) {
item.setReceiverDeptId(itemReceiver.getDeptId());
}
}
}
// 根据流水线模式和分组设置初始状态
if ("sequential".equals(dto.getPipelineMode())) {
if (groupNo == 1) {
item.setStatus("pending");
item.setIsLocked(0);
item.setPrevItemId(null);
} else {
item.setStatus("locked");
item.setIsLocked(1);
}
} else {
item.setStatus("pending");
item.setIsLocked(0);
}
taskItemMapper.insert(item);
log.info("子任务创建成功,ID: {}, 编号: {}, 组号: {}", item.getId(), item.getItemNo(), item.getGroupNo());
itemIndex++;
}
log.info("流水线子任务创建完成,主任务ID: {}, 子任务数: {}", mainTask.getId(), groupedItems.size());
}
/**
* 抢单