优化
This commit is contained in:
@@ -34,8 +34,8 @@ const config: CustomerDimensionConfig = {
|
||||
rules: boxes.map(([boxType, boxTypeName, innerLengthCm, innerWidthCm, innerHeightCm, remark], index) => ({
|
||||
id: String(100 + index),
|
||||
boxType, boxTypeName, innerLengthCm, innerWidthCm, innerHeightCm, edgeAdditionCm: 2,
|
||||
outerLengthCm: innerLengthCm + 4, outerWidthCm: innerWidthCm + 4, outerHeightCm: innerHeightCm + 4,
|
||||
volumeCbm: Number(((innerLengthCm + 4) * (innerWidthCm + 4) * (innerHeightCm + 4) / 1_000_000).toFixed(3)),
|
||||
outerLengthCm: innerLengthCm + 2, outerWidthCm: innerWidthCm + 2, outerHeightCm: innerHeightCm + 2,
|
||||
volumeCbm: Number(((innerLengthCm + 2) * (innerWidthCm + 2) * (innerHeightCm + 2) / 1_000_000).toFixed(3)),
|
||||
remark, version: 3, createdAt: '2026-08-07T10:00:00', updatedAt: '2026-08-07T10:20:00',
|
||||
})),
|
||||
}
|
||||
@@ -71,11 +71,11 @@ describe('CustomerBillingRulesPanel', () => {
|
||||
await flushPromises()
|
||||
expect(getCustomerDimensionConfig).toHaveBeenCalledWith('8')
|
||||
expect(document.body.textContent).toContain('按箱规尺寸计算')
|
||||
expect(document.body.textContent).toContain('内径尺寸 + 外边加宽 × 2 = 外径尺寸')
|
||||
expect(document.body.textContent).toContain('长加 X、宽加 X、高加 X = 外径尺寸')
|
||||
expect(document.body.textContent).toContain('小箱')
|
||||
expect(document.body.textContent).toContain('特大箱')
|
||||
expect(document.body.textContent).toContain('34 × 24 × 24')
|
||||
expect(document.body.textContent).toContain('0.020')
|
||||
expect(document.body.textContent).toContain('32 × 22 × 22')
|
||||
expect(document.body.textContent).toContain('0.015')
|
||||
expect(document.body.textContent).toContain('标准中箱')
|
||||
})
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ const BOX_NAMES: Record<CustomerDimensionBoxType, string> = {
|
||||
const columns: DataTableColumn[] = [
|
||||
{ key: 'boxTypeName', label: '箱规类型', minWidth: 110, slotName: 'boxTypeName' },
|
||||
{ key: 'inner', label: '内径尺寸(长×宽×高 cm)', minWidth: 210, slotName: 'inner' },
|
||||
{ key: 'edgeAdditionCm', label: '外边加宽(cm)', width: 150, slotName: 'edgeAdditionCm' },
|
||||
{ key: 'edgeAdditionCm', label: '尺寸增加值(cm)', width: 150, slotName: 'edgeAdditionCm' },
|
||||
{ key: 'outer', label: '外径尺寸(长×宽×高 cm)', minWidth: 210, slotName: 'outer' },
|
||||
{ key: 'volumeCbm', label: '体积(CBM)', width: 130, slotName: 'volumeCbm' },
|
||||
{ key: 'remark', label: '备注', minWidth: 140, prop: 'remark' },
|
||||
@@ -168,7 +168,7 @@ function validateRules() {
|
||||
return false
|
||||
}
|
||||
if (form.rules.some((rule) => !Number.isFinite(rule.edgeAdditionCm) || rule.edgeAdditionCm < 0.001 || rule.edgeAdditionCm > 100)) {
|
||||
ElMessage.error('外边加宽必须在 0.001 至 100cm 之间')
|
||||
ElMessage.error('尺寸增加值必须在 0.001 至 100cm 之间')
|
||||
return false
|
||||
}
|
||||
if (form.rules.some((rule) => (rule.remark || '').length > 500)) {
|
||||
@@ -300,7 +300,7 @@ onMounted(() => { void loadConfig(); void loadChargeRules() })
|
||||
</div>
|
||||
<el-button v-if="canEdit" type="primary" :disabled="loading" @click="openEditor"><Pencil :size="16" />编辑规则</el-button>
|
||||
</header>
|
||||
<div class="formula-band"><span>计算方式:<strong>内径尺寸 + 外边加宽 × 2 = 外径尺寸</strong>(按实测尺寸匹配最小可容纳箱规)</span><span>体积公式:外径长 × 外径宽 × 外径高 ÷ 1,000,000 = CBM</span><span>超出当前箱规时自动匹配下一档箱规</span></div>
|
||||
<div class="formula-band"><span>计算方式:<strong>长加 X、宽加 X、高加 X = 外径尺寸</strong>(X 为尺寸增加值,按实测尺寸匹配最小可容纳箱规)</span><span>体积公式:外径长 × 外径宽 × 外径高 ÷ 1,000,000 = CBM</span><span>超出当前箱规时自动匹配下一档箱规</span></div>
|
||||
<DataTable :data="config.rules" :columns="columns" :loading="loading" row-key="boxType" empty-text="当前客户暂无箱规尺寸规则">
|
||||
<template #boxTypeName="{ row }"><strong>{{ row.boxTypeName }}</strong></template>
|
||||
<template #inner="{ row }">{{ formatDimension(row.innerLengthCm, row.innerWidthCm, row.innerHeightCm) }}</template>
|
||||
@@ -328,10 +328,10 @@ onMounted(() => { void loadConfig(); void loadChargeRules() })
|
||||
|
||||
<AppDialog v-model="editorVisible" title="编辑箱规尺寸 / 计算规则" width="min(1200px, calc(100vw - 28px))" :confirm-loading="editorSaving" :show-cancel="false" :before-close="beforeEditorClose" @confirm="saveConfig">
|
||||
<div class="editor-content">
|
||||
<p class="editor-formula">计算公式:按长、宽、高匹配最小可容纳箱规;外径 = 该箱规内径 + 加宽 × 2(每侧加宽),体积(CBM) = 外径长 × 外径宽 × 外径高 ÷ 1,000,000</p>
|
||||
<p class="editor-formula">计算公式:按长、宽、高匹配最小可容纳箱规;长加 X、宽加 X、高加 X(X 为尺寸增加值),体积(CBM) = 外径长 × 外径宽 × 外径高 ÷ 1,000,000</p>
|
||||
<el-form ref="editorForm" :model="form" label-position="top">
|
||||
<div class="editor-table-wrap">
|
||||
<table class="editor-table"><thead><tr><th>箱规类型</th><th>内径长(cm)</th><th>内径宽(cm)</th><th>内径高(cm)</th><th>外边加宽(cm)</th><th>备注</th></tr></thead><tbody>
|
||||
<table class="editor-table"><thead><tr><th>箱规类型</th><th>内径长(cm)</th><th>内径宽(cm)</th><th>内径高(cm)</th><th>尺寸增加值(cm)</th><th>备注</th></tr></thead><tbody>
|
||||
<tr v-for="row in form.rules" :key="row.boxType"><th scope="row">{{ row.boxTypeName }}</th><td><el-input-number v-model="row.innerLengthCm" :min="0.001" :precision="3" :controls="false" /></td><td><el-input-number v-model="row.innerWidthCm" :min="0.001" :precision="3" :controls="false" /></td><td><el-input-number v-model="row.innerHeightCm" :min="0.001" :precision="3" :controls="false" /></td><td><el-input-number v-model="row.edgeAdditionCm" :min="0.001" :max="100" :precision="3" :controls="false" /></td><td><el-input v-model="row.remark" maxlength="500" /></td></tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
|
||||
@@ -336,6 +336,7 @@ describe('UnifiedOrdersView contract', () => {
|
||||
it('shows the matched dimension addition and enabled multiplier in calculation choices', () => {
|
||||
expect(source).toContain('getCustomerDimensionConfig')
|
||||
expect(source).toContain('matchingDimensionRule')
|
||||
expect(source).toContain('|| rules[rules.length - 1]')
|
||||
expect(source).toContain('`原尺寸 + ${values[0]}cm`')
|
||||
expect(source).toContain('`原尺寸 × ${rule.lengthFactor}`')
|
||||
expect(source).toContain('label="箱规尺寸" value="ADD"')
|
||||
@@ -353,10 +354,13 @@ describe('UnifiedOrdersView contract', () => {
|
||||
expect(source).toContain('calculatedMeasurementRow(row, measurementSectionModes.customer, true)')
|
||||
expect(source).toContain('calculatedMeasurementRow(source, measurementSectionModes.outer)')
|
||||
expect(source).toContain('calculatedMeasurementRow(row as unknown as Record<string, unknown>, measurementSectionModes.actual)')
|
||||
expect(source).toContain("return Number(hasOuterOverride && override != null && override !== '' ? override : value)")
|
||||
expect(source).toContain('rawDimensions.map((value) => value + rule.edgeAdditionCm)')
|
||||
expect(source).toContain('matchedSpecificationCoefficient(chargeRule, calculationSource)')
|
||||
expect(source).toContain('listCustomerChargeRules(customerId, tenantId)')
|
||||
expect(source).toContain('matchedDimensions.map((value) => roundedUp(value * specificationCoefficient, 3))')
|
||||
expect(source).toContain("const selectedMode: 'ADD' | 'MULTIPLY' = measurementSectionModes.outer === 'MULTIPLY'")
|
||||
expect(source).toContain('? selectedMode')
|
||||
expect(source).not.toContain('[chargeRule.lengthFactor, chargeRule.widthFactor, chargeRule.heightFactor]')
|
||||
expect(source).not.toContain('column.key === \'coefficientMode\'')
|
||||
expect(source).not.toContain('@change="updateMeasurementCalculationMode(null, $event)"')
|
||||
|
||||
@@ -277,15 +277,16 @@ function sortedDimensions(row: Record<string, unknown>) {
|
||||
function matchingDimensionRule(row: Record<string, unknown>): CustomerDimensionRule | null {
|
||||
const measured = sortedDimensions(row)
|
||||
if (!measured) return null
|
||||
return [...(measurementDimensionConfig.value?.rules || [])]
|
||||
const rules = [...(measurementDimensionConfig.value?.rules || [])]
|
||||
.sort((left, right) => (
|
||||
left.innerLengthCm * left.innerWidthCm * left.innerHeightCm
|
||||
- right.innerLengthCm * right.innerWidthCm * right.innerHeightCm
|
||||
))
|
||||
.find((rule) => {
|
||||
if (!rules.length) return null
|
||||
return rules.find((rule) => {
|
||||
const inner = [rule.innerLengthCm, rule.innerWidthCm, rule.innerHeightCm].sort((left, right) => right - left)
|
||||
return measured.every((value, index) => value <= inner[index])
|
||||
}) || null
|
||||
}) || rules[rules.length - 1]
|
||||
}
|
||||
|
||||
function addCoefficientLabel(row?: Record<string, unknown>) {
|
||||
@@ -333,9 +334,20 @@ function calculatedMeasurementRow(
|
||||
mode: MeasurementCalculationMode,
|
||||
customerSource = false,
|
||||
) {
|
||||
const calculationSource = source
|
||||
const outerOverrides = [source.outerLengthCm, source.outerWidthCm, source.outerHeightCm]
|
||||
const hasOuterOverride = !customerSource && mode !== 'ACTUAL'
|
||||
&& outerOverrides.some((value) => value != null && value !== '')
|
||||
const rawDimensions = [source.lengthCm, source.widthCm, source.heightCm].map((value, index) => {
|
||||
const override = outerOverrides[index]
|
||||
return Number(hasOuterOverride && override != null && override !== '' ? override : value)
|
||||
})
|
||||
const calculationSource = {
|
||||
...source,
|
||||
lengthCm: rawDimensions[0],
|
||||
widthCm: rawDimensions[1],
|
||||
heightCm: rawDimensions[2],
|
||||
}
|
||||
const rule = matchingDimensionRule(calculationSource)
|
||||
const rawDimensions = [Number(calculationSource.lengthCm), Number(calculationSource.widthCm), Number(calculationSource.heightCm)]
|
||||
if (!rawDimensions.every((value) => Number.isFinite(value) && value > 0)) return { ...source }
|
||||
|
||||
const matchedDimensions = mode === 'ADD' && rule
|
||||
@@ -346,13 +358,7 @@ function calculatedMeasurementRow(
|
||||
? matchedSpecificationCoefficient(chargeRule, calculationSource)
|
||||
: 1
|
||||
const strategyDimensions = matchedDimensions.map((value) => roundedUp(value * specificationCoefficient, 3))
|
||||
const outerOverrides = [source.outerLengthCm, source.outerWidthCm, source.outerHeightCm]
|
||||
const hasOuterOverride = !customerSource && mode !== 'ACTUAL'
|
||||
&& outerOverrides.some((value) => value != null && value !== '')
|
||||
const [lengthCm, widthCm, heightCm] = strategyDimensions.map((value, index) => {
|
||||
const override = outerOverrides[index]
|
||||
return hasOuterOverride && override != null && override !== '' ? Number(override) : value
|
||||
})
|
||||
const [lengthCm, widthCm, heightCm] = strategyDimensions
|
||||
const packageCount = Number(source.packageCount)
|
||||
const unitVolumeCbm = mode === 'ADD' && rule && !hasOuterOverride
|
||||
? Math.round((lengthCm * widthCm * heightCm / 1_000_000) * 1000) / 1000
|
||||
@@ -886,6 +892,12 @@ async function saveWarehouseOuterDimensions(row: Record<string, unknown>) {
|
||||
ElMessage.warning('仓库修改外箱尺寸必须大于 0')
|
||||
return
|
||||
}
|
||||
const selectedMode: 'ADD' | 'MULTIPLY' = measurementSectionModes.outer === 'MULTIPLY'
|
||||
? 'MULTIPLY'
|
||||
: 'ADD'
|
||||
const selectedChargeRuleId = selectedMode === 'MULTIPLY'
|
||||
? activeMeasurementChargeRule.value?.id || null
|
||||
: null
|
||||
measurementOuterSavingId.value = String(row.id)
|
||||
try {
|
||||
await saveInboundMeasurementDraft(String(summary.tenantId), String(summary.inboundId), {
|
||||
@@ -909,8 +921,10 @@ async function saveWarehouseOuterDimensions(row: Record<string, unknown>) {
|
||||
outerLengthCm: String(item.id) === String(row.id) ? dimensions[0] : item.outerLengthCm,
|
||||
outerWidthCm: String(item.id) === String(row.id) ? dimensions[1] : item.outerWidthCm,
|
||||
outerHeightCm: String(item.id) === String(row.id) ? dimensions[2] : item.outerHeightCm,
|
||||
chargeRuleId: item.chargeRuleId,
|
||||
coefficientMode: item.coefficientMode || 'ADD',
|
||||
chargeRuleId: String(item.id) === String(row.id) ? selectedChargeRuleId : item.chargeRuleId,
|
||||
coefficientMode: String(item.id) === String(row.id)
|
||||
? selectedMode
|
||||
: item.coefficientMode || 'ADD',
|
||||
remark: item.remark,
|
||||
})),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user