fix(dispatch): release failed request state and return rejected reviews
This commit is contained in:
@@ -109,22 +109,22 @@ describe('dispatch workflow native layout', () => {
|
||||
expect(api.submitDispatchReview).toHaveBeenCalledExactlyOnceWith('PC/1', expect.objectContaining({ recordVersion: 1, remark: null }))
|
||||
expect(vi.mocked(api.updateDispatch).mock.invocationCallOrder[0]).toBeLessThan(vi.mocked(api.submitDispatchReview).mock.invocationCallOrder[0]!)
|
||||
})
|
||||
it('retains the locally submitted draft after close and reopen and retries exactly the same failed request', async () => {
|
||||
vi.mocked(api.updateDispatch).mockRejectedValueOnce(new ApiResponseError('结果未确认', 'A0503', 503, null, 'workflow-request')).mockImplementationOnce(async (_, body) => command('EDIT', body.idempotencyKey))
|
||||
const { wrapper, dialog } = await render('EDIT')
|
||||
await field(dialog, '车牌号').get('input').setValue('CA-PRESERVED')
|
||||
dialog.vm.$emit('confirm'); await flushPromises()
|
||||
const original = JSON.parse(JSON.stringify(vi.mocked(api.updateDispatch).mock.calls[0]![1])) as UpdateDispatch
|
||||
it('keeps failed input editable and permits a new request and another target',async()=>{
|
||||
vi.mocked(api.updateDispatch).mockRejectedValueOnce(new ApiResponseError('结果未确认','S0503',200,null,'workflow-request')).mockImplementationOnce(async(_,body)=>command('EDIT',body.idempotencyKey))
|
||||
const {wrapper,dialog}=await render('EDIT')
|
||||
await field(dialog,'车牌号').get('input').setValue('CA-PRESERVED')
|
||||
dialog.vm.$emit('confirm');await flushPromises()
|
||||
const original=structuredClone(vi.mocked(api.updateDispatch).mock.calls[0]![1])
|
||||
expect(dialog.text()).toContain('workflow-request')
|
||||
expect(field(dialog, '车牌号').get('input').attributes('disabled')).toBeDefined()
|
||||
await wrapper.setProps({ dispatchNo: 'PC/2', action: 'CANCEL' }); await flushPromises()
|
||||
expect(dialog.props('title')).toBe('维护车辆 · PC/1')
|
||||
await wrapper.setProps({ modelValue: false }); await wrapper.setProps({ modelValue: true }); await flushPromises()
|
||||
expect((field(dialog, '车牌号').get('input').element as HTMLInputElement).value).toBe('CA-PRESERVED')
|
||||
expect(original.remark).toBe('真实备注')
|
||||
expect(dialog.find('textarea[aria-label="本次操作备注"]').exists()).toBe(false)
|
||||
dialog.findComponent(LoadErrorState).vm.$emit('retry'); await flushPromises()
|
||||
expect(vi.mocked(api.updateDispatch).mock.calls[1]![1]).toEqual(original)
|
||||
expect(field(dialog,'车牌号').get('input').attributes('disabled')).toBeUndefined()
|
||||
expect((field(dialog,'车牌号').get('input').element as HTMLInputElement).value).toBe('CA-PRESERVED')
|
||||
await field(dialog,'车牌号').get('input').setValue('CA-CHANGED')
|
||||
dialog.vm.$emit('confirm');await flushPromises()
|
||||
const next=vi.mocked(api.updateDispatch).mock.calls[1]![1]
|
||||
expect(next.vehicle?.plate).toBe('CA-CHANGED');expect(next.idempotencyKey).not.toBe(original.idempotencyKey)
|
||||
expect(api.getDispatchCommand).not.toHaveBeenCalled()
|
||||
await wrapper.setProps({dispatchNo:'PC/2',action:'CANCEL'});await flushPromises()
|
||||
expect(dialog.props('title')).toContain('PC/2')
|
||||
})
|
||||
it.each(['DISPATCH_REVIEW', 'LOADING_REVIEW'] as const)('keeps %s facts read-only and requires a rejection reason', async action => {
|
||||
const { dialog } = await render(action)
|
||||
@@ -143,7 +143,7 @@ describe('dispatch workflow native layout', () => {
|
||||
expect(review).toHaveBeenCalledExactlyOnceWith('PC/1', { recordVersion: 0, idempotencyKey: expect.any(String), decision: 'REJECTED', reason: '证据不完整' })
|
||||
expect(dialog.findAll('input[type="file"]')).toHaveLength(0)
|
||||
})
|
||||
it.each(['DISPATCH_REVIEW', 'LOADING_REVIEW'] as const)('approves %s directly and keeps an unknown result on the original request', async action => {
|
||||
it.each(['DISPATCH_REVIEW', 'LOADING_REVIEW'] as const)('approves %s directly and permits a new decision after failure', async action => {
|
||||
const review = action === 'DISPATCH_REVIEW' ? api.reviewDispatch : api.reviewDispatchLoading
|
||||
vi.mocked(review).mockRejectedValueOnce(new Error('结果未知'))
|
||||
const { dialog } = await render(action)
|
||||
@@ -153,10 +153,10 @@ describe('dispatch workflow native layout', () => {
|
||||
const original = structuredClone(vi.mocked(review).mock.calls[0]![1])
|
||||
expect(dialog.props('showCancel')).toBe(false)
|
||||
expect(dialog.findAll('button').some(button => button.text() === '取消')).toBe(false)
|
||||
expect(dialog.findAll('button').some(button => button.text() === '驳回')).toBe(false)
|
||||
await dialog.findAll('button').find(button => button.text() === '核对并重试原请求')!.trigger('click')
|
||||
expect(dialog.findAll('button').some(button => button.text() === '驳回')).toBe(true)
|
||||
await dialog.findAll('button').find(button => button.text() === '审核通过')!.trigger('click')
|
||||
await flushPromises()
|
||||
expect(vi.mocked(review).mock.calls[1]![1]).toEqual(original)
|
||||
expect(vi.mocked(review).mock.calls[1]![1].decision).toBe('APPROVED');expect(vi.mocked(review).mock.calls[1]![1].idempotencyKey).not.toBe(original.idempotencyKey)
|
||||
})
|
||||
it.each(['DISPATCH_REVIEW', 'LOADING_REVIEW'] as const)('disables both %s decisions when write permission is missing', async action => {
|
||||
can.mockReturnValue(false)
|
||||
@@ -169,7 +169,7 @@ describe('dispatch workflow native layout', () => {
|
||||
expect(api.reviewDispatch).not.toHaveBeenCalled()
|
||||
expect(api.reviewDispatchLoading).not.toHaveBeenCalled()
|
||||
})
|
||||
it('uploads all three photos during resource maintenance and retries the exact original edit', async () => {
|
||||
it('retains all three uploaded photos and permits a fresh vehicle save after failure', async () => {
|
||||
can.mockImplementation(code => code === 'platform:overseas-warehouse:dispatch:edit')
|
||||
vi.mocked(api.updateDispatch).mockRejectedValueOnce(new Error('unknown edit')).mockImplementationOnce(async (_, body) => command('EDIT', body.idempotencyKey))
|
||||
const { wrapper, dialog } = await render('EDIT', undefined, true)
|
||||
@@ -191,16 +191,16 @@ describe('dispatch workflow native layout', () => {
|
||||
dialog.vm.$emit('confirm'); await flushPromises()
|
||||
const original = structuredClone(vi.mocked(api.updateDispatch).mock.calls[0]![1])
|
||||
expect(original).toMatchObject({ vehicle: { evidenceFileIds: ['301', '401'] }, driver: { evidence: { photoFileIds: ['402'], fileIds: expect.arrayContaining(['403']) } } })
|
||||
await wrapper.setProps({ modelValue: false }); await wrapper.setProps({ modelValue: true }); await flushPromises()
|
||||
dialog.vm.$emit('confirm'); await flushPromises()
|
||||
expect(vi.mocked(api.updateDispatch).mock.calls[1]![1]).toEqual(original)
|
||||
const next=vi.mocked(api.updateDispatch).mock.calls[1]![1]
|
||||
expect(next).toMatchObject({...original,recordVersion:1,idempotencyKey:expect.any(String)})
|
||||
expect(next.idempotencyKey).not.toBe(original.idempotencyKey)
|
||||
expect(api.reviewDispatch).not.toHaveBeenCalled()
|
||||
expect(api.reviewDispatchLoading).not.toHaveBeenCalled()
|
||||
})
|
||||
it.each(['DISPATCH_REVIEW', 'LOADING_REVIEW'] as const)('shows saved photos and old audit evidence read-only in %s', async action => {
|
||||
const { wrapper, dialog } = await render(action)
|
||||
const value = detail({ actions })
|
||||
value.vehicleInfo.vehicle!.evidenceFileIds = ['401']
|
||||
value.vehicleInfo.driver!.evidence!.photoFileIds = ['402']
|
||||
value.reviews.dispatchReview.attachments = { vehicleFileIds: [], driverPhotoFileIds: ['403'], licenseFileIds: [] }
|
||||
vi.mocked(api.getDispatch).mockResolvedValueOnce(value)
|
||||
@@ -208,9 +208,6 @@ describe('dispatch workflow native layout', () => {
|
||||
const fields = dialog.findAllComponents(DispatchEvidenceFiles)
|
||||
expect(fields.map(item => item.props('label'))).toEqual(['车辆图片', '司机照片', '驾驶证照片'])
|
||||
expect(fields.every(item => item.props('readonly') && item.props('photoCard'))).toBe(true)
|
||||
expect(fields[0]!.props('modelValue')).toEqual(['401'])
|
||||
expect(api.getDispatchEvidence).toHaveBeenCalledWith('PC/1', 'VEHICLE', '401')
|
||||
expect(api.getDispatchEvidenceContent).toHaveBeenCalledWith('PC/1', 'VEHICLE', '401')
|
||||
expect(fields[1]!.props('modelValue')).toEqual(['402', '403'])
|
||||
expect(dialog.findAll('input[type="file"]')).toHaveLength(0)
|
||||
expect(api.uploadDispatchEvidence).not.toHaveBeenCalled()
|
||||
|
||||
Reference in New Issue
Block a user