feat: 为现场日历增加单据类型并同步派车记录,减少重复录入。

按起止地关键词生成现场出入库计划,同步来源修改和删除,保留历史记录不补录。调整卡片及复制文本的单据类型格式,并记录测试库和生产库迁移结果。
This commit is contained in:
wuzilong committed 2026-10-30 14:04:24 +08:00
1 parent 1ae8603045
commit fcbf8a9b65
17 files changed
+732 -42

No files matched your search

@@ -148,3 +148,47 @@ test('数量是可空文本,复制逐条展示,日汇总仍只计车次', ()
)
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/
)
})
@@ -14,7 +14,8 @@ try {
viewport: mobile ? { width: 375, height: 812 } : { width: 1440, height: 1000 }
})
const page = await context.newPage()
await page.clock.setFixedTime(new Date('2026-10-26T04:00:00Z'))
// 固定起始日期但保持时钟前进;冻结 Date.now 会触发 Vue 嵌套点击事件的时间戳保护。
await page.clock.install({ time: new Date('2026-10-26T04:00:00Z') })
page.setDefaultTimeout(20000)
page.on('console', (msg) => {
if (msg.type() === 'error') console.log('CONSOLE', msg.text())
@@ -188,6 +189,13 @@ try {
await editor.getByRole('combobox', { name: '产品名称', exact: true }).click()
await page.getByRole('option', { name: '液碱', exact: true }).click()
}
if (kind === 'site') {
await editor.getByRole('combobox', { name: '单据类型', exact: true }).click()
await page.getByRole('option', { name: '出库计划', exact: true }).waitFor()
await page.getByRole('option', { name: '入库计划', exact: true }).click()
} else {
assert.equal(await editor.getByRole('combobox', { name: '单据类型', exact: true }).count(), 0)
}
// 起止地留空也应保存成功,编辑后仍可补填。
await editor.getByRole('button', { name: '保存', exact: true }).click()
await editor.waitFor({ state: 'hidden' })
@@ -195,8 +203,16 @@ try {
assert.equal(rows[0].origin, '')
assert.equal(rows[0].destination, '')
assert.equal(rows[0].calendarKind, kind)
if (kind === 'site') assert.equal(rows[0].documentType, '入库计划')
await page.locator('[data-testid="manual-record"]').first().click()
if (kind === 'site')
await page.locator('.el-dialog:visible').getByText('入库计划', { exact: true }).waitFor()
await page.getByRole('button', { name: '编辑', exact: true }).click()
if (kind === 'site') {
assert.match(await editor.innerText(), /入库计划/)
await editor.getByRole('combobox', { name: '单据类型', exact: true }).fill('现场调拨')
await page.getByRole('option', { name: '现场调拨', exact: true }).click()
}
await editor.getByPlaceholder('请输入始发地').fill('山峡')
await editor.getByPlaceholder('请输入目的地').fill('云栋')
failSave = true
@@ -214,21 +230,32 @@ try {
fullPage: false
})
assert.match(await card.innerText(), /山峡 → 云栋/)
if (kind === 'site') {
assert.equal(rows[0].documentType, '现场调拨')
assert.equal(await card.locator('.route').innerText(), '山峡 → 云栋(现场调拨)')
assert.equal(await card.locator('.el-tag').count(), 0)
}
await page
.locator('[data-date="2026-10-26"]')
.getByRole('button', { name: mobile ? '复制' : '复制2026-10-26派车计划', exact: true })
.click()
assert.match(
await page.evaluate(() => navigator.clipboard.readText()),
/皖H12345.*液碱.*山峡 → 云栋/s
)
const copiedText = await page.evaluate(() => navigator.clipboard.readText())
if (kind === 'site') {
assert.equal(copiedText, '2026-10-26 派车计划\n ·皖H12345\n 液碱(现场调拨)')
} else {
assert.match(copiedText, /皖H12345.*液碱.*山峡 → 云栋/s)
}
await card.click()
await page.getByRole('button', { name: '编辑', exact: true }).click()
await editor.getByPlaceholder('请输入目的地').fill('安庆')
await editor.getByRole('button', { name: '保存', exact: true }).click()
await editor.waitFor({ state: 'hidden' })
await page.getByText('山峡 → 安庆', { exact: true }).first().waitFor()
if (kind === 'site') assert.equal(rows[0].documentType, '现场调拨')
await page
.getByText(kind === 'site' ? '山峡 → 安庆(现场调拨)' : '山峡 → 安庆', { exact: true })
.first()
.waitFor()
await page.locator('[data-testid="manual-record"]').first().click()
await page.getByRole('button', { name: '删除', exact: true }).click()
await page.getByRole('button', { name: mobile ? '确认删除' : '确定', exact: true }).click()
@@ -266,6 +293,31 @@ try {
calendarKind: kind
}
]
if (kind === 'site') {
allowManage = true
rows[0].sourceRecordId = 'source-fixture'
rows[0].documentType = '出入库计划'
rows.push({
...rows[0],
id: 'second-site',
sourceRecordId: 'second-source',
documentType: '入库计划'
})
await page.getByRole('tab', { name: title, exact: true }).click()
await page.locator('.pair-trip').nth(1).waitFor()
assert.match(await page.locator('.pair-trip').nth(0).innerText(), /山峡 → 云栋(出入库计划)/)
assert.match(await page.locator('.pair-trip').nth(1).innerText(), /山峡 → 云栋(入库计划)/)
assert.equal(await page.locator('.manual-day-content .el-tag').count(), 0)
await page.locator('[data-testid="manual-record"]').first().click()
await page.getByText('自动同步,请在来源派车日历修改或删除', { exact: true }).waitFor()
assert.equal(await page.getByRole('button', { name: '编辑', exact: true }).count(), 0)
assert.equal(await page.getByRole('button', { name: '删除', exact: true }).count(), 0)
await page.locator('.el-dialog:visible .el-dialog__headerbtn').click()
await page.getByRole('tab', { name: '实际派车信息', exact: true }).click()
allowManage = false
delete rows[0].sourceRecordId
rows.pop()
}
await page.getByRole('tab', { name: title, exact: true }).click()
await page.locator('[data-testid="manual-record"]').first().waitFor()
assert.equal(await page.getByRole('button', { name: '新增派车计划', exact: true }).count(), 0)