Files
shanxia2.0/web-admin/scripts/manual-dispatch-calendar.test.ts
T
wuzilong fcbf8a9b65 feat: 为现场日历增加单据类型并同步派车记录,减少重复录入。
按起止地关键词生成现场出入库计划,同步来源修改和删除,保留历史记录不补录。调整卡片及复制文本的单据类型格式,并记录测试库和生产库迁移结果。
2026-10-30 14:04:24 +08:00

195 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict'
import test from 'node:test'
import {
loadCalendarPages,
manualCalendarDays,
manualCopyText,
validateManualDraft
} from '../src/views/pl/dispatch-calendar/manual-model'
const row = (id: string, date = '2026-10-26', vehicleId = 'v1') => ({
id,
dispatchDate: date,
vehicleId,
licensePlate: '皖H12345',
productId: 'p1',
productName: '液碱',
origin: '山峡',
destination: '云栋',
quantity: '',
calendarKind: 'acid' as const,
remark: '',
createTime: '',
updateTime: ''
})
test('同车同日同路线保留独立车次,车辆筛选与汇总一致', () => {
const days = manualCalendarDays(
[row('1'), row('2'), row('3', '2026-10-26', 'v2'), row('4', '2026-11-01')],
'2026-10',
'v1'
)
const day = days.find((d) => d.date === '2026-10-26')!
assert.equal(day.rows.length, 2)
assert.equal(day.vehicles.length, 1)
assert.equal(day.products[0].count, 2)
assert.ok(days.some((d) => d.date === '2026-10-01' && d.rows.length === 0))
})
test('完整分页加载,不悄悄展示截断数据', async () => {
const calls: number[] = []
const rows = await loadCalendarPages(async ({ page }) => {
calls.push(page)
return { list: [row(String(page))], total: 3 }
})
assert.deepEqual(calls, [1, 2, 3])
assert.equal(rows?.length, 3)
await assert.rejects(
loadCalendarPages(async () => ({ list: [], total: 1 })),
/不完整/
)
})
test('过期请求不继续加载,不返回旧月份数据', async () => {
let current = true
assert.equal(
await loadCalendarPages(
async () => {
current = false
return { list: [row('1')], total: 3 }
},
() => current
),
null
)
})
test('复制保留重复车次,文本不混入实际运输计划', () => {
const text = manualCopyText('2026-10-26', [row('1'), row('2')])
assert.match(text, /2026-10-26 派车计划/)
assert.equal(text.split('山峡 → 云栋').length - 1, 2)
})
test('同一车辆按创建时间正序,复制时排在一起且每条换行', () => {
const later = {
...row('b', '2026-10-28', 'qa'),
licensePlate: '皖QA1024',
productName: '测试',
origin: '2',
destination: '3',
remark: '23',
createTime: '2026-10-28 10:00:00'
}
const earlier = {
...row('a', '2026-10-28', 'qa'),
licensePlate: '皖QA1024',
productName: '测试',
origin: '1',
destination: '2',
remark: '12',
createTime: '2026-10-28 09:00:00'
}
const other = {
...row('c', '2026-10-28', 'other'),
licensePlate: '皖H00001',
createTime: '2026-10-28 09:30:00'
}
const day = manualCalendarDays([later, other, earlier], '2026-10').find(
(item) => item.date === '2026-10-28'
)!
assert.deepEqual(
day.vehicles.find((vehicle) => vehicle.id === 'qa')!.rows.map((item) => item.id),
['a', 'b']
)
const text = manualCopyText('2026-10-28', [later, other, earlier])
assert.deepEqual(text.split('\n'), [
'2026-10-28 派车计划',
' ·皖QA1024',
' 测试 1 → 2(12)',
' 测试 2 → 3(23)',
' ·皖H00001',
' 液碱 山峡 → 云栋'
])
assert.equal(text.startsWith('2026-10-28'), true)
})
test('表单允许起止地留空,仍拒绝无效日期和超长地址', () => {
for (const calendarKind of ['acid', 'alkali', 'other', 'site'] as const) {
for (const addresses of [
{ origin: '', destination: '云栋' },
{ origin: '山峡', destination: '' },
{ origin: ' ', destination: ' ' }
]) {
assert.equal(validateManualDraft({ ...row('1'), calendarKind, ...addresses }), '')
}
}
for (const field of ['origin', 'destination']) {
assert.equal(
validateManualDraft({ ...row('1'), [field]: '地'.repeat(256) }),
'始发地和目的地最多255个字符'
)
}
assert.equal(
validateManualDraft({ ...row('1'), dispatchDate: '2026-02-30' }),
'请选择有效的派车日期'
)
assert.equal(validateManualDraft(row('1')), '')
})
test('数量是可空文本,复制逐条展示,日汇总仍只计车次', () => {
const tons = { ...row('1'), quantity: '32.50' }
const blank = { ...row('2'), quantity: ' ' }
const day = manualCalendarDays([tons, blank], '2026-10').find(
(item) => item.date === '2026-10-26'
)!
assert.deepEqual(day.products[0], { id: 'p1', name: '液碱', count: 2 })
const text = manualCopyText('2026-10-26', [tons, blank])
assert.match(text, /液碱 32\.50吨 山峡 → 云栋/)
assert.equal(text.split('山峡 → 云栋').length - 1, 2)
assert.equal((text.match(/吨/g) || []).length, 1)
assert.equal(validateManualDraft({ ...row('1'), quantity: '' }), '')
assert.equal(validateManualDraft({ ...row('1'), quantity: ' 12.5 ' }), '')
assert.equal(
validateManualDraft({ ...row('1'), quantity: '12.345' }),
'数量须为数字,最多两位小数'
)
assert.equal(validateManualDraft({ ...row('1'), quantity: '1吨' }), '数量须为数字,最多两位小数')
})
test('现场复制隐藏起止地和备注,单据类型放在每条记录末尾的中文括号中', () => {
for (const documentType of ['入库计划', '出库计划', '出入库计划', '现场调拨']) {
const record = {
...row('site'),
calendarKind: 'site' as const,
documentType,
quantity: '32.50',
remark: '内部备注'
}
assert.equal(validateManualDraft(record), '')
assert.deepEqual(
manualCopyText('2026-10-26', [record, { ...record, id: 'site-2', quantity: '' }]).split('\n'),
[
'2026-10-26 派车计划',
' ·皖H12345',
` 液碱 32.50吨(${documentType})`,
` 液碱(${documentType})`
]
)
assert.equal(
manualCalendarDays([record], '2026-10').find((d) => d.date === record.dispatchDate)?.rows
.length,
1
)
}
for (const documentType of [null, undefined, '', ' ']) {
const record = {
...row('site'),
calendarKind: 'site' as const,
documentType,
remark: '内部备注'
}
assert.equal(manualCopyText('2026-10-26', [record]), '2026-10-26 派车计划\n ·皖H12345\n 液碱')
}
})
test('单据类型选填且最多50个字符', () => {
assert.equal(validateManualDraft({ ...row('site'), calendarKind: 'site', documentType: '' }), '')
assert.match(
validateManualDraft({ ...row('site'), calendarKind: 'site', documentType: '字'.repeat(51) }),
/单据类型.*50/
)
})