fix: align appointment procurement and carpool workflows with agreed views

This commit is contained in:
2026-10-10 15:33:10 +08:00
parent 172cb05c78
commit 0cb8a5c2b2
18 changed files with 407 additions and 58 deletions
@@ -27,10 +27,11 @@ const candidates = [
{ lineId: '9007199254740993', customerId: 'A', overseasWarehouseId: '100', fbaWarehouseCode: 'ONT8', planId: '1', planNo: 'IN-A', orderId: '10' },
{ lineId: '9007199254740994', customerId: 'B', overseasWarehouseId: '100', fbaWarehouseCode: 'ONT8', planId: '2', planNo: 'IN-B', orderId: '20' },
]
function render() {
return mount(AppointmentCalendarView, { global: { directives: { loading: {} }, stubs: {
function render(openCalendar = true) {
const wrapper = mount(AppointmentCalendarView, { global: { directives: { loading: {} }, stubs: {
AdminPage: { template: '<main><slot /></main>' },
AppointmentCalendarPanel: { name: 'AppointmentCalendarPanel', props: ['events', 'incomplete'], template: '<button data-create @click="$emit(\'create\', \'2026-10-09\')">新增预约</button>' },
AppointmentContainerPanel: true,
AppointmentCalendarPanel: { name: 'AppointmentCalendarPanel', mounted() { this.$emit('layers', { arrivals: true, trips: true }) }, props: ['events', 'incomplete'], template: '<button data-create @click="$emit(\'create\', \'2026-10-09\')">新增预约</button>' },
AppDialog: { props: ['modelValue'], template: '<div v-if="modelValue"><slot /><button data-save @click="$emit(\'confirm\')">保存</button></div>' },
ElForm: { template: '<form><slot /></form>' },
ElFormItem: { template: '<label><slot /></label>' },
@@ -42,6 +43,8 @@ function render() {
DataTable: { name: 'DataTable', props: ['data'], template: '<div><slot name="toolbar-actions" /><button data-select @click="$emit(\'selection-change\', data)">选择货物</button></div>' },
LoadErrorState: true, ApiErrorMeta: true, AppointmentFollowupDialog: true, AppointmentCargoPanel: { name: 'AppointmentCargoPanel', props: ['externalSource'], template: '<div>合批工作区</div>' },
} } })
if (openCalendar) void wrapper.findAll('button').find(button => button.text() === '预约日历')!.trigger('click')
return wrapper
}
describe('appointment calendar data integration', () => {
@@ -58,6 +61,25 @@ 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('keeps exactly the documented three work views and defaults to the container list without calendar requests', async () => {
const wrapper = render(false); await flushPromises()
const tabs = wrapper.get('[aria-label="预约工作视图"]').findAll('button')
expect(tabs.map(button => button.text())).toEqual(['提柜与到仓', '送仓与排车', '预约日历'])
expect(tabs[0]!.attributes('aria-pressed')).toBe('true')
expect(wrapper.text()).toContain('美国预约总览')
expect(listFbaAppointmentCalendar).not.toHaveBeenCalled()
expect(listArrivalCalendar).not.toHaveBeenCalled()
await tabs[2]!.trigger('click'); await flushPromises()
expect(listFbaAppointmentCalendar).toHaveBeenCalledTimes(1)
await tabs[0]!.trigger('click'); await tabs[2]!.trigger('click'); await flushPromises()
expect(listFbaAppointmentCalendar).toHaveBeenCalledTimes(1)
})
it('distinguishes missing country data from truncation instead of suggesting a narrower date range', async () => {
vi.mocked(listPickupCalendar).mockResolvedValueOnce({ records: [], truncated: false, unclassifiedCount: 74, scopeBasis: 'US_DESTINATION_WAREHOUSE', timeBasis: 'SOURCE_LOCAL_UNSPECIFIED' })
const wrapper = render(); await flushPromises()
expect(wrapper.text()).toContain('74 条提柜记录')
expect(wrapper.text()).not.toContain('缩小日期范围')
})
it('shows the original pickup time once without claiming a port time zone and retains partial-source warnings', async () => {
vi.mocked(listPickupCalendar).mockResolvedValueOnce({records: [{containerBookingId: '123',bookingNo: 'CB-TEST',containerNo: 'TEST-CONT',destinationPortName: 'Port',destinationWarehouseCode: 'US-W',fleetSupplierName: 'Fleet',pickupAppointmentAt: '2026-10-09T11:00:00',actualPickupAt: null}],truncated: false,unclassifiedCount: 1,scopeBasis: 'US_DESTINATION_WAREHOUSE',timeBasis: 'SOURCE_LOCAL_UNSPECIFIED'})
const wrapper=render(); await flushPromises()
@@ -119,6 +141,7 @@ describe('appointment calendar data integration', () => {
})
it('only searches active FBA warehouses and loads cargo automatically after selection', async () => {
const wrapper = render()
await flushPromises()
await wrapper.get('[data-create]').trigger('click')
await flushPromises()
expect(listPlatformWarehouses).toHaveBeenCalledWith(expect.objectContaining({ warehouseType: 'FBA', status: 'ACTIVE', size: 50 }))
@@ -153,6 +176,7 @@ describe('appointment calendar data integration', () => {
it('changing or clearing the warehouse clears prior cargo selection and blocks saving it', async () => {
const wrapper = render()
await flushPromises()
await wrapper.get('[data-create]').trigger('click')
await flushPromises()
await wrapper.get('select[aria-label="预约仓库"]').setValue('ONT8')
@@ -170,6 +194,7 @@ describe('appointment calendar data integration', () => {
let resolveOld!: (value: Awaited<ReturnType<typeof listInboundOrders>>) => void
vi.mocked(listInboundOrders).mockImplementationOnce(() => new Promise(resolve => { resolveOld = resolve }))
const wrapper = render()
await flushPromises()
await wrapper.get('[data-create]').trigger('click')
await flushPromises()
await wrapper.get('select[aria-label="预约仓库"]').setValue('ONT8')
@@ -183,6 +208,7 @@ describe('appointment calendar data integration', () => {
it('searches by keyword and exposes warehouse failures without accepting free text', async () => {
const wrapper = render()
await flushPromises()
await wrapper.get('[data-create]').trigger('click')
await flushPromises()
const select = wrapper.findAllComponents({ name: 'ElSelect' }).find(item => item.props('remoteMethod'))!