feat(transfer): expose stock outbound and durable receipt recovery UI

This commit is contained in:
2026-10-05 06:16:21 +08:00
parent 578df0f927
commit 93f193c5d6
7 changed files with 432 additions and 2 deletions
@@ -12,6 +12,7 @@ import { allocateWarehouseTransfer, getWarehouseTransfer, type AllocateWarehouse
import { listWarehouseTransferSources, type WarehouseTransferSourceCandidate } from '../api/warehouseTransferSources'
import { lastMileStatusLabel, relabelApplicationStatusLabel } from '../lastMilePresentation'
import { overseasWarehousePermissions as permission } from '../permissions'
import WarehouseTransferMovementPanel from './WarehouseTransferMovementPanel.vue'
const props = defineProps<{ customerId: string; transferNo: string }>()
const router = useRouter(), access = useAccessPreviewStore()
@@ -117,12 +118,13 @@ const gateText = computed(() => {
if (!['READY_FOR_OUTBOUND', 'COMPLETED'].includes(detail.value.relabelStatus || '')) return '本票换标尚未完成复核和客户确认,不得提前出库。请沿关联换标单查看 PDA 作业及客户确认进度。'
return '换标已完成。后续出库仍须按转运单与服务端库存门禁执行。'
})
const allocationRows = computed(() => (detail.value?.allocations || []).map(row => ({ ...row, skuCode: row.skuCode && row.skuCode !== 'MIXED' ? row.skuCode : '—' })))
const allocationRows = computed(() => (detail.value?.allocations || []).map(row => ({ ...row, skuCode: row.skuCode && row.skuCode !== 'MIXED' ? row.skuCode : '—', movementStatus: ({ RESERVED: '已分配', SHIPPED: '已发运', RECEIVED: '目标已实收' } as Record<string, string>)[row.status] || '—' })))
const columns: DataTableColumn[] = [
{ key: 'inboundCode', prop: 'inboundCode', label: '来源入仓码', minWidth: 160 },
{ key: 'palletNo', prop: 'palletNo', label: '来源托盘码', minWidth: 180 },
{ key: 'skuCode', prop: 'skuCode', label: '实际 SKU', minWidth: 150 },
{ key: 'packageCount', prop: 'packageCount', label: '分配箱数', width: 100 },
{ key: 'movementStatus', prop: 'movementStatus', label: '履约状态', width: 120 },
]
async function load() {
const current = ++request
@@ -159,6 +161,7 @@ onBeforeUnmount(() => { request++; sourceRequest++ })
<p v-if="gateText" role="status">{{ gateText }}</p>
<el-button v-if="detail.relabelNo && access.can(permission.relabelOrderList)" @click="openRelabel">查看本票换标单</el-button>
<DataTable :data="allocationRows" :columns="columns" row-key="inventoryPositionId" :show-pagination="false" empty-text="尚未确认本票库存来源分配" />
<WarehouseTransferMovementPanel :customer-id="customerId" :detail="detail" @updated="detail = $event" />
</template>
</section>
<AppDialog v-model="allocationOpen" class="admin-density-dialog" title="选择本票库存来源" width="min(1320px, calc(100vw - 40px))" :confirm-text="originalCommand ? '重试本次分配' : '确认库存分配'" :confirm-loading="allocationSaving" :confirm-disabled="!canAllocate || sourceLoading || allocationRejected || !!sourceError || (!originalCommand && !selectionValid)" @confirm="confirmAllocation">