From ddb5e729b9601c097343526e910a95f5c6555cbe Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 12 Jan 2026 18:21:35 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=A2=AB=E9=A9=B3?= =?UTF-8?q?=E5=9B=9E=E6=B5=81=E6=B0=B4=E7=BA=BF=E4=BB=BB=E5=8A=A1=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E9=87=8D=E6=96=B0=E7=BC=96=E8=BE=91=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=8C=E6=94=AF=E6=8C=81PipelineTaskDTO=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designhub/controller/TaskController.java | 28 +- .../com/designhub/service/TaskService.java | 291 +++++++++++++++++- 2 files changed, 315 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/designhub/controller/TaskController.java b/backend/src/main/java/com/designhub/controller/TaskController.java index a264033..ff5073e 100644 --- a/backend/src/main/java/com/designhub/controller/TaskController.java +++ b/backend/src/main/java/com/designhub/controller/TaskController.java @@ -95,13 +95,35 @@ public class TaskController { return Result.success(task); } - @Operation(summary = "更新任务", description = "更新任务信息") + @Operation(summary = "更新任务", description = "更新任务信息,支持普通任务和流水线任务") @PutMapping("/{id}") - public Result updateTask(@PathVariable Long id, @RequestBody Task task, @RequestHeader("Authorization") String authHeader) { + public Result 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("更新成功"); } diff --git a/backend/src/main/java/com/designhub/service/TaskService.java b/backend/src/main/java/com/designhub/service/TaskService.java index aaa0f22..73f369b 100644 --- a/backend/src/main/java/com/designhub/service/TaskService.java +++ b/backend/src/main/java/com/designhub/service/TaskService.java @@ -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() + .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> groupedItems = new java.util.LinkedHashMap<>(); + Map 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> entry : groupedItems.entrySet()) { + int groupNo = entry.getKey(); + List groupItems = entry.getValue(); + + // 汇总该分组的积分、工时、数量 + int groupTotalScore = 0; + BigDecimal groupTotalHours = BigDecimal.ZERO; + int groupTotalQuantity = 0; + StringBuilder taskTypeIds = new StringBuilder(); + java.util.List> 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 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()); + } /** * 抢单