This commit is contained in:
gyq 2025-09-29 09:02:47 +08:00
commit 37a61e5c79
5 changed files with 253 additions and 113 deletions

View File

@ -1,4 +1,5 @@
import { BigNumber } from "bignumber.js";
import _ from "lodash";
/**
* 返回可以抵扣优惠券的商品列表,过滤掉赠品临时商品,价格从高到低排序
@ -10,6 +11,9 @@ export function returnCanDikouGoods(arr, user) {
.filter((v) => {
return v.is_temporary != 1 && v.is_gift != 1;
})
.filter((v) => {
return v.num > 0;
})
.sort((a, b) => {
return returnGoodsPrice(b, user) - returnGoodsPrice(a, user);
});
@ -65,17 +69,53 @@ export function returnCoupType(coupon) {
}
/**
* 判券是否可用
* 返回商品券抵扣后的商品列表
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表
* @param user 用户信息
*/
export function returnCouponCanUse(canDikouGoodsArr, coupon, goodsOrderPrice, user) {
export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) {
const goodsCouponGoods = selCoupon
.filter((v) => v.type == 2)
.reduce((prve, cur) => {
prve.push(...cur.discount.hasDiscountGoodsArr);
return prve;
}, []);
const arr = _.cloneDeep(canDikouGoodsArr)
.map((v) => {
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
if (findCart) {
v.num -= findCart.num;
}
return v;
})
.filter((v) => v.num > 0);
return arr;
}
/**
* 判断优惠券是否可使用
*
* @param {Object} args - 函数参数集合
* @param {Array} args.canDikouGoodsArr - 可参与抵扣的商品列表每个元素包含商品信息productIdnum等
* @param {Object} args.coupon - 优惠券信息对象
* @param {boolean} args.coupon.use - 优惠券是否启用true为启用false为禁用
* @param {Array} args.coupon.useFoods - 优惠券适用的商品ID列表空数组表示适用全部商品
* @param {number} args.coupon.fullAmount - 优惠券使用门槛金额
* @param {number} args.coupon.type - 优惠券类型1:满减券, 2:商品券, 3:折扣券, 4:第二件半价券, 6:买一送一券
* @param {number} args.goodsOrderPrice - 订单中所有商品的总金额未筛选时的初始金额
* @param {Object} args.user - 用户信息对象用于计算商品价格如会员价等
* @param {Object} args.user - 用户信息对象用于计算商品价格如会员价等
* @param {Object} args.selCoupon - 已经选择的优惠券信息对象
* @returns {boolean} - 优惠券是否可用true可用false不可用
*/
export function returnCouponCanUse(args) {
let { canDikouGoodsArr, coupon, goodsOrderPrice, user, selCoupon } = args;
if (!coupon.use) {
return false;
}
canDikouGoodsArr = returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user);
// 计算门槛金额
let fullAmount = goodsOrderPrice;
//是否抵扣全部商品
@ -143,7 +183,7 @@ export function returnCouponCanUse(canDikouGoodsArr, coupon, goodsOrderPrice, us
}
if (coupon.type == 3) {
//折扣券
return false;
return true;
}
}
@ -176,17 +216,65 @@ export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user) {
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
* @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表
*/
export function returnCouponDiscount(canDikouGoodsArr, coupon, user) {
export function returnCouponDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice, selCoupon) {
canDikouGoodsArr = returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user);
if (coupon.type == 2) {
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user);
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice);
}
if (coupon.type == 6) {
return returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user);
return returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice);
}
if (coupon.type == 4) {
return returnSecoendDiscount(canDikouGoodsArr, coupon, user);
return returnSecoendDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice);
}
if (coupon.type == 3) {
return returnCouponZhekouDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice, selCoupon);
}
}
/**
* 折扣券抵扣金额
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
* @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表
*
*/
export function returnCouponZhekouDiscount(
canDikouGoodsArr,
coupon,
user,
goodsOrderPrice,
selCoupon
) {
const { discountRate, maxDiscountAmount } = coupon;
const goodsCouponDiscount = selCoupon
.filter((v) => v.type == 2)
.reduce((prve, cur) => {
return prve + cur.discount.discountPrice;
}, 0);
goodsOrderPrice -= goodsCouponDiscount;
// 使用bignumber处理高精度计算
// 1. 计算折扣率百分比转小数discountRate / 100
const discountRatio = new BigNumber(discountRate).dividedBy(100);
// 2. 计算优惠比例1 - 折扣率例如8折的优惠比例是 1 - 0.8 = 0.2
const discountAmountRatio = new BigNumber(1).minus(discountRatio);
// 3. 计算折扣金额:商品订单金额 × 优惠比例
let discountPrice = new BigNumber(goodsOrderPrice).times(discountAmountRatio).toNumber();
if (maxDiscountAmount != 0) {
discountPrice = discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
}
return {
discountPrice, // 折扣抵扣金额(即优惠的金额)
hasDiscountGoodsArr: [],
};
}
/**

View File

@ -269,7 +269,7 @@ export function convertBackendCouponToToolCoupon(
currentTime: Date = new Date()
): Coupon | null {
// 1. 基础校验必选字段缺失直接返回null
if (!backendCoupon.id || backendCoupon.couponType === undefined || !backendCoupon.title) {
if (!backendCoupon.id || backendCoupon.type === undefined || !backendCoupon.title) {
console.warn('优惠券必选字段缺失', backendCoupon);
return null;
}

View File

@ -170,46 +170,46 @@ const AddDialogRef = ref(null);
const tabsValue = ref(1);
const formRef = ref(null);
const form = ref({
isEnable: 1,
id: "",
shopIdList: "",
useType: "all",
isCustom: 0,
isOrder: 0,
remark: "",
rechargeDetailList: [],
isEnable: 1,
id: "",
shopIdList: "",
useType: "all",
isCustom: 0,
isOrder: 0,
remark: "",
rechargeDetailList: [],
});
const rules = ref({
rechargeDetailList: [
{
validator: (rule, value, callback) => {
if (form.value.rechargeDetailList.length == 0) {
callback(new Error("请添加面额"));
} else {
callback();
}
},
trigger: "change",
},
],
remark: [{ required: true, message: "请输入充值说明", trigger: "blur" }],
rechargeDetailList: [
{
validator: (rule, value, callback) => {
if (form.value.rechargeDetailList.length == 0) {
callback(new Error("请添加面额"));
} else {
callback();
}
},
trigger: "change",
},
],
remark: [{ required: true, message: "请输入充值说明", trigger: "blur" }],
});
function submitHandle() {
formRef.value.validate(async (valid) => {
try {
if (valid) {
await shopRecharge(form.value);
ElNotification({
title: "注意",
message: "保存成功",
type: "success",
});
}
} catch (err) {
console.log(err);
}
});
formRef.value.validate(async (valid) => {
try {
if (valid) {
await shopRecharge(form.value);
ElNotification({
title: "注意",
message: "保存成功",
type: "success",
});
}
} catch (err) {
console.log(err);
}
});
}
//
@ -218,82 +218,83 @@ const shopInfo = ref("");
//
const branchList = ref([]);
async function getBranchPageAjax() {
try {
const res = await getBranchPage();
branchList.value = res.records;
} catch (err) {
console.log(err);
}
try {
const res = await getBranchPage();
branchList.value = res.records;
} catch (err) {
console.log(err);
}
}
function addSuccess(data) {
console.log("addSuccess===", data);
if (data.index == null) {
form.value.rechargeDetailList.push(data.data);
} else {
form.value.rechargeDetailList[data.index] = data.data;
}
console.log("addSuccess===", data);
if (data.index == null) {
form.value.rechargeDetailList.push(data.data);
} else {
form.value.rechargeDetailList[data.index] = data.data;
}
}
//
const couponList = ref([]);
async function couponPageAjax() {
try {
const res = await couponPage({
page: 1,
size: 500,
});
couponList.value = res.records;
} catch (err) {
console.log(err);
}
try {
const res = await couponPage({
page: 1,
size: 500,
});
couponList.value = res.records;
} catch (err) {
console.log(err);
}
}
// id
function couponListFilter(id) {
if (id) {
let obj = couponList.value.find((item) => item.id == id);
return obj.title;
} else {
return "";
}
if (id) {
let obj = couponList.value.find((item) => item.id == id);
return obj.title;
} else {
return "";
}
}
//
function getLocalShopInfo() {
shopInfo.value = JSON.parse(localStorage.getItem("userInfo"));
shopInfo.value = JSON.parse(localStorage.getItem("userInfo"));
}
function back() {
router.back();
router.back();
}
//
async function shopRechargeGetAjax() {
try {
const res = await shopRechargeGet();
res.rechargeDetailList.map((item) => {
item.couponInfoList.map((val) => {
val.id = val.coupon.id;
});
});
form.value = res;
try {
const res = await shopRechargeGet();
res.rechargeDetailList.map((item) => {
item.couponInfoList.map((val) => {
val.id = val.coupon ? val.coupon.id : null;
});
});
form.value = res;
console.log(form.value);
} catch (err) {
console.log(err);
}
console.log(form.value);
} catch (err) {
console.log(err);
}
}
onMounted(async () => {
await couponPageAjax();
getLocalShopInfo();
getBranchPageAjax();
shopRechargeGetAjax();
await couponPageAjax();
getLocalShopInfo();
getBranchPageAjax();
shopRechargeGetAjax();
});
</script>
<style scoped lang="scss">
<<<<<<< HEAD
.gyq_container {
padding: 14px;
.gyq_content {
@ -301,31 +302,40 @@ onMounted(async () => {
background-color: #fff;
border-radius: 8px;
}
=======
.container {
padding: 14px;
.content {
padding: 14px;
background-color: #fff;
border-radius: 8px;
}
>>>>>>> b5635f70ae9ce11a8b36341d218349454a0f5e88
}
.column {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
.item {
flex: 1;
}
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
.item {
flex: 1;
}
}
.center {
display: flex;
align-items: center;
gap: 10px;
display: flex;
align-items: center;
gap: 10px;
}
.tips {
color: #666;
color: #666;
}
.footer {
display: flex;
justify-content: center;
display: flex;
justify-content: center;
}
.textarea-num {
color: #999;
display: flex;
justify-content: flex-end;
color: #999;
display: flex;
justify-content: flex-end;
}
</style>

View File

@ -77,7 +77,7 @@ const state = reactive({
show: false,
query: {
name: "",
isVip: 1,
// isVip: 1,
},
tableData: {
data: [],

View File

@ -1,5 +1,5 @@
<template>
<el-dialog width="700px" :title="title" v-model="show" top="20px" @close="reset">
<el-dialog width="900px" :title="title" v-model="show" top="20px" @close="reset">
<div class="u-p-15">
<div class="">
<el-tabs v-model="activeName" @tab-click="tabClick">
@ -20,11 +20,16 @@
{{ UTILS.returnCoupType(scope.row) }}
</template>
</el-table-column>
<el-table-column prop="discountAmount" label="抵扣">
<el-table-column prop="discountAmount" label="抵扣" align="center">
<template v-slot="scope">
<span class="color-red">{{ scope.row.discountAmount }}</span>
</template>
</el-table-column>
<el-table-column prop="discountAmount" label="最大抵扣金额" align="center">
<template v-slot="scope">
<span class="color-red">{{ scope.row.maxDiscountAmount }}</span>
</template>
</el-table-column>
<el-table-column prop="discountAmount" label="限制" width="180">
<template v-slot="scope">
<div class="u-flex">
@ -255,10 +260,22 @@ async function getcoup() {
quans.value.coupon = res
.filter((v) => v.type != 2)
.filter((coupon) => {
return UTILS.returnCouponCanUse(canDikouGoodsArr, coupon, orderPrice.value, props.user);
return UTILS.returnCouponCanUse({
canDikouGoodsArr,
coupon,
orderPrice: orderPrice.value,
user: props.user,
selCoupon: quansSelArr.value,
});
})
.map((v) => {
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, props.user);
const discount = UTILS.returnCouponDiscount(
canDikouGoodsArr,
v,
props.user,
orderPrice.value,
quansSelArr.value
);
return {
...v,
discount,
@ -268,11 +285,23 @@ async function getcoup() {
quans.value.productCoupon = res
.filter((v) => v.type == 2)
.filter((coupon) => {
return UTILS.returnCouponCanUse(canDikouGoodsArr, coupon, orderPrice.value, props.user);
return UTILS.returnCouponCanUse({
canDikouGoodsArr,
coupon,
orderPrice: orderPrice.value,
user: props.user,
selCoupon: [],
});
})
.map((v) => {
const findGoods = goodsArr.find((goods) => goods.productId == v.proId);
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, props.user);
const discount = UTILS.returnCouponDiscount(
canDikouGoodsArr,
v,
props.user,
orderPrice.value,
[]
);
return {
...v,
productImg: findGoods ? findGoods.productImg : "",
@ -320,6 +349,19 @@ defineExpose({
close,
open,
});
watch(
() => activeName.value,
() => {
getcoup();
}
);
watch(
() => quansSelArr.value,
() => {
getcoup();
}
);
</script>
<style lang="scss" scoped>