This commit is contained in:
2026-08-14 17:38:06 +08:00
parent d1b4a4d3f3
commit 010204da57
12 changed files with 259 additions and 33 deletions
@@ -23,7 +23,7 @@ const detail = {
originalDocumentNo: 'ORD-001', originalGrossWeightKg: 100, originalVolumeCbm: 2, originalPackageCount: 10,
actualPackageCount: 10, actualGrossWeightKg: 110, actualVolumeCbm: 2.2, volumeWeightKg: 367.4, actualGoodsName: '测试货物',
items: [{ id: '1', boxCode: 'RK90001#10-1', itemNo: '001', boxSpecification: '60×40×30', packageCount: 10, lengthCm: 60, widthCm: 40, heightCm: 30, girthCm: 240, unitWeightKg: 11, unitVolumeCbm: 0.072, totalWeightKg: 110, totalVolumeCbm: 0.72, volumeWeightKg: 120.24, intelligentImageFileId: '30001', machineNo: 'MJ20210327', measuredAt: '2026-08-04T10:30:00+08:00', overLimitWarning: '周长超过渠道限制,请人工核验尺寸后再作出审核决定', outerLengthCm: 61, outerWidthCm: 41, outerHeightCm: 31, remark: '外箱存在轻微变形' }],
weightResults: [{ id: '2', fileId: 'file-1', ocrProvider: 'OCR', ocrRawText: '设备屏幕原始识别内容 110.5 KG,包含一段需要自动换行展示的较长文本', ocrWeightValue: 110.5, ocrWeightUnit: 'KG', confidence: 0.98, adjustedWeightValue: 110, adjustedWeightUnit: 'KG', finalWeightKg: 110, recognitionStatus: 'CONFIRMED', adjustmentReason: '去除托盘重量后采用净值', adjustedBy: '20001', adjustedAt: '2026-08-04T09:58:00', confirmedBy: '20002', confirmedAt: '2026-08-04T10:00:00', version: 1 }],
weightResults: [{ id: '2', fileId: 'file-1', palletId: '50001', palletCode: 'TP-001', palletType: '木托盘', palletCapacityCbm: 1.2, palletTareWeightKg: 10, ocrProvider: 'OCR', ocrRawText: '设备屏幕原始识别内容 120.5 KG,包含一段需要自动换行展示的较长文本', ocrWeightValue: 120.5, ocrWeightUnit: 'KG', confidence: 0.98, adjustedWeightValue: 120, adjustedWeightUnit: 'KG', grossWeightKg: 120, netWeightKg: 110, recognitionStatus: 'CONFIRMED', adjustmentReason: '修正 OCR 毛重读数', adjustedBy: '20001', adjustedAt: '2026-08-04T09:58:00', confirmedBy: '20002', confirmedAt: '2026-08-04T10:00:00', version: 1 }],
}
enableAutoUnmount(afterEach)
@@ -48,11 +48,14 @@ describe('MeasurementReviewPanel', () => {
expect(wrapper.text()).toContain('设备实测')
expect(wrapper.text()).toContain('设备采集')
expect(wrapper.text()).not.toContain('DEVICE')
expect(wrapper.text()).toContain('称重 OCR')
expect(wrapper.text()).toContain('货物总重量')
expect(wrapper.text()).toContain('实测长 × 宽 × 高(cm)')
expect(wrapper.text()).toContain('周长超过渠道限制')
expect(wrapper.text()).toContain('OCR 原文:设备屏幕原始识别内容')
expect(wrapper.text()).toContain('调整原因:去除托盘重量后采用净值')
expect(wrapper.text()).toContain('TP-001')
expect(wrapper.text()).toContain('托盘皮重')
expect(wrapper.text()).toContain('货物重量')
expect(wrapper.text()).toContain('调整原因:修正 OCR 毛重读数')
expect(wrapper.findComponent(DataTable).exists()).toBe(true)
expect(wrapper.text()).not.toContain('租户')
expect(wrapper.text()).toContain('通过并进入待分柜')
@@ -49,7 +49,7 @@ 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.finalWeightKg !== null).length ?? 0)
const confirmedWeights = computed(() => detail.value?.weightResults.filter((item) => item.confirmedAt && item.netWeightKg !== null).length ?? 0)
const reviewStatusLabel = computed(() => inboundStatusLabel(detail.value?.measureReviewStatus, inboundReviewStatusLabels, '未提交'))
const measurementColumns: DataTableColumn[] = [
@@ -69,10 +69,13 @@ const measurementColumns: DataTableColumn[] = [
const weightColumns: DataTableColumn[] = [
{ key: 'file', label: '称重文件 / OCR 原文', minWidth: 260, slotName: 'file' },
{ key: 'pallet', label: '托盘', minWidth: 170, slotName: 'pallet' },
{ key: 'status', label: '识别状态', width: 100, slotName: 'status' },
{ key: 'ocrWeight', label: '原始重量', minWidth: 110, slotName: 'ocrWeight' },
{ key: 'adjustedWeight', label: '调整后重量', minWidth: 120, slotName: 'adjustedWeight' },
{ key: 'finalWeight', label: '最终重量', minWidth: 110, slotName: 'finalWeight' },
{ key: 'ocrWeight', label: 'OCR 含托盘毛重', minWidth: 140, slotName: 'ocrWeight' },
{ key: 'adjustedWeight', label: '人工修正毛重', minWidth: 130, slotName: 'adjustedWeight' },
{ key: 'grossWeight', label: '服务端毛重', minWidth: 115, slotName: 'grossWeight' },
{ key: 'tareWeight', label: '托盘皮重', minWidth: 110, slotName: 'tareWeight' },
{ key: 'netWeight', label: '货物重量', minWidth: 110, slotName: 'netWeight' },
{ key: 'confidence', label: '置信度', width: 90, slotName: 'confidence' },
{ key: 'reason', label: '调整原因', minWidth: 180, slotName: 'reason' },
]
@@ -103,7 +106,7 @@ function measurementSourceLabel(value: string | null | undefined) {
function isConflict(error: unknown) {
const details = getApiErrorDetails(error)
return details.code === 'A0409' || details.code === '409' || /并发|版本|已被更新|状态已变化/.test(details.message)
return details.message.includes('版本已变化') || details.message.includes('并发修改')
}
async function loadReview() {
@@ -251,7 +254,7 @@ defineExpose({ confirmApprove, openReasonDialog, isPending, isRejected, canRevie
<div><dt>申报箱数</dt><dd>{{ formatNumber(detail.originalPackageCount, ' 箱') }}</dd></div>
<div><dt>实测箱数</dt><dd>{{ formatNumber(detail.actualPackageCount, ' 箱') }}</dd></div>
<div><dt>申报毛重</dt><dd>{{ formatNumber(detail.originalGrossWeightKg, ' kg') }}</dd></div>
<div><dt>称重 OCR</dt><dd>{{ formatNumber(detail.actualGrossWeightKg, ' kg') }}</dd></div>
<div><dt>货物总重量</dt><dd>{{ formatNumber(detail.actualGrossWeightKg, ' kg') }}</dd></div>
<div><dt>申报体积</dt><dd>{{ formatNumber(detail.originalVolumeCbm, ' CBM') }}</dd></div>
<div><dt>设备实测体积</dt><dd>{{ formatNumber(detail.actualVolumeCbm, ' CBM') }}</dd></div>
<div><dt>材积重</dt><dd>{{ formatNumber(detail.volumeWeightKg, ' kg') }}</dd></div>
@@ -289,10 +292,13 @@ defineExpose({ confirmApprove, openReasonDialog, isPending, isRejected, canRevie
<div class="section-heading"><h3>称重图片识别结果</h3><span class="section-count">{{ detail.weightResults.length }} 张</span></div>
<DataTable :data="detail.weightResults" :columns="weightColumns" empty-text="暂无称重图片识别结果" border stripe>
<template #file="{ row }"><div class="table-wrap"><strong>{{ row.fileId || '未关联文件' }}</strong><span v-if="row.ocrRawText">OCR 原文:{{ row.ocrRawText }}</span></div></template>
<template #pallet="{ row }"><div class="table-wrap"><strong>{{ row.palletCode }}</strong><span>{{ row.palletType }} · {{ formatNumber(row.palletCapacityCbm, ' m³') }}</span></div></template>
<template #status="{ row }">{{ recognitionStatusLabel(row.recognitionStatus) }}</template>
<template #ocrWeight="{ row }">{{ formatNumber(row.ocrWeightValue, ` ${row.ocrWeightUnit || ''}`) }}</template>
<template #adjustedWeight="{ row }">{{ formatNumber(row.adjustedWeightValue, ` ${row.adjustedWeightUnit || ''}`) }}</template>
<template #finalWeight="{ row }">{{ formatNumber(row.finalWeightKg, ' kg') }}</template>
<template #grossWeight="{ row }">{{ formatNumber(row.grossWeightKg, ' kg') }}</template>
<template #tareWeight="{ row }">{{ formatNumber(row.palletTareWeightKg, ' kg') }}</template>
<template #netWeight="{ row }">{{ formatNumber(row.netWeightKg, ' kg') }}</template>
<template #confidence="{ row }">{{ row.confidence === null ? '-' : `${Math.round(row.confidence * 100)}%` }}</template>
<template #reason="{ row }">{{ row.adjustmentReason ? `调整原因:${row.adjustmentReason}` : '-' }}</template>
</DataTable>
+7 -1
View File
@@ -28,6 +28,11 @@ export interface MeasurementReviewItem {
export interface MeasurementReviewWeightResult {
id: string
fileId: string | null
palletId: string
palletCode: string
palletType: string
palletCapacityCbm: number
palletTareWeightKg: number
ocrProvider: string | null
ocrRawText: string | null
ocrWeightValue: number | null
@@ -35,7 +40,8 @@ export interface MeasurementReviewWeightResult {
confidence: number | null
adjustedWeightValue: number | null
adjustedWeightUnit: string | null
finalWeightKg: number | null
grossWeightKg: number | null
netWeightKg: number | null
recognitionStatus: string | null
adjustmentReason: string | null
adjustedBy: string | null