diff --git a/backend/src/main/java/com/designhub/controller/TaskController.java b/backend/src/main/java/com/designhub/controller/TaskController.java index 46f58c9..4539723 100644 --- a/backend/src/main/java/com/designhub/controller/TaskController.java +++ b/backend/src/main/java/com/designhub/controller/TaskController.java @@ -257,6 +257,7 @@ public class TaskController { @Parameter(description = "发布人姓名") @RequestParam(required = false) String publisherName, @Parameter(description = "发布时间范围:today/week/month") @RequestParam(required = false) String timeRange, @Parameter(description = "排序方式:latest/score/deadline/hot") @RequestParam(required = false) String sortBy, + @Parameter(description = "筛选可接单部门ID") @RequestParam(required = false) Long filterDeptId, @Parameter(description = "页码") @RequestParam(defaultValue = "1") Integer page, @Parameter(description = "每页数量") @RequestParam(defaultValue = "20") Integer pageSize, @RequestHeader("Authorization") String authHeader) { @@ -268,13 +269,13 @@ public class TaskController { log.info("查询任务大厅: taskTypeId={}, demandTypeId={}, brandId={}, categoryId={}, platformId={}, " + "taskSubType={}, minScore={}, maxScore={}, keyword={}, publisherName={}, timeRange={}, " + - "sortBy={}, page={}, pageSize={}, userDeptId={}", + "sortBy={}, filterDeptId={}, page={}, pageSize={}, userDeptId={}", taskTypeId, demandTypeId, brandId, categoryId, platformId, taskSubType, - minScore, maxScore, keyword, publisherName, timeRange, sortBy, page, pageSize, userDeptId); + minScore, maxScore, keyword, publisherName, timeRange, sortBy, filterDeptId, page, pageSize, userDeptId); IPage taskPage = taskService.getTaskHall(page, pageSize, taskTypeId, demandTypeId, brandId, categoryId, platformId, taskSubType, minScore, maxScore, keyword, - publisherName, timeRange, sortBy, userDeptId); + publisherName, timeRange, sortBy, userDeptId, filterDeptId); return Result.success(taskPage); } diff --git a/backend/src/main/java/com/designhub/service/TaskService.java b/backend/src/main/java/com/designhub/service/TaskService.java index 90cc828..a4eb834 100644 --- a/backend/src/main/java/com/designhub/service/TaskService.java +++ b/backend/src/main/java/com/designhub/service/TaskService.java @@ -1022,21 +1022,22 @@ public class TaskService { /** * 获取任务大厅(根据用户部门筛选可接单的任务) + * @param filterDeptId 筛选只显示该部门可接单的任务(可选) */ public IPage getTaskHall(Integer page, Integer pageSize, Long taskTypeId, Long demandTypeId, Long brandId, Long categoryId, Long platformId, String taskSubType, Integer minScore, Integer maxScore, String keyword, String publisherName, - String timeRange, String sortBy, Long userDeptId) { + String timeRange, String sortBy, Long userDeptId, Long filterDeptId) { Page pageParam = new Page<>(page, pageSize); + List allDemandTypes = demandTypeMapper.selectList(null); + // 构建ID到DemandType的映射,用于快速查找父级 + Map demandTypeMap = allDemandTypes.stream() + .collect(Collectors.toMap(DemandType::getId, dt -> dt)); + // 获取当前用户部门可以接单的任务类型ID列表(支持三级分类继承二级分类的配置) List allowedTaskTypeIds = null; if (userDeptId != null) { - List allDemandTypes = demandTypeMapper.selectList(null); - // 构建ID到DemandType的映射,用于快速查找父级 - Map demandTypeMap = allDemandTypes.stream() - .collect(Collectors.toMap(DemandType::getId, dt -> dt)); - allowedTaskTypeIds = allDemandTypes.stream() .filter(dt -> { // 获取允许的部门ID(支持继承) @@ -1066,9 +1067,46 @@ public class TaskService { .collect(Collectors.toList()); } + // 🔥 如果指定了筛选部门,进一步过滤只显示该部门可接单的任务类型 + List filteredTaskTypeIds = allowedTaskTypeIds; + if (filterDeptId != null) { + List filterDeptAllowedIds = allDemandTypes.stream() + .filter(dt -> { + String allowedDepts = dt.getAllowedDeptIds(); + if ((allowedDepts == null || allowedDepts.isEmpty()) && dt.getParentId() != null) { + DemandType parentType = demandTypeMap.get(dt.getParentId()); + if (parentType != null) { + allowedDepts = parentType.getAllowedDeptIds(); + } + } + // 只筛选明确指定了该部门的任务类型(不包括所有部门可接单的) + if (allowedDepts == null || allowedDepts.isEmpty()) { + return false; // 所有部门都可接单的不纳入筛选结果 + } + String[] deptIds = allowedDepts.split(","); + for (String deptId : deptIds) { + if (deptId.trim().equals(String.valueOf(filterDeptId))) { + return true; + } + } + return false; + }) + .map(DemandType::getId) + .collect(Collectors.toList()); + + // 取交集:用户可接单的 ∩ 筛选部门可接单的 + if (allowedTaskTypeIds != null) { + filteredTaskTypeIds = allowedTaskTypeIds.stream() + .filter(filterDeptAllowedIds::contains) + .collect(Collectors.toList()); + } else { + filteredTaskTypeIds = filterDeptAllowedIds; + } + } + return taskMapper.selectTaskHallByDept(pageParam, taskTypeId, demandTypeId, brandId, categoryId, platformId, taskSubType, minScore, maxScore, keyword, - publisherName, timeRange, sortBy, allowedTaskTypeIds); + publisherName, timeRange, sortBy, filteredTaskTypeIds); } /** diff --git a/frontend/src/views/TaskHall.vue b/frontend/src/views/TaskHall.vue index 4eb862a..c1ea6bb 100644 --- a/frontend/src/views/TaskHall.vue +++ b/frontend/src/views/TaskHall.vue @@ -176,6 +176,23 @@ + + + + {{ dept.deptName }} + + + + +
+ 可接单部门: + + + {{ deptName }} + + +
+
任务类型明细
@@ -2598,6 +2630,7 @@ import * as taskApi from '@/api/task' import * as userApi from '@/api/user' import * as configApi from '@/api/config' import * as authApi from '@/api/auth' +import * as departmentApi from '@/api/department' import { getWorkHoursConfig } from '@/api/system' import type { Task, TaskApprovalDTO, TaskProduct } from '@/api/task' import type { DesignerWithWorkload } from '@/api/user' @@ -2829,6 +2862,9 @@ const workHoursPerDay = ref(9) // 默认9小时 // 层级任务类型数据(用于级联选择器) const hierarchicalTaskTypes = ref([]) +// 🔥 接单部门列表(用于筛选和显示标签) +const receivingDeptList = ref>([]) + // 递归查找任务类型(从层级数据中查找,支持三级分类) const findTaskTypeById = (id: number, items: any[] = hierarchicalTaskTypes.value): any => { for (const item of items) { @@ -2860,6 +2896,42 @@ const getTaskTypeFullPath = (id: number, items: any[] = hierarchicalTaskTypes.va return null } +// 🔥 获取任务可接单部门名称列表 +const getTaskAllowedDeptNames = (task: any): string[] => { + if (!task) return [] + + // 优先从任务类型配置中获取 + const taskTypeId = task.taskTypeId + if (!taskTypeId) return [] + + // 从层级任务类型数据中查找 + const taskType = findTaskTypeById(taskTypeId) + if (!taskType) return [] + + // 获取 allowedDeptIds(支持从父级继承) + let allowedDeptIds = taskType.allowedDeptIds + if ((!allowedDeptIds || allowedDeptIds.trim() === '') && taskType.parentId) { + const parentType = findTaskTypeById(taskType.parentId) + if (parentType) { + allowedDeptIds = parentType.allowedDeptIds + } + } + + // 如果为空,表示所有接单部门都可以接单 + if (!allowedDeptIds || allowedDeptIds.trim() === '') { + return ['全部接单部门'] + } + + // 将部门ID转换为部门名称 + const deptIds = allowedDeptIds.split(',').map((id: string) => parseInt(id.trim())) + const deptNames = deptIds.map((id: number) => { + const dept = receivingDeptList.value.find(d => d.id === id) + return dept ? dept.deptName : `部门${id}` + }) + + return deptNames.filter((name: string) => name) +} + // 构建级联选择器选项 const taskTypeCascaderOptions = computed(() => { const buildOptions = (items: any[]): any[] => { @@ -2891,7 +2963,8 @@ const filters = reactive({ keyword: undefined as string | undefined, publisherName: undefined as string | undefined, timeRange: undefined as 'today' | 'week' | 'month' | undefined, - sortBy: 'latest' as 'latest' | 'score' | 'deadline' | 'hot' + sortBy: 'latest' as 'latest' | 'score' | 'deadline' | 'hot', + filterDeptId: undefined as number | undefined // 🔥 按接单部门筛选 }) // 已完成任务筛选条件 @@ -3249,6 +3322,20 @@ const loadConfigs = async () => { if (response && response.data) { hierarchicalTaskTypes.value = response.data } + // 🔥 加载接单部门列表 + const deptResponse = await departmentApi.getDepartmentList() + if (deptResponse && deptResponse.data) { + // 过滤出接单部门(deptType === 'receiving'),只保留一级和二级部门 + const allDepts = deptResponse.data + const level1DeptIds = new Set( + allDepts.filter((d: any) => d.deptType === 'receiving' && (!d.parentId || d.parentId === 0)) + .map((d: any) => d.id) + ) + receivingDeptList.value = allDepts.filter((d: any) => + d.deptType === 'receiving' && + (!d.parentId || d.parentId === 0 || level1DeptIds.has(d.parentId)) + ) + } } catch (error) { console.error('加载配置数据失败:', error) } @@ -3303,6 +3390,7 @@ const loadTasks = async (forceReload = false) => { if (filters.publisherName) params.publisherName = filters.publisherName.trim() if (filters.timeRange) params.timeRange = filters.timeRange if (filters.sortBy) params.sortBy = filters.sortBy + if (filters.filterDeptId) params.filterDeptId = filters.filterDeptId // 🔥 按接单部门筛选 let allTasks: any[] = [] @@ -6512,6 +6600,37 @@ onUnmounted(() => { } } +// 🔥 可接单部门标签样式 +.allowed-depts-section { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: $space-xs; + margin-bottom: $space-md; + padding: $space-xs $space-sm; + background: rgba(#1890ff, 0.08); + border-radius: 6px; + + .allowed-depts-label { + font-size: $font-size-xs; + color: $text-tertiary; + white-space: nowrap; + } + + .allowed-depts-tags { + display: flex; + flex-wrap: wrap; + gap: 4px; + + :deep(.ant-tag) { + margin: 0; + font-size: $font-size-xs; + line-height: 18px; + padding: 0 6px; + } + } +} + // 任务详情 .task-details { display: grid;