fix: 优惠券调整

This commit is contained in:
2025-09-22 14:41:59 +08:00
parent 4934f20446
commit 2eae21d962
5 changed files with 319 additions and 242 deletions

View File

@@ -233,6 +233,7 @@ export const useCartsStore = defineStore("carts", () => {
const coupons = ref<BackendCoupon[]>([]);
function setCoupons(cps: BackendCoupon[]) {
console.log('setCoupons', cps);
coupons.value = cps;
}
// 优惠券列表

View File

@@ -0,0 +1,303 @@
import { BigNumber } from "bignumber.js";
/**
* 返回可以抵扣优惠券的商品列表,过滤掉赠品、临时商品,价格从高到低排序
* @param arr 商品列表
* @param user 用户信息
*/
export function returnCanDikouGoods(arr, user) {
return arr
.filter((v) => {
return v.is_temporary != 1 && v.is_gift != 1;
})
.sort((a, b) => {
return returnGoodsPrice(b, user) - returnGoodsPrice(a, user);
});
}
/**
* 返回商品单价
* @param goods 商品
* @param user 用户信息
*/
export function returnGoodsPrice(goods, user) {
if (goods.discount_sale_amount * 1 > 0) {
return goods.discount_sale_amount;
}
if (user.isVip && goods.memberPrice * 1 <= goods.salePrice * 1 && goods.memberPrice * 1 > 0) {
return goods.memberPrice;
}
return goods.salePrice;
}
/**
* 返回商品分组
* @param arr 商品列表
*/
export function returnGoodsGroupMap(arr) {
let map = {};
arr.forEach((v) => {
const key = v.productId + "_" + v.skuId;
if (!map[key]) {
map[key] = [];
}
map[key].push(v);
});
return map;
}
/**
* 优惠券类型1-满减券2-商品兑换券3-折扣券4-第二件半价券5-消费送券6-买一送一券7-固定价格券8-免配送费券
* @param coupon
*/
export function returnCoupType(coupon) {
const couponTypes = {
1: "满减券",
2: "商品券",
3: "折扣券",
4: "第二件半价券",
5: "消费送券",
6: "买一送一券",
7: "固定价格券",
8: "免配送费券",
};
return couponTypes[coupon.type] || "未知类型";
}
/**
* 判券是否可用
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param goodsOrderPrice 商品订单金额
* @param user 用户信息
*/
export function returnCouponCanUse(canDikouGoodsArr, coupon, goodsOrderPrice, user) {
if (!coupon.use) {
return false;
}
// 计算门槛金额
let fullAmount = goodsOrderPrice;
//是否抵扣全部商品
const isDikouAll = coupon.useFoods.length === 0;
let canCalcGoodsArr = [];
// 订单里参与门槛计算的商品
if (!isDikouAll) {
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
return coupon.useFoods.find((food) => food.id == v.productId);
});
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
return pre + returnGoodsPrice(cur, user) * cur.num;
}, 0);
}
//没有符合商品
if (!isDikouAll && canCalcGoodsArr.length == 0) {
return false;
}
//不满足门槛金额
if (fullAmount < coupon.fullAmount) {
console.log("不满足门槛金额");
return false;
}
if (coupon.type == 2) {
//商品券
return isDikouAll || canCalcGoodsArr.length > 0;
}
if (coupon.type == 1) {
//满减券
return fullAmount >= coupon.fullAmount;
}
if (coupon.type == 6) {
//买一送一券
let canUse = false;
if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
}
if (canCalcGoodsArr.length > 0) {
canUse = canDikouGoodsArr
.filter((v) => {
return coupon.useFoods.find((food) => food.id == v.productId);
})
.some((v) => v.num >= 2);
}
return canUse;
}
if (coupon.type == 4) {
//第二件半价券
let canUse = false;
if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
}
if (canCalcGoodsArr.length > 0) {
canUse = canDikouGoodsArr
.filter((v) => {
return coupon.useFoods.find((food) => food.id == v.productId);
})
.some((v) => v.num >= 2);
}
return canUse;
}
if (coupon.type == 3) {
//折扣券
return false;
}
}
/**
* 计算抵扣商品金额
* @param discountGoodsArr 可抵扣商品列表
* @param discountNum 抵扣数量
* @param user 用户信息
*/
export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user) {
let hasCountNum = 0;
let discountPrice = 0;
let hasDiscountGoodsArr = [];
for (let i = 0; i < discountGoodsArr.length; i++) {
if (hasCountNum >= discountNum) {
break;
}
const goods = discountGoodsArr[i];
const shengyuNum = discountNum - hasCountNum;
const num = Math.min(goods.num, shengyuNum);
discountPrice += returnGoodsPrice(goods, user) * num;
hasCountNum += num;
hasDiscountGoodsArr.push({ ...goods, num });
}
return { discountPrice, hasDiscountGoodsArr };
}
/**
* 计算优惠券抵扣金额
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
*/
export function returnCouponDiscount(canDikouGoodsArr, coupon, user) {
if (coupon.type == 2) {
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user);
}
if (coupon.type == 6) {
return returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user);
}
if (coupon.type == 4) {
return returnSecoendDiscount(canDikouGoodsArr, coupon, user);
}
}
/**
* 商品券抵扣金额
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
*/
export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user) {
const { useFoods, discountNum, useRule } = coupon;
//抵扣商品数组
let discountGoodsArr = [];
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoodsArr = canDikouGoodsArr
.slice(canDikouGoodsArr.length - discountNum, canDikouGoodsArr.length)
.reverse();
} else {
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
}
} else {
//抵扣选中商品
const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") {
discountGoodsArr = discountSelGoodsArr
.slice(discountSelGoodsArr.length - discountNum, discountSelGoodsArr.length)
.reverse();
} else {
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
}
}
const result = calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user);
console.log(result);
return result;
}
// 返回买一送一券抵扣详情
/**
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
*/
function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user) {
const { useFoods, useRule } = coupon;
//抵扣商品
let discountGoods = undefined;
//符合买一送一条件的商品
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoods = canUseGoods[canUseGoods.length - 1];
} else {
discountGoods = canUseGoods.slice(0, 1);
}
} else {
//符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId));
console.log(canUseGoods1);
if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else {
discountGoods = canUseGoods1.slice(0, 1);
}
}
console.log("discountGoods");
console.log(discountGoods);
const discountPrice = returnGoodsPrice(discountGoods, user);
const hasDiscountGoodsArr = [discountGoods];
return { discountPrice, hasDiscountGoodsArr };
}
/**
* 返回第二件半价券抵扣详情
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
*/
function returnSecoendDiscount(canDikouGoodsArr, coupon, user) {
const { useFoods, useRule } = coupon;
//抵扣商品
let discountGoods = undefined;
//符合买一送一条件的商品
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoods = canUseGoods[canUseGoods.length - 1];
} else {
discountGoods = canUseGoods.slice(0, 1);
}
} else {
//符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId));
console.log(canUseGoods1);
if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else {
discountGoods = canUseGoods1.slice(0, 1);
}
}
const discountPrice = returnGoodsPrice(discountGoods, user);
const hasDiscountGoodsArr = [discountGoods];
//返回半价价格
return {
discountPrice: new BigNumber(discountPrice).dividedBy(2).toNumber(),
hasDiscountGoodsArr,
};
}

View File

@@ -1205,6 +1205,7 @@ export function calcCouponDeduction(
excludedProductIds: []
};
}
console.log('toolCoupons', toolCoupons)
// 2. 优惠券互斥逻辑:兑换券与其他券互斥,优先选最优
const exchangeCoupons = toolCoupons.filter(c => c.type === CouponType.EXCHANGE);

View File

@@ -289,8 +289,9 @@ function refCouponConfirm(e, goodsList) {
pointsDiscountAmount.value = 0;
score.sel = -1;
console.log("refCouponConfirm", e);
quansSelArr.value = e;
carts.setCoupons(e);
quansSelArr.value = e;
checkOrderPay.discountAmount = 0;
checkOrderPay.discount = 0;
score.sel = -1;

View File

@@ -17,7 +17,7 @@
<el-table-column prop="name" label="券名称"></el-table-column>
<el-table-column label="券类型" width="80">
<template v-slot="scope">
{{ returnCoupType(scope.row) }}
{{ UTILS.returnCoupType(scope.row) }}
</template>
</el-table-column>
<el-table-column prop="discountAmount" label="抵扣">
@@ -103,7 +103,7 @@
<el-table-column prop="name" label="券名称"></el-table-column>
<el-table-column label="券类型" width="80">
<template v-slot="scope">
{{ returnCoupType(scope.row) }}
{{ UTILS.returnCoupType(scope.row) }}
</template>
</el-table-column>
<el-table-column label="商品信息" width="120">
@@ -167,7 +167,8 @@
<script setup>
import couponApi from "@/api/account/coupon";
import { OrderPriceCalculator } from "@/utils/goods";
import { BigNumber } from "bignumber.js";
import * as UTILS from "@/utils/goods-utils.js";
import { ElMessageBox } from "element-plus";
import * as quanUtil from "../quan_util.js";
const props = defineProps({
@@ -232,141 +233,21 @@ const refTable1 = ref();
let orderPrice = ref(0);
//可以抵扣的商品列表
let canDikouGoodsArr = [];
let goodsGroupMap = {};
let goodsArr = [];
/**
* 返回可以抵扣优惠券的商品列表,过滤掉赠品、临时商品,价格从高到低排序
* @param arr 商品列表
*/
function returnCanDikouGoods(arr) {
return arr
.filter((v) => {
return v.is_temporary != 1 && v.is_gift != 1;
})
.sort((a, b) => {
return returnGoodsPrice(b, props.user) - returnGoodsPrice(a, props.user);
});
}
/**
* 返回商品分组
* @param arr 商品列表
*/
function returnGoodsGroupMap(arr) {
let map = {};
arr.forEach((v) => {
const key = v.productId + "_" + v.skuId;
if (!map[key]) {
map[key] = [];
}
map[key].push(v);
});
return map;
}
/**
* 优惠券类型1-满减券2-商品兑换券3-折扣券4-第二件半价券5-消费送券6-买一送一券7-固定价格券8-免配送费券
* @param coupon
*/
function returnCoupType(coupon) {
const couponTypes = {
1: "满减券",
2: "商品券",
3: "折扣券",
4: "第二件半价券",
5: "消费送券",
6: "买一送一券",
7: "固定价格券",
8: "免配送费券",
};
return couponTypes[coupon.type] || "未知类型";
}
function open(money, orderInfo) {
let arr = [];
for (let i in orderInfo.detailMap) {
arr.push(...orderInfo.detailMap[i]);
}
goodsArr = arr;
canDikouGoodsArr = returnCanDikouGoods(arr);
goodsGroupMap = returnGoodsGroupMap(canDikouGoodsArr);
canDikouGoodsArr = UTILS.returnCanDikouGoods(arr, props.user);
console.log("canDikouGoodsArr", canDikouGoodsArr);
console.log("goodsGroupMap", goodsGroupMap);
getcoup();
orderPrice.value = money;
show.value = true;
}
/**
* 判断该商品券是否可用
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param goodsOrderPrice 商品订单金额
*/
function canUseGoodsCoupon(canDikouGoodsArr, coupon, goodsOrderPrice) {
//是否抵扣全部商品
const isDikouAll = coupon.useFoods.length === 0;
//是否包含抵扣商品
const isDikou = coupon.useFoods.some((v) =>
canDikouGoodsArr.some((goods) => goods.productId == v.id)
);
return (
coupon.type == 2 &&
(isDikouAll || isDikou) &&
coupon.use &&
goodsOrderPrice >= coupon.fullAmount
);
}
/**
* 判断该买一送一券是否可用
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param goodsOrderPrice 商品订单金额
*/
function canUseBuyOneGiveOne(canDikouGoodsArr, coupon, goodsOrderPrice) {
//是否抵扣全部商品
const isDikouAll = coupon.useFoods.length === 0;
//是否包含抵扣商品
const isDikou = coupon.useFoods.some((v) =>
canDikouGoodsArr.some((goods) => goods.productId == v.id)
);
let canUse = false;
if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
}
if (isDikou) {
canUse = canDikouGoodsArr
.filter((v) => {
return coupon.useFoods.find((food) => food.id == v.productId);
})
.some((v) => v.num >= 2);
}
return coupon.type == 6 && canUse && coupon.use && goodsOrderPrice >= coupon.fullAmount;
}
/**
* 判断该券是否可用
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param goodsOrderPrice 商品订单金额
*/
function juageCouponCanUse(canDikouGoodsArr, coupon, goodsOrderPrice) {
if (coupon.type == 2) {
//商品券
return canUseGoodsCoupon(canDikouGoodsArr, coupon, goodsOrderPrice);
}
if (coupon.type == 1) {
//满减券
return coupon.use && goodsOrderPrice >= coupon.fullAmount;
}
if (coupon.type == 6) {
//买一送一券
return (
coupon.use &&
goodsOrderPrice >= coupon.fullAmount &&
canUseBuyOneGiveOne(canDikouGoodsArr, coupon, goodsOrderPrice)
);
}
}
async function getcoup() {
const res = await couponApi.findCoupon({ shopUserId: props.user.id });
console.log(res);
@@ -374,30 +255,30 @@ async function getcoup() {
quans.value.coupon = res
.filter((v) => v.type != 2)
.filter((coupon) => {
return juageCouponCanUse(canDikouGoodsArr, coupon, orderPrice.value);
return UTILS.returnCouponCanUse(canDikouGoodsArr, coupon, orderPrice.value, props.user);
})
.map((v) => {
const discount = returnCouponDiscount(v);
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, props.user);
return {
...v,
discount,
discountAmount: discount.discountPrice || v.discountAmount,
discountAmount: discount ? discount.discountPrice : v.discountAmount,
};
});
quans.value.productCoupon = res
.filter((v) => v.type == 2)
.filter((coupon) => {
return juageCouponCanUse(canDikouGoodsArr, coupon, orderPrice.value);
return UTILS.returnCouponCanUse(canDikouGoodsArr, coupon, orderPrice.value, props.user);
})
.map((v) => {
const findGoods = goodsArr.find((goods) => goods.productId == v.proId);
const discount = returnCouponDiscount(v);
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, props.user);
return {
...v,
productImg: findGoods ? findGoods.productImg : "",
productName: findGoods ? findGoods.productName : "",
discount,
discountAmount: discount.discountPrice,
discountAmount: discount ? discount.discountPrice : v.discountAmount,
};
});
}
@@ -415,116 +296,6 @@ function productCouponClick(checked, item) {
goodsCouponSel.value = checked ? item : { id: "" };
}
/**
* 计算抵扣商品金额
*/
function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum) {
let hasCountNum = 0;
let discountPrice = 0;
let hasDiscountGoodsArr = [];
for (let i = 0; i < discountGoodsArr.length; i++) {
if (hasCountNum >= discountNum) {
break;
}
const goods = discountGoodsArr[i];
const shengyuNum = discountNum - hasCountNum;
const num = Math.min(goods.num, shengyuNum);
console.log("calcDiscountGoodsArrPrice");
console.log(goods);
discountPrice += returnGoodsPrice(goods, props.user) * num;
hasCountNum += num;
hasDiscountGoodsArr.push({ ...goods, num });
}
return { discountPrice, hasDiscountGoodsArr };
}
/**
*
*/
function returnCouponDiscount(coupon) {
if (coupon.type == 2) {
return returnCouponProductDiscount(coupon);
}
if (coupon.type == 6) {
return returnCouponBuyOneGiveOneDiscount(coupon);
}
}
// 返回买一送一券抵扣详情
function returnCouponBuyOneGiveOneDiscount(coupon) {
const { useFoods, useRule } = coupon;
//抵扣商品
let discountGoods = undefined;
//符合买一送一条件的商品
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoods = canUseGoods[canUseGoods.length - 1];
} else {
discountGoods = canUseGoods.slice(0, 1);
}
} else {
//符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId));
console.log(canUseGoods1);
if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else {
discountGoods = canUseGoods1.slice(0, 1);
}
}
console.log("discountGoods");
console.log(discountGoods);
const discountPrice = returnGoodsPrice(discountGoods, props.user);
const hasDiscountGoodsArr = [discountGoods];
return { discountPrice, hasDiscountGoodsArr };
}
// 返回商品单价
function returnGoodsPrice(goods, user) {
if (goods.discount_sale_amount * 1 > 0) {
return goods.discount_sale_amount;
}
if (user.isVip && goods.memberPrice * 1 <= goods.salePrice * 1 && goods.memberPrice * 1 > 0) {
return goods.memberPrice;
}
return goods.salePrice;
}
//返回商品券抵扣金额
function returnCouponProductDiscount(coupon) {
const { useFoods, discountNum, useRule } = coupon;
//抵扣商品数组
let discountGoodsArr = [];
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoodsArr = canDikouGoodsArr
.slice(canDikouGoodsArr.length - discountNum, canDikouGoodsArr.length)
.reverse();
} else {
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
}
} else {
//抵扣选中商品
const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") {
discountGoodsArr = discountSelGoodsArr
.slice(discountSelGoodsArr.length - discountNum, discountSelGoodsArr.length)
.reverse();
} else {
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
}
}
const result = calcDiscountGoodsArrPrice(discountGoodsArr, discountNum);
console.log(result);
return result;
}
//删除选中的优惠券
function delQuan(row) {
if (row.type == 2) {