From 983df11081f16b3003b6f972be40e9090925cb74 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 28 Sep 2026 07:45:57 +0800 Subject: [PATCH] fix(client): render estimated sailing fields from unified orders --- src/modules/first-leg/api/unifiedOrders.ts | 10 +++++++-- .../first-leg/store/firstLegOrders.test.mjs | 21 +++++++++++++++++++ src/modules/first-leg/store/firstLegOrders.ts | 4 ++-- src/modules/first-leg/types/firstLegOrder.ts | 4 ++-- .../views/FirstLegOrdersView.test.mjs | 2 +- .../first-leg/views/FirstLegOrdersView.vue | 8 +++---- 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/modules/first-leg/api/unifiedOrders.ts b/src/modules/first-leg/api/unifiedOrders.ts index 8101851..d1e3d51 100644 --- a/src/modules/first-leg/api/unifiedOrders.ts +++ b/src/modules/first-leg/api/unifiedOrders.ts @@ -48,8 +48,14 @@ export interface MerchantUnifiedTransportSummary { cabinetNo: string | null vesselName: string | null voyageNo: string | null - sailingAt: string | null - portArrivalAt: string | null + estimatedSailingAt: string | null + actualSailingAt: string | null + effectiveSailingAt: string | null + effectiveSailingAtEstimated: boolean | null + estimatedPortArrivalAt: string | null + actualPortArrivalAt: string | null + effectivePortArrivalAt: string | null + effectivePortArrivalAtEstimated: boolean | null } export interface MerchantUnifiedOrderRow { diff --git a/src/modules/first-leg/store/firstLegOrders.test.mjs b/src/modules/first-leg/store/firstLegOrders.test.mjs index 6f6c561..0985d23 100644 --- a/src/modules/first-leg/store/firstLegOrders.test.mjs +++ b/src/modules/first-leg/store/firstLegOrders.test.mjs @@ -1,11 +1,32 @@ import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' +import { runInNewContext } from 'node:vm' +import ts from 'typescript' const storeSource = readFileSync(new URL('./firstLegOrders.ts', import.meta.url), 'utf8') const apiSource = readFileSync(new URL('../api/firstLeg.ts', import.meta.url), 'utf8') const unifiedApiSource = readFileSync(new URL('../api/unifiedOrders.ts', import.meta.url), 'utf8') +test('renders estimated sailing from the current API without substituting actual departure', () => { + const mapper = storeSource.slice(storeSource.indexOf('function businessSummary('), storeSource.indexOf('\nconst unifiedActionLabels')) + const javascript = ts.transpileModule(mapper, { compilerOptions: { target: ts.ScriptTarget.ES2022 } }).outputText + const map = runInNewContext(`${javascript}; businessSummary`) + const transport = { + vesselName: 'REASSIGNED', voyageNo: 'V02', + estimatedSailingAt: '2026-10-07T08:00:00', actualSailingAt: '2026-10-08T09:00:00', + effectiveSailingAt: '2026-10-08T09:00:00', effectiveSailingAtEstimated: false, + estimatedPortArrivalAt: '2026-10-27T08:00:00', actualPortArrivalAt: null, + } + const mapped = map({ transport }) + assert.equal(mapped.estimatedSailingAt, transport.estimatedSailingAt) + assert.equal(mapped.estimatedPortArrivalAt, transport.estimatedPortArrivalAt) + assert.equal(mapped.vesselName, 'REASSIGNED') + assert.equal(mapped.voyageNo, 'V02') + assert.equal(map().estimatedSailingAt, '') + assert.equal(map({ transport: null }).estimatedPortArrivalAt, '') +}) + test('maps the first-leg aggregate list fields without loading detail rows', () => { assert.match(apiSource, /interface MerchantFirstLegOrderRow/) assert.match(apiSource, /skuNos: string \| string\[\] \| null/) diff --git a/src/modules/first-leg/store/firstLegOrders.ts b/src/modules/first-leg/store/firstLegOrders.ts index 96ce9c5..edd4530 100644 --- a/src/modules/first-leg/store/firstLegOrders.ts +++ b/src/modules/first-leg/store/firstLegOrders.ts @@ -220,8 +220,8 @@ function businessSummary(summary?: MerchantUnifiedOrderRow): FirstLegOrder['busi cabinetNo: summary?.transport?.cabinetNo ?? '', vesselName: summary?.transport?.vesselName ?? '', voyageNo: summary?.transport?.voyageNo ?? '', - sailingAt: summary?.transport?.sailingAt ?? '', - portArrivalAt: summary?.transport?.portArrivalAt ?? '', + estimatedSailingAt: summary?.transport?.estimatedSailingAt ?? '', + estimatedPortArrivalAt: summary?.transport?.estimatedPortArrivalAt ?? '', inboundId: summary?.inboundId == null ? '' : String(summary.inboundId), inboundVersion: summary?.inboundVersion ?? null, inboundCode: summary?.inboundCode ?? '', diff --git a/src/modules/first-leg/types/firstLegOrder.ts b/src/modules/first-leg/types/firstLegOrder.ts index 3d7abce..21bf849 100644 --- a/src/modules/first-leg/types/firstLegOrder.ts +++ b/src/modules/first-leg/types/firstLegOrder.ts @@ -87,8 +87,8 @@ export interface FirstLegOrderBusinessSummary { cabinetNo: string vesselName: string voyageNo: string - sailingAt: string - portArrivalAt: string + estimatedSailingAt: string + estimatedPortArrivalAt: string inboundId: string inboundVersion: number | null inboundCode: string diff --git a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs index 7f227ab..5c6964e 100644 --- a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs +++ b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs @@ -729,7 +729,7 @@ test('shows authoritative warehouse, loading and sailing fields on desktop and n } assert.match(source, /businessSummary\.cabinetNo \|\| .*businessSummary\.containerNo/) assert.match(source, /businessSummary\.vesselName.*businessSummary\.voyageNo/s) - assert.match(source, /businessSummary\.sailingAt/) + assert.match(source, /businessSummary\.estimatedSailingAt/) }) test('loads complete order detail before editing and rejects an unavailable historical warehouse', () => { diff --git a/src/modules/first-leg/views/FirstLegOrdersView.vue b/src/modules/first-leg/views/FirstLegOrdersView.vue index 5010781..af9dc8c 100644 --- a/src/modules/first-leg/views/FirstLegOrdersView.vue +++ b/src/modules/first-leg/views/FirstLegOrdersView.vue @@ -144,7 +144,7 @@ const selectableOrderColumns: DataTableColumn[] = [ { key: 'expectedShipDate', label: '期望出运', width: 132, align: 'center', headerAlign: 'center', slotName: 'expectedShipDate' }, { key: 'cabinetNo', label: '柜号 / 柜次', width: 150, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'cabinetNo' }, { key: 'vesselVoyage', label: '船名 / 航次', width: 160, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'vesselVoyage' }, - { key: 'sailingAt', label: '预计船期', width: 164, align: 'center', headerAlign: 'center', slotName: 'sailingAt' }, + { key: 'estimatedSailingAt', label: '预计船期', width: 164, align: 'center', headerAlign: 'center', slotName: 'estimatedSailingAt' }, { key: 'createdAt', label: '创建时间', width: 164, align: 'center', headerAlign: 'center', slotName: 'createdAt' }, { key: 'updatedAt', label: '更新时间', width: 164, align: 'center', headerAlign: 'center', slotName: 'updatedAt' }, ] @@ -572,7 +572,7 @@ const progressSummaryItems = computed(() => { const cabinetProgressItems = computed(() => { const summary = detailOrder.value?.businessSummary if (!summary || (!summary.cabinetNo && !summary.containerNo)) return [] - return [{ cabinetId: summary.cabinetNo || summary.containerNo, cabinetNo: summary.cabinetNo || summary.containerNo, status: summary.loadingStatus || '待更新', vesselName: summary.vesselName, voyageNo: summary.voyageNo, sailingAt: summary.sailingAt }] + return [{ cabinetId: summary.cabinetNo || summary.containerNo, cabinetNo: summary.cabinetNo || summary.containerNo, status: summary.loadingStatus || '待更新', vesselName: summary.vesselName, voyageNo: summary.voyageNo, estimatedSailingAt: summary.estimatedSailingAt }] }) const selectedWarehouse = computed(() => availableWarehouses.value.find((item) => item.id === form.receivingWarehouseId)) const selectedDestinationWarehouse = computed(() => store.warehouses.find((item) => item.id === form.destinationWarehouseId && item.warehouseType === form.destinationType)) @@ -2147,7 +2147,7 @@ async function searchOrders(model: QueryModel) { - +