This commit is contained in:
wujinliang
2026-09-18 11:41:27 +08:00
parent f2d5b2d8e4
commit 451663b6ff
24 changed files with 156 additions and 30 deletions
@@ -37,7 +37,7 @@ describe('InboundTaskList measurement scope', () => {
expect(source).toContain(':tenant-id="selectedInbound.tenantId"')
expect(source).toContain(':customer-id="selectedInbound.tenantId"')
expect(source).toContain(':customer-name="selectedInbound.customerName || selectedInbound.companyName"')
expect(source).toContain(':customer-name="customerDisplayName(selectedInbound)"')
expect(source).toContain(':channel-name="selectedInbound.channelName"')
expect(source).not.toContain('selectedInbound.customerId || selectedInbound.tenantId')
})
@@ -65,6 +65,9 @@ const actionPermission = computed(() => isReview.value
const taskLabel = computed(() => isReview.value ? '审核' : '测量')
const emptyText = computed(() => isReview.value ? '暂无待审核的测量数据' : '暂无当前可测量的订单')
const preferenceKey = computed(() => isReview.value ? 'inbound-measurement-reviews' : 'inbound-measurements')
const customerNameById = computed(() => new Map(customers.value.map((customer) => [
String(customer.id), customer.legalName?.trim() || customer.tenantName,
])))
const queryFields = computed<QueryField[]>(() => [
{
@@ -111,6 +114,11 @@ function text(value: unknown) {
return value === null || value === undefined || value === '' ? '—' : String(value)
}
function customerDisplayName(inbound: InboundOrderSummary) {
const snapshot = inbound.customerName?.trim() || inbound.companyName?.trim()
return snapshot || customerNameById.value.get(String(inbound.customerId || inbound.tenantId)) || ''
}
function formatNumber(value: number | null | undefined) {
return value === null || value === undefined ? '—' : value.toLocaleString('zh-CN', { maximumFractionDigits: 3 })
}
@@ -440,6 +448,7 @@ onBeforeUnmount(() => { disposed = true; requestSerial += 1; optionsRequestSeria
v-if="!isReview && selectedInbound"
v-model="measurementDialogOpen"
:customer-id="selectedInbound.tenantId"
:customer-name="customerDisplayName(selectedInbound)"
:inbound-id="selectedInbound.id"
:inbound-code="selectedInbound.inboundCode"
@updated="handleMeasurementUpdated"
@@ -40,6 +40,7 @@ describe('InboundWorkflowWorkspace', () => {
expect(source).toContain('@click="reviewDialogOpen = true"')
expect(source).toContain(':key="`review-dialog-${revision}`"')
expect(source).toContain(':customer-name="detail?.summary.customerName || detail?.summary.companyName"')
expect(source).toContain(':customer-name="detail?.summary.customerName || detail?.summary.companyName"')
expect(source).toContain(':channel-name="detail?.summary.channelName"')
expect(source).toContain('@changed="handleReviewChanged"')
expect(source).not.toContain('<template #footer>')
@@ -197,6 +197,7 @@ onBeforeUnmount(() => {
<InboundMeasurementDialog
v-model="measurementDialogOpen"
:customer-id="customerId"
:customer-name="detail?.summary.customerName || detail?.summary.companyName"
:inbound-id="inboundId"
:inbound-code="title"
@updated="handleDomainChanged"
@@ -20,6 +20,8 @@ describe('InboundMeasurementDialog', () => {
expect(densitySource).toContain('padding: var(--admin-space-4, 10px) 48px var(--admin-space-4, 10px) var(--admin-space-6, 16px)')
expect(source).toContain('<WeightOcrPanel')
expect(source).toContain('<InboundMeasurementPanel')
expect(source).toContain('customerName?: string | null')
expect(source).toContain(':customer-name="customerName"')
expect(source).toContain('class="measurement-dialog-weight"')
expect(source).not.toContain('class="surface-panel measurement-dialog-weight"')
expect(source).toContain('border-bottom: 1px solid var(--cc-border)')
@@ -10,6 +10,7 @@ import WeightOcrPanel from '../weight/components/WeightOcrPanel.vue'
const props = defineProps<{
modelValue: boolean
customerId: string
customerName?: string | null
inboundId: string
inboundCode?: string | null
openWarehouseSuggestion?: boolean
@@ -92,6 +93,7 @@ function handleSubmitted() {
<InboundMeasurementPanel
ref="measurementPanelRef"
:customer-id="customerId"
:customer-name="customerName"
:inbound-id="inboundId"
:open-warehouse-suggestion="openWarehouseSuggestion"
@updated="handleUpdated"
@@ -52,6 +52,7 @@ function measurement(overrides: Partial<InboundMeasurementDetail> = {}): Inbound
channelName: '美西海运',
processStatus: 'MEASURING',
measureReviewStatus: null,
customerFeeConfirmed: false,
recommendedPalletType: 'STANDARD',
reviewReason: null,
reviewerId: null,
@@ -135,7 +136,7 @@ async function mountPanel(permissions = [
'platform:firstleg:inbound:measure:edit',
'platform:firstleg:inbound:measure:manual-entry',
'platform:firstleg:inbound:measure:submit',
]) {
], props: Partial<{ customerId: string; inboundId: string; customerName: string }> = {}) {
const pinia = createPinia()
setActivePinia(pinia)
const auth = useAuthStore()
@@ -143,7 +144,7 @@ async function mountPanel(permissions = [
auth.permissions = permissions
useAccessPreviewStore().initializeAfterLogin()
const wrapper = mount(InboundMeasurementPanel, {
props: { customerId: '10001', inboundId: '7001' },
props: { customerId: '10001', inboundId: '7001', ...props },
attachTo: document.body,
global: { plugins: [pinia, ElementPlus] },
})
@@ -195,6 +196,13 @@ describe('InboundMeasurementPanel', () => {
expect(wrapper.find('button[aria-label="预览测量图片"]').exists()).toBe(true)
})
it('uses the list customer name when a legacy measurement detail has no customer snapshot', async () => {
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({ companyName: '' }))
const wrapper = await mountPanel(undefined, { customerName: '柏悦物流' })
expect(wrapper.find('.measurement-summary-context').text()).toContain('柏悦物流')
})
it('warns when declared dimensions or gross weight differ from measurements by at least ten percent', async () => {
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({
actualGrossWeightKg: 132,
@@ -499,7 +507,7 @@ describe('InboundMeasurementPanel', () => {
await flushPromises()
expect(ElMessageBox.confirm).toHaveBeenCalledWith(
expect.stringContaining('准备托盘与库位占用'),
expect.stringContaining('提交成功后本批次不能继续编辑'),
'提交测量审核',
expect.objectContaining({ confirmButtonText: '确认提交' }),
)
@@ -21,6 +21,7 @@ const props = defineProps<{
customerId?: string
tenantId?: string
inboundId: string
customerName?: string | null
}>()
const emit = defineEmits<{
@@ -110,6 +111,7 @@ const canEdit = computed(() => access.can('platform:firstleg:inbound:measure:edi
const canManualEntry = computed(() => access.can('platform:firstleg:inbound:measure:manual-entry'))
const canSubmit = computed(() => access.can('platform:firstleg:inbound:measure:submit'))
const customerId = computed(() => props.customerId || props.tenantId || '')
const displayCustomerName = computed(() => detail.value?.companyName?.trim() || props.customerName?.trim() || '客户未命名')
const hasContext = computed(() => Boolean(customerId.value && props.inboundId))
const countEditableProcess = computed(() => ['PREPARING', 'WAIT_MEASURE', 'MEASURING', 'MEASURE_PENDING', 'MEASURE_REJECTED'].includes(detail.value?.processStatus || ''))
const submitEditableProcess = computed(() => ['PREPARING', 'WAIT_MEASURE', 'MEASURING', 'MEASURE_REJECTED'].includes(detail.value?.processStatus || ''))
@@ -698,7 +700,7 @@ defineExpose({ saveDraft, submitForReview, updateWeightEvidence, submissionBlock
<section class="measurement-section measurement-summary-section">
<header class="measurement-summary-header">
<div class="measurement-summary-context">
<p><span>客户</span>{{ detail.companyName || '客户未命名' }}</p>
<p><span>客户</span>{{ displayCustomerName }}</p>
<p><span>渠道</span>{{ detail.channelName || detail.channelCode || '渠道未填写' }}</p>
</div>
<div class="measurement-summary-status">
@@ -107,6 +107,7 @@ export interface InboundMeasurementDetail {
expectedPalletCount?: number | null
processStatus: InboundMeasurementProcessStatus
measureReviewStatus: string | null
customerFeeConfirmed: boolean
recommendedPalletType: string | null
reviewReason: string | null
reviewerId: MeasurementIdentifier | null