From c7fbcb2b56fbae27a3ad8bc386d6d0702a5c1f99 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 7 Jan 2026 11:51:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8E=A5=E5=8D=95?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E5=AE=A1=E6=A0=B8=E5=BC=B9=E7=AA=97=E7=9A=84?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=B1=BB=E5=9E=8B=E5=92=8C=E6=95=B0=E9=87=8F?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 添加层级任务类型数据加载,支持递归查找三级分类 2. 修复任务类型显示为'未知类型'的问题(支持从层级数据中递归查找) 3. 修复任务数量全部显示为1的问题(从typeDetails中获取实际数量) 4. 将添加任务类型改为级联选择器(树形结构) --- frontend/src/views/TaskHall.vue | 131 +++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 27 deletions(-) diff --git a/frontend/src/views/TaskHall.vue b/frontend/src/views/TaskHall.vue index 5355f05..86a6c4e 100644 --- a/frontend/src/views/TaskHall.vue +++ b/frontend/src/views/TaskHall.vue @@ -1991,27 +1991,19 @@ - +
- - - {{ type.name }} - - - + /> + 添加
@@ -2364,6 +2356,7 @@ import DefaultLayout from '@/layouts/DefaultLayout.vue' import Icon from '@/components/Icon.vue' import * as taskApi from '@/api/task' import * as userApi from '@/api/user' +import * as configApi from '@/api/config' import type { Task, TaskApprovalDTO, TaskProduct } from '@/api/task' import type { DesignerWithWorkload } from '@/api/user' import { useConfigStore } from '@/stores/config' @@ -2485,6 +2478,38 @@ const brands = computed(() => configStore.brands) const platforms = computed(() => configStore.platforms) const categories = computed(() => configStore.categories) +// 层级任务类型数据(用于级联选择器) +const hierarchicalTaskTypes = ref([]) + +// 递归查找任务类型(从层级数据中查找,支持三级分类) +const findTaskTypeById = (id: number, items: any[] = hierarchicalTaskTypes.value): any => { + for (const item of items) { + if (item.id === id) return item + if (item.children) { + const found = findTaskTypeById(id, item.children) + if (found) return found + } + } + return null +} + +// 构建级联选择器选项 +const taskTypeCascaderOptions = computed(() => { + const buildOptions = (items: any[]): any[] => { + return items.map(item => { + const option: any = { + value: item.id, + label: item.name + } + if (item.children && item.children.length > 0) { + option.children = buildOptions(item.children) + } + return option + }) + } + return buildOptions(hierarchicalTaskTypes.value) +}) + // 筛选条件 const filters = reactive({ taskTypeId: undefined as number | undefined, @@ -2573,7 +2598,10 @@ const getTaskTypeName = (typeId: number, taskTypeName?: string, taskSubType?: st if (taskSubType) return taskSubType // 如果有直接传入的类型名称,使用它 if (taskTypeName) return taskTypeName - // 从需求类型列表中查找 + // 从层级数据中递归查找(支持三级分类) + const typeInfo = findTaskTypeById(typeId) + if (typeInfo) return typeInfo.name + // 兼容:从平铺列表中查找 const type = demandTypes.value.find(t => t.id === typeId) return type?.name || '未知类型' } @@ -2592,6 +2620,10 @@ const parseTypeDetails = (typeDetails: string | TaskTypeDetail[] | undefined): T // 获取任务类型单位积分 const getTaskTypeUnitScore = (typeId: number) => { + // 从层级数据中递归查找(支持三级分类) + const typeInfo = findTaskTypeById(typeId) + if (typeInfo && typeInfo.unitScore) return typeInfo.unitScore + // 兼容:从平铺列表中查找 const type = demandTypes.value.find(t => t.id === typeId) return type?.unitScore || 0 } @@ -2714,6 +2746,11 @@ const isHighScoreTask = (task: TaskOrSubTask) => { const loadConfigs = async () => { try { await configStore.loadAllConfigs() + // 加载层级任务类型数据(用于级联选择器和递归查找) + const response = await configApi.getDemandTypesTree() + if (response && response.data) { + hierarchicalTaskTypes.value = response.data + } } catch (error) { console.error('加载配置数据失败:', error) } @@ -3024,7 +3061,30 @@ const approveAssignType = ref<'auto' | 'manual'>('auto') const approveTaskTypes = ref>([]) const approveDesignerId = ref(undefined) const designersList = ref([]) -const newTaskTypeId = ref(undefined) +const newTaskTypePath = ref<(string | number)[] | undefined>(undefined) + +// 级联选择器搜索过滤 +const cascaderFilter = (inputValue: string, path: any[]) => { + return path.some(option => + option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1 + ) +} + +// 添加审核弹窗中的任务类型 +const handleAddApproveTaskType = () => { + if (!newTaskTypePath.value || newTaskTypePath.value.length === 0) { + message.warning('请选择任务类型') + return + } + // 获取最后一个ID(即最深层级的类型ID) + const typeId = newTaskTypePath.value[newTaskTypePath.value.length - 1] as number + if (approveTaskTypes.value.find(t => t.typeId === typeId)) { + message.warning('该任务类型已添加') + return + } + approveTaskTypes.value.push({ typeId, quantity: 1 }) + newTaskTypePath.value = undefined +} // 格式化相对时间 const formatDeadlineRelative = (deadline: string) => { @@ -3067,17 +3127,34 @@ const showAssignDesignerModal = async (task: Task) => { approveTaskData.value = task approveAssignType.value = 'auto' approveDesignerId.value = undefined - newTaskTypeId.value = undefined + newTaskTypePath.value = undefined - // 解析任务类型 - const taskTypeIdsStr = task.taskTypeIds || task.taskTypeId?.toString() || '' - const taskTypeIdArray = taskTypeIdsStr.split(',').filter(id => id.trim()) + // 解析任务类型 - 优先从 typeDetails 获取(包含每个类型的实际数量) + let typeDetailsArray: TaskTypeDetail[] = [] + if ((task as any).typeDetails) { + try { + const details = (task as any).typeDetails + typeDetailsArray = typeof details === 'string' ? JSON.parse(details) : details + } catch (e) { + console.warn('解析 typeDetails 失败:', e) + } + } - // 初始化任务类型列表 - approveTaskTypes.value = taskTypeIdArray.map(id => ({ - typeId: parseInt(id.trim()), - quantity: task.quantity || 1 - })) + // 如果有 typeDetails,从中获取任务类型和数量 + if (typeDetailsArray.length > 0) { + approveTaskTypes.value = typeDetailsArray.map(detail => ({ + typeId: detail.typeId, + quantity: detail.quantity || 1 + })) + } else { + // 兼容旧数据:从 taskTypeIds 获取 + const taskTypeIdsStr = task.taskTypeIds || task.taskTypeId?.toString() || '' + const taskTypeIdArray = taskTypeIdsStr.split(',').filter(id => id.trim()) + approveTaskTypes.value = taskTypeIdArray.map(id => ({ + typeId: parseInt(id.trim()), + quantity: task.quantity || 1 + })) + } approveModalVisible.value = true } catch (error: any) {