修改价格套餐样式结构

This commit is contained in:
wuweihua
2026-09-14 11:53:11 +08:00
parent 4cc20386d9
commit e2f75afb27
16 changed files with 2348 additions and 1330 deletions
@@ -0,0 +1,189 @@
/**
* 价格套餐 · 参考数据与明细级联
*
* 页面内共享一份(在父页面调用一次,作为 prop 传给各步骤组件),
* 避免产品 / 产品国家 / 附加费 被重复请求。
*/
import { listProduct, listProductCountries } from '@/api/price/product'
import { listSurchargeByProduct } from '@/api/price/surcharge'
import {
buildCountryOptions,
buildWeightOptions,
countryKeyOf,
formatWeightLabel,
matchCountry,
toEditableDetailRow
} from '../utils/priceSet'
/**
* 产品 / 产品国家 / 附加费 参考数据(带缓存)
*/
export function usePriceSetRefData() {
/** 产品下拉选项 */
const productOptions = ref([])
/** productCode -> bms_product_country 行 */
const countryCache = reactive({})
/** productCode -> 有效附加费关联 */
const surchargeCache = reactive({})
/** productCode -> 进行中的请求 */
const surchargePending = {}
const productMap = computed(() => new Map(productOptions.value.map(p => [p.value, p])))
/** 加载可选产品(在售) */
function loadProducts() {
return listProduct({ status: '0', pageNum: 1, pageSize: 1000 }).then(res => {
productOptions.value = (res.rows || []).map(p => ({
value: p.productCode,
label: `${p.productCode} ${p.productName || ''}`.trim(),
name: p.productName
}))
return productOptions.value
})
}
/** 产品名称 */
function productNameOf(productCode) {
const hit = productMap.value.get(productCode)
return hit ? hit.name : productCode
}
/** 确保产品的国家×重量段配置已加载(过滤已失效配置) */
function ensureCountries(productCode) {
if (!productCode) return Promise.resolve([])
if (countryCache[productCode]) return Promise.resolve(countryCache[productCode])
return listProductCountries(productCode).then(res => {
const rows = (res.data || []).filter(item => !item.expireDate)
countryCache[productCode] = rows
return rows
})
}
/** 确保产品的有效附加费已加载(剔除 OF 燃油,结果缓存 + 请求去重) */
function ensureSurcharges(productCode) {
if (!productCode) return Promise.resolve([])
if (surchargeCache[productCode]) return Promise.resolve(surchargeCache[productCode])
if (surchargePending[productCode]) return surchargePending[productCode]
surchargePending[productCode] = listSurchargeByProduct(productCode).then(res => {
const rows = (res.data || []).filter(item => String(item.ssCode || '').toLowerCase() !== 'of')
surchargeCache[productCode] = rows
return rows
}).catch(() => {
surchargeCache[productCode] = []
return []
}).finally(() => {
delete surchargePending[productCode]
})
return surchargePending[productCode]
}
/** 明细行命中的附加费(按产品 + 国家 + 重量段过滤) */
function surchargesOf(row) {
if (!row || !row.productCode) return []
const all = surchargeCache[row.productCode] || []
return all.filter(s => {
if (s.countryCode && row.countryCode && String(s.countryCode).toUpperCase() !== String(row.countryCode).toUpperCase()) {
return false
}
if (s.detailId == null) return true
if (row.productCountryId != null && Number(s.detailId) === Number(row.productCountryId)) return true
return false
})
}
/** 明细行可选国家 */
function countryOptionsOf(row) {
return buildCountryOptions(countryCache[row?.productCode] || [])
}
/** 明细行可选重量段 */
function weightOptionsOf(row) {
return buildWeightOptions(countryCache[row?.productCode] || [], row || {})
}
return {
productOptions,
loadProducts,
productNameOf,
ensureCountries,
ensureSurcharges,
surchargesOf,
countryOptionsOf,
weightOptionsOf
}
}
/**
* 明细行级联:产品 → 国家 → 重量段,并带出默认运费 / 挂号费
*
* @param {Object} refData usePriceSetRefData() 的返回值(页面内共享同一份)
*/
export function useDetailCascade(refData) {
/** 切换产品后清空下游字段 */
function resetRow(row) {
row.countryCode = undefined
row.countryName = undefined
row._countryKey = undefined
row.weightLabel = undefined
row.productCountryId = undefined
row.fvValue = undefined
row.fvRegistrationFee = undefined
}
/** 选择产品:回填名称、清空级联、预取附加费与国家配置 */
function onProductChange(row, setType) {
row.productName = row.productCode ? refData.productNameOf(row.productCode) : undefined
resetRow(row)
if (!row.productCode) return
refData.ensureSurcharges(row.productCode)
if (setType === 'FIXED') refData.ensureCountries(row.productCode)
}
/** 选择国家:回填国家码 / 名称,清空重量段与价格 */
function onCountryChange(row) {
const opt = refData.countryOptionsOf(row).find(c => c.key === row._countryKey)
row.countryCode = opt ? opt.code : undefined
row.countryName = opt ? opt.name : undefined
row.weightLabel = undefined
row.productCountryId = undefined
row.fvValue = undefined
row.fvRegistrationFee = undefined
}
/** 选择重量段:绑定产品国家明细,并带出默认运费 / 挂号费 */
function onWeightChange(row) {
const opt = refData.weightOptionsOf(row).find(w => w.value === row.weightLabel)
if (!opt) {
row.productCountryId = undefined
return
}
row.productCountryId = opt.detailId
if (opt.freightPrice != null) row.fvValue = Number(opt.freightPrice)
if (opt.registrationFee != null) row.fvRegistrationFee = Number(opt.registrationFee)
}
/** 回显历史明细行:补齐字段,并把旧重量段文案归一化为 min≤W≤max */
function hydrateRow(d, setType) {
const row = toEditableDetailRow(d)
if (!row.productCode) return row
refData.ensureSurcharges(row.productCode)
if (setType !== 'FIXED') return row
refData.ensureCountries(row.productCode).then(rows => {
if (!row.weightLabel) return
const hit = rows.find(item => {
if (!matchCountry(row, item)) return false
return formatWeightLabel(item.weightMin, item.weightMax) === row.weightLabel
|| (row.weightLabel.includes(String(item.weightMin)) && row.weightLabel.includes(String(item.weightMax)))
})
if (!hit) return
row.weightLabel = formatWeightLabel(hit.weightMin, hit.weightMax)
row._countryKey = countryKeyOf(hit)
row.productCountryId = hit.detailId
if (!row.countryCode) row.countryCode = hit.countryCode
if (!row.countryName) row.countryName = hit.countryName
})
return row
}
return { resetRow, onProductChange, onCountryChange, onWeightChange, hydrateRow }
}