From 0e67cb9d651da87398b476de7722b5b3c8636029 Mon Sep 17 00:00:00 2001 From: liuyihe <2513762445@qq.com> Date: Fri, 21 Aug 2026 18:16:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../overseas-warehouse/api/dispatches.test.ts | 10 +- .../overseas-warehouse/api/dispatches.ts | 26 +++ .../pages/DispatchDetailView.vue | 167 ++++++++++++++++++ .../pages/DispatchesView.vue | 6 + .../pages/InventoryView.vue | 2 - .../pages/prototypeContract.test.ts | 21 ++- src/modules/overseas-warehouse/routes.test.ts | 3 +- src/modules/overseas-warehouse/routes.ts | 6 + 8 files changed, 233 insertions(+), 8 deletions(-) create mode 100644 src/modules/overseas-warehouse/pages/DispatchDetailView.vue diff --git a/src/modules/overseas-warehouse/api/dispatches.test.ts b/src/modules/overseas-warehouse/api/dispatches.test.ts index 9bfebc89..804d6884 100644 --- a/src/modules/overseas-warehouse/api/dispatches.test.ts +++ b/src/modules/overseas-warehouse/api/dispatches.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { overseasHttp } from '@/shared/api/overseasHttp' -import { listDispatchCandidates, listDispatches, lockDispatchDraftPallet, preArrangeDispatch, releaseDispatchDraft, unlockDispatchDraftPallet } from './dispatches' +import { getDispatch, listDispatchCandidates, listDispatches, lockDispatchDraftPallet, preArrangeDispatch, releaseDispatchDraft, unlockDispatchDraftPallet } from './dispatches' vi.mock('@/shared/api/overseasHttp', () => ({ overseasHttp: { get: vi.fn(), post: vi.fn() } })) @@ -28,6 +28,14 @@ describe('dispatch overseas API', () => { }) }) + it('loads a platform dispatch detail by encoded dispatch number', async () => { + vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: { id: '1', dispatchNo: 'PC/1' } }) + + await getDispatch('PC/1') + + expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/dispatches/PC%2F1') + }) + it('loads candidates and creates a pre-arrange dispatch in an explicit customer scope', async () => { vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: [] }) vi.mocked(overseasHttp.post).mockResolvedValue({ code: '200', message: 'success', data: { id: '1', dispatchNo: 'PC-1' } }) diff --git a/src/modules/overseas-warehouse/api/dispatches.ts b/src/modules/overseas-warehouse/api/dispatches.ts index e2ca48b7..aee553e7 100644 --- a/src/modules/overseas-warehouse/api/dispatches.ts +++ b/src/modules/overseas-warehouse/api/dispatches.ts @@ -84,6 +84,25 @@ export interface DispatchSummaryDto { remainingPackageCount?: number | null partialCompletionReason?: string | null createdAt?: string | null + items?: DispatchItemDto[] +} + +export interface DispatchItemDto { + id: string + planPalletId: string + warehousePalletId?: string | null + palletNo?: string | null + overseasWarehouseId?: string | null + overseasWarehouseName?: string | null + orderNo?: string | null + orderRefs?: string | null + inboundCode?: string | null + destinationWarehouseCode?: string | null + destinationWarehouseName?: string | null + fbaWarehouseCode?: string | null + packageCount?: number | null + volumeCbm?: number | null + sourceStage?: string | null } export async function listDispatches(query: DispatchQuery) { @@ -94,6 +113,13 @@ export async function listDispatches(query: DispatchQuery) { return unwrapApiResponse(response) } +export async function getDispatch(dispatchNo: string) { + const response = await overseasHttp.get, ApiEnvelope>( + `/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}`, + ) + return unwrapApiResponse(response) +} + export async function listDispatchCandidates(query: DispatchCandidateQuery) { const response = await overseasHttp.get, ApiEnvelope>( '/platform/v1/last-leg/dispatches/candidates', diff --git a/src/modules/overseas-warehouse/pages/DispatchDetailView.vue b/src/modules/overseas-warehouse/pages/DispatchDetailView.vue new file mode 100644 index 00000000..d6f6f95c --- /dev/null +++ b/src/modules/overseas-warehouse/pages/DispatchDetailView.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/src/modules/overseas-warehouse/pages/DispatchesView.vue b/src/modules/overseas-warehouse/pages/DispatchesView.vue index 9f9ed5b3..43851b26 100644 --- a/src/modules/overseas-warehouse/pages/DispatchesView.vue +++ b/src/modules/overseas-warehouse/pages/DispatchesView.vue @@ -1,5 +1,7 @@ @@ -141,6 +146,7 @@ onMounted(load)
+
diff --git a/src/modules/overseas-warehouse/pages/InventoryView.vue b/src/modules/overseas-warehouse/pages/InventoryView.vue index 9eed9838..14566ec6 100644 --- a/src/modules/overseas-warehouse/pages/InventoryView.vue +++ b/src/modules/overseas-warehouse/pages/InventoryView.vue @@ -53,8 +53,6 @@ const columns: DataTableColumn[] = [ { key: 'held', prop: 'held', label: '暂扣库存', width: 105, align: 'right' }, { key: 'looseboard', prop: 'looseboard', label: '美本土散板', width: 115, align: 'right' }, { key: 'inTransit', prop: 'inTransit', label: '在途库存', width: 105, align: 'right' }, - { key: 'purchase', prop: 'purchase', label: '采购库存', width: 105, align: 'right' }, - { key: 'status', prop: 'status', label: '库存状态', width: 110 }, { key: 'updatedAt', prop: 'updatedAt', label: '更新时间', minWidth: 150 }, ] diff --git a/src/modules/overseas-warehouse/pages/prototypeContract.test.ts b/src/modules/overseas-warehouse/pages/prototypeContract.test.ts index 408cabf2..cbea5ee2 100644 --- a/src/modules/overseas-warehouse/pages/prototypeContract.test.ts +++ b/src/modules/overseas-warehouse/pages/prototypeContract.test.ts @@ -41,7 +41,7 @@ describe('overseas warehouse first-batch prototype contract', () => { }) it('keeps the operation column first on every business list', () => { - for (const fileName of ['LastMileOrdersView.vue', 'InboundOrdersView.vue', 'InventoryView.vue', 'RelabelOrdersView.vue', 'PalletsView.vue', 'CartonsView.vue', 'ProductsView.vue']) { + for (const fileName of ['LastMileOrdersView.vue', 'InboundOrdersView.vue', 'DispatchesView.vue', 'InventoryView.vue', 'RelabelOrdersView.vue', 'PalletsView.vue', 'CartonsView.vue', 'ProductsView.vue']) { const value = source(fileName) const columns = value.slice(value.indexOf('const columns: DataTableColumn[]')) expect(columns.match(/\{\s*key: '([^']+)'/)?.[1]).toBe('actions') @@ -105,8 +105,8 @@ describe('overseas warehouse first-batch prototype contract', () => { expect(pallets).toContain('ElMessage.success') }) - it('implements three prototype-defined details as formal pages', () => { - for (const fileName of ['LastMileOrderDetailView.vue', 'InboundOrderDetailView.vue', 'InventoryDetailView.vue']) { + it('implements prototype-defined details as formal pages', () => { + for (const fileName of ['LastMileOrderDetailView.vue', 'InboundOrderDetailView.vue', 'DispatchDetailView.vue', 'InventoryDetailView.vue']) { const value = source(fileName) expect(value).toContain(' { const expected = [ ['LastMileOrdersView.vue', 'overseas-last-mile-order-detail'], ['InboundOrdersView.vue', 'overseas-inbound-order-detail'], + ['DispatchesView.vue', 'overseas-dispatch-detail'], ['InventoryView.vue', 'overseas-inventory-detail'], ['RelabelOrdersView.vue', 'overseas-relabel-order-detail'], ['PalletsView.vue', 'overseas-pallet-detail'], @@ -283,6 +284,18 @@ describe('overseas warehouse first-batch prototype contract', () => { } }) + it('connects the dispatch prototype detail to the real overseas API', () => { + const detail = source('DispatchDetailView.vue') + expect(detail).toContain('getDispatch') + expect(detail).toContain('车辆信息') + expect(detail).toContain('排车信息') + expect(detail).toContain('单据信息') + expect(detail).toContain('关联订单明细') + expect(detail).toContain(':data="relatedOrders"') + expect(detail).toContain("router.push({ name: 'overseas-dispatches' })") + expect(detail).not.toContain('ElMessage.success') + }) + it('preserves last-mile status tabs and read-only outbound association columns without links', () => { const value = source('LastMileOrdersView.vue') expect(value).toContain('aria-label="尾程订单状态"') @@ -317,7 +330,7 @@ describe('overseas warehouse first-batch prototype contract', () => { ]) expect(columnKeys('InventoryView.vue')).toEqual([ 'actions', 'owner', 'warehouse', 'sku', 'productName', 'location', 'onHand', 'available', 'held', 'looseboard', - 'inTransit', 'purchase', 'status', 'updatedAt', + 'inTransit', 'updatedAt', ]) expect(columnKeys('RelabelOrdersView.vue')).toEqual([ 'actions', 'orderNo', 'sku', 'productName', 'cartons', 'budgetTotal', 'labelRequirement', 'fileName', 'status', diff --git a/src/modules/overseas-warehouse/routes.test.ts b/src/modules/overseas-warehouse/routes.test.ts index 8746188a..a72c562e 100644 --- a/src/modules/overseas-warehouse/routes.test.ts +++ b/src/modules/overseas-warehouse/routes.test.ts @@ -10,6 +10,7 @@ describe('overseas warehouse routes', () => { ['overseas-warehouse/inbound-orders', permission.inboundOrderList], ['overseas-warehouse/inbound-orders/:orderId', permission.inboundOrderList], ['overseas-warehouse/dispatches', permission.dispatchList], + ['overseas-warehouse/dispatches/:dispatchNo', permission.dispatchList], ['overseas-warehouse/inventory', permission.inventoryList], ['overseas-warehouse/inventory-transactions', permission.inventoryList], ['overseas-warehouse/inventory/:inventoryId', permission.inventoryList], @@ -22,7 +23,7 @@ describe('overseas warehouse routes', () => { it('keeps all details as formal parameterized pages', () => { const details = overseasWarehouseRoutes.filter((route) => route.path.includes('/:')) - expect(details).toHaveLength(5) + expect(details).toHaveLength(6) expect(details.every((route) => route.meta.showPageHeading === false)).toBe(true) }) diff --git a/src/modules/overseas-warehouse/routes.ts b/src/modules/overseas-warehouse/routes.ts index 01519d2e..aca6eaf0 100644 --- a/src/modules/overseas-warehouse/routes.ts +++ b/src/modules/overseas-warehouse/routes.ts @@ -32,6 +32,12 @@ export const overseasWarehouseRoutes = [ component: () => import('./pages/DispatchesView.vue'), meta: { title: '排车列表', description: '查看海外仓车辆调度、预约与发车状态', permission: permission.dispatchList }, }, + { + path: 'overseas-warehouse/dispatches/:dispatchNo', + name: 'overseas-dispatch-detail', + component: () => import('./pages/DispatchDetailView.vue'), + meta: { title: '排车详情', description: '查看排车、车辆和关联订单明细', permission: permission.dispatchList, showPageHeading: false }, + }, { path: 'overseas-warehouse/inventory', name: 'overseas-inventory',