订单结算修改,增加限时折扣

This commit is contained in:
2025-10-24 16:13:40 +08:00
parent 5aa469a7b7
commit 26532150b5
36 changed files with 4989 additions and 1885 deletions

View File

@@ -0,0 +1,18 @@
// 引入 request 文件
import request from '@/common/api/request.js'
import {prveUrl} from './config.js'
export const exchange = (data) => {
return request({
url: prveUrl + '/user/redemption/exchange',
method: 'post',
data: data
})
}
export const redemption = (data) => {
return request({
url: prveUrl + '/user/redemption',
method: 'get',
data: data
})
}

View File

@@ -0,0 +1,11 @@
// 引入 request 文件
import request from '@/common/api/request.js'
import {prveUrl} from './config.js'
export const getConfig = (data) => {
return request({
url: prveUrl + '/user/limitTimeDiscount',
method: 'get',
data: data
})
}

View File

@@ -0,0 +1,11 @@
// 引入 request 文件
import request from '@/common/api/request.js'
import {prveUrl} from './config.js'
export const getGoods = (data) => {
return request({
url: prveUrl + '/user/suggest',
method: 'get',
data: data
})
}

View File

@@ -260,7 +260,7 @@ const getCouponPopupAjax = async () => {
try { try {
const shopId = uni.cache.get("shopId"); const shopId = uni.cache.get("shopId");
const res = await birthdayGiftApi.config({ shopId }); const res = await birthdayGiftApi.config({ shopId });
if (res.length) { if (res&&res.length) {
// 处理有效期格式(固定有效期规则) // 处理有效期格式(固定有效期规则)
allCoupons.value = res.map((item) => { allCoupons.value = res.map((item) => {
if (item.validType === "fixed") { if (item.validType === "fixed") {

View File

@@ -0,0 +1,56 @@
<template>
<text v-if="limitDiscount && limitDiscount.id" class="limit-price">
{{ returnPrice() }}
</text>
<text v-else>
<text v-if="shopInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1" class="memberPrice">
{{ cart.memberPrice || cart.salePrice }}
</text>
<text v-else class="salePrice">{{ cart.salePrice }}</text>
</text>
</template>
<script setup>
import BigNumber from "bignumber.js";
import * as orderUtils from "@/utils/order-utils.js";
function returnPrice(){
return orderUtils.returnPrice({
goods:props.cart,
shopInfo:props.shopInfo,
limitTimeDiscountRes:props.limitDiscount,
shopUserInfo:props.shopUserInfo,
idKey:props.idKey
})
}
const props = defineProps({
//购物车
cart: {
type: Object,
default: () => {},
},
idKey:{
type: String,
default: 'id',
},
//限时折扣
limitDiscount: {
type: Object,
default: () => {},
},
//店铺用户信息
shopUserInfo: {
type: Object,
default: () => {},
},
//店铺信息
shopInfo: {
type: Object,
default: () => {},
},
});
</script>
<style scoped lang="scss"></style>

View File

@@ -51,7 +51,6 @@ const wechatAcQrcode = ref("");
const userinfo = uni.cache.get("userInfo") || {}; const userinfo = uni.cache.get("userInfo") || {};
const codeVal = ref(userinfo.wechatAcQrcode || ""); const codeVal = ref(userinfo.wechatAcQrcode || "");
function qrcodeResult(e) { function qrcodeResult(e) {
console.log("qrcodeResult", e);
wechatAcQrcode.value = e; wechatAcQrcode.value = e;
} }
</script> </script>

View File

@@ -1,6 +1,5 @@
<template> <template>
<view> <view>
<up-popup :show="show" bgColor="transparent" mode="center" @close="close"> <up-popup :show="show" bgColor="transparent" mode="center" @close="close">
<view class="container"> <view class="container">
<view class="content"> <view class="content">
@@ -32,7 +31,7 @@
<script setup> <script setup>
import _ from "lodash"; import _ from "lodash";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { onMounted, ref } from "vue"; import { onMounted, ref, watch } from "vue";
import { string } from "../uni_modules/uview-plus/libs/function/test"; import { string } from "../uni_modules/uview-plus/libs/function/test";
const bgUrl = ref( const bgUrl = ref(
@@ -65,7 +64,7 @@ function init() {
show.value = true; show.value = true;
} }
} }
watch(() => props.wechatAcQrcode, init);
onMounted(() => { onMounted(() => {
init(); init();
}); });

View File

@@ -37,14 +37,7 @@ const userinfo = uni.cache.get("userInfo") || {};
const codeVal = ref(userinfo.wechatAcQrcode || ""); const codeVal = ref(userinfo.wechatAcQrcode || "");
console.log("codeVal", codeVal.value); console.log("codeVal", codeVal.value);
function qrcodeResult(e) { function qrcodeResult(e) {
console.log("qrcodeResult", e);
wechatAcQrcode.value = e; wechatAcQrcode.value = e;
} }
</script> </script>
<style lang="scss">
.qrcode {
position: fixed;
transform: translateX(200vw, 200vh);
}
</style>

View File

@@ -162,12 +162,10 @@ const radiovalue = defineModel({
watch( watch(
() => props.disablePayType, () => props.disablePayType,
(newval) => { (newval) => {
console.log('禁止支付方式', newval);
const canUsePayType = paymentMethodList.value.filter((item) => { const canUsePayType = paymentMethodList.value.filter((item) => {
return !newval.includes(item.name); return !newval.includes(item.name);
}); });
console.log('可用支付方式', canUsePayType);
if (canUsePayType.find((v) => v.type == radiovalue.value.type)) { if (canUsePayType.find((v) => v.type == radiovalue.value.type)) {
return; return;
} }

View File

@@ -28,7 +28,6 @@ onMounted(() => {
}); });
const emit = defineEmits(["generate"]); const emit = defineEmits(["generate"]);
function qrcodeResult(e) { function qrcodeResult(e) {
console.log(e);
emit("generate", e.img.tempFilePath); emit("generate", e.img.tempFilePath);
} }
</script> </script>
@@ -37,8 +36,10 @@ function qrcodeResult(e) {
.qrcode-box { .qrcode-box {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
left: -400px;
width: 1px; width: 1px;
height: 1px; height: 1px;
opacity: 0; opacity: 0;
z-index: -1;
} }
</style> </style>

39
distribution/index.vue Normal file
View File

@@ -0,0 +1,39 @@
<template>
<view>
<view class="top">
<up-navbar
bg-color="transparent"
title="分销中心"
@leftClick="back"
:fixed="false"
></up-navbar>
<image class="top_bg" src="/distribution/static/top_bg.png"></image>
<view class="top_content"></view>
</view>
</view>
</template>
<script setup>
function back() {
uni.navigateBack({
delta: 1,
});
}
</script>
<style scoped lang="scss">
.top{
position: relative;
.top_content{
position: absolute;
left: 28rpx;
right: 28rpx;
bottom: 0;
padding: 32rpx 28rpx;
}
}
.top_bg {
width: 100%;
height: 530rpx;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@@ -203,45 +203,55 @@
} }
}, },
{ {
"path" : "pages/user/member/czzx-shop-list", "path": "pages/user/member/czzx-shop-list",
"style" : "style": {
{ "navigationBarTitleText": "适用门店"
"navigationBarTitleText" : "适用门店"
} }
} }
], ],
"subPackages": [{ "subPackages": [{
"root": "user", "root": "user",
"pages": [{ "pages": [{
"path": "vip/vip", "path": "vip/vip",
"style": { "style": {
"navigationBarTitleText": "", "navigationBarTitleText": "",
"navigationStyle": "custom" "navigationStyle": "custom"
}
},
{
"path": "vip/buy-vip",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "score/list",
"style": {
"navigationBarTitleText": "积分门店"
}
},
{
"path": "exchange/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
} }
},
{
"path": "vip/buy-vip",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "score/list",
"style": {
"navigationBarTitleText": "积分门店"
}
},
{
"path": "exchange/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
] ]
}], },
{
"root": "distribution",
"pages": [{
"path": "index",
"style": {
"navigationBarTitleText": "分销中心",
"navigationStyle": "custom"
}
}, ]
}
],
"uniIdRouter": {}, "uniIdRouter": {},
"globalStyle": { "globalStyle": {
"navigationBarTextStyle": "black", "navigationBarTextStyle": "black",

File diff suppressed because it is too large Load Diff

View File

@@ -45,62 +45,66 @@
</view> </view>
<view class="card"> <view class="card">
<orderItemVue <!-- <orderItemVue
:useVipPrice="useVipPrice" :useVipPrice="useVipPrice"
v-if="nowCarts.length" v-if="nowCarts.length"
:nowCarts="nowCarts" :nowCarts="nowCarts"
:limitDiscount="cartStore.limitTimeDiscount"
></orderItemVue> -->
<orderItemVue
:useVipPrice="useVipPrice"
v-if="cartStore.allGoods.length"
:nowCarts="cartStore.allGoods"
:limitDiscount="cartStore.limitTimeDiscount"
></orderItemVue> ></orderItemVue>
<!-- 订单头部 --> <template v-if="false">
<view <view
class="card_item" class="card_item"
v-for="(value, key) in listinfo.detailMap" v-for="(value, key) in listinfo.detailMap"
:key="key" :key="key"
> >
<!-- <view class="head"> <view class="shop-info">
<view class="head_left"> <view class="item" v-for="item in value" :key="item.id">
<text class="placeNum" v-if="key!=0">{{key}}次下单</text> <view class="cover">
</view> <up-image
</view> --> width="76"
<!-- 订单详情 --> height="76"
<view class="shop-info"> radius="6"
<view class="item" v-for="item in value" :key="item.id"> :src="item.productImg"
<view class="cover"> v-if="item.productId != -999"
<up-image ></up-image>
width="76" <up-image
height="76" width="76"
radius="16" height="76"
:src="item.productImg" radius="6"
v-if="item.productId != -999" :src="'https://czg-qr-order.oss-cn-beijing.aliyuncs.com/confirmOrder/table.png'"
></up-image> mode="heightFix"
<up-image v-else
width="76" ></up-image>
height="76" </view>
radius="16" <view class="info">
:src="'https://czg-qr-order.oss-cn-beijing.aliyuncs.com/confirmOrder/table.png'" <text class="productName">{{ item.productName }}</text>
mode="heightFix" <text class="productSkuName" v-if="item.skuName">{{
v-else item.skuName
></up-image> }}</text>
</view> </view>
<view class="info"> <view class="price">
<text class="productName">{{ item.productName }}</text> <view class="priceAmount">
<text class="productSkuName" v-if="item.skuName">{{ <text v-if="isBwc">{{ item.price }}</text>
item.skuName <text v-else>
}}</text> {{
</view> useVipPrice
<view class="price"> ? item.memberPrice || item.price
<view class="priceAmount"> : item.price
<text v-if="isBwc">{{ item.price }}</text> }}
<text v-else> </text>
{{ </view>
useVipPrice ? item.memberPrice || item.price : item.price <view class="num">x{{ item.num }}</view>
}}
</text>
</view> </view>
<view class="num">x{{ item.num }}</view>
</view> </view>
</view> </view>
</view> </view>
</view> </template>
<view <view
class="total-wrap u-m-t-30" class="total-wrap u-m-t-30"
@@ -154,7 +158,7 @@
" "
> >
<view class="u-m-t-40 u-p-l-20 u-p-r-20"> <view class="u-m-t-40 u-p-l-20 u-p-r-20">
<view class="youhui-item" v-if="discountActivity"> <view class="youhui-item" v-if="cartStore.orderCostSummary.fullReduction.actualAmount">
<view class="u-flex align-center"> <view class="u-flex align-center">
<image <image
src="/static/icon/coup.png" src="/static/icon/coup.png"
@@ -165,13 +169,13 @@
</view> </view>
<view class="red font-12 u-flex align-center" <view class="red font-12 u-flex align-center"
>-¥{{ discountActivity.discountAmount }}</view >-¥{{ cartStore.orderCostSummary.fullReduction.actualAmount }}</view
> >
</view> </view>
<view class="youhui-item" v-if="newUserDiscount"> <view class="youhui-item" v-if="newUserDiscount">
<view class="u-flex align-center"> <view class="u-flex align-center">
<image <image
src="/static/icon/coup.png" src="/static/icon/newUserDiscount.png"
bgColor="#fff" bgColor="#fff"
style="width: 40rpx; height: 34rpx" style="width: 40rpx; height: 34rpx"
></image> ></image>
@@ -304,7 +308,10 @@
</view> </view>
</block> </block>
<block v-else> <block v-else>
<view class="cell-item column" v-if="listinfo.discountInfo"> <view
class="cell-item column"
v-if="listinfo.discountInfo && listinfo.discountInfo != '{}'"
>
<view class="label">优惠折扣</view> <view class="label">优惠折扣</view>
<view class="val column"> <view class="val column">
<view <view
@@ -387,6 +394,7 @@ import {
defineExpose, defineExpose,
toRaw, toRaw,
onMounted, onMounted,
provide,
nextTick, nextTick,
} from "vue"; } from "vue";
import { returnHasCouponCanUse } from "@/utils/coupon.js"; import { returnHasCouponCanUse } from "@/utils/coupon.js";
@@ -588,8 +596,6 @@ const tabClick = (item, index) => {
}; };
cartStore.setDinnerType(tebtypeList[is_type.value].val); cartStore.setDinnerType(tebtypeList[is_type.value].val);
// 清空 // 清空
const bwcclear = () => { const bwcclear = () => {
IntegralInputclose(); IntegralInputclose();
@@ -833,16 +839,13 @@ function calcDiscountActivity() {
const res = discountActivityRes.value; const res = discountActivityRes.value;
const user = uni.cache.get("shopUserInfo"); const user = uni.cache.get("shopUserInfo");
//不与会员同享 const usedFullReductionActivityFullAmount=cartStore.orderCostSummary.fullReduction.usedFullReductionActivityFullAmount;
if (!res.vipPriceShare && user.isVip) { console.log("usedFullReductionActivityFullAmount", usedFullReductionActivityFullAmount);
return;
}
console.log("calcDiscountActivity:originalPrice", originalPrice.value);
if (res && res.thresholds && res.thresholds.length > 0) { if (res && res.thresholds && res.thresholds.length > 0) {
const canUseThresholds = res.thresholds const canUseThresholds = res.thresholds
.filter((v) => { .filter((v) => {
return originalPrice.value >= v.fullAmount; return usedFullReductionActivityFullAmount >= v.fullAmount;
}) })
.sort((a, b) => { .sort((a, b) => {
return b.discountAmount - a.discountAmount; return b.discountAmount - a.discountAmount;
@@ -859,9 +862,7 @@ function calcDiscountActivity() {
} }
console.log("当前满减门槛", discountActivity.value); console.log("当前满减门槛", discountActivity.value);
if (discountActivity.value) {
cartStore.fullReductionActivities = [discountActivityRes.value];
}
} }
async function getDiscountActivity() { async function getDiscountActivity() {
const res = await discountActivityApi.config({ const res = await discountActivityApi.config({
@@ -871,6 +872,8 @@ async function getDiscountActivity() {
return; return;
} }
discountActivityRes.value = res; discountActivityRes.value = res;
cartStore.fullReductionActivities = [res];
calcDiscountActivity(); calcDiscountActivity();
} }
onMounted(async () => { onMounted(async () => {
@@ -1174,6 +1177,7 @@ onMounted(async () => {
display: flex; display: flex;
.cover { .cover {
position: relative;
} }
.info { .info {
@@ -1561,4 +1565,19 @@ onMounted(async () => {
.align-center { .align-center {
align-items: center; align-items: center;
} }
.limitDiscount {
background-color: #cc5617;
padding: 2rpx 10rpx;
white-space: nowrap;
text-align: center;
position: absolute;
top: 0;
left: 0;
font-weight: 400;
font-size: 24rpx;
color: #ffffff;
border-radius: 20rpx 0rpx 20rpx 0rpx;
z-index: 9;
color: #fff;
}
</style> </style>

View File

@@ -223,7 +223,7 @@
@close="ispws = false" @close="ispws = false"
/> />
<!-- 私域引流配置 --> <!-- 私域引流配置 -->
<OrderFinshModal v-model="showDrainage" ></OrderFinshModal> <OrderFinshModal v-model="showDrainage"></OrderFinshModal>
</view> </view>
</template> </template>
<script setup> <script setup>
@@ -243,8 +243,10 @@ import {
watch, watch,
onBeforeMount, onBeforeMount,
onBeforeUnmount, onBeforeUnmount,
provide,
} from "vue"; } from "vue";
provide("shopUserInfo", ref(uni.cache.get("shopUserInfo")));
provide("shopInfo", ref(uni.cache.get("shopInfo")));
import { getTableInfo } from "@/common/api/shop/index.js"; import { getTableInfo } from "@/common/api/shop/index.js";
import { import {
APIgetOrderById, APIgetOrderById,
@@ -278,8 +280,8 @@ const cartStore = useCartsStore();
//充值相关start //充值相关start
//充值和余额支付是否可用 //充值和余额支付是否可用
const isCanUseCharge = ref(false); const isCanUseCharge = ref(true);
function updateIsShow(e){ function updateIsShow(e) {
isCanUseCharge.value = e; isCanUseCharge.value = e;
} }
const rechargeItem = ref({ const rechargeItem = ref({
@@ -437,20 +439,22 @@ let historyTotalPrices = 0;
// * 获取订单详情接口 // * 获取订单详情接口
const orderorderInfo = async () => { const orderorderInfo = async () => {
console.log("listinfo.id", listinfo.id); console.log("listinfo.id", listinfo.id);
if (!listinfo.id && !options.tableCode) {
return;
}
let res = listinfo.id let res = listinfo.id
? await APIgetOrderById({ ? await APIgetOrderById({
orderId: listinfo.id, orderId: listinfo.id,
}) })
: await APIhistoryOrder({ : await APIhistoryOrder({
tableCode: options.tableCode||"", tableCode: options.tableCode || "",
}); });
orderRemarker.value = res.remark; orderRemarker.value = res.remark;
Object.assign(listinfo, res); Object.assign(listinfo, res);
if (res && res.tableCode) { if (res && res.tableCode) {
socketInitPar.table_code = res.tableCode; socketInitPar.table_code = res.tableCode;
let tableRes = await getTableInfo({ let tableRes = await getTableInfo({
tableCode: options.tableCode||"", tableCode: options.tableCode || "",
}); });
console.log(tableRes); console.log(tableRes);
listinfo.tableName = tableRes.name; listinfo.tableName = tableRes.name;
@@ -458,7 +462,7 @@ const orderorderInfo = async () => {
if (options.tableCode) { if (options.tableCode) {
socketInitPar.table_code = options.tableCode; socketInitPar.table_code = options.tableCode;
let tableRes = await getTableInfo({ let tableRes = await getTableInfo({
tableCode: options.tableCode||"", tableCode: options.tableCode || "",
}); });
console.log(tableRes); console.log(tableRes);
listinfo.tableName = tableRes.name; listinfo.tableName = tableRes.name;
@@ -634,8 +638,17 @@ const createOrder = async () => {
placeNum: listinfo.id ? listinfo.placeNum * 1 + 1 : 1, //当前订单下单次数 placeNum: listinfo.id ? listinfo.placeNum * 1 + 1 : 1, //当前订单下单次数
waitCall: "", //是否等叫 0 否 1 等叫 waitCall: "", //是否等叫 0 否 1 等叫
orderId: listinfo.id || "", orderId: listinfo.id || "",
tableCode: options.tableCode||'', tableCode: options.tableCode || "",
userId: uni.cache.get("userInfo").id || "", // userId: uni.cache.get("userInfo").id || "", //
limitRate: (cartStore.limitTimeDiscount&&cartStore.limitTimeDiscount.id)
? {
id: cartStore.limitTimeDiscount.id,
discountRate: cartStore.limitTimeDiscount.discountRate,
discountPriority: cartStore.limitTimeDiscount.discountPriority,
foodType: cartStore.limitTimeDiscount.foodType,
foods: cartStore.limitTimeDiscount.foods,
}
: null,
}); });
// 清空购物车 // 清空购物车
if (res) { if (res) {
@@ -716,7 +729,18 @@ function returnPayParams() {
: "", : "",
remark: orderRemarker.value, //用户备注 remark: orderRemarker.value, //用户备注
discountActAmount: cartStore.orderCostSummary.fullReduction.actualAmount, //满减抵扣金额 discountActAmount: cartStore.orderCostSummary.fullReduction.actualAmount, //满减抵扣金额
discountActId:cartStore.orderCostSummary.fullReduction.usedActivity?cartStore.orderCostSummary.fullReduction.usedActivity.id:null,
userId: uni.cache.get("userInfo").id || "", // userId: uni.cache.get("userInfo").id || "", //
limitRate: (cartStore.limitTimeDiscount&&cartStore.limitTimeDiscount.id)
? {
id: cartStore.limitTimeDiscount.id,
discountRate: cartStore.limitTimeDiscount.discountRate,
discountPriority: cartStore.limitTimeDiscount.discountPriority,
foodType: cartStore.limitTimeDiscount.foodType,
foods: cartStore.limitTimeDiscount.foods,
}
: null,
vipDiscountAmount: cartStore.orderCostSummary.vipDiscountAmount, //会员折扣减免金额
}; };
return { return {
isBwc: isBwc.value, isBwc: isBwc.value,
@@ -919,7 +943,6 @@ const goToPay = async (payParams) => {
orderorderInfo(); orderorderInfo();
}; };
// //
const clickPointsamount = (Pointsamount) => { const clickPointsamount = (Pointsamount) => {
listinfo.pointsDiscountAmount = Pointsamount.pointsDiscountAmount; listinfo.pointsDiscountAmount = Pointsamount.pointsDiscountAmount;
@@ -1063,9 +1086,13 @@ async function init(opt) {
if (res) { if (res) {
uni.cache.set("tableCode", res.tableCode); uni.cache.set("tableCode", res.tableCode);
uni.cache.set("tableCode", res.seatNum); uni.cache.set("tableCode", res.seatNum);
options.tableCode = res.tableCode||''; options.tableCode = res.tableCode || "";
cartStore.setSeatFeeConfig("personCount", res.seatNum); cartStore.setSeatFeeConfig("personCount", res.seatNum);
cartStore.setDinnerType(res.dineMode || "dine-in"); cartStore.setDinnerType(res.dineMode || "dine-in");
cartStore.setOldOrder(res);
if(res.limitRate){
cartStore.limitTimeDiscount=res.limitRate
}
orderRemarker.value = res.remark; orderRemarker.value = res.remark;
Object.assign(listinfo, res); Object.assign(listinfo, res);
} }
@@ -1162,7 +1189,7 @@ const disablePayType = computed(() => {
// if (cartStore.orderCostSummary.orderOriginFinalPayAmount <= 0) { // if (cartStore.orderCostSummary.orderOriginFinalPayAmount <= 0) {
// arr.add("微信支付"); // arr.add("微信支付");
// } // }
if(!isCanUseCharge.value){ if (!isCanUseCharge.value) {
arr.add("余额支付"); arr.add("余额支付");
} }

View File

@@ -328,7 +328,8 @@ function formatCoupon(){
goodsOrderPrice, goodsOrderPrice,
user, user,
selCoupon:selCoupon, selCoupon:selCoupon,
shopInfo shopInfo,
limitTimeDiscount:cartStore.limitTimeDiscount
}); });
const { canUse, reason } = canuseResult; const { canUse, reason } = canuseResult;
if (coupon.type == 2) { if (coupon.type == 2) {
@@ -353,7 +354,7 @@ function formatCoupon(){
} }
//商品券 //商品券
canUseGoodsCoupon = canUseGoodsCoupon.map((v) => { canUseGoodsCoupon = canUseGoodsCoupon.map((v) => {
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, quansSelArr.value, shopInfo); const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, quansSelArr.value, shopInfo,cartStore.limitTimeDiscount);
return { return {
...v, ...v,
discount, discount,
@@ -362,7 +363,7 @@ function formatCoupon(){
}); });
//非商品券 //非商品券
canUseDiscountCoupon = canUseDiscountCoupon.map((v) => { canUseDiscountCoupon = canUseDiscountCoupon.map((v) => {
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, quansSelArr.value, shopInfo); const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, quansSelArr.value, shopInfo,cartStore.limitTimeDiscount);
return { return {
...v, ...v,
discount, discount,
@@ -518,7 +519,7 @@ watch(
let goodsCoupon = newval.filter((v) => v.type == 2); let goodsCoupon = newval.filter((v) => v.type == 2);
let otherCoupon = newval.filter((v) => v.type != 2); let otherCoupon = newval.filter((v) => v.type != 2);
goodsCoupon = goodsCoupon.map((v) => { goodsCoupon = goodsCoupon.map((v) => {
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, [], shopInfo); const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, [], shopInfo,cartStore.limitTimeDiscount);
return { return {
...v, ...v,
discount, discount,
@@ -526,7 +527,7 @@ watch(
}; };
}); });
otherCoupon = otherCoupon.map((v) => { otherCoupon = otherCoupon.map((v) => {
const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, goodsCoupon, shopInfo); const discount = UTILS.returnCouponDiscount(canDikouGoodsArr, v, user, goodsOrderPrice, goodsCoupon, shopInfo,cartStore.limitTimeDiscount);
return { return {
...v, ...v,
discount, discount,

View File

@@ -0,0 +1,196 @@
<template>
<up-overlay :show="show">
<view class="box" v-if="SelData">
<view class="bg-fff u-p-30 item">
<view class="u-flex coverImg">
<up-image
width="204rpx"
height="228rpx"
radius="6"
:src="SelData.goods.coverImg"
></up-image>
<view class="limitDiscount" v-if="showLimitDiscount(SelData.goods)"
>限时折扣</view
>
</view>
<view class="u-flex-1 u-p-l-36">
<view class="u-flex u-col-center justify-between u-m-t-10">
<view class="u-line-1 font-16 color-333 font-bold u-p-r-16">{{
SelData.title
}}</view>
<up-icon
size="20"
name="close-circle"
color="#666"
@click="close"
></up-icon>
</view>
<view class="color-333 font-14 u-m-t-32 u-line-1">{{
SelData.guideDetail
}}</view>
<view class="u-flex justify-between u-m-t-30">
<view class="price"
>¥
<GoodsPrice
:limitDiscount="cartStore.limitTimeDiscount"
:cart="SelData.goods"
:shopUserInfo="shopUserInfo"
:shopInfo="shopInfo"
></GoodsPrice
></view>
<view class="buy" @click="buy">立即下单</view>
</view>
</view>
</view>
</view>
</up-overlay>
</template>
<script setup>
import * as orderUtils from "@/utils/order-utils.js";
import GoodsPrice from "@/components/goods-price.vue";
import * as suggestApi from "@/common/api/market/suggest.js";
import { ref, onMounted, inject, watch } from "vue";
const cartStore = inject("cartStore");
const shopUserInfo = inject("shopUserInfo");
const shopInfo = inject("shopInfo");
function showLimitDiscount(item) {
if (!cartStore.limitTimeDiscount) {
return false;
}
return orderUtils.canUseLimitTimeDiscount(
item,
cartStore.limitTimeDiscount,
shopInfo,
shopUserInfo.value,
"id"
);
}
const show = ref(false);
let timer = null;
function taskEnd() {
clearInterval(timer);
show.value = false;
}
function statTime() {
clearInterval(timer);
timer = setTimeout(() => {
const item = list.value[nowIndex.value];
if (item) {
SelData.value = item;
show.value = true;
} else {
taskEnd();
}
}, suggestTime.value * 1000);
}
const list = ref([]);
const SelData = ref(null);
const nowIndex = ref(0);
function close() {
suggestTime.value = 30;
taskEnd();
nowIndex.value += 1;
if (nowIndex.value == list.value.length) {
return;
}
statTime();
}
const suggestTime = ref(100);
const emits = defineEmits(["onBuyClick"]);
function buy() {
emits("onBuyClick", SelData.value.goods);
}
onMounted(() => {
suggestApi
.getGoods({
shopId: uni.cache.get("shopId"),
})
.then((res) => {
if (res) {
suggestTime.value = res.suggestTime;
list.value = (res.list || [])
.map((v) => {
return {
...v,
goods: cartStore.returnGoods(v.foods),
};
})
.filter((v) => v.goods);
console.log('list.value ', list.value )
startWatch();
}
});
});
function startWatch() {
watch(
() => cartStore.isEmpty,
(newval) => {
if (newval && list.value.length) {
statTime();
} else {
clearInterval(timer);
nowIndex.value = 0;
show.value = false;
}
},
{
immediate: true,
}
);
}
</script>
<style scoped lang="scss">
.box {
position: fixed;
z-index: 100;
left: 30rpx;
right: 30rpx;
bottom: calc(var(--safe-area-inset-bottom) + 0px);
.item {
padding: 32rpx 28rpx;
border-radius: 16rpx;
background: #fff;
box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.05);
display: flex;
}
.price {
font-size: 40rpx;
color: #333;
}
.buy {
padding: 4rpx 28rpx;
border-radius: 36rpx;
background: #e8ad7b;
color: #ffffff;
font-size: 28rpx;
line-height: 48rpx;
}
}
.coverImg{
position: relative;
}
.limitDiscount {
background-color: #cc5617;
padding: 2rpx 10rpx;
white-space: nowrap;
text-align: center;
position: absolute;
top: 0;
left: 0;
font-weight: 400;
font-size: 24rpx;
color: #ffffff;
border-radius: 20rpx 0rpx 20rpx 0rpx;
z-index: 9;
color: #fff;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -58,6 +58,9 @@
v-for="(item, index) in shopProductList.hots" v-for="(item, index) in shopProductList.hots"
:key="index" :key="index"
> >
<view class="limitDiscount" v-if="showLimitDiscount(item)"
>限时折扣</view
>
<image <image
class="panelfiveitemimage" class="panelfiveitemimage"
:src="item.coverImg" :src="item.coverImg"
@@ -151,6 +154,10 @@
<text class="unit" v-if="item.unitName" <text class="unit" v-if="item.unitName"
>/{{ item.unitName }}</text >/{{ item.unitName }}</text
> >
<text class="old-price"
>¥{{ item.salePrice }}</text
>
</view> </view>
</view> </view>
<view class="panelfiveitemNum"> <view class="panelfiveitemNum">
@@ -189,16 +196,21 @@
>¥</text >¥</text
> >
<!-- 会员价与价格 --> <!-- 会员价与价格 -->
<text class="price"> <view class="price">
{{ <GoodsPrice
shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1 :limitDiscount="limitTimeDiscountRes"
? item.memberPrice || item.salePrice :cart="item"
: item.salePrice :shopUserInfo="shopUserInfo"
}} :shopInfo="shopInfo"
</text> ></GoodsPrice>
</view>
<text class="unit" v-if="item.unitName" <text class="unit" v-if="item.unitName"
>/{{ item.unitName }}</text >/{{ item.unitName }}</text
> >
<text class="old-price"
>¥{{ item.salePrice }}</text
>
<!-- <text v-if="item.suitNum>1 && item.type!= 'sku'" <!-- <text v-if="item.suitNum>1 && item.type!= 'sku'"
style="font-size: 16rpx;">「{{item.suitNum}}{{item.unitName}}起点」</text> --> style="font-size: 16rpx;">「{{item.suitNum}}{{item.unitName}}起点」</text> -->
</view> </view>
@@ -357,12 +369,16 @@
mode="" mode=""
></image> ></image>
</view> </view>
<view <view
v-if="index == '0'" v-if="index == '0'"
class="topSort" class="topSort"
:class="'c' + (index1 + 1)" :class="'c' + (index1 + 1)"
>TOP{{ index1 + 1 }}</view >TOP{{ index1 + 1 }}</view
> >
<view class="limitDiscount" v-else-if="showLimitDiscount(item1)"
>限时折扣</view
>
<view class="goods_right" style="overflow: hidden"> <view class="goods_right" style="overflow: hidden">
<view class="name">{{ item1.name }}</view> <view class="name">{{ item1.name }}</view>
<!-- <view class="lookBack" v-if="index=='0'">本店销量第{{index1+1}}名</view>--> <!-- <view class="lookBack" v-if="index=='0'">本店销量第{{index1+1}}名</view>-->
@@ -417,16 +433,21 @@
<view v-else class="flex-between" style="flex-wrap: inherit"> <view v-else class="flex-between" style="flex-wrap: inherit">
<view class="money"> <view class="money">
<view>¥</view> <view>¥</view>
<text class="money_num"> <view class="money_num">
{{ <GoodsPrice
shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1 :limitDiscount="limitTimeDiscountRes"
? item1.memberPrice || item1.salePrice :cart="item1"
: item1.salePrice :shopUserInfo="shopUserInfo"
}} :shopInfo="shopInfo"
</text> ></GoodsPrice>
</view>
<text class="money_num" v-if="item1.unitName" <text class="money_num" v-if="item1.unitName"
>/{{ item1.unitName }}</text >/{{ item1.unitName }}</text
> >
<text class="old-price"
>¥{{ item1.salePrice }}</text
>
<!-- <text v-if="item1.suitNum>1 && item1.type!= 'sku'" <!-- <text v-if="item1.suitNum>1 && item1.type!= 'sku'"
style="font-size: 14rpx;"> style="font-size: 14rpx;">
「{{item1.suitNum}}{{item1.unitName}}起点」 「{{item1.suitNum}}{{item1.unitName}}起点」
@@ -513,6 +534,7 @@
:cartLists_count="cartLists_count" :cartLists_count="cartLists_count"
:cartList="matchedProducts" :cartList="matchedProducts"
:showCart="showCart" :showCart="showCart"
:limitDiscount="limitTimeDiscountRes"
@customevent="websocketsendMessage" @customevent="websocketsendMessage"
@close="showCart = !showCart" @close="showCart = !showCart"
:orderinfo="orderinfo" :orderinfo="orderinfo"
@@ -772,11 +794,23 @@
</view> </view>
<Loading :isLoading="!useSocket.isConnected" /> <Loading :isLoading="!useSocket.isConnected" />
<ModalList></ModalList> <ModalList></ModalList>
<recommendGoodsModal
v-if="isDataLoaded"
@onBuyClick="onBuyClick"
></recommendGoodsModal>
</view> </view>
</template> </template>
<script setup> <script setup>
//价格计算辅助函数
import * as orderUtils from "@/utils/order-utils.js";
import BigNumber from "bignumber.js";
import GoodsPrice from "@/components/goods-price.vue";
import * as limitTimeDiscountapi from "@/common/api/market/limitTimeDiscount.js";
import ModalList from "@/components/modal-list.vue"; import ModalList from "@/components/modal-list.vue";
import recommendGoodsModal from "./components/recommend-goods-modal.vue";
import { import {
ref, ref,
reactive, reactive,
@@ -784,6 +818,7 @@ import {
watchEffect, watchEffect,
getCurrentInstance, getCurrentInstance,
computed, computed,
provide,
watch, watch,
} from "vue"; } from "vue";
@@ -805,6 +840,49 @@ import dayjs from "dayjs";
import isBetween from "dayjs/plugin/isBetween"; import isBetween from "dayjs/plugin/isBetween";
dayjs.extend(isBetween); dayjs.extend(isBetween);
//点单智能推荐
function onBuyClick(item) {
console.log("onBuyClick", item);
console.log("shopProductList", shopProductList);
let index = -1;
let index1 = -1;
if (!item.isHot) {
if (
item.type == "sku" ||
(item.type == "package" && item.groupType == "1")
) {
for (let i in shopProductList.productInfo) {
const cate = shopProductList.productInfo[i];
const goodsList = cate.productList;
const index1 = goodsList.findIndex((goods) => goods.id == item.id);
if (index1 > -1) {
index = i;
clickspecifications(item, index, index1);
break;
}
}
} else {
uni.$u.throttle(() => singleclick(item, "+"), 500);
}
} else {
if (
item.type == "sku" ||
(item.type == "package" && item.groupType == "1")
) {
for (let i in shopProductList.hots) {
const goods = shopProductList.hots[i];
if (goods.id==item.id) {
index = i;
clickspecifications(item, index, index);
break;
}
}
} else {
uni.$u.throttle(() => singleclick(item, "+"), 500);
}
}
}
// 获取全局属性 // 获取全局属性
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
@@ -852,8 +930,8 @@ store.updateNavbarConfig({
isTransparent: false, isTransparent: false,
hasPlaceholder: false, //是否要占位符 hasPlaceholder: false, //是否要占位符
}); });
const shopInfo = reactive({});
const shopInfo = uni.cache.get("shopInfo"); Object.assign(shopInfo, uni.cache.get("shopInfo"));
const shopTable = uni.cache.get("shopTable"); const shopTable = uni.cache.get("shopTable");
const distance = uni.cache.get("distance"); //距离 const distance = uni.cache.get("distance"); //距离
@@ -1082,6 +1160,8 @@ const selectSpec = async (specType, option) => {
} }
}; };
const shopUserInfo = ref(uni.cache.get("shopUserInfo"));
// 监听 specifications 的变化 // 监听 specifications 的变化
watch( watch(
() => specifications.item.groupSnap, () => specifications.item.groupSnap,
@@ -1567,8 +1647,21 @@ const updateProductQuantities = () => {
//websocket产值 //websocket产值
const websocketsendMessage = (data) => { const websocketsendMessage = (data) => {
console.log(data); const sendData = { ...data, is_time_discount: 0 };
uni.$u.debounce(useSocket.sendMessage(data), 500); if (cartStore.limitTimeDiscount && cartStore.limitTimeDiscount.id && data.discount_sale_amount*1<=0) {
if (
orderUtils.canUseLimitTimeDiscount(
data,
cartStore.limitTimeDiscount,
shopInfo,
shopUserInfo.value,
"product_id"
)
) {
sendData.is_time_discount = 1;
}
}
uni.$u.debounce(useSocket.sendMessage(sendData), 500);
}; };
// 用于记录已经处理过的消息的 msg_id // 用于记录已经处理过的消息的 msg_id
@@ -1627,6 +1720,7 @@ async function onMessage(Message) {
// 初始化 // 初始化
if (Message.operate_type == "init") { if (Message.operate_type == "init") {
cartStore.carts = Message.data; cartStore.carts = Message.data;
cartStore.limitTimeDiscount = Message.time_dis_info;
uni.hideLoading(); uni.hideLoading();
isLoading.value = false; isLoading.value = false;
// 初始化商品数量 // 初始化商品数量
@@ -1697,6 +1791,10 @@ async function onMessage(Message) {
}, },
}); });
} }
if (Message.operate_type == "time_discount_save") {
console.log("time_discount_save", Message.data);
cartStore.limitTimeDiscount = Message.data;
}
//除去p 每次返回都回执消息 //除去p 每次返回都回执消息
await websocketsendMessage({ await websocketsendMessage({
@@ -1835,35 +1933,6 @@ function combineOrderInfoDetailMap(orderinfo) {
// 计算购物车商品费用 // 计算购物车商品费用
const totalPrices = computed(() => { const totalPrices = computed(() => {
// 待支付订单
let cartone = 0;
if (orderinfo.value) {
let combinedArray = [];
for (const key in orderinfo.value.detailMap) {
if (orderinfo.value.detailMap.hasOwnProperty(key)) {
let subArray = orderinfo.value.detailMap[key];
combinedArray = [...combinedArray, ...subArray];
}
}
// 购物车总数价格
cartone = combinedArray.reduce((total, item) => {
// 是否启用会员价 0否1是
if (shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1) {
// memberPrice会员价
return (
total +
parseFloat(item.memberPrice || item.price) *
parseFloat(item.num - item.returnNum)
);
} else {
// salePrice销售价
return (
total +
parseFloat(item.price || 0) * parseFloat(item.num - item.returnNum)
);
}
}, 0);
}
// 购物车总数价格 // 购物车总数价格
let cart = 0; let cart = 0;
if (matchedProducts.value.length > 0) { if (matchedProducts.value.length > 0) {
@@ -1877,6 +1946,18 @@ const totalPrices = computed(() => {
} }
}); });
} }
if (limitTimeDiscountRes.value && limitTimeDiscountRes.value.id) {
//限时折扣
const price = orderUtils.returnPrice({
goods: item,
shopInfo,
limitTimeDiscountRes: limitTimeDiscountRes.value,
shopUserInfo: shopUserInfo.value,
idKey: "id",
});
console.log("限时折扣", item, price);
return total + parseFloat(price) * parseFloat(item.cartNumber);
}
// 是否启用会员价 0否1是 // 是否启用会员价 0否1是
if (shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1) { if (shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1) {
// memberPrice会员价 // memberPrice会员价
@@ -2059,6 +2140,7 @@ const productqueryProduct = async () => {
); );
cartStore.setGoodsMap(i.id, i); cartStore.setGoodsMap(i.id, i);
}); });
cartStore.goodsIsloading = true; cartStore.goodsIsloading = true;
scrollTopSize.value = 0; scrollTopSize.value = 0;
topArr.value = []; topArr.value = [];
@@ -2081,11 +2163,49 @@ const productqueryProduct = async () => {
} }
}; };
provide("cartStore", cartStore);
provide("shopUserInfo", shopUserInfo);
provide("shopInfo", shopInfo);
onLoad(async (e) => { onLoad(async (e) => {
await proxy.$onLaunched; await proxy.$onLaunched;
}); });
const limitTimeDiscountRes = ref(null);
function showLimitDiscount(item) {
if (!limitTimeDiscountRes.value) {
return false;
}
return orderUtils.canUseLimitTimeDiscount(
item,
limitTimeDiscountRes.value,
shopInfo,
shopUserInfo.value,
"id"
);
}
onShow(async () => { onShow(async () => {
limitTimeDiscountapi
.getConfig({
shopId: uni.cache.get("shopId"),
})
.then((res) => {
console.log("limitTimeDiscountapi", res);
if (res && typeof res == "object") {
limitTimeDiscountRes.value = res;
cartStore.limitTimeDiscount = res;
websocketsendMessage({
type: "shopping",
operate_type: "time_discount_save",
table_code: uni.cache.get("tableCode"),
shop_id: uni.cache.get("shopId"),
operate_type: "time_discount_save",
data: res,
});
}
});
// 监听页面显示和隐藏 // 监听页面显示和隐藏
useSocket.setOnMessage(onMessage); useSocket.setOnMessage(onMessage);
useSocket.onShowconnect(); useSocket.onShowconnect();
@@ -2304,6 +2424,8 @@ function toHistory() {
.panelfiveitemsex { .panelfiveitemsex {
.panelfiveitemsex_oen { .panelfiveitemsex_oen {
display: flex;
align-items: baseline;
.tips { .tips {
font-family: Source Han Sans CN, Source Han Sans CN; font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400; font-weight: 400;
@@ -2412,7 +2534,8 @@ function toHistory() {
position: relative; position: relative;
.left { .left {
width: 200rpx; // width: 200rpx;
width: 156rpx;
background-color: #f6f6f6; background-color: #f6f6f6;
line-height: normal; line-height: normal;
box-sizing: border-box; box-sizing: border-box;
@@ -2554,6 +2677,7 @@ function toHistory() {
width: 200rpx; width: 200rpx;
height: 100%; height: 100%;
position: absolute; position: absolute;
border-radius: 18rpx;
top: 0; top: 0;
left: 0; left: 0;
z-index: 9; z-index: 9;
@@ -2578,6 +2702,7 @@ function toHistory() {
font-size: 24rpx; font-size: 24rpx;
color: #ffffff; color: #ffffff;
border-radius: 20rpx 0rpx 20rpx 0rpx; border-radius: 20rpx 0rpx 20rpx 0rpx;
z-index: 10;
} }
.topSort.c1 { .topSort.c1 {
@@ -2632,10 +2757,11 @@ function toHistory() {
.money { .money {
font-weight: bold; font-weight: bold;
font-size: 24rpx; font-size: 20rpx;
color: #333; color: #333;
display: flex; display: flex;
align-items: flex-end; align-items: baseline;
white-space: nowrap;
.money_num { .money_num {
font-size: 28rpx; font-size: 28rpx;
@@ -3073,4 +3199,25 @@ function toHistory() {
height: 36rpx; height: 36rpx;
} }
} }
.old-price {
color: #999;
font-size: 24rpx;
text-decoration: line-through;
margin-left: 8rpx;
}
.limitDiscount {
background-color: #cc5617;
padding: 2rpx 10rpx;
white-space: nowrap;
text-align: center;
position: absolute;
top: 0;
left: 0;
font-weight: 400;
font-size: 24rpx;
color: #ffffff;
border-radius: 20rpx 0rpx 20rpx 0rpx;
z-index: 9;
color: #fff;
}
</style> </style>

View File

@@ -1,6 +1,9 @@
<template> <template>
<view class="container"> <view class="container">
<view class="header-wrap"> <view class="header-wrap">
<view class="u-flex" style="justify-content: flex-end;">
<view @click="toExchangeCode" class="color-333 font-12 u-m-b-26 font-700">优惠券兑换码</view>
</view>
<view class="search-wrap"> <view class="search-wrap">
<view class="input-wrap"> <view class="input-wrap">
<view class="icon left"> <view class="icon left">
@@ -137,7 +140,11 @@ onReachBottom(() => {
getCouponList(); getCouponList();
} }
}); });
function toExchangeCode(){
uni.navigateTo({
url: '/user/exchange/index'
})
}
const showDetail = ref(false); const showDetail = ref(false);
const selectListItem = ref(''); const selectListItem = ref('');
const selectListItemDetails = ref([]); const selectListItemDetails = ref([]);

View File

@@ -63,7 +63,9 @@
<text v-if="item.bizCode == 'freeIn'"> <text v-if="item.bizCode == 'freeIn'">
霸王餐充值 霸王餐充值
</text> </text>
<text v-if="item.bizCode == 'rechargeRedemption'">
兑换券充值
</text>
</view> </view>
<view v-else> <view v-else>
{{item.content}} {{item.content}}

View File

@@ -25,6 +25,7 @@
<text class="n t">{{ shopUserInfo.amount || 0 }}</text> <text class="n t">{{ shopUserInfo.amount || 0 }}</text>
</view> </view>
<view class="right"> <view class="right">
<text class="t" @click="toduihuan">兑换码</text>
<text class="t" @click="toDetail">明细</text> <text class="t" @click="toDetail">明细</text>
<text class="t" @click="toPwd">密码设置</text> <text class="t" @click="toPwd">密码设置</text>
</view> </view>
@@ -161,7 +162,7 @@ import * as rechargeApi from "@/common/api/market/recharge.js";
import { recharge } from "@/common/api/order/index.js"; import { recharge } from "@/common/api/order/index.js";
import { joinMember } from "@/common/api/order/index.js"; import { joinMember } from "@/common/api/order/index.js";
import { ref, onMounted, computed, reactive, watch } from "vue"; import { ref, onMounted, computed, reactive, watch } from "vue";
import { onLoad } from "@dcloudio/uni-app"; import { onLoad, onShow } from "@dcloudio/uni-app";
import { pay } from "@/utils/pay.js"; import { pay } from "@/utils/pay.js";
function toShopList() { function toShopList() {
@@ -170,6 +171,12 @@ function toShopList() {
}); });
} }
function toduihuan() {
uni.navigateTo({
url: "/user/exchange/index",
});
}
function couponNum(list) { function couponNum(list) {
return list.reduce((prve, cur) => { return list.reduce((prve, cur) => {
return prve + cur.num; return prve + cur.num;
@@ -285,7 +292,7 @@ const charge_money = computed(() => {
}); });
onLoad((opt) => { onLoad((opt) => {
Object.assign(option, opt); Object.assign(option, opt);
init(); // init();
}); });
watch( watch(
@@ -296,6 +303,9 @@ watch(
} }
} }
); );
onShow(() => {
init();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@@ -367,7 +377,7 @@ watch(
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
position: relative; position: relative;
padding-top: 40upx; padding-top: 20rpx;
.left { .left {
display: flex; display: flex;

View File

@@ -224,7 +224,7 @@
<!-- <l-qrcode :value="wechatAcQrcode" @complete="e=>qrcodeResult(e)"/> --> <!-- <l-qrcode :value="wechatAcQrcode" @complete="e=>qrcodeResult(e)"/> -->
<view <view
class="qrcode u-flex u-col-center justify-between" class="qrcode u-flex u-col-center justify-between"
v-if="qrcode" v-if="showQrcode"
> >
<view> <view>
<view class="color-000 font-14 font-bold">扫码关注公众号</view> <view class="color-000 font-14 font-bold">扫码关注公众号</view>
@@ -259,10 +259,8 @@ import * as rechargeApi from "@/common/api/market/recharge.js";
import { pointsShopList } from "@/common/api/account/points.js"; import { pointsShopList } from "@/common/api/account/points.js";
const qrcode = ref("");
function qrcodeResult(res) { function qrcodeResult(res) {
console.log("qrcodeResult", res);
qrcode.value = res qrcode.value = res
} }
@@ -470,7 +468,14 @@ onShow(() => {
getData(); getData();
}); });
const qrcode = ref("");
const showQrcode = computed(() => {
const followIndex = uni.cache.get("followIndex");
if ( followIndex == "mine" && qrcode.value) {
return true;
}
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

View File

@@ -157,6 +157,8 @@ export const useCartsStore = defineStore("cart", () => {
const isFreeDine = ref(false); const isFreeDine = ref(false);
// 商家霸王餐配置 // 商家霸王餐配置
const freeDineConfig = ref(null); const freeDineConfig = ref(null);
//限时折扣
const limitTimeDiscount = ref(null);
// 订单额外配置 // 订单额外配置
const orderExtraConfig = computed(() => ({ const orderExtraConfig = computed(() => ({
// 引用扩展后的商家减免配置 // 引用扩展后的商家减免配置
@@ -173,6 +175,7 @@ export const useCartsStore = defineStore("cart", () => {
currentDinnerType: dinnerType.value, currentDinnerType: dinnerType.value,
isFreeDine: isFreeDine.value, isFreeDine: isFreeDine.value,
freeDineConfig: freeDineConfig.value, freeDineConfig: freeDineConfig.value,
limitTimeDiscount: limitTimeDiscount.value,
})); }));
// 营销活动列表 // 营销活动列表
@@ -191,6 +194,7 @@ export const useCartsStore = defineStore("cart", () => {
// 订单费用汇总 // 订单费用汇总
const orderCostSummary = computed(() => { const orderCostSummary = computed(() => {
allGoods.value = getAllGoodsList(); allGoods.value = getAllGoodsList();
console.log("allGoods.value", allGoods.value);
console.log("orderExtraConfig.value", orderExtraConfig.value); console.log("orderExtraConfig.value", orderExtraConfig.value);
const costSummary = OrderPriceCalculator.calculateOrderCostSummary( const costSummary = OrderPriceCalculator.calculateOrderCostSummary(
allGoods.value, allGoods.value,
@@ -209,6 +213,11 @@ export const useCartsStore = defineStore("cart", () => {
//商品数据Map //商品数据Map
const goodsMap = reactive({}); const goodsMap = reactive({});
function returnGoods(product_id){
return goodsMap[product_id*1]
}
//获取商品数据 //获取商品数据
async function goodsInit() { async function goodsInit() {
goodsIsloading.value = true; goodsIsloading.value = true;
@@ -232,10 +241,6 @@ export const useCartsStore = defineStore("cart", () => {
goodsMap[product_id] = data; goodsMap[product_id] = data;
} }
//websocket回执
const websocketsendMessage = (data) => {
uni.$u.debounce(sendMessage(data), 500);
};
const isLoading = ref(true); const isLoading = ref(true);
@@ -348,6 +353,11 @@ export const useCartsStore = defineStore("cart", () => {
icon: "none", icon: "none",
}); });
} }
//获取限时折扣
// if(Message.operate_type == "time_discount_get"){
// console.log("time_discount_get", Message.data);
// limitTimeDiscount.value = Message.data;
// }
if (Message.type == "no_suit_num") { if (Message.type == "no_suit_num") {
uni.showModal({ uni.showModal({
@@ -394,6 +404,9 @@ export const useCartsStore = defineStore("cart", () => {
//是否使用会员价 //是否使用会员价
const useVipPrice = computed(() => { const useVipPrice = computed(() => {
if (!orderVIP.value) {
return false;
}
const isUse = const isUse =
orderVIP.value.isVip && shopInfo.value.isMemberPrice ? true : false; orderVIP.value.isVip && shopInfo.value.isMemberPrice ? true : false;
return isUse; return isUse;
@@ -606,6 +619,10 @@ export const useCartsStore = defineStore("cart", () => {
userPoints.value = 0; userPoints.value = 0;
fullReductionActivities.value = []; fullReductionActivities.value = [];
isFreeDine.value = false; isFreeDine.value = false;
oldOrder.value = {
detailMap: {},
originAmount: 0,
};
} }
return { return {
@@ -616,7 +633,7 @@ export const useCartsStore = defineStore("cart", () => {
carts, carts,
isEmpty, isEmpty,
setGoodsMap, setGoodsMap,
goodsMap, goodsMap:goodsMap,
goodsIsloading, goodsIsloading,
goodsInit, goodsInit,
onMessage, onMessage,
@@ -631,6 +648,8 @@ export const useCartsStore = defineStore("cart", () => {
setUserPoints, setUserPoints,
setPointDeductionRule, setPointDeductionRule,
setOldOrder, setOldOrder,
//返回商品信息
returnGoods,
//优惠券列表 //优惠券列表
backendCoupons, backendCoupons,
allGoods, allGoods,
@@ -652,5 +671,7 @@ export const useCartsStore = defineStore("cart", () => {
isFreeDine, //是否使用霸王餐 isFreeDine, //是否使用霸王餐
// 商家霸王餐配置 // 商家霸王餐配置
freeDineConfig, freeDineConfig,
//限时折扣
limitTimeDiscount,
}; };
}); });

View File

@@ -228,8 +228,10 @@ export const Memberpay = defineStore('memberpay', {
// 生成订单 // 生成订单
actionscreateOrder(data) { actionscreateOrder(data) {
console.log('actionscreateOrder:生成订单',data);
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
let res = await APIcreateOrder({ let res = await APIcreateOrder({
...data,
orderId: data.orderId, //多次下单时使用 orderId: data.orderId, //多次下单时使用
shopId: uni.cache.get('shopId'), //店铺Id shopId: uni.cache.get('shopId'), //店铺Id
userId: uni.cache.get('userInfo').id || '', // userId: uni.cache.get('userInfo').id || '', //

View File

@@ -1,6 +1,7 @@
<template> <template>
<view @longtap.stop="longtap"> <view @longtap.stop="longtap">
<canvas <canvas
class="canvas"
:width="info.destWidth" :width="info.destWidth"
:height="info.destHeight" :height="info.destHeight"
:canvas-id="item.id" :canvas-id="item.id"
@@ -174,3 +175,8 @@
} }
</script> </script>
<!-- #endif --> <!-- #endif -->
<style scoped>
.canvas{
opacity: 0;
}
</style>

View File

@@ -11,21 +11,21 @@
<view class="box"> <view class="box">
<view class="u-flex top justify-between u-p-32"> <view class="u-flex top justify-between u-p-32">
<text class="title">确认信息</text> <text class="title">确认信息</text>
<up-icon name="close"></up-icon> <up-icon name="close" @click="close"></up-icon>
</view> </view>
<view class="info"> <view class="info">
<view class="color-333">兑换码包含内容如下:</view> <view class="color-333">兑换码包含内容如下:</view>
<view class="u-m-t-32 u-flex u-col-center"> <view class="u-m-t-32 u-flex u-col-center">
<view class="color-333 font-bold small-title">店铺</view> <view class="color-333 font-bold small-title">店铺</view>
<text class="color-666 u-m-l-38">店铺名称</text> <text class="color-666 u-m-l-38">{{data.shopName}}</text>
</view> </view>
<view class="u-m-t-32 u-flex u-col-center"> <view class="u-m-t-32 u-flex u-col-center">
<view class="color-333 font-bold small-title">名称</view> <view class="color-333 font-bold small-title">名称</view>
<text class="color-666 u-m-l-38">10张券兑换码</text> <text class="color-666 u-m-l-38">{{data.name}}</text>
</view> </view>
<view class="u-m-t-32 u-flex u-col-center"> <view class="u-m-t-32 u-flex u-col-center" v-if="data.couponInfoList&&data.couponInfoList.length">
<view class="color-333 font-bold small-title">优惠券</view> <view class="color-333 font-bold small-title">优惠券</view>
<text class="color-666 u-m-l-38">优惠券名称*2优惠券名称*1</text> <text class="color-666 u-m-l-38">{{data.couponInfoList.map(item=>item.title+'*'+item.num).join('、')}}</text>
</view> </view>
<view class="u-m-t-32 u-flex u-col-center" style="gap: 54rpx"> <view class="u-m-t-32 u-flex u-col-center" style="gap: 54rpx">
<view class="cancel" @click="close">取消</view> <view class="cancel" @click="close">取消</view>
@@ -39,6 +39,13 @@
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
const props=defineProps({
//兑换码信息
data:{
type:Object,
default:()=>({}),
},
})
const show = defineModel({ const show = defineModel({
type: Boolean, type: Boolean,
default: false, default: false,

View File

@@ -14,46 +14,92 @@
<view class="input-box u-flex"> <view class="input-box u-flex">
<image class="icon" src="/user/static/duihuan.png"></image> <image class="icon" src="/user/static/duihuan.png"></image>
<view class="u-flex-1"> <view class="u-flex-1">
<input placeholder="请输入兑换码" /> <input placeholder="请输入兑换码" v-model="code" />
</view> </view>
</view> </view>
</view> </view>
<view class="u-flex justify-center u-m-t-24"> <view class="u-flex justify-center u-m-t-24">
<button class="duihuan">确认兑换</button> <button class="duihuan" @click="confirmExchange">确认兑换</button>
</view> </view>
</view> </view>
<view class="desc"> <view class="desc">
<view>兑换说明:</view> <view>兑换说明:</view>
<view> <view>
兑换说明 1请直接输入您获得的兑换码点击立即兑换即可 1请直接输入您获得的兑换码点击立即兑换即可
<br />
2兑换码为一次性兑换完成之后即失效 2兑换码为一次性兑换完成之后即失效
<br />
3兑换获得的奖励将直接发送至您的账号可直接前往余额或优惠券查看 3兑换获得的奖励将直接发送至您的账号可直接前往余额或优惠券查看
<br />
4兑换码为赠品不可转赠不退不换 4兑换码为赠品不可转赠不退不换
<br />
5兑换码需在有效期内完成兑换过期即作废 5兑换码需在有效期内完成兑换过期即作废
</view> </view>
</view> </view>
</view> </view>
<confirmModal v-model="modal.confirm.show"></confirmModal> <confirmModal v-model="modal.confirm.show" :data="modal.confirm.data" @confirm="exchange"></confirmModal>
<resultModal v-model="modal.result.show" :title="modal.result.title"></resultModal> <resultModal
v-model="modal.result.show"
:title="modal.result.title"
></resultModal>
</view> </view>
</template> </template>
<script setup> <script setup>
import { result } from "lodash";
import confirmModal from "./components/confirm.vue"; import confirmModal from "./components/confirm.vue";
import resultModal from "./components/result.vue"; import resultModal from "./components/result.vue";
import { reactive } from "vue"; import * as exchangeApi from "@/common/api/market/exchange.js";
import { reactive, ref } from "vue";
const modal = reactive({ const modal = reactive({
confirm: { confirm: {
show: false, show: false,
}, },
result:{ result: {
show:true, show: false,
title:'该兑换码无效,请输入有效兑换码' title: "该兑换码无效,请输入有效兑换码",
} },
}); });
const code = ref("");
function confirmExchange() {
if (code.value == "") {
uni.showToast({
title: "请输入兑换码",
icon: "none",
});
return;
}
exchangeApi.redemption({
code: code.value,
}).then((res) => {
if (res) {
modal.confirm.show = true;
modal.confirm.data = res;
}
})
}
function exchange() {
exchangeApi
.exchange({
code: code.value,
})
.then((res) => {
if (res) {
modal.result.title = "兑换成功!奖励已发放至您的账户";
modal.result.show = true;
code.value = "";
}
})
.catch((err) => {
console.log("err,", err);
modal.result.title = err.message || "该兑换码无效,请输入有效兑换码";
modal.result.show = true;
});
}
function back() { function back() {
uni.navigateBack(); uni.navigateBack();
} }
@@ -115,7 +161,6 @@ function back() {
font-weight: 700; font-weight: 700;
} }
.desc { .desc {
width: 662rpx;
color: #666666; color: #666666;
font-size: 24rpx; font-size: 24rpx;
font-weight: 400; font-weight: 400;

View File

@@ -270,10 +270,10 @@
return v; return v;
}); });
tiaojian_menus = tiaojian_menus.filter(v => { tiaojian_menus = tiaojian_menus.filter(v => {
if (!state.isCostRewardPoints && v.name == '消费送积分') { if (!res.memberLevel.isCostRewardPoints && v.name == '消费送积分') {
return false return false
} }
if (!state.isCycleReward && v.name == '周期福利') { if (!res.memberLevel.isCycleReward && v.name == '周期福利') {
return false return false
} }
if (!res.memberLevel.cycleRewardCouponList || res.memberLevel.cycleRewardCouponList.length <= if (!res.memberLevel.cycleRewardCouponList || res.memberLevel.cycleRewardCouponList.length <=

1507
utils/goods copy.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,55 @@
import { import { BigNumber } from "bignumber.js";
BigNumber
} from "bignumber.js";
import _ from "lodash"; import _ from "lodash";
/** /**
* 返回商品单价 * 返回商品单价
* @param goods 商品 * @param goods 商品
* @param user 用户信息 * @param user 用户信息
* @param {Object} shopInfo * @param {Object} shopInfo 店铺信息
* @param {boolean} limitTimeDiscount - 限时折扣
*/ */
export function returnGoodsPrice(goods, user, shopInfo) { export function returnGoodsPrice(goods, user, shopInfo, limitTimeDiscount) {
if (goods.discount_sale_amount * 1 > 0) { if (!goods) {
return goods.discount_sale_amount; return 0;
} }
if(shopInfo&&!shopInfo.isMemberPrice){ // 商家改价
return goods.salePrice; 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; // 限时折扣
} if (limitTimeDiscount && limitTimeDiscount.id) {
return goods.salePrice; if (
limitTimeDiscount.foodType == 1 &&
limitTimeDiscount.discountPriority == "limit-time"
) {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
const canUseFoods = limitTimeDiscount.foods.split(",");
if (
limitTimeDiscount.foodType == 2 &&
limitTimeDiscount.discountPriority == "limit-time" &&
canUseFoods.includes(`${goods.productId}`)
) {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
}
if (shopInfo && !shopInfo.isMemberPrice) {
return goods.salePrice;
}
if (
user.isVip &&
goods.memberPrice * 1 <= goods.salePrice * 1 &&
goods.memberPrice * 1 > 0
) {
return goods.memberPrice;
}
return goods.salePrice;
} }
/** /**
@@ -29,15 +57,15 @@ export function returnGoodsPrice(goods, user, shopInfo) {
* @param arr 商品列表 * @param arr 商品列表
*/ */
export function returnGoodsGroupMap(arr) { export function returnGoodsGroupMap(arr) {
let map = {}; let map = {};
arr.forEach((v) => { arr.forEach((v) => {
const key = v.productId + "_" + v.skuId; const key = v.productId + "_" + v.skuId;
if (!map[key]) { if (!map[key]) {
map[key] = []; map[key] = [];
} }
map[key].push(v); map[key].push(v);
}); });
return map; return map;
} }
/** /**
@@ -45,17 +73,17 @@ export function returnGoodsGroupMap(arr) {
* @param coupon * @param coupon
*/ */
export function returnCoupType(coupon) { export function returnCoupType(coupon) {
const couponTypes = { const couponTypes = {
1: "满减券", 1: "满减券",
2: "商品券", 2: "商品券",
3: "折扣券", 3: "折扣券",
4: "第二件半价券", 4: "第二件半价券",
5: "消费送券", 5: "消费送券",
6: "买一送一券", 6: "买一送一券",
7: "固定价格券", 7: "固定价格券",
8: "免配送费券", 8: "免配送费券",
}; };
return couponTypes[coupon.type] || "未知类型"; return couponTypes[coupon.type] || "未知类型";
} }
/** /**
@@ -65,22 +93,37 @@ export function returnCoupType(coupon) {
* @param user 用户信息 * @param user 用户信息
*/ */
export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) { export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) {
const goodsCouponGoods = selCoupon const types = [2, 4, 6];
.filter((v) => v.type == 2) // 收集已抵扣商品并关联对应的优惠券类型
.reduce((prve, cur) => { const goodsCouponGoods = selCoupon
prve.push(...cur.discount.hasDiscountGoodsArr); .filter((v) => types.includes(v.type))
return prve; .reduce((prev, cur) => {
}, []); // 给每个抵扣商品添加所属优惠券类型
const arr = _.cloneDeep(canDikouGoodsArr) const goodsWithType = cur.discount.hasDiscountGoodsArr.map((goods) => ({
.map((v) => { ...goods,
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id); couponType: cur.type, // 记录该商品是被哪种类型的优惠券抵扣的
if (findCart) { }));
v.num -= findCart.num; prev.push(...goodsWithType);
} return prev;
return v; }, []);
}) const arr = _.cloneDeep(canDikouGoodsArr)
.filter((v) => v.num > 0); .map((v) => {
return arr; const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
if (findCart) {
// 根据优惠券类型判断扣减数量
if ([4, 6].includes(findCart.couponType)) {
// 类型4第二件半价或6买一送一数量减2
v.num -= 2;
} else {
// 其他类型如类型2商品券按原逻辑扣减对应数量
v.num -= findCart.num;
}
}
return v;
})
.filter((v) => v.num > 0); // 过滤掉数量<=0的商品
return arr;
} }
/** /**
@@ -97,139 +140,208 @@ export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) {
* @param {Object} args.user - 用户信息对象 * @param {Object} args.user - 用户信息对象
* @param {Object} args.selCoupon - 已经选择的优惠券信息对象 * @param {Object} args.selCoupon - 已经选择的优惠券信息对象
* @param {Object} args.shopInfo * @param {Object} args.shopInfo
* @param {boolean} args.limitTimeDiscount - 限时折扣
* @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因 * @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因
*/ */
export function returnCouponCanUse(args) { export function returnCouponCanUse(args) {
let { let {
canDikouGoodsArr, canDikouGoodsArr,
coupon, coupon,
goodsOrderPrice, goodsOrderPrice,
user, user,
selCoupon, selCoupon,
shopInfo shopInfo,
} = args; isMemberPrice,
limitTimeDiscount,
} = args;
// 优惠券未启用
if (!coupon.use) {
return {
canUse: false,
reason: coupon.noUseRestrictions || "不在可用时间段内",
};
}
if(limitTimeDiscount&&limitTimeDiscount.id&&!coupon.discountShare){
return {
canUse: false,
reason: coupon.noUseRestrictions || "不可与限时折扣同享",
};
}
// 优惠券未启用 // 计算门槛金额
if (!coupon.use) { let fullAmount = goodsOrderPrice;
return { canDikouGoodsArr = returnCanDikouGoodsArr(
canUse: false, canDikouGoodsArr,
reason: "优惠券未启用" selCoupon,
}; user,
} shopInfo,
limitTimeDiscount
);
//优惠券指定门槛商品列表
let canCalcGoodsArr = [...canDikouGoodsArr];
//部分商品参与门槛计算
if (coupon.thresholdFoods.length) {
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
return coupon.thresholdFoods.find((food) => food.id == v.productId);
});
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
return (
pre + returnGoodsPrice(cur, user, shopInfo, limitTimeDiscount) * cur.num
);
}, 0);
}
canDikouGoodsArr = returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user,shopInfo); // 是否全部商品可用
// 计算门槛金额 const isDikouAll = coupon.useFoods.length === 0;
let fullAmount = goodsOrderPrice; // 订单可用商品列表
// 是否抵扣全部商品 let canUseGoodsArr = [];
const isDikouAll = coupon.useFoods.length === 0; if (!isDikouAll) {
let canCalcGoodsArr = []; canUseGoodsArr = canDikouGoodsArr.filter((v) => {
// 订单里参与门槛计算的商品 return coupon.useFoods.find((food) => food.id == v.productId);
if (!isDikouAll) { });
canCalcGoodsArr = canDikouGoodsArr.filter((v) => { }
return coupon.useFoods.find((food) => food.id == v.productId); if (user.isVip && !coupon.vipPriceShare) {
}); return {
fullAmount = canCalcGoodsArr.reduce((pre, cur) => { canUse: false,
return pre + returnGoodsPrice(cur, user,shopInfo) * cur.num; reason: "非会员可用",
}, 0); };
} }
if (selCoupon.length > 0 && !selCoupon[0].otherCouponShare) {
return {
canUse: false,
reason: "当前选中的券不可与其他券同享",
};
}
if (selCoupon.length > 0 && !coupon.otherCouponShare) {
return {
canUse: false,
reason: "当前选中的券不可与其他券同享",
};
}
// 满减券和折扣券计算门槛金额是否满足
if ([1, 3].includes(coupon.type)) {
if (canCalcGoodsArr.length <= 0) {
return {
canUse: false,
reason: "没有可参与计算门槛的商品",
};
}
// 不满足门槛金额
if (fullAmount < coupon.fullAmount) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
}
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
if ([2, 4, 5].includes(coupon.type)) {
if (coupon.type == 2 && fullAmount < coupon.fullAmount) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
// 没有符合条件的商品 // 没有符合条件的商品
if (!isDikouAll && canCalcGoodsArr.length === 0) { if (isDikouAll && canDikouGoodsArr.length === 0) {
return { return {
canUse: false, canUse: false,
reason: "没有符合条件的商品" reason: "没有符合条件的商品",
}; };
} }
if (!isDikouAll && canUseGoodsArr.length === 0) {
return {
canUse: false,
reason: "没有符合条件的商品",
};
}
}
//商品兑换券是否达到门槛金额
if (coupon.type == 2 && goodsOrderPrice < coupon.fullAmount) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
// 不满足门槛金额 // 买一送一券特殊验证
if (fullAmount < coupon.fullAmount) { if (coupon.type === 6) {
return { let canUse = false;
canUse: false, if (isDikouAll) {
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}` canUse = canDikouGoodsArr.some((v) => v.num >= 2);
}; } else if (canUseGoodsArr.length > 0) {
} canUse = canUseGoodsArr.some((v) => v.num >= 2);
}
// 商品券特殊验证 if (!canUse) {
if (coupon.type === 2) { return {
if (!(isDikouAll || canCalcGoodsArr.length > 0)) { canUse: false,
return { reason: "需要购买至少2件相同的商品才能使用",
canUse: false, };
reason: "没有符合条件的商品可抵扣" }
}; }
}
}
// 买一送一券特殊验证 // 第二件半价券特殊验证
if (coupon.type === 6) { if (coupon.type === 4) {
let canUse = false; let canUse = false;
if (isDikouAll) { if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => v.num >= 2); canUse = canDikouGoodsArr.some((v) => v.num >= 2);
} else if (canCalcGoodsArr.length > 0) { } else if (canUseGoodsArr.length > 0) {
canUse = canCalcGoodsArr.some((v) => v.num >= 2); canUse = canUseGoodsArr.some((v) => v.num >= 2);
} }
if (!canUse) {
return {
canUse: false,
reason: "需要购买至少2件相同的商品才能使用",
};
}
}
if (!canUse) { // 所有条件都满足
return { return {
canUse: false, canUse: true,
reason: "需要购买至少2件相同的商品才能使用" reason: "",
}; };
}
}
// 第二件半价券特殊验证
if (coupon.type === 4) {
let canUse = false;
if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => v.num >= 2);
} else if (canCalcGoodsArr.length > 0) {
canUse = canCalcGoodsArr.some((v) => v.num >= 2);
}
if (!canUse) {
return {
canUse: false,
reason: "需要购买至少2件相同的商品才能使用"
};
}
}
// 所有条件都满足
return {
canUse: true,
reason: ""
};
} }
/** /**
* 计算抵扣商品金额 * 计算抵扣商品金额
* @param discountGoodsArr 可抵扣商品列表 * @param discountGoodsArr 可抵扣商品列表
* @param discountNum 抵扣数量 * @param discountNum 抵扣数量
* @param user 用户信息 * @param user 用户信息
* @param {Object} shopInfo 店铺信息 * @param {Object} shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user,shopInfo) { export function calcDiscountGoodsArrPrice(
let hasCountNum = 0; discountGoodsArr,
let discountPrice = 0; discountNum,
let hasDiscountGoodsArr = []; user,
for (let i = 0; i < discountGoodsArr.length; i++) { shopInfo,limitTimeDiscount
if (hasCountNum >= discountNum) { ) {
break; let hasCountNum = 0;
} let discountPrice = 0;
const goods = discountGoodsArr[i]; let hasDiscountGoodsArr = [];
const shengyuNum = discountNum - hasCountNum; for (let i = 0; i < discountGoodsArr.length; i++) {
const num = Math.min(goods.num, shengyuNum); if (hasCountNum >= discountNum) {
discountPrice += returnGoodsPrice(goods, user,shopInfo) * num; break;
hasCountNum += num; }
hasDiscountGoodsArr.push({ const goods = discountGoodsArr[i];
...goods, const shengyuNum = discountNum - hasCountNum;
num const num = Math.min(goods.num, shengyuNum);
}); discountPrice += returnGoodsPrice(goods, user, shopInfo,limitTimeDiscount) * num;
}
return { hasCountNum += num;
discountPrice, hasDiscountGoodsArr.push({
hasDiscountGoodsArr ...goods,
}; num,
});
}
return {
discountPrice,
hasDiscountGoodsArr,
};
} }
/** /**
@@ -239,23 +351,51 @@ export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user,sh
* @param user 用户信息 * @param user 用户信息
* @param goodsOrderPrice 商品订单金额 * @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表 * @param selCoupon 已选择的优惠券列表
* @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
export function returnCouponDiscount(arr, coupon, user, goodsOrderPrice, selCoupon) { export function returnCouponDiscount(
console.log('arr', arr); arr,
const canDikouGoodsArr = returnCanDikouGoodsArr(arr, selCoupon, user); coupon,
console.log('canDikouGoodsArr', canDikouGoodsArr); user,
if (coupon.type == 2) { goodsOrderPrice,
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice); selCoupon,
} shopInfo,limitTimeDiscount
if (coupon.type == 6) { ) {
return returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice); arr = returnCanDikouGoods(arr, user, shopInfo);
} const canDikouGoodsArr = returnCanDikouGoodsArr(arr, selCoupon, user);
if (coupon.type == 4) { if (coupon.type == 2) {
return returnSecoendDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice); return returnCouponProductDiscount(
} canDikouGoodsArr,
if (coupon.type == 3) { coupon,
return returnCouponZhekouDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice, selCoupon); user,
} shopInfo,
limitTimeDiscount
);
}
if (coupon.type == 6) {
const result = returnCouponBuyOneGiveOneDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
);
return result;
}
if (coupon.type == 4) {
return returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo,limitTimeDiscount);
}
if (coupon.type == 3) {
return returnCouponZhekouDiscount(
canDikouGoodsArr,
coupon,
user,
goodsOrderPrice,
selCoupon,
limitTimeDiscount
);
}
} }
/** /**
@@ -265,41 +405,53 @@ export function returnCouponDiscount(arr, coupon, user, goodsOrderPrice, selCoup
* @param user 用户信息 * @param user 用户信息
* @param goodsOrderPrice 商品订单金额 * @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表 * @param selCoupon 已选择的优惠券列表
* @param limitTimeDiscount 限时折扣
* *
*/ */
export function returnCouponZhekouDiscount( export function returnCouponZhekouDiscount(
canDikouGoodsArr, canDikouGoodsArr,
coupon, coupon,
user, user,
goodsOrderPrice, goodsOrderPrice,
selCoupon selCoupon,limitTimeDiscount
) { ) {
const { const { discountRate, maxDiscountAmount } = coupon;
discountRate,
maxDiscountAmount
} = coupon;
const goodsCouponDiscount = selCoupon // 计算商品优惠券折扣总和使用BigNumber避免精度问题
.filter((v) => v.type == 2) const goodsCouponDiscount = selCoupon
.reduce((prve, cur) => { .filter((v) => v.type == 2)
return prve + cur.discount.discountPrice; .reduce((prve, cur) => {
}, 0); return new BigNumber(prve).plus(
goodsOrderPrice -= goodsCouponDiscount; new BigNumber(cur.discount.discountPrice)
// 使用bignumber处理高精度计算 );
// 1. 计算折扣率百分比转小数discountRate / 100 }, new BigNumber(0));
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 { // 将商品订单价格转换为BigNumber并减去优惠券折扣
discountPrice, // 折扣抵扣金额(即优惠的金额) const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(
hasDiscountGoodsArr: [], goodsCouponDiscount
}; );
// 计算优惠比例:(100 - 折扣率) / 100
const discountAmountRatio = new BigNumber(100)
.minus(discountRate)
.dividedBy(100);
// 计算折扣金额:调整后的商品订单金额 × 优惠比例
let discountPrice = adjustedGoodsOrderPrice
.times(discountAmountRatio)
.decimalPlaces(2, BigNumber.ROUND_FLOOR)
.toNumber();
// 应用最大折扣金额限制
if (maxDiscountAmount !== 0) {
discountPrice =
discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
}
return {
discountPrice, // 折扣抵扣金额(即优惠的金额)
hasDiscountGoodsArr: [],
};
} }
/** /**
@@ -307,39 +459,45 @@ export function returnCouponZhekouDiscount(
* @param canDikouGoodsArr 可抵扣商品列表 * @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券 * @param coupon 优惠券
* @param user 用户信息 * @param user 用户信息
* @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user) { export function returnCouponProductDiscount(
const { canDikouGoodsArr,
useFoods, coupon,
discountNum, user,
useRule shopInfo,
} = coupon; limitTimeDiscount
//抵扣商品数组 ) {
let discountGoodsArr = []; const { useFoods, discountNum, useRule } = coupon;
//抵扣全部商品 //抵扣商品数组
if (useFoods.length === 0) { let discountGoodsArr = [];
if (useRule == "price_asc") { //抵扣全部商品
discountGoodsArr = canDikouGoodsArr if (useFoods.length === 0) {
.slice(canDikouGoodsArr.length - discountNum, canDikouGoodsArr.length) if (useRule == "price_asc") {
.reverse(); discountGoodsArr = canDikouGoodsArr.slice(discountNum * -1).reverse();
} else { } else {
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum); discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
} }
} else { } else {
//抵扣选中商品 //抵扣选中商品
const discountSelGoodsArr = canDikouGoodsArr.filter((v) => const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
useFoods.find((food) => food.id == v.productId) useFoods.find((food) => food.id == v.productId)
); );
if (useRule == "price_asc") { if (useRule == "price_asc") {
discountGoodsArr = discountSelGoodsArr discountGoodsArr = discountSelGoodsArr.slice(discountNum * -1).reverse();
.slice(discountSelGoodsArr.length - discountNum, discountSelGoodsArr.length) } else {
.reverse(); discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
} else { }
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum); }
} const result = calcDiscountGoodsArrPrice(
} discountGoodsArr,
const result = calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user); discountNum,
return result; user,
shopInfo,
limitTimeDiscount
);
return result;
} }
// 返回买一送一券抵扣详情 // 返回买一送一券抵扣详情
@@ -348,38 +506,47 @@ export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user) {
* @param coupon 优惠券 * @param coupon 优惠券
* @param user 用户信息 * @param user 用户信息
* @param shopInfo 店铺信息 * @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user,shopInfo) { function returnCouponBuyOneGiveOneDiscount(
const { canDikouGoodsArr,
useFoods, coupon,
useRule user,
} = coupon; shopInfo,limitTimeDiscount
//抵扣商品 ) {
let discountGoods = undefined; const { useFoods, useRule } = coupon;
//符合买一送一条件的商品 //抵扣商品
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2); let discountGoods = undefined;
//抵扣全部商品 //符合买一送一条件的商品
if (useFoods.length === 0) { const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
if (useRule == "price_asc") { //抵扣全部商品
discountGoods = canUseGoods[canUseGoods.length - 1]; if (useFoods.length === 0) {
} else { if (useRule == "price_asc") {
discountGoods = canUseGoods.slice(0, 1); discountGoods = canUseGoods[canUseGoods.length - 1];
} } else {
} else { discountGoods = canUseGoods[0];
//符合抵扣条件的商品 }
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId)); } else {
if (useRule == "price_asc") { //符合抵扣条件的商品
discountGoods = canUseGoods1[canUseGoods1.length - 1]; const canUseGoods1 = canUseGoods.filter((v) =>
} else { useFoods.find((food) => food.id == v.productId)
discountGoods = canUseGoods1.slice(0, 1); );
} if (useRule == "price_asc") {
} discountGoods = canUseGoods1[canUseGoods1.length - 1];
const discountPrice = returnGoodsPrice(discountGoods, user,shopInfo); } else {
const hasDiscountGoodsArr = [discountGoods]; discountGoods = canUseGoods1[0];
return { }
discountPrice, }
hasDiscountGoodsArr let discountPrice = 0;
}; let hasDiscountGoodsArr = [];
if (discountGoods) {
discountPrice = returnGoodsPrice(discountGoods, user, shopInfo,limitTimeDiscount);
hasDiscountGoodsArr = [discountGoods];
}
return {
discountPrice: discountPrice <= 0 ? 0 : discountPrice,
hasDiscountGoodsArr,
};
} }
/** /**
@@ -388,39 +555,46 @@ function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user,shopIn
* @param coupon 优惠券 * @param coupon 优惠券
* @param user 用户信息 * @param user 用户信息
* @param shopInfo 店铺信息 * @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
function returnSecoendDiscount(canDikouGoodsArr, coupon, user,shopInfo) { function returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo,limitTimeDiscount) {
const { const { useFoods, useRule } = coupon;
useFoods, //抵扣商品
useRule let discountGoods = undefined;
} = coupon; //符合条件的商品
//抵扣商品 const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2);
let discountGoods = undefined; //抵扣全部商品
//符合买一送一条件的商品 if (useFoods.length === 0) {
const canUseGoods = canDikouGoodsArr.filter((v) => v.num >= 2); if (useRule == "price_asc") {
//抵扣全部商品 discountGoods = canUseGoods[canUseGoods.length - 1];
if (useFoods.length === 0) { } else {
if (useRule == "price_asc") { discountGoods = canUseGoods[0];
discountGoods = canUseGoods[canUseGoods.length - 1]; }
} else { } else {
discountGoods = canUseGoods.slice(0, 1); //符合抵扣条件的商品
} const canUseGoods1 = canUseGoods.filter((v) =>
} else { useFoods.find((food) => food.id == v.productId)
//符合抵扣条件的商品 );
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId)); if (useRule == "price_asc") {
if (useRule == "price_asc") { discountGoods = canUseGoods1[canUseGoods1.length - 1];
discountGoods = canUseGoods1[canUseGoods1.length - 1]; } else {
} else { discountGoods = canUseGoods1[0];
discountGoods = canUseGoods1.slice(0, 1); }
} }
} let discountPrice = 0;
const discountPrice = returnGoodsPrice(discountGoods, user,shopInfo); let hasDiscountGoodsArr = [];
const hasDiscountGoodsArr = [discountGoods]; if (discountGoods) {
//返回半价价格 discountPrice = returnGoodsPrice(discountGoods, user, shopInfo,limitTimeDiscount);
return { hasDiscountGoodsArr = [discountGoods];
discountPrice: new BigNumber(discountPrice).dividedBy(2).toNumber(), }
hasDiscountGoodsArr, //返回半价价格
}; return {
discountPrice:
discountPrice <= 0
? 0
: new BigNumber(discountPrice).dividedBy(2).toNumber(),
hasDiscountGoodsArr,
};
} }
/** /**
@@ -428,17 +602,21 @@ function returnSecoendDiscount(canDikouGoodsArr, coupon, user,shopInfo) {
* @param arr 商品列表 * @param arr 商品列表
* @param user 用户信息 * @param user 用户信息
* @param shopInfo 店铺信息 * @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
export function returnCanDikouGoods(arr, user, shopInfo) { export function returnCanDikouGoods(arr, user, shopInfo,limitTimeDiscount) {
const result = arr const result = arr
.filter((v) => { .filter((v) => {
return v.is_temporary != 1 && v.is_gift != 1; return v.is_temporary != 1 && v.is_gift != 1;
}) })
.filter((v) => { .filter((v) => {
return v.num > 0; return v.num > 0;
}) })
.sort((a, b) => { .sort((a, b) => {
return returnGoodsPrice(b, use, shopInfo) - returnGoodsPrice(a, user, shopInfo); return (
}); returnGoodsPrice(b, user, shopInfo,limitTimeDiscount) -
return result; returnGoodsPrice(a, user, shopInfo,limitTimeDiscount)
);
});
return result;
} }

View File

@@ -5,19 +5,48 @@ import _ from "lodash";
* 返回商品单价 * 返回商品单价
* @param goods 商品 * @param goods 商品
* @param user 用户信息 * @param user 用户信息
* @param {Object} shopInfo * @param {Object} shopInfo 店铺信息
* @param {boolean} limitTimeDiscount - 限时折扣
*/ */
export function returnGoodsPrice(goods, user, shopInfo) { export function returnGoodsPrice(goods, user, shopInfo, limitTimeDiscount) {
if (!goods) { if (!goods) {
return 0; return 0;
} }
// 商家改价
if (goods.discount_sale_amount * 1 > 0) { if (goods.discount_sale_amount * 1 > 0) {
return goods.discount_sale_amount; return goods.salePrice;
}
// 限时折扣
if (limitTimeDiscount && limitTimeDiscount.id) {
if (
limitTimeDiscount.foodType == 1 &&
limitTimeDiscount.discountPriority == "limit-time"
) {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
const canUseFoods = limitTimeDiscount.foods.split(",");
if (
limitTimeDiscount.foodType == 2 &&
limitTimeDiscount.discountPriority == "limit-time" &&
canUseFoods.includes(`${goods.productId}`)
) {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
} }
if (shopInfo && !shopInfo.isMemberPrice) { if (shopInfo && !shopInfo.isMemberPrice) {
return goods.salePrice; return goods.salePrice;
} }
if (user.isVip && goods.memberPrice * 1 <= goods.salePrice * 1 && goods.memberPrice * 1 > 0) { if (
user.isVip &&
goods.memberPrice * 1 <= goods.salePrice * 1 &&
goods.memberPrice * 1 > 0
) {
return goods.memberPrice; return goods.memberPrice;
} }
return goods.salePrice; return goods.salePrice;
@@ -63,7 +92,9 @@ export function returnCoupType(coupon) {
* @param selCoupon 已选择的优惠券列表 * @param selCoupon 已选择的优惠券列表
* @param user 用户信息 * @param user 用户信息
*/ */
export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) { export function returnCanDikouGoodsArr(args) {
const { canDikouGoodsArr, selCoupon, user, shopInfo, limitTimeDiscount } =
args;
const types = [2, 4, 6]; const types = [2, 4, 6];
// 收集已抵扣商品并关联对应的优惠券类型 // 收集已抵扣商品并关联对应的优惠券类型
const goodsCouponGoods = selCoupon const goodsCouponGoods = selCoupon
@@ -92,11 +123,53 @@ export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) {
} }
return v; return v;
}) })
.filter((v) => v.num > 0); // 过滤掉数量<=0的商品 .filter((v) => {
const canUseNum=v.num-(v.returnNum||0)
if(canUseNum <= 0||v.is_temporary==1||v.is_gift==1){
return false
}
return true
}); // 过滤掉数量<=0的商品,赠菜,临时菜
return arr; return arr;
} }
/**
* 返回商品是否享用了会员价/会员折扣
* @param {*} goods
*/
function returnGoodsIsUseVipPrice(shopInfo,user,goods) {
if(goods.is_time_discount){
return false
}
if(shopInfo.isMemberPrice!=1||user.isVip!=1){
return false
}
if(shopInfo.isMemberPrice==1&&user.isVip==1){
if(goods.memberPrice<=0){
return false
}
return true
}
}
/**
* 返回可以计算抵扣金额的商品列表
*/
function returnCanCalcGoodsList(canCalcGoodsArr, coupon, shopInfo, user) {
return canCalcGoodsArr.filter((goods) => {
if (!coupon.discountShare && goods.is_time_discount) {
return false;
}
if(!coupon.vipPriceShare&& returnGoodsIsUseVipPrice(shopInfo,user,goods)){
return false;
}
return true;
});
}
/** /**
* 判断优惠券是否可使用,并返回不可用原因 * 判断优惠券是否可使用,并返回不可用原因
* *
@@ -111,10 +184,20 @@ export function returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user) {
* @param {Object} args.user - 用户信息对象 * @param {Object} args.user - 用户信息对象
* @param {Object} args.selCoupon - 已经选择的优惠券信息对象 * @param {Object} args.selCoupon - 已经选择的优惠券信息对象
* @param {Object} args.shopInfo * @param {Object} args.shopInfo
* @param {boolean} args.limitTimeDiscount - 限时折扣
* @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因 * @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因
*/ */
export function returnCouponCanUse(args) { export function returnCouponCanUse(args) {
let { canDikouGoodsArr, coupon, goodsOrderPrice, user, selCoupon, shopInfo } = args; let {
canDikouGoodsArr,
coupon,
goodsOrderPrice,
user,
selCoupon,
shopInfo,
isMemberPrice,
limitTimeDiscount,
} = args;
// 优惠券未启用 // 优惠券未启用
if (!coupon.use) { if (!coupon.use) {
return { return {
@@ -122,10 +205,27 @@ export function returnCouponCanUse(args) {
reason: coupon.noUseRestrictions || "不在可用时间段内", reason: coupon.noUseRestrictions || "不在可用时间段内",
}; };
} }
if (
limitTimeDiscount &&
limitTimeDiscount.id &&
limitTimeDiscount.foodType == 1 &&
!coupon.discountShare
) {
return {
canUse: false,
reason: coupon.noUseRestrictions || "不可与限时折扣同享",
};
}
// 计算门槛金额 // 计算门槛金额
let fullAmount = goodsOrderPrice; let fullAmount = goodsOrderPrice;
canDikouGoodsArr = returnCanDikouGoodsArr(canDikouGoodsArr, selCoupon, user, shopInfo); canDikouGoodsArr = returnCanDikouGoodsArr({
canDikouGoodsArr,
selCoupon,
user,
shopInfo,
limitTimeDiscount,
});
//优惠券指定门槛商品列表 //优惠券指定门槛商品列表
let canCalcGoodsArr = [...canDikouGoodsArr]; let canCalcGoodsArr = [...canDikouGoodsArr];
//部分商品参与门槛计算 //部分商品参与门槛计算
@@ -133,10 +233,18 @@ export function returnCouponCanUse(args) {
canCalcGoodsArr = canDikouGoodsArr.filter((v) => { canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
return coupon.thresholdFoods.find((food) => food.id == v.productId); return coupon.thresholdFoods.find((food) => food.id == v.productId);
}); });
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
return pre + returnGoodsPrice(cur, user, shopInfo) * cur.num;
}, 0);
} }
canCalcGoodsArr = returnCanCalcGoodsList(
canCalcGoodsArr,
coupon,
shopInfo,
user
);
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
return (
pre + returnGoodsPrice(cur, user, shopInfo, limitTimeDiscount) * cur.num
);
}, 0);
// 是否全部商品可用 // 是否全部商品可用
const isDikouAll = coupon.useFoods.length === 0; const isDikouAll = coupon.useFoods.length === 0;
@@ -147,12 +255,12 @@ export function returnCouponCanUse(args) {
return coupon.useFoods.find((food) => food.id == v.productId); return coupon.useFoods.find((food) => food.id == v.productId);
}); });
} }
if (user.isVip && !coupon.vipPriceShare) { // if (user.isVip && !coupon.vipPriceShare) {
return { // return {
canUse: false, // canUse: false,
reason: "非会员可用", // reason: "非会员可用",
}; // };
} // }
if (selCoupon.length > 0 && !selCoupon[0].otherCouponShare) { if (selCoupon.length > 0 && !selCoupon[0].otherCouponShare) {
return { return {
canUse: false, canUse: false,
@@ -183,15 +291,8 @@ export function returnCouponCanUse(args) {
} }
// 商品兑换券,第二件半价和买一送一判断是否有可用商品 // 商品兑换券,第二件半价和买一送一判断是否有可用商品
if ([2, 4, 5].includes(coupon.type)) { if ([2, 4, 5].includes(coupon.type)) {
if (coupon.type == 2 && fullAmount < coupon.fullAmount) { // 没有符合条件的商品
return { if (isDikouAll && canDikouGoodsArr.length === 0) {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
// 没有符合条件的商品
if (isDikouAll && canDikouGoodsArr.length === 0) {
return { return {
canUse: false, canUse: false,
reason: "没有符合条件的商品", reason: "没有符合条件的商品",
@@ -203,6 +304,23 @@ export function returnCouponCanUse(args) {
reason: "没有符合条件的商品", reason: "没有符合条件的商品",
}; };
} }
if (coupon.type == 2 ) {
if(canCalcGoodsArr.length<=0){
return {
canUse: false,
reason: "没有符合计算门槛条件的商品",
};
}
if(fullAmount < coupon.fullAmount){
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
}
} }
//商品兑换券是否达到门槛金额 //商品兑换券是否达到门槛金额
if (coupon.type == 2 && goodsOrderPrice < coupon.fullAmount) { if (coupon.type == 2 && goodsOrderPrice < coupon.fullAmount) {
@@ -258,8 +376,15 @@ export function returnCouponCanUse(args) {
* @param discountNum 抵扣数量 * @param discountNum 抵扣数量
* @param user 用户信息 * @param user 用户信息
* @param {Object} shopInfo 店铺信息 * @param {Object} shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, shopInfo) { export function calcDiscountGoodsArrPrice(
discountGoodsArr,
discountNum,
user,
shopInfo,
limitTimeDiscount
) {
let hasCountNum = 0; let hasCountNum = 0;
let discountPrice = 0; let discountPrice = 0;
let hasDiscountGoodsArr = []; let hasDiscountGoodsArr = [];
@@ -270,7 +395,8 @@ export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, s
const goods = discountGoodsArr[i]; const goods = discountGoodsArr[i];
const shengyuNum = discountNum - hasCountNum; const shengyuNum = discountNum - hasCountNum;
const num = Math.min(goods.num, shengyuNum); const num = Math.min(goods.num, shengyuNum);
discountPrice += returnGoodsPrice(goods, user, shopInfo) * num; discountPrice +=
returnGoodsPrice(goods, user, shopInfo, limitTimeDiscount) * num;
hasCountNum += num; hasCountNum += num;
hasDiscountGoodsArr.push({ hasDiscountGoodsArr.push({
@@ -293,22 +419,62 @@ export function calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, s
* @param goodsOrderPrice 商品订单金额 * @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表 * @param selCoupon 已选择的优惠券列表
* @param shopInfo 店铺信息 * @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
export function returnCouponDiscount(arr, coupon, user, goodsOrderPrice, selCoupon, shopInfo) { export function returnCouponDiscount(
arr,
coupon,
user,
goodsOrderPrice,
selCoupon,
shopInfo,
limitTimeDiscount
) {
arr = returnCanDikouGoods(arr, user, shopInfo); arr = returnCanDikouGoods(arr, user, shopInfo);
const canDikouGoodsArr = returnCanDikouGoodsArr(arr, selCoupon, user); const canDikouGoodsArr = returnCanDikouGoodsArr({
canDikouGoodsArr: arr,
selCoupon,
user,
shopInfo,
limitTimeDiscount,
});
if (coupon.type == 2) { if (coupon.type == 2) {
return returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shopInfo); return returnCouponProductDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
);
} }
if (coupon.type == 6) { if (coupon.type == 6) {
const result = returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopInfo); const result = returnCouponBuyOneGiveOneDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
);
return result; return result;
} }
if (coupon.type == 4) { if (coupon.type == 4) {
return returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo); return returnSecoendDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
);
} }
if (coupon.type == 3) { if (coupon.type == 3) {
return returnCouponZhekouDiscount(canDikouGoodsArr, coupon, user, goodsOrderPrice, selCoupon); return returnCouponZhekouDiscount(
canDikouGoodsArr,
coupon,
user,
goodsOrderPrice,
selCoupon,
limitTimeDiscount
);
} }
} }
@@ -319,6 +485,7 @@ export function returnCouponDiscount(arr, coupon, user, goodsOrderPrice, selCoup
* @param user 用户信息 * @param user 用户信息
* @param goodsOrderPrice 商品订单金额 * @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表 * @param selCoupon 已选择的优惠券列表
* @param limitTimeDiscount 限时折扣
* *
*/ */
export function returnCouponZhekouDiscount( export function returnCouponZhekouDiscount(
@@ -326,7 +493,8 @@ export function returnCouponZhekouDiscount(
coupon, coupon,
user, user,
goodsOrderPrice, goodsOrderPrice,
selCoupon selCoupon,
limitTimeDiscount
) { ) {
const { discountRate, maxDiscountAmount } = coupon; const { discountRate, maxDiscountAmount } = coupon;
@@ -334,14 +502,20 @@ export function returnCouponZhekouDiscount(
const goodsCouponDiscount = selCoupon const goodsCouponDiscount = selCoupon
.filter((v) => v.type == 2) .filter((v) => v.type == 2)
.reduce((prve, cur) => { .reduce((prve, cur) => {
return new BigNumber(prve).plus(new BigNumber(cur.discount.discountPrice)); return new BigNumber(prve).plus(
new BigNumber(cur.discount.discountPrice)
);
}, new BigNumber(0)); }, new BigNumber(0));
// 将商品订单价格转换为BigNumber并减去优惠券折扣 // 将商品订单价格转换为BigNumber并减去优惠券折扣
const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(goodsCouponDiscount); const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(
goodsCouponDiscount
);
// 计算优惠比例:(100 - 折扣率) / 100 // 计算优惠比例:(100 - 折扣率) / 100
const discountAmountRatio = new BigNumber(100).minus(discountRate).dividedBy(100); const discountAmountRatio = new BigNumber(100)
.minus(discountRate)
.dividedBy(100);
// 计算折扣金额:调整后的商品订单金额 × 优惠比例 // 计算折扣金额:调整后的商品订单金额 × 优惠比例
let discountPrice = adjustedGoodsOrderPrice let discountPrice = adjustedGoodsOrderPrice
@@ -351,7 +525,8 @@ export function returnCouponZhekouDiscount(
// 应用最大折扣金额限制 // 应用最大折扣金额限制
if (maxDiscountAmount !== 0) { if (maxDiscountAmount !== 0) {
discountPrice = discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice; discountPrice =
discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
} }
return { return {
@@ -366,8 +541,15 @@ export function returnCouponZhekouDiscount(
* @param coupon 优惠券 * @param coupon 优惠券
* @param user 用户信息 * @param user 用户信息
* @param shopInfo 店铺信息 * @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shopInfo) { export function returnCouponProductDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
) {
const { useFoods, discountNum, useRule } = coupon; const { useFoods, discountNum, useRule } = coupon;
//抵扣商品数组 //抵扣商品数组
let discountGoodsArr = []; let discountGoodsArr = [];
@@ -389,7 +571,13 @@ export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shop
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum); discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
} }
} }
const result = calcDiscountGoodsArrPrice(discountGoodsArr, discountNum, user, shopInfo); const result = calcDiscountGoodsArrPrice(
discountGoodsArr,
discountNum,
user,
shopInfo,
limitTimeDiscount
);
return result; return result;
} }
@@ -399,8 +587,15 @@ export function returnCouponProductDiscount(canDikouGoodsArr, coupon, user, shop
* @param coupon 优惠券 * @param coupon 优惠券
* @param user 用户信息 * @param user 用户信息
* @param shopInfo 店铺信息 * @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopInfo) { function returnCouponBuyOneGiveOneDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
) {
const { useFoods, useRule } = coupon; const { useFoods, useRule } = coupon;
//抵扣商品 //抵扣商品
let discountGoods = undefined; let discountGoods = undefined;
@@ -415,7 +610,9 @@ function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopI
} }
} else { } else {
//符合抵扣条件的商品 //符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId)); const canUseGoods1 = canUseGoods.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") { if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1]; discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else { } else {
@@ -425,7 +622,12 @@ function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopI
let discountPrice = 0; let discountPrice = 0;
let hasDiscountGoodsArr = []; let hasDiscountGoodsArr = [];
if (discountGoods) { if (discountGoods) {
discountPrice = returnGoodsPrice(discountGoods, user, shopInfo); discountPrice = returnGoodsPrice(
discountGoods,
user,
shopInfo,
limitTimeDiscount
);
hasDiscountGoodsArr = [discountGoods]; hasDiscountGoodsArr = [discountGoods];
} }
return { return {
@@ -440,8 +642,15 @@ function returnCouponBuyOneGiveOneDiscount(canDikouGoodsArr, coupon, user, shopI
* @param coupon 优惠券 * @param coupon 优惠券
* @param user 用户信息 * @param user 用户信息
* @param shopInfo 店铺信息 * @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
function returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo) { function returnSecoendDiscount(
canDikouGoodsArr,
coupon,
user,
shopInfo,
limitTimeDiscount
) {
const { useFoods, useRule } = coupon; const { useFoods, useRule } = coupon;
//抵扣商品 //抵扣商品
let discountGoods = undefined; let discountGoods = undefined;
@@ -456,7 +665,9 @@ function returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
} }
} else { } else {
//符合抵扣条件的商品 //符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) => useFoods.find((food) => food.id == v.productId)); const canUseGoods1 = canUseGoods.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") { if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1]; discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else { } else {
@@ -466,12 +677,20 @@ function returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
let discountPrice = 0; let discountPrice = 0;
let hasDiscountGoodsArr = []; let hasDiscountGoodsArr = [];
if (discountGoods) { if (discountGoods) {
discountPrice = returnGoodsPrice(discountGoods, user, shopInfo); discountPrice = returnGoodsPrice(
discountGoods,
user,
shopInfo,
limitTimeDiscount
);
hasDiscountGoodsArr = [discountGoods]; hasDiscountGoodsArr = [discountGoods];
} }
//返回半价价格 //返回半价价格
return { return {
discountPrice: discountPrice <= 0 ? 0 : new BigNumber(discountPrice).dividedBy(2).toNumber(), discountPrice:
discountPrice <= 0
? 0
: new BigNumber(discountPrice).dividedBy(2).toNumber(),
hasDiscountGoodsArr, hasDiscountGoodsArr,
}; };
} }
@@ -481,8 +700,9 @@ function returnSecoendDiscount(canDikouGoodsArr, coupon, user, shopInfo) {
* @param arr 商品列表 * @param arr 商品列表
* @param user 用户信息 * @param user 用户信息
* @param shopInfo 店铺信息 * @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/ */
export function returnCanDikouGoods(arr, user, shopInfo) { export function returnCanDikouGoods(arr, user, shopInfo, limitTimeDiscount) {
const result = arr const result = arr
.filter((v) => { .filter((v) => {
return v.is_temporary != 1 && v.is_gift != 1; return v.is_temporary != 1 && v.is_gift != 1;
@@ -491,7 +711,10 @@ export function returnCanDikouGoods(arr, user, shopInfo) {
return v.num > 0; return v.num > 0;
}) })
.sort((a, b) => { .sort((a, b) => {
return returnGoodsPrice(b, user, shopInfo) - returnGoodsPrice(a, user, shopInfo); return (
returnGoodsPrice(b, user, shopInfo, limitTimeDiscount) -
returnGoodsPrice(a, user, shopInfo, limitTimeDiscount)
);
}); });
return result; return result;
} }

View File

@@ -234,6 +234,40 @@ export interface FreeDineConfig {
useShopType?: string; //all 全部 part部分 useShopType?: string; //all 全部 part部分
shopIdList?: number[]; //可用门店id shopIdList?: number[]; //可用门店id
} }
//限时折扣配置
export interface TimeLimitDiscountConfig {
/**
* 折扣优先级 limit-time/vip-price
*/
discountPriority: string;
/**
* 折扣% 范围1-99
*/
discountRate: number;
/**
* 参与商品
*/
foods: string;
/**
* 参与商品 1全部 2部分
*/
foodType: number;
/**
* 自增主键
*/
id: number;
/**
* 店铺ID
*/
shopId: number;
/**
* 可使用类型:堂食 dine-in 外带 take-out 外卖 take-away 配送 post
*/
useType: string;
[property: string]: any;
}
/** 订单额外费用配置 */ /** 订单额外费用配置 */
export interface OrderExtraConfig { export interface OrderExtraConfig {
// merchantReduction: number; // 商家减免金额默认0 // merchantReduction: number; // 商家减免金额默认0
@@ -251,6 +285,7 @@ export interface OrderExtraConfig {
currentDinnerType: "dine-in" | "take-out" | "take-away" | "post"; // 当前就餐类型匹配useType currentDinnerType: "dine-in" | "take-out" | "take-away" | "post"; // 当前就餐类型匹配useType
isFreeDine?: boolean; //是否霸王餐 isFreeDine?: boolean; //是否霸王餐
freeDineConfig?: FreeDineConfig; freeDineConfig?: FreeDineConfig;
limitTimeDiscount?: TimeLimitDiscountConfig; //限时折扣
} }
/** 订单费用汇总(修改:补充商家减免类型和明细) */ /** 订单费用汇总(修改:补充商家减免类型和明细) */
@@ -283,10 +318,12 @@ export interface OrderCostSummary {
config: OrderExtraConfig; // 订单额外费用配置 config: OrderExtraConfig; // 订单额外费用配置
//满减活动 //满减活动
fullReduction: { fullReduction: {
usedFullReductionActivityFullAmount: number; // 计算出的满减活动的门槛金额
usedActivity?: FullReductionActivity; // 实际使用的满减活动 usedActivity?: FullReductionActivity; // 实际使用的满减活动
usedThreshold?: FullReductionThreshold; // 实际使用的满减阈值(多门槛中选最优) usedThreshold?: FullReductionThreshold; // 实际使用的满减阈值(多门槛中选最优)
actualAmount: number; // 满减实际减免金额(元) actualAmount: number; // 满减实际减免金额(元)
}; };
vipDiscountAmount: number; //会员折扣减免金额
// 订单原支付金额 // 订单原支付金额
orderOriginFinalPayAmount: number; //订单原金额(包含打包费+餐位费) orderOriginFinalPayAmount: number; //订单原金额(包含打包费+餐位费)
} }
@@ -399,6 +436,188 @@ function isDinnerTypeMatch(
//满减活动的就餐类型和当前券类型字段值不一样暂时返回true //满减活动的就餐类型和当前券类型字段值不一样暂时返回true
return true; return true;
} }
//判断商品是否可以使用限时折扣
export function returnCanUseLimitTimeDiscount(
goods: BaseCartItem,
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined,
useVipPrice: boolean,
idKey = "product_id"
) {
if (!limitTimeDiscount || !limitTimeDiscount.id) {
return false;
}
const canUseFoods = (limitTimeDiscount.foods || "").split(",");
if (limitTimeDiscount.discountPriority == "limit-time") {
if (
limitTimeDiscount.foodType == 1 ||
canUseFoods.includes("" + goods[idKey])
) {
return true;
}
}
if (limitTimeDiscount.discountPriority == "vip-price") {
if (!useVipPrice) {
return true;
}
}
return false;
}
function returnMemberPrice(useVipPrice: boolean, goods: BaseCartItem) {
if (useVipPrice) {
return goods.memberPrice || goods.salePrice;
} else {
return goods.salePrice;
}
}
/**
* 返回商品限时折扣价格
*/
function returnLimitPrice(
goods: BaseCartItem,
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined,
useVipPrice
) {
if (!limitTimeDiscount) {
return 0;
}
const discountRate = new BigNumber(limitTimeDiscount.discountRate).dividedBy(
100
);
const canuseLimit = returnCanUseLimitTimeDiscount(
goods,
limitTimeDiscount,
useVipPrice
);
if (canuseLimit) {
//可以使用限时折扣
if (limitTimeDiscount.discountPriority == "limit-time") {
//限时价优先
const result = BigNumber(goods.salePrice)
.times(discountRate)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
return result;
}
if (limitTimeDiscount.discountPriority == "vip-price") {
//会员价优先
if (useVipPrice) {
//使用会员价
return returnMemberPrice(useVipPrice, goods);
} else {
//不使用会员价
const result = BigNumber(goods.salePrice)
.times(discountRate)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
return result;
}
}
} else {
//不可以使用限时折扣
//会员价优先
if (useVipPrice) {
//使用会员价
return returnMemberPrice(useVipPrice, goods);
} else {
return goods.salePrice;
}
}
}
/**
* 计算商品计算门槛时的金额
*/
export function returnCalcPrice(
goods: BaseCartItem,
fullReductionActivitie: FullReductionActivity | undefined,
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined,
useVipPrice: boolean,
idKey = "product_id"
) {
if (goods.discountSaleAmount && goods.discountSaleAmount * 1 > 0) {
return goods.salePrice;
}
//限时折扣和满减活动都有
if (fullReductionActivitie && limitTimeDiscount) {
if (
fullReductionActivitie.discountShare == 1 &&
fullReductionActivitie.vipPriceShare == 1
) {
//与限时折扣同享,与会员价不同享
return returnLimitPrice(goods, limitTimeDiscount, useVipPrice);
}
if (
fullReductionActivitie.discountShare != 1 &&
fullReductionActivitie.vipPriceShare == 1
) {
//与限时折扣不同享,与会员价同享
return returnMemberPrice(useVipPrice, goods);
}
if (fullReductionActivitie.vipPriceShare != 1) {
//与会员价不同享
return goods.salePrice;
}
return goods.salePrice;
}
//只有满减活动
if (fullReductionActivitie) {
if (fullReductionActivitie.vipPriceShare == 1) {
return returnMemberPrice(useVipPrice, goods);
} else {
return goods.salePrice;
}
}
//只有限时折扣
if (limitTimeDiscount) {
return returnLimitPrice(goods, limitTimeDiscount, useVipPrice);
}
if (useVipPrice) {
return returnMemberPrice(useVipPrice, goods);
}
return goods.salePrice;
}
/**
* 计算满减活动门槛
*/
export function calcFullReductionActivityFullAmount(
goodsList: BaseCartItem[],
fullReductionActivitie: FullReductionActivity | undefined,
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined,
useVipPrice: boolean
): number {
if (!fullReductionActivitie) {
return 0;
}
let amount = 0;
for (let goods of goodsList) {
const availableNum = Math.max(0, goods.number - (goods.returnNum || 0));
if (goods.is_temporary || goods.is_gift || availableNum <= 0) {
//临时菜,赠菜,数量<=0的商品不计算
continue;
}
const calcPrice = returnCalcPrice(
goods,
fullReductionActivitie,
limitTimeDiscount,
useVipPrice,
"product_id"
);
if (calcPrice !== undefined) {
amount += calcPrice * availableNum;
}
}
return amount;
console.log("amount", amount);
}
/** /**
* 筛选最优满减活动(对齐后端逻辑:状态→时间→周期→时段→就餐类型→排序→修改时间) * 筛选最优满减活动(对齐后端逻辑:状态→时间→周期→时段→就餐类型→排序→修改时间)
* @param activities 后端返回的满减活动列表 * @param activities 后端返回的满减活动列表
@@ -424,11 +643,16 @@ export function filterOptimalFullReductionActivity(
activity.thresholds?.length // 至少有一个满减阈值 activity.thresholds?.length // 至少有一个满减阈值
); );
}); });
console.log("baseEligible", baseEligible);
if (!baseEligible.length) return undefined; if (!baseEligible.length) return undefined;
// 第二步:时间筛选(有效期内+周期内+时段内) // 第二步:时间筛选(有效期内+周期内+时段内)
const timeEligible = baseEligible.filter((activity) => { const timeEligible = baseEligible.filter((activity) => {
// 1. 校验有效期validStartTime ~ validEndTime // 1. 校验有效期validStartTime ~ validEndTime
if (activity.useTimeType == "all") {
return true;
}
if (!activity.validStartTime || !activity.validEndTime) return false; if (!activity.validStartTime || !activity.validEndTime) return false;
const startDate = new Date(activity.validStartTime); const startDate = new Date(activity.validStartTime);
const endDate = new Date(activity.validEndTime); const endDate = new Date(activity.validEndTime);
@@ -665,11 +889,12 @@ export function calcCouponThresholdAmount(
*/ */
export function calcSingleGoodsRealPrice( export function calcSingleGoodsRealPrice(
goods: BaseCartItem, goods: BaseCartItem,
config: Pick<OrderExtraConfig, "isMember" | "memberDiscountRate"> & { config: Pick<
activity?: ActivityConfig; // 商品参与的营销活动如限时折扣按商品ID匹配 OrderExtraConfig,
} "isMember" | "memberDiscountRate" | "limitTimeDiscount"
>
): number { ): number {
const { isMember, memberDiscountRate, activity } = config; const { isMember, memberDiscountRate, limitTimeDiscount: activity } = config;
//如果是增菜价格为0 //如果是增菜价格为0
if (goods.is_gift) { if (goods.is_gift) {
@@ -680,6 +905,7 @@ export function calcSingleGoodsRealPrice(
if (goods.discountSaleAmount && goods.discountSaleAmount > 0) { if (goods.discountSaleAmount && goods.discountSaleAmount > 0) {
return truncateToTwoDecimals(goods.discountSaleAmount); return truncateToTwoDecimals(goods.discountSaleAmount);
} }
console.log("calcSingleGoodsRealPrice:goods", goods);
// 2. 优先级2会员价含会员折扣率SKU会员价优先 // 2. 优先级2会员价含会员折扣率SKU会员价优先
const memberPrice = new BigNumber( const memberPrice = new BigNumber(
@@ -687,12 +913,35 @@ export function calcSingleGoodsRealPrice(
); );
// 3. 优先级3营销活动折扣如限时折扣需按商品ID匹配活动 // 3. 优先级3营销活动折扣如限时折扣需按商品ID匹配活动
const isActivityApplicable = activity let isActivityApplicable = false;
? (activity.applicableProductIds || []).includes(String(goods.product_id)) // 核心修正用商品ID匹配活动 if (activity) {
: false; if (activity.foodType == 1) {
isActivityApplicable = true;
} else {
const canUseGoods = activity.foods?.split(",") || [];
if (canUseGoods.find((v) => v == String(goods.product_id))) {
isActivityApplicable = true;
}
}
}
if (!activity || !isActivityApplicable) { if (!activity || !isActivityApplicable) {
return memberPrice.toNumber(); return memberPrice.toNumber();
} }
//限时折扣优先或者会员价优先但是不是会员或者未开启会员价格时限时折扣优先
if (
activity.discountPriority == "limit-time" ||
(activity.discountPriority == "vip-price" && !isMember)
) {
//限时折扣优先
return truncateToTwoDecimals(
new BigNumber(goods.salePrice)
.multipliedBy(activity.discountRate / 100)
.toNumber()
);
}
if (activity.discountPriority == "vip-price" && isMember) {
return memberPrice.toNumber();
}
// 处理活动与会员的同享/不同享逻辑 // 处理活动与会员的同享/不同享逻辑
if (activity.vipPriceShare) { if (activity.vipPriceShare) {
@@ -751,26 +1000,17 @@ export function calcGoodsOriginalAmount(goodsList: BaseCartItem[]): number {
*/ */
export function calcGoodsRealAmount( export function calcGoodsRealAmount(
goodsList: BaseCartItem[], goodsList: BaseCartItem[],
config: Pick<OrderExtraConfig, "isMember" | "memberDiscountRate">, config: Pick<
activities: ActivityConfig[] = [] OrderExtraConfig,
"isMember" | "memberDiscountRate" | "limitTimeDiscount"
>
): number { ): number {
let total = new BigNumber(0); let total = new BigNumber(0);
for (const goods of goodsList) { for (const goods of goodsList) {
const availableNum = Math.max(0, goods.number - (goods.returnNum || 0)); const availableNum = Math.max(0, goods.number - (goods.returnNum || 0));
if (availableNum <= 0) continue; if (availableNum <= 0) continue;
const realPrice = new BigNumber(calcSingleGoodsRealPrice(goods, config));
// 匹配商品参与的营销活动按商品ID匹配优先商品自身配置
const activity =
goods.activityInfo ??
activities.find(
(act) =>
(act.applicableProductIds || []).includes(String(goods.product_id)) // 核心修正用商品ID匹配活动
);
const realPrice = new BigNumber(
calcSingleGoodsRealPrice(goods, { ...config, activity })
);
total = total.plus(realPrice.multipliedBy(availableNum)); total = total.plus(realPrice.multipliedBy(availableNum));
} }
@@ -968,13 +1208,12 @@ export function calcTotalPackFee(
const packNumber = goods.packNumber ? goods.packNumber * 1 : 0; const packNumber = goods.packNumber ? goods.packNumber * 1 : 0;
let availableNum = Math.max(0, goods.number - (goods.returnNum || 0)); let availableNum = Math.max(0, goods.number - (goods.returnNum || 0));
if (availableNum === 0) continue; if (availableNum === 0) continue;
// 计算单个商品打包数量外卖全打包堂食按配置称重商品≤1 // 计算单个商品打包数量外卖全打包堂食按配置称重商品≤1
let packNum = Math.min(availableNum, packNumber); let packNum = Math.min(availableNum, packNumber);
if(dinnerType === "take-out"){ if (dinnerType === "take-out") {
packNum=availableNum packNum = availableNum;
} }
if (goods.product_type === GoodsType.WEIGHT) { if (goods.product_type === GoodsType.WEIGHT) {
packNum = Math.min(packNum, 1); packNum = Math.min(packNum, 1);
@@ -1066,7 +1305,12 @@ export function calculateOrderCostSummary(
currentTime: Date = new Date() currentTime: Date = new Date()
): OrderCostSummary { ): OrderCostSummary {
//是否使用霸王餐,霸王餐配置 //是否使用霸王餐,霸王餐配置
const { isFreeDine, freeDineConfig } = config; const {
isFreeDine,
freeDineConfig,
limitTimeDiscount,
fullReductionActivities,
} = config;
// ------------------------------ 1. 基础费用计算 ------------------------------ // ------------------------------ 1. 基础费用计算 ------------------------------
const goodsOriginalAmount = calcGoodsOriginalAmount(goodsList); // 商品原价总和 const goodsOriginalAmount = calcGoodsOriginalAmount(goodsList); // 商品原价总和
@@ -1076,13 +1320,17 @@ export function calculateOrderCostSummary(
{ {
isMember: config.isMember, isMember: config.isMember,
memberDiscountRate: config.memberDiscountRate, memberDiscountRate: config.memberDiscountRate,
}, limitTimeDiscount: config.limitTimeDiscount,
activities }
); );
const goodsDiscountAmount = calcGoodsDiscountAmount( const goodsDiscountAmount = calcGoodsDiscountAmount(
goodsOriginalAmount, goodsOriginalAmount,
goodsRealAmount goodsRealAmount
); // 商品折扣金额 ); // 商品折扣金额
//会员折扣
let vipDiscountAmount = 0;
const newUserDiscount = config.newUserDiscount || 0; // 新客立减 const newUserDiscount = config.newUserDiscount || 0; // 新客立减
// ------------------------------ 2. 满减活动计算(核心步骤) ------------------------------ // ------------------------------ 2. 满减活动计算(核心步骤) ------------------------------
@@ -1104,7 +1352,14 @@ export function calculateOrderCostSummary(
const additionalFee = Math.max(0, config.additionalFee); // 附加费 const additionalFee = Math.max(0, config.additionalFee); // 附加费
// 2.2 计算满减基数(先扣新客立减) // 2.2 计算满减基数(先扣新客立减)
let baseAfterNewUserDiscount = new BigNumber(goodsRealAmount) let baseAfterNewUserDiscount = new BigNumber(
limitTimeDiscount &&
limitTimeDiscount.id &&
usedFullReductionActivity &&
!usedFullReductionActivity.discountShare
? goodsRealAmount
: goodsRealAmount
)
.minus(newUserDiscount) .minus(newUserDiscount)
.plus(packFee) .plus(packFee)
.plus(seatFee) .plus(seatFee)
@@ -1114,10 +1369,19 @@ export function calculateOrderCostSummary(
baseAfterNewUserDiscount > 0 ? baseAfterNewUserDiscount : 0; baseAfterNewUserDiscount > 0 ? baseAfterNewUserDiscount : 0;
// 2.3 选择最优满减阈值(多门槛场景) // 2.3 选择最优满减阈值(多门槛场景)
let usedFullReductionActivityFullAmount = 0;
if (usedFullReductionActivity) { if (usedFullReductionActivity) {
//计算当前满减活动的门槛金额
usedFullReductionActivityFullAmount = calcFullReductionActivityFullAmount(
goodsList,
usedFullReductionActivity,
config.limitTimeDiscount,
config.isMember
);
usedFullReductionThreshold = selectOptimalThreshold( usedFullReductionThreshold = selectOptimalThreshold(
usedFullReductionActivity.thresholds, usedFullReductionActivity.thresholds,
baseAfterNewUserDiscount, usedFullReductionActivityFullAmount,
goodsOriginalAmount, goodsOriginalAmount,
goodsRealAmount, goodsRealAmount,
usedFullReductionActivity.discountShare || 0 // 与限时折扣同享规则 usedFullReductionActivity.discountShare || 0 // 与限时折扣同享规则
@@ -1182,27 +1446,23 @@ export function calculateOrderCostSummary(
maxPointDeductionLimit = maxPointDeductionLimit =
maxPointDeductionLimit > 0 ? maxPointDeductionLimit : 0; maxPointDeductionLimit > 0 ? maxPointDeductionLimit : 0;
const pointResult = calcPointDeduction( const pointResult = calcPointDeduction(
config.userPoints, config.userPoints,
config.pointDeductionRule, config.pointDeductionRule,
maxPointDeductionLimit maxPointDeductionLimit
); );
console.log("积分抵扣结果:", pointResult);
pointDeductionAmount = pointResult.deductionAmount; pointDeductionAmount = pointResult.deductionAmount;
usedPoints = pointResult.usedPoints; usedPoints = pointResult.usedPoints;
// 若满减与积分不同享pointsShare=1积分抵扣为0 // 若满减与积分不同享pointsShare=1积分抵扣为0
if (usedFullReductionActivity && !usedFullReductionActivity.pointsShare) { if (usedFullReductionActivity && !usedFullReductionActivity.pointsShare) {
console.log("满减与积分不同享:积分抵扣为0");
pointDeductionAmount = 0; pointDeductionAmount = 0;
usedPoints = 0; usedPoints = 0;
} }
//使用霸王餐 //使用霸王餐
if (isFreeDine && freeDineConfig && freeDineConfig.enable) { if (isFreeDine && freeDineConfig && freeDineConfig.enable) {
console.log("使用霸王餐"); fullReductionAmount = 0;
fullReductionAmount=0;
//不与优惠券同享 //不与优惠券同享
if (!freeDineConfig.withCoupon) { if (!freeDineConfig.withCoupon) {
couponDeductionAmount = 0; couponDeductionAmount = 0;
@@ -1319,10 +1579,12 @@ export function calculateOrderCostSummary(
scoreMaxMoney, scoreMaxMoney,
// 满减活动明细(后端字段) // 满减活动明细(后端字段)
fullReduction: { fullReduction: {
usedFullReductionActivityFullAmount: usedFullReductionActivityFullAmount,
usedActivity: usedFullReductionActivity, usedActivity: usedFullReductionActivity,
usedThreshold: usedFullReductionThreshold, usedThreshold: usedFullReductionThreshold,
actualAmount: truncateToTwoDecimals(fullReductionAmount), actualAmount: truncateToTwoDecimals(fullReductionAmount),
}, },
vipDiscountAmount: vipDiscountAmount, //会员折扣减免金额
merchantReduction: { merchantReduction: {
type: merchantReductionConfig.type, type: merchantReductionConfig.type,
originalConfig: merchantReductionConfig, originalConfig: merchantReductionConfig,

152
utils/order-utils.js Normal file
View File

@@ -0,0 +1,152 @@
import BigNumber from "bignumber.js";
//判断商品是否可以使用限时折扣
export function canUseLimitTimeDiscount(
goods,
limitTimeDiscountRes,
shopInfo,
shopUserInfo,
idKey = "id"
) {
shopInfo=shopInfo||{}
shopUserInfo=shopUserInfo||{}
if (!limitTimeDiscountRes || !limitTimeDiscountRes.id) {
return false;
}
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
if (limitTimeDiscountRes.discountPriority == "limit-time") {
if (
limitTimeDiscountRes.foodType == 1 ||
canUseFoods.includes("" + goods[idKey])
) {
return true;
}
}
if (
limitTimeDiscountRes.discountPriority == "vip-price"
) {
if(shopUserInfo.isVip != 1 || shopInfo.isMemberPrice != 1){
return true;
}
}
return false;
}
/**
* 返回商品显示价格
* @params {*} args 参数对象
* @params {*} args.goods 商品对象
* @params {*} args.shopInfo 店铺信息
* @params {*} args.limitTimeDiscountRes 限时折扣信息
* @params {*} args.shopUserInfo 店铺用户信息
* @returns
*/
export function returnPrice(args) {
let {
goods,
shopInfo,
limitTimeDiscountRes,
shopUserInfo,
idKey = "product_id",
} = args;
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
shopInfo=shopInfo||{}
shopUserInfo=shopUserInfo||{}
if (shopInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
const memberPrice = goods.memberPrice || goods.salePrice;
//是会员而且启用会员价
if (limitTimeDiscountRes) {
//使用限时折扣
//限时折扣优先
if (limitTimeDiscountRes.discountPriority == "limit-time") {
if (
limitTimeDiscountRes.foodType == 1 ||
canUseFoods.includes("" + goods[idKey])
) {
return returnLimitPrice({
price: goods.salePrice,
limitTimeDiscountRes,
});
} else {
return memberPrice;
}
}
if (limitTimeDiscountRes.discountPriority == "vip-price") {
//会员优先
return memberPrice;
}
} else {
//是会员没有限时折扣
return memberPrice;
}
} else {
// console.log('不是会员或者没有启用会员价',goods,limitTimeDiscountRes);
//不是会员或者没有启用会员价
if (
limitTimeDiscountRes &&
limitTimeDiscountRes.id &&
(limitTimeDiscountRes.foodType == 1 ||
canUseFoods.includes("" + goods[idKey]))
) {
const price = returnLimitPrice({
price: goods.salePrice,
limitTimeDiscountRes,
goods: goods,
});
return price;
} else {
return goods.salePrice;
}
}
}
/**
* 返回限时折扣价格
* @params {*} args 参数对象
* @params {*} args.limitTimeDiscountRes 限时折扣信息
* @params {*} args.price 商品价格
* @param {*} args.goods 商品对象
* @returns
*/
export function returnLimitPrice(args) {
const { limitTimeDiscountRes, price, goods } = args;
const discountRate = new BigNumber(
limitTimeDiscountRes.discountRate
).dividedBy(100);
const result = BigNumber(price)
.times(discountRate)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
return result;
}
/**
* 判断是否返回会员价
* @param {*} args 参数对象
* @param {*} args.shopInfo 店铺信息
* @param {*} args.shopUserInfo 店铺用户信息
* @returns
*/
export function canReturnMemberPrice(args) {
const { shopInfo, shopUserInfo } = args;
if (shopInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
return true;
} else {
return false;
}
}
/**
* 返回会员价格
* @param {*} goods
* @returns
*/
export function returnMemberPrice(goods) {
return goods.memberPrice || goods.salePrice;
}