This commit is contained in:
2026-10-21 17:26:49 +08:00
parent f8c9334e98
commit 22e60248d2
6 changed files with 27 additions and 7 deletions
+2 -2
View File
@@ -35,7 +35,7 @@
## 履约硬边界
- 排车详情固定四个彩色图标页签:车辆信息、排车信息、单据信息、关联订单明细。五个作业阶段及审核分区、逐动作Gate由服务端返回;取消独立于阶段。装车完成须真实PDA拣货核平,装车完成进入装车后,五张装车照片全部保存后自动生成派送单并进入派送中,无独立安排派送或发车确认;Admin和PDA共用正式版本化命令。已有单写入提交recordVersion(0合法)、原幂等键和完整载荷;未知结果保留原请求核对,成功后另读当前事实。
- 排车详情固定四个彩色图标页签:车辆信息、排车信息、单据信息、关联订单明细。五个作业阶段及审核分区、逐动作Gate由服务端返回;取消独立于阶段。装车完成须真实PDA拣货核平,装车中可同步上传五张装车照片,确认装车完成且资料齐全自动生成派送单并进入派送中,资料未齐时留在装车后,无独立安排派送或发车确认;Admin和PDA共用正式版本化命令。已有单写入提交recordVersion(0合法)、原幂等键和完整载荷;未知结果保留原请求核对,成功后另读当前事实。
- 智能排车来源支持 `RELABEL`(待出库换标单),按服务端候选的`selection.relabelNo/sourceVersion`提交,不用展示订单号或原入仓号替代换标身份;沿用真实库存、托盘与箱唛,不生成新入库单。客户和仓库归属由服务端核验,不在前端拼接客户子排车。
- 托盘标签从 `pages/PalletsView.vue` → `api/pallets.ts` 的 `getPalletLabelPdf` 下载服务端 PDF,传该行仓库与托盘 ID,复用列表权限;不在前端生成标签或维护模板、尺寸、编码。模板/接口变化才查 [Print 指引](../../../../../baiyue-firstleg/print/AGENTS.md)的托盘入口及[标签维护](../../../../../docs/打印标签维护/README.md),纯按钮文案不追加打印资料。
@@ -54,7 +54,7 @@
| 货物计划与装车命令 | [对应条款](../../../../../docs/业务实现边界.md#admin-货物计划与装车命令) |
| 取消与费用展示 | [对应条款](../../../../../docs/业务实现边界.md#admin-取消与费用展示) |
| 业务导出 | [对应条款](../../../../../docs/业务实现边界.md#admin-业务导出) |
| 装车后资料入口 | [对应条款](../../../../../docs/业务实现边界.md#admin-装车后资料入口) |
| 装车照片与资料入口 | [对应条款](../../../../../docs/业务实现边界.md#admin-装车照片与资料入口) |
## 验证
@@ -428,4 +428,4 @@
| 页面 | 操作 | 原型/确认依据 | 承载与实现 | 验收 |
|---|---|---|---|---|
| 排车列表:派送中、配送完成 | 管理资料 | 用户管理资料截图及同车/派送单资料共用确认;签收完成即可,其他可补 | 1100px居中可全屏弹框,签收文件/油耗图片/装车资料三个页签;按关联派送单切换,共用原派送资料编辑器;油耗沿本车附加照片保存 | 自动回归单独报告;1920×1080、100%待人工截图确认 |
| 排车列表:装车中、装车后、派送中、配送完成 | 管理资料 | 用户管理资料截图及同车/派送单资料共用确认;签收完成即可,其他可补 | 1100px居中可全屏弹框,签收文件/油耗图片/装车资料三个页签;装车中及装车后默认打开装车资料,可同步上传,确认装车且资料齐全后自动派送;按关联派送单切换,共用原派送资料编辑器;油耗沿本车附加照片保存 | 自动回归单独报告;1920×1080、100%待人工截图确认 |
@@ -61,3 +61,13 @@ it('shows existing photos without exposing upload for a read-only account', asyn
expect(wrapper.find('input[type="file"]').exists()).toBe(false)
expect(api.uploadLoadingPhoto).not.toHaveBeenCalled(); wrapper.unmount()
})
it('allows saving photos while loading and keeps the loading stage', async () => {
vi.mocked(api.getLoadingDocuments).mockResolvedValue(data({ stage: 'LOADING' }))
vi.mocked(api.bindLoadingPhoto).mockResolvedValue(data({ stage: 'LOADING', recordVersion: '1', photos: [photo] }))
const wrapper = setup(); await flushPromises()
expect(wrapper.text()).toContain('可边装车边上传')
await upload(wrapper)
expect(wrapper.emitted('saved')).toHaveLength(1)
expect(wrapper.text()).toContain('可边装车边上传'); wrapper.unmount()
})
@@ -3,11 +3,11 @@ import { ApiResponseError } from '@/shared/api/http'
import { useDispatchCommandRecovery } from './dispatchCommandRecovery'
import { command } from './dispatchTestFixtures'
beforeEach(() => sessionStorage.clear())
it('rejects a loading result that skips the loading documents stage', async () => {
it('rejects a loading result that has not completed loading', async () => {
const owner = crypto.randomUUID(), recovery = useDispatchCommandRecovery(() => owner)
recovery.begin('PC/1', 'LOADING_COMPLETE', { recordVersion: 0, idempotencyKey: 'key' })
const read = vi.fn()
await expect(recovery.execute(vi.fn().mockResolvedValue({ ...command('LOADING_COMPLETE'), stage: 'DELIVERING' }), read, vi.fn())).rejects.toThrow('装车后')
await expect(recovery.execute(vi.fn().mockResolvedValue({ ...command('LOADING_COMPLETE'), stage: 'LOADING' }), read, vi.fn())).rejects.toThrow('装车完成')
expect(read).not.toHaveBeenCalled()
expect(recovery.pending.value?.result).toBeNull()
expect(recovery.pending.value?.body.idempotencyKey).toBe('key')