This commit is contained in:
2026-08-13 19:00:37 +08:00
parent 41038e1edd
commit 0f0ae612ca
18 changed files with 175 additions and 170 deletions
@@ -9,6 +9,7 @@ import {
downloadInboundMeasurementImage,
createManualCartonScan,
getInboundMeasurement,
saveInboundMeasurementDraft,
submitInboundMeasurement,
updateConfirmedPackageCount,
} from './api'
@@ -132,6 +133,7 @@ describe('InboundMeasurementPanel', () => {
measurementId: '9001', measurementVersion: 3, itemId: '9101',
boxCode: 'RK202608040001#10-1', confirmedPackageCount: 10,
})
vi.mocked(saveInboundMeasurementDraft).mockReset().mockResolvedValue({ measurementId: '9001', version: 3, status: 'DRAFT' })
vi.mocked(submitInboundMeasurement).mockReset().mockResolvedValue({
measurementId: '9001', version: 2, processStatus: 'MEASURE_PENDING', measureReviewStatus: 'PENDING',
recommendedPalletType: 'STANDARD', feeId: null, feeNo: null, feeStatus: null,
@@ -230,7 +232,7 @@ describe('InboundMeasurementPanel', () => {
const wrapper = await mountPanel()
const countInput = wrapper.find('.measurement-count-editor input')
await countInput?.setValue('9')
const save = wrapper.findAll('button').find((button) => button.text().includes('保存确认箱数'))
const save = wrapper.findAll('button').find((button) => button.text().includes('保存测量数据'))
await save?.trigger('click')
await flushPromises()
@@ -247,7 +249,7 @@ describe('InboundMeasurementPanel', () => {
const wrapper = await mountPanel()
const countInput = wrapper.find('.measurement-count-editor input')
await countInput?.setValue('9')
const save = wrapper.findAll('button').find((button) => button.text().includes('保存确认箱数'))
const save = wrapper.findAll('button').find((button) => button.text().includes('保存测量数据'))
await save?.trigger('click')
await flushPromises()
@@ -288,8 +290,7 @@ describe('InboundMeasurementPanel', () => {
vi.mocked(getInboundMeasurement).mockResolvedValueOnce(measurement({ originalPackageCount: 12 }))
const wrapper = await mountPanel()
expect(wrapper.text()).toContain('确认箱数尚未与订单总箱数匹配')
expect(wrapper.text()).toContain('还差 2 箱')
expect(wrapper.text()).not.toContain('确认箱数尚未与订单总箱数匹配')
const submit = wrapper.findAll('button').find((button) => button.text().includes('提交审核'))
expect(submit?.attributes('disabled')).toBeDefined()
expect(submitInboundMeasurement).not.toHaveBeenCalled()
@@ -301,7 +302,7 @@ describe('InboundMeasurementPanel', () => {
const countInput = wrapper.find('.measurement-count-editor input')
expect((countInput?.element as HTMLInputElement).matches(':disabled')).toBe(false)
expect(wrapper.findAll('button').find((button) => button.text().includes('保存确认箱数'))?.attributes('disabled')).toBeUndefined()
expect(wrapper.findAll('button').find((button) => button.text().includes('保存测量数据'))?.attributes('disabled')).toBeUndefined()
expect(wrapper.findAll('button').find((button) => button.text().includes('提交审核'))?.attributes('disabled')).toBeDefined()
expect(vi.mocked(downloadInboundMeasurementImage)).not.toHaveBeenCalled()
})
@@ -8,7 +8,7 @@ import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
import { inboundProcessStatusLabels, inboundStatusLabel } from '../status'
import { createManualCartonScan, downloadInboundMeasurementImage, getInboundMeasurement, submitInboundMeasurement, updateConfirmedPackageCount } from './api'
import { createManualCartonScan, downloadInboundMeasurementImage, getInboundMeasurement, saveInboundMeasurementDraft, submitInboundMeasurement, updateConfirmedPackageCount } from './api'
import type {
InboundMeasurementDetail,
InboundMeasurementItem,
@@ -109,12 +109,6 @@ const confirmedPackageCount = computed(() => form.items.reduce((sum, item) => su
const expectedPackageCount = computed(() => detail.value?.originalPackageCount ?? null)
const packageCountDifference = computed(() => expectedPackageCount.value == null ? null : confirmedPackageCount.value - expectedPackageCount.value)
const packageCountMatched = computed(() => packageCountDifference.value === null || packageCountDifference.value === 0)
const packageCountDifferenceLabel = computed(() => {
if (packageCountDifference.value == null) return ''
return packageCountDifference.value > 0
? `超出 ${packageCountDifference.value} 箱`
: `还差 ${Math.abs(packageCountDifference.value)} 箱`
})
const maySubmit = computed(() => canSubmit.value && submitEditableProcess.value && Boolean(form.measurementId) && packageCountMatched.value && !loading.value && !saving.value)
const snapshot = computed(() => JSON.stringify(form))
const isDirty = computed(() => Boolean(detail.value) && snapshot.value !== baseline.value)
@@ -335,8 +329,29 @@ async function saveDraft() {
conflictDetected.value = false
try {
const originalCounts = new Map((detail.value?.items || []).map((item) => [String(item.id), item.packageCount]))
const originalDraft = detail.value
? { originalDocumentNo: detail.value.originalDocumentNo || '', originalGrossWeightKg: detail.value.originalGrossWeightKg, originalVolumeCbm: detail.value.originalVolumeCbm, actualGoodsName: detail.value.actualGoodsName || '' }
: null
const draftChanged = Boolean(originalDraft && (
originalDraft.originalDocumentNo !== form.originalDocumentNo
|| originalDraft.originalGrossWeightKg !== form.originalGrossWeightKg
|| originalDraft.originalVolumeCbm !== form.originalVolumeCbm
|| originalDraft.actualGoodsName !== form.actualGoodsName
))
const changedItems = form.items.filter((item) => originalCounts.get(item.itemId) !== item.packageCount)
let version = form.version
if (draftChanged) {
const saved = await saveInboundMeasurementDraft(customerId.value, props.inboundId, {
measurementId: form.measurementId,
version,
originalDocumentNo: form.originalDocumentNo.trim() || null,
originalGrossWeightKg: form.originalGrossWeightKg,
originalVolumeCbm: form.originalVolumeCbm,
actualGoodsName: form.actualGoodsName.trim() || null,
items: form.items.map(({ itemId: _itemId, clientKey: _clientKey, serverValues: _serverValues, ...item }) => item),
})
version = saved.version
}
for (const item of changedItems) {
const saved = await updateConfirmedPackageCount(customerId.value, props.inboundId, item.itemId, {
measurementVersion: version,
@@ -496,11 +511,6 @@ defineExpose({ saveDraft, submitForReview, mayMaintain, maySubmit, saving, submi
</ul>
</el-alert>
<el-alert v-if="expectedPackageCount !== null && !packageCountMatched" type="warning" :closable="false" show-icon class="measurement-alert">
<template #title>确认箱数尚未与订单总箱数匹配</template>
当前已确认 {{ confirmedPackageCount }} 箱,订单总箱数 {{ expectedPackageCount }} 箱,{{ packageCountDifferenceLabel }}。
</el-alert>
<form class="measurement-form" @submit.prevent="saveDraft">
<fieldset :disabled="!mayMaintain || saving">
<legend class="sr-only">测量草稿</legend>
@@ -518,12 +528,12 @@ defineExpose({ saveDraft, submitForReview, mayMaintain, maySubmit, saving, submi
<label><span>确认箱数合计</span><el-input :model-value="formatNumber(confirmedPackageCount, 0)" readonly /></label>
<label><span>订单总箱数</span><el-input :model-value="formatNumber(expectedPackageCount, 0)" readonly /></label>
<label><span>实测总毛重(T.K.GW)</span><el-input :model-value="formatNumber(detail.actualGrossWeightKg)" readonly /></label>
<label><span>原单总毛重(T.K.GW)</span><el-input :model-value="formatNumber(form.originalGrossWeightKg)" readonly /></label>
<label><span>原单总毛重(T.K.GW)</span><el-input-number v-model="form.originalGrossWeightKg" :min="0" :precision="3" controls-position="right" /></label>
<label><span>实测总体积(T.CBM)</span><el-input :model-value="formatNumber(detail.actualVolumeCbm, 4)" readonly /></label>
<label><span>原单总体积(T.CBM)</span><el-input :model-value="formatNumber(form.originalVolumeCbm, 4)" readonly /></label>
<label><span>原单总体积(T.CBM)</span><el-input-number v-model="form.originalVolumeCbm" :min="0" :precision="4" controls-position="right" /></label>
<label><span>实测总材积重(kg)</span><el-input :model-value="formatNumber(detail.volumeWeightKg)" readonly /></label>
<label><span>原单据号码(CKW)</span><el-input :model-value="form.originalDocumentNo || '—'" readonly /></label>
<label><span>实际品名</span><el-input :model-value="form.actualGoodsName || '—'" readonly /></label>
<label><span>原单据号码(CKW)</span><el-input v-model="form.originalDocumentNo" placeholder="请输入原单据号码" maxlength="128" /></label>
<label><span>实际品名</span><el-input v-model="form.actualGoodsName" placeholder="请输入实际品名" maxlength="128" /></label>
</div>
</section>
@@ -610,7 +620,7 @@ defineExpose({ saveDraft, submitForReview, mayMaintain, maySubmit, saving, submi
<span v-if="isDirty"><AlertTriangle :size="15" />有尚未保存的修改</span>
<span v-else>当前显示版本 {{ form.version }}</span>
<div>
<el-button v-if="canEdit" type="primary" plain :loading="saving" :disabled="!mayMaintain" @click="saveDraft"><Save :size="15" />保存确认箱数</el-button>
<el-button v-if="canEdit" type="primary" plain :loading="saving" :disabled="!mayMaintain" @click="saveDraft"><Save :size="15" />保存测量数据</el-button>
<el-button v-if="canSubmit" type="primary" :loading="submitting" :disabled="!maySubmit" @click="submitForReview"><Send :size="15" />提交审核</el-button>
</div>
</footer>