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})` : ''}`,