feat: 完善头程审核与计费信息

This commit is contained in:
2026-09-08 17:38:09 +08:00
parent cb7bb90eb6
commit dd9b8f7a63
16 changed files with 273 additions and 31 deletions
+42 -5
View File
@@ -86,11 +86,17 @@ const normalizedInboundId = computed(() => {
return identifier && identifier !== 'null' && identifier !== 'undefined' ? identifier : ''
})
const adjustmentEligible = computed(() => (
snapshot.value?.feeStatus === 'CALCULATED'
['CALCULATED', 'CONFIRMED', 'SENT'].includes(snapshot.value?.feeStatus || '')
&& snapshot.value?.nextProcessStatus === 'WAIT_SPLIT'
&& snapshot.value?.customerConfirmationStatus !== 'CONFIRMED'
))
const chargeModeLabel = computed(() => snapshot.value?.chargeMode === 'KG' ? '按重量计费' : '按体积计费')
const chargeUnitLabel = computed(() => snapshot.value?.chargeUnit === 'KG' ? 'KG' : 'CBM')
const convertedQuantityLabel = computed(() => snapshot.value?.chargeMode === 'KG' ? '体积重量' : '重量折算体积')
const adjustmentBaseline = computed(() => Number(snapshot.value?.baselineChargeableQuantity || 0))
const adjustmentMinimum = computed(() => Number(snapshot.value?.lowerChargeableQuantity || 0))
const adjustmentMaximum = computed(() => Number(snapshot.value?.upperChargeableQuantity || 0))
const adjustmentQuantityChanged = computed(() => Math.abs(Number(adjustmentForm.chargeableQuantity) - adjustmentBaseline.value) > 1e-8)
const statusInfo = computed(() => feeStatusInfo(snapshot.value?.feeStatus))
const sourceOptions = computed(() => {
const value = measurement.value
@@ -145,6 +151,12 @@ function taxModeLabel(value: string) {
return firstLegTaxModeLabel(value)
}
function pricingTaxModeLabel(value: string | null | undefined) {
if (value === 'TAX_INCLUDED') return '包税'
if (value === 'TAX_EXCLUDED') return '不包税'
return '—'
}
function roundingModeLabel(value: string) {
const labels: Record<string, string> = {
UP: '远离零方向', DOWN: '向零方向', CEILING: '向上', FLOOR: '向下',
@@ -275,6 +287,7 @@ function adjustmentPayload(): AdjustPublishedInboundFeeRequest {
unitPrice: Number(adjustmentForm.unitPrice),
additionalAmount: Number(adjustmentForm.additionalAmount),
reason: adjustmentForm.reason.trim(),
toleranceConfirmed: true,
}
}
@@ -291,6 +304,22 @@ async function submitAdjustment() {
if (!snapshot.value) return
const valid = await adjustFormRef.value?.validate().catch(() => false)
if (!valid) return
const nextQuantity = Number(adjustmentForm.chargeableQuantity)
if (nextQuantity < adjustmentMinimum.value || nextQuantity > adjustmentMaximum.value) {
ElMessage.warning(`调整后计费量须在基准值的 ±10% 范围内(${formatNumber(adjustmentMinimum.value, 4)}–${formatNumber(adjustmentMaximum.value, 4)} ${chargeUnitLabel.value})`)
return
}
if (adjustmentQuantityChanged.value) {
try {
await ElMessageBox.confirm(
`计费量将由 ${formatNumber(adjustmentBaseline.value, 4)} 调整为 ${formatNumber(nextQuantity, 4)} ${chargeUnitLabel.value},并生成新费用版本。是否继续?`,
'再次确认计费量调整',
{ type: 'warning', confirmButtonText: '确认调整', cancelButtonText: '返回检查' },
)
} catch {
return
}
}
const payload = adjustmentPayload()
adjustmentError.value = null
conflictRefreshed.value = false
@@ -364,7 +393,7 @@ defineExpose({ reload: loadFee })
data-testid="adjust-fee-button"
type="primary"
@click="openAdjustment"
><PencilLine :size="16" />调整初算费用</el-button>
><PencilLine :size="16" />{{ snapshot?.feeStatus === 'CALCULATED' ? '调整初算费用' : '调整已发布费用' }}</el-button>
<el-button
v-if="!displayOnly && canConfirm && snapshot?.feeStatus === 'CALCULATED'"
data-testid="confirm-fee-button"
@@ -452,12 +481,15 @@ defineExpose({ reload: loadFee })
<section class="calculation-section" aria-labelledby="calculation-title">
<div class="section-title">
<div><h4 id="calculation-title">计费依据</h4><p v-if="!compact">实际重量与体积重量取大后计费,金额以服务端快照为准。</p></div>
<el-tag effect="plain">{{ taxModeLabel(snapshot.taxMode) }}</el-tag>
<div class="calculation-tags">
<el-tag effect="plain">订单报关:{{ taxModeLabel(snapshot.taxMode) }}</el-tag>
<el-tag effect="plain">报价税制:{{ pricingTaxModeLabel(snapshot.pricingTaxMode) }}</el-tag>
</div>
</div>
<div class="calculation-flow">
<div><span>实际重量</span><strong>{{ formatNumber(snapshot.actualWeightKg, 3) }} KG</strong></div>
<div><span>实际体积</span><strong>{{ formatNumber(snapshot.actualVolumeCbm, 4) }} CBM</strong></div>
<div><span>体积重量</span><strong>{{ formatNumber(snapshot.convertedQuantity, snapshot.roundingScale) }} {{ chargeUnitLabel }}</strong><small>系数 {{ formatNumber(snapshot.conversionFactor, 4) }}</small></div>
<div><span>{{ convertedQuantityLabel }}</span><strong>{{ formatNumber(snapshot.convertedQuantity, snapshot.roundingScale) }} {{ chargeUnitLabel }}</strong><small>系数 {{ formatNumber(snapshot.conversionFactor, 4) }}</small></div>
<div class="is-chargeable"><span>取大后的计费量</span><strong>{{ formatNumber(snapshot.chargeableQuantity, snapshot.roundingScale) }} {{ chargeUnitLabel }}</strong></div>
</div>
<div class="amount-equation" aria-label="费用计算公式">
@@ -517,6 +549,10 @@ defineExpose({ reload: loadFee })
@confirm="submitAdjustment"
>
<el-alert type="warning" :closable="false" show-icon title="调整会生成新的费用版本;小计和总额由服务端按计费量、单价和附加费重算。" />
<el-alert class="adjustment-alert" type="info" :closable="false" show-icon>
<template #title>计费量允许在系统原始基准值 ±{{ formatNumber(snapshot?.tolerancePercent, 2) }}% 内调整</template>
<p>系统基准 {{ formatNumber(adjustmentBaseline, 4) }} {{ chargeUnitLabel }},服务端允许范围 {{ formatNumber(adjustmentMinimum, 4) }}–{{ formatNumber(adjustmentMaximum, 4) }} {{ chargeUnitLabel }}(包含边界);超出范围将无法提交。</p>
</el-alert>
<el-alert v-if="conflictRefreshed" class="adjustment-alert" type="warning" :closable="false" show-icon>
<template #title>费用已被其他操作员更新,系统已刷新最新快照</template>
<p>当前输入仍保留,请先核对最新版本后再提交。</p>
@@ -524,7 +560,7 @@ defineExpose({ reload: loadFee })
<el-form ref="adjustFormRef" :model="adjustmentForm" :rules="adjustmentRules" label-position="top" class="adjustment-form" :disabled="adjusting">
<div class="adjustment-amounts">
<el-form-item label="调整后计费量" prop="chargeableQuantity" required>
<el-input-number v-model="adjustmentForm.chargeableQuantity" aria-label="调整后计费量" :min="0.0001" :max="999999999999.9999" :precision="4" :step="1" controls-position="right" placeholder="请输入调整后计费量" />
<el-input-number v-model="adjustmentForm.chargeableQuantity" aria-label="调整后计费量" :min="adjustmentMinimum" :max="adjustmentMaximum" :precision="4" :step="1" controls-position="right" placeholder="请输入调整后计费量" />
<span class="adjustment-unit">{{ chargeUnitLabel }}</span>
</el-form-item>
<el-form-item label="调整后单价" prop="unitPrice" required>
@@ -571,6 +607,7 @@ defineExpose({ reload: loadFee })
.version-status { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.calculation-section, .fee-timeline { padding: 10px 0; border-bottom: 1px solid var(--cc-border); }
.section-title { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.calculation-tags { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
.section-title h4 { font-size: 14px; }
.calculation-flow { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: 7px; border-top: 1px solid var(--cc-border); border-bottom: 1px solid var(--cc-border); }
.calculation-flow > div { display: flex; min-width: 0; min-height: 46px; flex-direction: row; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 10px; border-right: 1px solid var(--cc-border); }