fix: require appointment cancellation reason and expose history

This commit is contained in:
2026-10-11 13:27:39 +08:00
parent d77abbef7c
commit 240aa5d6d0
8 changed files with 272 additions and 26 deletions
@@ -31,6 +31,9 @@ const candidates = [
]
function render(openCalendar = true) {
const wrapper = mount(AppointmentCalendarView, { global: { directives: { loading: {} }, stubs: {
AppointmentCancellationDialog: {name:'AppointmentCancellationDialog',template:'<div>取消弹窗</div>'},
AppointmentCancellationHistory: {name:'AppointmentCancellationHistory',template:'<div>取消历史详情</div>'},
AppointmentCancellationRecords: {name:'AppointmentCancellationRecords',template:'<button data-history-view @click="$emit(\'view\',\'AP-CANCEL\')">查看取消记录</button>'},
AdminPage: { template: '<main><slot /></main>' },
AppointmentContainerPanel: { name: 'AppointmentContainerPanel', setup() {
const register = inject<(guard: () => boolean) => () => void>('appointment-register-leave-guard')!
@@ -67,6 +70,38 @@ describe('appointment calendar data integration', () => {
vi.mocked(createFbaAppointment).mockResolvedValue({ version: 0, id: '1', appointmentNo: 'APT-AB', plannedDate: '2026-10-09', appointmentAt: null, originWarehouseId: '100', appointmentStatus: 'PENDING', selectedCount: 2, fbaWarehouseCode: 'ONT8', items: [] })
})
it('loads cancellation records only after expansion and opens cancelled appointments read-only', async () => {
const record = { version: 1, id: '1', appointmentNo: 'AP-CANCEL', originWarehouseId: '100', appointmentStatus: 'CANCELLED', selectedCount: 1, fbaWarehouseCode: 'ABE3', items: [] }
vi.mocked(getFbaAppointment).mockResolvedValue(record)
const wrapper=render();await flushPromises()
expect(wrapper.findComponent({name:'AppointmentCancellationRecords'}).exists()).toBe(false)
const records=wrapper.findAll('details').find(d=>d.find('summary').text()==='取消记录')!
;(records.element as HTMLDetailsElement).open=true;await records.trigger('toggle')
await wrapper.get('[data-history-view]').trigger('click');await flushPromises()
expect(getFbaAppointment).toHaveBeenCalledWith('AP-CANCEL')
expect(wrapper.find('[data-save]').exists()).toBe(false)
expect(wrapper.findComponent({name:'FbaAppointmentFields'}).props('disabled')).toBe(true)
expect(wrapper.findComponent({name:'AppointmentCancellationHistory'}).exists()).toBe(false)
const history=wrapper.findAll('details').find(d=>d.find('summary').text()==='取消历史')!
;(history.element as HTMLDetailsElement).open=true;await history.trigger('toggle')
expect(wrapper.findComponent({name:'AppointmentCancellationHistory'}).exists()).toBe(true)
wrapper.findAllComponents({name:'AppDialog'}).at(-1)!.vm.$emit('confirm');await flushPromises()
expect(updateFbaAppointment).not.toHaveBeenCalled();wrapper.unmount()
})
it('refreshes an expanded cancellation list after a successful cancellation', async () => {
vi.mocked(listFbaAppointmentCalendar).mockResolvedValue([{version:0,id:'1',appointmentNo:'AP-CANCEL',originWarehouseId:'100',appointmentStatus:'PENDING',selectedCount:1,fbaWarehouseCode:'ABE3',items:[],plannedDate:'2026-10-15'}])
const wrapper=render();await flushPromises()
const records=wrapper.findAll('details').find(d=>d.find('summary').text()==='取消记录')!
;(records.element as HTMLDetailsElement).open=true;await records.trigger('toggle')
const previous=wrapper.getComponent({name:'AppointmentCancellationRecords'}).vm
wrapper.getComponent({name:'AppointmentCalendarPanel'}).vm.$emit('delete',{key:'AP-CANCEL'});await flushPromises()
wrapper.getComponent({name:'AppointmentCancellationDialog'}).vm.$emit('cancelled');await flushPromises()
expect(wrapper.getComponent({name:'AppointmentCancellationRecords'}).vm).not.toBe(previous)
expect(wrapper.findComponent({name:'AppointmentCancellationDialog'}).exists()).toBe(false)
wrapper.unmount()
})
it('keeps the container view mounted while a child has an unresolved command', async () => {
const wrapper = render(); await flushPromises()
const tabs = wrapper.get('[aria-label="预约工作视图"]').findAll('button')
@@ -150,7 +185,7 @@ describe('appointment calendar data integration', () => {
vi.mocked(listTripCalendar).mockResolvedValueOnce({records:[],unresolvedRecords:[{sourceType:'TRIP_PLAN',tripNo:'TR-UNKNOWN',status:'PLANNED',originWarehouseId:null,originWarehouseCode:null,originWarehouseName:null,originCountryCode:null,originTimezone:null,originWarehouseStatus:null,plannedDepartureAt:'2026-10-10T12:00:00Z',expectedDriverEndAt:null,departedAt:null,completedAt:null,stops:[],incompleteReasons:['ORIGIN_WAREHOUSE_UNKNOWN']}]})
const wrapper=render();await flushPromises()
expect(wrapper.findComponent({name:'AppointmentCalendarPanel'}).props('events')).toEqual([])
expect(wrapper.find('.appointment-extra').exists()).toBe(false)
expect(wrapper.findAll('.appointment-extra summary').map(node => node.text())).not.toContain('待核实地点的车次(1)')
expect(wrapper.text()).not.toContain('原计划时间保留 UTC')
await wrapper.findAll('button').find(button => button.text() === '查看待核实车次(1)')!.trigger('click')
expect(wrapper.text()).toContain('原计划时间保留 UTC')