feat(overseas): select stock transfer sources and follow relabel

This commit is contained in:
2026-10-04 21:19:11 +08:00
parent d3a2671fd7
commit 939cc11d7b
9 changed files with 574 additions and 2 deletions
@@ -3,16 +3,30 @@ import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { getLastMileOrder } from '../api/lastMileOrders'
import LastMileOrderDetailView from './LastMileOrderDetailView.vue'
import { getWarehouseTransfer } from '../api/warehouseTransfers'
const push = vi.hoisted(() => vi.fn())
vi.mock('vue-router', () => ({ useRoute: () => ({ params: { orderId: 'internal-order-id' } }), useRouter: () => ({ push }) }))
vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can: () => false }) }))
vi.mock('../api/lastMileOrders', () => ({ getLastMileOrder: vi.fn(), createLastMileOrderFee: vi.fn() }))
vi.mock('../api/warehouseTransfers', () => ({ getWarehouseTransfer: vi.fn() }))
enableAutoUnmount(afterEach)
describe('LastMileOrderDetailView domestic detail alignment', () => {
it('loads transfer fulfillment only on the plan tab using sourceOrderNo, never the tail order number', async () => {
vi.mocked(getLastMileOrder).mockResolvedValue({ order: { id: 'internal-transfer-tail', customerId: 'customer-1', orderNo: 'WT-TAIL-1', sourceOrderNo: 'WT-SOURCE-1', orderType: 'WAREHOUSE_TRANSFER', currentStatus: 'INBOUND_COMPLETED' }, cargo: [], fees: [], statusHistory: [], operationHistory: [] })
vi.mocked(getWarehouseTransfer).mockResolvedValue({ id: 'internal-transfer', transferNo: 'WT-SOURCE-1', needRelabel: true, status: 'WAIT_RELABEL', relabelNo: 'RL-1', relabelStatus: 'CUSTOMER_CONFIRM_PENDING', packageCount: 2, items: [], cartons: [], pallets: [], relabelBindings: [] })
const wrapper = mount(LastMileOrderDetailView, { global: { plugins: [ElementPlus] } }); await flushPromises()
expect(getWarehouseTransfer).not.toHaveBeenCalled()
await wrapper.findAll('[role="tab"]').find(x => x.text().includes('计划信息'))!.trigger('click'); await flushPromises()
expect(getWarehouseTransfer).toHaveBeenCalledExactlyOnceWith('customer-1', 'WT-SOURCE-1')
expect(wrapper.get('[aria-label="本票转运与换标履约"]').text()).toContain('待客户确认')
expect(wrapper.get('[aria-label="本票转运与换标履约"]').text()).toContain('不得提前出库')
})
beforeEach(() => {
push.mockReset()
vi.mocked(getWarehouseTransfer).mockReset()
vi.mocked(getLastMileOrder).mockResolvedValue({
order: { id: 'internal-order-id', customerId: 'customer-1', orderNo: 'FL-WH-001', currentStatus: 'PENDING_ASSIGNMENT', customerName: '示例客户', overseasWarehouseName: '洛杉矶仓', packageCount: 0, palletCount: 2, grossWeightKg: 30, netWeightKg: 22, volumeCbm: 6.374, inboundCode: 'IN-001', containerNo: 'CONT-001', customerRemark: '完整保留客户备注', updatedAt: '2026-09-14T10:00:00' },
cargo: [{ id: 'cargo-1', skuCode: 'SKU-001', productNameZh: '测试货物' }], fees: [], statusHistory: [], operationHistory: [],
@@ -17,6 +17,7 @@ import { relabelApplicationStatusLabel, formatOverseasDateTime, lastMileOrderRef
import { overseasWarehousePermissions as permission } from '../permissions'
import OverseasDetailShell from '../components/OverseasDetailShell.vue'
import OrderReferenceText from '../components/OrderReferenceText.vue'
import WarehouseTransferFulfillmentPanel from '../components/WarehouseTransferFulfillmentPanel.vue'
interface DetailField { label: string; value: string | number; wide?: boolean }
interface CargoRow { id: string; sku: string; productName: string; pallets: number; cartons: number; quantity: number; weight: number; volume: number }
@@ -215,7 +216,8 @@ onMounted(load)
</dl>
</el-tab-pane>
<el-tab-pane name="cargo"><template #label><span class="density-tab-icon" aria-hidden="true">📦</span><span>货物信息</span></template><section class="table-panel"><DataTable :data="cargo" :columns="cargoColumns" column-settings-mode="hide" row-key="id" empty-text="暂无货物明细"></DataTable></section></el-tab-pane>
<el-tab-pane name="plan"><template #label><span class="density-tab-icon" aria-hidden="true">🗓️</span><span>计划信息</span></template>
<el-tab-pane name="plan" lazy><template #label><span class="density-tab-icon" aria-hidden="true">🗓️</span><span>计划信息</span></template>
<WarehouseTransferFulfillmentPanel v-if="detail?.order.orderType === 'WAREHOUSE_TRANSFER'" :customer-id="detail.order.customerId" :transfer-no="detail.order.sourceOrderNo || ''" />
<section class="info-panel plan-panel" aria-label="计划信息"><dl class="detail-fields plan-fields density-fields"><div v-for="field in planFields" :key="field.label"><dt>{{ field.label }}</dt><dd :class="{ 'detail-field-value--business': isSingleLineBusinessField(field) }" :title="isSingleLineBusinessField(field) ? String(field.value) : undefined">{{ field.value }}</dd></div></dl></section>
<section class="table-panel related-panel"><DataTable :data="documents" :columns="documentColumns" column-settings-mode="hide" empty-text="暂无关联单据"><template #toolbar-start><h2>关联单据</h2></template></DataTable></section>
</el-tab-pane>