Revert "fix: respect switched dept when grabbing tasks"
This reverts commit 2a222c8290268b23fe6c65cf7bb89d4ac1a88640.
This commit is contained in:
parent
2a222c8290
commit
ecda3cd4b0
@ -7,7 +7,6 @@ import com.designhub.dto.TaskAuditRequest;
|
|||||||
import com.designhub.entity.Task;
|
import com.designhub.entity.Task;
|
||||||
import com.designhub.service.TaskApprovalService;
|
import com.designhub.service.TaskApprovalService;
|
||||||
import com.designhub.service.TaskService;
|
import com.designhub.service.TaskService;
|
||||||
import com.designhub.service.UserService;
|
|
||||||
import com.designhub.util.JwtUtil;
|
import com.designhub.util.JwtUtil;
|
||||||
import com.designhub.vo.DashboardStatsVO;
|
import com.designhub.vo.DashboardStatsVO;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@ -34,7 +33,6 @@ public class TaskController {
|
|||||||
|
|
||||||
private final TaskService taskService;
|
private final TaskService taskService;
|
||||||
private final TaskApprovalService taskApprovalService;
|
private final TaskApprovalService taskApprovalService;
|
||||||
private final UserService userService;
|
|
||||||
private final JwtUtil jwtUtil;
|
private final JwtUtil jwtUtil;
|
||||||
|
|
||||||
@Operation(summary = "创建任务", description = "发起新的设计任务")
|
@Operation(summary = "创建任务", description = "发起新的设计任务")
|
||||||
@ -215,13 +213,11 @@ public class TaskController {
|
|||||||
|
|
||||||
@Operation(summary = "抢单", description = "设计师抢单")
|
@Operation(summary = "抢单", description = "设计师抢单")
|
||||||
@PostMapping("/{id}/grab")
|
@PostMapping("/{id}/grab")
|
||||||
public Result<String> grabTask(@PathVariable Long id,
|
public Result<String> grabTask(@PathVariable Long id, @RequestHeader("Authorization") String authHeader) {
|
||||||
@RequestHeader("Authorization") String authHeader,
|
|
||||||
@RequestHeader(value = "X-Dept-Id", required = false) Long actingDeptId) {
|
|
||||||
log.info("抢单: {}", id);
|
log.info("抢单: {}", id);
|
||||||
String token = jwtUtil.extractTokenFromHeader(authHeader);
|
String token = jwtUtil.extractTokenFromHeader(authHeader);
|
||||||
Long userId = jwtUtil.getUserIdFromToken(token);
|
Long userId = jwtUtil.getUserIdFromToken(token);
|
||||||
taskService.grabTask(id, userId, actingDeptId);
|
taskService.grabTask(id, userId);
|
||||||
return Result.success("抢单成功");
|
return Result.success("抢单成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,22 +318,18 @@ public class TaskController {
|
|||||||
@Parameter(description = "筛选可接单部门ID") @RequestParam(required = false) Long filterDeptId,
|
@Parameter(description = "筛选可接单部门ID") @RequestParam(required = false) Long filterDeptId,
|
||||||
@Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer page,
|
@Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer page,
|
||||||
@Parameter(description = "每页数量") @RequestParam(defaultValue = "20") Integer pageSize,
|
@Parameter(description = "每页数量") @RequestParam(defaultValue = "20") Integer pageSize,
|
||||||
@RequestHeader("Authorization") String authHeader,
|
@RequestHeader("Authorization") String authHeader) {
|
||||||
@RequestHeader(value = "X-Dept-Id", required = false) Long actingDeptId) {
|
|
||||||
|
|
||||||
// 获取当前用户的部门ID
|
// 获取当前用户的部门ID
|
||||||
String token = jwtUtil.extractTokenFromHeader(authHeader);
|
String token = jwtUtil.extractTokenFromHeader(authHeader);
|
||||||
Long userId = jwtUtil.getUserIdFromToken(token);
|
Long userId = jwtUtil.getUserIdFromToken(token);
|
||||||
Long userDeptId = taskService.getUserDeptId(userId);
|
Long userDeptId = taskService.getUserDeptId(userId);
|
||||||
if (actingDeptId != null) {
|
|
||||||
userDeptId = userService.resolveAccessibleDepartmentForView(userId, actingDeptId).getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("查询任务大厅: taskTypeId={}, demandTypeId={}, brandId={}, categoryId={}, platformId={}, " +
|
log.info("查询任务大厅: taskTypeId={}, demandTypeId={}, brandId={}, categoryId={}, platformId={}, " +
|
||||||
"taskSubType={}, minScore={}, maxScore={}, keyword={}, publisherName={}, timeRange={}, " +
|
"taskSubType={}, minScore={}, maxScore={}, keyword={}, publisherName={}, timeRange={}, " +
|
||||||
"sortBy={}, filterDeptId={}, page={}, pageSize={}, userDeptId={}, actingDeptId={}",
|
"sortBy={}, filterDeptId={}, page={}, pageSize={}, userDeptId={}",
|
||||||
taskTypeId, demandTypeId, brandId, categoryId, platformId, taskSubType,
|
taskTypeId, demandTypeId, brandId, categoryId, platformId, taskSubType,
|
||||||
minScore, maxScore, keyword, publisherName, timeRange, sortBy, filterDeptId, page, pageSize, userDeptId, actingDeptId);
|
minScore, maxScore, keyword, publisherName, timeRange, sortBy, filterDeptId, page, pageSize, userDeptId);
|
||||||
|
|
||||||
IPage<Task> taskPage = taskService.getTaskHall(page, pageSize, taskTypeId, demandTypeId,
|
IPage<Task> taskPage = taskService.getTaskHall(page, pageSize, taskTypeId, demandTypeId,
|
||||||
brandId, categoryId, platformId, taskSubType, minScore, maxScore, keyword,
|
brandId, categoryId, platformId, taskSubType, minScore, maxScore, keyword,
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.designhub.common.Result;
|
import com.designhub.common.Result;
|
||||||
import com.designhub.entity.TaskItem;
|
import com.designhub.entity.TaskItem;
|
||||||
import com.designhub.service.TaskItemService;
|
import com.designhub.service.TaskItemService;
|
||||||
import com.designhub.service.UserService;
|
|
||||||
import com.designhub.mapper.UserMapper;
|
import com.designhub.mapper.UserMapper;
|
||||||
import com.designhub.mapper.DepartmentMapper;
|
import com.designhub.mapper.DepartmentMapper;
|
||||||
import com.designhub.util.JwtUtil;
|
import com.designhub.util.JwtUtil;
|
||||||
@ -44,7 +43,6 @@ public class TaskItemController {
|
|||||||
private final TaskItemMapper taskItemMapper;
|
private final TaskItemMapper taskItemMapper;
|
||||||
private final JwtUtil jwtUtil;
|
private final JwtUtil jwtUtil;
|
||||||
private final WorkHoursCalculator workHoursCalculator;
|
private final WorkHoursCalculator workHoursCalculator;
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取可接单的子任务列表
|
* 获取可接单的子任务列表
|
||||||
@ -64,20 +62,19 @@ public class TaskItemController {
|
|||||||
@Parameter(description = "类目ID") @RequestParam(required = false) Long categoryId,
|
@Parameter(description = "类目ID") @RequestParam(required = false) Long categoryId,
|
||||||
@Parameter(description = "平台ID") @RequestParam(required = false) Long platformId,
|
@Parameter(description = "平台ID") @RequestParam(required = false) Long platformId,
|
||||||
@Parameter(description = "需求类型") @RequestParam(required = false) String taskSubType,
|
@Parameter(description = "需求类型") @RequestParam(required = false) String taskSubType,
|
||||||
@RequestHeader(value = "Authorization", required = false) String token,
|
@RequestHeader(value = "Authorization", required = false) String token) {
|
||||||
@RequestHeader(value = "X-Dept-Id", required = false) Long actingDeptId) {
|
|
||||||
|
|
||||||
Long viewerDeptId = null;
|
Long viewerDeptId = null;
|
||||||
if (token != null && !token.trim().isEmpty()) {
|
if (token != null && !token.trim().isEmpty()) {
|
||||||
String actualToken = jwtUtil.extractTokenFromHeader(token);
|
try {
|
||||||
Long userId = jwtUtil.getUserIdFromToken(actualToken);
|
String actualToken = jwtUtil.extractTokenFromHeader(token);
|
||||||
com.designhub.entity.User user = userMapper.selectById(userId);
|
Long userId = jwtUtil.getUserIdFromToken(actualToken);
|
||||||
if (user != null) {
|
com.designhub.entity.User user = userMapper.selectById(userId);
|
||||||
if (actingDeptId != null) {
|
if (user != null) {
|
||||||
viewerDeptId = userService.resolveAccessibleDepartmentForView(userId, actingDeptId).getId();
|
|
||||||
} else {
|
|
||||||
viewerDeptId = user.getDeptId();
|
viewerDeptId = user.getDeptId();
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("解析任务大厅用户部门失败,继续使用默认口径: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,12 +347,11 @@ public class TaskItemController {
|
|||||||
@PostMapping("/{itemId}/grab")
|
@PostMapping("/{itemId}/grab")
|
||||||
public Result<String> grabItem(
|
public Result<String> grabItem(
|
||||||
@Parameter(description = "子任务ID") @PathVariable Long itemId,
|
@Parameter(description = "子任务ID") @PathVariable Long itemId,
|
||||||
@RequestHeader("Authorization") String token,
|
@RequestHeader("Authorization") String token) {
|
||||||
@RequestHeader(value = "X-Dept-Id", required = false) Long actingDeptId) {
|
|
||||||
|
|
||||||
String actualToken = token.replace("Bearer ", "");
|
String actualToken = token.replace("Bearer ", "");
|
||||||
Long userId = jwtUtil.getUserIdFromToken(actualToken);
|
Long userId = jwtUtil.getUserIdFromToken(actualToken);
|
||||||
taskItemService.grabItem(itemId, userId, actingDeptId);
|
taskItemService.grabItem(itemId, userId);
|
||||||
return Result.success("抢单成功");
|
return Result.success("抢单成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -203,12 +203,6 @@ public interface TaskItemMapper extends BaseMapper<TaskItem> {
|
|||||||
" #{typeId}" +
|
" #{typeId}" +
|
||||||
" </foreach> " +
|
" </foreach> " +
|
||||||
"</if> " +
|
"</if> " +
|
||||||
"<if test='visibleReceiverDeptIds != null and visibleReceiverDeptIds.size() > 0'> " +
|
|
||||||
" AND (ti.receiver_dept_id IS NULL OR ti.receiver_dept_id IN " +
|
|
||||||
" <foreach collection='visibleReceiverDeptIds' item='deptId' open='(' separator=',' close=')'>" +
|
|
||||||
" #{deptId}" +
|
|
||||||
" </foreach>) " +
|
|
||||||
"</if> " +
|
|
||||||
"ORDER BY ti.create_time DESC" +
|
"ORDER BY ti.create_time DESC" +
|
||||||
"</script>")
|
"</script>")
|
||||||
IPage<TaskItem> selectAvailableItemsWithFilters(Page<TaskItem> page,
|
IPage<TaskItem> selectAvailableItemsWithFilters(Page<TaskItem> page,
|
||||||
@ -218,8 +212,7 @@ public interface TaskItemMapper extends BaseMapper<TaskItem> {
|
|||||||
@Param("categoryId") Long categoryId,
|
@Param("categoryId") Long categoryId,
|
||||||
@Param("platformId") Long platformId,
|
@Param("platformId") Long platformId,
|
||||||
@Param("taskSubType") String taskSubType,
|
@Param("taskSubType") String taskSubType,
|
||||||
@Param("allowedTaskTypeIds") List<Long> allowedTaskTypeIds,
|
@Param("allowedTaskTypeIds") List<Long> allowedTaskTypeIds);
|
||||||
@Param("visibleReceiverDeptIds") List<Long> visibleReceiverDeptIds);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询进行中的子任务列表
|
* 查询进行中的子任务列表
|
||||||
|
|||||||
@ -106,17 +106,21 @@ public class TaskItemService {
|
|||||||
Long brandId, Long categoryId, Long platformId, String taskSubType,
|
Long brandId, Long categoryId, Long platformId, String taskSubType,
|
||||||
Long viewerDeptId) {
|
Long viewerDeptId) {
|
||||||
Page<TaskItem> pageParam = new Page<>(page, pageSize);
|
Page<TaskItem> pageParam = new Page<>(page, pageSize);
|
||||||
List<com.designhub.entity.DemandType> allDemandTypes = demandTypeMapper.selectList(null);
|
IPage<TaskItem> result;
|
||||||
Map<Long, com.designhub.entity.DemandType> demandTypeMap = allDemandTypes.stream()
|
|
||||||
.collect(java.util.stream.Collectors.toMap(com.designhub.entity.DemandType::getId, dt -> dt));
|
// 如果没有指定筛选部门,直接查询
|
||||||
|
if (filterDeptId == null) {
|
||||||
List<Long> viewerAllowedTaskTypeIds = resolveViewerAllowedTaskTypeIds(viewerDeptId, allDemandTypes, demandTypeMap);
|
result = taskItemMapper.selectAvailableItemsWithFilters(pageParam, taskTypeId, keyword, brandId, categoryId, platformId, taskSubType, null);
|
||||||
List<Long> effectiveTaskTypeIds = viewerAllowedTaskTypeIds;
|
} else {
|
||||||
|
// 🔥 获取筛选部门及其所有子部门的ID列表
|
||||||
if (filterDeptId != null) {
|
|
||||||
Set<Long> filterDeptAndChildIds = getDeptAndChildIds(filterDeptId);
|
Set<Long> filterDeptAndChildIds = getDeptAndChildIds(filterDeptId);
|
||||||
log.debug("筛选部门ID: {}, 包含子部门: {}", filterDeptId, filterDeptAndChildIds);
|
log.debug("筛选部门ID: {}, 包含子部门: {}", filterDeptId, filterDeptAndChildIds);
|
||||||
|
|
||||||
|
// 获取该部门可接单的任务类型ID列表
|
||||||
|
List<com.designhub.entity.DemandType> allDemandTypes = demandTypeMapper.selectList(null);
|
||||||
|
Map<Long, com.designhub.entity.DemandType> demandTypeMap = allDemandTypes.stream()
|
||||||
|
.collect(java.util.stream.Collectors.toMap(com.designhub.entity.DemandType::getId, dt -> dt));
|
||||||
|
|
||||||
List<Long> filterDeptAllowedTypeIds = allDemandTypes.stream()
|
List<Long> filterDeptAllowedTypeIds = allDemandTypes.stream()
|
||||||
.filter(dt -> {
|
.filter(dt -> {
|
||||||
String allowedDepts = dt.getAllowedDeptIds();
|
String allowedDepts = dt.getAllowedDeptIds();
|
||||||
@ -126,6 +130,7 @@ public class TaskItemService {
|
|||||||
allowedDepts = parentType.getAllowedDeptIds();
|
allowedDepts = parentType.getAllowedDeptIds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 只筛选明确指定了该部门(或其子部门)的任务类型
|
||||||
if (allowedDepts == null || allowedDepts.isEmpty()) {
|
if (allowedDepts == null || allowedDepts.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -133,41 +138,17 @@ public class TaskItemService {
|
|||||||
})
|
})
|
||||||
.map(com.designhub.entity.DemandType::getId)
|
.map(com.designhub.entity.DemandType::getId)
|
||||||
.collect(java.util.stream.Collectors.toList());
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
log.debug("匹配的任务类型ID: {}", filterDeptAllowedTypeIds);
|
log.debug("匹配的任务类型ID: {}", filterDeptAllowedTypeIds);
|
||||||
|
|
||||||
|
// 如果没有找到匹配的任务类型,返回空结果
|
||||||
if (filterDeptAllowedTypeIds.isEmpty()) {
|
if (filterDeptAllowedTypeIds.isEmpty()) {
|
||||||
return new Page<>(page, pageSize);
|
return new Page<>(page, pageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectiveTaskTypeIds != null) {
|
// 查询并筛选
|
||||||
effectiveTaskTypeIds = effectiveTaskTypeIds.stream()
|
result = taskItemMapper.selectAvailableItemsWithFilters(pageParam, taskTypeId, keyword, brandId, categoryId, platformId, taskSubType, filterDeptAllowedTypeIds);
|
||||||
.filter(filterDeptAllowedTypeIds::contains)
|
|
||||||
.collect(java.util.stream.Collectors.toList());
|
|
||||||
} else {
|
|
||||||
effectiveTaskTypeIds = filterDeptAllowedTypeIds;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectiveTaskTypeIds != null && effectiveTaskTypeIds.isEmpty()) {
|
|
||||||
return new Page<>(page, pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Long> visibleReceiverDeptIds = viewerDeptId != null
|
|
||||||
? getVisibleReceiverDeptIds(viewerDeptId)
|
|
||||||
: (filterDeptId != null ? getVisibleReceiverDeptIds(filterDeptId) : null);
|
|
||||||
|
|
||||||
IPage<TaskItem> result = taskItemMapper.selectAvailableItemsWithFilters(
|
|
||||||
pageParam,
|
|
||||||
taskTypeId,
|
|
||||||
keyword,
|
|
||||||
brandId,
|
|
||||||
categoryId,
|
|
||||||
platformId,
|
|
||||||
taskSubType,
|
|
||||||
effectiveTaskTypeIds,
|
|
||||||
visibleReceiverDeptIds
|
|
||||||
);
|
|
||||||
|
|
||||||
// 🔥 填充排队状态信息
|
// 🔥 填充排队状态信息
|
||||||
if (result.getRecords() != null && !result.getRecords().isEmpty()) {
|
if (result.getRecords() != null && !result.getRecords().isEmpty()) {
|
||||||
@ -275,57 +256,6 @@ public class TaskItemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> resolveViewerAllowedTaskTypeIds(Long viewerDeptId,
|
|
||||||
List<com.designhub.entity.DemandType> allDemandTypes,
|
|
||||||
Map<Long, com.designhub.entity.DemandType> demandTypeMap) {
|
|
||||||
if (viewerDeptId == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return allDemandTypes.stream()
|
|
||||||
.filter(dt -> {
|
|
||||||
String allowedDepts = dt.getAllowedDeptIds();
|
|
||||||
if ((allowedDepts == null || allowedDepts.isEmpty()) && dt.getParentId() != null) {
|
|
||||||
com.designhub.entity.DemandType parentType = demandTypeMap.get(dt.getParentId());
|
|
||||||
if (parentType != null) {
|
|
||||||
allowedDepts = parentType.getAllowedDeptIds();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowedDepts == null || allowedDepts.isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return expandAllowedDeptIds(allowedDepts).contains(viewerDeptId);
|
|
||||||
})
|
|
||||||
.map(com.designhub.entity.DemandType::getId)
|
|
||||||
.collect(java.util.stream.Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Long> getVisibleReceiverDeptIds(Long viewerDeptId) {
|
|
||||||
if (viewerDeptId == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
java.util.LinkedHashSet<Long> visibleDeptIds = new java.util.LinkedHashSet<>();
|
|
||||||
Long currentDeptId = viewerDeptId;
|
|
||||||
while (currentDeptId != null) {
|
|
||||||
visibleDeptIds.add(currentDeptId);
|
|
||||||
com.designhub.entity.Department currentDept = departmentMapper.selectById(currentDeptId);
|
|
||||||
if (currentDept == null || currentDept.getParentId() == null
|
|
||||||
|| currentDeptId.equals(currentDept.getParentId())) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
currentDeptId = currentDept.getParentId();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSharedGrabDept(viewerDeptId, GRAPHIC_VISUAL_DEPT_ID)) {
|
|
||||||
visibleDeptIds.add(GRAPHIC_VISUAL_DEPT_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new java.util.ArrayList<>(visibleDeptIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断用户部门是否属于目标部门(含目标部门的子部门)
|
* 判断用户部门是否属于目标部门(含目标部门的子部门)
|
||||||
*/
|
*/
|
||||||
@ -585,8 +515,8 @@ public class TaskItemService {
|
|||||||
* 抢单子任务
|
* 抢单子任务
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void grabItem(Long itemId, Long userId, Long actingDeptId) {
|
public void grabItem(Long itemId, Long userId) {
|
||||||
log.info("设计师 {} 抢单子任务 {},当前切换部门: {}", userId, itemId, actingDeptId);
|
log.info("设计师 {} 抢单子任务 {}", userId, itemId);
|
||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
var user = userService.getUserById(userId);
|
var user = userService.getUserById(userId);
|
||||||
@ -602,20 +532,15 @@ public class TaskItemService {
|
|||||||
|
|
||||||
// 检查是否是管理员(管理员可以抢单,绕过所有限制)
|
// 检查是否是管理员(管理员可以抢单,绕过所有限制)
|
||||||
boolean isAdmin = user.getIsAdmin() != null && user.getIsAdmin() == 1;
|
boolean isAdmin = user.getIsAdmin() != null && user.getIsAdmin() == 1;
|
||||||
Long deptId = user.getDeptId();
|
|
||||||
if (actingDeptId != null && !isAdmin) {
|
|
||||||
com.designhub.entity.Department actingDepartment = userService.resolveReceivingDepartmentForAction(userId, actingDeptId);
|
|
||||||
deptId = actingDepartment.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 非管理员需要进行权限验证
|
// 非管理员需要进行权限验证
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
// 验证用户部门权限
|
// 验证用户部门权限
|
||||||
if (deptId == null) {
|
if (user.getDeptId() == null) {
|
||||||
throw new BusinessException(ResultCode.FORBIDDEN, "您未分配部门,无法接单");
|
throw new BusinessException(ResultCode.FORBIDDEN, "您未分配部门,无法接单");
|
||||||
}
|
}
|
||||||
|
|
||||||
com.designhub.entity.Department department = departmentMapper.selectById(deptId);
|
com.designhub.entity.Department department = departmentMapper.selectById(user.getDeptId());
|
||||||
if (department == null) {
|
if (department == null) {
|
||||||
throw new BusinessException(ResultCode.FORBIDDEN, "未找到用户所属部门,请联系管理员");
|
throw new BusinessException(ResultCode.FORBIDDEN, "未找到用户所属部门,请联系管理员");
|
||||||
}
|
}
|
||||||
@ -632,7 +557,7 @@ public class TaskItemService {
|
|||||||
|
|
||||||
// 检查3:如果子任务已指定接单部门,则仅允许该部门(含子部门)成员接单
|
// 检查3:如果子任务已指定接单部门,则仅允许该部门(含子部门)成员接单
|
||||||
if (item.getReceiverDeptId() != null
|
if (item.getReceiverDeptId() != null
|
||||||
&& !isDeptMatchedOrInherited(deptId, item.getReceiverDeptId())) {
|
&& !isDeptMatchedOrInherited(user.getDeptId(), item.getReceiverDeptId())) {
|
||||||
throw new BusinessException(ResultCode.FORBIDDEN, "该任务仅允许指定接单部门成员接单");
|
throw new BusinessException(ResultCode.FORBIDDEN, "该任务仅允许指定接单部门成员接单");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,7 +579,7 @@ public class TaskItemService {
|
|||||||
// 检查用户部门或其父部门是否在允许列表中(子部门继承父部门权限)
|
// 检查用户部门或其父部门是否在允许列表中(子部门继承父部门权限)
|
||||||
String[] allowedIds = allowedDeptIds.split(",");
|
String[] allowedIds = allowedDeptIds.split(",");
|
||||||
Set<Long> allowedDeptIdSet = new HashSet<>();
|
Set<Long> allowedDeptIdSet = new HashSet<>();
|
||||||
for (String allowedId : allowedIds) {
|
for (String allowedId : allowedIds) {
|
||||||
try {
|
try {
|
||||||
allowedDeptIdSet.add(Long.parseLong(allowedId.trim()));
|
allowedDeptIdSet.add(Long.parseLong(allowedId.trim()));
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
@ -664,12 +589,12 @@ public class TaskItemService {
|
|||||||
|
|
||||||
// 获取用户部门及其所有父部门ID
|
// 获取用户部门及其所有父部门ID
|
||||||
boolean isAllowed = false;
|
boolean isAllowed = false;
|
||||||
Long currentDeptId = deptId;
|
Long currentDeptId = user.getDeptId();
|
||||||
while (currentDeptId != null) {
|
while (currentDeptId != null) {
|
||||||
if (allowedDeptIdSet.contains(currentDeptId)) {
|
if (allowedDeptIdSet.contains(currentDeptId)) {
|
||||||
isAllowed = true;
|
isAllowed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// 向上查找父部门
|
// 向上查找父部门
|
||||||
com.designhub.entity.Department currentDept = departmentMapper.selectById(currentDeptId);
|
com.designhub.entity.Department currentDept = departmentMapper.selectById(currentDeptId);
|
||||||
if (currentDept != null && currentDept.getParentId() != null) {
|
if (currentDept != null && currentDept.getParentId() != null) {
|
||||||
@ -679,8 +604,8 @@ public class TaskItemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAllowed) {
|
if (!isAllowed) {
|
||||||
throw new BusinessException(ResultCode.FORBIDDEN, "您的部门无权接收此类型的任务");
|
throw new BusinessException(ResultCode.FORBIDDEN, "您的部门无权接收此类型的任务");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -704,9 +629,9 @@ public class TaskItemService {
|
|||||||
|
|
||||||
if (!"assigned".equals(releaseType)) {
|
if (!"assigned".equals(releaseType)) {
|
||||||
// 非指定任务,检查是否可抢单
|
// 非指定任务,检查是否可抢单
|
||||||
Long targetDeptId = resolveApplicableQueueDeptId(item, deptId);
|
Long targetDeptId = resolveApplicableQueueDeptId(item, user.getDeptId());
|
||||||
if (targetDeptId == null) {
|
if (targetDeptId == null) {
|
||||||
targetDeptId = item.getReceiverDeptId() != null ? item.getReceiverDeptId() : deptId;
|
targetDeptId = item.getReceiverDeptId() != null ? item.getReceiverDeptId() : user.getDeptId();
|
||||||
}
|
}
|
||||||
if (!taskUnlockService.canGrab(itemId, targetDeptId, releaseType)) {
|
if (!taskUnlockService.canGrab(itemId, targetDeptId, releaseType)) {
|
||||||
throw new BusinessException(ResultCode.TASK_STATUS_ERROR, "该任务正在排队中,暂不可接单");
|
throw new BusinessException(ResultCode.TASK_STATUS_ERROR, "该任务正在排队中,暂不可接单");
|
||||||
@ -750,7 +675,7 @@ public class TaskItemService {
|
|||||||
result = taskItemMapper.grabAssignedItem(itemId, userId, user.getRealName(), deadline);
|
result = taskItemMapper.grabAssignedItem(itemId, userId, user.getRealName(), deadline);
|
||||||
} else {
|
} else {
|
||||||
// 普通任务:乐观锁抢单(同时设置接单部门ID和deadline)
|
// 普通任务:乐观锁抢单(同时设置接单部门ID和deadline)
|
||||||
result = taskItemMapper.grabItem(itemId, userId, user.getRealName(), deptId, deadline);
|
result = taskItemMapper.grabItem(itemId, userId, user.getRealName(), user.getDeptId(), deadline);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
@ -803,9 +728,9 @@ public class TaskItemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 🔥 任务被抢单后,检查并补充解锁下一批任务
|
// 🔥 任务被抢单后,检查并补充解锁下一批任务
|
||||||
Long grabberDeptId = deptId;
|
Long grabberDeptId = user.getDeptId();
|
||||||
if (!isAssignedItem && !"assigned".equals(releaseType)) {
|
if (!isAssignedItem && !"assigned".equals(releaseType)) {
|
||||||
Long queueDeptId = resolveApplicableQueueDeptId(item, deptId);
|
Long queueDeptId = resolveApplicableQueueDeptId(item, user.getDeptId());
|
||||||
if (queueDeptId != null) {
|
if (queueDeptId != null) {
|
||||||
grabberDeptId = queueDeptId;
|
grabberDeptId = queueDeptId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2437,8 +2437,8 @@ public class TaskService {
|
|||||||
* 抢单
|
* 抢单
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void grabTask(Long taskId, Long userId, Long actingDeptId) {
|
public void grabTask(Long taskId, Long userId) {
|
||||||
log.info("用户 {} 抢单任务 {},当前切换部门: {}", userId, taskId, actingDeptId);
|
log.info("用户 {} 抢单任务 {}", userId, taskId);
|
||||||
|
|
||||||
Task task = getTaskById(taskId);
|
Task task = getTaskById(taskId);
|
||||||
|
|
||||||
@ -2462,10 +2462,6 @@ public class TaskService {
|
|||||||
boolean isAdmin = isAdminUser(userId);
|
boolean isAdmin = isAdminUser(userId);
|
||||||
|
|
||||||
Long deptId = user.getDeptId();
|
Long deptId = user.getDeptId();
|
||||||
if (actingDeptId != null && !isAdmin) {
|
|
||||||
Department actingDepartment = userService.resolveReceivingDepartmentForAction(userId, actingDeptId);
|
|
||||||
deptId = actingDepartment.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 非管理员需要进行权限验证
|
// 非管理员需要进行权限验证
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
|
|||||||
@ -1351,108 +1351,6 @@ public class UserService {
|
|||||||
}
|
}
|
||||||
return departmentMapper.selectBatchIds(deptIds);
|
return departmentMapper.selectBatchIds(deptIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户当前可切换的部门视角
|
|
||||||
* - 用户挂载的全部部门
|
|
||||||
* - 用户主部门
|
|
||||||
* - 负责人管理的部门
|
|
||||||
* - 一级需求负责人可切换其子需求部门
|
|
||||||
*/
|
|
||||||
public List<Department> getUserAccessibleDepartments(Long userId) {
|
|
||||||
if (userId == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
java.util.LinkedHashMap<Long, Department> departmentMap = new java.util.LinkedHashMap<>();
|
|
||||||
|
|
||||||
User user = getUserById(userId);
|
|
||||||
if (user != null && user.getDeptId() != null) {
|
|
||||||
Department primaryDept = departmentMapper.selectById(user.getDeptId());
|
|
||||||
if (isActiveDepartment(primaryDept)) {
|
|
||||||
departmentMap.put(primaryDept.getId(), primaryDept);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Department department : getUserDepartments(userId)) {
|
|
||||||
if (isActiveDepartment(department)) {
|
|
||||||
departmentMap.put(department.getId(), department);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Department> leadingDepts = departmentMapper.selectList(
|
|
||||||
new LambdaQueryWrapper<Department>()
|
|
||||||
.eq(Department::getLeaderId, userId)
|
|
||||||
.eq(Department::getStatus, 1)
|
|
||||||
.eq(Department::getDeleted, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (Department department : leadingDepts) {
|
|
||||||
if (!isActiveDepartment(department)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
departmentMap.put(department.getId(), department);
|
|
||||||
|
|
||||||
if ("primary_demand".equals(department.getDeptType())) {
|
|
||||||
List<Department> childDepartments = departmentMapper.selectList(
|
|
||||||
new LambdaQueryWrapper<Department>()
|
|
||||||
.eq(Department::getParentId, department.getId())
|
|
||||||
.eq(Department::getStatus, 1)
|
|
||||||
.eq(Department::getDeleted, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (Department childDepartment : childDepartments) {
|
|
||||||
if (!isActiveDepartment(childDepartment)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!"demand".equals(childDepartment.getDeptType())
|
|
||||||
&& !"primary_demand".equals(childDepartment.getDeptType())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
departmentMap.put(childDepartment.getId(), childDepartment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ArrayList<>(departmentMap.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验当前切换的部门是否属于用户可访问范围
|
|
||||||
*/
|
|
||||||
public Department resolveAccessibleDepartmentForView(Long userId, Long requestedDeptId) {
|
|
||||||
if (requestedDeptId == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getUserAccessibleDepartments(userId).stream()
|
|
||||||
.filter(department -> requestedDeptId.equals(department.getId()))
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow(() -> new BusinessException(ResultCode.FORBIDDEN, "当前切换的部门不属于您,无法执行该操作"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验当前切换的部门是否可用于接单
|
|
||||||
*/
|
|
||||||
public Department resolveReceivingDepartmentForAction(Long userId, Long requestedDeptId) {
|
|
||||||
if (requestedDeptId == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Department department = resolveAccessibleDepartmentForView(userId, requestedDeptId);
|
|
||||||
if (!"receiving".equals(department.getDeptType())) {
|
|
||||||
throw new BusinessException(ResultCode.FORBIDDEN, "当前切换的部门不是接单部门,无法执行该操作");
|
|
||||||
}
|
|
||||||
return department;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isActiveDepartment(Department department) {
|
|
||||||
return department != null
|
|
||||||
&& (department.getStatus() == null || department.getStatus() == 1)
|
|
||||||
&& (department.getDeleted() == null || department.getDeleted() == 0)
|
|
||||||
&& departmentService.isDepartmentActiveWithAncestors(department.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加用户到部门(如果不存在则添加)
|
* 添加用户到部门(如果不存在则添加)
|
||||||
|
|||||||
@ -194,16 +194,6 @@ export interface MyTasksParams {
|
|||||||
sortBy?: string
|
sortBy?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildActingDeptHeaders = (actingDeptId?: number) => {
|
|
||||||
if (actingDeptId === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
'X-Dept-Id': String(actingDeptId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建任务
|
* 创建任务
|
||||||
*/
|
*/
|
||||||
@ -235,10 +225,8 @@ export const updateTask = (id: number, data: Partial<Task>) => {
|
|||||||
/**
|
/**
|
||||||
* 抢单
|
* 抢单
|
||||||
*/
|
*/
|
||||||
export const grabTask = (id: number, actingDeptId?: number) => {
|
export const grabTask = (id: number) => {
|
||||||
return request.post<any>(`/tasks/${id}/grab`, null, {
|
return request.post<any>(`/tasks/${id}/grab`)
|
||||||
headers: buildActingDeptHeaders(actingDeptId)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -285,11 +273,8 @@ export const rateTask = (id: number, rating: number, comment?: string) => {
|
|||||||
/**
|
/**
|
||||||
* 获取任务大厅
|
* 获取任务大厅
|
||||||
*/
|
*/
|
||||||
export const getTaskHall = (params: TaskHallParams, actingDeptId?: number) => {
|
export const getTaskHall = (params: TaskHallParams) => {
|
||||||
return request.get<any>('/tasks/hall', {
|
return request.get<any>('/tasks/hall', { params })
|
||||||
params,
|
|
||||||
headers: buildActingDeptHeaders(actingDeptId)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -441,11 +426,8 @@ export const getAvailableTaskItems = (params: {
|
|||||||
taskSubType?: string
|
taskSubType?: string
|
||||||
filterDeptId?: number
|
filterDeptId?: number
|
||||||
sortBy?: string
|
sortBy?: string
|
||||||
}, actingDeptId?: number) => {
|
}) => {
|
||||||
return request.get<any>('/tasks/items/available', {
|
return request.get<any>('/tasks/items/available', { params })
|
||||||
params,
|
|
||||||
headers: buildActingDeptHeaders(actingDeptId)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -489,10 +471,8 @@ export const getTaskItemById = (itemId: number) => {
|
|||||||
/**
|
/**
|
||||||
* 抢单子任务
|
* 抢单子任务
|
||||||
*/
|
*/
|
||||||
export const grabTaskItem = (itemId: number, actingDeptId?: number) => {
|
export const grabTaskItem = (itemId: number) => {
|
||||||
return request.post<any>(`/tasks/items/${itemId}/grab`, null, {
|
return request.post<any>(`/tasks/items/${itemId}/grab`)
|
||||||
headers: buildActingDeptHeaders(actingDeptId)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -3747,14 +3747,8 @@ const loadTasks = async (forceReload = false) => {
|
|||||||
|
|
||||||
// 同时加载普通任务和子任务(流水线任务)
|
// 同时加载普通任务和子任务(流水线任务)
|
||||||
const [taskResponse, itemResponse] = await Promise.all([
|
const [taskResponse, itemResponse] = await Promise.all([
|
||||||
taskApi.getTaskHall(
|
taskApi.getTaskHall(params),
|
||||||
params,
|
taskApi.getAvailableTaskItems(params)
|
||||||
currentDeptView.value !== undefined ? currentDeptView.value : undefined
|
|
||||||
),
|
|
||||||
taskApi.getAvailableTaskItems(
|
|
||||||
params,
|
|
||||||
currentDeptView.value !== undefined ? currentDeptView.value : undefined
|
|
||||||
)
|
|
||||||
])
|
])
|
||||||
|
|
||||||
// 处理普通任务(非流水线任务)
|
// 处理普通任务(非流水线任务)
|
||||||
@ -6271,7 +6265,7 @@ const canGrabTask = (task: TaskOrSubTask) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查2:需求部门不能抢单
|
// 检查2:需求部门不能抢单
|
||||||
if (currentDeptType === 'demand' || currentDeptType === 'primary_demand') {
|
if (currentDeptType === 'demand') {
|
||||||
return { canGrab: false, reason: '需求部门成员不能接单' }
|
return { canGrab: false, reason: '需求部门成员不能接单' }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6321,16 +6315,10 @@ const handleGrab = async (task: TaskOrSubTask) => {
|
|||||||
let response
|
let response
|
||||||
if (isSubTask) {
|
if (isSubTask) {
|
||||||
// 抢子任务
|
// 抢子任务
|
||||||
response = await taskApi.grabTaskItem(
|
response = await taskApi.grabTaskItem(task.itemId || task.id!)
|
||||||
task.itemId || task.id!,
|
|
||||||
currentDeptView.value !== undefined ? currentDeptView.value : undefined
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// 抢普通任务
|
// 抢普通任务
|
||||||
response = await taskApi.grabTask(
|
response = await taskApi.grabTask(task.id!)
|
||||||
task.id!,
|
|
||||||
currentDeptView.value !== undefined ? currentDeptView.value : undefined
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
@ -6379,15 +6367,9 @@ const handleGrabTask = async (task: TaskOrSubTask) => {
|
|||||||
try {
|
try {
|
||||||
let response
|
let response
|
||||||
if (isSubTask) {
|
if (isSubTask) {
|
||||||
response = await taskApi.grabTaskItem(
|
response = await taskApi.grabTaskItem(task.itemId || task.id!)
|
||||||
task.itemId || task.id!,
|
|
||||||
currentDeptView.value !== undefined ? currentDeptView.value : undefined
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
response = await taskApi.grabTask(
|
response = await taskApi.grabTask(task.id!)
|
||||||
task.id!,
|
|
||||||
currentDeptView.value !== undefined ? currentDeptView.value : undefined
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
@ -6668,10 +6650,7 @@ const loadAllTabCounts = async () => {
|
|||||||
|
|
||||||
// 1. 可接任务数量
|
// 1. 可接任务数量
|
||||||
promises.push(
|
promises.push(
|
||||||
taskApi.getTaskHall(
|
taskApi.getTaskHall({ page: 1, pageSize: 1 }).then(res => {
|
||||||
{ page: 1, pageSize: 1 },
|
|
||||||
currentDeptView.value !== undefined ? currentDeptView.value : undefined
|
|
||||||
).then(res => {
|
|
||||||
if (res.data && res.data.total !== undefined) {
|
if (res.data && res.data.total !== undefined) {
|
||||||
total.value = res.data.total
|
total.value = res.data.total
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user