修复智能装柜订单状态多选
This commit is contained in:
@@ -68,7 +68,10 @@ describe('platform container loading API', () => {
|
||||
.mockResolvedValueOnce({ code: '200', data: container })
|
||||
.mockResolvedValueOnce({ code: '200', data: { records: [{ accountId: 1, customerId: 1, inboundId: 2, orderId: 4, orderNo: 'ORD-1', inboundCode: 'IN-1', orderStatusSnapshot: 'WAIT_SPLIT', expectedArrivalAt: '2026-09-10T09:30:00', warehouseId: 5, destinationWarehouseId: 6, channelCode: 'NY_EXX', channelName: '纽约EXX海铁', customerName: '示例企业', goodsSummary: '服装、鞋类', availablePackageCount: '7', unitGrossWeightKg: '12.5', unitNetWeightKg: '11.8', averageUnitVolumeCbm: '0.187', availableVolumeCbm: '1.309', coLoadGroupId: 9007199254740999n, groupNo: 'CLG-9007199254740999', memberCount: '3', groupTotalBoxes: '21', locked: false, blockReason: null, groupMembers: [] }], page: '1', size: '20', total: '1', pages: '1' } })
|
||||
expect((await getContainer('9')).id).toBe(String(container.id))
|
||||
expect(await listSmartLoadingCandidates({ channelGroupCodes: ['EXX', 'HEDE'], warehouseId: '5', page: 1, size: 20 })).toMatchObject({ records: [{ accountId: '1', customerId: '1', inboundId: '2', inboundCode: 'IN-1', orderStatusSnapshot: 'WAIT_SPLIT', expectedArrivalAt: '2026-09-10T09:30:00', destinationWarehouseId: '6', channelCode: 'NY_EXX', channelName: '纽约EXX海铁', goodsSummary: '服装、鞋类', availablePackageCount: 7, unitGrossWeightKg: 12.5, unitNetWeightKg: 11.8, averageUnitVolumeCbm: 0.187, availableVolumeCbm: 1.309, coLoadGroupId: '9007199254740999', groupNo: 'CLG-9007199254740999', memberCount: 3, groupTotalBoxes: 21, locked: false, blockReason: null }], total: 1 })
|
||||
expect(await listSmartLoadingCandidates({ channelGroupCodes: ['EXX', 'HEDE'], warehouseId: '5', orderStatuses: ['PENDING_REVIEW', 'WAIT_MEASURE'], page: 1, size: 20 })).toMatchObject({ records: [{ accountId: '1', customerId: '1', inboundId: '2', inboundCode: 'IN-1', orderStatusSnapshot: 'WAIT_SPLIT', expectedArrivalAt: '2026-09-10T09:30:00', destinationWarehouseId: '6', channelCode: 'NY_EXX', channelName: '纽约EXX海铁', goodsSummary: '服装、鞋类', availablePackageCount: 7, unitGrossWeightKg: 12.5, unitNetWeightKg: 11.8, averageUnitVolumeCbm: 0.187, availableVolumeCbm: 1.309, coLoadGroupId: '9007199254740999', groupNo: 'CLG-9007199254740999', memberCount: 3, groupTotalBoxes: 21, locked: false, blockReason: null }], total: 1 })
|
||||
const candidateParams = vi.mocked(http.get).mock.calls.at(-1)?.[1]?.params as URLSearchParams
|
||||
expect(candidateParams.getAll('orderStatuses')).toEqual(['PENDING_REVIEW', 'WAIT_MEASURE'])
|
||||
expect(candidateParams.has('orderStatus')).toBe(false)
|
||||
const params = vi.mocked(http.get).mock.calls.at(-1)?.[1]?.params as URLSearchParams
|
||||
expect(params.getAll('channelGroupCodes')).toEqual(['EXX', 'HEDE'])
|
||||
expect(params.get('warehouseId')).toBe('5')
|
||||
@@ -112,7 +115,7 @@ describe('platform container loading API', () => {
|
||||
page: '1', size: '200', total: '1', pages: '1',
|
||||
} })
|
||||
|
||||
const result = await listSmartLoadingWorkbenchContainers({ channelGroupCodes: ['MATSON_CLX', 'EXX'], customerId: '12', inboundCode: 'IN-1', createdStart: '2026-09-01', createdEnd: '2026-09-03', orderStatus: 'WAIT_SPLIT', page: 1, size: 200 })
|
||||
const result = await listSmartLoadingWorkbenchContainers({ channelGroupCodes: ['MATSON_CLX', 'EXX'], customerId: '12', inboundCode: 'IN-1', createdStart: '2026-09-01', createdEnd: '2026-09-03', orderStatuses: ['WAIT_SPLIT'], page: 1, size: 200 })
|
||||
|
||||
expect(result).toMatchObject({ records: [{ bookingId: '9007199254740993', warehouseId: '8', planId: '9007199254740994', version: 2 }], total: 1 })
|
||||
const params = vi.mocked(http.get).mock.calls.at(-1)?.[1]?.params as URLSearchParams
|
||||
@@ -121,7 +124,8 @@ describe('platform container loading API', () => {
|
||||
expect(params.get('inboundCode')).toBe('IN-1')
|
||||
expect(params.get('createdStart')).toBe('2026-09-01')
|
||||
expect(params.get('createdEnd')).toBe('2026-09-03')
|
||||
expect(params.get('orderStatus')).toBe('WAIT_SPLIT')
|
||||
expect(params.has('orderStatus')).toBe(false)
|
||||
expect(params.has('orderStatuses')).toBe(false)
|
||||
expect(params.has('bookingId')).toBe(false)
|
||||
})
|
||||
|
||||
|
||||
@@ -228,20 +228,23 @@ export async function completeContainerClearance(containerId: string, expectedVe
|
||||
return document(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
function smartLoadingQueryParams(query: SmartLoadingCandidateQuery) {
|
||||
function smartLoadingQueryParams(query: SmartLoadingCandidateQuery, includeOrderStatuses = false) {
|
||||
const params = new URLSearchParams()
|
||||
for (const channelGroupCode of query.channelGroupCodes) params.append('channelGroupCodes', channelGroupCode)
|
||||
if (includeOrderStatuses) {
|
||||
for (const orderStatus of query.orderStatuses || []) params.append('orderStatuses', orderStatus)
|
||||
}
|
||||
const optionalParams: Array<[string, string | number | undefined]> = [
|
||||
['warehouseId', query.warehouseId], ['customerId', query.customerId], ['inboundCode', query.inboundCode],
|
||||
['createdStart', query.createdStart], ['createdEnd', query.createdEnd],
|
||||
['orderStatus', query.orderStatus], ['page', query.page], ['size', query.size],
|
||||
['page', query.page], ['size', query.size],
|
||||
]
|
||||
for (const [key, value] of optionalParams) if (value !== undefined && value !== '') params.append(key, String(value))
|
||||
return params
|
||||
}
|
||||
|
||||
export async function listSmartLoadingCandidates(query: SmartLoadingCandidateQuery) {
|
||||
const params = smartLoadingQueryParams(query)
|
||||
const params = smartLoadingQueryParams(query, true)
|
||||
const response = await http.get<ApiEnvelope<SmartLoadingCandidatePage>, ApiEnvelope<SmartLoadingCandidatePage>>(`${smartLoadingPath}/inbound-candidates`, { params })
|
||||
const result = unwrapApiResponse(response)
|
||||
return {
|
||||
|
||||
@@ -280,7 +280,7 @@ describe('GlobalSmartLoadingView', () => {
|
||||
expect(wrapper.text()).toContain('MSCU-DG')
|
||||
const containerRequestCount = vi.mocked(listSmartLoadingWorkbenchContainers).mock.calls.length
|
||||
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '18', customerId: '', inboundCode: '', createdRange: [], orderStatus: '' })
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '18', customerId: '', inboundCode: '', createdRange: [], orderStatuses: [] })
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.text()).toContain('MSCU-DG')
|
||||
@@ -307,7 +307,7 @@ describe('GlobalSmartLoadingView', () => {
|
||||
await flushPromises()
|
||||
const containerRequestCount = vi.mocked(listSmartLoadingWorkbenchContainers).mock.calls.length
|
||||
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '18', customerId: '', inboundCode: '', createdRange: [], orderStatus: '' })
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', { warehouseId: '18', customerId: '', inboundCode: '', createdRange: [], orderStatuses: [] })
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.find('.channel-tags .el-checkbox-button.is-checked').text()).toBe('美森正班')
|
||||
@@ -338,7 +338,7 @@ describe('GlobalSmartLoadingView', () => {
|
||||
const containerRequestCount = vi.mocked(listSmartLoadingWorkbenchContainers).mock.calls.length
|
||||
|
||||
wrapper.findComponent(QueryToolbar).vm.$emit('search', {
|
||||
warehouseId: '', customerId: '', inboundCode: 'NYEXX2609030002', createdRange: [], orderStatus: '',
|
||||
warehouseId: '', customerId: '', inboundCode: 'NYEXX2609030002', createdRange: [], orderStatuses: [],
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
@@ -363,7 +363,7 @@ describe('GlobalSmartLoadingView', () => {
|
||||
expect(source).toContain(': candidate.availablePackageCount')
|
||||
})
|
||||
|
||||
it('filters candidates by expected arrival range and order status', async () => {
|
||||
it('filters candidates by creation range and multiple order statuses', async () => {
|
||||
vi.mocked(listSmartLoadingCandidates)
|
||||
.mockResolvedValueOnce(candidatePage([
|
||||
{ ...candidate, inboundId: '51', inboundCode: 'IN-MATCH', orderStatusSnapshot: 'WAIT_SPLIT', expectedArrivalAt: '2026-09-11T08:00:00' },
|
||||
@@ -376,7 +376,7 @@ describe('GlobalSmartLoadingView', () => {
|
||||
const containerRequestCount = vi.mocked(listSmartLoadingWorkbenchContainers).mock.calls.length
|
||||
|
||||
wrapper.getComponent(QueryToolbar).vm.$emit('search', {
|
||||
customerId: '', inboundCode: '', orderStatus: 'WAIT_SPLIT', createdRange: ['2026-09-10', '2026-09-12'],
|
||||
customerId: '', inboundCode: '', orderStatuses: ['WAIT_SPLIT', 'LOADING'], createdRange: ['2026-09-10', '2026-09-12'],
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
@@ -384,7 +384,7 @@ describe('GlobalSmartLoadingView', () => {
|
||||
expect(candidates).toContain('IN-MATCH')
|
||||
expect(candidates).not.toContain('IN-WRONG-STATUS')
|
||||
expect(candidates).not.toContain('IN-WRONG-DATE')
|
||||
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], createdStart: '2026-09-10', createdEnd: '2026-09-12', orderStatus: 'WAIT_SPLIT', page: 1, size: 20 })
|
||||
expect(listSmartLoadingCandidates).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], createdStart: '2026-09-10', createdEnd: '2026-09-12', orderStatuses: ['WAIT_SPLIT', 'LOADING'], page: 1, size: 20 })
|
||||
expect(listSmartLoadingWorkbenchContainers).toHaveBeenCalledTimes(containerRequestCount)
|
||||
expect(listSmartLoadingWorkbenchContainers).toHaveBeenLastCalledWith({ channelGroupCodes: ['MATSON_CLX'], page: 1, size: 200 })
|
||||
})
|
||||
@@ -520,16 +520,16 @@ describe('GlobalSmartLoadingView', () => {
|
||||
const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
|
||||
const fields = wrapper.findComponent(QueryToolbar).props('fields') as Array<{ key: string; options?: Array<{ label: string; value: string }> }>
|
||||
expect(fields.map((field) => field.key)).toEqual(['warehouseId', 'customerId', 'inboundCode', 'createdRange', 'orderStatus'])
|
||||
const fields = wrapper.findComponent(QueryToolbar).props('fields') as Array<{ key: string; options?: Array<{ label: string; value: string }>; props?: Record<string, unknown> }>
|
||||
expect(fields.map((field) => field.key)).toEqual(['warehouseId', 'customerId', 'inboundCode', 'createdRange', 'orderStatuses'])
|
||||
expect(fields.find((field) => field.key === 'warehouseId')?.options).toEqual([{ label: '义乌仓', value: '8' }])
|
||||
expect(fields.find((field) => field.key === 'orderStatus')?.options).toEqual([
|
||||
{ value: '', label: '全部' },
|
||||
expect(fields.find((field) => field.key === 'orderStatuses')?.options).toEqual([
|
||||
{ value: 'PENDING_REVIEW', label: '待审核' },
|
||||
{ value: 'WAIT_MEASURE', label: '待测量数据' },
|
||||
{ value: 'WAIT_SPLIT', label: '待分柜' },
|
||||
{ value: 'LOADING', label: '装柜中' },
|
||||
])
|
||||
expect(fields.find((field) => field.key === 'orderStatuses')?.props).toMatchObject({ multiple: true, collapseTags: true, maxCollapseTags: 2 })
|
||||
expect(source).not.toContain('目的仓')
|
||||
|
||||
expect(wrapper.text()).not.toContain('税率')
|
||||
|
||||
@@ -63,8 +63,8 @@ const selectedCandidate = ref<SmartLoadingCandidateRow | null>(null)
|
||||
const assignForm = reactive({ packageCount: 1 })
|
||||
const quantityDrafts = reactive<Record<string, number>>({})
|
||||
const planGroupsByInboundId = ref(new Map<string, SmartLoadingPlanCoLoadGroup>())
|
||||
const query = ref<QueryModel>({ warehouseId: '', customerId: '', inboundCode: '', createdRange: [], orderStatus: '' })
|
||||
const appliedQuery = ref<QueryModel>({ ...query.value })
|
||||
const query = ref<QueryModel>({ warehouseId: '', customerId: '', inboundCode: '', createdRange: [], orderStatuses: [] })
|
||||
const appliedQuery = ref<QueryModel>({ ...query.value, orderStatuses: [] })
|
||||
const candidatePage = ref(1)
|
||||
const candidatePageSize = ref(20)
|
||||
const candidateTotal = ref(0)
|
||||
@@ -185,7 +185,6 @@ const weightPercent = computed(() => weightLimit.value ? totalWeight.value / wei
|
||||
const displayedVolumePercent = computed(() => percentage(volumePercent.value))
|
||||
const displayedWeightPercent = computed(() => percentage(weightPercent.value))
|
||||
const candidateOrderStatusOptions = [
|
||||
{ value: '', label: '全部' },
|
||||
{ value: 'PENDING_REVIEW', label: '待审核' },
|
||||
{ value: 'WAIT_MEASURE', label: '待测量数据' },
|
||||
{ value: 'WAIT_SPLIT', label: '待分柜' },
|
||||
@@ -199,7 +198,7 @@ const queryFields = computed<QueryField[]>(() => [
|
||||
{ key: 'customerId', type: 'select', label: '客户', placeholder: '全部客户', width: 180, options: customers.value.filter((customer) => customer.status === 'ACTIVE').map((customer) => ({ label: customer.tenantName, value: String(customer.id) })), props: { filterable: true, loading: customersLoading.value } },
|
||||
{ key: 'inboundCode', type: 'input', label: '入仓码', placeholder: '请输入入仓码', width: 210 },
|
||||
{ key: 'createdRange', type: 'daterange', label: '创建日期', placeholder: '请选择创建日期范围', width: 260 },
|
||||
{ key: 'orderStatus', type: 'select', label: '订单状态', placeholder: '全部订单状态', width: 160, options: candidateOrderStatusOptions },
|
||||
{ key: 'orderStatuses', type: 'select', label: '订单状态', placeholder: '全部订单状态', width: 210, options: candidateOrderStatusOptions, props: { multiple: true, collapseTags: true, collapseTagsTooltip: true, maxCollapseTags: 2 } },
|
||||
])
|
||||
|
||||
const filteredContainers = computed(() => containers.value)
|
||||
@@ -300,7 +299,9 @@ function candidateQueryParams(): Parameters<typeof listSmartLoadingCandidates>[0
|
||||
const warehouseId = String(appliedQuery.value.warehouseId || '')
|
||||
const customerId = String(appliedQuery.value.customerId || '')
|
||||
const inboundCode = String(appliedQuery.value.inboundCode || '').trim()
|
||||
const orderStatus = String(appliedQuery.value.orderStatus || '') as typeof params.orderStatus
|
||||
const orderStatuses = Array.isArray(appliedQuery.value.orderStatuses)
|
||||
? appliedQuery.value.orderStatuses.map((value) => String(value)).filter(Boolean) as NonNullable<typeof params.orderStatuses>
|
||||
: []
|
||||
if (warehouseId) params.warehouseId = warehouseId
|
||||
if (customerId) params.customerId = customerId
|
||||
if (inboundCode) params.inboundCode = inboundCode
|
||||
@@ -308,7 +309,7 @@ function candidateQueryParams(): Parameters<typeof listSmartLoadingCandidates>[0
|
||||
params.createdStart = createdRange[0]
|
||||
params.createdEnd = createdRange[1]
|
||||
}
|
||||
if (orderStatus) params.orderStatus = orderStatus
|
||||
if (orderStatuses.length) params.orderStatuses = orderStatuses
|
||||
return params
|
||||
}
|
||||
|
||||
@@ -443,7 +444,10 @@ async function selectChannels(codes: string[]) {
|
||||
await loadWorkbenchData()
|
||||
}
|
||||
async function applyFilters(model: QueryModel) {
|
||||
appliedQuery.value = { ...model }
|
||||
appliedQuery.value = {
|
||||
...model,
|
||||
orderStatuses: Array.isArray(model.orderStatuses) ? model.orderStatuses.map((value) => String(value)) : [],
|
||||
}
|
||||
candidatePage.value = 1
|
||||
await loadCandidateData()
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ export interface SmartLoadingCandidateQuery {
|
||||
inboundCode?: string
|
||||
createdStart?: string
|
||||
createdEnd?: string
|
||||
orderStatus?: 'PENDING_REVIEW' | 'WAIT_MEASURE' | 'WAIT_SPLIT' | 'LOADING'
|
||||
orderStatuses?: Array<'PENDING_REVIEW' | 'WAIT_MEASURE' | 'WAIT_SPLIT' | 'LOADING'>
|
||||
page: number
|
||||
size: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user