Merge remote-tracking branch 'origin/release/test' into release/test
This commit is contained in:
@@ -117,6 +117,27 @@ describe('InboundFeePanel', () => {
|
||||
expect(wrapper.find('.surface-panel').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('supports a display-only fee snapshot without calculation or transition actions', async () => {
|
||||
vi.mocked(getLatestInboundFee).mockResolvedValue({ ...snapshot, feeStatus: 'CALCULATED', confirmedAt: null, sentAt: null })
|
||||
const pinia = setupPermissions([
|
||||
'firstleg:fba-pricing:view', 'firstleg:fba-pricing:calculate', 'firstleg:fba-pricing:adjust',
|
||||
'firstleg:fba-pricing:confirm', 'firstleg:inbound:send-fee',
|
||||
])
|
||||
const wrapper = mount(InboundFeePanel, {
|
||||
props: { customerId: '10001', inboundId: '88', displayOnly: true },
|
||||
global: { plugins: [pinia, ElementPlus] },
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.find('button[aria-label="刷新费用快照"]').exists()).toBe(true)
|
||||
expect(wrapper.text()).not.toContain('费用试算')
|
||||
expect(wrapper.text()).not.toContain('确认费用')
|
||||
expect(wrapper.text()).not.toContain('确认推送费用')
|
||||
expect(wrapper.find('[data-testid="adjust-fee-button"]').exists()).toBe(false)
|
||||
expect(wrapper.find('[data-testid="confirm-fee-button"]').exists()).toBe(false)
|
||||
expect(wrapper.find('[data-testid="send-fee-button"]').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('keeps the legacy integration prop compatible while the page layer uses customer context', async () => {
|
||||
const pinia = setupPermissions(['firstleg:fba-pricing:view'])
|
||||
mount(InboundFeePanel, {
|
||||
|
||||
@@ -30,6 +30,7 @@ const props = defineProps<{
|
||||
tenantId?: string
|
||||
inboundId: string
|
||||
compact?: boolean
|
||||
displayOnly?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -352,20 +353,20 @@ defineExpose({ reload: loadFee })
|
||||
><RefreshCw :size="16" /></el-button>
|
||||
</el-tooltip>
|
||||
<el-button
|
||||
v-if="canCalculate"
|
||||
v-if="!displayOnly && canCalculate"
|
||||
type="primary"
|
||||
plain
|
||||
:loading="trialLoading"
|
||||
@click="openTrial"
|
||||
><CircleDollarSign :size="16" />费用试算</el-button>
|
||||
<el-button
|
||||
v-if="canAdjust && adjustmentEligible"
|
||||
v-if="!displayOnly && canAdjust && adjustmentEligible"
|
||||
data-testid="adjust-fee-button"
|
||||
type="primary"
|
||||
@click="openAdjustment"
|
||||
><PencilLine :size="16" />调整初算费用</el-button>
|
||||
<el-button
|
||||
v-if="canConfirm && snapshot?.feeStatus === 'CALCULATED'"
|
||||
v-if="!displayOnly && canConfirm && snapshot?.feeStatus === 'CALCULATED'"
|
||||
data-testid="confirm-fee-button"
|
||||
type="primary"
|
||||
:loading="feeAction === 'confirm'"
|
||||
@@ -373,14 +374,14 @@ defineExpose({ reload: loadFee })
|
||||
@click="transitionFee('confirm')"
|
||||
><Check :size="16" />确认费用</el-button>
|
||||
<el-button
|
||||
v-if="canConfirm && canSend && snapshot?.feeStatus === 'CALCULATED'"
|
||||
v-if="!displayOnly && canConfirm && canSend && snapshot?.feeStatus === 'CALCULATED'"
|
||||
type="primary"
|
||||
:loading="Boolean(feeAction)"
|
||||
:disabled="Boolean(feeAction)"
|
||||
@click="confirmAndPush"
|
||||
><Send :size="16" />确认推送费用</el-button>
|
||||
<el-button
|
||||
v-if="canSend && snapshot?.feeStatus === 'CONFIRMED'"
|
||||
v-if="!displayOnly && canSend && snapshot?.feeStatus === 'CONFIRMED'"
|
||||
data-testid="send-fee-button"
|
||||
type="primary"
|
||||
:loading="feeAction === 'send'"
|
||||
|
||||
@@ -7,10 +7,11 @@ const source = readFileSync(resolve(process.cwd(), 'src/modules/unified-orders/p
|
||||
const routeSource = readFileSync(resolve(process.cwd(), 'src/modules/unified-orders/routes.ts'), 'utf8')
|
||||
|
||||
describe('UnifiedOrdersView contract', () => {
|
||||
it('blocks confirm-send when the customer has already confirmed the fee', () => {
|
||||
expect(source).toContain("snapshot.customerConfirmationStatus === 'CONFIRMED'")
|
||||
expect(source).toContain('客户已确认该费用,费用已锁定,不允许再修改或重新发送')
|
||||
expect(source).toContain('async function openFeeConfirmDialog()')
|
||||
it('shows the server confirmation lock without reading a stale fee snapshot', () => {
|
||||
const openDialogSource = source.slice(source.indexOf('async function openFeeConfirmDialog()'), source.indexOf('async function executeConfirmAndSendFee()'))
|
||||
const sendFeeSource = source.slice(source.indexOf('async function executeConfirmAndSendFee()'), source.indexOf('function handleOrderSelectionChange'))
|
||||
expect(openDialogSource).not.toContain('getLatestInboundFee')
|
||||
expect(sendFeeSource).toContain("ElMessage.error(getApiErrorDetails(error, '确认费用发送失败').message)")
|
||||
})
|
||||
|
||||
it('only exposes the six product main statuses', () => {
|
||||
@@ -88,7 +89,7 @@ describe('UnifiedOrdersView contract', () => {
|
||||
})
|
||||
|
||||
it('covers real list states and keeps operation column first and left-fixed', () => {
|
||||
expect(source).toContain("{ key: 'actions', label: '操作', width: 300, fixed: 'left'")
|
||||
expect(source).toContain("{ key: 'actions', label: '操作', width: 270, fixed: 'left'")
|
||||
expect(source).toContain("key: 'selection', type: 'selection'")
|
||||
expect(source).not.toContain('批量审核接口待接入')
|
||||
expect(source).toContain('@selection-change="handleOrderSelectionChange"')
|
||||
@@ -115,7 +116,7 @@ describe('UnifiedOrdersView contract', () => {
|
||||
expect(columnSource.indexOf("key: 'actions'")).toBeLessThan(columnSource.indexOf("key: 'inboundCode'"))
|
||||
expect(columnSource).not.toContain("key: 'coLoadGroup'")
|
||||
expect(columnSource).not.toContain("key: 'orderNo'")
|
||||
expect(columnSource).toContain("key: 'inboundCode', prop: 'inboundCode', label: '入仓码', minWidth: 260, slotName: 'inboundCode'")
|
||||
expect(columnSource).toContain("key: 'inboundCode', prop: 'inboundCode', label: '入仓码', minWidth: 160, slotName: 'inboundCode'")
|
||||
expect(columnSource).toContain("{ key: 'mainStatus', prop: 'mainStatus', label: '订单主状态'")
|
||||
expect(columnSource).not.toContain("key: 'loadingStatus'")
|
||||
expect(columnSource).not.toContain("key: 'businessDate'")
|
||||
@@ -124,8 +125,8 @@ describe('UnifiedOrdersView contract', () => {
|
||||
expect(columnSource).not.toContain("key: 'recommendedPalletType'")
|
||||
expect(columnSource).toContain("key: 'requestedPickupAt', prop: 'requestedPickupAt', label: '预约提货时间'")
|
||||
expect(columnSource.match(/defaultVisible: false/g)).toHaveLength(13)
|
||||
expect(columnSource).toContain("key: 'expectedArrivalAt', prop: 'expectedArrivalAt', label: '预计到货时间', minWidth: 220, slotName: 'expectedArrival' }")
|
||||
expect(columnSource).toContain("key: 'estimatedVolumeCbm', prop: 'estimatedVolumeCbm', label: '预估体积(m³)', minWidth: 180, slotName: 'estimatedVolume' }")
|
||||
expect(columnSource).toContain("key: 'expectedArrivalAt', prop: 'expectedArrivalAt', label: '预计到货时间', minWidth: 170, slotName: 'expectedArrival' }")
|
||||
expect(columnSource).toContain("key: 'estimatedVolumeCbm', prop: 'estimatedVolumeCbm', label: '预估体积(m³)', minWidth: 120, slotName: 'estimatedVolume' }")
|
||||
expect(columnSource).toContain("key: 'expectedVolumeCbm', prop: 'expectedVolumeCbm', label: '下单体积(m³)', minWidth: 130, slotName: 'field' }")
|
||||
const planningColumnPositions = [
|
||||
columnSource.indexOf("key: 'expectedArrivalAt'"),
|
||||
@@ -391,13 +392,13 @@ describe('UnifiedOrdersView contract', () => {
|
||||
it('confirms customer billing from the saved outer-carton totals', () => {
|
||||
expect(source).toContain('const outerTotals = measurementTotals(outerMeasurementRows.value)')
|
||||
expect(source).toContain("ElMessage.warning('外箱规数据不完整,请先保存外箱规尺寸和计算规则')")
|
||||
expect(source).toContain("weightSource: 'OUTER'")
|
||||
expect(source).toContain("volumeSource: 'OUTER'")
|
||||
expect(source).toContain("weightSource: 'ACTUAL'")
|
||||
expect(source).toContain("volumeSource: 'ACTUAL'")
|
||||
expect(source).not.toContain('测量审核通过后才能确认并发送费用')
|
||||
expect(source).not.toContain("reviewStatus !== 'APPROVED'")
|
||||
expect(source).toContain('const hasActualMeasurementData = computed(() => (measurementDetail.value?.items?.length ?? 0) > 0)')
|
||||
expect(source).toContain("暂无实际测量数据,不能确认并发送费用")
|
||||
expect(source).toContain(':disabled="confirmFeeSending || measurementLoading || !hasActualMeasurementData || !canSendFeeForCurrentStatus"')
|
||||
expect(source).not.toContain(':disabled="confirmFeeSending || measurementLoading || !hasActualMeasurementData"')
|
||||
expect(source).toContain('selectAndSaveOuterMeasurementMode($event)')
|
||||
expect(source).toContain('const saved = await updateMeasurementCalculationMode(null, mode, ruleId)')
|
||||
expect(source).toContain('coefficientMode: targetIds.has(String(item.id)) ? mode')
|
||||
@@ -408,13 +409,22 @@ describe('UnifiedOrdersView contract', () => {
|
||||
expect(source).toContain('item.calculatedOuterLengthCm, item.calculatedOuterWidthCm, item.calculatedOuterHeightCm')
|
||||
expect(source).toContain('if (dimensions.every((dimension) => dimension == null)) return true')
|
||||
expect(source).toContain('已保存并绑定计算规则,体积已重新计算')
|
||||
expect(source).not.toContain('feeConfirmVolume.value = Number(summary.measurement?.actualVolumeCbm)')
|
||||
expect(source).toContain('const measuredGrossWeight = Number(measurementDetail.value?.actualGrossWeightKg)')
|
||||
expect(source).toContain('const measuredNetWeight = Number(measurementDetail.value?.actualNetWeightKg)')
|
||||
expect(source).toContain('const actualVolume = Number(measurementDetail.value?.actualVolumeCbm)')
|
||||
expect(source).toContain('feeConfirmWeight.value = measuredGrossWeight > 0')
|
||||
expect(source).toContain('feeConfirmVolume.value = actualVolume > 0')
|
||||
const sendFeeSource = source.slice(source.indexOf('async function executeConfirmAndSendFee()'), source.indexOf('function handleOrderSelectionChange'))
|
||||
expect(sendFeeSource).not.toContain('saveInboundMeasurementDraft')
|
||||
expect(sendFeeSource).not.toContain('updateMeasurementCalculationMode')
|
||||
expect(source.slice(source.indexOf('async function openFeeConfirmDialog()'), source.indexOf('async function executeConfirmAndSendFee()'))).not.toContain('getLatestInboundFee')
|
||||
})
|
||||
|
||||
it('clears an invalidated measurement loading state before refreshing order details', () => {
|
||||
const detailLoaderSource = source.slice(source.indexOf('async function loadDetail(force = false)'), source.indexOf('watch([page, pageSize]'))
|
||||
expect(detailLoaderSource).toContain('measurementRequestSerial += 1\n measurementLoading.value = false')
|
||||
})
|
||||
|
||||
it('restores the saved outer-carton rule and server-calculated dimensions on re-entry', () => {
|
||||
expect(source).toContain('const savedModes = [...new Set(response.items.map((item) => item.coefficientMode)')
|
||||
expect(source).toContain('measurementSectionModes.outer = savedModes.length === 1')
|
||||
@@ -502,6 +512,9 @@ describe('UnifiedOrdersView contract', () => {
|
||||
expect(source).toContain('InboundFeeDetailManager')
|
||||
expect(source).toContain(':customer-id="String(detail.summary.tenantId)"')
|
||||
expect(source).toContain('compact')
|
||||
expect(source).toContain('display-only')
|
||||
expect(source).toContain(':key="`fee-${normalizedInboundId}-${feePanelRevision}`"')
|
||||
expect(source).toContain('feePanelRevision.value += 1')
|
||||
expect(source).toContain('头程自动初算')
|
||||
expect(source).toContain('其他费用明细')
|
||||
expect(source).toContain('@changed="loadDetail(true)"')
|
||||
|
||||
@@ -129,6 +129,7 @@ const detailError = ref<ApiErrorDetails | null>(null)
|
||||
const declarationEditorOpen = ref(false)
|
||||
const activeDetailTab = ref('basic')
|
||||
const automaticFee = ref<AutomaticFeeSummary | null>(null)
|
||||
const feePanelRevision = ref(0)
|
||||
const otherFeeSummary = ref<OtherFeeSummary>({ currency: 'CNY', approvedReceivable: 0, approvedPayable: 0 })
|
||||
const customerFeeTotal = computed(() => (
|
||||
(automaticFee.value?.feeStatus === 'SENT' ? Number(automaticFee.value.totalAmount || 0) : 0)
|
||||
@@ -197,9 +198,13 @@ const feeConfirmWeight = ref<number | null>(null)
|
||||
const feeConfirmVolume = ref<number | null>(null)
|
||||
const feeConfirmRows = computed(() => {
|
||||
const summary = detail.value?.summary
|
||||
const measurement = summary?.measurement
|
||||
const actualWeight = Number(measurement?.actualGrossWeightKg)
|
||||
const actualVolume = Number(measurement?.actualVolumeCbm)
|
||||
const measuredGrossWeight = Number(measurementDetail.value?.actualGrossWeightKg)
|
||||
const measuredNetWeight = Number(measurementDetail.value?.actualNetWeightKg)
|
||||
const measuredVolume = Number(measurementDetail.value?.actualVolumeCbm)
|
||||
const actualWeight = measuredGrossWeight > 0
|
||||
? measuredGrossWeight
|
||||
: measuredNetWeight > 0 ? measuredNetWeight : null
|
||||
const actualVolume = measuredVolume > 0 ? measuredVolume : null
|
||||
const customerTotals = measurementTotals(customerMeasurementRows.value)
|
||||
return [
|
||||
{ source: '客户下单数据', count: customerTotals.count, weight: customerTotals.gross, volume: customerTotals.volume ?? summary?.expectedVolumeCbm },
|
||||
@@ -434,11 +439,6 @@ const actualMeasurementRows = computed(() => (measurementDetail.value?.items ||
|
||||
calculatedMeasurementRow(row as unknown as Record<string, unknown>, measurementSectionModes.actual, false, false)
|
||||
)))
|
||||
const hasActualMeasurementData = computed(() => (measurementDetail.value?.items?.length ?? 0) > 0)
|
||||
const feeSendEditableStatuses = new Set([
|
||||
'WAIT_MEASURE', 'MEASURING', 'MEASURE_PENDING', 'MEASURE_REJECTED',
|
||||
'WAIT_PRICING', 'FEE_CONFIRMING', 'WAIT_SPLIT',
|
||||
])
|
||||
const canSendFeeForCurrentStatus = computed(() => feeSendEditableStatuses.has(String(detail.value?.summary?.mainStatus || '')))
|
||||
|
||||
function updateMeasurementSectionMode(section: MeasurementSection, mode: MeasurementCalculationMode) {
|
||||
if (mode === 'MULTIPLY' && !activeMeasurementChargeRule.value) {
|
||||
@@ -1180,7 +1180,7 @@ async function loadMeasurementDetails() {
|
||||
measurementLoadedKey.value = key
|
||||
} catch (error) {
|
||||
if (serial !== measurementRequestSerial) return
|
||||
measurementDetail.value = null
|
||||
if (!measurementDetail.value) measurementDetail.value = null
|
||||
measurementError.value = getApiErrorDetails(error, '测量数据加载失败,请稍后重试')
|
||||
} finally {
|
||||
if (serial === measurementRequestSerial) measurementLoading.value = false
|
||||
@@ -1414,10 +1414,6 @@ async function openFeeConfirmDialog() {
|
||||
ElMessage.warning('暂无实际测量数据,不能确认并发送费用')
|
||||
return
|
||||
}
|
||||
if (!canSendFeeForCurrentStatus.value) {
|
||||
ElMessage.warning('订单已进入装柜流程,不能再修改或发送费用')
|
||||
return
|
||||
}
|
||||
if (confirmFeeSending.value) {
|
||||
return
|
||||
}
|
||||
@@ -1431,12 +1427,17 @@ async function openFeeConfirmDialog() {
|
||||
return
|
||||
}
|
||||
const actualTotals = measurementTotals(actualMeasurementRows.value)
|
||||
const customerTotals = measurementTotals(customerMeasurementRows.value)
|
||||
const defaultWeight = Number(outerTotals.gross) > 0 ? Number(outerTotals.gross)
|
||||
: Number(actualTotals.gross) > 0 ? Number(actualTotals.gross)
|
||||
: Number(customerTotals.gross) > 0 ? Number(customerTotals.gross) : null
|
||||
feeConfirmWeight.value = defaultWeight
|
||||
feeConfirmVolume.value = Number(outerTotals.volume)
|
||||
const measuredGrossWeight = Number(measurementDetail.value?.actualGrossWeightKg)
|
||||
const measuredNetWeight = Number(measurementDetail.value?.actualNetWeightKg)
|
||||
const actualVolume = Number(measurementDetail.value?.actualVolumeCbm)
|
||||
feeConfirmWeight.value = measuredGrossWeight > 0
|
||||
? measuredGrossWeight
|
||||
: measuredNetWeight > 0
|
||||
? measuredNetWeight
|
||||
: Number(actualTotals.gross) > 0 ? Number(actualTotals.gross) : null
|
||||
feeConfirmVolume.value = actualVolume > 0
|
||||
? actualVolume
|
||||
: Number(actualTotals.volume) > 0 ? Number(actualTotals.volume) : null
|
||||
feeConfirmOpen.value = true
|
||||
}
|
||||
|
||||
@@ -1456,13 +1457,15 @@ async function executeConfirmAndSendFee() {
|
||||
let snapshot = await calculateInboundFee(tenantId, inboundId, {
|
||||
selectedWeightKg,
|
||||
selectedVolumeCbm,
|
||||
weightSource: 'OUTER',
|
||||
volumeSource: 'OUTER',
|
||||
weightSource: 'ACTUAL',
|
||||
volumeSource: 'ACTUAL',
|
||||
}, createFeeActionIdempotencyKey('calculate'))
|
||||
snapshot = await confirmInboundFee(tenantId, inboundId, createFeeActionIdempotencyKey('confirm'))
|
||||
if (snapshot.feeStatus === 'CONFIRMED') {
|
||||
await sendInboundFee(tenantId, inboundId, createFeeActionIdempotencyKey('send'))
|
||||
ElMessage.success('费用已确认并发送给客户')
|
||||
const sent = await sendInboundFee(tenantId, inboundId, createFeeActionIdempotencyKey('send'))
|
||||
automaticFee.value = { feeStatus: sent.feeStatus, totalAmount: Number(sent.totalAmount || 0) }
|
||||
feePanelRevision.value += 1
|
||||
ElMessage.success('计费重已确认并发送给客户')
|
||||
feeConfirmOpen.value = false
|
||||
await loadDetail(true)
|
||||
return
|
||||
@@ -1799,7 +1802,9 @@ async function loadDetail(force = false) {
|
||||
const serial = ++detailRequestSerial
|
||||
detailLoadingKey = requestKey
|
||||
measurementRequestSerial += 1
|
||||
measurementDetail.value = null
|
||||
measurementLoading.value = false
|
||||
// 刷新详情时保留现有测量数据,避免请求期间列表被清空。
|
||||
if (!force) measurementDetail.value = null
|
||||
measurementError.value = null
|
||||
measurementLoadedKey.value = ''
|
||||
measurementSectionModes.customer = 'ACTUAL'
|
||||
@@ -2024,11 +2029,12 @@ onBeforeUnmount(() => {
|
||||
</dl>
|
||||
<h3 class="fee-section-title">头程自动初算</h3>
|
||||
<InboundFeePanel
|
||||
:key="`fee-${normalizedInboundId}-${feePanelRevision}`"
|
||||
:customer-id="String(detail.summary.tenantId)"
|
||||
:inbound-id="normalizedInboundId"
|
||||
compact
|
||||
display-only
|
||||
@loaded="automaticFee = $event"
|
||||
@changed="loadDetail(true)"
|
||||
/>
|
||||
<h3 class="fee-section-title fee-section-title--secondary">其他费用明细</h3>
|
||||
<InboundFeeDetailManager
|
||||
@@ -2091,11 +2097,10 @@ onBeforeUnmount(() => {
|
||||
v-if="can('firstleg:inbound:confirm-send-fee')"
|
||||
type="primary"
|
||||
:loading="confirmFeeSending"
|
||||
:disabled="confirmFeeSending || measurementLoading || !hasActualMeasurementData || !canSendFeeForCurrentStatus"
|
||||
title="确认并发送费用"
|
||||
data-testid="confirm-send-fee-button"
|
||||
@click="openFeeConfirmDialog"
|
||||
><Send :size="15" />确认费用发送</el-button>
|
||||
><Send :size="15" />确认计费重发送</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-alert v-if="!can('platform:firstleg:inbound:measure:view')" title="当前账号缺少测量查看权限" type="warning" :closable="false" show-icon />
|
||||
@@ -2125,18 +2130,7 @@ onBeforeUnmount(() => {
|
||||
<el-option label="箱规尺寸" value="ADD" />
|
||||
<el-option label="箱规系数" value="MULTIPLY" :disabled="multiplyModeDisabled" />
|
||||
</el-select>
|
||||
<el-select
|
||||
v-if="measurementSectionModes.outer === 'MULTIPLY'"
|
||||
class="measurement-rule-selector__rule"
|
||||
:model-value="boundOuterMeasurementChargeRule?.id"
|
||||
:disabled="Boolean(measurementStrategySavingId) || !activeMeasurementChargeRules.length"
|
||||
placeholder="选择系数规则"
|
||||
aria-label="箱规系数规则"
|
||||
@change="selectAndSaveOuterMeasurementMode('MULTIPLY', $event)"
|
||||
>
|
||||
<el-option v-for="rule in activeMeasurementChargeRules" :key="rule.id" :label="`${rule.ruleCode} v${rule.ruleVersion}`" :value="rule.id" />
|
||||
</el-select>
|
||||
<span class="measurement-rule-selector__hint">规则参数来源:客户管理<span v-if="boundOuterMeasurementChargeRule"> · 当前绑定:{{ boundOuterMeasurementChargeRule.ruleCode }} v{{ boundOuterMeasurementChargeRule.ruleVersion }}</span></span>
|
||||
<span class="measurement-rule-selector__hint">规则参数来源:客户管理</span>
|
||||
</div>
|
||||
<section class="measurement-section">
|
||||
<div class="measurement-section-title"><button type="button" class="measurement-section-toggle" :aria-expanded="!measurementCollapsed.actual" @click="toggleMeasurementSection('actual')"><h3>三、实际测量数据</h3><span class="measurement-section-summary"><span>总件数:{{ measurementTotals(actualMeasurementRows).count ?? '—' }}</span><span>总毛重:{{ formatNumber(measurementTotals(actualMeasurementRows).gross) }}</span><span>总体积:{{ formatNumber(measurementTotals(actualMeasurementRows).volume, 6) }}</span><span>总材积重:{{ formatNumber(measurementTotals(actualMeasurementRows).volumetric) }}</span><span>重量体积:{{ formatNumber(measurementTotals(actualMeasurementRows).weightVolume, 6) }}</span></span><ChevronUp v-if="!measurementCollapsed.actual" :size="18" /><ChevronDown v-else :size="18" /></button><el-select class="measurement-section-mode" :model-value="measurementSectionModes.actual" aria-label="实际测量数据计算方式" @change="updateMeasurementSectionMode('actual', $event)"><el-option label="实测原尺寸(不调整)" value="ACTUAL" /><el-option label="箱规尺寸" value="ADD" /><el-option label="箱规系数" value="MULTIPLY" :disabled="multiplyModeDisabled" /></el-select></div>
|
||||
|
||||
Reference in New Issue
Block a user