@@ -10,7 +10,6 @@ import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import { getApiErrorDetails , type ApiErrorDetails } from '@/shared/api/http'
import { inboundProcessStatusLabels , inboundStatusLabel } from '../status'
import { createManualCartonScan , downloadInboundMeasurementImage , getInboundMeasurement , saveInboundMeasurementDraft , submitInboundMeasurement , updateConfirmedPackageCount } from './api'
import { listCustomerChargeRules , type CustomerChargeRule } from '@/modules/fba-pricing'
import type {
InboundMeasurementDetail ,
InboundMeasurementItem ,
@@ -21,7 +20,6 @@ const props = defineProps<{
customerId ? : string
tenantId ? : string
inboundId : string
openWarehouseSuggestion ? : boolean
} > ( )
const emit = defineEmits < {
@@ -62,15 +60,10 @@ const loading = ref(false)
const saving = ref ( false )
const submitting = ref ( false )
const manualEntryOpen = ref ( false )
const warehouseSuggestionOpen = ref ( false )
const warehouseSuggestionAutoOpened = ref ( false )
const warehouseSuggestion = reactive ( { itemId : '' , packageCount : 1 , remark : '' , coefficientMode : 'ADD' as 'ADD' | 'MULTIPLY' } )
const manualEntrySubmitting = ref ( false )
const manualEntryImage = ref < File | null > ( null )
const manualEntryErrors = ref < string [ ] > ( [ ] )
const detail = ref < InboundMeasurementDetail | null > ( null )
const chargeRules = ref < CustomerChargeRule [ ] > ( [ ] )
const chargeRulesLoading = ref ( false )
const loadError = ref < ApiErrorDetails | null > ( null )
const operationError = ref < ApiErrorDetails | null > ( null )
const conflictDetected = ref ( false )
@@ -105,7 +98,6 @@ const canView = computed(() => access.can('platform:firstleg:inbound:measure:vie
const canEdit = computed ( ( ) => access . can ( 'platform:firstleg:inbound:measure:edit' ) )
const canManualEntry = computed ( ( ) => access . can ( 'platform:firstleg:inbound:measure:manual-entry' ) )
const canSubmit = computed ( ( ) => access . can ( 'platform:firstleg:inbound:measure:submit' ) )
const canWarehouseSuggestion = computed ( ( ) => access . can ( 'platform:firstleg:inbound:warehouse-suggestion:edit' ) )
const customerId = computed ( ( ) => props . customerId || props . tenantId || '' )
const hasContext = computed ( ( ) => Boolean ( customerId . value && props . inboundId ) )
const countEditableProcess = computed ( ( ) => [ 'WAIT_MEASURE' , 'MEASURING' , 'MEASURE_PENDING' , 'MEASURE_REJECTED' ] . includes ( detail . value ? . processStatus || '' ) )
@@ -123,9 +115,6 @@ const isDirty = computed(() => Boolean(detail.value) && snapshot.value !== basel
const registrationOpen = computed ( ( ) => hasContext . value && canView . value && Boolean ( detail . value ) )
const requiredPermission = computed ( ( ) => canEdit . value ? 'platform:firstleg:inbound:measure:edit' : null )
const sourceLabel = computed ( ( ) => ( { THIRD _PARTY : '第三方设备' , MANUAL : '平台人工' , OPENAPI : '第三方设备' } [ detail . value ? . sourceType || '' ] || ( detail . value ? . sourceType ? '未知来源' : '尚未测量' ) ) )
const suggestionItem = computed ( ( ) => form . items . find ( ( item ) => item . itemId === warehouseSuggestion . itemId ) || null )
const suggestionTotalVolume = computed ( ( ) => Number ( suggestionItem . value ? . serverValues . unitVolumeCbm || 0 ) * warehouseSuggestion . packageCount )
const suggestionGirth = computed ( ( ) => suggestionItem . value ? suggestionItem . value . lengthCm + 2 * ( suggestionItem . value . widthCm + suggestionItem . value . heightCm ) : 0 )
interface MeasurementDeviationWarning {
key : string
@@ -305,36 +294,6 @@ function editableItem(item: InboundMeasurementItem): EditableMeasurementItem {
}
}
function openWarehouseSuggestion ( ) {
if ( ! canWarehouseSuggestion . value && ! canEdit . value ) return
const first = form . items [ 0 ]
warehouseSuggestion . itemId = first ? . itemId || ''
warehouseSuggestion . packageCount = first ? . packageCount || 1
warehouseSuggestion . remark = first ? . remark || ''
warehouseSuggestion . coefficientMode = first ? . coefficientMode === 'MULTIPLY' ? 'MULTIPLY' : 'ADD'
warehouseSuggestionOpen . value = true
}
function applyWarehouseSuggestion ( ) {
const item = suggestionItem . value
if ( ! item ) { ElMessage . warning ( '请选择当前实测 SKU' ) ; return }
if ( ! Number . isInteger ( warehouseSuggestion . packageCount ) || warehouseSuggestion . packageCount < 1 ) { ElMessage . warning ( '箱数必须是大于 0 的整数' ) ; return }
item . packageCount = warehouseSuggestion . packageCount
item . remark = warehouseSuggestion . remark . trim ( ) || null
item . coefficientMode = warehouseSuggestion . coefficientMode
warehouseSuggestionOpen . value = false
ElMessage . success ( '仓库建议数据已加入,请保存测量数据' )
}
async function loadChargeRules ( ) {
if ( ! customerId . value || ! access . can ( 'firstleg:fba-pricing:rule:view' ) ) return
chargeRulesLoading . value = true
try {
chargeRules . value = await listCustomerChargeRules ( customerId . value )
} catch { chargeRules . value = [ ] }
finally { chargeRulesLoading . value = false }
}
function clearForm ( ) {
form . measurementId = null
form . version = 0
@@ -366,11 +325,6 @@ async function loadMeasurement() {
const resource = await getInboundMeasurement ( customerId . value , props . inboundId )
if ( sequence !== requestSequence ) return
applyDetail ( resource )
void loadChargeRules ( )
if ( props . openWarehouseSuggestion && ! warehouseSuggestionAutoOpened . value && form . items . length ) {
warehouseSuggestionAutoOpened . value = true
openWarehouseSuggestion ( )
}
} catch ( error ) {
if ( sequence !== requestSequence ) return
detail . value = null
@@ -603,17 +557,6 @@ function measurementRowClassName({ row }: { row: EditableMeasurementItem }) {
return validationErrors . value [ row . clientKey ] ? . length ? 'measurement-table__row--error' : ''
}
function chargeRuleName ( ruleId : string | null | undefined ) {
if ( ! ruleId ) return '默认规则'
const rule = chargeRules . value . find ( ( item ) => item . id === ruleId )
return rule ? chargeRuleLabel ( rule ) : ruleId
}
function chargeRuleLabel ( rule : CustomerChargeRule ) {
const remark = rule . remark ? . trim ( )
return ` 系数 ${ rule . lengthFactor } ${ remark ? ` · ${ remark } ` : '' } ${ rule . defaultRule ? '(默认)' : '' } `
}
watch (
( ) => [ customerId . value , props . inboundId , canView . value ] as const ,
( ) => {
@@ -623,7 +566,6 @@ watch(
operationError . value = null
conflictDetected . value = false
validationErrors . value = { }
warehouseSuggestionAutoOpened . value = false
clearForm ( )
if ( hasContext . value && canView . value ) void loadMeasurement ( )
} ,
@@ -733,7 +675,6 @@ defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, may
< div class = "measurement-section__heading" >
< div > < h3 > 箱规明细 < / h3 > < / div >
< div class = "measurement-section-actions" >
< el-button v-if = "canWarehouseSuggestion" type="primary" plain :disabled="!mayMaintain || !form.items.length" @click="openWarehouseSuggestion"><Plus :size="15" / > 添加仓库建议数据 < / el-button >
< el-button v-if = "canManualEntry" type="primary" plain :disabled="!mayCreateManualEntry" @click="openManualEntry"><Plus :size="15" / > 手动录入箱规 < / el-button >
< / div >
< / div >
@@ -789,15 +730,6 @@ defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, may
/ >
< / template >
< / el-table-column >
< el-table-column label = "计算方式" min -width = " 150 " >
< template # default = "{ row }" >
< el-select v-model = "row.coefficientMode" placeholder="选择计算方式" >
< el -option label = "实测原尺寸(不调整)" value = "ACTUAL" / >
< el-option label = "按箱规尺寸策略" value = "ADD" / >
< el-option label = "按箱规尺寸系数" value = "MULTIPLY" : disabled = "!chargeRules.some((rule) => rule.defaultRule && rule.status === 'ACTIVE')" / >
< / el-select >
< / template >
< / el-table-column >
< el-table-column label = "总体积(m³)" width = "108" align = "right" >
< template # default = "{ row }" > { { formatNumber ( row . serverValues . totalVolumeCbm , 4 ) } } < / template >
< / el-table-column >
@@ -812,18 +744,6 @@ defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, may
< / el-table-column >
< / el-table >
< el-empty v-else description = "暂无扫描箱测量数据" / >
< div v-if = "form.items.length" class="warehouse-suggestion-table" >
< h3 > 仓库建议数据 < / h3 >
< el-table :data = "form.items" border stripe empty -text = " 暂无仓库建议数据 " >
< el-table-column prop = "itemNo" label = "当前实测 SKU" min -width = " 150 " / >
< el-table-column label = "外箱规 长×宽×高(cm)" min -width = " 190 " > < template # default = "{ row }" > { { formatNumber ( row . outerLengthCm ) } } × { { formatNumber ( row . outerWidthCm ) } } × { { formatNumber ( row . outerHeightCm ) } } < / template > < / el-table-column >
< el-table-column prop = "packageCount" label = "箱数" width = "90" / >
< el-table-column label = "周长(cm)" width = "110" > < template # default = "{ row }" > { { formatNumber ( row . serverValues . girthCm ) } } < / template > < / el-table-column >
< el-table-column label = "总体积(m³)" width = "120" > < template # default = "{ row }" > { { formatNumber ( row . serverValues . unitVolumeCbm == null ? null : row . serverValues . unitVolumeCbm * row . packageCount , 6 ) } } < / template > < / el-table-column >
< el-table-column label = "计算策略" min -width = " 190 " > < template # default = "{ row }" > { { row . coefficientMode === 'MULTIPLY' ? '按箱规尺寸系数' : '按箱规尺寸策略' } } < span v-if = "row.coefficientMode === 'MULTIPLY'" > ( {{ chargeRuleName ( row.chargeRuleId ) }} ) < / span > < / template > < / el -table -column >
< el-table-column prop = "remark" label = "备注" min -width = " 160 " show -overflow -tooltip / >
< / el-table >
< / div >
< / section >
< / fieldset >
< / form >
@@ -837,21 +757,6 @@ defineExpose({ saveDraft, submitForReview, updateActualWeights, mayMaintain, may
< / div >
< / footer >
< AppDialog v-model = "warehouseSuggestionOpen" title="添加仓库建议数据" width="min(680px, calc(100vw - 28px))" confirm-text="加入建议" @confirm="applyWarehouseSuggestion" >
< el -form label -position = " top " class = "warehouse-suggestion-form" >
< el-form-item label = "当前实测 SKU" required > < el-select v-model = "warehouseSuggestion.itemId" filterable><el-option v-for="item in form.items" :key="item.itemId" :label="`${item.itemNo} · ${item.boxSpecification || item.boxCode || '实测SKU'}`" :value="item.itemId" / > < / el-select > < / el-form-item >
< el-form-item label = "箱数" required > < el-input-number v-model = "warehouseSuggestion.packageCount" :min="1" :max="1000000" step -strictly / > < / el-form-item >
< el-form-item label = "计算方式" > < el-select v-model = "warehouseSuggestion.coefficientMode"><el-option label="按箱规尺寸策略" value="ADD" /><el-option label="按箱规尺寸系数" value="MULTIPLY" / > < / el-select > < / el-form-item >
< el-form-item label = "备注" > < el-input v-model = "warehouseSuggestion.remark" type="textarea" :rows="3" maxlength="500" show -word -limit / > < / el-form-item >
< / el-form >
< dl v-if = "suggestionItem" class="suggestion-preview" >
< div > < dt > 长 × 宽 × 高 < / dt > < dd > { { formatNumber ( suggestionItem . lengthCm ) } } × { { formatNumber ( suggestionItem . widthCm ) } } × { { formatNumber ( suggestionItem . heightCm ) } } cm < / dd > < / div >
< div > < dt > 箱规周长 < / dt > < dd > { { formatNumber ( suggestionGirth ) } } cm < / dd > < / div >
< div > < dt > 单箱体积 < / dt > < dd > { { formatNumber ( suggestionItem . serverValues . unitVolumeCbm , 6 ) } } m³ < / dd > < / div >
< div > < dt > 总体积 < / dt > < dd > { { formatNumber ( suggestionTotalVolume , 6 ) } } m³ < / dd > < / div >
< / dl >
< / AppDialog >
< el-dialog v-model = "imagePreviewOpen" title="当前有效测量图片" width="min(720px, 92vw)" destroy-on-close @closed="releaseImagePreview" >
< div class = "measurement-image-preview" >
< el-skeleton v-if = "imagePreviewLoading" :rows="5" animated / >