diff --git a/src/modules/overseas-warehouse/api/dispatches.test.ts b/src/modules/overseas-warehouse/api/dispatches.test.ts index d9f41d5c..9a326fd7 100644 --- a/src/modules/overseas-warehouse/api/dispatches.test.ts +++ b/src/modules/overseas-warehouse/api/dispatches.test.ts @@ -1,13 +1,14 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { overseasHttp } from '@/shared/api/overseasHttp' -import { createDispatchDraftContainer, deleteDispatchDraftContainer, getDispatch, listDispatchCandidates, listDispatchDrafts, listDispatches, lockDispatchDraftPallet, preArrangeDispatch, releaseDispatchDraft, unlockDispatchDraftPallet } from './dispatches' +import { cancelDispatch, createDispatchDraftContainer, deleteDispatchDraftContainer, getDispatch, listDispatchCandidates, listDispatchDrafts, listDispatches, lockDispatchDraftPallet, preArrangeDispatch, releaseDispatchDraft, transferDispatchToDelivery, unlockDispatchDraftPallet, updateDispatch } from './dispatches' -vi.mock('@/shared/api/overseasHttp', () => ({ overseasHttp: { get: vi.fn(), post: vi.fn(), delete: vi.fn() } })) +vi.mock('@/shared/api/overseasHttp', () => ({ overseasHttp: { get: vi.fn(), post: vi.fn(), put: vi.fn(), delete: vi.fn() } })) describe('dispatch overseas API', () => { beforeEach(() => { vi.mocked(overseasHttp.get).mockReset() vi.mocked(overseasHttp.post).mockReset() + vi.mocked(overseasHttp.put).mockReset() vi.mocked(overseasHttp.delete).mockReset() }) @@ -68,6 +69,23 @@ describe('dispatch overseas API', () => { expect(overseasHttp.post).toHaveBeenNthCalledWith(3, '/platform/v1/last-leg/dispatches/draft-locks/release', { draftToken: 'draft-1' }) }) + it('edits and cancels only by dispatchNo without customer scope or status mutation', async () => { + vi.mocked(overseasHttp.put).mockResolvedValue({ code: '200', message: 'success', data: { id: '1', dispatchNo: 'PC/1' } }) + vi.mocked(overseasHttp.delete).mockResolvedValue({ code: '200', message: 'success', data: null }) + await updateDispatch('PC/1', { vehiclePlate: 'CA-100', route: 'LAX → ONT8' }) + await cancelDispatch('PC/1') + expect(overseasHttp.put).toHaveBeenCalledWith('/platform/v1/last-leg/dispatches/PC%2F1', { vehiclePlate: 'CA-100', route: 'LAX → ONT8' }) + expect(overseasHttp.put).not.toHaveBeenCalledWith(expect.anything(), expect.objectContaining({ status: expect.anything() })) + expect(overseasHttp.delete).toHaveBeenCalledWith('/platform/v1/last-leg/dispatches/PC%2F1') + }) + + it('transfers to delivery only by dispatchNo without customerId', async () => { + vi.mocked(overseasHttp.post).mockResolvedValue({ code: '200', message: 'success', data: { dispatchNo: 'PC/1', outboundNo: 'OUT-1', deliveryNo: 'DEL-1' } }) + const payload = { idempotencyKey: 'transfer-1', plannedDeliveryAt: '2026-09-01T10:00:00', deliveryMethod: 'TRUCK_PALLET', pickupMethod: 'WAREHOUSE_PICKUP', loadingType: 'PALLET', fees: [{ feeType: 'DELIVERY_FEE', currency: 'USD', amount: 10 }] } + await transferDispatchToDelivery('PC/1', payload) + expect(overseasHttp.post).toHaveBeenCalledWith('/platform/v1/last-leg/dispatches/PC%2F1/transfer-delivery', payload) + }) + it('loads drafts and preserves long container ids in create and delete paths', async () => { vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: [] }) vi.mocked(overseasHttp.post).mockResolvedValue({ code: '200', message: 'success', data: { id: '190000000000000099', capacity: 68, palletIds: [] } }) diff --git a/src/modules/overseas-warehouse/api/dispatches.ts b/src/modules/overseas-warehouse/api/dispatches.ts index 2812973b..9fa660bb 100644 --- a/src/modules/overseas-warehouse/api/dispatches.ts +++ b/src/modules/overseas-warehouse/api/dispatches.ts @@ -87,6 +87,19 @@ export interface DispatchSummaryDto { items?: DispatchItemDto[] } +export interface UpdateDispatchPayload { + vehiclePlate?: string | null + driverName?: string | null + driverPhone?: string | null + carrierName?: string | null + route?: string | null + departAt?: string | null + fbaAppointmentNo?: string | null + fbaAppointmentStatus?: string | null + vehicleAppointmentStatus?: string | null + estimatedArrivalAt?: string | null +} + export interface DispatchItemDto { id: string planPalletId: string @@ -120,6 +133,20 @@ export async function getDispatch(dispatchNo: string) { return unwrapApiResponse(response) } +export async function updateDispatch(dispatchNo: string, payload: UpdateDispatchPayload) { + const response = await overseasHttp.put, ApiEnvelope>( + `/platform/v1/last-leg/dispatches/${encodeURIComponent(dispatchNo)}`, payload, + ) + return unwrapApiResponse(response) +} + +export async function cancelDispatch(dispatchNo: string) { + const response = await overseasHttp.delete, 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/api/outbounds.test.ts b/src/modules/overseas-warehouse/api/outbounds.test.ts new file mode 100644 index 00000000..eca9bdf8 --- /dev/null +++ b/src/modules/overseas-warehouse/api/outbounds.test.ts @@ -0,0 +1,31 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { overseasHttp } from '@/shared/api/overseasHttp' +import { cancelOutbound, createOneClickDropshipOutbound, getOutbound, listOutbounds } from './outbounds' + +vi.mock('@/shared/api/overseasHttp', () => ({ overseasHttp: { get: vi.fn(), post: vi.fn() } })) + +describe('outbound overseas API', () => { + beforeEach(() => { vi.mocked(overseasHttp.get).mockReset(); vi.mocked(overseasHttp.post).mockReset() }) + + it('lists outbound orders with supported filters', async () => { + vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', data: { records: [], page: 1, size: 20, total: 0, pages: 0 } }) + await listOutbounds({ page: 1, size: 20, documentNo: 'OUT-1', warehouseId: 'WH-1', status: 'PICKED' }) + expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/outbound-orders', { params: { page: 1, size: 20, documentNo: 'OUT-1', warehouseId: 'WH-1', status: 'PICKED' } }) + }) + + it('loads detail and cancels only by outboundNo without customerId', async () => { + vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', data: { outbound: { id: '1', outboundNo: 'OUT/1', status: 'PICKED' }, delivery: null } }) + vi.mocked(overseasHttp.post).mockResolvedValue({ code: '200', data: null }) + await getOutbound('OUT/1') + await cancelOutbound('OUT/1', '运营取消') + expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/outbound-orders/OUT%2F1') + expect(overseasHttp.post).toHaveBeenCalledWith('/platform/v1/last-leg/outbound-orders/OUT%2F1/cancel', { reason: '运营取消' }) + }) + + it('keeps customerId explicit only for one-click dropship creation', async () => { + vi.mocked(overseasHttp.post).mockResolvedValue({ code: '200', data: { id: '1', outboundNo: 'OUT-1' } }) + const payload = { recipient: 'John / 555 / LA', items: [{ inventoryPositionId: '99', packages: 2, sku: 'SKU-1' }], idempotencyKey: 'dropship-1' } + await createOneClickDropshipOutbound('customer-1', payload) + expect(overseasHttp.post).toHaveBeenCalledWith('/platform/v1/last-leg/outbound-orders/one-click-dropship', payload, { params: { customerId: 'customer-1' } }) + }) +}) diff --git a/src/modules/overseas-warehouse/api/outbounds.ts b/src/modules/overseas-warehouse/api/outbounds.ts index edf65236..b9d4cf09 100644 --- a/src/modules/overseas-warehouse/api/outbounds.ts +++ b/src/modules/overseas-warehouse/api/outbounds.ts @@ -1,18 +1,24 @@ import { overseasHttp } from '@/shared/api/overseasHttp' import { unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http' import { normalizeOverseasPage, type OverseasPagePayload } from './lastMileOrders' +import type { DeliveryOrderRow } from './deliveryOrders' export interface OutboundRow { id: string; outboundNo: string; dispatchNo?: string | null; overseasWarehouseId?: string | null; status?: string | null; palletCount?: number | null; packageCount?: number | null; createdAt?: string | null } +export interface OutboundDetail { outbound: OutboundRow; delivery?: DeliveryOrderRow | null } export interface OutboundQuery { page: number; size: number; documentNo?: string; warehouseId?: string; status?: string } export async function listOutbounds(query: OutboundQuery) { const response = await overseasHttp.get>, ApiEnvelope>>('/platform/v1/last-leg/outbound-orders', { params: query }) return normalizeOverseasPage(unwrapApiResponse(response)) } +export async function getOutbound(outboundNo: string) { + const response = await overseasHttp.get, ApiEnvelope>(`/platform/v1/last-leg/outbound-orders/${encodeURIComponent(outboundNo)}`) + return unwrapApiResponse(response) +} export async function createOneClickDropshipOutbound(customerId: string, payload: { recipient: string; items: Array<{ inventoryPositionId: string; packages: number; sku?: string }>; remark?: string; idempotencyKey: string }) { const response = await overseasHttp.post, ApiEnvelope>('/platform/v1/last-leg/outbound-orders/one-click-dropship', payload, { params: { customerId } }) return unwrapApiResponse(response) } -export async function cancelOutbound(outboundNo: string, reason: string, customerId?: string) { - const response = await overseasHttp.post, ApiEnvelope>(`/platform/v1/last-leg/outbound-orders/${encodeURIComponent(outboundNo)}/cancel`, { reason }, { params: customerId ? { customerId } : undefined }) +export async function cancelOutbound(outboundNo: string, reason: string) { + const response = await overseasHttp.post, ApiEnvelope>(`/platform/v1/last-leg/outbound-orders/${encodeURIComponent(outboundNo)}/cancel`, { reason }) return unwrapApiResponse(response) } diff --git a/src/modules/overseas-warehouse/pages/DispatchesView.test.ts b/src/modules/overseas-warehouse/pages/DispatchesView.test.ts index b3e37ad5..09b72678 100644 --- a/src/modules/overseas-warehouse/pages/DispatchesView.test.ts +++ b/src/modules/overseas-warehouse/pages/DispatchesView.test.ts @@ -4,10 +4,12 @@ import { resolve } from 'node:path' import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils' import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import QueryToolbar, { type QueryModel } from '@/shared/components/QueryToolbar.vue' -import { listDispatches } from '../api/dispatches' +import { cancelDispatch, listDispatches, transferDispatchToDelivery, updateDispatch } from '../api/dispatches' import DispatchesView from './DispatchesView.vue' -vi.mock('../api/dispatches', () => ({ listDispatches: vi.fn() })) +const canPermission = vi.hoisted(() => vi.fn(() => true)) +vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: canPermission }) })) +vi.mock('../api/dispatches', () => ({ listDispatches: vi.fn(), updateDispatch: vi.fn(), cancelDispatch: vi.fn(), transferDispatchToDelivery: vi.fn() })) class ResizeObserverStub implements ResizeObserver { observe() {} @@ -44,6 +46,10 @@ describe('DispatchesView', () => { }], page: 1, size: 20, total: 1, pages: 1, }) + vi.mocked(updateDispatch).mockReset() + vi.mocked(cancelDispatch).mockReset() + vi.mocked(transferDispatchToDelivery).mockReset() + canPermission.mockReset().mockReturnValue(true) }) it('loads immediately and sends only supported page filters', async () => { @@ -81,4 +87,21 @@ describe('DispatchesView', () => { const source = readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/pages/DispatchesView.vue'), 'utf8') expect(source).toContain('请确认海外尾程排车接口已发布') }) + + it('gates edit, cancel and transfer with independent permissions and service statuses', async () => { + const source = readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/pages/DispatchesView.vue'), 'utf8') + expect(source).toContain('permission.dispatchEdit') + expect(source).toContain('permission.dispatchCancel') + expect(source).toContain('permission.dispatchTransferDelivery') + expect(source).toContain("function isPendingDeparture(row: DispatchListItem) { return row.statusCode === 'PENDING_DEPARTURE' }") + expect(source).toContain('access.can(permission.dispatchEdit) && isPendingDeparture(row)') + expect(source).toContain('access.can(permission.dispatchTransferDelivery) && isPendingDeparture(row)') + expect(source).toContain('普通编辑不会修改排车状态') + expect(source).not.toContain('departDispatch') + + canPermission.mockReturnValue(false) + const wrapper = mount(DispatchesView, { global: { plugins: [ElementPlus] } }) + await flushPromises() + expect(wrapper.text()).not.toContain('转派送') + }) }) diff --git a/src/modules/overseas-warehouse/pages/DispatchesView.vue b/src/modules/overseas-warehouse/pages/DispatchesView.vue index 64bd0be0..135c0585 100644 --- a/src/modules/overseas-warehouse/pages/DispatchesView.vue +++ b/src/modules/overseas-warehouse/pages/DispatchesView.vue @@ -1,7 +1,7 @@ + + + + diff --git a/src/modules/overseas-warehouse/pages/OutboundsView.test.ts b/src/modules/overseas-warehouse/pages/OutboundsView.test.ts new file mode 100644 index 00000000..426df26b --- /dev/null +++ b/src/modules/overseas-warehouse/pages/OutboundsView.test.ts @@ -0,0 +1,53 @@ +import ElementPlus from 'element-plus' +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' +import { flushPromises, mount } from '@vue/test-utils' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { listOutbounds } from '../api/outbounds' +import OutboundsView from './OutboundsView.vue' + +const canPermission = vi.hoisted(() => vi.fn((_code: string) => true)) +const routerPush = vi.hoisted(() => vi.fn()) +vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: canPermission }) })) +vi.mock('vue-router', () => ({ useRouter: () => ({ push: routerPush }) })) +vi.mock('../api/outbounds', () => ({ listOutbounds: vi.fn(), cancelOutbound: vi.fn(), createOneClickDropshipOutbound: vi.fn() })) +vi.mock('../api/inventory', () => ({ listInventoryBalances: vi.fn(), listInventoryPositions: vi.fn() })) + +class ResizeObserverStub { observe() {} unobserve() {} disconnect() {} } + +describe('OutboundsView permissions and navigation', () => { + beforeEach(() => { + vi.stubGlobal('ResizeObserver', ResizeObserverStub) + vi.stubGlobal('localStorage', { getItem: () => null, setItem: () => undefined, removeItem: () => undefined }) + vi.mocked(listOutbounds).mockReset().mockResolvedValue({ records: [{ id: '1', outboundNo: 'OUT-1', dispatchNo: 'PC-1', status: 'PICKED', palletCount: 1, packageCount: 2 }], page: 1, size: 20, total: 1, pages: 1 }) + canPermission.mockReset().mockReturnValue(true) + routerPush.mockReset() + }) + + it('uses list access for detail and independent create/cancel permissions', async () => { + canPermission.mockImplementation((code: string) => code.endsWith(':list')) + const wrapper = mount(OutboundsView, { global: { plugins: [ElementPlus] } }) + await flushPromises() + expect(wrapper.text()).toContain('详情') + expect(wrapper.text()).not.toContain('一件代发出库') + expect(wrapper.text()).not.toContain('取消') + expect(OutboundsView.__file).toContain('OutboundsView.vue') + wrapper.unmount() + }) + + it('shows one-click creation and cancellation only with their exact permissions', async () => { + canPermission.mockImplementation((code: string) => ['platform:overseas-warehouse:outbound:create', 'platform:overseas-warehouse:outbound:cancel'].includes(code)) + const wrapper = mount(OutboundsView, { global: { plugins: [ElementPlus] } }) + await flushPromises() + expect(wrapper.text()).toContain('一件代发出库') + expect(wrapper.text()).toContain('取消') + wrapper.unmount() + }) + + it('requires an explicit customer selection before choosing customer inventory', async () => { + const source = readFileSync(resolve(process.cwd(), 'src/modules/overseas-warehouse/pages/OutboundsView.vue'), 'utf8') + expect(source).toContain('v-model="selectedCustomerId"') + expect(source).toContain('availablePositionOptions') + expect(source).toContain('createOneClickDropshipOutbound(selectedCustomerId.value') + }) +}) diff --git a/src/modules/overseas-warehouse/pages/OutboundsView.vue b/src/modules/overseas-warehouse/pages/OutboundsView.vue index 4e7da4e6..7a4d7cfe 100644 --- a/src/modules/overseas-warehouse/pages/OutboundsView.vue +++ b/src/modules/overseas-warehouse/pages/OutboundsView.vue @@ -1,41 +1,57 @@ diff --git a/src/modules/overseas-warehouse/pages/phase5Behavior.test.ts b/src/modules/overseas-warehouse/pages/phase5Behavior.test.ts new file mode 100644 index 00000000..67d8730a --- /dev/null +++ b/src/modules/overseas-warehouse/pages/phase5Behavior.test.ts @@ -0,0 +1,54 @@ +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' +import { describe, expect, it } from 'vitest' + +function source(name: string) { return readFileSync(resolve(process.cwd(), `src/modules/overseas-warehouse/pages/${name}`), 'utf8') } + +function expectOperationColumnFirst(name: string) { + const value = source(name) + if (!value.includes("key: 'actions', label: '操作'")) return + expect(value).toMatch(/const columns:[\s\S]*?= \[\s*\{ key: 'actions', label: '操作'/) +} + +describe('phase-five outbound, delivery, exception and visit behavior', () => { + it('keeps outbound detail and cancellation scoped only by outboundNo', () => { + const list = source('OutboundsView.vue') + const detail = source('OutboundDetailView.vue') + expect(list).toContain("params: { outboundNo: row.outboundNo }") + expect(list).toContain('access.can(permission.outboundCreate)') + expect(list).toContain('access.can(permission.outboundCancel)') + expect(detail).toContain('getOutbound(outboundNo.value)') + expect(detail).toContain('cancelOutbound(outboundNo.value, reason)') + expect(detail).not.toContain('customerId') + expect(list).toContain('createOneClickDropshipOutbound(selectedCustomerId.value') + expectOperationColumnFirst('OutboundsView.vue') + }) + + it('keeps delivery return and status operations on real APIs with independent permissions', () => { + const value = source('DeliveryOrdersView.vue') + expect(value).toContain('permission.deliveryStatus') + expect(value).toContain('permission.deliveryReturn') + expect(value).toContain('updateDeliveryOrderStatus') + expect(value).toContain('markDeliveryReturn') + expect(value).toContain('listDeliveryReturnInboundOptions') + expectOperationColumnFirst('DeliveryOrdersView.vue') + }) + + it('keeps exception creation and relation resolution on real APIs', () => { + const value = source('ExceptionOrdersView.vue') + expect(value).toContain('permission.exceptionOrderCreate') + expect(value).toContain('resolveExceptionRelation') + expect(value).toContain('createExceptionOrder') + expect(value).toContain('getApiErrorDetails') + expectOperationColumnFirst('ExceptionOrdersView.vue') + }) + + it('keeps customer visit updates and attachments behind edit permission', () => { + const value = source('CustomerVisitsView.vue') + expect(value).toContain('permission.customerVisitEdit') + expect(value).toContain('saveCustomerVisit') + expect(value).toContain('uploadCustomerVisitAttachment') + expect(value).toContain('getApiErrorDetails') + expectOperationColumnFirst('CustomerVisitsView.vue') + }) +}) diff --git a/src/modules/overseas-warehouse/permissions.ts b/src/modules/overseas-warehouse/permissions.ts index dc22f323..7045a30a 100644 --- a/src/modules/overseas-warehouse/permissions.ts +++ b/src/modules/overseas-warehouse/permissions.ts @@ -8,8 +8,12 @@ export const overseasWarehousePermissions = { inboundOrderAppointment: 'platform:overseas-warehouse:inbound-order:fba-appointment', inboundOrderSmartDispatch: 'platform:overseas-warehouse:inbound-order:smart-dispatch', dispatchList: 'platform:overseas-warehouse:dispatch:list', + dispatchEdit: 'platform:overseas-warehouse:dispatch:edit', + dispatchCancel: 'platform:overseas-warehouse:dispatch:cancel', + dispatchTransferDelivery: 'platform:overseas-warehouse:dispatch:transfer-delivery', outboundList: 'platform:overseas-warehouse:outbound:list', outboundCreate: 'platform:overseas-warehouse:outbound:create', + outboundCancel: 'platform:overseas-warehouse:outbound:cancel', deliveryList: 'platform:overseas-warehouse:delivery:list', exceptionOrderList: 'platform:overseas-warehouse:exception-order:list', exceptionOrderCreate: 'platform:overseas-warehouse:exception-order:create', diff --git a/src/modules/overseas-warehouse/routes.test.ts b/src/modules/overseas-warehouse/routes.test.ts index 06c9bdb6..89e3d74d 100644 --- a/src/modules/overseas-warehouse/routes.test.ts +++ b/src/modules/overseas-warehouse/routes.test.ts @@ -12,6 +12,7 @@ describe('overseas warehouse routes', () => { ['overseas-warehouse/dispatches', permission.dispatchList], ['overseas-warehouse/dispatches/:dispatchNo', permission.dispatchList], ['overseas-warehouse/outbounds', permission.outboundList], + ['overseas-warehouse/outbounds/:outboundNo', permission.outboundList], ['overseas-warehouse/delivery-orders', permission.deliveryList], ['overseas-warehouse/delivery-orders/:deliveryNo', permission.deliveryList], ['overseas-warehouse/exception-orders', permission.exceptionOrderList], @@ -28,7 +29,7 @@ describe('overseas warehouse routes', () => { it('keeps all details as formal parameterized pages', () => { const details = overseasWarehouseRoutes.filter((route) => route.path.includes('/:')) - expect(details).toHaveLength(7) + expect(details).toHaveLength(8) expect(details.every((route) => route.meta.showPageHeading === false)).toBe(true) }) @@ -46,6 +47,8 @@ describe('overseas warehouse routes', () => { permission.productCreate, permission.productEdit, permission.exceptionOrderCreate, permission.deliveryReturn, permission.deliveryStatus, permission.customerVisitEdit, - ]).size).toBe(12) + permission.dispatchEdit, permission.dispatchCancel, permission.dispatchTransferDelivery, + permission.outboundCancel, permission.outboundCreate, + ]).size).toBe(17) }) }) diff --git a/src/modules/overseas-warehouse/routes.ts b/src/modules/overseas-warehouse/routes.ts index c596dfaf..de4bd8f5 100644 --- a/src/modules/overseas-warehouse/routes.ts +++ b/src/modules/overseas-warehouse/routes.ts @@ -44,6 +44,12 @@ export const overseasWarehouseRoutes = [ component: () => import('./pages/OutboundsView.vue'), meta: { title: '出库单', description: '查询海外仓出库单并创建一件代发出库', permission: permission.outboundList }, }, + { + path: 'overseas-warehouse/outbounds/:outboundNo', + name: 'overseas-outbound-detail', + component: () => import('./pages/OutboundDetailView.vue'), + meta: { title: '出库单详情', description: '查看海外仓出库单与关联派送信息', permission: permission.outboundList, showPageHeading: false }, + }, { path: 'overseas-warehouse/delivery-orders', name: 'overseas-delivery-orders', diff --git a/src/modules/overseas-warehouse/types.ts b/src/modules/overseas-warehouse/types.ts index 23db9f71..41090933 100644 --- a/src/modules/overseas-warehouse/types.ts +++ b/src/modules/overseas-warehouse/types.ts @@ -87,6 +87,7 @@ export interface DispatchListItem { vehicleAppointment: string estimatedArrivalAt: string status: string + statusCode: string palletCount: number packageCount: number createdAt: string