fix(overseas): show inventory business reference

This commit is contained in:
2026-09-08 17:56:17 +08:00
parent 44420919f6
commit cf612ce11e
2 changed files with 29 additions and 3 deletions
@@ -64,7 +64,31 @@ describe('inventory customer-name snapshots', () => {
await flushPromises()
expect(wrapper.text()).toContain('华远贸易')
expect(wrapper.text()).toContain('洛杉矶仓')
expect(wrapper.text()).toContain('入库单号')
expect(wrapper.text()).toContain(balance.inboundOrderNo)
expect(wrapper.text()).toContain('美本土散板')
expect(wrapper.text()).not.toContain('美本土散版')
expect(wrapper.text()).not.toContain('ONT8目的仓')
expect(wrapper.text()).not.toContain(customerId)
expect(wrapper.text()).not.toContain(balance.id)
})
it('falls back to the inbound code and then an explicit empty business reference without exposing the inventory id', async () => {
vi.mocked(listInventoryBalances).mockResolvedValueOnce({ records: [{ ...balance, inboundOrderNo: '' }], page: 1, size: 10, total: 1, pages: 1 })
routing.route.params = { inventoryId: balance.id }
routing.route.query = { inboundCode: balance.inboundCode, skuCode: balance.skuCode }
const inboundCodeWrapper = mount(InventoryDetailView, { attachTo: document.body, global: { plugins: [createPinia(), ElementPlus] } })
await flushPromises()
expect(inboundCodeWrapper.text()).toContain('入仓码')
expect(inboundCodeWrapper.text()).toContain(balance.inboundCode)
expect(inboundCodeWrapper.text()).not.toContain(balance.id)
inboundCodeWrapper.unmount()
vi.mocked(listInventoryBalances).mockResolvedValueOnce({ records: [{ ...balance, inboundOrderNo: '', inboundCode: '' }], page: 1, size: 10, total: 1, pages: 1 })
routing.route.query = { skuCode: balance.skuCode }
const emptyWrapper = mount(InventoryDetailView, { attachTo: document.body, global: { plugins: [createPinia(), ElementPlus] } })
await flushPromises()
expect(emptyWrapper.text()).toContain('业务标识')
expect(emptyWrapper.text()).not.toContain(balance.id)
})
})
@@ -8,9 +8,11 @@ import { listInventoryBalances, listInventoryLedger, listInventoryPositions, typ
const route = useRoute(); const router = useRouter(); const inventoryId = computed(() => String(route.params.inventoryId || ''))
const balance = ref<InventoryBalanceDto | null>(null); const positions = ref<InventoryPositionDto[]>([]); const ledger = ref<InventoryLedgerDto[]>([]); const loading = ref(false); const loadError = ref<ApiErrorDetails | null>(null)
function text(value: unknown) { return String(value ?? '').trim() || '—' }
const referenceLabel = computed(() => String(balance.value?.inboundOrderNo || route.query.inboundOrderNo || '').trim() ? '入库单号' : String(balance.value?.inboundCode || route.query.inboundCode || '').trim() ? '入仓码' : '业务标识')
const referenceValue = computed(() => text(balance.value?.inboundOrderNo || route.query.inboundOrderNo || balance.value?.inboundCode || route.query.inboundCode))
const productValues = computed(() => ({ 客户: text(balance.value?.customerName), 海外仓: text(balance.value?.overseasWarehouseName), SKU编码: text(balance.value?.skuCode), 产品名称: balance.value ? inventoryProductName(balance.value) : '—', 更新时间: formatOverseasDateTime(balance.value?.updatedAt) }))
const stockValues = computed(() => ({ 在库总量: Number(balance.value?.totalPackages || 0), 可用库存: Number(balance.value?.availablePackages || 0), 暂扣库存: Number(balance.value?.holdPackages || 0), 美本土散版: '—', 在途库存: Number(balance.value?.inTransitPackages || 0), 采购库存: Number(balance.value?.procurementPackages || 0), 预计总量: Number(balance.value?.totalPackages || 0) + Number(balance.value?.inTransitPackages || 0) + Number(balance.value?.procurementPackages || 0) }))
const productFields = ['客户', '海外仓', 'SKU编码', '产品名称', '更新时间']; const stockFields = ['在库总量', '可用库存', '暂扣库存', '美本土散版', '在途库存', '采购库存', '预计总量']
const stockValues = computed(() => ({ 在库总量: Number(balance.value?.totalPackages || 0), 可用库存: Number(balance.value?.availablePackages || 0), 暂扣库存: Number(balance.value?.holdPackages || 0), 美本土散板: '—', 在途库存: Number(balance.value?.inTransitPackages || 0), 采购库存: Number(balance.value?.procurementPackages || 0), 预计总量: Number(balance.value?.totalPackages || 0) + Number(balance.value?.inTransitPackages || 0) + Number(balance.value?.procurementPackages || 0) }))
const productFields = ['客户', '海外仓', 'SKU编码', '产品名称', '更新时间']; const stockFields = ['在库总量', '可用库存', '暂扣库存', '美本土散板', '在途库存', '采购库存', '预计总量']
const locationRows = computed(() => positions.value.map((item) => ({ id: String(item.id), location: text(item.warehouseLocationCode), status: text(item.status), palletNo: text(item.palletNo), cartons: Number(item.totalPackages || 0), quantity: Number(item.totalPackages || 0), available: Number(item.availablePackages || 0), inboundDate: formatOverseasDateTime(item.updatedAt), ageDays: '—' })))
const palletRows = computed(() => positions.value.map((item) => ({ id: String(item.id), palletNo: text(item.palletNo), cartons: Number(item.totalPackages || 0), cartonRange: '—', location: text(item.warehouseLocationCode), quantity: Number(item.totalPackages || 0) })))
const ledgerRows = computed(() => ledger.value.map((item) => ({ id: String(item.id), occurredAt: formatOverseasDateTime(item.occurredAt), businessType: inventoryBusinessTypeLabel(item.businessType), businessOrderNo: text(item.businessOrderNo), inboundOrderNo: text(item.inboundOrderNo), outboundOrderNo: text(item.outboundOrderNo), location: text(item.warehouseLocationCode), inboundQuantity: item.deltaPackages > 0 ? item.deltaPackages : 0, outboundQuantity: item.deltaPackages < 0 ? Math.abs(item.deltaPackages) : 0, balance: Number(item.afterPackages || 0), operator: '—', remark: text(item.remark) })))
@@ -21,7 +23,7 @@ async function load() { if (!inventoryId.value) { loadError.value = { message: '
function back() { void router.push({ name: 'overseas-inventory' }) }; onMounted(load)
</script>
<template><OverseasDetailShell title="库存详情" reference-label="库存记录" :reference-value="inventoryId" back-label="返回库存管理" domain="库存详情" :pending="false" :status-text="balance ? '库存事实' : '加载中'" @back="back"><LoadErrorState v-if="loadError" title="库存详情加载失败" :message="loadError.message" :loading="loading" @retry="load"><template #details><ApiErrorMeta :details="loadError" /></template></LoadErrorState>
<template><OverseasDetailShell title="库存详情" :reference-label="referenceLabel" :reference-value="referenceValue" back-label="返回库存管理" domain="库存详情" :pending="false" :status-text="balance ? '库存事实' : '加载中'" @back="back"><LoadErrorState v-if="loadError" title="库存详情加载失败" :message="loadError.message" :loading="loading" @retry="load"><template #details><ApiErrorMeta :details="loadError" /></template></LoadErrorState>
<template v-else><section v-loading="loading" class="overview-panel" aria-label="库存概览"><section aria-labelledby="inventory-product-heading"><h2 id="inventory-product-heading">商品信息</h2><dl class="detail-fields"><div v-for="label in productFields" :key="label"><dt>{{ label }}</dt><dd>{{ productValues[label as keyof typeof productValues] }}</dd></div></dl></section><section aria-labelledby="inventory-summary-heading"><h2 id="inventory-summary-heading">库存状态汇总</h2><dl class="detail-fields"><div v-for="label in stockFields" :key="label"><dt>{{ label }}</dt><dd>{{ stockValues[label as keyof typeof stockValues] }}</dd></div></dl></section></section>
<section class="ledger-section" aria-labelledby="inventory-location-heading"><h2 id="inventory-location-heading">库位库存</h2><DataTable :data="locationRows" :columns="locationColumns" column-settings-mode="hide" row-key="id" empty-text="暂无库位库存" /></section><section class="ledger-section" aria-labelledby="inventory-pallet-heading"><h2 id="inventory-pallet-heading">托盘箱号信息</h2><DataTable :data="palletRows" :columns="palletColumns" column-settings-mode="hide" row-key="id" empty-text="暂无托盘库存" /></section><section class="ledger-section" aria-labelledby="inventory-ledger-heading"><h2 id="inventory-ledger-heading">进销存单据明细</h2><p class="ledger-note">按该库存记录的入库单范围展示,出库字段仅为只读事实。</p><DataTable :data="ledgerRows" :columns="ledgerColumns" column-settings-mode="hide" row-key="id" empty-text="暂无进销存明细" /></section></template>
</OverseasDetailShell></template>