fix: align audit and dispatch workflows and release failed requests

This commit is contained in:
2026-10-22 23:10:09 +08:00
parent 9cdcb9c077
commit 4a3456756f
124 changed files with 1296 additions and 2120 deletions
@@ -14,30 +14,29 @@ vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({
vi.mock('vue-router', () => ({ useRouter: () => ({ push }) }))
vi.mock('@/modules/warehouses', () => ({ listAllPlatformWarehouses: vi.fn() }))
vi.mock('./DispatchResourceFields.vue', () => ({ default: { template: '<div />' } }))
vi.mock('./SmartDispatchExistingCargo.vue', () => ({ default: { name: 'SmartDispatchExistingCargo', emits: ['saved', 'busy'], template: '<div data-existing-cargo />' } }))
vi.mock('../api/dispatches', () => ({ listDispatchDrafts: vi.fn(), listDispatchCandidates: vi.fn(), createDispatchDraft: vi.fn(), createDispatchDraftContainer: vi.fn(), lockDispatchDraftPallet: vi.fn(), unlockDispatchDraftPallet: vi.fn(), deleteDispatchDraftContainer: vi.fn(), releaseDispatchDraft: vi.fn(), convertDispatchDraft: vi.fn(), createDispatch: vi.fn(), getDispatch: vi.fn(), getDispatchCommand: vi.fn() }))
const source = () => candidate(), draft = (): DispatchDraft => ({ draftToken: 'server-token', recordVersion: 0, status: 'ACTIVE', warehouseId: '321', containers: [{ draftContainerId: '100000000000000001', sequenceNo: 1, capacity: 30, sourceKeys: ['source-1'] }], sources: [source()], expiresAt: '2026-12-01T00:00:00Z' })
it('switches to existing cargo inside the same dialog without creating a draft or submitting a new dispatch', async () => {
it('opens only new dispatch planning and keeps draft cargo selection available', async () => {
const wrapper = mount(SmartDispatchDialog, options); await flushPromises()
const dialog = wrapper.getComponent(AppDialog)
await wrapper.getComponent({ name: 'ElDialogContent' }).findAll('button').find(button => button.text() === '调整已有排车货物')!.trigger('click'); await flushPromises()
expect(wrapper.findComponent({ name: 'SmartDispatchExistingCargo' }).exists()).toBe(true)
expect(dialog.props('showConfirm')).toBe(false)
dialog.vm.$emit('confirm'); await flushPromises()
expect(dialog.find('[aria-label="智能排车工作方式"]').exists()).toBe(false)
expect(dialog.text()).not.toContain('调整已有排车货物')
expect(dialog.findComponent({ name: 'SmartDispatchCargoBoard' }).exists()).toBe(true)
expect(dialog.props('showConfirm')).toBe(true)
expect(api.listDispatchCandidates).toHaveBeenCalledOnce()
expect(api.createDispatch).not.toHaveBeenCalled()
expect(api.createDispatchDraft).not.toHaveBeenCalled()
expect(api.convertDispatchDraft).not.toHaveBeenCalled()
wrapper.getComponent({ name: 'SmartDispatchExistingCargo' }).vm.$emit('saved'); await flushPromises()
expect(wrapper.emitted('created')).toHaveLength(1)
expect(wrapper.emitted('created')).toBeUndefined()
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
wrapper.unmount()
})
it.each(['ADD_CARGO','REMOVE_CARGO'] as const)('ignores old %s browser requests and opens a fresh workspace',async action=>{
sessionStorage.setItem('dispatch-command:'+identity.id,JSON.stringify({dispatchNo:'PC/1',action,attempted:true,body:{idempotencyKey:'old'}}))
const wrapper=mount(SmartDispatchDialog,options);await flushPromises()
expect(wrapper.findComponent({name:'SmartDispatchExistingCargo'}).exists()).toBe(false)
expect(wrapper.find('[aria-label="智能排车工作方式"]').exists()).toBe(false)
expect(api.listDispatchDrafts).toHaveBeenCalledOnce()
expect(sessionStorage.getItem('dispatch-command:'+identity.id)).toBeNull()
expect(wrapper.text()).not.toContain('原请求已保留')
expect(wrapper.text()).not.toContain('原请求结果尚待核对');wrapper.unmount()
})
it('converts a filtered relabel group with both authoritative sources and locks it through one HTTP command', async () => {
@@ -148,7 +147,7 @@ it('clears an old departure request without blocking new empty creation',async()
const state=wrapper.vm as unknown as {mode:string;submit():Promise<void>}
state.mode='empty';await flushPromises();await state.submit()
expect(api.createDispatch).toHaveBeenCalledOnce()
expect(sessionStorage.getItem('dispatch-command:'+identity.id)).toBeNull();wrapper.unmount()
expect(wrapper.text()).not.toContain('原请求已保留');wrapper.unmount()
})
it('rejects a restored source whose batch customer differs from its real cargo owner', async () => {
const original = draft(); original.sources[0]!.appointmentBatches = [{ batchKey: 'batch-1', batchNo: 'BATCH-1', recordVersion: 0, customerId: 'other-customer', sources: [{ sourceKey: 'source-1', destinationKey: 'CODE:ONT8', packageCount: 2 }] }]