Merge remote-tracking branch 'origin/release/test' into release/test
This commit is contained in:
@@ -355,6 +355,11 @@ export interface ChangeContainerReceivingWarehousePayload {
|
||||
}
|
||||
|
||||
export interface LastMileOrderDetailDto {
|
||||
returnReceipt?: {
|
||||
order: { returnNo: string; receivedQuantity: number; expectedQuantity: number }
|
||||
receipts: Array<{ receiptNo: string; unitType: string; unitCode?: string; palletCode?: string; receivedQuantity: number; boxCount: number; signedAt: string }>
|
||||
cartons?: Array<{ receiptNo: string; palletCode?: string; cartonMark: string; countStatus: string; countedAt?: string; items: Array<{ skuCode: string; productNameZh?: string; quantity: number }> }>
|
||||
} | null
|
||||
order: LastMileOrderDto
|
||||
manualNodes?: ManualNodesResponse['nodes']
|
||||
cargo: LastMileCargoDto[]
|
||||
|
||||
@@ -13,6 +13,19 @@ vi.mock('../api/warehouseTransfers', () => ({ getWarehouseTransfer: vi.fn() }))
|
||||
enableAutoUnmount(afterEach)
|
||||
|
||||
describe('LastMileOrderDetailView domestic detail alignment', () => {
|
||||
it('shows signed box contents and actual quantities on return orders', async () => {
|
||||
vi.mocked(getLastMileOrder).mockResolvedValue({ order: { id: 'tail-return', customerId: 'customer-1', orderNo: 'RETU-1', orderType: 'RETURN_RELABEL', currentStatus: 'INBOUND_COMPLETED' }, cargo: [], fees: [], statusHistory: [], operationHistory: [],
|
||||
returnReceipt: { order: { returnNo: 'RT-1', receivedQuantity: 10, expectedQuantity: 10 }, receipts: [{ receiptNo: 'RR-1', unitType: 'PALLET', unitCode: 'PLT-1', receivedQuantity: 10, boxCount: 2, signedAt: '' }],
|
||||
cartons: [{ receiptNo: 'RR-1', cartonMark: 'RC#2-1', countStatus: 'CONFIRMED', items: [{ skuCode: 'SKU-A', quantity: 3 }, { skuCode: 'SKU-B', quantity: 7 }] }, { receiptNo: 'RR-2', cartonMark: 'RC-PENDING', countStatus: 'PENDING', items: [] }] } })
|
||||
const wrapper = mount(LastMileOrderDetailView, { global: { plugins: [ElementPlus] } }); await flushPromises()
|
||||
await wrapper.findAll('[role="tab"]').find(tab => tab.text().includes('退货签收与箱内清点'))!.trigger('click'); await flushPromises()
|
||||
const panel = wrapper.get('[aria-label="退货签收与箱内清点"]')
|
||||
expect(panel.text()).toContain('实收 10 / 预报 10 件')
|
||||
expect(panel.text()).toContain('RC#2-1')
|
||||
expect(panel.text()).toContain('SKU-A')
|
||||
expect(panel.text()).toContain('实际签收数量')
|
||||
expect(panel.text()).toContain('待清点')
|
||||
})
|
||||
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: [] })
|
||||
|
||||
@@ -227,6 +227,33 @@ 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 v-if="detail?.order.orderType === 'RETURN_RELABEL'" name="return-receipt"><template #label><span class="density-tab-icon" aria-hidden="true">📦</span><span>退货签收与箱内清点</span></template>
|
||||
<section v-if="detail.returnReceipt" class="table-panel" aria-label="退货签收与箱内清点">
|
||||
<h3>{{ detail.returnReceipt.order.returnNo }} · 实收 {{ detail.returnReceipt.order.receivedQuantity }} / 预报 {{ detail.returnReceipt.order.expectedQuantity }} 件</h3>
|
||||
<el-table :data="detail.returnReceipt.receipts" size="small" border>
|
||||
<el-table-column prop="receiptNo" label="签收单号" min-width="190" />
|
||||
<el-table-column label="签收方式" width="90"><template #default="{ row }">{{ row.unitType === 'PALLET' ? '托盘' : row.unitType === 'BOX' ? '箱子' : '包裹' }}</template></el-table-column>
|
||||
<el-table-column prop="unitCode" label="签收载体" min-width="220" />
|
||||
<el-table-column prop="boxCount" label="实收箱数" width="100" />
|
||||
<el-table-column prop="receivedQuantity" label="实收数量" width="100" />
|
||||
</el-table>
|
||||
<h3>签收箱号明细({{ detail.returnReceipt.cartons?.length || 0 }} 箱)</h3>
|
||||
<el-collapse v-if="detail.returnReceipt.cartons?.length">
|
||||
<el-collapse-item v-for="box in detail.returnReceipt.cartons" :key="box.cartonMark" :name="box.cartonMark">
|
||||
<template #title>{{ box.cartonMark }} · {{ box.countStatus === 'CONFIRMED' ? `已确认 · ${box.items.length} 种 SKU · ${box.items.reduce((sum, item) => sum + Number(item.quantity), 0)} 件` : box.countStatus === 'PENDING' ? '待清点' : '未留存箱内签收明细' }}</template>
|
||||
<p>签收单 {{ box.receiptNo }}<template v-if="box.palletCode"> · 托盘 {{ box.palletCode }}</template><template v-if="box.countedAt"> · 确认时间 {{ formatOverseasDateTime(box.countedAt) }}</template></p>
|
||||
<el-table v-if="box.countStatus === 'CONFIRMED'" :data="box.items" size="small" border>
|
||||
<el-table-column prop="skuCode" label="SKU" min-width="220" />
|
||||
<el-table-column prop="productNameZh" label="中文品名" min-width="180" />
|
||||
<el-table-column prop="quantity" label="实际签收数量" width="130" />
|
||||
</el-table>
|
||||
<p v-else>{{ box.countStatus === 'PENDING' ? '箱内数量待仓库清点确认' : '未留存原始箱内明细,不以当前库存代替签收数量' }}</p>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<el-empty v-else description="暂无签收箱号明细" />
|
||||
</section>
|
||||
<el-empty v-else description="暂无退货签收记录" />
|
||||
</el-tab-pane>
|
||||
<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>
|
||||
|
||||
@@ -204,7 +204,7 @@ function warehouseName(warehouseId?: string) {
|
||||
);
|
||||
}
|
||||
function statusLabel(status?: string) {
|
||||
return status === "AVAILABLE" ? "可用" : status === "MERGED" ? "已合箱" : "—";
|
||||
return status === "PENDING_COUNT" ? "箱内待清点" : status === "AVAILABLE" ? "可用" : status === "MERGED" ? "已合箱" : "—";
|
||||
}
|
||||
async function loadCustomerOptions() {
|
||||
const records: PlatformTenantResource[] = [];
|
||||
@@ -634,7 +634,7 @@ const tableColumns = computed(() =>
|
||||
v-model="query.status"
|
||||
clearable
|
||||
placeholder="箱状态"
|
||||
><el-option label="可用" value="AVAILABLE" /><el-option
|
||||
><el-option label="箱内待清点" value="PENDING_COUNT" /><el-option label="可用" value="AVAILABLE" /><el-option
|
||||
label="已合箱"
|
||||
value="MERGED" /></el-select
|
||||
><el-button type="primary" @click="search"
|
||||
|
||||
Reference in New Issue
Block a user