This commit is contained in:
2026-08-17 12:31:27 +08:00
parent c6fa22c1b5
commit 6a0c0b9229
22 changed files with 399 additions and 171 deletions
@@ -62,9 +62,12 @@ describe('MeasurementReviewPanel', () => {
expect(wrapper.text()).toContain('柏悦客户 · 海运')
expect(wrapper.text()).toContain('合计货物重量')
expect(wrapper.text()).toContain('全部称重图片')
expect(wrapper.text()).toContain('托盘数量')
expect(wrapper.text()).toContain('1 托')
expect(wrapper.text()).toContain('称重图片')
expect(wrapper.text()).toContain('货物重量')
expect(wrapper.text()).toContain('110 kg')
expect(wrapper.text()).toContain('容量 1.2 m³')
expect(wrapper.text()).not.toContain('申报毛重')
expect(wrapper.text()).not.toContain('托盘皮重')
expect(wrapper.text()).not.toContain('OCR 原文')
@@ -110,6 +113,7 @@ describe('MeasurementReviewPanel', () => {
'货物重量120 kg',
])
expect(wrapper.find('.weight-overview').text()).toContain('330 kg')
expect(wrapper.find('.weight-overview').text()).toContain('3 托')
expect(downloadWeightThumbnail).toHaveBeenCalledTimes(3)
})
@@ -57,7 +57,6 @@ const canRelease = computed(() => access.can('firstleg:inbound:exception-release
const customerId = computed(() => props.customerId || props.tenantId || '')
const isPending = computed(() => detail.value?.measureReviewStatus === 'PENDING' && detail.value?.processStatus === 'MEASURE_PENDING')
const isRejected = computed(() => detail.value?.measureReviewStatus === 'REJECTED' && detail.value?.processStatus === 'MEASURE_REJECTED')
const confirmedWeights = computed(() => detail.value?.weightResults.filter((item) => item.confirmedAt && item.netWeightKg !== null).length ?? 0)
const reviewStatusLabel = computed(() => inboundStatusLabel(detail.value?.measureReviewStatus, inboundReviewStatusLabels, '未提交'))
function formatNumber(value: number | null | undefined, unit = '') {
@@ -262,7 +261,7 @@ defineExpose({ confirmApprove, openReasonDialog, isPending, isRejected, canRevie
<template v-else-if="detail">
<dl class="weight-overview" aria-label="重量审核摘要">
<div class="weight-overview__primary"><dt>合计货物重量</dt><dd>{{ formatNumber(detail.actualGrossWeightKg, ' kg') }}</dd></div>
<div><dt>称重图片</dt><dd>{{ confirmedWeights }} / {{ detail.weightResults.length }} 张已确认</dd></div>
<div><dt>托盘数量</dt><dd>{{ detail.weightResults.length }} 托</dd></div>
</dl>
<div v-if="detail.reviewReason" class="review-reason">
@@ -288,6 +287,10 @@ defineExpose({ confirmApprove, openReasonDialog, isPending, isRejected, canRevie
<span>货物重量</span>
<strong>{{ formatNumber(row.netWeightKg, ' kg') }}</strong>
</div>
<div class="weight-evidence-card__record">
<span>{{ row.palletCode }} · {{ row.palletType }}</span>
<span>容量 {{ formatNumber(row.palletCapacityCbm, ' m³') }}</span>
</div>
</article>
</div>
<el-empty v-else description="暂无称重图片" :image-size="56" />
@@ -365,6 +368,7 @@ defineExpose({ confirmApprove, openReasonDialog, isPending, isRejected, canRevie
.weight-evidence-card__weight { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; }
.weight-evidence-card__weight span { color: var(--cc-muted); font-size: 12px; }
.weight-evidence-card__weight strong { color: #067647; font-size: 20px; overflow-wrap: anywhere; text-align: right; }
.weight-evidence-card__record { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 12px; padding: 0 14px 12px; color: var(--cc-muted); font-size: 12px; }
.missing-evidence { color: var(--cc-muted); font-size: 12px; }
.weight-preview { display: grid; gap: 14px; }.weight-preview__canvas { display: grid; min-height: 320px; max-height: 62vh; overflow: hidden; place-items: center; border: 1px solid var(--cc-border); border-radius: 6px; background: #f2f4f7; }.weight-preview__canvas img { display: block; max-width: 100%; max-height: 62vh; object-fit: contain; }.weight-preview__canvas .el-alert { width: min(520px, calc(100% - 24px)); }.weight-preview__facts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; overflow: hidden; border: 1px solid var(--cc-border); border-radius: 6px; }.weight-preview__facts > div { display: grid; min-width: 0; gap: 5px; padding: 12px 14px; border-right: 1px solid var(--cc-border); }.weight-preview__facts > div:last-child { border-right: 0; }.weight-preview__facts dt { color: var(--cc-muted); font-size: 12px; }.weight-preview__facts dd { min-width: 0; margin: 0; font-weight: 700; overflow-wrap: anywhere; }
.review-actions { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 15px 16px; border: 1px solid #b3d8ff; border-radius: 10px; background: #ecf5ff; }.review-actions > div:first-child { display: grid; gap: 4px; min-width: 0; }.review-actions span { color: #606266; font-size: 12px; line-height: 1.5; }.review-actions--disabled { border-color: var(--cc-border); background: var(--cc-surface-muted); }.action-buttons { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }