diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts index 2fc61325..6db8959d 100644 --- a/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts +++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.test.ts @@ -395,12 +395,33 @@ describe('GlobalSmartLoadingView', () => { 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', 'expectedArrivalRange', 'orderStatus']) expect(fields.find((field) => field.key === 'warehouseId')?.options).toEqual([{ label: '义乌仓', value: '8' }]) + expect(fields.find((field) => field.key === 'orderStatus')?.options).toEqual([ + { value: '', label: '全部' }, + { value: 'PENDING_REVIEW', label: '待审核' }, + { value: 'WAIT_MEASURE', label: '待测量数据' }, + { value: 'WAIT_SPLIT', label: '待分柜' }, + { value: 'LOADING', label: '装柜中' }, + ]) expect(source).not.toContain('目的仓') expect(wrapper.text()).not.toContain('税率') expect(wrapper.text()).not.toContain('是否退税') }) + it('filters completed loading candidates out even when all statuses are selected', async () => { + vi.mocked(listSmartLoadingCandidates).mockResolvedValue([ + candidate, + { ...candidate, inboundId: '6', orderId: '8', inboundCode: 'IN-LOADED', orderStatusSnapshot: 'LOADED' }, + { ...candidate, inboundId: '7', orderId: '9', inboundCode: 'IN-COMPLETED', orderStatusSnapshot: 'COMPLETED' }, + ]) + const wrapper = mount(GlobalSmartLoadingView, { global: { plugins: [ElementPlus] } }) + await flushPromises() + + expect(wrapper.get('.candidate-pane').text()).toContain('IN-2') + expect(wrapper.get('.candidate-pane').text()).not.toContain('IN-LOADED') + expect(wrapper.get('.candidate-pane').text()).not.toContain('IN-COMPLETED') + }) + it('prefers an editing container on first load while keeping loading containers available', async () => { const pushed = { ...container, id: '9007199254740995', planStatus: 'LOADING' as const } vi.mocked(listContainers).mockResolvedValue({ records: [pushed, container], page: 1, size: 100, total: 2, pages: 1 }) diff --git a/src/modules/container-loading/pages/GlobalSmartLoadingView.vue b/src/modules/container-loading/pages/GlobalSmartLoadingView.vue index 4b1cce18..bf1de4a7 100644 --- a/src/modules/container-loading/pages/GlobalSmartLoadingView.vue +++ b/src/modules/container-loading/pages/GlobalSmartLoadingView.vue @@ -179,24 +179,26 @@ const volumePercent = computed(() => volumeLimit.value ? totalVolume.value / vol const weightPercent = computed(() => weightLimit.value ? totalWeight.value / weightLimit.value * 100 : 0) const displayedVolumePercent = computed(() => percentage(volumePercent.value)) const displayedWeightPercent = computed(() => percentage(weightPercent.value)) -const candidateOrderStatusLabels: Record = { - DRAFT: '草稿', SUBMITTED: '待审核', PENDING_REVIEW: '待审核', APPROVED: '已审核', ACCEPTED: '已受理', - REJECTED: '已驳回', PROCESSING: '处理中', WAIT_MEASURE: '待测量数据', WAIT_SPLIT: '待分柜', - LOADING: '装柜中', LOADED: '装柜完成', COMPLETED: '已完成', DELIVERED: '派送完成', CANCELLED: '已取消', +const candidateOrderStatusOptions = [ + { value: '', label: '全部' }, + { value: 'PENDING_REVIEW', label: '待审核' }, + { value: 'WAIT_MEASURE', label: '待测量数据' }, + { value: 'WAIT_SPLIT', label: '待分柜' }, + { value: 'LOADING', label: '装柜中' }, +] +const candidateOrderStatusGroups: Record = { + PENDING_REVIEW: ['SUBMITTED', 'PENDING_REVIEW'], + WAIT_MEASURE: ['WAIT_MEASURE'], + WAIT_SPLIT: ['WAIT_SPLIT'], + LOADING: ['LOADING'], } -function candidateOrderStatusLabel(status: string) { - return candidateOrderStatusLabels[status] || '未知状态' -} -const candidateOrderStatusOptions = computed(() => [...new Set(candidates.value - .map((candidate) => candidate.orderStatusSnapshot?.trim().toUpperCase() || '') - .filter(Boolean))] - .map((status) => ({ value: status, label: candidateOrderStatusLabel(status) }))) +const completedCandidateOrderStatuses = new Set(['LOADED', 'COMPLETED']) const queryFields = computed(() => [ { key: 'warehouseId', type: 'select', label: '发货仓', placeholder: '全部发货仓', width: 160, options: warehouseOptions.value, props: { filterable: true } }, { 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: 'expectedArrivalRange', type: 'daterange', label: '预计到货时间', placeholder: '请选择预计到货时间范围', width: 260 }, - { key: 'orderStatus', type: 'select', label: '订单状态', placeholder: '全部订单状态', width: 160, options: candidateOrderStatusOptions.value }, + { key: 'orderStatus', type: 'select', label: '订单状态', placeholder: '全部订单状态', width: 160, options: candidateOrderStatusOptions }, ]) const filteredContainers = computed(() => containers.value.filter((item) => ( @@ -214,9 +216,10 @@ const filteredCandidates = computed(() => { const channelCode = selectedContainer.value?.channelCode return displayedCandidates.value.filter((item) => { if (!channelCode || item.channelCode !== channelCode) return false + if (item.sourceCandidates.some((member) => completedCandidateOrderStatuses.has(member.orderStatusSnapshot?.trim().toUpperCase() || ''))) return false if (customerId && !item.sourceCandidates.some((member) => member.accountId === customerId)) return false if (inboundCode && !item.memberInboundCodes.some((code) => code.toLowerCase().includes(inboundCode))) return false - if (orderStatus && !item.sourceCandidates.some((member) => member.orderStatusSnapshot?.trim().toUpperCase() === orderStatus)) return false + if (orderStatus && !item.sourceCandidates.some((member) => candidateOrderStatusGroups[orderStatus]?.includes(member.orderStatusSnapshot?.trim().toUpperCase() || ''))) return false if (arrivalRange.length === 2 && !item.sourceCandidates.some((member) => { const arrivalDate = member.expectedArrivalAt?.slice(0, 10) || '' return arrivalDate && arrivalDate >= arrivalRange[0] && arrivalDate <= arrivalRange[1] diff --git a/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts b/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts index b1f5faed..e53dc6d4 100644 --- a/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts +++ b/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts @@ -461,8 +461,10 @@ describe('UnifiedOrdersView contract', () => { expect(routeSource).not.toContain('unified-order-workflow') }) - it('only exposes declaration editing on approved editable details and marks channel changes', () => { - expect(source).toContain("detail.value.summary.mainStatus === 'WAIT_MEASURE'") + it('only exposes declaration editing before loading and marks channel changes', () => { + expect(source).toContain("new Set(['PENDING_REVIEW', 'WAIT_MEASURE', 'WAIT_SPLIT'])") + expect(source).toContain('declarationEditableStatuses.has(detail.value.summary.mainStatus)') + expect(source).not.toContain("detail.value.summary.mainStatus === 'WAIT_MEASURE'") expect(source).toContain("can('platform:order:declaration:edit')") expect(source).toContain('编辑客户申报资料') expect(source).toContain('(['PENDING_REVIEW', 'WAIT_MEASURE', 'WAIT_SPLIT']) const canEditDeclaration = computed(() => Boolean( detail.value - && detail.value.summary.mainStatus === 'WAIT_MEASURE' + && declarationEditableStatuses.has(detail.value.summary.mainStatus) && detail.value.order.order?.version !== null && detail.value.order.order?.version !== undefined && can('platform:order:declaration:edit'),