diff --git a/src/modules/first-leg/api/unifiedOrders.ts b/src/modules/first-leg/api/unifiedOrders.ts index 490f768..dfab37f 100644 --- a/src/modules/first-leg/api/unifiedOrders.ts +++ b/src/modules/first-leg/api/unifiedOrders.ts @@ -86,6 +86,7 @@ export interface MerchantUnifiedOrderRow { loading: MerchantUnifiedLoadingSummary | null delivery: MerchantUnifiedDeliverySummary | null transport: MerchantUnifiedTransportSummary | null + customerRemark: string | null createdAt: string updatedAt: string } diff --git a/src/modules/first-leg/store/firstLegOrders.test.mjs b/src/modules/first-leg/store/firstLegOrders.test.mjs index b4ca59d..ae720a8 100644 --- a/src/modules/first-leg/store/firstLegOrders.test.mjs +++ b/src/modules/first-leg/store/firstLegOrders.test.mjs @@ -19,7 +19,8 @@ test('maps the first-leg aggregate list fields without loading detail rows', () assert.match(storeSource, /row\.cargoes/) assert.match(storeSource, /chargeableWeightKg: null/) assert.match(storeSource, /chargeableVolumeCbm: null/) - assert.match(storeSource, /orders\.value = orderResult\.value\.records\.map\(mapFirstLegOrderRow\)/) + assert.match(storeSource, /orderResult\.value\.records\.map\(mapFirstLegOrderRow\)/) + assert.match(storeSource, /orderResult\.value\.records\.map\(\(item\) => mapUnifiedOrderRow\(item, warehouses\.value\)\)/) }) test('declares the documented merchant warehouse and first-leg endpoints', () => { @@ -69,6 +70,7 @@ test('declares the final C02 row and detail contract in the API adapter', () => assert.match(unifiedApiSource, /orderId: number \| string/) assert.match(unifiedApiSource, /mainStatus: ApiUnifiedOrderMainStatus/) assert.match(unifiedApiSource, /nextAction: string \| null/) + assert.match(unifiedApiSource, /customerRemark: string \| null/) assert.match(unifiedApiSource, /loadingVersion: number/) assert.match(unifiedApiSource, /pickingVersion: number/) assert.match(unifiedApiSource, /summary: MerchantUnifiedOrderRow/) @@ -103,6 +105,7 @@ test('maps C02 rows by orderId and leaves absent transport details unknown', () assert.match(storeSource, /summary\?\.loading\?\.loadingVersion/) assert.match(storeSource, /summary\?\.loading\?\.pickingVersion/) assert.match(storeSource, /summary\?\.inboundId == null \? '' : String\(summary\.inboundId\)/) + assert.match(storeSource, /customerRemark: summary\.customerRemark \?\? ''/) }) test('sends backend-required channel, pricing, customs, destination and cargo fields', () => { diff --git a/src/modules/first-leg/store/firstLegOrders.ts b/src/modules/first-leg/store/firstLegOrders.ts index cf0e33b..0262a74 100644 --- a/src/modules/first-leg/store/firstLegOrders.ts +++ b/src/modules/first-leg/store/firstLegOrders.ts @@ -357,7 +357,7 @@ function mapUnifiedOrderRow(summary: MerchantUnifiedOrderRow, warehouses: Platfo shipper: '', consigneePartyId: '', consigneePartySnapshot: null, consignee: '', expressCompanyName: summary.expressCompany ?? '', trackingNumber: summary.delivery?.trackingNo ?? '', skuNos: summary.skuNos ?? [], totalNetWeightKg: summary.totalNetWeightKg ?? null, totalQuantity: summary.totalQuantity ?? null, chargeableVolumeCbm: null, - inboundedAt: summary.inboundedAt ?? '', businessDate: '', priority: 'NORMAL', customerRemark: '', operatorName: '', + inboundedAt: summary.inboundedAt ?? '', businessDate: summary.businessDate ?? '', priority: 'NORMAL', customerRemark: summary.customerRemark ?? '', operatorName: '', status: summary.mainStatus, version: 0, items: [], timeline: [], businessSummary: businessSummary(summary), createdAt: summary.createdAt, updatedAt: summary.updatedAt, tradeTerm: '', destinationCountryCode: '', destinationWarehouseId: summary.destinationWarehouseId == null ? '' : String(summary.destinationWarehouseId), @@ -411,6 +411,7 @@ function mapUnifiedOrderDetail(detail: MerchantUnifiedOrderDetail, warehouses: P type OrderListReadResult = | { source: 'first-leg'; records: MerchantFirstLegOrderRow[] } + | { source: 'unified'; records: MerchantUnifiedOrderRow[]; drafts: MerchantFirstLegOrderRow[] } interface ClientOrderReadQuery extends MerchantUnifiedOrderQuery { draftOnly?: boolean @@ -427,9 +428,35 @@ function legacyQuery(query: ClientOrderReadQuery, status?: ApiFirstLegStatus) { } async function getOrdersForClient(query: ClientOrderReadQuery = {}): Promise { - const status = query.draftOnly ? 'DRAFT' : undefined - const response = await getMerchantFirstLegOrders(legacyQuery(query, status)) - return { source: 'first-leg', records: response.records } + if (query.draftOnly) { + const response = await getMerchantFirstLegOrders(legacyQuery(query, 'DRAFT')) + return { source: 'first-leg', records: response.records } + } + + const unifiedQuery: MerchantUnifiedOrderQuery = { + keyword: query.keyword, + orderNo: query.orderNo, + mainStatus: query.mainStatus, + receivingWarehouseId: query.receivingWarehouseId, + destinationWarehouseId: query.destinationWarehouseId, + createdFrom: query.createdFrom, + createdTo: query.createdTo, + page: query.page, + size: query.size, + } + try { + const [response, draftResponse] = await Promise.all([ + getMerchantUnifiedOrders(unifiedQuery), + query.includeDrafts + ? getMerchantFirstLegOrders(legacyQuery(query, 'DRAFT')) + : Promise.resolve({ records: [] as MerchantFirstLegOrderRow[] }), + ]) + return { source: 'unified', records: response.records, drafts: draftResponse.records } + } catch (error) { + if (!isUnifiedOrderQueryUnavailable(error)) throw error + const response = await getMerchantFirstLegOrders(legacyQuery(query)) + return { source: 'first-leg', records: response.records } + } } function mapWarehouse(item: MerchantWarehouse): ClientWarehouse { @@ -495,7 +522,12 @@ export const useFirstLegOrdersStore = defineStore('client-first-leg-orders', () const [orderResult, warehouseResult] = await Promise.allSettled([getOrdersForClient(query), loadWarehouseType('DOMESTIC', true)]) if (warehouseResult.status === 'rejected' && !warehouseLoadError.value) warehouseLoadError.value = warehouseResult.reason instanceof Error ? warehouseResult.reason.message : '公共仓库数据加载失败' if (orderResult.status === 'fulfilled') { - orders.value = orderResult.value.records.map(mapFirstLegOrderRow) + orders.value = orderResult.value.source === 'unified' + ? [ + ...orderResult.value.drafts.map(mapFirstLegOrderRow), + ...orderResult.value.records.map((item) => mapUnifiedOrderRow(item, warehouses.value)), + ] + : orderResult.value.records.map(mapFirstLegOrderRow) } else { loadError.value = orderResult.reason instanceof Error ? orderResult.reason.message : '订单数据加载失败' } diff --git a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs index c9f9216..36e93a9 100644 --- a/src/modules/first-leg/views/FirstLegOrdersView.test.mjs +++ b/src/modules/first-leg/views/FirstLegOrdersView.test.mjs @@ -480,6 +480,15 @@ test('copies reactive order drafts into plain request data', () => { assert.doesNotMatch(source, /structuredClone\((?:form|order\.)/) }) +test('shows authoritative warehouse, loading and sailing fields on desktop and narrow screens', () => { + for (const label of ['国内收货仓', '期望出运', '柜号 / 柜次', '船名 / 航次', '预计船期', '更新时间']) { + assert.match(source, new RegExp(label.replace('/', '\\/'))) + } + assert.match(source, /businessSummary\.cabinetNo \|\| .*businessSummary\.containerNo/) + assert.match(source, /businessSummary\.vesselName.*businessSummary\.voyageNo/s) + assert.match(source, /businessSummary\.sailingAt/) +}) + test('loads complete order detail before editing and rejects an unavailable historical warehouse', () => { assert.match(source, /async function openEdit\(order: FirstLegOrder\)/) assert.match(source, /const detailedOrder = await store\.loadDetail\(order\.id\)/) diff --git a/src/modules/first-leg/views/FirstLegOrdersView.vue b/src/modules/first-leg/views/FirstLegOrdersView.vue index e83d6c1..35a0ba5 100644 --- a/src/modules/first-leg/views/FirstLegOrdersView.vue +++ b/src/modules/first-leg/views/FirstLegOrdersView.vue @@ -94,6 +94,7 @@ const fixedOrderColumns: DataTableColumn[] = [ const selectableOrderColumns: DataTableColumn[] = [ { key: 'inboundCode', label: '入仓码', width: 176, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'inboundCode' }, { key: 'channel', label: '渠道', width: 150, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'channel' }, + { 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: 'status', label: '当前订单状态', width: 126, align: 'center', headerAlign: 'center', slotName: 'status' }, { key: 'packageCount', label: '箱数', width: 82, align: 'center', headerAlign: 'center', slotName: 'packageCount' }, @@ -112,7 +113,12 @@ const selectableOrderColumns: DataTableColumn[] = [ { key: 'referenceId', label: '跟踪编号', width: 150, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'referenceId' }, { key: 'receivingTime', label: '国内仓入库时间', width: 164, align: 'center', headerAlign: 'center', slotName: 'receivingTime' }, { key: 'businessDate', label: '业务日期', width: 148, align: 'center', headerAlign: 'center', slotName: 'businessDate' }, + { 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: 'createdAt', label: '创建时间', width: 164, align: 'center', headerAlign: 'center', slotName: 'createdAt' }, + { key: 'updatedAt', label: '更新时间', width: 164, align: 'center', headerAlign: 'center', slotName: 'updatedAt' }, ] const allSelectableColumnKeys = selectableOrderColumns.map((column) => String(column.key)) const visibleColumnKeys = ref([...allSelectableColumnKeys]) @@ -1543,6 +1549,7 @@ async function searchOrders(model: QueryModel) { + @@ -1561,7 +1568,12 @@ async function searchOrders(model: QueryModel) { + + + + +