fix(fleet): preserve retry intent and restore inquiry editing

This commit is contained in:
2026-10-03 13:00:32 +08:00
parent 0b5094dd8f
commit 3440f9dd11
9 changed files with 152 additions and 14 deletions
@@ -0,0 +1,44 @@
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
import { shallowMount, flushPromises, type VueWrapper } from '@vue/test-utils'
import FleetQuoteEditor from './FleetQuoteEditor.vue'
import { ApiResponseError } from '@/shared/api/http'
import * as api from '../api/fleetQuotes'
vi.mock('../api/fleetQuotes', async original => ({ ...(await original<typeof import('../api/fleetQuotes')>()), createFleetQuote: vi.fn(), updateFleetQuote: vi.fn() }))
const wrappers: VueWrapper[] = []
const input = (name: string) => ({ name, props: ['modelValue'], emits: ['update:modelValue'], template: '<input :value="modelValue" />' })
const slot = { template: '<div><slot/></div>' }
async function mount() {
const wrapper = shallowMount(FleetQuoteEditor, { props: { modelValue: false, quote: null, kind: 'SALE' }, global: { stubs: {
AppDialog: { props: ['modelValue'], template: '<div v-if="modelValue"><slot/><slot name="footer"/></div>' }, ElForm: { name: 'ElForm', props: ['disabled'], template: '<div><slot/></div>' },
ElFormItem: slot, ElInput: input('ElInput'), ElInputNumber: input('ElInputNumber'), ElDatePicker: input('ElDatePicker'), ElSelect: slot, ElOption: true,
FleetQuotePartySelect: input('FleetQuotePartySelect'), ElButton: { template: '<button><slot/></button>' }, ElAlert: { props: ['title'], template: '<p>{{ title }}<slot/></p>' }, ApiErrorMeta: true,
} } }); wrappers.push(wrapper); await wrapper.setProps({ modelValue: true }); await flushPromises()
wrapper.findComponent({ name: 'FleetQuotePartySelect' }).vm.$emit('update:modelValue', '101')
wrapper.findAllComponents({ name: 'ElInput' })[1]!.vm.$emit('update:modelValue', 'QA-Origin')
wrapper.findAllComponents({ name: 'ElInput' })[2]!.vm.$emit('update:modelValue', 'QA-DEST')
wrapper.findAllComponents({ name: 'ElInputNumber' })[0]!.vm.$emit('update:modelValue', 10)
wrapper.findAllComponents({ name: 'ElInputNumber' })[2]!.vm.$emit('update:modelValue', 0)
wrapper.findAllComponents({ name: 'ElDatePicker' })[1]!.vm.$emit('update:modelValue', '2100-01-01')
await flushPromises(); return wrapper
}
async function clickSave(wrapper: VueWrapper) { await wrapper.findAll('button').find(b => ['保存报价', '按原请求重试'].includes(b.text()))!.trigger('click'); await flushPromises() }
beforeEach(() => vi.clearAllMocks()); afterEach(() => wrappers.splice(0).forEach(w => w.unmount()))
it('HTTP 200/A0409 unlocks the form so corrected content receives a new key', async () => {
const wrapper = await mount(); vi.mocked(api.createFleetQuote).mockRejectedValueOnce(new ApiResponseError('报价组合重复', 'A0409', 200))
await clickSave(wrapper); const original = vi.mocked(api.createFleetQuote).mock.calls[0]!
expect(wrapper.findComponent({ name: 'ElForm' }).props('disabled')).toBe(false); expect(wrapper.text()).not.toContain('按原请求重试')
wrapper.findAllComponents({ name: 'ElInput' })[1]!.vm.$emit('update:modelValue', 'QA-Another-Origin')
vi.mocked(api.createFleetQuote).mockResolvedValue({ quoteNo: 'FQ-NEW', details: original[1], recordVersion: '0', partyName: '测试客户', status: 'ACTIVE', updatedAt: '' })
await clickSave(wrapper)
const corrected = vi.mocked(api.createFleetQuote).mock.calls[1]!
expect(corrected[0]).not.toBe(original[0]); expect(corrected[1].originCity).toBe('QA-Another-Origin'); expect(corrected[1].fullDeliveryPrice).toBe(0)
})
it('unknown creation retains its exact key after viewing another quote', async () => {
const wrapper = await mount(); vi.mocked(api.createFleetQuote).mockRejectedValueOnce(new Error('Network unavailable'))
await clickSave(wrapper); const original = vi.mocked(api.createFleetQuote).mock.calls[0]!
const other: api.FleetQuote = { quoteNo: 'FQ-OTHER', details: { ...original[1], originCity: 'OTHER' }, recordVersion: '2', partyName: '测试客户', status: 'ACTIVE', updatedAt: '' }
await wrapper.setProps({ modelValue: false }); await wrapper.setProps({ quote: other, readonly: true, modelValue: true }); await flushPromises()
await wrapper.setProps({ modelValue: false }); await wrapper.setProps({ quote: null, readonly: false, modelValue: true }); await flushPromises()
expect(wrapper.text()).toContain('按原请求重试'); vi.mocked(api.createFleetQuote).mockResolvedValue({ ...other, quoteNo: 'FQ-NEW', details: original[1] })
await clickSave(wrapper); expect(vi.mocked(api.createFleetQuote).mock.calls[1]).toEqual(original)
})