优化优惠积分使用逻辑

This commit is contained in:
gyq
2026-01-23 14:14:33 +08:00
parent 4090647345
commit 9a1654e728

View File

@@ -206,7 +206,7 @@
<el-form-item label="积分抵扣">
<div class="flex">
<el-input v-model="couponForm.pointsNum"
:disabled="!couponFormUser.id || !pointOptions.usable || goodsStore.cartInfo.costSummary.finalPayAmount < pointOptions.minPaymentAmount || (couponFormUser.accountPoints || 0) < (pointOptions.minPoints || 0)"
:disabled="!couponFormUser.id || !pointOptions.usable || goodsStore.cartInfo.costSummary.finalPayAmount < pointOptions.minPaymentAmount"
:placeholder="pointOptions.usable ? '请输入需要抵扣的积分' : pointOptions.unusableReason"
v-loading="pointOptions.loading" @input="pointInput">
<template #prepend>现有积分:{{ couponFormUser.accountPoints || 0 }}</template>
@@ -214,10 +214,11 @@
</el-input>
<el-button type="danger" @click="clearPoint">清除</el-button>
</div>
<div class="point_tips err"
v-if="couponFormUser.id && goodsStore.cartInfo.costSummary.finalPayAmount < pointOptions.minPaymentAmount">
注意:订单金额不足¥{{
formatDecimal(+pointOptions.minPaymentAmount) }},无法使用积分抵扣
<div class="point_tips err" v-if="couponFormUser.id && !pointOptions.usable">
注意:{{ pointOptions.unusableReason || (`订单金额不足¥${formatDecimal(+pointOptions.minPaymentAmount)},无法使用积分抵扣`) }}
</div>
<div class="point_tips" v-if="couponFormUser.id && pointOptions.usable">
说明:订单已满足使用门槛,当前积分可抵扣最多¥{{ pointOptions.potentialAmount }}(当前积分 {{ couponFormUser.accountPoints || 0 }}
</div>
</el-form-item>
</el-form>
@@ -666,6 +667,7 @@ const pointOptions = ref({
usable: true,
unusableReason: '',
amount: 0, // 抵扣金额(元)
potentialAmount: 0, // 用户当前积分可抵扣的最大金额(元,供展示)
loading: false
})
@@ -775,7 +777,8 @@ const pointInput = _.debounce(function (e) {
// 未登录用户或无可用积分时直接归0并返回
const userAvailablePoints = Number(couponFormUser.value && couponFormUser.value.accountPoints ? couponFormUser.value.accountPoints : 0)
if (!couponFormUser.value || !couponFormUser.value.id || userAvailablePoints <= 0) {
// 如果未登录、无可用积分或积分抵扣不可用不满足门槛或商家未开启直接归0并返回
if (!couponFormUser.value || !couponFormUser.value.id || userAvailablePoints <= 0 || !pointOptions.value.usable) {
couponForm.value.pointsNum = 0
pointOptions.value.amount = 0
updateCartCalc()
@@ -788,12 +791,11 @@ const pointInput = _.debounce(function (e) {
}
// 边界限制:不得超过最大/小于最小
if (couponForm.value.pointsNum > pointOptions.value.maxPoints) {
if (pointOptions.value.maxPoints && couponForm.value.pointsNum > pointOptions.value.maxPoints) {
couponForm.value.pointsNum = pointOptions.value.maxPoints
}
if (couponForm.value.pointsNum < pointOptions.value.minPoints) {
couponForm.value.pointsNum = pointOptions.value.minPoints
}
// 允许输入少于 minPoints 的积分(前端做友好展示),实际抵扣金额由 calcPointMoney 和后端规则决定
// 如果希望严格按照 minPoints 阈值生效可在此恢复置0逻辑
if (!e) {
couponForm.value.pointsNum = 0
@@ -806,7 +808,7 @@ const pointInput = _.debounce(function (e) {
// 满足条件式开始计算抵扣金额,由后端返回
if (couponForm.value.pointsNum >= pointOptions.value.minPoints && couponForm.value.pointsNum <= pointOptions.value.maxPoints) {
if (couponForm.value.pointsNum > 0 && (!pointOptions.value.maxPoints || couponForm.value.pointsNum <= pointOptions.value.maxPoints)) {
pointOptions.value.loading = true
calcPointMoney()
}
@@ -822,25 +824,30 @@ const calcPointMoney = async () => {
const points = Number(couponForm.value.pointsNum || 0)
const orderAmount = Number(goodsStore.cartInfo.costSummary.finalPayAmount || 0)
if (!pointsPerYuan || points <= 0) {
// 若不满足计算条件,则直接退出并复位
if (!pointOptions.value.usable || !pointsPerYuan || points <= 0) {
pointOptions.value.amount = 0
// 若未初始化 couponForm.value.amount则用订单原价
couponForm.value.amount = couponForm.value.amount || originOrderAmount.value || orderAmount
updateCartCalc()
pointOptions.value.loading = false
return
}
// 积分可抵扣的金额(元) => 积分 / (积分数/元)
let deductionFromPoints = points / pointsPerYuan
const deductionFromPoints = points / pointsPerYuan
// 最大可抵扣金额基于订单金额和最大抵扣比例
// 最大可抵扣金额基于订单金额和最大抵扣比例(后端规则)
const maxDeductionAmount = orderAmount * (pointOptions.value.maxDeductionRatio || 0)
// 最终抵扣为积分抵扣金额与最大比例的较小者,且不超过订单可支付金额
const baseAmount = Number(couponForm.value.amount || originOrderAmount.value || orderAmount)
// 基数为当前可用于抵扣的订单金额可能已经包含其他优惠不能小于0
const baseAmount = Math.max(0, Number(couponForm.value.amount || originOrderAmount.value || orderAmount))
// 最终抵扣为:积分折算金额、最大可抵扣金额、当前可抵扣金额三者的最小值
let deduction = Math.min(deductionFromPoints, maxDeductionAmount, baseAmount)
pointOptions.value.amount = formatDecimal(deduction)
deduction = Number(formatDecimal(deduction))
pointOptions.value.amount = deduction
couponForm.value.amount = formatDecimal(baseAmount - deduction)
updateCartCalc()
@@ -977,19 +984,46 @@ async function pointOptionsAjax() {
// 后端的 equivalentPoints 表示 积分数/元(例如 20 表示 20 积分 = 1 元)
pointOptions.value.pointsPerYuan = pointOptions.value.equivalentPoints
// 规范化 maxDeductionRatio后端可能以百分比(如50)返回若大于1则认为是百分比并除以100
if (pointOptions.value.maxDeductionRatio > 1) {
pointOptions.value.maxDeductionRatio = pointOptions.value.maxDeductionRatio / 100
}
// 计算页面需要的最小/最大可用积分(按接口返回的金额阈值与比例换算为积分)
const pointsPerYuan = pointOptions.value.pointsPerYuan || 0
const orderAmount = Number(goodsStore.cartInfo.costSummary.finalPayAmount || 0)
// 最少使用积分基于最小抵扣金额换算若无则为0minPaymentAmount 单位为元
pointOptions.value.minPoints = pointOptions.value.minPaymentAmount && pointsPerYuan ? Math.ceil(pointOptions.value.minPaymentAmount * pointsPerYuan) : 0
pointOptions.value.minPoints = (pointOptions.value.minPaymentAmount && pointsPerYuan) ? Math.ceil(pointOptions.value.minPaymentAmount * pointsPerYuan) : 0
// 最大可用积分:基于订单金额与最大抵扣比例换算
pointOptions.value.maxPoints = (pointOptions.value.maxDeductionRatio && pointsPerYuan) ? Math.floor(orderAmount * pointOptions.value.maxDeductionRatio * pointsPerYuan) : 0
// 最大可用积分:基于订单金额与最大抵扣比例换算。后端返回的 maxDeductionRatio 表示可抵扣的最大金额占比,需换算为积分
const maxDeductionAmount = orderAmount * (pointOptions.value.maxDeductionRatio || 0)
pointOptions.value.maxPoints = (pointOptions.value.maxDeductionRatio && pointsPerYuan) ? Math.floor(maxDeductionAmount * pointsPerYuan) : 0
// 可用性
pointOptions.value.usable = pointOptions.value.enableRewards === 1 && pointOptions.value.maxPoints > 0
pointOptions.value.unusableReason = pointOptions.value.usable ? '' : (pointOptions.value.enableRewards !== 1 ? '商家未开启积分抵扣' : '订单不可抵扣积分')
// 可用性:必须开启、订单满足最小支付金额门槛且最大可用积分>0
pointOptions.value.usable = (pointOptions.value.enableRewards === 1) && (orderAmount >= (pointOptions.value.minPaymentAmount || 0)) && pointOptions.value.maxPoints > 0
if (!pointOptions.value.usable) {
if (pointOptions.value.enableRewards !== 1) {
pointOptions.value.unusableReason = '商家未开启积分抵扣'
} else if (orderAmount < (pointOptions.value.minPaymentAmount || 0)) {
pointOptions.value.unusableReason = `订单金额不足¥${formatDecimal(+pointOptions.value.minPaymentAmount)},无法使用积分抵扣`
} else {
pointOptions.value.unusableReason = '订单不可抵扣积分'
}
} else {
pointOptions.value.unusableReason = ''
}
// 计算当前用户积分在当前订单下的潜在最大抵扣金额(仅供展示)
let potential = 0
const userPoints = Number(couponFormUser.value && couponFormUser.value.accountPoints ? couponFormUser.value.accountPoints : 0)
if (pointsPerYuan && userPoints > 0) {
potential = Math.min(userPoints / pointsPerYuan, maxDeductionAmount, orderAmount)
}
pointOptions.value.potentialAmount = formatDecimal(potential)
console.log('pointOptions after calc:', JSON.parse(JSON.stringify(pointOptions.value)), 'couponFormUser:', JSON.parse(JSON.stringify(couponFormUser.value)), 'orderAmount:', orderAmount)
} catch (error) {
console.log(error);
}