import { describe, it } from 'node:test' import assert from 'node:assert/strict' import { buildTaskListDisplayItems, pickSharedRemarkAndAttachments, companyGroupProgress, uniqueAssigneeNames, sortThirdPartyTasksByCompany, allThirdPartyCardSubtitle, thirdPartyCompanyDisplayName, countDistinctThirdPartyCompanies } from './qc-company-task-group' type TestQcTask = { id: string taskType: string taskNo?: string itemCode?: string itemName?: string taskStatus?: string workOrderId?: string companyId?: string companyName?: string remark?: string thirdPartyAttachments?: string updateTime?: string assigneeUserNames?: string attachmentFiles?: Array<{ fileUrl: string; fileName?: string; fileType?: string }> } function task(partial: Partial & Pick): TestQcTask { return { taskNo: 'T1', itemCode: 'I', itemName: 'Item', taskStatus: 'dzx', workOrderId: 'wo1', ...partial } } describe('buildTaskListDisplayItems', () => { it('keeps lab tasks as single cards and merges all third-party into one card', () => { const tasks = [ task({ id: 'l1', taskType: 'sysz', itemName: '无菌' }), task({ id: 't1', taskType: 'dsfjc', companyId: 'c1', companyName: '金域', itemName: '乙肝' }), task({ id: 't2', taskType: 'dsfjc', companyId: 'c1', companyName: '金域', itemName: '丙肝' }), task({ id: 't3', taskType: 'dsfjc', companyId: 'c2', companyName: '迪安', itemName: 'HIV' }), task({ id: 't0', taskType: 'dsfjc', companyId: '', companyName: '', itemName: '孤儿' }) ] const items = buildTaskListDisplayItems(tasks) assert.equal(items.length, 2) assert.equal(items[0].kind, 'lab') assert.equal(items[0].kind === 'lab' && items[0].task.id, 'l1') assert.equal(items[1].kind, 'all-third') if (items[1].kind === 'all-third') { assert.equal(items[1].tasks.length, 4) assert.deepEqual( items[1].tasks.map((t) => t.id), ['t1', 't2', 't3', 't0'] ) } }) it('merges orphan third-party into all-third card', () => { const tasks = [ task({ id: 't0', taskType: 'dsfjc', companyId: '', companyName: '', itemName: '孤儿' }) ] const items = buildTaskListDisplayItems(tasks) assert.equal(items.length, 1) assert.equal(items[0].kind, 'all-third') if (items[0].kind === 'all-third') { assert.equal(items[0].tasks[0].id, 't0') } }) }) describe('sortThirdPartyTasksByCompany', () => { it('groups by company first-seen order and puts orphans last', () => { const sorted = sortThirdPartyTasksByCompany([ task({ id: 'a1', taskType: 'dsfjc', companyId: 'c2', companyName: '迪安' }), task({ id: 'o1', taskType: 'dsfjc', companyId: '' }), task({ id: 'b1', taskType: 'dsfjc', companyId: 'c1', companyName: '金域' }), task({ id: 'a2', taskType: 'dsfjc', companyId: 'c2', companyName: '迪安' }), task({ id: 'b2', taskType: 'dsfjc', companyId: 'c1', companyName: '金域' }) ]) assert.deepEqual( sorted.map((t) => t.id), ['a1', 'a2', 'b1', 'b2', 'o1'] ) }) }) describe('allThirdPartyCardSubtitle / company helpers', () => { it('counts distinct companies excluding unassigned', () => { const tasks = [ task({ id: '1', taskType: 'dsfjc', companyId: 'c1', companyName: '金域' }), task({ id: '2', taskType: 'dsfjc', companyId: 'c1', companyName: '金域' }), task({ id: '3', taskType: 'dsfjc', companyId: 'c2', companyName: '迪安' }), task({ id: '4', taskType: 'dsfjc', companyId: '' }) ] assert.equal(countDistinctThirdPartyCompanies(tasks), 2) assert.equal(allThirdPartyCardSubtitle(tasks), '第三方 · 4 个检测项目 · 2 家公司') assert.equal( allThirdPartyCardSubtitle([task({ id: '4', taskType: 'dsfjc', companyId: '' })]), '第三方 · 1 个检测项目' ) assert.equal(thirdPartyCompanyDisplayName({ companyId: '', companyName: '' }), '未归属公司') assert.equal( thirdPartyCompanyDisplayName({ companyId: 'c1', companyName: '金域' }), '金域' ) }) }) describe('companyGroupProgress', () => { it('counts ywc vs total', () => { const p = companyGroupProgress([ task({ id: 'a', taskType: 'dsfjc', taskStatus: 'ywc' }), task({ id: 'b', taskType: 'dsfjc', taskStatus: 'dzx' }) ]) assert.deepEqual(p, { completed: 1, total: 2 }) }) }) describe('pickSharedRemarkAndAttachments', () => { it('picks latest non-empty remark and attachments by updateTime', () => { const picked = pickSharedRemarkAndAttachments([ task({ id: 'a', taskType: 'dsfjc', remark: '旧备注', thirdPartyAttachments: 'http://a.pdf', updateTime: '2026-08-01 10:00:00', attachmentFiles: [{ fileUrl: 'http://a.pdf', fileName: 'a.pdf' }] }), task({ id: 'b', taskType: 'dsfjc', remark: '新备注', thirdPartyAttachments: '', updateTime: '2026-08-28 12:00:00', attachmentFiles: [] }) ]) assert.equal(picked.remark, '新备注') assert.equal(picked.thirdPartyAttachments, 'http://a.pdf') assert.equal(picked.attachmentFiles?.length, 1) }) }) describe('uniqueAssigneeNames', () => { it('dedupes assignee names split by comma or顿号', () => { const names = uniqueAssigneeNames([ task({ id: 'a', taskType: 'dsfjc', assigneeUserNames: '张三,李四' }), task({ id: 'b', taskType: 'dsfjc', assigneeUserNames: '李四、王五' }) ]) assert.equal(names, '张三、李四、王五') }) it('returns em dash when no assignees', () => { assert.equal(uniqueAssigneeNames([task({ id: 'a', taskType: 'dsfjc' })]), '—') }) })