From 038659bd4140228ba212f0545909514cea5dbff0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 3 Jan 2026 11:07:42 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=92=8C=E4=BB=BB=E5=8A=A1=E6=8A=A2=E5=8D=95?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 修复设置管理员报错 - 修正BusinessException构造函数调用 2. 完善抢单权限控制 - 需求部门成员不能抢单 - 所有部门负责人不能抢单(包括需求和接单部门) - 只有指定接单部门的普通成员可以抢单 - 验证部门是否允许接该需求类型 - 抢单成功后发送通知给任务发起人 3. 前端抢单按钮状态控制 - 添加canGrabTask方法判断抢单权限 - 可接单:绿色按钮 - 不可接单:灰色按钮并禁用 - 鼠标悬停显示不能抢单的原因 - 支持任务列表和详情页面 4. 优化用户体验 - 点击不可抢单按钮时提示具体原因 - 按钮文案动态显示状态 --- .../com/designhub/service/TaskService.java | 46 ++++++++++--- .../com/designhub/service/UserService.java | 2 +- frontend/src/views/TaskHall.vue | 67 +++++++++++++++++-- 3 files changed, 99 insertions(+), 16 deletions(-) diff --git a/backend/src/main/java/com/designhub/service/TaskService.java b/backend/src/main/java/com/designhub/service/TaskService.java index 8016f3b..6513394 100644 --- a/backend/src/main/java/com/designhub/service/TaskService.java +++ b/backend/src/main/java/com/designhub/service/TaskService.java @@ -670,26 +670,39 @@ public class TaskService { throw new BusinessException(ResultCode.FORBIDDEN, "该任务不支持抢单"); } - // 验证用户权限:只有接单部门可以接任务(管理员除外) + // 获取用户信息 var user = userService.getUserById(userId); if (user == null) { throw new BusinessException(ResultCode.FORBIDDEN, "用户不存在"); } - // 检查是否是管理员(管理员可以同时拥有需求部门和接单部门权限) - boolean isAdmin = isAdminUser(userId); - Long deptId = user.getDeptId(); - Department department = deptId != null ? departmentService.getDepartmentById(deptId) : null; + if (deptId == null) { + throw new BusinessException(ResultCode.FORBIDDEN, "您未分配部门,无法接单"); + } + + // 获取用户所属部门 + Department department = departmentService.getDepartmentById(deptId); if (department == null) { throw new BusinessException(ResultCode.FORBIDDEN, "未找到用户所属部门,请联系管理员"); } + + // 检查1:需求部门不能抢单 + if ("demand".equals(department.getDeptType())) { + throw new BusinessException(ResultCode.FORBIDDEN, "需求部门成员不能接单,只能发起需求"); + } + + // 检查2:接单部门类型验证 if (!"receiving".equals(department.getDeptType())) { - throw new BusinessException(ResultCode.FORBIDDEN, "只有接单部门可以接收任务"); + throw new BusinessException(ResultCode.FORBIDDEN, "只有接单部门成员可以接收任务"); } - if (!isAdmin && deptId == null) { - throw new BusinessException(ResultCode.FORBIDDEN, "用户部门信息不完整"); + + // 检查3:部门负责人不能抢单 + if (department.getLeaderId() != null && department.getLeaderId().equals(userId)) { + throw new BusinessException(ResultCode.FORBIDDEN, "部门负责人不能接单,请分配给设计师"); } + + // 检查4:验证部门是否允许接该需求类型 if (task.getDemandTypeId() != null) { validateAllowedDemandTypes(department, task.getDemandTypeId()); } @@ -708,7 +721,22 @@ public class TaskService { throw new BusinessException(ResultCode.TASK_ALREADY_TAKEN, "任务已被其他设计师抢走"); } - // TODO: 发送通知 + log.info("用户 {} 成功抢单任务 {}", userId, taskId); + + // 发送通知给任务发起人 + if (task.getPublisherId() != null) { + try { + notificationService.sendNotification( + task.getPublisherId(), + "任务已被接单", + String.format("您的任务【%s】已被 %s 接单", task.getTitle(), user.getRealName() != null ? user.getRealName() : user.getUsername()), + "task_grabbed", + taskId + ); + } catch (Exception e) { + log.error("发送抢单通知失败", e); + } + } } /** diff --git a/backend/src/main/java/com/designhub/service/UserService.java b/backend/src/main/java/com/designhub/service/UserService.java index 549f75b..98a5e59 100644 --- a/backend/src/main/java/com/designhub/service/UserService.java +++ b/backend/src/main/java/com/designhub/service/UserService.java @@ -1272,7 +1272,7 @@ public class UserService { User user = getUserById(userId); if (user == null) { - throw new BusinessException("用户不存在"); + throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在"); } // 更新管理员标识 diff --git a/frontend/src/views/TaskHall.vue b/frontend/src/views/TaskHall.vue index 97835d2..8f75620 100644 --- a/frontend/src/views/TaskHall.vue +++ b/frontend/src/views/TaskHall.vue @@ -320,11 +320,21 @@ 查看详情 @@ -1840,11 +1850,19 @@ - 确认抢单 + {{ canGrabTask(selectedTask).canGrab ? '确认抢单' : `不可接单(${canGrabTask(selectedTask).reason})` }} @@ -3372,12 +3390,49 @@ const handleTaskClick = (task: TaskOrSubTask) => { detailDrawerVisible.value = true } +// 判断用户是否可以抢单 +const canGrabTask = (task: TaskOrSubTask) => { + const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}') + const userDeptId = userInfo.deptId + const userDeptType = userInfo.deptType // 'demand' 或 'receiving' + + // 检查1:没有部门不能抢单 + if (!userDeptId) { + return { canGrab: false, reason: '您未分配部门,无法接单' } + } + + // 检查2:需求部门不能抢单 + if (userDeptType === 'demand') { + return { canGrab: false, reason: '需求部门成员不能接单' } + } + + // 检查3:部门负责人不能抢单 + if (userInfo.isDepartmentLeader === 1 || userInfo.isDepartmentLeader === true) { + return { canGrab: false, reason: '部门负责人不能接单' } + } + + // 检查4:验证部门是否允许接该需求类型(如果任务有需求类型限制) + if (task.demandTypeId) { + // 这里需要检查任务的需求类型是否允许当前用户的部门接单 + // 由于前端没有完整的需求类型配置,暂时信任后端验证 + } + + return { canGrab: true, reason: '' } +} + // 抢单(支持普通任务和子任务) const handleGrab = async (task: TaskOrSubTask) => { const isSubTask = task.isSubTask const taskType = isSubTask ? '子任务' : '任务' const taskNo = isSubTask ? task.subTaskNo : task.taskNo + // 先检查权限 + const { canGrab, reason } = canGrabTask(task) + if (!canGrab) { + message.warning(reason) + return + } + Modal.confirm({ title: `确认抢单${taskType}`, content: `确定要抢单${taskType}"${task.title}"吗?${taskNo ? `(编号:${taskNo})` : ''}`,