2026-08-10 15:36:53 +08:00
|
|
|
import ElementPlus from 'element-plus'
|
|
|
|
|
import { createPinia, setActivePinia } from 'pinia'
|
|
|
|
|
import { createMemoryHistory, createRouter } from 'vue-router'
|
|
|
|
|
import { flushPromises, mount } from '@vue/test-utils'
|
|
|
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
|
import ContainersView from './ContainersView.vue'
|
|
|
|
|
import { listAllPlatformWarehouses } from '@/modules/warehouses'
|
|
|
|
|
import { listContainers } from '../api/platformContainerLoading'
|
|
|
|
|
|
|
|
|
|
vi.mock('@/modules/warehouses', () => ({ listAllPlatformWarehouses: vi.fn() }))
|
2026-08-11 11:15:44 +08:00
|
|
|
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) }))
|
2026-08-10 15:36:53 +08:00
|
|
|
vi.mock('../api/platformContainerLoading', () => ({ listContainers: vi.fn(), getContainer: vi.fn(), createContainer: vi.fn(), updateContainer: vi.fn(), updateContainerTransport: vi.fn() }))
|
|
|
|
|
|
2026-08-11 11:15:44 +08:00
|
|
|
function createTestRouter() {
|
|
|
|
|
return createRouter({ history: createMemoryHistory(), routes: [
|
|
|
|
|
{ path: '/', component: ContainersView },
|
|
|
|
|
{ path: '/container-loading/:containerId/smart-loading', name: 'smart-loading-workbench', component: { template: '<div />' } },
|
|
|
|
|
{ path: '/loading-plans', name: 'loading-plans', component: { template: '<div />' } },
|
|
|
|
|
{ path: '/loading-lists', name: 'loading-lists', component: { template: '<div />' } },
|
|
|
|
|
] })
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-10 15:36:53 +08:00
|
|
|
describe('ContainersView', () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
setActivePinia(createPinia())
|
|
|
|
|
vi.mocked(listAllPlatformWarehouses).mockResolvedValue([])
|
2026-08-11 11:52:30 +08:00
|
|
|
vi.mocked(listContainers).mockResolvedValue({ records: [{ id: '9001', planId: null, bookingNo: 'BK-1', cabinetNo: 'CB-1', containerNo: 'MSCU-1', warehouseId: '8', warehouseName: '义乌仓', containerType: '40HQ', planStatus: 'WAIT_LOADING', version: 0, billOfLadingNo: null, vesselName: null, voyageNo: null, shippingCompanyId: null, shippingCompanyName: null, departurePortCode: null, departurePortName: '宁波', destinationPortCode: null, destinationPortName: '长滩', destinationWarehouseCode: null, destinationWarehouseName: null, capacityCbm: 68, maxWeightKg: 28000, terminalTruckingCompany: null, loadingAt: null, estimatedSailingAt: null, actualSailingAt: null, estimatedPortArrivalAt: null, actualPortArrivalAt: null, estimatedWarehouseArrivalAt: null, actualWarehouseArrivalAt: null }], page: 1, size: 20, total: 1, pages: 1 })
|
2026-08-10 15:36:53 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('loads the real paged contract and renders core container fields', async () => {
|
2026-08-11 11:15:44 +08:00
|
|
|
const router = createTestRouter()
|
2026-08-10 15:36:53 +08:00
|
|
|
await router.push('/'); await router.isReady()
|
|
|
|
|
const wrapper = mount(ContainersView, { global: { plugins: [ElementPlus, router] } })
|
|
|
|
|
await flushPromises()
|
|
|
|
|
expect(listContainers).toHaveBeenCalledWith(expect.objectContaining({ page: 1, size: 20 }))
|
2026-08-11 11:52:30 +08:00
|
|
|
expect(wrapper.text()).toContain('待装柜')
|
2026-08-10 15:36:53 +08:00
|
|
|
expect(wrapper.text()).toContain('CB-1')
|
|
|
|
|
expect(wrapper.text()).toContain('MSCU-1')
|
|
|
|
|
expect(wrapper.text()).toContain('宁波 → 长滩')
|
|
|
|
|
expect(wrapper.find('button[aria-label="查看 CB-1"]').exists()).toBe(true)
|
|
|
|
|
})
|
2026-08-10 17:42:17 +08:00
|
|
|
|
2026-08-11 11:15:44 +08:00
|
|
|
it('keeps the cross-warehouse list usable when warehouse form options fail', async () => {
|
|
|
|
|
vi.mocked(listAllPlatformWarehouses).mockRejectedValueOnce(new Error('warehouse unavailable'))
|
|
|
|
|
const router = createTestRouter()
|
|
|
|
|
await router.push('/'); await router.isReady()
|
|
|
|
|
const wrapper = mount(ContainersView, { global: { plugins: [ElementPlus, router] } })
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
expect(wrapper.text()).toContain('CB-1')
|
|
|
|
|
expect(wrapper.text()).not.toContain('装柜仓库加载失败')
|
|
|
|
|
expect(wrapper.find('button[aria-label="查看 CB-1"]').exists()).toBe(true)
|
|
|
|
|
})
|
|
|
|
|
|
2026-08-10 17:42:17 +08:00
|
|
|
it('uses stable view labels when cabinetNo is missing', async () => {
|
|
|
|
|
const base = {
|
2026-08-11 11:52:30 +08:00
|
|
|
id: '9001', planId: null, bookingNo: 'BK-1', cabinetNo: 'CB-1', containerNo: 'MSCU-1', warehouseId: '8', warehouseName: '义乌仓', containerType: '40HQ', planStatus: 'WAIT_LOADING' as const, version: 0,
|
2026-08-10 17:42:17 +08:00
|
|
|
billOfLadingNo: null, vesselName: null, voyageNo: null, shippingCompanyId: null, shippingCompanyName: null,
|
|
|
|
|
departurePortCode: null, departurePortName: '宁波', destinationPortCode: null, destinationPortName: '长滩',
|
|
|
|
|
destinationWarehouseCode: null, destinationWarehouseName: null, capacityCbm: 68, maxWeightKg: 28000,
|
|
|
|
|
terminalTruckingCompany: null, loadingAt: null, estimatedSailingAt: null, actualSailingAt: null,
|
|
|
|
|
estimatedPortArrivalAt: null, actualPortArrivalAt: null, estimatedWarehouseArrivalAt: null, actualWarehouseArrivalAt: null,
|
|
|
|
|
}
|
|
|
|
|
vi.mocked(listContainers).mockResolvedValueOnce({
|
|
|
|
|
records: [
|
|
|
|
|
{ ...base, id: '9002', cabinetNo: undefined, containerNo: 'MSCU-2', bookingNo: 'BK-2' },
|
|
|
|
|
{ ...base, id: '9003', cabinetNo: '', containerNo: null, bookingNo: 'BK-3' },
|
|
|
|
|
{ ...base, id: '9004', cabinetNo: null, containerNo: null, bookingNo: '' },
|
|
|
|
|
],
|
|
|
|
|
page: 1, size: 20, total: 3, pages: 1,
|
|
|
|
|
} as never)
|
2026-08-11 11:15:44 +08:00
|
|
|
const router = createTestRouter()
|
2026-08-10 17:42:17 +08:00
|
|
|
await router.push('/'); await router.isReady()
|
|
|
|
|
const wrapper = mount(ContainersView, { global: { plugins: [ElementPlus, router] } })
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
const labels = wrapper.findAll('.el-table__body button')
|
|
|
|
|
.map((button) => button.attributes('aria-label'))
|
|
|
|
|
.filter((label): label is string => Boolean(label))
|
|
|
|
|
expect(labels).toEqual(expect.arrayContaining(['查看 MSCU-2', '查看 BK-3', '查看货柜详情']))
|
|
|
|
|
expect(labels.every((label) => !/undefined|null/.test(label))).toBe(true)
|
|
|
|
|
})
|
2026-08-11 11:15:44 +08:00
|
|
|
|
|
|
|
|
it('routes each plan status to its owning workflow without reopening pushed drafts', async () => {
|
|
|
|
|
const base = {
|
|
|
|
|
id: '9001', planId: '9101', bookingNo: 'BK-1', cabinetNo: 'CB-1', containerNo: 'MSCU-1', warehouseId: '8', warehouseName: '义乌仓', containerType: '40HQ', version: 0,
|
|
|
|
|
billOfLadingNo: null, vesselName: null, voyageNo: null, shippingCompanyId: null, shippingCompanyName: null,
|
|
|
|
|
departurePortCode: null, departurePortName: '宁波', destinationPortCode: null, destinationPortName: '长滩',
|
|
|
|
|
destinationWarehouseCode: null, destinationWarehouseName: null, capacityCbm: 68, maxWeightKg: 28000,
|
|
|
|
|
terminalTruckingCompany: null, loadingAt: null, estimatedSailingAt: null, actualSailingAt: null,
|
|
|
|
|
estimatedPortArrivalAt: null, actualPortArrivalAt: null, estimatedWarehouseArrivalAt: null, actualWarehouseArrivalAt: null,
|
|
|
|
|
}
|
|
|
|
|
vi.mocked(listContainers).mockResolvedValueOnce({
|
|
|
|
|
records: [
|
|
|
|
|
{ ...base, planStatus: 'EDITING' as const },
|
|
|
|
|
{ ...base, id: '9002', planId: '9102', cabinetNo: 'CB-2', planStatus: 'LOADING' as const },
|
|
|
|
|
{ ...base, id: '9003', planId: '9103', cabinetNo: 'CB-3', planStatus: 'COMPLETED' as const },
|
|
|
|
|
],
|
|
|
|
|
page: 1, size: 20, total: 3, pages: 1,
|
|
|
|
|
})
|
|
|
|
|
const router = createTestRouter()
|
|
|
|
|
await router.push('/'); await router.isReady()
|
|
|
|
|
const push = vi.spyOn(router, 'push').mockResolvedValue(undefined as never)
|
|
|
|
|
const wrapper = mount(ContainersView, { global: { plugins: [ElementPlus, router] } })
|
|
|
|
|
await flushPromises()
|
|
|
|
|
|
|
|
|
|
expect(wrapper.text()).toContain('排柜')
|
|
|
|
|
expect(wrapper.text()).toContain('查看预装清单')
|
|
|
|
|
expect(wrapper.text()).toContain('查看装柜清单')
|
|
|
|
|
|
|
|
|
|
await wrapper.findAll('button').find((button) => button.text().trim() === '排柜')!.trigger('click')
|
|
|
|
|
await wrapper.findAll('button').find((button) => button.text().includes('查看预装清单'))!.trigger('click')
|
|
|
|
|
await wrapper.findAll('button').find((button) => button.text().includes('查看装柜清单'))!.trigger('click')
|
|
|
|
|
expect(push).toHaveBeenNthCalledWith(1, { name: 'smart-loading-workbench', params: { containerId: '9001' } })
|
|
|
|
|
expect(push).toHaveBeenNthCalledWith(2, { name: 'loading-plans', query: { planId: '9102', warehouseId: '8' } })
|
|
|
|
|
expect(push).toHaveBeenNthCalledWith(3, { name: 'loading-lists', query: { planId: '9103', warehouseId: '8' } })
|
|
|
|
|
})
|
2026-08-10 15:36:53 +08:00
|
|
|
})
|