优化
This commit is contained in:
@@ -87,7 +87,7 @@ function measurement(overrides: Partial<InboundMeasurementDetail> = {}): Inbound
|
||||
volumeWeightKg: 100.2,
|
||||
intelligentImageFileId: '88001',
|
||||
machineNo: 'MJ20210327',
|
||||
measuredAt: '2026-08-04T10:30:00+08:00',
|
||||
deviceMeasuredAt: '2026-08-04T10:30:00+08:00',
|
||||
overLimitWarning: null,
|
||||
outerLengthCm: null,
|
||||
outerWidthCm: null,
|
||||
@@ -199,10 +199,13 @@ describe('InboundMeasurementPanel', () => {
|
||||
const text = wrapper.text()
|
||||
|
||||
expect(text).toContain('实测箱数')
|
||||
expect(text).toContain('货物重量')
|
||||
expect(text).toContain('货物净重')
|
||||
expect(text).toContain('总体积')
|
||||
expect(text).toContain('材积重')
|
||||
expect(text).toContain('申报信息')
|
||||
expect(text).toContain('客户申报')
|
||||
expect(text).toContain('平台实测')
|
||||
expect(text).toContain('差异 +1.5 kg')
|
||||
expect(text).toContain('差异 -0.2 m³')
|
||||
expect(text).toContain('箱规明细')
|
||||
expect(text).not.toContain('租户')
|
||||
expect(text).not.toContain('数据版本')
|
||||
@@ -210,6 +213,8 @@ describe('InboundMeasurementPanel', () => {
|
||||
expect(wrapper.find('.measurement-table').exists()).toBe(true)
|
||||
expect(wrapper.find('.measurement-item').exists()).toBe(false)
|
||||
expect(wrapper.find('.measurement-table').text()).not.toContain('周长')
|
||||
expect(wrapper.text()).not.toContain('每箱毛重')
|
||||
expect(wrapper.text()).not.toContain('总重量(kg)')
|
||||
const source = await import('./InboundMeasurementPanel.vue?raw').then((module) => module.default)
|
||||
expect(source).toContain('<section class="measurement-declaration"')
|
||||
expect(source).not.toContain('<el-collapse-item name="declaration"')
|
||||
@@ -237,6 +242,12 @@ describe('InboundMeasurementPanel', () => {
|
||||
expect(declaration.find('.measurement-goods-name input').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('does not render differences when the corresponding declaration is unavailable', async () => {
|
||||
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({ originalGrossWeightKg: null, originalVolumeCbm: null }))
|
||||
const wrapper = await mountPanel()
|
||||
expect(wrapper.find('.measurement-metrics').text()).not.toContain('差异')
|
||||
})
|
||||
|
||||
it('shows all declaration fields as plain text when measurement is not editable', async () => {
|
||||
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({ processStatus: 'WAIT_SPLIT' }))
|
||||
const wrapper = await mountPanel()
|
||||
@@ -396,6 +407,16 @@ describe('InboundMeasurementPanel', () => {
|
||||
expect(wrapper.emitted('updated')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('maps the formal deviceMeasuredAt response field into the read-only measurement time', async () => {
|
||||
const wrapper = await mountPanel()
|
||||
await wrapper.get('.el-table__expand-icon').trigger('click')
|
||||
|
||||
expect(wrapper.text()).toContain('2026-08-04 10:30:00+08:00')
|
||||
const source = await import('./InboundMeasurementPanel.vue?raw').then((module) => module.default)
|
||||
expect(source).toContain('measuredAt: item.deviceMeasuredAt')
|
||||
expect(source).not.toContain('measuredAt: item.measuredAt')
|
||||
})
|
||||
|
||||
it('blocks normal submission when confirmed box counts do not match the order total', async () => {
|
||||
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({ originalPackageCount: 12 }))
|
||||
const wrapper = await mountPanel()
|
||||
|
||||
@@ -214,7 +214,7 @@ function editableItem(item: InboundMeasurementItem): EditableMeasurementItem {
|
||||
unitWeightKg: item.unitWeightKg,
|
||||
intelligentImageFileId: item.intelligentImageFileId == null ? null : String(item.intelligentImageFileId),
|
||||
machineNo: item.machineNo,
|
||||
measuredAt: item.measuredAt,
|
||||
measuredAt: item.deviceMeasuredAt,
|
||||
overLimitWarning: item.overLimitWarning,
|
||||
outerLengthCm: item.outerLengthCm,
|
||||
outerWidthCm: item.outerWidthCm,
|
||||
@@ -398,6 +398,14 @@ function formatNumber(value: number | null | undefined, maximumFractionDigits =
|
||||
return new Intl.NumberFormat('zh-CN', { maximumFractionDigits }).format(value)
|
||||
}
|
||||
|
||||
function formatDifference(actual: number | null | undefined, declared: number | null | undefined, maximumFractionDigits = 3, unit = '') {
|
||||
if (actual == null || declared == null || !Number.isFinite(actual) || !Number.isFinite(declared)) return null
|
||||
const difference = actual - declared
|
||||
if (difference === 0) return null
|
||||
const sign = difference > 0 ? '+' : ''
|
||||
return `差异 ${sign}${formatNumber(difference, maximumFractionDigits)}${unit}`
|
||||
}
|
||||
|
||||
function releaseImagePreview() {
|
||||
if (imagePreviewUrl.value) URL.revokeObjectURL(imagePreviewUrl.value)
|
||||
imagePreviewUrl.value = ''
|
||||
@@ -510,19 +518,20 @@ defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, may
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<dl class="measurement-metrics" aria-label="测量结果汇总">
|
||||
<h4 class="measurement-subheading">平台实测</h4>
|
||||
<dl class="measurement-metrics" aria-label="平台实测结果汇总">
|
||||
<div :class="{ 'measurement-metric--warning': !packageCountMatched }">
|
||||
<dt>实测箱数</dt>
|
||||
<dd>{{ formatNumber(confirmedPackageCount, 0) }} <small>/ 申报 {{ formatNumber(expectedPackageCount, 0) }}</small></dd>
|
||||
<dd>{{ formatNumber(confirmedPackageCount, 0) }} <small v-if="formatDifference(confirmedPackageCount, expectedPackageCount, 0)">/ {{ formatDifference(confirmedPackageCount, expectedPackageCount, 0) }}</small></dd>
|
||||
</div>
|
||||
<div><dt>实测毛重</dt><dd>{{ formatNumber(detail.actualGrossWeightKg) }} <small>kg</small></dd></div>
|
||||
<div class="measurement-metric--primary"><dt>货物重量</dt><dd>{{ formatNumber(detail.actualNetWeightKg) }} <small>kg</small></dd></div>
|
||||
<div><dt>总体积</dt><dd>{{ formatNumber(detail.actualVolumeCbm, 4) }} <small>m³</small></dd></div>
|
||||
<div><dt>实测毛重</dt><dd>{{ formatNumber(detail.actualGrossWeightKg) }} <small>kg<span v-if="formatDifference(detail.actualGrossWeightKg, detail.originalGrossWeightKg, 3, ' kg')"> · {{ formatDifference(detail.actualGrossWeightKg, detail.originalGrossWeightKg, 3, ' kg') }}</span></small></dd></div>
|
||||
<div class="measurement-metric--primary"><dt>货物净重</dt><dd>{{ formatNumber(detail.actualNetWeightKg) }} <small>kg</small></dd></div>
|
||||
<div><dt>总体积</dt><dd>{{ formatNumber(detail.actualVolumeCbm, 4) }} <small>m³<span v-if="formatDifference(detail.actualVolumeCbm, detail.originalVolumeCbm, 4, ' m³')"> · {{ formatDifference(detail.actualVolumeCbm, detail.originalVolumeCbm, 4, ' m³') }}</span></small></dd></div>
|
||||
<div><dt>材积重</dt><dd>{{ formatNumber(detail.volumeWeightKg) }} <small>kg</small></dd></div>
|
||||
</dl>
|
||||
|
||||
<section class="measurement-declaration" aria-labelledby="measurement-declaration-title">
|
||||
<h4 id="measurement-declaration-title">申报信息</h4>
|
||||
<h4 id="measurement-declaration-title">客户申报</h4>
|
||||
<div class="measurement-data-grid">
|
||||
<div class="measurement-readonly-field"><span>申报箱数</span><strong>{{ formatNumber(expectedPackageCount, 0) }}</strong></div>
|
||||
<div class="measurement-readonly-field"><span>申报毛重(kg)</span><strong>{{ formatNumber(detail.originalGrossWeightKg) }}</strong></div>
|
||||
@@ -554,7 +563,6 @@ defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, may
|
||||
<dl class="measurement-row-details">
|
||||
<div><dt>机器编号</dt><dd>{{ row.machineNo || '人工录入' }}</dd></div>
|
||||
<div><dt>测量时间</dt><dd>{{ row.measuredAt ? row.measuredAt.replace('T', ' ') : '—' }}</dd></div>
|
||||
<div><dt>每箱毛重</dt><dd>{{ formatNumber(row.unitWeightKg) }} kg</dd></div>
|
||||
<div><dt>单箱体积</dt><dd>{{ formatNumber(row.serverValues.unitVolumeCbm, 4) }} m³</dd></div>
|
||||
<div><dt>箱规周长</dt><dd>{{ formatNumber(row.serverValues.girthCm) }} cm</dd></div>
|
||||
<div><dt>总材积重</dt><dd>{{ formatNumber(row.serverValues.volumeWeightKg) }} kg</dd></div>
|
||||
@@ -583,9 +591,6 @@ defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, may
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总重量(kg)" width="112" align="right">
|
||||
<template #default="{ row }">{{ formatNumber(row.serverValues.totalWeightKg) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总体积(m³)" width="108" align="right">
|
||||
<template #default="{ row }">{{ formatNumber(row.serverValues.totalVolumeCbm, 4) }}</template>
|
||||
</el-table-column>
|
||||
@@ -679,6 +684,7 @@ defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, may
|
||||
.measurement-summary-context p { display: inline-flex; min-width: 0; align-items: baseline; gap: 6px; margin: 0; overflow-wrap: anywhere; color: var(--cc-text); font-size: 12px; font-weight: 600; }
|
||||
.measurement-summary-status { display: flex; flex: 0 0 auto; align-items: center; gap: 9px; }
|
||||
.measurement-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 2px 0; }
|
||||
.measurement-subheading { margin: 0; color: #344054; font-size: 12px; font-weight: 700; }
|
||||
.measurement-metrics > div { display: grid; min-width: 0; min-height: 58px; align-content: center; gap: 4px; padding: 5px 18px; border-left: 1px solid var(--cc-border); }
|
||||
.measurement-metrics > div:first-child { padding-left: 0; border-left: 0; }
|
||||
.measurement-metrics dt { color: var(--cc-muted); font-size: 12px; }
|
||||
|
||||
@@ -34,7 +34,7 @@ function segment(value: string) {
|
||||
|
||||
export async function getInboundMeasurement(customerId: string, inboundId: string) {
|
||||
// Device-scanned fields expected from the backend: originalPackageCount and
|
||||
// items[].boxCode, machineNo, measuredAt. Keep this compatibility mapping here.
|
||||
// items[].boxCode, machineNo, deviceMeasuredAt. Keep the response aligned with the backend OpenAPI.
|
||||
const response = await http.get<ApiEnvelope<InboundMeasurementDetail>, ApiEnvelope<InboundMeasurementDetail>>(
|
||||
measurementPath(inboundId),
|
||||
{ params: { tenantId: customerId } },
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface InboundMeasurementItem {
|
||||
volumeWeightKg: number | null
|
||||
intelligentImageFileId: MeasurementIdentifier | null
|
||||
machineNo: string | null
|
||||
measuredAt: string | null
|
||||
deviceMeasuredAt: string | null
|
||||
overLimitWarning: string | null
|
||||
outerLengthCm: number | null
|
||||
outerWidthCm: number | null
|
||||
|
||||
Reference in New Issue
Block a user