diff --git a/backend/src/main/java/com/designhub/controller/DesignerController.java b/backend/src/main/java/com/designhub/controller/DesignerController.java index 10094ec..4f66385 100644 --- a/backend/src/main/java/com/designhub/controller/DesignerController.java +++ b/backend/src/main/java/com/designhub/controller/DesignerController.java @@ -47,7 +47,7 @@ public class DesignerController { @Operation(summary = "获取设计师进行中的任务列表") @GetMapping("/{userId}/in-progress-tasks") - public Result> getDesignerInProgressTasks(@PathVariable Long userId) { + public Result>> getDesignerInProgressTasks(@PathVariable Long userId) { return Result.success(designerService.getDesignerInProgressTasks(userId)); } } diff --git a/backend/src/main/java/com/designhub/controller/TaskController.java b/backend/src/main/java/com/designhub/controller/TaskController.java index 7beb302..16ab8bf 100644 --- a/backend/src/main/java/com/designhub/controller/TaskController.java +++ b/backend/src/main/java/com/designhub/controller/TaskController.java @@ -152,6 +152,21 @@ public class TaskController { return Result.success("取消成功"); } + @Operation(summary = "评分任务", description = "需求方对已完成任务进行评分") + @PostMapping("/{id}/rate") + public Result rateTask( + @PathVariable Long id, + @RequestParam Integer rating, + @RequestParam(required = false) String comment, + @RequestHeader("Authorization") String authHeader) { + + log.info("评分任务: {}, 评分: {}, 评语: {}", id, rating, comment); + String token = jwtUtil.extractTokenFromHeader(authHeader); + Long userId = jwtUtil.getUserIdFromToken(token); + taskService.rateTask(id, userId, rating, comment); + return Result.success("评分成功"); + } + @Operation(summary = "获取已完成任务列表", description = "根据用户角色返回不同范围的已完成任务") @GetMapping("/completed") public Result> getCompletedTasks( diff --git a/backend/src/main/java/com/designhub/service/DesignerService.java b/backend/src/main/java/com/designhub/service/DesignerService.java index 473bc67..0fb79a5 100644 --- a/backend/src/main/java/com/designhub/service/DesignerService.java +++ b/backend/src/main/java/com/designhub/service/DesignerService.java @@ -439,15 +439,61 @@ public class DesignerService { } /** - * 获取设计师进行中的任务列表 + * 获取设计师进行中的任务列表(包括主任务和子任务) + * 返回统一格式的 Map 列表 */ - public List getDesignerInProgressTasks(Long userId) { - return taskMapper.selectList( + public List> getDesignerInProgressTasks(Long userId) { + List> result = new ArrayList<>(); + + // 1. 查询主任务 + List mainTasks = taskMapper.selectList( new LambdaQueryWrapper() .eq(Task::getReceiverId, userId) .eq(Task::getStatus, "in_progress") + .eq(Task::getDeleted, 0) .orderByDesc(Task::getCreateTime) ); + + for (Task task : mainTasks) { + java.util.Map item = new java.util.LinkedHashMap<>(); + item.put("id", task.getId()); + item.put("taskNo", task.getTaskNo()); + item.put("title", task.getTitle()); + item.put("status", task.getStatus()); + item.put("progress", task.getProgress()); + item.put("score", task.getScore()); + item.put("deadline", task.getDeadline()); + item.put("createTime", task.getCreateTime()); + item.put("isSubTask", false); + item.put("type", "主任务"); + result.add(item); + } + + // 2. 查询子任务 + List subTasks = taskItemMapper.selectList( + new LambdaQueryWrapper() + .eq(TaskItem::getReceiverId, userId) + .eq(TaskItem::getStatus, "in_progress") + .orderByDesc(TaskItem::getCreateTime) + ); + + for (TaskItem item : subTasks) { + java.util.Map taskItem = new java.util.LinkedHashMap<>(); + taskItem.put("id", item.getId()); + taskItem.put("taskNo", item.getItemNo()); + taskItem.put("title", "子任务 #" + item.getGroupNo()); + taskItem.put("status", item.getStatus()); + taskItem.put("progress", item.getProgress()); + taskItem.put("score", item.getTotalScore()); + taskItem.put("deadline", item.getDeadline()); + taskItem.put("createTime", item.getCreateTime()); + taskItem.put("isSubTask", true); + taskItem.put("type", "子任务"); + taskItem.put("mainTaskId", item.getTaskId()); + result.add(taskItem); + } + + return result; } } diff --git a/backend/src/main/java/com/designhub/service/TaskService.java b/backend/src/main/java/com/designhub/service/TaskService.java index fc8495e..2972beb 100644 --- a/backend/src/main/java/com/designhub/service/TaskService.java +++ b/backend/src/main/java/com/designhub/service/TaskService.java @@ -1290,6 +1290,64 @@ public class TaskService { } } + /** + * 对已完成的任务进行评分(需求方) + */ + @Transactional(rollbackFor = Exception.class) + public void rateTask(Long taskId, Long userId, Integer rating, String comment) { + log.info("用户 {} 对任务 {} 评分: {}", userId, taskId, rating); + + Task task = getTaskById(taskId); + + // 验证权限(必须是任务发布人) + if (!userId.equals(task.getPublisherId())) { + throw new BusinessException(ResultCode.FORBIDDEN, "只有任务发布人可以评分"); + } + + // 验证任务状态(必须是已完成) + if (!"completed".equals(task.getStatus())) { + throw new BusinessException(ResultCode.TASK_STATUS_ERROR, "只能对已完成的任务评分"); + } + + // 验证评分是否已存在 + if (task.getRating() != null && task.getRating() > 0) { + throw new BusinessException(ResultCode.PARAM_ERROR, "该任务已经评分过了"); + } + + // 验证评分值 + if (rating == null || rating < 1 || rating > 5) { + throw new BusinessException(ResultCode.PARAM_ERROR, "评分必须在1-5之间"); + } + + // 更新评分 + task.setRating(rating); + if (comment != null && !comment.trim().isEmpty()) { + task.setReviewComment(comment); + } + taskMapper.updateById(task); + + // 发送通知给设计师 + if (task.getReceiverId() != null) { + try { + User publisher = userService.getUserById(userId); + String publisherName = publisher != null ? + (publisher.getRealName() != null ? publisher.getRealName() : publisher.getUsername()) : "需求方"; + + String ratingDesc = rating == 5 ? "五星好评" : rating + "星评价"; + notificationService.sendTaskNotification( + task.getReceiverId(), + taskId, + "任务获得评分", + String.format("您完成的任务【%s】已被 %s 评为 %s", task.getTitle(), publisherName, ratingDesc) + ); + } catch (Exception e) { + log.error("发送任务评分通知失败", e); + } + } + + log.info("任务 {} 评分成功: {} 星", taskId, rating); + } + /** * 取消任务 */ diff --git a/frontend/src/api/task.ts b/frontend/src/api/task.ts index 4dffdfb..b796ce4 100644 --- a/frontend/src/api/task.ts +++ b/frontend/src/api/task.ts @@ -240,6 +240,15 @@ export const cancelTask = (id: number, reason: string) => { }) } +/** + * 评分任务(需求方对已完成任务进行评分) + */ +export const rateTask = (id: number, rating: number, comment?: string) => { + return request.post(`/tasks/${id}/rate`, null, { + params: { rating, comment } + }) +} + /** * 获取任务大厅 */ diff --git a/frontend/src/views/DesignerHall.vue b/frontend/src/views/DesignerHall.vue index 7f00f60..f4a17c3 100644 --- a/frontend/src/views/DesignerHall.vue +++ b/frontend/src/views/DesignerHall.vue @@ -386,6 +386,25 @@ const handleMonthChange = () => { loadLeaderboard(activeLeaderboard.value) } +// 加载设计师进行中的任务 +const loadDesignerTasks = async (designer: DesignerStats) => { + if (designer.loadingTasks) return + + designer.loadingTasks = true + try { + const response = await designerApi.getDesignerInProgressTasks(designer.userId) + if (response.code === 200) { + designer.inProgressTasks = response.data || [] + designer.showTasks = true + } + } catch (error) { + console.error('加载设计师任务失败:', error) + message.error('加载任务列表失败') + } finally { + designer.loadingTasks = false + } +} + // 组件挂载 onMounted(() => { // 设置默认选中当前月份 diff --git a/frontend/src/views/TaskHall.vue b/frontend/src/views/TaskHall.vue index 7f3340c..ef784ab 100644 --- a/frontend/src/views/TaskHall.vue +++ b/frontend/src/views/TaskHall.vue @@ -1375,6 +1375,38 @@ 完成: {{ formatDate(task.completeTime) }} + + +
+ +
+ 已评分 +
+ +
+
+ + + + 立即评分 + + +
+ 等待发布人评分 +
+
@@ -2190,15 +2222,31 @@ - + + block + @click="showRatingModal(selectedTask)"> + 评分 + +
+
已评分
+
+ +
+
+ + + + +
+
+
任务名称
+
{{ ratingTask?.title }}
+
+ +
+
请为本次任务评分
+
+
+ +
+
+
+ {{ ratingValue === 5 ? '非常满意' : ratingValue === 4 ? '比较满意' : ratingValue === 3 ? '一般' : ratingValue === 2 ? '不太满意' : '非常不满意' }} +
+
+ +
+
评价留言(选填)
+ +
+ +
+ + 取消 + + + 提交评分 + +
+
+
@@ -2277,6 +2396,13 @@ const total = ref(0) const detailDrawerVisible = ref(false) const selectedTask = ref(null) +// 评分弹窗 +const ratingModalVisible = ref(false) +const ratingTask = ref(null) +const ratingValue = ref(5) +const ratingComment = ref('') +const ratingLoading = ref(false) + // 商品ID管理 const taskProducts = ref([]) const newProductId = ref('') @@ -4029,6 +4155,47 @@ const canCompleteTask = (task: TaskOrSubTask) => { return task.receiverId === userInfo.id && (task.progress || 0) >= 100 } +// 判断是否是任务发布人 +const isTaskPublisher = (task: TaskOrSubTask) => { + const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}') + return task.publisherId === userInfo.id +} + +// 显示评分弹窗 +const showRatingModal = (task: TaskOrSubTask) => { + ratingTask.value = task + ratingValue.value = 5 + ratingComment.value = '' + ratingModalVisible.value = true +} + +// 提交评分 +const submitRating = async () => { + if (!ratingTask.value) return + + ratingLoading.value = true + try { + await taskApi.rateTask(ratingTask.value.id!, ratingValue.value, ratingComment.value || undefined) + message.success('评分成功!') + ratingModalVisible.value = false + + // 更新当前任务的评分 + if (selectedTask.value && selectedTask.value.id === ratingTask.value.id) { + selectedTask.value.rating = ratingValue.value + } + + // 刷新已完成任务列表 + if (activeTab.value === 'completed') { + loadCompletedTasks() + } + } catch (error: any) { + console.error('评分失败:', error) + message.error(error.msg || error.message || '评分失败') + } finally { + ratingLoading.value = false + } +} + // 判断是否可以审核任务 // 对于审批流程中的任务:只有当前审核人可以审核 // 对于其他情况:只有部门负责人可以审核