diff --git a/shared/src/index.ts b/shared/src/index.ts index 42c4559..a1a89da 100644 --- a/shared/src/index.ts +++ b/shared/src/index.ts @@ -91,6 +91,7 @@ export const FIRST_LEG_ORDER_STATUSES = [ { code: 'LOADING', label: '装柜中' }, { code: 'LOADED', label: '装柜完成' }, { code: 'DELIVERED', label: '派送完成' }, + { code: 'COMPLETED', label: '已完成' }, ] as const export type FirstLegOrderStatus = (typeof FIRST_LEG_ORDER_STATUSES)[number]['code'] diff --git a/src/modules/first-leg/api/unifiedOrders.ts b/src/modules/first-leg/api/unifiedOrders.ts index 944a78f..8101851 100644 --- a/src/modules/first-leg/api/unifiedOrders.ts +++ b/src/modules/first-leg/api/unifiedOrders.ts @@ -9,6 +9,7 @@ export type ApiUnifiedOrderMainStatus = | 'LOADING' | 'LOADED' | 'DELIVERED' + | 'COMPLETED' export interface MerchantUnifiedMeasurementSummary { reviewStatus: string | null diff --git a/src/modules/first-leg/components/OrderProgressPanel.vue b/src/modules/first-leg/components/OrderProgressPanel.vue index d56f20c..bcdc0cc 100644 --- a/src/modules/first-leg/components/OrderProgressPanel.vue +++ b/src/modules/first-leg/components/OrderProgressPanel.vue @@ -6,6 +6,7 @@ import { FIRST_LEG_PROGRESS_STAGES, getFirstLegProgressIndex, getFirstLegStatusLabel, + getFirstLegStatusTone, } from '@/modules/first-leg/utils/firstLegOrder' const props = defineProps<{ order: FirstLegOrder }>() @@ -25,7 +26,7 @@ function stageState(index: number) {

订单进度

国内入仓、组托、装柜及后续履约同步 - + {{ getFirstLegStatusLabel(order.status) }} @@ -49,7 +50,7 @@ function stageState(index: number) { .progress-heading h3 { margin: 0; color: var(--navy); } .progress-heading h3 { font-size: 15px; } .progress-heading span { color: var(--muted); font-size: 11px; } -.progress-stages { display: grid; grid-template-columns: repeat(7, minmax(76px, 1fr)); margin: 16px 0 0; padding: 0; overflow-x: auto; list-style: none; } +.progress-stages { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(76px, 1fr); margin: 16px 0 0; padding: 0; overflow-x: auto; list-style: none; } .progress-stages li { position: relative; display: flex; min-width: 76px; align-items: center; flex-direction: column; gap: 7px; color: #96a0a6; font-size: 10px; text-align: center; } .progress-stages li::before { position: absolute; top: 10px; right: 50%; left: -50%; height: 2px; background: #e1e6e8; content: ''; } .progress-stages li:first-child::before { display: none; } @@ -60,7 +61,7 @@ function stageState(index: number) { .is-current .stage-label { color: var(--navy); font-weight: 700; } .draft-progress-note { margin: 12px 0 0; padding: 10px 12px; background: #f6f8f8; color: var(--muted); font-size: 11px; } @media (max-width: 720px) { - .progress-stages { grid-template-columns: repeat(7, 82px); padding-bottom: 8px; } + .progress-stages { grid-auto-columns: 82px; padding-bottom: 8px; } .progress-heading { align-items: flex-start; } } diff --git a/src/modules/first-leg/store/firstLegOrders.test.mjs b/src/modules/first-leg/store/firstLegOrders.test.mjs index 9cdeba9..272f2ba 100644 --- a/src/modules/first-leg/store/firstLegOrders.test.mjs +++ b/src/modules/first-leg/store/firstLegOrders.test.mjs @@ -60,7 +60,7 @@ test('maps transport and status fields instead of treating container mode as tra assert.match(storeSource, /status === 'SUBMITTED'\) return 'PENDING_REVIEW'/) assert.match(storeSource, /status === 'REJECTED'\) return 'PENDING_REVIEW'/) assert.match(storeSource, /status === 'APPROVED' \|\| status === 'ACCEPTED' \|\| status === 'PROCESSING'\) return 'WAIT_MEASURE'/) - assert.match(storeSource, /status === 'COMPLETED'\) return 'LOADED'/) + assert.match(storeSource, /status === 'COMPLETED'\) return 'COMPLETED'/) assert.doesNotMatch(storeSource, /status === 'COMPLETED'\) return 'DELIVERED'/) }) diff --git a/src/modules/first-leg/store/firstLegOrders.ts b/src/modules/first-leg/store/firstLegOrders.ts index 2feaf38..d202fc2 100644 --- a/src/modules/first-leg/store/firstLegOrders.ts +++ b/src/modules/first-leg/store/firstLegOrders.ts @@ -45,7 +45,7 @@ function clientStatus(status: ApiFirstLegStatus): FirstLegOrder['status'] { // 后端联调任务曾出现 REJECTED,但一期已确认订单不设驳回状态;兼容旧数据时仍按待审核展示。 if (status === 'REJECTED') return 'PENDING_REVIEW' if (status === 'APPROVED' || status === 'ACCEPTED' || status === 'PROCESSING') return 'WAIT_MEASURE' - if (status === 'COMPLETED') return 'LOADED' + if (status === 'COMPLETED') return 'COMPLETED' if (status === 'CANCELLED') return 'PENDING_REVIEW' return 'PENDING_REVIEW' } diff --git a/src/modules/first-leg/utils/firstLegOrder.test.mjs b/src/modules/first-leg/utils/firstLegOrder.test.mjs index fc56662..c412805 100644 --- a/src/modules/first-leg/utils/firstLegOrder.test.mjs +++ b/src/modules/first-leg/utils/firstLegOrder.test.mjs @@ -68,7 +68,7 @@ test('uses the confirmed status and transport labels', () => { assert.equal(getFirstLegStatusLabel('DELIVERED'), '派送完成') assert.equal(getFirstLegTransportModeLabel('FCL'), '海运整箱 FCL') assert.deepEqual(FIRST_LEG_PROGRESS_STAGES.map((item) => item.code), [ - 'PENDING_REVIEW', 'WAIT_MEASURE', 'WAIT_PALLETIZE', 'WAIT_SPLIT', 'LOADING', 'LOADED', 'DELIVERED', + 'PENDING_REVIEW', 'WAIT_MEASURE', 'WAIT_PALLETIZE', 'WAIT_SPLIT', 'LOADING', 'LOADED', 'DELIVERED', 'COMPLETED', ]) assert.equal(getFirstLegProgressIndex('WAIT_PALLETIZE'), 2) }) @@ -207,5 +207,8 @@ test('distinguishes first-leg draft, review, active handling and completion', () } assert.equal(getFirstLegStatusTone('LOADED'), 'success') assert.equal(getFirstLegStatusTone('DELIVERED'), 'success') + assert.equal(getFirstLegStatusTone('COMPLETED'), 'success') + assert.equal(getFirstLegStatusLabel('COMPLETED'), '已完成') + assert.equal(getFirstLegStatusLabel('UNRECOGNIZED'), '未知状态') assert.equal(getFirstLegStatusTone('UNRECOGNIZED'), 'info') }) diff --git a/src/modules/first-leg/utils/firstLegOrder.ts b/src/modules/first-leg/utils/firstLegOrder.ts index e8fd6fc..129667f 100644 --- a/src/modules/first-leg/utils/firstLegOrder.ts +++ b/src/modules/first-leg/utils/firstLegOrder.ts @@ -15,7 +15,7 @@ const transportModeLabels = new Map( ) export function getFirstLegStatusLabel(status: FirstLegOrderStatus) { - return statusLabels.get(status) ?? status + return statusLabels.get(status) ?? '未知状态' } export function getFirstLegTransportModeLabel(mode: FirstLegTransportMode | null) { @@ -24,7 +24,7 @@ export function getFirstLegTransportModeLabel(mode: FirstLegTransportMode | null } export function getFirstLegStatusTone(status: FirstLegOrderStatus): 'success' | 'warning' | 'info' | 'primary' { - if (status === 'DELIVERED' || status === 'LOADED') return 'success' + if (status === 'DELIVERED' || status === 'LOADED' || status === 'COMPLETED') return 'success' if (status === 'DRAFT') return 'info' if (status === 'PENDING_REVIEW') return 'warning' if (['WAIT_MEASURE', 'WAIT_PALLETIZE', 'WAIT_SPLIT', 'LOADING'].includes(status)) return 'primary' diff --git a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs index 45427c6..afcc746 100644 --- a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs +++ b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs @@ -233,8 +233,8 @@ test('shows and searches the inbound code after a draft is submitted', () => { assert.match(source, /—<\/span>/) }) -test('keeps the seven-stage progress and business summary usable on mobile', () => { - assert.match(progressSource, /grid-template-columns: repeat\(7, 82px\)/) +test('keeps all progress stages and business summary usable on mobile', () => { + assert.match(progressSource, /grid-auto-columns: 82px/) assert.match(progressSource, /overflow-x: auto/) assert.match(source, /\.fulfillment-summary \{ grid-template-columns: 1fr; \}/) }) diff --git a/src/modules/first-leg/views/FirstLegOrdersView.vue b/src/modules/first-leg/views/FirstLegOrdersView.vue index 3ce3488..1a6fea7 100644 --- a/src/modules/first-leg/views/FirstLegOrdersView.vue +++ b/src/modules/first-leg/views/FirstLegOrdersView.vue @@ -112,10 +112,11 @@ const batchImportError = ref('') const fixedOrderColumns: DataTableColumn[] = [ { key: 'selection', type: 'selection', width: 48, fixed: 'left', reserveSelection: true }, { key: 'actions', label: '操作', width: 284, fixed: 'left', align: 'left', headerAlign: 'left', slotName: 'actions' }, - { key: 'order', label: '订单号', width: 190, fixed: 'left', align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'order' }, + { key: 'order', label: '订单号', width: 240, fixed: 'left', align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'order' }, ] const selectableOrderColumns: DataTableColumn[] = [ - { key: 'inboundCode', label: '入仓码', width: 176, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'inboundCode' }, + { key: 'inboundCode', label: '入仓码', width: 230, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'inboundCode' }, + { key: 'status', label: '当前订单状态', width: 126, align: 'center', headerAlign: 'center', slotName: 'status' }, { key: 'channel', label: '渠道', width: 150, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'channel' }, { key: 'transportMode', label: '运输方式', width: 104, align: 'center', headerAlign: 'center', slotName: 'transportMode' }, { key: 'pickupMethod', label: '交货方式', width: 112, align: 'center', headerAlign: 'center', slotName: 'pickupMethod' }, @@ -123,7 +124,6 @@ const selectableOrderColumns: DataTableColumn[] = [ { key: 'receivingWarehouse', label: '国内收货仓', width: 150, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'receivingWarehouse' }, { key: 'destinationWarehouse', label: '目的仓', width: 120, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'destinationWarehouse' }, { key: 'destinationType', label: '目的仓类型', width: 112, align: 'center', headerAlign: 'center', slotName: 'destinationType' }, - { key: 'status', label: '当前订单状态', width: 126, align: 'center', headerAlign: 'center', slotName: 'status' }, { key: 'packageCount', label: '箱数', width: 82, align: 'center', headerAlign: 'center', slotName: 'packageCount' }, { key: 'expressCompany', label: '快递公司', width: 128, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'expressCompany' }, { key: 'trackingNumber', label: '快递单号', width: 158, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'trackingNumber' },