完善预约确认与排车表单并统一计费和筛选展示
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
submitInboundMeasurement,
|
||||
updateConfirmedPackageCount,
|
||||
} from './api'
|
||||
import type { InboundMeasurementDetail } from './types'
|
||||
import type { InboundMeasurementDetail, SaveInboundMeasurementItemRequest } from './types'
|
||||
import InboundMeasurementPanel from './InboundMeasurementPanel.vue'
|
||||
|
||||
vi.mock('./api', () => ({
|
||||
@@ -152,6 +152,10 @@ async function mountPanel(permissions = [
|
||||
return wrapper
|
||||
}
|
||||
|
||||
function measurementDraft(wrapper: Awaited<ReturnType<typeof mountPanel>>) {
|
||||
return (wrapper.vm.$ as unknown as { setupState: { form: { items: SaveInboundMeasurementItemRequest[] } } }).setupState.form
|
||||
}
|
||||
|
||||
enableAutoUnmount(afterEach)
|
||||
afterAll(() => vi.unstubAllGlobals())
|
||||
|
||||
@@ -317,6 +321,50 @@ describe('InboundMeasurementPanel', () => {
|
||||
expect(wrapper.find('.measurement-declaration').element.parentElement).toBe(wrapper.find('.measurement-summary-section').element.parentElement)
|
||||
})
|
||||
|
||||
it('shows raw measured volume rather than customer weighted billing volume in the rows and comparison', async () => {
|
||||
const value = measurement({ originalVolumeCbm: 3.3, originalPackageCount: 22, actualPackageCount: 22, actualVolumeCbm: 7.205, volumeWeightKg: 1203.235 })
|
||||
Object.assign(value.items[0]!, {
|
||||
lengthCm: 62, widthCm: 52, heightCm: 52, packageCount: 22,
|
||||
coefficientMode: 'MULTIPLY', chargeRuleId: '6001',
|
||||
calculatedOuterLengthCm: 77.5, calculatedOuterWidthCm: 65, calculatedOuterHeightCm: 65,
|
||||
unitVolumeCbm: 0.3275, totalVolumeCbm: 7.205,
|
||||
})
|
||||
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(value)
|
||||
const wrapper = await mountPanel()
|
||||
const comparisonVolume = () => wrapper.get('.measurement-comparison tbody tr:last-child').findAll('td').map(cell => cell.text())
|
||||
|
||||
expect(comparisonVolume()).toEqual(['3.300', '3.688', '差异 +0.388 m³'])
|
||||
expect(wrapper.get('.measurement-table').text()).toContain('3.688')
|
||||
expect(wrapper.get('.measurement-table').text()).not.toContain('7.205')
|
||||
expect(wrapper.get('.measurement-extra-facts').text()).toContain('计费材积重')
|
||||
|
||||
await wrapper.get('input[aria-label="仓库修改外箱长"]').setValue('80')
|
||||
expect(comparisonVolume()[1]).toBe('3.688')
|
||||
await wrapper.get('.measurement-count-editor input').setValue('11')
|
||||
expect(comparisonVolume()).toEqual(['3.300', '1.844', '差异 -1.456 m³'])
|
||||
expect(wrapper.get('.measurement-table').text()).toContain('1.844')
|
||||
expect(value.actualVolumeCbm).toBe(7.205)
|
||||
expect(saveInboundMeasurementDraft).not.toHaveBeenCalled()
|
||||
expect(updateConfirmedPackageCount).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('sums measured volumes across rows and does not substitute billing totals for incomplete dimensions', async () => {
|
||||
const value = measurement({ actualVolumeCbm: 9.999 })
|
||||
value.items.push({ ...value.items[0]!, id: '9102', itemNo: '002', boxCode: 'RK202608040001#10-2', lengthCm: 10, widthCm: 20, heightCm: 30, packageCount: 2, totalVolumeCbm: 8.888 })
|
||||
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(value)
|
||||
const wrapper = await mountPanel()
|
||||
expect(wrapper.get('.measurement-comparison tbody tr:last-child').findAll('td')[1]!.text()).toBe('0.612')
|
||||
|
||||
value.items[1]!.lengthCm = 0
|
||||
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(value)
|
||||
await wrapper.setProps({ inboundId: '7002' })
|
||||
await flushPromises()
|
||||
const cells = wrapper.get('.measurement-comparison tbody tr:last-child').findAll('td')
|
||||
expect(cells[1]!.text()).toBe('未测量')
|
||||
expect(cells[2]!.text()).toBe('待测量')
|
||||
expect(wrapper.get('.measurement-table').text()).not.toContain('8.888')
|
||||
})
|
||||
|
||||
it('shows pending comparison rather than a negative count when no boxes have been measured', async () => {
|
||||
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({
|
||||
items: [], actualPackageCount: null, actualGrossWeightKg: null, actualVolumeCbm: null,
|
||||
@@ -424,7 +472,7 @@ describe('InboundMeasurementPanel', () => {
|
||||
it('retains server-calculated facts in the draft without the removed expandable row', async () => {
|
||||
const wrapper = await mountPanel()
|
||||
expect(wrapper.find('.el-table__expand-icon').exists()).toBe(false)
|
||||
expect(wrapper.vm.form.items[0]).toMatchObject({
|
||||
expect(measurementDraft(wrapper).items[0]).toMatchObject({
|
||||
boxSpecification: '50×40×30cm', coefficientMode: 'ACTUAL',
|
||||
calculatedOuterLengthCm: 50, calculatedOuterWidthCm: 40, calculatedOuterHeightCm: 30,
|
||||
calculationRuleVersion: 'DIMENSION_ACTUAL_V1',
|
||||
@@ -621,7 +669,7 @@ describe('InboundMeasurementPanel', () => {
|
||||
|
||||
it('retains the formal deviceMeasuredAt response field in the measurement draft', async () => {
|
||||
const wrapper = await mountPanel()
|
||||
expect(wrapper.vm.form.items[0].measuredAt).toBe('2026-08-04T10:30:00+08:00')
|
||||
expect(measurementDraft(wrapper).items[0]!.measuredAt).toBe('2026-08-04T10: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')
|
||||
|
||||
@@ -120,11 +120,28 @@ const mayMaintain = computed(() => canEdit.value && countEditableProcess.value &
|
||||
const manualEntryEditableProcess = computed(() => ['PREPARING', 'WAIT_MEASURE', 'MEASURING', 'MEASURE_REJECTED'].includes(detail.value?.processStatus || ''))
|
||||
const mayCreateManualEntry = computed(() => canManualEntry.value && manualEntryEditableProcess.value && !loading.value && !saving.value && !submitting.value && !isDirty.value)
|
||||
const confirmedPackageCount = computed(() => form.items.reduce((sum, item) => sum + (Number.isFinite(item.packageCount) ? item.packageCount : 0), 0))
|
||||
// No scan rows means no measured count yet, rather than a measured zero.
|
||||
// 实测展示只使用原始尺寸与确认箱数,不套用计费规则或仓库外箱修正,也不回写计费快照。
|
||||
function measuredVolumeCbm(item: Pick<EditableMeasurementItem, 'lengthCm' | 'widthCm' | 'heightCm' | 'packageCount'>) {
|
||||
if (![item.lengthCm, item.widthCm, item.heightCm].every(value => Number.isFinite(value) && value > 0)
|
||||
|| !Number.isInteger(item.packageCount) || item.packageCount < 1) return null
|
||||
const volume = item.lengthCm * item.widthCm * item.heightCm * item.packageCount / 1_000_000
|
||||
return Number.isFinite(volume) ? volume : null
|
||||
}
|
||||
const measuredTotalVolumeCbm = computed(() => {
|
||||
if (!form.items.length) return null
|
||||
let total = 0
|
||||
for (const item of form.items) {
|
||||
const volume = measuredVolumeCbm(item)
|
||||
if (volume == null) return null
|
||||
total += volume
|
||||
}
|
||||
return total
|
||||
})
|
||||
// 尚无扫描行时保持未测量,不把缺失的实测事实显示为零。
|
||||
const comparisonMetrics = computed(() => [
|
||||
{ label: '箱数', declared: detail.value?.originalPackageCount, actual: form.items.length ? confirmedPackageCount.value : null, digits: 0, unit: '' },
|
||||
{ label: '毛重(kg)', declared: detail.value?.originalGrossWeightKg, actual: detail.value?.actualGrossWeightKg, digits: 3, unit: ' kg' },
|
||||
{ label: '总体积(m³)', declared: detail.value?.originalVolumeCbm, actual: detail.value?.actualVolumeCbm, digits: 3, unit: ' m³' },
|
||||
{ label: '总体积(m³)', declared: detail.value?.originalVolumeCbm, actual: measuredTotalVolumeCbm.value, digits: 3, unit: ' m³' },
|
||||
])
|
||||
|
||||
const expectedPackageCount = computed(() => detail.value?.originalPackageCount ?? null)
|
||||
@@ -734,8 +751,8 @@ defineExpose({ saveDraft, submitForReview, updateWeightEvidence, submissionBlock
|
||||
</table></div>
|
||||
<div class="measurement-extra-facts">
|
||||
<span>货物净重 <strong>{{ formatNumber(detail.actualNetWeightKg) }}</strong> kg</span>
|
||||
<span>材积重 <strong>{{ formatNumber(detail.volumeWeightKg) }}</strong> kg</span>
|
||||
<el-tooltip content="净重、材积重为平台数据,不与客户申报毛重比较"><span tabindex="0">平台补充数据</span></el-tooltip>
|
||||
<span>计费材积重 <strong>{{ formatNumber(detail.volumeWeightKg) }}</strong> kg</span>
|
||||
<el-tooltip content="实测体积按原始尺寸和确认箱数展示;计费材积重沿用服务端按客户计费规则计算的结果,不与客户申报毛重比较"><span tabindex="0">平台补充数据</span></el-tooltip>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -827,7 +844,7 @@ defineExpose({ saveDraft, submitForReview, updateWeightEvidence, submissionBlock
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="总体积(m³)" width="108" align="right">
|
||||
<template #default="{ row }">{{ formatNumber(row.serverValues.totalVolumeCbm, 3, 3) }}</template>
|
||||
<template #default="{ row }">{{ formatNumber(measuredVolumeCbm(row as EditableMeasurementItem), 3, 3) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="图片" width="82" align="center">
|
||||
<template #default="{ row }">
|
||||
|
||||
Reference in New Issue
Block a user