This commit is contained in:
2026-10-09 17:36:32 +08:00
parent 7a9e91b7ce
commit 3df3f874db
25 changed files with 431 additions and 12 deletions
@@ -9,6 +9,10 @@ import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import { cancelDispatch, getDispatchBolPdf, getDispatchExternalFreight, getDispatchFeeCoverage, listDispatches, removeDispatchItem, transferDispatchToDelivery, updateDispatch } from '../api/dispatches'
import DeliveryFeeCoveragePanel from '../components/DeliveryFeeCoveragePanel.vue'
import DispatchesView from './DispatchesView.vue'
vi.mock('@/modules/warehouses', () => ({
listAllPlatformWarehouses: vi.fn(async (query: { keyword: string }) => [{ id: query.keyword, warehouseCode: query.keyword, warehouseType: 'FBA' }]),
getPlatformWarehouse: vi.fn(async (id: string) => ({ warehouse: { warehouseCode: id, warehouseType: id === '321' ? 'OVERSEAS' : 'FBA' }, addresses: [{ addressType: 'OPERATING', addressLine1: '100 Example Street', city: 'City', stateProvince: 'CA', countryCode: 'US' }], capabilities: [] })),
}))
const push = vi.hoisted(() => vi.fn())
vi.mock('vue-router', () => ({ useRouter: () => ({ push }) }))
@@ -44,8 +48,8 @@ describe('DispatchesView', () => {
vi.mocked(listDispatches).mockReset().mockResolvedValue({
records: [{
id: '190000000000000099', dispatchNo: 'PC-1', vehiclePlate: 'CA-100', driverName: '张师傅',
driverPhone: '555-0100', carrierName: 'Carrier A', orderNos: 'LM-1,LM-2', route: 'LAX -> ONT8',
overseasWarehouseName: '洛杉矶仓', departAt: '2026-08-20T09:00:00', fbaAppointmentNo: 'FBA-1',
driverPhone: '555-0100', carrierName: 'Carrier A', orderNos: 'LM-1,LM-2', route: 'ONT8,LAX9',
overseasWarehouseId: '321', overseasWarehouseName: '洛杉矶仓', departAt: '2026-08-20T09:00:00', fbaAppointmentNo: 'FBA-1',
fbaAppointmentStatus: 'CONFIRMED', vehicleAppointmentStatus: 'BOOKED', estimatedArrivalAt: '2026-08-20T18:00:00',
status: 'PENDING_DEPARTURE', palletCount: 12, packageCount: 80, createdAt: '2026-08-19T16:00:00',
}],
@@ -78,6 +82,25 @@ describe('DispatchesView', () => {
expect(listDispatches).toHaveBeenLastCalledWith(expect.objectContaining({ stage: 'AFTER_LOADING', page: 1 }))
})
it('shows the shared route map only in the after-loading vehicle section without another query', async () => {
const wrapper = mount(DispatchesView, { attachTo: document.body, global: { plugins: [ElementPlus] } })
await flushPromises()
expect(wrapper.text()).not.toContain('查看路线')
await wrapper.get('[aria-label="排车执行阶段"]').findAll('button')[3]!.trigger('click')
await flushPromises()
const requests = vi.mocked(listDispatches).mock.calls.length
await wrapper.findAll('button').find(button => button.text() === '查看路线')!.trigger('click')
await flushPromises()
expect(wrapper.findComponent({ name: 'TransportRouteDialog' }).props('modelValue')).toBe(true)
expect(wrapper.findComponent({ name: 'TransportRouteDialog' }).props('origin')).toEqual({ kind: 'warehouse', label: '洛杉矶仓', warehouseId: '321' })
expect(wrapper.findComponent({ name: 'TransportRouteDialog' }).props('destinations')).toEqual(['ONT8', 'LAX9'].map(code => ({ kind: 'warehouse', label: code, warehouseCode: code })))
expect(listDispatches).toHaveBeenCalledTimes(requests)
await wrapper.get('[aria-label="排车执行阶段"]').findAll('button')[1]!.trigger('click')
await flushPromises()
await wrapper.get('[aria-label="排车业务分区"]').findAll('button')[1]!.trigger('click')
expect(wrapper.findAll('button').some(button => button.text() === '查看路线')).toBe(false)
})
it('shows review facts and opens the matching trip section with read permission', async () => {
const result = await listDispatches({ page: 1, size: 10 })
result.records[0]!.workflow = { tripNo: 'TR-A', dispatchReview: { status: 'REJECTED', reason: '请核对货量', reviewedAt: null }, loadingReview: { status: 'PENDING', reason: null, reviewedAt: null } }
@@ -86,6 +109,9 @@ describe('DispatchesView', () => {
const wrapper = mount(DispatchesView, { global: { plugins: [ElementPlus] } })
await flushPromises()
const sections = wrapper.get('[aria-label="排车业务分区"]')
expect(sections.findAll('button').map(button => button.text())).toEqual(['车辆信息'])
await wrapper.get('[aria-label="排车执行阶段"]').findAll('button')[1]!.trigger('click')
await flushPromises()
expect(sections.findAll('button').map(button => button.text())).toEqual(['车辆信息', '调度审核', '理货员审核'])
expect(wrapper.findAll('[role="tablist"]')).toHaveLength(2)
expect(wrapper.text()).not.toContain('请核对货量')
@@ -103,7 +129,28 @@ describe('DispatchesView', () => {
await links[0]!.trigger('click')
expect(push).toHaveBeenLastCalledWith({ name: 'overseas-master-data-trip-detail', params: { tripNo: 'TR-A' }, query: { tab: 'loading' } })
expect(wrapper.text()).not.toContain('前往审核')
expect(listDispatches).toHaveBeenCalledTimes(1)
expect(listDispatches).toHaveBeenCalledTimes(2)
})
it.each([0, 2, 3, 4].flatMap(stageIndex => [1, 2].map(sectionIndex => [stageIndex, sectionIndex])))('leaving a review section for stage %s resets section %s to vehicle information', async (stageIndex, sectionIndex) => {
const wrapper = mount(DispatchesView, { global: { plugins: [ElementPlus] } })
await flushPromises()
const stages = wrapper.get('[aria-label="排车执行阶段"]').findAll('button')
const sections = wrapper.get('[aria-label="排车业务分区"]')
await stages[1]!.trigger('click')
await flushPromises()
await sections.findAll('button')[sectionIndex]!.trigger('click')
expect(wrapper.findAll('button').some(button => button.text() === '打印BOL')).toBe(false)
await stages[stageIndex]!.trigger('click')
await flushPromises()
expect(sections.findAll('button').map(button => button.text())).toEqual(['车辆信息'])
expect(sections.get('button').attributes('aria-selected')).toBe('true')
expect(wrapper.findAll('button').some(button => button.text() === '打印BOL')).toBe(true)
expect(wrapper.findAll('button').some(button => ['前往审核', '查看审核'].includes(button.text()))).toBe(false)
await stages[1]!.trigger('click')
await flushPromises()
expect(sections.findAll('button').map(button => button.text())).toEqual(['车辆信息', '调度审核', '理货员审核'])
expect(sections.get('button').attributes('aria-selected')).toBe('true')
})
it.each([