feat(admin): 实现排车候选分页并修正报关批次参数
This commit is contained in:
@@ -20,7 +20,7 @@ const source = () => candidate(), draft = (): DispatchDraft => ({ draftToken: 's
|
||||
it('converts a filtered relabel group with both authoritative sources and locks it through one HTTP command', async () => {
|
||||
const [first, second] = sharedPalletCandidates(), original = draft()
|
||||
original.sources = [first!]; original.containers[0]!.sourceKeys = [first!.sourceKey]
|
||||
vi.mocked(api.listDispatchCandidates).mockResolvedValue({ candidates: [first!], complete: true, snapshotAt: '' })
|
||||
vi.mocked(api.listDispatchCandidates).mockResolvedValue({ total: 1, page: 1, size: 20, pages: 1, candidates: [first!], complete: true, snapshotAt: '' })
|
||||
vi.mocked(api.listDispatchDrafts).mockResolvedValue([original]); vi.mocked(api.lockDispatchDraftPallet).mockResolvedValue(original)
|
||||
vi.mocked(api.convertDispatchDraft).mockImplementation(async request => ({ draftToken: request.draftToken, replayed: false, vehicles: request.groups.map(group => ({ draftContainerId: group.draftContainerId, dispatch: command('CREATE', group.dispatch.idempotencyKey) })) }))
|
||||
const wrapper = mount(SmartDispatchDialog, options); await flushPromises()
|
||||
@@ -41,7 +41,7 @@ it('allows one atomic removal of a restored group that is no longer selectable',
|
||||
expect(api.unlockDispatchDraftPallet).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ source: first.selection })); wrapper.unmount()
|
||||
})
|
||||
const options = { props: { modelValue: true, orders: [] }, global: { plugins: [ElementPlus] } }
|
||||
beforeEach(() => { vi.clearAllMocks(); sessionStorage.clear(); identity.id = crypto.randomUUID(); vi.stubGlobal('ResizeObserver', class { observe() {} unobserve() {} disconnect() {} }); vi.mocked(listAllPlatformWarehouses).mockResolvedValue([{ id: '321', warehouseName: '洛杉矶仓' }] as Awaited<ReturnType<typeof listAllPlatformWarehouses>>); vi.mocked(api.listDispatchDrafts).mockResolvedValue([draft()]); vi.mocked(api.listDispatchCandidates).mockResolvedValue({ candidates: [source()], complete: true, snapshotAt: '2026-10-19T00:00:00Z' }); vi.mocked(api.getDispatch).mockResolvedValue(detail({ recordVersion: 1 })) })
|
||||
beforeEach(() => { vi.clearAllMocks(); sessionStorage.clear(); identity.id = crypto.randomUUID(); vi.stubGlobal('ResizeObserver', class { observe() {} unobserve() {} disconnect() {} }); vi.mocked(listAllPlatformWarehouses).mockResolvedValue([{ id: '321', warehouseName: '洛杉矶仓' }] as Awaited<ReturnType<typeof listAllPlatformWarehouses>>); vi.mocked(api.listDispatchDrafts).mockResolvedValue([draft()]); vi.mocked(api.listDispatchCandidates).mockResolvedValue({ total: 1, page: 1, size: 20, pages: 1, candidates: [source()], complete: true, snapshotAt: '2026-10-19T00:00:00Z' }); vi.mocked(api.getDispatch).mockResolvedValue(detail({ recordVersion: 1 })) })
|
||||
it.each([0, '0', '9007199254740993'])('transmits original authoritative batch version %s in complete draft conversion and exact retries', async recordVersion => {
|
||||
const original = draft()
|
||||
original.sources[0]!.appointmentBatches = [{ batchKey: 'FBA_APPOINTMENT:1', batchNo: 'AP-1', customerId: 'C1', recordVersion, sources: [{ sourceKey: 'ORDER:1', destinationKey: 'FBA:ONT8', packageCount: 2 }] }]
|
||||
@@ -96,9 +96,9 @@ it('does not discard draft selections when recovery fails and never submits an i
|
||||
vi.mocked(api.listDispatchDrafts).mockRejectedValue(new Error('draft unavailable'))
|
||||
const wrapper = mount(SmartDispatchDialog, options); await flushPromises(); expect(wrapper.getComponent({ name: 'ElDialogContent' }).text()).toContain('排车候选或草稿恢复失败'); expect(api.convertDispatchDraft).not.toHaveBeenCalled(); wrapper.unmount()
|
||||
})
|
||||
it('refuses an incomplete candidate page without pretending its filtered rows are all available cargo', async () => {
|
||||
vi.mocked(api.listDispatchCandidates).mockResolvedValue({ candidates: [], complete: false, snapshotAt: '' })
|
||||
const wrapper = mount(SmartDispatchDialog, options); await flushPromises(); const state = wrapper.vm as unknown as { restoreDraft: (token: string) => void }; state.restoreDraft('server-token'); await flushPromises(); expect(wrapper.getComponent({ name: 'ElDialogContent' }).text()).toContain('尚未完整返回'); wrapper.unmount()
|
||||
it('accepts a partial candidate page without requiring the filtered whole set', async () => {
|
||||
vi.mocked(api.listDispatchCandidates).mockResolvedValue({ total: 21, page: 1, size: 20, pages: 2, candidates: [source()], complete: false, snapshotAt: '' })
|
||||
const wrapper = mount(SmartDispatchDialog, options); await flushPromises(); const state = wrapper.vm as unknown as { restoreDraft: (token: string) => void }; state.restoreDraft('server-token'); await flushPromises(); expect(wrapper.getComponent({ name: 'ElDialogContent' }).text()).not.toContain('尚未完整返回'); wrapper.unmount()
|
||||
})
|
||||
it('keeps vehicle assignments independent between containers and reuses a proven conversion after a detail read fails', async () => {
|
||||
const original = draft(); original.containers.push({ draftContainerId: 'container-B', sequenceNo: 2, capacity: 15, sourceKeys: ['source-B'] }); original.sources.push(candidate({ sourceKey: 'source-B', customerId: 'B' }))
|
||||
@@ -128,3 +128,22 @@ it('rejects a restored source whose batch customer differs from its real cargo o
|
||||
const state = wrapper.vm as unknown as { restoreDraft(token: string): void; submit(): Promise<void> }; state.restoreDraft('server-token'); await flushPromises(); await state.submit()
|
||||
expect(api.convertDispatchDraft).not.toHaveBeenCalled(); expect(wrapper.getComponent({ name: 'ElDialogContent' }).text()).toContain('预约客户不一致'); wrapper.unmount()
|
||||
})
|
||||
|
||||
it('keeps server draft cargo across pages, resets filters and sends regional tabs to the server', async () => {
|
||||
vi.mocked(api.listDispatchCandidates).mockImplementation(async query => ({ candidates: query.page === 2 ? [] : [source()], complete: false, snapshotAt: '', total: 21, page: query.page!, size: query.size!, pages: Math.ceil(21 / query.size!) }))
|
||||
vi.mocked(api.convertDispatchDraft).mockImplementation(async request => ({ draftToken: request.draftToken, replayed: false, vehicles: request.groups.map(group => ({ draftContainerId: group.draftContainerId, dispatch: command('CREATE', group.dispatch.idempotencyKey) })) }))
|
||||
const wrapper = mount(SmartDispatchDialog, options); await flushPromises()
|
||||
try {
|
||||
const state = wrapper.vm as unknown as { restoreDraft(token: string): void; changePage(page: number): void; changeTab(tab: string): void; changeSize(size: number): void; query: { orderNo: string }; search(): Promise<void>; submit(): Promise<void> }
|
||||
state.restoreDraft('server-token'); await flushPromises(); state.changePage(2); await flushPromises()
|
||||
expect(api.listDispatchCandidates).toHaveBeenLastCalledWith(expect.objectContaining({ page: 2, size: 20 }))
|
||||
state.query.orderNo = 'query'; await state.search()
|
||||
expect(api.listDispatchCandidates).toHaveBeenLastCalledWith(expect.objectContaining({ page: 1, orderNo: 'query' }))
|
||||
state.changeTab('NYC'); await flushPromises()
|
||||
expect(api.listDispatchCandidates).toHaveBeenLastCalledWith(expect.objectContaining({ page: 1, warehouseTab: 'NYC' }))
|
||||
state.changeSize(10); await flushPromises()
|
||||
expect(api.listDispatchCandidates).toHaveBeenLastCalledWith(expect.objectContaining({ page: 1, size: 10 }))
|
||||
state.changePage(2); await flushPromises(); await state.submit()
|
||||
expect(api.convertDispatchDraft).toHaveBeenCalledWith(expect.objectContaining({ groups: [expect.objectContaining({ dispatch: expect.objectContaining({ cargo: [source().selection] }) })] }))
|
||||
} finally { wrapper.unmount() }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user