This commit is contained in:
2026-08-18 11:33:01 +08:00
parent 834382e04b
commit 114d5bacc7
34 changed files with 522 additions and 570 deletions
@@ -37,9 +37,6 @@ interface EditableMeasurementItem extends SaveInboundMeasurementItemRequest {
interface MeasurementFormModel {
measurementId: string | null
version: number
originalDocumentNo: string
originalGrossWeightKg: number | null
originalVolumeCbm: number | null
actualGoodsName: string
items: EditableMeasurementItem[]
}
@@ -79,9 +76,6 @@ let itemSequence = 0
const form = reactive<MeasurementFormModel>({
measurementId: null,
version: 0,
originalDocumentNo: '',
originalGrossWeightKg: null,
originalVolumeCbm: null,
actualGoodsName: '',
items: [],
})
@@ -239,9 +233,6 @@ function editableItem(item: InboundMeasurementItem): EditableMeasurementItem {
function clearForm() {
form.measurementId = null
form.version = 0
form.originalDocumentNo = ''
form.originalGrossWeightKg = null
form.originalVolumeCbm = null
form.actualGoodsName = ''
form.items.splice(0)
baseline.value = JSON.stringify(form)
@@ -252,9 +243,6 @@ function applyDetail(resource: InboundMeasurementDetail) {
detail.value = resource
form.measurementId = resource.measurementId == null ? null : String(resource.measurementId)
form.version = resource.version ?? 0
form.originalDocumentNo = resource.originalDocumentNo || ''
form.originalGrossWeightKg = resource.originalGrossWeightKg
form.originalVolumeCbm = resource.originalVolumeCbm
form.actualGoodsName = resource.actualGoodsName || ''
form.items.splice(0, form.items.length, ...resource.items.map(editableItem))
baseline.value = JSON.stringify(form)
@@ -340,24 +328,13 @@ 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 draftChanged = Boolean(detail.value && (detail.value.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),
})
@@ -446,9 +423,9 @@ function processStatusLabel(status: string | undefined) {
return inboundStatusLabel(status, inboundProcessStatusLabels)
}
function updateActualGrossWeight(actualGrossWeightKg: number | null) {
function updateActualWeights(actualGrossWeightKg: number | null, actualNetWeightKg: number | null) {
if (!detail.value) return
detail.value = { ...detail.value, actualGrossWeightKg }
detail.value = { ...detail.value, actualGrossWeightKg, actualNetWeightKg }
}
function measurementRowClassName({ row }: { row: EditableMeasurementItem }) {
@@ -472,7 +449,7 @@ watch(
onBeforeUnmount(releaseImagePreview)
defineExpose({ saveDraft, submitForReview, updateActualGrossWeight, mayMaintain, maySubmit, saving, submitting, canEdit, canSubmit, isDirty })
defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, maySubmit, saving, submitting, canEdit, canSubmit, isDirty })
</script>
<template>
@@ -523,10 +500,9 @@ defineExpose({ saveDraft, submitForReview, updateActualGrossWeight, mayMaintain,
<legend class="sr-only">测量草稿</legend>
<section class="measurement-section measurement-summary-section">
<header class="measurement-summary-header">
<div>
<span>入仓码</span>
<strong>{{ detail.inboundCode || '—' }}</strong>
<p>{{ detail.companyName || '客户未命名' }} · {{ detail.channelName || detail.channelCode || '渠道未填写' }}</p>
<div class="measurement-summary-context">
<p><span>客户</span>{{ detail.companyName || '客户未命名' }}</p>
<p><span>渠道</span>{{ detail.channelName || detail.channelCode || '渠道未填写' }}</p>
</div>
<div class="measurement-summary-status">
<el-tag effect="light">{{ processStatusLabel(detail.processStatus) }}</el-tag>
@@ -539,7 +515,8 @@ defineExpose({ saveDraft, submitForReview, updateActualGrossWeight, mayMaintain,
<dt>实测箱数</dt>
<dd>{{ formatNumber(confirmedPackageCount, 0) }} <small>/ 申报 {{ formatNumber(expectedPackageCount, 0) }}</small></dd>
</div>
<div class="measurement-metric--primary"><dt>货物重量</dt><dd>{{ formatNumber(detail.actualGrossWeightKg) }} <small>kg</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.volumeWeightKg) }} <small>kg</small></dd></div>
</dl>
@@ -547,11 +524,12 @@ defineExpose({ saveDraft, submitForReview, updateActualGrossWeight, mayMaintain,
<section class="measurement-declaration" aria-labelledby="measurement-declaration-title">
<h4 id="measurement-declaration-title">申报信息</h4>
<div class="measurement-data-grid">
<label><span>申报箱数</span><el-input :model-value="formatNumber(expectedPackageCount, 0)" readonly /></label>
<label><span>申报毛重(kg)</span><el-input-number v-model="form.originalGrossWeightKg" :min="0" :precision="3" controls-position="right" /></label>
<label><span>申报体积(m³)</span><el-input-number v-model="form.originalVolumeCbm" :min="0" :precision="4" controls-position="right" /></label>
<label><span>实际品名</span><el-input v-model="form.actualGoodsName" placeholder="请输入实际品名" maxlength="128" /></label>
<label><span>原单据号码</span><el-input v-model="form.originalDocumentNo" placeholder="请输入原单据号码" maxlength="128" /></label>
<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>
<div class="measurement-readonly-field"><span>申报体积(m³)</span><strong>{{ formatNumber(detail.originalVolumeCbm, 4) }}</strong></div>
<label v-if="mayMaintain" class="measurement-goods-name"><span>实际品名</span><el-input v-model="form.actualGoodsName" placeholder="请输入实际品名" maxlength="255" /></label>
<div v-else class="measurement-readonly-field measurement-goods-name"><span>实际品名</span><strong>{{ detail.actualGoodsName || '—' }}</strong></div>
<div class="measurement-readonly-field"><span>原单据号码</span><strong>{{ detail.originalDocumentNo || '—' }}</strong></div>
</div>
</section>
</section>
@@ -696,10 +674,9 @@ defineExpose({ saveDraft, submitForReview, updateActualGrossWeight, mayMaintain,
.measurement-section { padding: 16px 20px; border-top: 1px solid var(--cc-border); }
.measurement-summary-section { display: grid; gap: 12px; border-top: 0; }
.measurement-summary-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; }
.measurement-summary-header > div:first-child { display: grid; min-width: 0; gap: 3px; }
.measurement-summary-context { display: flex; min-width: 0; flex-wrap: wrap; align-items: center; gap: 8px 20px; }
.measurement-summary-header span { color: var(--cc-muted); font-size: 11px; }
.measurement-summary-header strong { overflow-wrap: anywhere; color: var(--cc-text); font-size: 20px; line-height: 1.3; }
.measurement-summary-header p { margin: 0; color: var(--cc-muted); font-size: 12px; }
.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-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); }
@@ -718,7 +695,10 @@ defineExpose({ saveDraft, submitForReview, updateActualGrossWeight, mayMaintain,
.measurement-form label { display: flex; min-width: 0; flex-direction: column; gap: 7px; color: #344054; font-size: 12px; font-weight: 650; }
.measurement-form :deep(.el-input-number), .measurement-form :deep(.el-input) { width: 100%; }
.measurement-data-grid label { display: flex; min-width: 0; flex-direction: column; gap: 5px; color: #344054; font-size: 12px; font-weight: 600; }
.measurement-data-grid :deep(.el-input__wrapper) { border-radius: 3px; background: #f5f5f5; box-shadow: 0 0 0 1px #e5e7eb inset; }
.measurement-data-grid :deep(.el-input__wrapper) { border-radius: 3px; }
.measurement-readonly-field { display: grid; min-width: 0; align-content: start; gap: 7px; }
.measurement-readonly-field span { color: #344054; font-size: 12px; font-weight: 600; }
.measurement-readonly-field strong { min-height: 32px; padding: 7px 0; overflow-wrap: anywhere; color: var(--cc-text); font-size: 13px; line-height: 18px; }
.measurement-image-preview { display: grid; min-height: 240px; place-items: center; }
.measurement-image-preview img { display: block; width: auto; max-width: 100%; max-height: 68vh; object-fit: contain; }
.manual-entry-alert { margin-bottom: 16px; }