修改价格套餐样式结构
This commit is contained in:
@@ -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 }
|
||||
}
|
||||
Reference in New Issue
Block a user