Files
admin-web/src/modules/unified-orders/pages/UnifiedOrdersView.requests.test.ts
T

469 lines
26 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { flushPromises, shallowMount } from '@vue/test-utils'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { getPlatformUnifiedOrderStatusCounts, listPlatformUnifiedOrders, updatePlatformUnifiedOrderPlanning } from '@/modules/unified-orders/api/unifiedOrders'
import { createPlatformExportTask } from '@/modules/downloads'
import { showExportTaskCreatedDialog } from '@/shared/components/exportTaskCreatedDialog'
import { ApiResponseError } from '@/shared/api/http'
import { ElMessage } from 'element-plus'
import UnifiedOrdersView from './UnifiedOrdersView.vue'
vi.mock('vue-router', () => ({
useRoute: () => ({ params: {}, query: {} }),
useRouter: () => ({ push: vi.fn() }),
}))
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => true }) }))
vi.mock('@/modules/iam', async importOriginal => ({
...await importOriginal<typeof import('@/modules/iam')>(), listPlatformTenants: vi.fn().mockResolvedValue({ records: [], page: 1, size: 200, total: 0, pages: 0 }) }))
vi.mock('@/modules/warehouses', () => ({ listAllPlatformWarehouses: vi.fn().mockResolvedValue([]) }))
vi.mock('@/modules/inbounds', async () => {
const { defineComponent } = await import('vue')
return {
downloadWeightImage: vi.fn(), getInboundMeasurement: vi.fn(),
InboundTaskList: defineComponent({
name: 'InboundTaskList', props: ['mode', 'title', 'taskLoader'],
methods: { reload() { return this.taskLoader({ page: 1, size: 20 }) } },
mounted() { void this.reload() },
template: '<section><slot name="filters" :loading="false" /><slot name="status-tabs" /></section>',
}),
}
})
vi.mock('@/modules/downloads', () => ({ createPlatformExportTask: vi.fn() }))
vi.mock('@/shared/components/exportTaskCreatedDialog', () => ({ showExportTaskCreatedDialog: vi.fn() }))
vi.mock('@/modules/unified-orders/workflows', () => ({ UnifiedOrderWorkflowPanel: { template: '<div />' } }))
vi.mock('@/modules/unified-orders/api/coLoadGroups', () => ({
cancelPlatformCoLoadGroup: vi.fn(),
createPlatformCoLoadGroup: vi.fn(),
getPlatformCoLoadGroupByInboundCode: vi.fn(),
}))
vi.mock('@/modules/unified-orders/api/unifiedOrders', () => ({
updatePlatformUnifiedOrderRemarks: vi.fn(),
approvePlatformUnifiedOrder: vi.fn(),
getPlatformUnifiedOrder: vi.fn(),
listPlatformUnifiedOrderFeeDetails: vi.fn(),
getPlatformUnifiedOrderStatusCounts: vi.fn().mockResolvedValue({ counts: {} }), listPlatformUnifiedOrders: vi.fn(),
updatePlatformUnifiedOrderPlanning: vi.fn(),
unifiedOrderStatusOptions: [
{ value: 'PENDING_REVIEW', label: '待审核' },
{ value: 'WAIT_MEASURE', label: '待测量数据' },
{ value: 'WAIT_SPLIT', label: '待装柜' },
{ value: 'LOADING', label: '装柜中' },
{ value: 'LOADED', label: '装柜完成' },
{ value: 'DELIVERING', label: '派送中' },
{ value: 'SIGNED', label: '派送完成' },
],
}))
function emptyPage() {
return { records: [], page: 1, size: 20, total: 0, pages: 0 }
}
function mountView() {
return shallowMount(UnifiedOrdersView, {
global: {
directives: { loading: () => undefined },
stubs: {
AdminPage: { template: '<main><slot /></main>' },
InboundTaskList: false,
ListPageLayout: { template: '<section><slot name="toolbar" /><slot name="state" /><slot /></section>' },
QueryToolbar: { name: 'QueryToolbar', props: ['modelValue', 'fields', 'maxVisible'], emits: ['update:modelValue', 'search', 'reset'], template: '<div data-testid="query-toolbar"><slot name="actions" /></div>' },
DataTable: { name: 'DataTable', props: ['page', 'pageSize', 'data'], emits: ['update:page', 'update:pageSize', 'selection-change'], template: '<div data-testid="data-table"><slot name="toolbar-start" /><slot name="toolbar-actions" /><slot name="filters" /><slot name="notices" /><div v-for="row in data" :key="row.orderId" class="test-row"><slot name="estimatedVolume" :row="row" /><slot name="expectedArrival" :row="row" /></div></div>' },
'el-button': { template: '<button><slot /></button>' },
'el-input-number': { name: 'ElInputNumber', props: ['modelValue', 'disabled'], emits: ['update:modelValue', 'change'], template: '<input class="number-input" :value="modelValue" :disabled="disabled" @change="$emit(\'change\')" />' },
'el-date-picker': { name: 'ElDatePicker', props: ['modelValue', 'disabled'], emits: ['update:modelValue', 'change'], template: '<input class="date-input" :value="modelValue" :disabled="disabled" @change="$emit(\'change\')" />' },
ApiErrorMeta: { props: ['details'], template: '<code class="api-meta">{{ details.code }} {{ details.requestId }} {{ details.traceId }}</code>' },
},
},
})
}
describe('UnifiedOrdersView list request coordination', () => {
beforeEach(() => {
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockReset().mockResolvedValue({ counts: {} })
vi.mocked(listPlatformUnifiedOrders).mockReset().mockResolvedValue(emptyPage())
vi.mocked(updatePlatformUnifiedOrderPlanning).mockReset()
vi.mocked(createPlatformExportTask).mockReset().mockResolvedValue({ taskName: '国内仓订单', taskNo: 'EXP-1' } as never)
vi.mocked(showExportTaskCreatedDialog).mockReset().mockResolvedValue(false)
})
it('shares applied filters, advanced fields and reset across measurement review and other tabs', async () => {
const wrapper = mountView()
await flushPromises()
const model = { receivingWarehouseId: '9007199254740993', destinationWarehouseId: '200', inboundCode: ' IN-9 ', tenantId: '300', channelName: '海派', containerNo: 'CONT-1', cabinetNo: 'CAB-1', loaded: 'false', fullContainer: 'true', expectedArrivalDate: '2026-10-20', sailingDate: '2026-11-01', feeReviewStatus: 'APPROVED', measurementReviewStatus: 'PENDING', fbaCode: 'SKU-1', createdRange: ['2026-10-01', '2026-10-20'] }
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
toolbar.vm.$emit('update:modelValue', { ...toolbar.props('modelValue'), ...model })
await flushPromises()
toolbar.vm.$emit('search')
await flushPromises()
const ordinaryQuery = vi.mocked(listPlatformUnifiedOrders).mock.lastCall![0]
await wrapper.findAll('[role="tab"]').find(tab => tab.text().startsWith('测量数据审核'))!.trigger('click')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith({ ...ordinaryQuery, mainStatus: 'MEASUREMENT_REVIEW' })
const reviewToolbar = wrapper.getComponent({ name: 'QueryToolbar' })
expect(reviewToolbar.props('modelValue')).toMatchObject(model)
expect(reviewToolbar.attributes('preference-key')).toBe('unified-orders-query-v2')
expect(reviewToolbar.props('maxVisible')).toBe(3)
expect(reviewToolbar.props('fields').map((field: { key: string }) => field.key)).toEqual(expect.arrayContaining(['createdRange', 'tenantId', 'inboundCode']))
reviewToolbar.vm.$emit('reset')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ mainStatus: 'MEASUREMENT_REVIEW', receivingWarehouseId: undefined, inboundCode: undefined, channelName: undefined, tenantId: undefined }))
reviewToolbar.vm.$emit('update:modelValue', { ...reviewToolbar.props('modelValue'), inboundCode: 'IN-REVIEW' })
await flushPromises()
reviewToolbar.vm.$emit('search')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ mainStatus: 'MEASUREMENT_REVIEW', inboundCode: 'IN-REVIEW' }))
await wrapper.findAll('[role="tab"]').find(tab => tab.text().startsWith('待审核'))!.trigger('click')
await flushPromises()
expect(wrapper.getComponent({ name: 'QueryToolbar' }).props('modelValue')).toMatchObject({ inboundCode: 'IN-REVIEW' })
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ mainStatus: 'PENDING_REVIEW', inboundCode: 'IN-REVIEW' }))
})
it.each(['全部', '测量数据审核'])('limits fields after saved ordering without changing filters or querying when %s is expanded and collapsed', async (tabLabel) => {
const wrapper = mountView()
await flushPromises()
if (tabLabel !== '全部') {
await wrapper.findAll('[role="tab"]').find(tab => tab.text().startsWith(tabLabel))!.trigger('click')
await flushPromises()
}
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
const fieldKeys = toolbar.props('fields').map((field: { key: string }) => field.key)
expect(fieldKeys).toHaveLength(15)
expect(fieldKeys).toEqual(expect.arrayContaining(['createdRange', 'tenantId', 'inboundCode']))
expect(toolbar.props('maxVisible')).toBe(3)
const model = { ...toolbar.props('modelValue'), tenantId: 'customer-1', inboundCode: 'IN-KEEP', createdRange: ['2026-10-01', '2026-10-28'] }
toolbar.vm.$emit('update:modelValue', model)
await flushPromises()
const requestCount = vi.mocked(listPlatformUnifiedOrders).mock.calls.length
await wrapper.get('[aria-controls="unified-orders-advanced-filters"]').trigger('click')
expect(toolbar.props('maxVisible')).toBeUndefined()
await wrapper.get('[aria-controls="unified-orders-advanced-filters"]').trigger('click')
expect(toolbar.props('maxVisible')).toBe(3)
expect(toolbar.props('fields').map((field: { key: string }) => field.key)).toEqual(fieldKeys)
expect(toolbar.props('modelValue')).toEqual(model)
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(requestCount)
wrapper.unmount()
})
it('shows only supported counts, keeps all text-only and never scopes counts by status or pagination', async () => {
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockResolvedValue({ counts: { PENDING_REVIEW: 12, WAIT_MEASURE: 0, SIGNED: 3 } })
const wrapper = mountView()
await flushPromises()
const tabs = wrapper.findAll('[role="tab"]')
expect(tabs[0]!.text()).toBe('全部')
expect(tabs[1]!.text()).toBe('待审核(12)')
expect(tabs[2]!.text()).toBe('待测量数据(0)')
expect(tabs[3]!.text()).toBe('测量数据审核')
expect(tabs.at(-1)!.text()).toBe('派送完成(3)')
expect(tabs.map((tab) => tab.text())).not.toContain('派送完成')
expect(tabs.map((tab) => tab.text())).not.toContain('已完成')
await tabs[1]!.trigger('click')
wrapper.getComponent({ name: 'DataTable' }).vm.$emit('update:page', 2)
await flushPromises()
expect(getPlatformUnifiedOrderStatusCounts).toHaveBeenCalledTimes(1)
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
toolbar.vm.$emit('update:modelValue', { ...toolbar.props('modelValue'), inboundCode: ' IN-9 ', loaded: 'false' })
toolbar.vm.$emit('search')
await flushPromises()
expect(getPlatformUnifiedOrderStatusCounts).toHaveBeenCalledTimes(2)
const params = vi.mocked(getPlatformUnifiedOrderStatusCounts).mock.lastCall![0]
expect(params).toMatchObject({ inboundCode: 'IN-9', loaded: false })
expect(params).not.toHaveProperty('mainStatus')
expect(params).not.toHaveProperty('page')
expect(params).not.toHaveProperty('size')
toolbar.vm.$emit('reset')
await flushPromises()
expect(getPlatformUnifiedOrderStatusCounts).toHaveBeenCalledTimes(3)
})
it('ignores older count responses and hides stale counts during loading and failures with retry', async () => {
let resolveOld!: (value: { counts: { PENDING_REVIEW: number } }) => void
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockImplementationOnce(() => new Promise((resolve) => { resolveOld = resolve }))
const wrapper = mountView()
await flushPromises()
expect(wrapper.get('[role="tablist"]').attributes('aria-busy')).toBe('true')
expect(wrapper.find('.order-status-count').exists()).toBe(false)
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockResolvedValueOnce({ counts: { PENDING_REVIEW: 7 } })
wrapper.getComponent({ name: 'QueryToolbar' }).vm.$emit('search')
await flushPromises()
resolveOld({ counts: { PENDING_REVIEW: 99 } })
await flushPromises()
expect(wrapper.findAll('[role="tab"]')[1]!.text()).toBe('待审核(7)')
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockRejectedValueOnce(new Error('统计不可用'))
wrapper.getComponent({ name: 'QueryToolbar' }).vm.$emit('search')
await flushPromises()
expect(wrapper.find('.order-status-count').exists()).toBe(false)
expect(wrapper.findComponent({ name: 'DataTable' }).exists()).toBe(true)
expect(wrapper.find('.order-status-feedback').text()).toContain('重试数量')
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockResolvedValueOnce({ counts: { PENDING_REVIEW: 8, MEASUREMENT_REVIEW: 3 } })
await wrapper.findAll('button').find((button) => button.text() === '重试数量')!.trigger('click')
await flushPromises()
expect(wrapper.findAll('[role="tab"]')[1]!.text()).toBe('待审核(8)')
expect(wrapper.findAll('[role="tab"]')[3]!.text()).toBe('测量数据审核(3)')
})
it('keeps every count and the toolbar state stable when switching between ordinary and review tabs', async () => {
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockResolvedValueOnce({ counts: { PENDING_REVIEW: 12, WAIT_MEASURE: 0, MEASUREMENT_REVIEW: 4, SIGNED: 3 } })
const wrapper = mountView()
await flushPromises()
const labels = wrapper.findAll('[role="tab"]').map(tab => tab.text())
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockImplementation(() => new Promise(() => {}))
for (const label of ['待审核(12)', '测量数据审核(4)', '待测量数据(0)', '全部']) {
await wrapper.findAll('[role="tab"]').find(tab => tab.text() === label)!.trigger('click')
await flushPromises()
expect(wrapper.findAll('[role="tab"]').map(tab => tab.text())).toEqual(labels)
expect(wrapper.get('[aria-selected="true"]').text()).toBe(label)
expect(wrapper.get('[role="tablist"]').attributes('aria-busy')).toBe('false')
expect(wrapper.find('.order-status-feedback').exists()).toBe(false)
expect(getPlatformUnifiedOrderStatusCounts).toHaveBeenCalledTimes(1)
}
})
it.each(['全部', '测量数据审核'])('keeps the %s tab bar mounted without a loading text row during query', async (label) => {
const wrapper = mountView()
await flushPromises()
if (label !== '全部') {
await wrapper.findAll('[role="tab"]').find(tab => tab.text() === label)!.trigger('click')
await flushPromises()
}
const tabList = wrapper.get('[role="tablist"]').element
let resolveCounts!: (value: { counts: {} }) => void
vi.mocked(getPlatformUnifiedOrderStatusCounts).mockImplementationOnce(() => new Promise(resolve => { resolveCounts = resolve }))
wrapper.getComponent({ name: 'QueryToolbar' }).vm.$emit('search')
await flushPromises()
expect(wrapper.get('[role="tablist"]').element).toBe(tabList)
expect(wrapper.get('[role="tablist"]').attributes('aria-busy')).toBe('true')
expect(wrapper.find('.order-status-feedback').exists()).toBe(false)
resolveCounts({ counts: {} })
await flushPromises()
expect(wrapper.get('[role="tablist"]').element).toBe(tabList)
expect(wrapper.get('[role="tablist"]').attributes('aria-busy')).toBe('false')
wrapper.unmount()
})
it.each(['success', 'failure'] as const)('ignores an older tab request %s after the current tab has loaded', async (outcome) => {
const wrapper = mountView()
await flushPromises()
let resolveOlder!: (value: Awaited<ReturnType<typeof listPlatformUnifiedOrders>>) => void
let rejectOlder!: (reason: Error) => void
vi.mocked(listPlatformUnifiedOrders).mockImplementationOnce(() => new Promise((resolve, reject) => { resolveOlder = resolve; rejectOlder = reject }))
await wrapper.findAll('[role="tab"]').find(tab => tab.text() === '待审核')!.trigger('click')
const latest = { ...emptyPage(), records: [{ orderId: 'new-order', tenantId: '8', orderVersion: 1, inboundCode: 'IN-NEW', internalOrderStatus: 'SUBMITTED', mainStatus: 'WAIT_MEASURE', expectedArrivalAt: null, estimatedVolumeCbm: null }], total: 1, pages: 1 } as Awaited<ReturnType<typeof listPlatformUnifiedOrders>>
vi.mocked(listPlatformUnifiedOrders).mockResolvedValueOnce(latest)
await wrapper.findAll('[role="tab"]').find(tab => tab.text() === '待测量数据')!.trigger('click')
await flushPromises()
expect(wrapper.getComponent({ name: 'DataTable' }).props('data')).toEqual(latest.records)
if (outcome === 'success') resolveOlder(emptyPage())
else rejectOlder(new Error('旧页签请求失败'))
await flushPromises()
expect(wrapper.get('[aria-selected="true"]').text()).toBe('待测量数据')
expect(wrapper.getComponent({ name: 'DataTable' }).props('data')).toEqual(latest.records)
expect(wrapper.findComponent({ name: 'LoadErrorState' }).exists()).toBe(false)
})
it('loads once initially and once for query, reset, status tab and pagination', async () => {
const wrapper = mountView()
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(1)
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
toolbar.vm.$emit('search')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(2)
toolbar.vm.$emit('reset')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(3)
await wrapper.findAll('.status-tab')[1]!.trigger('click')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(4)
wrapper.getComponent({ name: 'DataTable' }).vm.$emit('update:page', 2)
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(5)
})
it('opens the existing measurement review list beside measurement and returns to order queries', async () => {
const wrapper = mountView()
await flushPromises()
const labels = wrapper.findAll('[role="tab"]').map((tab) => tab.text())
expect(labels.indexOf('测量数据审核')).toBe(labels.indexOf('待测量数据') + 1)
await wrapper.findAll('[role="tab"]').find((tab) => tab.text() === '测量数据审核')!.trigger('click')
await flushPromises()
expect(wrapper.getComponent({ name: 'InboundTaskList' }).props()).toMatchObject({ mode: 'review', title: '订单列表' })
expect(wrapper.getComponent({ name: 'InboundTaskList' }).classes()).toContain('is-embedded')
expect(wrapper.get('main').classes()).not.toContain('is-embedded')
expect(wrapper.get('[aria-selected="true"]').text()).toBe('测量数据审核')
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(2)
await wrapper.findAll('[role="tab"]').find((tab) => tab.text() === '待测量数据')!.trigger('click')
await flushPromises()
expect(wrapper.findComponent({ name: 'InboundTaskList' }).exists()).toBe(false)
expect(wrapper.find('.is-embedded').exists()).toBe(false)
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ mainStatus: 'WAIT_MEASURE' }))
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(3)
})
it('does not apply draft filters to pagination until query is submitted', async () => {
const wrapper = mountView()
await flushPromises()
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
const draft = { ...toolbar.props('modelValue'), inboundCode: ' DRAFT-CODE ' }
toolbar.vm.$emit('update:modelValue', draft)
await wrapper.vm.$nextTick()
wrapper.getComponent({ name: 'DataTable' }).vm.$emit('update:page', 2)
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ page: 2, inboundCode: undefined }))
toolbar.vm.$emit('search')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(3)
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ page: 1, inboundCode: 'DRAFT-CODE' }))
})
it('resets a later page and changes page size with one request per interaction', async () => {
const wrapper = mountView()
await flushPromises()
const table = wrapper.getComponent({ name: 'DataTable' })
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
table.vm.$emit('update:page', 3)
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(2)
toolbar.vm.$emit('reset')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(3)
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ page: 1 }))
table.vm.$emit('update:pageSize', 50)
table.vm.$emit('update:page', 1)
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(4)
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ page: 1, size: 50 }))
})
it('does not turn a cleared full-container filter into false', async () => {
const wrapper = mountView()
await flushPromises()
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
const selected = { ...toolbar.props('modelValue'), fullContainer: 'true' }
toolbar.vm.$emit('update:modelValue', selected)
toolbar.vm.$emit('search')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ fullContainer: true }))
toolbar.vm.$emit('update:modelValue', { ...selected, fullContainer: undefined })
toolbar.vm.$emit('search')
await flushPromises()
expect(listPlatformUnifiedOrders).toHaveBeenLastCalledWith(expect.objectContaining({ fullContainer: undefined }))
})
it('exports the selected business order numbers without loading other pages', async () => {
const wrapper = mountView()
await flushPromises()
wrapper.getComponent({ name: 'DataTable' }).vm.$emit('selection-change', [
{ orderId: '1', orderNo: 'ORDER-1', tenantId: '8' },
{ orderId: '2', orderNo: 'ORDER-2', tenantId: '8' },
])
await wrapper.vm.$nextTick()
await wrapper.findAll('button').find((button) => button.text().includes('导出'))!.trigger('click')
await flushPromises()
expect(createPlatformExportTask).toHaveBeenCalledWith({
exportType: 'DOMESTIC_WAREHOUSE_ORDER_LIST', format: 'XLSX', taskName: '国内仓订单-已选2票',
parameters: { selectedOrderNos: ['ORDER-1', 'ORDER-2'] },
})
expect(listPlatformUnifiedOrders).toHaveBeenCalledTimes(1)
})
it('exports every result matching the applied filters instead of the current page', async () => {
const wrapper = mountView()
await flushPromises()
const toolbar = wrapper.getComponent({ name: 'QueryToolbar' })
toolbar.vm.$emit('update:modelValue', {
...toolbar.props('modelValue'), inboundCode: ' IN-8 ', loaded: 'false', createdRange: ['2026-08-01', '2026-08-31'],
})
toolbar.vm.$emit('search')
await flushPromises()
await wrapper.findAll('button').find((button) => button.text() === '导出')!.trigger('click')
await flushPromises()
expect(createPlatformExportTask).toHaveBeenCalledWith(expect.objectContaining({
exportType: 'DOMESTIC_WAREHOUSE_ORDER_LIST', taskName: '国内仓订单-当前筛选',
parameters: expect.objectContaining({
inboundCode: 'IN-8', loaded: false,
createdFrom: '2026-08-01T00:00:00', createdTo: '2026-08-31T23:59:59',
}),
}))
expect(createPlatformExportTask).not.toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({ page: expect.anything(), size: expect.anything() }),
}))
})
it('edits arrival and estimated volume and reports compact failure evidence through a message', async () => {
const errorMessage = vi.spyOn(ElMessage, 'error').mockImplementation(() => undefined as never)
vi.mocked(listPlatformUnifiedOrders).mockResolvedValue({
records: [{
orderId: '2089223263733518337', orderVersion: 7, tenantId: '2089176869176389634',
internalOrderStatus: 'SUBMITTED',
inboundCode: 'NYEXX2609030001', expectedArrivalAt: '2026-09-10T08:30:00', estimatedVolumeCbm: 0.25,
}], page: 1, size: 20, total: 1, pages: 1,
} as never)
vi.mocked(updatePlatformUnifiedOrderPlanning)
.mockResolvedValueOnce({ version: 8 } as never)
.mockRejectedValueOnce(new ApiResponseError('订单版本已变化', 'A0409', 200, undefined, 'req-planning', 'trace-planning'))
const wrapper = mountView()
await flushPromises()
const volume = wrapper.getComponent({ name: 'ElInputNumber' })
volume.vm.$emit('update:modelValue', 0.5)
volume.vm.$emit('change', 0.5)
await flushPromises()
expect(updatePlatformUnifiedOrderPlanning).toHaveBeenNthCalledWith(1,
'2089176869176389634', '2089223263733518337', {
expectedVersion: 7, expectedArrivalAt: '2026-09-10T08:30:00', estimatedVolumeCbm: 0.5,
})
const arrival = wrapper.getComponent({ name: 'ElDatePicker' })
arrival.vm.$emit('update:modelValue', '2026-09-12T16:00:00')
arrival.vm.$emit('change', '2026-09-12T16:00:00')
await flushPromises()
expect(updatePlatformUnifiedOrderPlanning).toHaveBeenNthCalledWith(2,
'2089176869176389634', '2089223263733518337', {
expectedVersion: 8, expectedArrivalAt: '2026-09-12T16:00:00', estimatedVolumeCbm: 0.5,
})
expect(wrapper.getComponent({ name: 'ElDatePicker' }).props('modelValue')).toBe('2026-09-12T16:00:00')
expect(wrapper.text()).not.toContain('订单版本已变化')
expect(wrapper.find('.planning-error').exists()).toBe(false)
expect(errorMessage).toHaveBeenCalledWith(expect.objectContaining({
message: '订单版本已变化(错误码 A0409;Request ID req-planning;Trace ID trace-planning)',
showClose: true,
}))
})
it('shows planning values without editors after the order enters irreversible fulfillment', async () => {
vi.mocked(listPlatformUnifiedOrders).mockResolvedValue({
records: [{
orderId: '2099751993783402497', orderVersion: 7, tenantId: '2097708157074210818',
internalOrderStatus: 'PROCESSING', mainStatus: 'LOADED', inboundCode: 'AT0E9B5BF2839C6944CFA3',
expectedArrivalAt: '2026-10-15T00:00:00', estimatedVolumeCbm: 220,
}], page: 1, size: 20, total: 1, pages: 1,
} as never)
const wrapper = mountView()
await flushPromises()
expect(wrapper.findComponent({ name: 'ElInputNumber' }).exists()).toBe(false)
expect(wrapper.findComponent({ name: 'ElDatePicker' }).exists()).toBe(false)
expect(wrapper.text()).toContain('220')
expect(wrapper.text()).toContain('2026-10-15 00:00')
expect(updatePlatformUnifiedOrderPlanning).not.toHaveBeenCalled()
})
})