优化
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { AlertTriangle, Image, Plus, RefreshCw, Ruler, Save, Send, Trash2 } from '@lucide/vue'
|
||||
import { AlertTriangle, Image, RefreshCw, Ruler, Save, Send } from '@lucide/vue'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { useUnsavedWorkRegistration } from '@/core/unsaved-work/useUnsavedWorkRegistration'
|
||||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||||
@@ -75,11 +75,17 @@ const customerId = computed(() => props.customerId || props.tenantId || '')
|
||||
const hasContext = computed(() => Boolean(customerId.value && props.inboundId))
|
||||
const editableProcess = computed(() => ['WAIT_MEASURE', 'MEASURING', 'MEASURE_REJECTED'].includes(detail.value?.processStatus || ''))
|
||||
const mayMaintain = computed(() => canEdit.value && editableProcess.value && !loading.value && !submitting.value)
|
||||
const maySubmit = computed(() => canSubmit.value && editableProcess.value && Boolean(form.measurementId) && packageCountMatched.value && !loading.value && !saving.value)
|
||||
const confirmedPackageCount = computed(() => form.items.reduce((sum, item) => sum + (Number.isFinite(item.packageCount) ? item.packageCount : 0), 0))
|
||||
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 && editableProcess.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)
|
||||
const registrationOpen = computed(() => hasContext.value && canView.value && Boolean(detail.value))
|
||||
@@ -105,29 +111,6 @@ function nextItemKey() {
|
||||
return `measurement-item-${itemSequence}`
|
||||
}
|
||||
|
||||
function emptyItem(): EditableMeasurementItem {
|
||||
return {
|
||||
clientKey: nextItemKey(),
|
||||
boxCode: null,
|
||||
itemNo: '',
|
||||
boxSpecification: '',
|
||||
packageCount: 1,
|
||||
lengthCm: 0,
|
||||
widthCm: 0,
|
||||
heightCm: 0,
|
||||
unitWeightKg: 0,
|
||||
intelligentImageFileId: null,
|
||||
machineNo: null,
|
||||
measuredAt: null,
|
||||
overLimitWarning: null,
|
||||
outerLengthCm: null,
|
||||
outerWidthCm: null,
|
||||
outerHeightCm: null,
|
||||
remark: null,
|
||||
serverValues: { girthCm: null, unitVolumeCbm: null, totalWeightKg: null, totalVolumeCbm: null, volumeWeightKg: null },
|
||||
}
|
||||
}
|
||||
|
||||
function editableItem(item: InboundMeasurementItem): EditableMeasurementItem {
|
||||
return {
|
||||
clientKey: nextItemKey(),
|
||||
@@ -219,23 +202,6 @@ async function reloadLatest() {
|
||||
await loadMeasurement()
|
||||
}
|
||||
|
||||
function addItem() {
|
||||
if (form.items.length >= 500) {
|
||||
ElMessage.warning('单个测量批次最多包含 500 条箱规')
|
||||
return
|
||||
}
|
||||
form.items.push(emptyItem())
|
||||
}
|
||||
|
||||
async function removeItem(index: number) {
|
||||
if (saving.value || submitting.value) return
|
||||
if (form.items.length === 1) {
|
||||
ElMessage.warning('测量草稿至少需要一条箱规')
|
||||
return
|
||||
}
|
||||
form.items.splice(index, 1)
|
||||
}
|
||||
|
||||
function isPositive(value: number | null) {
|
||||
return value != null && Number.isFinite(value) && value > 0
|
||||
}
|
||||
@@ -514,7 +480,7 @@ onBeforeUnmount(releaseImagePreview)
|
||||
|
||||
<el-alert v-if="expectedPackageCount !== null && !packageCountMatched" type="warning" :closable="false" show-icon class="measurement-alert">
|
||||
<template #title>确认箱数尚未与订单总箱数匹配</template>
|
||||
当前已确认 {{ confirmedPackageCount }} 箱,订单总箱数 {{ expectedPackageCount }} 箱,还差 {{ Math.abs(packageCountDifference || 0) }} 箱。
|
||||
当前已确认 {{ confirmedPackageCount }} 箱,订单总箱数 {{ expectedPackageCount }} 箱,{{ packageCountDifferenceLabel }}。
|
||||
</el-alert>
|
||||
|
||||
<form class="measurement-form" @submit.prevent="saveDraft">
|
||||
@@ -534,18 +500,14 @@ onBeforeUnmount(releaseImagePreview)
|
||||
|
||||
<section class="measurement-section measurement-items-section">
|
||||
<div class="measurement-section__heading">
|
||||
<div><h3>入库单测量数据明细</h3><p>最多 500 条;保存后由服务端重新计算箱规周长、单箱体积、总毛重、总体积和总材积重。</p></div>
|
||||
<el-button v-if="canEdit" :disabled="!mayMaintain || form.items.length >= 500" @click="addItem"><Plus :size="15" />新增箱规</el-button>
|
||||
<div><h3>扫描箱测量数据明细</h3><p>每条记录对应一个实际扫描箱;人工只确认该条记录代表的箱数,设备数据由服务端计算汇总。</p></div>
|
||||
</div>
|
||||
|
||||
<el-empty v-if="!form.items.length" description="暂无箱规明细">
|
||||
<el-button v-if="mayMaintain" type="primary" @click="addItem"><Plus :size="15" />添加第一条箱规</el-button>
|
||||
</el-empty>
|
||||
<el-empty v-if="!form.items.length" description="暂无扫描箱测量数据" />
|
||||
|
||||
<article v-for="(item, index) in form.items" :key="item.clientKey" class="measurement-item" :class="{ 'has-error': validationErrors[item.clientKey]?.length }">
|
||||
<header>
|
||||
<div><strong>扫描箱 {{ index + 1 }}</strong><span>{{ item.boxCode || '未关联箱号' }} · {{ item.machineNo || '人工录入' }}</span></div>
|
||||
<el-button v-if="canEdit" link type="danger" :disabled="!mayMaintain || form.items.length === 1" @click="removeItem(index)"><Trash2 :size="15" />删除</el-button>
|
||||
</header>
|
||||
<div class="measurement-item__grid">
|
||||
<label><span>箱号</span><el-input :model-value="item.boxCode || '—'" readonly /></label>
|
||||
@@ -621,7 +583,7 @@ onBeforeUnmount(releaseImagePreview)
|
||||
.measurement-context__identity span { color: var(--cc-muted); font-size: 12px; line-height: 1.5; }
|
||||
.measurement-tags { display: flex; flex: 0 0 auto; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 7px; }
|
||||
.measurement-tags > span:last-child { color: var(--cc-muted); font-size: 11px; }
|
||||
.measurement-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 16px 0 0; border: 1px solid var(--cc-border); border-radius: 8px; background: #fff; }
|
||||
.measurement-metrics { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); margin: 16px 0 0; border: 1px solid var(--cc-border); border-radius: 8px; background: #fff; }
|
||||
.measurement-metrics > div { min-width: 0; padding: 13px 15px; border-right: 1px solid var(--cc-border); }
|
||||
.measurement-metrics > div:last-child { border-right: 0; }
|
||||
.measurement-metrics dt { color: var(--cc-muted); font-size: 11px; }
|
||||
@@ -638,6 +600,9 @@ onBeforeUnmount(releaseImagePreview)
|
||||
.measurement-form-grid, .measurement-item__grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 15px; }
|
||||
.measurement-form label, .measurement-item 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-image-field :deep(.el-button) { width: 100%; margin: 0; }
|
||||
.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; }
|
||||
.measurement-items-section { background: #fafbfc; }
|
||||
.measurement-item { overflow: hidden; margin-top: 14px; border: 1px solid var(--cc-border); border-radius: 9px; background: #fff; }
|
||||
.measurement-item.has-error { border-color: var(--el-color-danger-light-5); }
|
||||
|
||||
Reference in New Issue
Block a user