183 lines
5.8 KiB
TypeScript
183 lines
5.8 KiB
TypeScript
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<TestQcTask> & Pick<TestQcTask, 'id' | 'taskType'>): 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' })]), '—')
|
|
})
|
|
})
|