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 }}
-
-
-
{
- if (newTaskTypeId && !approveTaskTypes.find(t => t.typeId === newTaskTypeId)) {
- approveTaskTypes.push({ typeId: newTaskTypeId, quantity: 1 })
- newTaskTypeId = undefined
- } else if (newTaskTypeId) {
- message.warning('该任务类型已添加')
- }
- }">
+ />
+
添加
@@ -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) {