From 371cfd5b2ab888a01067333614c47c2c2da9fdb5 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 3 Jan 2026 11:32:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BA=E4=BB=BB=E5=8A=A1=E5=8D=A1?= =?UTF-8?q?=E7=89=87=E6=B7=BB=E5=8A=A0=E5=AD=90=E4=BB=BB=E5=8A=A1=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=E7=BB=9F=E8=AE=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增功能: 1. Task实体新增字段: - subTaskTotal: 子任务总数 - subTaskCompleted: 已完成子任务数 - subTaskInProgress: 进行中子任务数 - subTaskPending: 待接单子任务数 - subTasks: 子任务列表(包含处理人信息) 2. TaskService新增方法: - fillSubTaskStats(): 填充流水线任务的子任务统计信息 - 自动在getMyPublishedTasks和getMyReceivedTasks中调用 - 统计各状态子任务数量 - 自动填充处理人信息 3. 同时修复流水线任务主任务状态同步问题: - 设计师接单第一个子任务时,主任务状态更新为in_progress - 确保需求方能正确看到任务进度 影响范围: - 需求方查看"我发起的"任务时,可以看到子任务进度 - 设计师查看接收的任务时,可以看到子任务详情 - 为后续前端显示提供数据支持 --- .../main/java/com/designhub/entity/Task.java | 45 +++++++++++++ .../designhub/service/DepartmentService.java | 2 +- .../service/TaskApprovalService.java | 4 +- .../designhub/service/TaskItemService.java | 36 +++++++---- .../com/designhub/service/TaskService.java | 63 ++++++++++++++++++- frontend/src/components/NotificationBell.vue | 8 +-- 6 files changed, 137 insertions(+), 21 deletions(-) diff --git a/backend/src/main/java/com/designhub/entity/Task.java b/backend/src/main/java/com/designhub/entity/Task.java index 3ba2b60..d6b08e5 100644 --- a/backend/src/main/java/com/designhub/entity/Task.java +++ b/backend/src/main/java/com/designhub/entity/Task.java @@ -317,6 +317,36 @@ public class Task implements Serializable { @TableField(exist = false) private String auditorName; + /** + * 子任务总数(非数据库字段,流水线任务专用) + */ + @TableField(exist = false) + private Integer subTaskTotal; + + /** + * 已完成子任务数(非数据库字段,流水线任务专用) + */ + @TableField(exist = false) + private Integer subTaskCompleted; + + /** + * 进行中子任务数(非数据库字段,流水线任务专用) + */ + @TableField(exist = false) + private Integer subTaskInProgress; + + /** + * 待接单子任务数(非数据库字段,流水线任务专用) + */ + @TableField(exist = false) + private Integer subTaskPending; + + /** + * 子任务列表(非数据库字段,流水线任务专用) + */ + @TableField(exist = false) + private java.util.List subTasks; + /** * 当前审核人姓名(查询时返回,不映射到数据库) */ @@ -513,5 +543,20 @@ public class Task implements Serializable { public String getCurrentApproverName() { return currentApproverName; } public void setCurrentApproverName(String currentApproverName) { this.currentApproverName = currentApproverName; } + + public Integer getSubTaskTotal() { return subTaskTotal; } + public void setSubTaskTotal(Integer subTaskTotal) { this.subTaskTotal = subTaskTotal; } + + public Integer getSubTaskCompleted() { return subTaskCompleted; } + public void setSubTaskCompleted(Integer subTaskCompleted) { this.subTaskCompleted = subTaskCompleted; } + + public Integer getSubTaskInProgress() { return subTaskInProgress; } + public void setSubTaskInProgress(Integer subTaskInProgress) { this.subTaskInProgress = subTaskInProgress; } + + public Integer getSubTaskPending() { return subTaskPending; } + public void setSubTaskPending(Integer subTaskPending) { this.subTaskPending = subTaskPending; } + + public java.util.List getSubTasks() { return subTasks; } + public void setSubTasks(java.util.List subTasks) { this.subTasks = subTasks; } } diff --git a/backend/src/main/java/com/designhub/service/DepartmentService.java b/backend/src/main/java/com/designhub/service/DepartmentService.java index 988ca0e..a8d5438 100644 --- a/backend/src/main/java/com/designhub/service/DepartmentService.java +++ b/backend/src/main/java/com/designhub/service/DepartmentService.java @@ -105,7 +105,7 @@ public class DepartmentService { @Transactional(rollbackFor = Exception.class) public DepartmentOverviewVO createDepartment(DepartmentCreateRequest request) { validateDeptType(request.getDeptType()); - + // 验证负责人ID是否有效 if (request.getLeaderId() != null && request.getLeaderId() > 0) { User leader = userMapper.selectById(request.getLeaderId()); diff --git a/backend/src/main/java/com/designhub/service/TaskApprovalService.java b/backend/src/main/java/com/designhub/service/TaskApprovalService.java index 290dc1b..9a323c9 100644 --- a/backend/src/main/java/com/designhub/service/TaskApprovalService.java +++ b/backend/src/main/java/com/designhub/service/TaskApprovalService.java @@ -261,8 +261,8 @@ public class TaskApprovalService { // TODO: 通知指定的设计师 log.info("任务【{}】已指定给设计师", task.getTitle()); } else { - // TODO: 通知任务大厅(所有接单部门成员) - log.info("任务【{}】已发布到任务大厅", task.getTitle()); + // TODO: 通知任务大厅(所有接单部门成员) + log.info("任务【{}】已发布到任务大厅", task.getTitle()); } log.info("接单部门负责人审核通过,任务ID:{},审核人:{},指定接收人:{}", diff --git a/backend/src/main/java/com/designhub/service/TaskItemService.java b/backend/src/main/java/com/designhub/service/TaskItemService.java index 2b11f34..354dc2c 100644 --- a/backend/src/main/java/com/designhub/service/TaskItemService.java +++ b/backend/src/main/java/com/designhub/service/TaskItemService.java @@ -131,19 +131,31 @@ public class TaskItemService { log.info("设计师 {} 成功抢单子任务 {}", userId, itemId); - // 发送通知给任务发布者 + // 更新主任务状态 Task mainTask = taskMapper.selectById(item.getTaskId()); - if (mainTask != null && mainTask.getPublisherId() != null) { - Notification notification = new Notification(); - notification.setReceiverId(mainTask.getPublisherId()); - notification.setNotificationType("task"); - notification.setTitle("子任务已被接单"); - notification.setContent(user.getRealName() + " 接单了子任务:" + item.getItemNo()); - notification.setRelatedId(itemId); - notification.setRelatedType("task_item"); - notification.setPriority(1); // 普通 - notification.setPushDingtalk(1); // 推送到钉钉 - notificationService.sendNotification(notification); + if (mainTask != null) { + // 如果主任务还是pending状态,更新为in_progress + if ("pending".equals(mainTask.getStatus())) { + mainTask.setStatus("in_progress"); + mainTask.setStartTime(LocalDateTime.now()); + mainTask.setActualStartTime(LocalDateTime.now()); + taskMapper.updateById(mainTask); + log.info("主任务 {} 状态已更新为 in_progress", mainTask.getId()); + } + + // 发送通知给任务发布者 + if (mainTask.getPublisherId() != null) { + Notification notification = new Notification(); + notification.setReceiverId(mainTask.getPublisherId()); + notification.setNotificationType("task"); + notification.setTitle("子任务已被接单"); + notification.setContent(user.getRealName() + " 接单了子任务:" + item.getItemNo()); + notification.setRelatedId(itemId); + notification.setRelatedType("task_item"); + notification.setPriority(1); // 普通 + notification.setPushDingtalk(1); // 推送到钉钉 + notificationService.sendNotification(notification); + } } } diff --git a/backend/src/main/java/com/designhub/service/TaskService.java b/backend/src/main/java/com/designhub/service/TaskService.java index 6513394..ea405bc 100644 --- a/backend/src/main/java/com/designhub/service/TaskService.java +++ b/backend/src/main/java/com/designhub/service/TaskService.java @@ -618,7 +618,14 @@ public class TaskService { */ public IPage getMyPublishedTasks(Integer page, Integer pageSize, Long userId, String status) { Page pageParam = new Page<>(page, pageSize); - return taskMapper.selectMyPublishedTasks(pageParam, userId, status); + IPage taskPage = taskMapper.selectMyPublishedTasks(pageParam, userId, status); + + // 填充子任务统计信息 + for (Task task : taskPage.getRecords()) { + fillSubTaskStats(task); + } + + return taskPage; } /** @@ -626,7 +633,59 @@ public class TaskService { */ public IPage getMyReceivedTasks(Integer page, Integer pageSize, Long userId, String status) { Page pageParam = new Page<>(page, pageSize); - return taskMapper.selectMyReceivedTasks(pageParam, userId, status); + IPage taskPage = taskMapper.selectMyReceivedTasks(pageParam, userId, status); + + // 填充子任务统计信息 + for (Task task : taskPage.getRecords()) { + fillSubTaskStats(task); + } + + return taskPage; + } + + /** + * 填充流水线任务的子任务统计信息 + */ + private void fillSubTaskStats(Task task) { + // 只有流水线任务才需要填充子任务信息 + if (task.getIsPipeline() == null || task.getIsPipeline() != 1) { + return; + } + + try { + // 查询所有子任务 + List subTasks = taskItemMapper.selectList( + new LambdaQueryWrapper() + .eq(TaskItem::getTaskId, task.getId()) + .orderByAsc(TaskItem::getSortOrder) + ); + + if (subTasks != null && !subTasks.isEmpty()) { + task.setSubTaskTotal(subTasks.size()); + + // 统计各状态子任务数量 + long completedCount = subTasks.stream().filter(item -> "completed".equals(item.getStatus())).count(); + long inProgressCount = subTasks.stream().filter(item -> "in_progress".equals(item.getStatus())).count(); + long pendingCount = subTasks.stream().filter(item -> "pending".equals(item.getStatus())).count(); + + task.setSubTaskCompleted((int) completedCount); + task.setSubTaskInProgress((int) inProgressCount); + task.setSubTaskPending((int) pendingCount); + + // 设置子任务列表(包含处理人信息) + task.setSubTasks(subTasks); + + // 如果主任务没有receiverName,从子任务中获取第一个有接单人的 + if (task.getReceiverName() == null || task.getReceiverName().isEmpty()) { + subTasks.stream() + .filter(item -> item.getReceiverName() != null && !item.getReceiverName().isEmpty()) + .findFirst() + .ifPresent(item -> task.setReceiverName(item.getReceiverName() + "等")); + } + } + } catch (Exception e) { + log.error("填充子任务统计信息失败:taskId={}", task.getId(), e); + } } /** diff --git a/frontend/src/components/NotificationBell.vue b/frontend/src/components/NotificationBell.vue index 3c7a0c5..46af165 100644 --- a/frontend/src/components/NotificationBell.vue +++ b/frontend/src/components/NotificationBell.vue @@ -168,22 +168,22 @@ const getIconName = (notification: Notification) => { // 匹配系统通知 if (type === 'system') { - return 'info' + return 'info' } // 匹配任务相关通知(task, task_approval, task_review, task_completed, task_rejected等) if (type.includes('task')) { - return 'document' + return 'document' } // 匹配积分通知 if (type.includes('score')) { - return 'trophy' + return 'trophy' } // 匹配评审通知 if (type === 'review' || type.includes('review')) { - return 'star' + return 'star' } // 默认铃铛图标