import type { QcTask } from '../api/qc-task' export type QcTaskListLabItem = { kind: 'lab'; task: QcTask } /** 批次内全部第三方任务合一卡 */ export type QcTaskListAllThirdItem = { kind: 'all-third'; tasks: QcTask[] } export type QcTaskListDisplayItem = QcTaskListLabItem | QcTaskListAllThirdItem export const UNASSIGNED_THIRD_PARTY_COMPANY_LABEL = '未归属公司' export const ALL_THIRD_PARTY_CARD_TITLE = '第三方质检项目' function trimId(v?: string) { return (v || '').trim() } export function thirdPartyCompanyDisplayName(task: Pick): string { if (!trimId(task.companyId)) return UNASSIGNED_THIRD_PARTY_COMPANY_LABEL return (task.companyName || '').trim() || UNASSIGNED_THIRD_PARTY_COMPANY_LABEL } /** 有非空 companyId 的去重公司数(不含未归属) */ export function countDistinctThirdPartyCompanies(tasks: QcTask[]): number { const ids = new Set() for (const t of tasks || []) { const cid = trimId(t.companyId) if (cid) ids.add(cid) } return ids.size } export function allThirdPartyCardSubtitle(tasks: QcTask[]): string { const list = tasks || [] const n = list.length const m = countDistinctThirdPartyCompanies(list) if (m > 0) return `第三方 · ${n} 个检测项目 · ${m} 家公司` return `第三方 · ${n} 个检测项目` } /** * 先按公司首次出现顺序分组,组内保持原序;无 companyId 的「未归属公司」组放最后。 */ export function sortThirdPartyTasksByCompany(tasks: QcTask[]): QcTask[] { const list = [...(tasks || [])] const companyOrder: string[] = [] const byCompany = new Map() const orphans: QcTask[] = [] for (const t of list) { const cid = trimId(t.companyId) if (!cid) { orphans.push(t) continue } if (!byCompany.has(cid)) { byCompany.set(cid, []) companyOrder.push(cid) } byCompany.get(cid)!.push(t) } const sorted: QcTask[] = [] for (const cid of companyOrder) { sorted.push(...(byCompany.get(cid) || [])) } sorted.push(...orphans) return sorted } /** 自检卡在前(原序);全部第三方(含无 companyId)合成一张 all-third 卡 */ export function buildTaskListDisplayItems(tasks: QcTask[]): QcTaskListDisplayItem[] { const lab: QcTaskListDisplayItem[] = [] const third: QcTask[] = [] for (const t of tasks || []) { if ((t.taskType || '').trim() === 'dsfjc') { third.push(t) continue } // sysz 及其他非第三方:按自检单卡展示(与旧逻辑一致) lab.push({ kind: 'lab', task: t }) } if (!third.length) return lab return [...lab, { kind: 'all-third', tasks: third }] } export function companyGroupProgress(tasks: QcTask[]) { const list = tasks || [] const completed = list.filter((t) => (t.taskStatus || '').trim() === 'ywc').length return { completed, total: list.length } } function timeMs(v?: string) { if (!v) return 0 const n = Date.parse(String(v).replace(/-/g, '/')) return Number.isFinite(n) ? n : 0 } export function pickSharedRemarkAndAttachments(tasks: QcTask[]): { remark: string thirdPartyAttachments: string attachmentFiles: NonNullable } { const list = [...(tasks || [])].sort((a, b) => timeMs(b.updateTime) - timeMs(a.updateTime)) let remark = '' let thirdPartyAttachments = '' let attachmentFiles: NonNullable = [] for (const t of list) { if (!remark && (t.remark || '').trim()) remark = (t.remark || '').trim() const urls = (t.thirdPartyAttachments || '').trim() const files = t.attachmentFiles || [] if (!thirdPartyAttachments && (urls || files.length)) { thirdPartyAttachments = urls attachmentFiles = files.length ? [...files] : [] } if (remark && (thirdPartyAttachments || attachmentFiles.length)) break } return { remark, thirdPartyAttachments, attachmentFiles } } export function uniqueAssigneeNames(tasks: QcTask[]): string { const names: string[] = [] const seen = new Set() for (const t of tasks || []) { const raw = (t.assigneeUserNames || '').trim() if (!raw) continue for (const part of raw.split(/[,,、]/)) { const n = part.trim() if (!n || seen.has(n)) continue seen.add(n) names.push(n) } } return names.join('、') || '—' }