diff --git a/backend/src/main/java/com/designhub/service/AnalyticsService.java b/backend/src/main/java/com/designhub/service/AnalyticsService.java index 9a48e0f..f18cac8 100644 --- a/backend/src/main/java/com/designhub/service/AnalyticsService.java +++ b/backend/src/main/java/com/designhub/service/AnalyticsService.java @@ -32,6 +32,7 @@ import java.util.stream.Collectors; public class AnalyticsService { private final TaskMapper taskMapper; + private final TaskItemMapper taskItemMapper; private final UserMapper userMapper; private final DepartmentMapper departmentMapper; private final TeamScorePoolMapper teamScorePoolMapper; @@ -1489,6 +1490,140 @@ public class AnalyticsService { } } + // 查询已完成的子任务(按完成时间查询) + List completedTaskItems = taskItemMapper.selectList( + new LambdaQueryWrapper() + .eq(TaskItem::getReceiverId, userId) + .eq(TaskItem::getStatus, "completed") + .isNotNull(TaskItem::getCompleteTime) + .ge(TaskItem::getCompleteTime, startTime) + .le(TaskItem::getCompleteTime, endTime) + ); + + // 查询进行中的子任务 + List inProgressTaskItems = taskItemMapper.selectList( + new LambdaQueryWrapper() + .eq(TaskItem::getReceiverId, userId) + .eq(TaskItem::getStatus, "in_progress") + .isNotNull(TaskItem::getEstimatedHours) + ); + + log.info("获取设计师扣分明细 - 用户: {}, 月份: {}, 已完成子任务数: {}, 进行中子任务数: {}", + designer.getRealName() != null ? designer.getRealName() : designer.getUsername(), + currentMonth, completedTaskItems.size(), inProgressTaskItems.size()); + + // 处理已完成的子任务的延误扣分(使用子任务自己的estimatedHours计算deadline) + for (TaskItem item : completedTaskItems) { + if (item.getEstimatedHours() != null && item.getEstimatedHours().compareTo(BigDecimal.ZERO) > 0 + && item.getCreateTime() != null && item.getCompleteTime() != null) { + + // 计算子任务的预期deadline:createTime + estimatedHours + long estimatedMinutes = item.getEstimatedHours().multiply(BigDecimal.valueOf(60)).longValue(); + LocalDateTime expectedDeadline = item.getCreateTime().plusMinutes(estimatedMinutes); + + // 如果完成时间超过预期deadline,计算延误扣分 + if (item.getCompleteTime().isAfter(expectedDeadline)) { + BigDecimal itemScore = item.getTotalScore() != null ? BigDecimal.valueOf(item.getTotalScore()) : BigDecimal.ZERO; + + if (itemScore.compareTo(BigDecimal.ZERO) > 0) { + // 计算延误小时数 + long overdueHours = Duration.between(expectedDeadline, item.getCompleteTime()).toHours(); + + if (overdueHours > 0) { + // 计算扣分 + BigDecimal itemDeduction = itemScore + .multiply(BigDecimal.valueOf(overdueHours)) + .multiply(deductionRate) + .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); + + // 扣分不能超过任务积分 + if (itemDeduction.compareTo(itemScore) > 0) { + itemDeduction = itemScore; + } + + totalDelayDeduction = totalDelayDeduction.add(itemDeduction); + + // 获取主任务信息用于显示 + Task mainTask = taskMapper.selectById(item.getTaskId()); + String taskNo = item.getItemNo() != null ? item.getItemNo() : ""; + String taskTitle = mainTask != null ? mainTask.getTitle() : "子任务"; + + log.info("发现已完成延误子任务: itemNo={}, 任务积分={}, 延误小时={}, 扣分={}", + taskNo, itemScore, overdueHours, itemDeduction); + + delayDeductions.add(DeductionDetailVO.DelayDeductionItem.builder() + .taskId(item.getTaskId()) // 使用主任务ID + .taskNo(taskNo) + .taskTitle(taskTitle + " (" + taskNo + ")") + .taskScore(itemScore) + .deadline(expectedDeadline) + .actualEndTime(item.getCompleteTime()) + .overdueHours(overdueHours) + .deductionScore(itemDeduction) + .deductionReason("子任务延误 " + overdueHours + " 小时") + .build()); + } + } + } + } + } + + // 处理进行中的子任务的延误扣分(使用子任务自己的estimatedHours计算deadline) + for (TaskItem item : inProgressTaskItems) { + if (item.getEstimatedHours() != null && item.getEstimatedHours().compareTo(BigDecimal.ZERO) > 0 + && item.getCreateTime() != null) { + + // 计算子任务的预期deadline:createTime + estimatedHours + long estimatedMinutes = item.getEstimatedHours().multiply(BigDecimal.valueOf(60)).longValue(); + LocalDateTime expectedDeadline = item.getCreateTime().plusMinutes(estimatedMinutes); + + // 如果当前时间超过预期deadline,计算延误扣分 + if (now.isAfter(expectedDeadline)) { + BigDecimal itemScore = item.getTotalScore() != null ? BigDecimal.valueOf(item.getTotalScore()) : BigDecimal.ZERO; + + if (itemScore.compareTo(BigDecimal.ZERO) > 0) { + // 计算延误小时数(当前时间 - 预期deadline) + long overdueHours = Duration.between(expectedDeadline, now).toHours(); + + if (overdueHours > 0) { + // 计算扣分 + BigDecimal itemDeduction = itemScore + .multiply(BigDecimal.valueOf(overdueHours)) + .multiply(deductionRate) + .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); + + // 扣分不能超过任务积分 + if (itemDeduction.compareTo(itemScore) > 0) { + itemDeduction = itemScore; + } + + totalDelayDeduction = totalDelayDeduction.add(itemDeduction); + + // 获取主任务信息用于显示 + Task mainTask = taskMapper.selectById(item.getTaskId()); + String taskNo = item.getItemNo() != null ? item.getItemNo() : ""; + String taskTitle = mainTask != null ? mainTask.getTitle() : "子任务"; + + log.info("发现进行中延误子任务: itemNo={}, 任务积分={}, 延误小时={}, 扣分={}", + taskNo, itemScore, overdueHours, itemDeduction); + + delayDeductions.add(DeductionDetailVO.DelayDeductionItem.builder() + .taskId(item.getTaskId()) // 使用主任务ID + .taskNo(taskNo) + .taskTitle(taskTitle + " (" + taskNo + ")") + .taskScore(itemScore) + .deadline(expectedDeadline) + .actualEndTime(null) // 进行中子任务没有完成时间 + .overdueHours(overdueHours) + .deductionScore(itemDeduction) + .deductionReason("子任务进行中,已延误 " + overdueHours + " 小时") + .build()); + } + } + } + } + } + log.info("延误扣分总数: {}, 延误扣分记录数: {}", totalDelayDeduction, delayDeductions.size()); // 获取进度未更新扣分明细