import type { ProductionWorkOrderItem } from '@/api/production-work-order' import { fetchProductionWorkOrderDetail } from '@/api/production-work-order' import { fetchMyProductionTasks } from '@/api/production-task' import type { ProductionWorkOrderTabKey } from '@/utils/production-work-order-tabs' import { resolveTabKeyFromWorkOrder, getProductionWorkOrderTab, toWorkOrderListQuery, isAllProductionWorkOrderTab } from '@/utils/production-work-order-tabs' import { toAllTabListQuery, workOrderMatchesCategory } from '@/utils/production-work-order-category' import { matchesWorkOrderStatusFilter } from '@/utils/status-tag-registry' import { computeWorkOrderPlannedStartTimeRange } from '@/utils/production-labels' export type ProductionTaskMineFilters = { keyword?: string taskStatus?: string productionCategory?: string tabKey: ProductionWorkOrderTabKey excludeVoidProtocol?: boolean plannedStartTimeStart?: string plannedStartTimeEnd?: string } export type MineWorkOrderSearchFilters = { keyword?: string workOrderStatus?: string | string[] productionCategory?: string tabKey: ProductionWorkOrderTabKey excludeVoidProtocol?: boolean } export type ProductionTaskRow = Record export type MineWorkOrderEntry = { workOrderId: string workOrder: ProductionWorkOrderItem tabKey: ProductionWorkOrderTabKey tasks: ProductionTaskRow[] } const MINE_TASK_FETCH_PAGE_SIZE = 100 function keywordMatchesWorkOrder( row: ProductionWorkOrderItem, keyword: string, tabKey: ProductionWorkOrderTabKey ): boolean { const kw = keyword.trim().toLowerCase() if (!kw) return true const tab = getProductionWorkOrderTab(tabKey)! const fields = tabKey === 'temporary' ? [row.remark] : tabKey === 'outbound_basic_experiment' ? [ row.workOrderNo, row.applicationNo, row.projectTitle, row.customerName, row.applicationName ] : tab.group === 'outbound' ? [row.workOrderNo, row.applicationNo, row.applicationName, row.patientName] : [row.workOrderNo, row.sampleCode, row.labStorageCode, row.motherName, row.newbornName] return fields.some((f) => (f || '').toLowerCase().includes(kw)) } export function resolveWorkOrderTabKey(task: ProductionTaskRow): ProductionWorkOrderTabKey { return resolveTabKeyFromWorkOrder({ workOrderType: task.workOrderType || task.orderSource, receptionSource: task.receptionSource, bizType: task.bizType }) } export function buildWorkOrderFromTasks(tasks: ProductionTaskRow[]): ProductionWorkOrderItem { const t = tasks[0] const tabKey = resolveWorkOrderTabKey(t) const tab = getProductionWorkOrderTab(tabKey)! return { id: t.workOrderId, workOrderNo: t.workOrderNo || '—', workOrderType: tab.workOrderType, workOrderStatus: t.workOrderStatus || '', protocolNo: t.protocolNo || '', sampleCode: t.sampleCode || '', receptionSource: t.receptionSource, receptionSourceLabel: t.receptionSourceLabel, protocolStatus: t.protocolStatus, bizType: tab.group === 'outbound' ? t.bizType : undefined, bizTypeLabel: tab.group === 'outbound' ? t.bizTypeLabel : undefined, applicationNo: t.applicationNo, applicationName: t.applicationName, channelName: t.channelName, projectTitle: t.projectTitle, customerName: t.customerName, patientName: t.patientName, sortNo: t.sortNo, totalCourseCount: t.totalCourseCount, infusionTime: t.infusionTime, sampleTypeName: t.sampleTypeName, handlerName: t.handlerName, receptionTime: t.receptionTime, labStorageCode: t.labStorageCode, motherName: t.motherName, newbornName: t.newbornName, remark: t.workOrderRemark || t.remark, createTime: t.workOrderCreateTime || t.createTime || '' } } export function groupMineTasksByWorkOrder(tasks: ProductionTaskRow[]): MineWorkOrderEntry[] { const map = new Map() const order: string[] = [] for (const row of tasks) { const key = row.workOrderId || row.workOrderNo || row.id if (!map.has(key)) { map.set(key, []) order.push(key) } map.get(key)!.push(row) } return order.map((workOrderId) => { const groupTasks = map.get(workOrderId)! return { workOrderId, workOrder: buildWorkOrderFromTasks(groupTasks), tabKey: resolveWorkOrderTabKey(groupTasks[0]), tasks: groupTasks } }) } export function buildPresetTasksMap( entries: MineWorkOrderEntry[] ): Record { const map: Record = {} for (const entry of entries) { map[entry.workOrder.id] = entry.tasks } return map } async function fetchMineTasksByScope( scope: 'current' | 'history', filters: ProductionTaskMineFilters ): Promise { const tab = getProductionWorkOrderTab(filters.tabKey)! const listQuery = isAllProductionWorkOrderTab(filters.tabKey) ? toAllTabListQuery(filters.productionCategory || '') : toWorkOrderListQuery(tab) const pageSize = MINE_TASK_FETCH_PAGE_SIZE let page = 1 const all: ProductionTaskRow[] = [] let total = 0 while (true) { const res = await fetchMyProductionTasks({ scope, page, pageSize, keyword: filters.keyword || undefined, taskStatus: filters.taskStatus || undefined, workOrderType: listQuery.workOrderType, receptionSource: listQuery.receptionSource, bizType: listQuery.bizType, includeStepSummary: true, excludeVoidProtocol: filters.excludeVoidProtocol, plannedStartTimeStart: filters.plannedStartTimeStart, plannedStartTimeEnd: filters.plannedStartTimeEnd }) const list = res.list || [] all.push(...list) total = res.total || 0 if (!list.length || all.length >= total) break page += 1 } return all } /** 合并当前负责人任务与曾转发任务(方案 C:单列表) */ export async function fetchAllMineProductionTasks( filters: ProductionTaskMineFilters ): Promise { const [current, history] = await Promise.all([ fetchMineTasksByScope('current', filters), fetchMineTasksByScope('history', filters) ]) const map = new Map() for (const row of [...current, ...history]) { if (row.id) map.set(row.id, row) } return [...map.values()] } export async function enrichMineEntriesWithWorkOrders( entries: MineWorkOrderEntry[] ): Promise { const cache = new Map() const uniqueIds = [...new Set(entries.map((entry) => entry.workOrderId))] await Promise.all( uniqueIds.map(async (id) => { try { const detail = await fetchProductionWorkOrderDetail(id) cache.set(id, detail) } catch { // 保留任务聚合的工单摘要 } }) ) return entries.map((entry) => { const detail = cache.get(entry.workOrderId) if (!detail) return entry return { ...entry, workOrder: { ...entry.workOrder, ...detail, paymentSummary: detail.paymentSummary ?? entry.workOrder.paymentSummary, feeSummary: detail.feeSummary ?? entry.workOrder.feeSummary }, tabKey: resolveTabKeyFromWorkOrder(detail) } }) } export function filterMineEntriesByWorkOrderSearch( entries: MineWorkOrderEntry[], filters: MineWorkOrderSearchFilters ): MineWorkOrderEntry[] { const tabKey = filters.tabKey return entries.filter((entry) => { const row = entry.workOrder if (!isAllProductionWorkOrderTab(tabKey) && resolveTabKeyFromWorkOrder(row) !== tabKey) { return false } if ( isAllProductionWorkOrderTab(tabKey) && !workOrderMatchesCategory(row, filters.productionCategory || '') ) { return false } if (!isAllProductionWorkOrderTab(tabKey) && entry.tabKey !== tabKey) return false if (!matchesWorkOrderStatusFilter(row.workOrderStatus, filters.workOrderStatus)) return false const keywordTabKey = isAllProductionWorkOrderTab(tabKey) ? resolveTabKeyFromWorkOrder(row) : tabKey if (!keywordMatchesWorkOrder(row, filters.keyword || '', keywordTabKey)) return false return true }) } export function paginateMineEntries(items: T[], page: number, pageSize: number) { const safePage = Math.max(1, page) const safeSize = Math.max(1, pageSize) const start = (safePage - 1) * safeSize return { total: items.length, items: items.slice(start, start + safeSize) } } export function buildMineTableRows(pageEntries: MineWorkOrderEntry[]): { rows: ProductionWorkOrderItem[] presetTasksByWorkOrderId: Record } { return { rows: pageEntries.map((e) => ({ ...e.workOrder, plannedStartTimeRange: computeWorkOrderPlannedStartTimeRange(e.tasks) })), presetTasksByWorkOrderId: buildPresetTasksMap(pageEntries) } }