代客下单问题修复,积分上传问题修复

This commit is contained in:
2025-12-12 17:56:26 +08:00
parent 9a0164eff6
commit 6f1864771d
29 changed files with 12071 additions and 7571 deletions

View File

@@ -10,4 +10,27 @@ export const pointsShopList = (data) => {
})
}
export const pointsConfig = (data) => {
return request({
url: prveUrl + '/user/point/pointsConfig',
method: 'get',
data: data
})
}
export const userPoints = (data) => {
return request({
url: prveUrl + '/user/point/userPoints',
method: 'get',
data: data
})
}
export const userRecord = (data) => {
return request({
url: prveUrl + '/user/point/userRecord',
method: 'get',
data: data
})
}

View File

@@ -29,7 +29,7 @@
>
<image
@click.stop="()=>{}"
@click.stop="onBack"
class="max-img"
:src="item"
:lazy-load="true"

0
lib/carts.ts Normal file
View File

852
lib/coupon.ts Normal file
View File

@@ -0,0 +1,852 @@
import { BigNumber } from "bignumber.js";
import _ from "lodash";
import {
ShopInfo,
couponCalcParams,
BaseCartItem,
TimeLimitDiscountConfig,
CanDikouGoodsArrArgs,
Coupon,
ShopUserInfo,
GoodsType,
BackendCoupon,
ExchangeCalculationResult,
PointDeductionRule,
OrderCostSummary,
} from "./types";
import { getCompatibleFieldValue } from "./utils";
/**
* 返回商品单价
* @param goods 商品
* @param user 用户信息
* @param {Object} shopInfo
*/
export function returnGoodsPrice(
goods: BaseCartItem,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined
) {
if (!goods) {
return 0;
}
//是否可以使用会员价
const canUseVipPrice =
user &&
user.isVip &&
user.isMemberPrice &&
goods.memberPrice * 1 > 0 &&
shopInfo &&
shopInfo.isMemberPrice;
// 商家改价
if (goods.discount_sale_amount && goods.discount_sale_amount * 1 > 0) {
return goods.salePrice;
}
// 限时折扣
if (limitTimeDiscount && limitTimeDiscount.id) {
//优先使用
// 兼容 isTimeDiscount/is_time_discount这里顺便处理该字段的命名兼容
const isTimeDiscount = getCompatibleFieldValue(
goods,
"isTimeDiscount",
"is_time_discount"
);
if (isTimeDiscount) {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
const canUseFoods = limitTimeDiscount.foods.split(",");
const canUseLimit =
limitTimeDiscount.foodType == 1 ||
canUseFoods.includes(`${goods.productId}`);
if (canUseLimit && limitTimeDiscount.discountPriority == "limit-time") {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
if (canUseLimit && limitTimeDiscount.discountPriority == "vip-price") {
if (canUseVipPrice) {
return goods.memberPrice;
} else {
return new BigNumber(goods.salePrice)
.times(limitTimeDiscount.discountRate / 100)
.decimalPlaces(2, BigNumber.ROUND_UP)
.toNumber();
}
}
}
if (canUseVipPrice) {
return goods.memberPrice;
}
return goods.salePrice;
}
/**
* 返回商品分组
* @param arr 商品列表
*/
export function returnGoodsGroupMap(arr: BaseCartItem[]) {
let map: { [key: string]: BaseCartItem[] } = {};
arr.forEach((v) => {
const key = v.productId + "_" + v.skuId;
if (!map[key]) {
map[key] = [];
}
map[key].push(v);
});
return map;
}
interface CouponTypes {
1: "满减券";
2: "商品券";
3: "折扣券";
4: "第二件半价券";
5: "消费送券";
6: "买一送一券";
7: "固定价格券";
8: "免配送费券";
}
/**
* 优惠券类型1-满减券2-商品兑换券3-折扣券4-第二件半价券5-消费送券6-买一送一券7-固定价格券8-免配送费券
* @param coupon
*/
export function returnCoupType(coupon: Coupon) {
const couponTypes: CouponTypes = {
1: "满减券",
2: "商品券",
3: "折扣券",
4: "第二件半价券",
5: "消费送券",
6: "买一送一券",
7: "固定价格券",
8: "免配送费券",
};
return couponTypes[coupon.type as keyof CouponTypes] || "未知类型";
}
/**
* 返回商品券抵扣后的商品列表
* @param canDikouGoodsArr 可抵扣商品列表
* @param selCoupon 已选择的优惠券列表
* @param user 用户信息
*/
export function returnCanDikouGoodsArr(args: CanDikouGoodsArrArgs) {
const { canDikouGoodsArr, selCoupon, user, shopInfo, limitTimeDiscount } =
args;
const types = [2, 4, 6];
// 收集已抵扣商品并关联对应的优惠券类型
const goodsCouponGoods = selCoupon
.filter((v) => types.includes(v.type))
.reduce((prev: BaseCartItem[], cur) => {
// 给每个抵扣商品添加所属优惠券类型
if (cur && cur.discount) {
const goodsWithType = cur.discount.hasDiscountGoodsArr.map((goods) => ({
...goods,
couponType: cur.type, // 记录该商品是被哪种类型的优惠券抵扣的
}));
prev.push(...goodsWithType);
}
return prev;
}, []);
const arr = _.cloneDeep(canDikouGoodsArr)
.map((v) => {
const findCart = goodsCouponGoods.find((carts) => carts.id == v.id);
if (findCart) {
// 根据优惠券类型判断扣减数量
if ([4, 6].includes(findCart.couponType ?? 0)) {
// 类型4第二件半价或6买一送一数量减2
if (v.num) {
v.num -= 2;
}
} else {
// 其他类型如类型2商品券按原逻辑扣减对应数量
if (v.num) {
v.num -= findCart.num ?? 0;
}
}
}
return v;
})
.filter((v) => {
const canUseNum = (v.num ?? 0) - (v.returnNum || 0);
// 兼容 is_temporary/isTemporary 和 is_gift/isGift
const isTemporary = getCompatibleFieldValue(
v,
"isTemporary",
"is_temporary"
);
const isGift = getCompatibleFieldValue(v, "isGift", "is_gift");
if (canUseNum <= 0 || isTemporary || isGift) {
return false;
}
return true;
}); // 过滤掉数量<=0的商品,赠菜,临时菜
return arr;
}
/**
* 返回商品是否享用了会员价/会员折扣
* @param {*} goods
*/
function returnGoodsIsUseVipPrice(
shopInfo: ShopInfo,
user: ShopUserInfo,
goods: BaseCartItem
) {
// 兼容 isTimeDiscount/is_time_discount
const isTimeDiscount = getCompatibleFieldValue(
goods,
"isTimeDiscount",
"is_time_discount"
);
if (isTimeDiscount) {
return false;
}
if (shopInfo.isMemberPrice != 1 || user.isVip != 1) {
return false;
}
if (shopInfo.isMemberPrice == 1 && user.isVip == 1) {
if (goods.memberPrice <= 0) {
return false;
} else {
return true;
}
}
return false;
}
/**
* 返回可以计算抵扣金额的商品列表
*/
function returnCanCalcGoodsList(
canCalcGoodsArr: BaseCartItem[],
coupon: Coupon,
shopInfo: ShopInfo,
user: ShopUserInfo
) {
return canCalcGoodsArr.filter((goods) => {
// 兼容 isTimeDiscount/is_time_discount
const isTimeDiscount = getCompatibleFieldValue(
goods,
"isTimeDiscount",
"is_time_discount"
);
if (!coupon.discountShare && isTimeDiscount) {
return false;
}
if (
!coupon.vipPriceShare &&
returnGoodsIsUseVipPrice(shopInfo, user, goods)
) {
return false;
}
return true;
});
}
/**
* 判断优惠券是否可使用,并返回不可用原因
*
* @param {Object} args - 函数参数集合
* @param {Array} args.canDikouGoodsArr - 可参与抵扣的商品列表
* @param {Object} args.coupon - 优惠券信息对象
* @param {boolean} args.coupon.use - 优惠券是否启用
* @param {Array} args.coupon.useFoods - 优惠券适用的商品ID列表
* @param {number} args.coupon.fullAmount - 优惠券使用门槛金额
* @param {number} args.coupon.type - 优惠券类型
* @param {number} args.goodsOrderPrice - 订单中所有商品的总金额
* @param {Object} args.user - 用户信息对象
* @param {Object} args.selCoupon - 已经选择的优惠券信息对象
* @param {Object} args.shopInfo
* @param {boolean} args.limitTimeDiscount - 限时折扣
* @returns {Object} - { canUse: boolean, reason: string } 可用状态及不可用原因
*/
export function returnCouponCanUse(args: couponCalcParams) {
let {
canDikouGoodsArr,
coupon,
goodsOrderPrice,
user,
selCoupon,
shopInfo,
isMemberPrice,
limitTimeDiscount,
} = args;
// 优惠券未启用
if (!coupon.use) {
return {
canUse: false,
reason: coupon.noUseRestrictions || "不在可用时间段内",
};
}
if (
limitTimeDiscount &&
limitTimeDiscount.id &&
limitTimeDiscount.foodType == 1 &&
!coupon.discountShare
) {
return {
canUse: false,
reason: coupon.noUseRestrictions || "不可与限时折扣同享",
};
}
// 计算门槛金额
let fullAmount = goodsOrderPrice;
canDikouGoodsArr = returnCanDikouGoodsArr(args);
//优惠券指定门槛商品列表
let canCalcGoodsArr = [...canDikouGoodsArr];
//部分商品参与门槛计算
if (coupon.thresholdFoods.length) {
canCalcGoodsArr = canDikouGoodsArr.filter((v) => {
return coupon.thresholdFoods.find((food) => food.id == v.productId);
});
}
canCalcGoodsArr = returnCanCalcGoodsList(
canCalcGoodsArr,
coupon,
shopInfo,
user
);
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
return (
pre +
returnGoodsPrice(cur, user, shopInfo, limitTimeDiscount) * (cur.num || 0)
);
}, 0);
// 是否全部商品可用
const isDikouAll = coupon.useFoods.length === 0;
// 订单可用商品列表
let canUseGoodsArr: BaseCartItem[] = [];
if (!isDikouAll) {
canUseGoodsArr = canDikouGoodsArr.filter((v) => {
return coupon.useFoods.find((food) => food.id == v.productId);
});
}
// if (user.isVip && !coupon.vipPriceShare) {
// return {
// canUse: false,
// reason: "非会员可用",
// };
// }
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 || 0)) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
}
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
if ([2, 4, 5].includes(coupon.type)) {
// 没有符合条件的商品
if (isDikouAll && canDikouGoodsArr.length === 0) {
return {
canUse: false,
reason: "没有符合条件的商品",
};
}
if (!isDikouAll && canUseGoodsArr.length === 0) {
return {
canUse: false,
reason: "没有符合条件的商品",
};
}
if (coupon.type == 2) {
if (canCalcGoodsArr.length <= 0) {
return {
canUse: false,
reason: "没有符合计算门槛条件的商品",
};
}
if (fullAmount < (coupon.fullAmount || 0)) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
}
}
//商品兑换券是否达到门槛金额
if (coupon.type == 2 && goodsOrderPrice < (coupon.fullAmount || 0)) {
return {
canUse: false,
reason: `${coupon.fullAmount}元可用,当前可参与金额${fullAmount}`,
};
}
// 买一送一券特殊验证
if (coupon.type === 6) {
let canUse = false;
if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => (v.num || 0) >= 2);
} else if (canUseGoodsArr.length > 0) {
canUse = canUseGoodsArr.some((v) => (v.num || 0) >= 2);
}
if (!canUse) {
return {
canUse: false,
reason: "需要购买至少2件相同的商品才能使用",
};
}
}
// 第二件半价券特殊验证
if (coupon.type === 4) {
let canUse = false;
if (isDikouAll) {
canUse = canDikouGoodsArr.some((v) => (v.num || 0) >= 2);
} else if (canUseGoodsArr.length > 0) {
canUse = canUseGoodsArr.some((v) => (v.num || 0) >= 2);
}
if (!canUse) {
return {
canUse: false,
reason: "需要购买至少2件相同的商品才能使用",
};
}
}
// 所有条件都满足
return {
canUse: true,
reason: "",
};
}
/**
* 计算抵扣商品金额
* @param discountGoodsArr 可抵扣商品列表
* @param discountNum 抵扣数量
* @param user 用户信息
* @param {Object} shopInfo 店铺信息
*/
export function calcDiscountGoodsArrPrice(
discountGoodsArr: BaseCartItem[],
discountNum: number,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
let hasCountNum = 0;
let discountPrice = 0;
let hasDiscountGoodsArr:BaseCartItem[] = [];
for (let i = 0; i < discountGoodsArr.length; i++) {
if (hasCountNum >= discountNum) {
break;
}
const goods = discountGoodsArr[i];
const shengyuNum = discountNum - hasCountNum;
const num = Math.min(goods.num || 0, shengyuNum);
const realPrice = returnGoodsPrice(
goods,
user,
shopInfo,
limitTimeDiscount
);
discountPrice += realPrice * num;
hasCountNum += num;
if(goods){
hasDiscountGoodsArr.push({
...goods,
num,
});
}
}
return {
discountPrice,
hasDiscountGoodsArr,
};
}
/**
* 计算优惠券抵扣金额
* @param arr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
* @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表
* @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/
export function returnCouponDiscount(
arr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
goodsOrderPrice: number,
selCoupon: Coupon[],
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
arr = returnCanDikouGoods(arr, user, shopInfo, limitTimeDiscount);
const canDikouGoodsArr = returnCanDikouGoodsArr({
canDikouGoodsArr: arr,
selCoupon,
user,
shopInfo,
limitTimeDiscount,
});
if (coupon.type == 2) {
return returnCouponProductDiscount(
canDikouGoodsArr,
coupon,
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
);
}
}
/**
* 折扣券抵扣金额
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
* @param goodsOrderPrice 商品订单金额
* @param selCoupon 已选择的优惠券列表
* @param limitTimeDiscount 限时折扣
*/
export function returnCouponZhekouDiscount(
canDikouGoodsArr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
goodsOrderPrice: number,
selCoupon: Coupon[],
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
let { discountRate, maxDiscountAmount } = coupon;
maxDiscountAmount = maxDiscountAmount || 0;
// 计算商品优惠券折扣总和使用BigNumber避免精度问题
const goodsCouponDiscount = selCoupon
.filter((v) => v.type == 2)
.reduce((prve, cur) => {
return new BigNumber(prve).plus(
new BigNumber(cur?.discount?.discountPrice || 0)
);
}, new BigNumber(0));
// 将商品订单价格转换为BigNumber并减去优惠券折扣
const adjustedGoodsOrderPrice = new BigNumber(goodsOrderPrice).minus(
goodsCouponDiscount
);
// 计算优惠比例:(100 - 折扣率) / 100
const discountAmountRatio = new BigNumber(100)
.minus(discountRate || 0)
.dividedBy(100);
// 计算折扣金额:调整后的商品订单金额 × 优惠比例
let discountPrice = adjustedGoodsOrderPrice
.times(discountAmountRatio)
.decimalPlaces(2, BigNumber.ROUND_FLOOR)
.toNumber();
// 应用最大折扣金额限制
if (maxDiscountAmount !== 0) {
discountPrice =
discountPrice >= maxDiscountAmount ? maxDiscountAmount : discountPrice;
}
return {
discountPrice, // 折扣抵扣金额(即优惠的金额)
hasDiscountGoodsArr: [],
};
}
/**
* 商品券抵扣金额
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
* @param shopInfo 店铺信息
*/
export function returnCouponProductDiscount(
canDikouGoodsArr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
let { useFoods, discountNum, useRule } = coupon;
discountNum = discountNum || 0;
//抵扣商品数组
let discountGoodsArr:BaseCartItem[] = [];
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoodsArr = canDikouGoodsArr.slice(discountNum * -1).reverse();
} else {
discountGoodsArr = canDikouGoodsArr.slice(0, discountNum);
}
} else {
//抵扣选中商品
const discountSelGoodsArr = canDikouGoodsArr.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") {
discountGoodsArr = discountSelGoodsArr.slice(discountNum * -1).reverse();
} else {
discountGoodsArr = discountSelGoodsArr.slice(0, discountNum);
}
}
const result = calcDiscountGoodsArrPrice(
discountGoodsArr,
discountNum,
user,
shopInfo,
limitTimeDiscount
);
return result;
}
/**
* 返回买一送一券抵扣详情
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
* @param shopInfo 店铺信息
*/
function returnCouponBuyOneGiveOneDiscount(
canDikouGoodsArr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
const { useFoods, useRule } = coupon;
//抵扣商品
let discountGoods:BaseCartItem | undefined = undefined;
//符合买一送一条件的商品(数量>=2 + 非临时/非赠品)
const canUseGoods = canDikouGoodsArr.filter((v) => {
const isTemporary = getCompatibleFieldValue(
v,
"isTemporary",
"is_temporary"
);
const isGift = getCompatibleFieldValue(v, "isGift", "is_gift");
return (v.num || 0) >= 2 && !isTemporary && !isGift;
});
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoods = canUseGoods[canUseGoods.length - 1];
} else {
discountGoods = canUseGoods[0];
}
} else {
//符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else {
discountGoods = canUseGoods1[0];
}
}
let discountPrice = 0;
let hasDiscountGoodsArr: BaseCartItem[] = [];
if (discountGoods) {
discountPrice = returnGoodsPrice(
discountGoods,
user,
shopInfo,
limitTimeDiscount
);
hasDiscountGoodsArr = [discountGoods];
}
return {
discountPrice: discountPrice <= 0 ? 0 : discountPrice,
hasDiscountGoodsArr,
};
}
/**
* 返回第二件半价券抵扣详情
* @param canDikouGoodsArr 可抵扣商品列表
* @param coupon 优惠券
* @param user 用户信息
* @param shopInfo 店铺信息
*/
function returnSecoendDiscount(
canDikouGoodsArr: BaseCartItem[],
coupon: Coupon,
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
const { useFoods, useRule } = coupon;
//抵扣商品
let discountGoods:BaseCartItem | undefined = undefined;
//符合条件的商品(数量>=2 + 非临时/非赠品)
const canUseGoods = canDikouGoodsArr.filter((v) => {
const isTemporary = getCompatibleFieldValue(
v,
"isTemporary",
"is_temporary"
);
const isGift = getCompatibleFieldValue(v, "isGift", "is_gift");
return (v.num || 0) >= 2 && !isTemporary && !isGift;
});
//抵扣全部商品
if (useFoods.length === 0) {
if (useRule == "price_asc") {
discountGoods = canUseGoods[canUseGoods.length - 1];
} else {
discountGoods = canUseGoods[0];
}
} else {
//符合抵扣条件的商品
const canUseGoods1 = canUseGoods.filter((v) =>
useFoods.find((food) => food.id == v.productId)
);
if (useRule == "price_asc") {
discountGoods = canUseGoods1[canUseGoods1.length - 1];
} else {
discountGoods = canUseGoods1[0];
}
}
let discountPrice = 0;
let hasDiscountGoodsArr: BaseCartItem[] = [];
if (discountGoods) {
discountPrice = returnGoodsPrice(
discountGoods,
user,
shopInfo,
limitTimeDiscount
);
hasDiscountGoodsArr = [discountGoods];
}
//返回半价价格
return {
discountPrice:
discountPrice <= 0
? 0
: new BigNumber(discountPrice).dividedBy(2).toNumber(),
hasDiscountGoodsArr,
};
}
/**
* 返回可以抵扣优惠券的商品列表,过滤掉赠品、临时商品,价格从高到低排序
* @param arr 商品列表
* @param user 用户信息
* @param shopInfo 店铺信息
* @param limitTimeDiscount 限时折扣
*/
export function returnCanDikouGoods(
arr: BaseCartItem[],
user: ShopUserInfo,
shopInfo: ShopInfo,
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined
) {
const result = arr
.filter((v) => {
// 兼容 is_temporary/isTemporary 和 is_gift/isGift
const isTemporary = getCompatibleFieldValue(
v,
"isTemporary",
"is_temporary"
);
const isGift = getCompatibleFieldValue(v, "isGift", "is_gift");
return !isTemporary && !isGift;
})
.filter((v) => {
return (v.num || 0) > 0;
})
.sort((a, b) => {
return (
returnGoodsPrice(b, user, shopInfo, limitTimeDiscount) -
returnGoodsPrice(a, user, shopInfo, limitTimeDiscount)
);
});
return result;
}
export const utils = {
returnGoodsPrice,
returnGoodsGroupMap,
returnCoupType,
returnCanDikouGoods,
returnCanDikouGoodsArr,
returnCouponCanUse,
calcDiscountGoodsArrPrice,
returnCouponDiscount,
returnCouponProductDiscount,
returnCouponZhekouDiscount,
};
export default utils;

1275
lib/goods-1.0.47-back.ts Normal file

File diff suppressed because it is too large Load Diff

1388
lib/goods.ts Normal file

File diff suppressed because it is too large Load Diff

11
lib/index.ts Normal file
View File

@@ -0,0 +1,11 @@
export * from "./types";
import OrderPriceCalculator from "./goods";
import couponUtils from "./coupon";
import limitUtils from "./limit";
export { OrderPriceCalculator, couponUtils, limitUtils };
export default {
OrderPriceCalculator,
couponUtils,
limitUtils,
};

216
lib/limit.ts Normal file
View File

@@ -0,0 +1,216 @@
import BigNumber from "bignumber.js";
import _ from "lodash";
import {
BaseCartItem,
ShopUserInfo,
ShopInfo,
TimeLimitDiscountConfig,
CanReturnMemberPriceArgs,
returnPriceArgs,
} from "./types";
/**
* 判断商品是否可以使用限时折扣
* @param goods 商品对象
* @param limitTimeDiscountRes 限时折扣配置
* @param shopInfo 店铺信息
* @param shopUserInfo 店铺用户信息
* @param idKey 商品ID键名默认"id"
* @returns
*/
export function canUseLimitTimeDiscount(
goods: BaseCartItem,
limitTimeDiscountRes: TimeLimitDiscountConfig | null | undefined,
shopInfo: ShopInfo,
shopUserInfo: ShopUserInfo,
idKey = "id" as keyof BaseCartItem
) {
shopInfo = shopInfo || {};
shopUserInfo = shopUserInfo || {};
if(shopInfo.isMemberPrice){
shopUserInfo.isMemberPrice=1
}
if (!limitTimeDiscountRes || !limitTimeDiscountRes.id) {
return false;
}
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
const goodsCanUse =
limitTimeDiscountRes.foodType == 1 ||
canUseFoods.includes(`${goods[idKey]}`);
if (!goodsCanUse) {
return false;
}
if (limitTimeDiscountRes.discountPriority == "limit-time") {
return true;
}
if (limitTimeDiscountRes.discountPriority == "vip-price") {
if (
shopUserInfo.isVip == 1 &&
shopUserInfo.isMemberPrice == 1 &&
goods.memberPrice * 1 > 0
) {
return false;
}
return true;
}
return false;
}
/**
* 返回商品显示价格
* @params {*} args 参数对象
* @params {*} args.goods 商品对象
* @params {*} args.shopInfo 店铺信息
* @params {*} args.limitTimeDiscountRes 限时折扣信息
* @params {*} args.shopUserInfo 店铺用户信息
* @returns
*/
export function returnPrice(args: returnPriceArgs) {
let {
goods,
shopInfo,
limitTimeDiscountRes,
shopUserInfo,
idKey = "product_id",
} = args;
limitTimeDiscountRes = limitTimeDiscountRes || {
foods: "",
foodType: 2,
discountPriority: "",
discountRate: 0,
id: 0,
shopId: 0,
useType: "",
};
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
const includesGoods =
limitTimeDiscountRes.foodType == 1 ||
canUseFoods.includes("" + goods[idKey]);
shopInfo = shopInfo || {};
shopUserInfo = shopUserInfo || {};
if (
shopUserInfo.isMemberPrice == 1 &&
shopUserInfo.isVip == 1 &&
shopInfo.isMemberPrice == 1
) {
const memberPrice = goods.memberPrice || goods.salePrice;
//是会员而且启用会员价
if (limitTimeDiscountRes) {
//使用限时折扣
//限时折扣优先
if (limitTimeDiscountRes.discountPriority == "limit-time") {
if (includesGoods) {
return returnLimitPrice({
price: goods.salePrice,
limitTimeDiscountRes,
});
} else {
return memberPrice;
}
}
if (
limitTimeDiscountRes.discountPriority == "vip-price" &&
includesGoods
) {
if (goods.memberPrice * 1 > 0) {
//会员优先
return memberPrice;
} else {
const price = returnLimitPrice({
price: goods.salePrice,
limitTimeDiscountRes,
goods: goods,
});
return price;
}
} else {
return memberPrice;
}
} else {
//是会员没有限时折扣
return memberPrice;
}
} else {
//不是会员或者没有启用会员价
if (limitTimeDiscountRes && limitTimeDiscountRes.id && includesGoods) {
const price = returnLimitPrice({
price: goods.salePrice,
limitTimeDiscountRes,
goods: goods,
});
return price;
} else {
return goods.salePrice;
}
}
}
interface returnLimitPriceArgs {
limitTimeDiscountRes: TimeLimitDiscountConfig | null | undefined;
price: number;
goods?: BaseCartItem;
}
/**
* 返回限时折扣价格
* @params {*} args 参数对象
* @params {*} args.limitTimeDiscountRes 限时折扣信息
* @params {*} args.price 商品价格
* @param {*} args.goods 商品对象
* @returns
*/
export function returnLimitPrice(args: returnLimitPriceArgs) {
const { limitTimeDiscountRes, price, goods } = args;
const discountRate = new BigNumber(
limitTimeDiscountRes ? limitTimeDiscountRes.discountRate : 100
).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: CanReturnMemberPriceArgs) {
const { shopInfo, shopUserInfo } = args;
if (shopUserInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
return true;
} else {
return false;
}
}
/**
* 返回会员价格
* @param {*} goods
* @returns
*/
export function returnMemberPrice(goods: BaseCartItem) {
return goods.memberPrice || goods.salePrice;
}
export const utils = {
returnPrice,
canUseLimitTimeDiscount,
returnLimitPrice,
canReturnMemberPrice,
returnMemberPrice,
};
export default utils;

0
lib/socket.ts Normal file
View File

430
lib/types.ts Normal file
View File

@@ -0,0 +1,430 @@
/** 商品类型枚举 */
export enum GoodsType {
NORMAL = "normal", // 普通商品
WEIGHT = "weight", // 称重商品
GIFT = "gift", // 赠菜(继承普通商品逻辑,标记用)
EMPTY = "", // 空字符串类型(后端未返回时默认归类为普通商品)
PACKAGE = "package", // 打包商品(如套餐/预打包商品,按普通商品逻辑处理,可扩展特殊规则)
}
/** 优惠券计算结果类型(新增细分字段) */
export interface CouponResult {
deductionAmount: number; // 抵扣金额
excludedProductIds: string[]; // 不适用商品ID列表注意是商品ID非购物车ID
usedCoupon: Coupon | undefined; // 实际使用的优惠券
productCouponDeduction: number; // 新增:商品优惠券抵扣(兑换券等)
fullCouponDeduction: number; // 新增:满减优惠券抵扣
}
/** 兑换券计算结果类型(新增细分字段) */
export interface ExchangeCalculationResult {
deductionAmount: number;
excludedProductIds: string[]; // 不适用商品ID列表商品ID
productCouponDeduction: number; // 新增:兑换券属于商品券,同步记录
}
export interface CouponTypes {
1: "满减券";
2: "商品券";
3: "折扣券";
4: "第二件半价券";
5: "消费送券";
6: "买一送一券";
7: "固定价格券";
8: "免配送费券";
}
/** 优惠券类型枚举 */
export enum CouponType {
FULL_REDUCTION = "full_reduction", // 满减券
DISCOUNT = "discount", // 折扣券
SECOND_HALF = "second_half", // 第二件半价券
BUY_ONE_GET_ONE = "buy_one_get_one", // 买一送一券
EXCHANGE = "exchange", // 商品兑换券
}
/** 后端返回的优惠券原始字段类型 */
export interface BackendCoupon {
id?: number; // 自增主键int64
shopId?: number; // 店铺IDint64
syncId?: number; // 同步Idint64
type?: number; // 优惠券类型1-满减券2-商品兑换券3-折扣券4-第二件半价券5-消费送券6-买一送一券7-固定价格券8-免配送费券
name?: string; // 券名称
useShopType?: string; // 可用门店类型only-仅本店all-所有门店custom-指定门店
useShops?: string; // 可用门店(逗号分隔字符串,如"1,2,3"
useType?: string; // 可使用类型dine堂食/pickup自取/deliv配送/express快递
validType?: string; // 有效期类型fixed固定时间custom自定义时间
validDays?: number; // 有效期(天)
validStartTime?: string; // 有效期开始时间(如"2024-01-01 00:00:00"
validEndTime?: string; // 有效期结束时间
daysToTakeEffect?: number; // 隔天生效
useDays?: string; // 可用周期(如"周一,周二"
useTimeType?: string; // 可用时间段类型all-全时段custom-指定时段
useStartTime?: string; // 可用开始时间(每日)
useEndTime?: string; // 可用结束时间(每日)
getType?: string; // 发放设置:不可自行领取/no可领取/yes
getMode?: string; // 用户领取方式
giveNum?: number; // 总发放数量,-10086为不限量
getUserType?: string; // 可领取用户:全部/all新用户一次/new仅会员/vip
getLimit?: number; // 每人领取限量,-10086为不限量
useLimit?: number; // 每人每日使用限量,-10086为不限量
discountShare?: number; // 与限时折扣同享0-否1-是
vipPriceShare?: number; // 与会员价同享0-否1-是
ruleDetails?: string; // 附加规则说明
status?: number; // 状态0-禁用1-启用
useNum?: number; // 已使用数量
leftNum?: number; // 剩余数量
foods?: string; // 指定门槛商品(逗号分隔字符串,如"101,102"此处为商品ID
fullAmount?: number; // 使用门槛:满多少金额(元)
discountAmount?: number; // 使用门槛:减多少金额(元)
discountRate?: number; // 折扣%如90=9折
maxDiscountAmount?: number; // 可抵扣最大金额(元)
useRule?: string; // 使用规则price_asc-价格低到高price_desc-高到低
discountNum?: number; // 抵扣数量
otherCouponShare?: number; // 与其它优惠共享0-否1-是
createTime?: string; // 创建时间
updateTime?: string; // 更新时间
}
/** 营销活动类型枚举 */
export enum ActivityType {
TIME_LIMIT_DISCOUNT = "time_limit_discount", // 限时折扣
}
/** 基础购物车商品项核心修正新增product_id明确各ID含义 */
export interface BaseCartItem {
id: string | number; // 购物车ID唯一标识购物车中的条目如购物车项主键
product_id: string | number; // 商品ID唯一标识商品用于优惠券/活动匹配,必选)
productId?: string | number; // 商品ID
salePrice: number; // 商品原价(元)
number: number; // 商品数量
num?: number; // 商品数量
isTimeDiscount?: boolean; // 是否限时折扣商品默认false
is_time_discount?: boolean; // 是否限时折扣商品默认false
product_type: GoodsType; // 商品类型
is_temporary?: boolean; // 是否临时菜默认false
isTemporary?: boolean; // 是否临时菜默认false
is_gift?: boolean; // 是否赠菜默认false
isGift?: boolean; // 是否赠菜默认false
returnNum?: number; // 退货数量历史订单用默认0
memberPrice: number; // 商品会员价(元,优先级:商品会员价 > 会员折扣)
discountSaleAmount?: number; // 商家改价后单价(元,优先级最高)
discount_sale_amount?: number; // 商家改价后单价(元,优先级最高)
packFee?: number; // 单份打包费默认0
packNumber?: number; // 堂食打包数量默认0
activityInfo?: {
// 商品参与的营销活动(如限时折扣)
type: ActivityType;
discountRate: number; // 折扣率如0.8=8折
vipPriceShare: boolean; // 是否与会员优惠同享默认false
};
skuData?: {
// SKU扩展数据可选
id: string | number; // SKU ID唯一标识商品规格如颜色/尺寸)
memberPrice: number; // SKU会员价
salePrice?: number; // SKU原价
};
skuId?: string | number; // SKU ID唯一标识商品规格如颜色/尺寸)
couponType?: number; // 优惠券类型1-满减券2-商品兑换券3-折扣券4-第二件半价券5-消费送券6-买一送一券7-固定价格券8-免配送费券
}
export interface CouponFoods {
id: string;
name: string;
images: string;
}
/** 基础优惠券接口(所有券类型继承,包含统一门槛商品字段) */
export interface BaseCoupon {
otherCouponShare?: number; // 与其它优惠共享0-否1-是
id: string | number; // 优惠券ID
type: number; // 工具库字符串枚举由后端couponType转换
name: string; // 对应后端title
available: boolean; // 基于BackendCoupon字段计算的可用性
useShopType?: string; // only-仅本店all-所有门店custom-指定门店
useShops: string[]; // 可用门店ID列表
discountShare: boolean; // 与限时折扣同享0-否1-是(后端字段转换为布尔值)
vipPriceShare: boolean; // 与会员价同享0-否1-是(后端字段转换为布尔值)
useType?: string[]; // 可使用类型dine堂食/pickup自取/deliv配送/express快递
isValid: boolean; // 是否在有效期内
discountAmount?: number; // 减免金额 (满减券有)
fullAmount?: number; // 使用门槛:满多少金额
maxDiscountAmount?: number; // 可抵扣最大金额 元
use: boolean;
discountNum?: number; // 抵扣数量
useRule?: string; // 使用规则price_asc-价格低到高price_desc-高到低
discountRate?: number; // 折扣%如90=9折
noUseRestrictions?: boolean; // 是不可用原因
thresholdFoods: CouponFoods[]; // 门槛商品ID列表空数组=全部商品,非空=指定商品ID
useFoods: CouponFoods[]; // 可用商品ID列表空数组=全部商品,非空=指定商品ID
}
export interface couponDiscount {
discountPrice: number;
hasDiscountGoodsArr: BaseCartItem[];
}
/** 满减券(适配后端字段) */
export interface FullReductionCoupon extends BaseCoupon {
fullAmount: number; // 对应后端fullAmount满减门槛
discountAmount: number; // 对应后端discountAmount减免金额
maxDiscountAmount?: number; // 对应后端maxDiscountAmount最大减免
discount?: couponDiscount;
}
/** 折扣券(适配后端字段) */
export interface DiscountCoupon extends BaseCoupon {
discountRate: number; // 后端discountRate%转小数如90→0.9
maxDiscountAmount: number; // 对应后端maxDiscountAmount最大减免
discount?: couponDiscount;
}
/** 第二件半价券(适配后端字段) */
export interface SecondHalfPriceCoupon extends BaseCoupon {
maxUseCountPerOrder?: number; // 对应后端useLimit-10086=不限)
discount?: couponDiscount;
}
/** 买一送一券(适配后端字段) */
export interface BuyOneGetOneCoupon extends BaseCoupon {
maxUseCountPerOrder?: number; // 对应后端useLimit-10086=不限)
discount?: couponDiscount;
}
/** 商品兑换券(适配后端字段) */
export interface ExchangeCoupon extends BaseCoupon {
deductCount: number; // 对应后端discountNum抵扣数量
sortRule: "low_price_first" | "high_price_first"; // 后端useRule转换
discount?: couponDiscount;
}
/** 所有优惠券类型联合 */
export type Coupon =
| FullReductionCoupon
| DiscountCoupon
| SecondHalfPriceCoupon
| BuyOneGetOneCoupon
| ExchangeCoupon;
/** 营销活动配置如限时折扣applicableProductIds为商品ID列表 */
export interface ActivityConfig {
type: ActivityType;
applicableProductIds?: string[]; // 适用商品ID列表与BaseCartItem.product_id匹配
discountRate: number; // 折扣率如0.8=8折
vipPriceShare: boolean; // 是否与会员优惠同享
}
/** 积分抵扣规则 */
export interface PointDeductionRule {
pointsPerYuan: number; // X积分=1元如100=100积分抵1元
maxDeductionAmount?: number; // 最大抵扣金额(元,默认不限)
}
/** 餐位费配置 */
export interface SeatFeeConfig {
pricePerPerson: number; // 每人餐位费(元)
personCount: number; // 用餐人数默认1
isEnabled: boolean; // 是否启用餐位费默认false
}
/** 商家减免类型枚举 */
export enum MerchantReductionType {
FIXED_AMOUNT = "fixed_amount", // 固定金额减免(如直接减 10 元)
DISCOUNT_RATE = "discount_rate", // 比例折扣减免(如打 9 折,即减免 10%
}
/** 商家减免配置(新增,替代原单一金额字段) */
export interface MerchantReductionConfig {
type: MerchantReductionType; // 减免类型(二选一)
fixedAmount?: number; // 固定减免金额(元,仅 FIXED_AMOUNT 生效≥0
discountRate?: number; // 折扣率(%,仅 DISCOUNT_RATE 生效0-100如 90 代表 9 折)
}
/**商家霸王餐配置 */
export interface FreeDineConfig {
enable: boolean; //是否开启
rechargeThreshold: number; //订单满多少元可以使用
rechargeTimes: number; //充值多少倍免单
withCoupon: boolean; //与优惠券同享
withPoints: boolean; //与积分同享
useType?: string[]; //使用类型 dine-in店内 takeout 自取 post快递takeaway外卖
useShopType?: string; //all 全部 part部分
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 ShopUserInfo {
isVip: number | null; //是否会员
discount: number | null; //用户折扣
isMemberPrice: number | null; //会员折扣与会员价是否同时使用
id?: number; //用户ID
}
/** 订单额外费用配置 */
export interface OrderExtraConfig {
// merchantReduction: number; // 商家减免金额默认0
// 替换原单一金额字段,支持两种减免形式
merchantReduction: MerchantReductionConfig;
additionalFee: number; // 附加费如余额充值、券包默认0
pointDeductionRule: PointDeductionRule; // 积分抵扣规则
seatFeeConfig: SeatFeeConfig; // 餐位费配置
currentStoreId: string; // 当前门店ID用于验证优惠券适用门店
userPoints: number; // 用户当前积分(用于积分抵扣)
isMember: boolean; // 用户是否会员(用于会员优惠)
memberDiscountRate?: number; // 会员折扣率如0.95=95折无会员价时用
newUserDiscount?: number; // 新用户减免金额默认0
fullReductionActivities: FullReductionActivity[]; // 当前店铺的满减活动列表(后端返回结构)
currentDinnerType: "dine-in" | "take-out" | "take-away" | "post"; // 当前就餐类型匹配useType
isFreeDine?: boolean; //是否霸王餐
freeDineConfig?: FreeDineConfig;
limitTimeDiscount?: TimeLimitDiscountConfig; //限时折扣
shopUserInfo: ShopUserInfo; // 用户信息
}
/** 订单费用汇总(修改:补充商家减免类型和明细) */
export interface OrderCostSummary {
goodsList: BaseCartItem[];
// 商品总件数
goodsTotal: number;
totalDiscountAmount: number;
goodsRealAmount: number; // 商品真实原价总和
goodsOriginalAmount: number; // 商品原价总和
goodsDiscountAmount: number; // 商品折扣金额
couponDeductionAmount: number; // 优惠券总抵扣
productCouponDeduction: number; // 商品优惠券抵扣
fullCouponDeduction: number; // 满减优惠券抵扣
pointDeductionAmount: number; // 积分抵扣金额
seatFee: number; // 餐位费
packFee: number; // 打包费
scoreMaxMoney: number; // 积分最大可抵扣金额
// 新增:商家减免明细
merchantReduction: {
type: MerchantReductionType; // 实际使用的减免类型
originalConfig: MerchantReductionConfig; // 原始配置(便于前端展示)
actualAmount: number; // 实际减免金额计算后的值≥0
};
additionalFee: number; // 附加费
finalPayAmount: number; // 最终实付金额
couponUsed?: Coupon; // 实际使用的优惠券
pointUsed: number; // 实际使用的积分
newUserDiscount: number; // 新用户减免金额默认0
dinnerType?: "dine-in" | "take-out"; // 就餐类型(堂食/自取/配送/快递)
config: OrderExtraConfig; // 订单额外费用配置
//满减活动
fullReduction: {
usedFullReductionActivityFullAmount: number; // 计算出的满减活动的门槛金额
usedActivity?: FullReductionActivity; // 实际使用的满减活动
usedThreshold?: FullReductionThreshold; // 实际使用的满减阈值(多门槛中选最优)
actualAmount: number; // 满减实际减免金额(元)
};
vipDiscountAmount: number; //会员折扣减免金额
// 订单原支付金额
orderOriginFinalPayAmount: number; //订单原金额(包含打包费+餐位费)
}
/** 满减活动阈值单条满减规则满X减Y- 对应 MkDiscountThresholdInsertGroupDefaultGroup */
export interface FullReductionThreshold {
activityId?: number; // 关联满减活动ID
fullAmount?: number; // 满多少金额(元,必填)
discountAmount?: number; // 减多少金额(元,必填)
}
/** 满减活动主表 - 对应 Request 接口(后端真实字段) */
export interface FullReductionActivity {
id?: number; // 自增主键后端字段id
shopId?: number; // 店铺ID后端字段shopId
status?: number; // 活动状态1=未开始2=进行中3=已结束后端字段status
sort?: number; // 排序值越大优先级越高后端字段sort
createTime?: string; // 创建时间后端字段createTime格式如"2025-10-14 13:56:07"
updateTime?: string; // 最新修改时间后端字段updateTime用于优先级排序
validStartTime?: string; // 有效期开始时间后端字段validStartTime格式如"2025-10-14"
validEndTime?: string; // 有效期结束时间后端字段validEndTime格式如"2025-12-14"
useType?: string; // 可使用类型后端字段useType如"dine,pickup,deliv,express"
useDays?: string; // 可用周期后端字段useDays如"周一,周二,周三,周四,周五,周六,周日"
useTimeType?: string; // 可用时间段类型后端字段useTimeTypeall=全时段custom=指定时段)
useStartTime?: string; // 每日可用开始时间后端字段useStartTime如"09:00:00"仅custom时有效
useEndTime?: string; // 每日可用结束时间后端字段useEndTime如"22:00:00"仅custom时有效
couponShare?: number; // 与优惠券同享0=否1=是后端字段couponShare
discountShare?: number; // 与限时折扣同享0=否1=是后端字段discountShare
vipPriceShare?: number; // 与会员价同享0=否1=是后端字段vipPriceShare
pointsShare?: number; // 与积分抵扣同享0=否1=是后端字段pointsShare
thresholds?: FullReductionThreshold[]; // 满减阈值列表多门槛后端字段thresholds
isDel?: boolean; // 是否删除0=否1=是后端字段isDel默认false
}
// 辅助枚举星期映射用于useDays校验
export const WEEKDAY_MAP = {
周一: 1,
周二: 2,
周三: 3,
周四: 4,
周五: 5,
周六: 6,
周日: 0, // JS中getDay()返回0=周日
};
export interface ShopInfo {
isMemberPrice: number; // 是否开启会员价 1是开启
[property: string]: any;
}
export interface couponCalcParams {
canDikouGoodsArr: BaseCartItem[];
coupon: Coupon;
user: ShopUserInfo;
shopInfo: ShopInfo;
selCoupon: Coupon[];
goodsOrderPrice: number; //商品订单总价
isMemberPrice: number; // 是否开启会员价 1是开启
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined;
}
export interface CanDikouGoodsArrArgs {
canDikouGoodsArr: BaseCartItem[];
selCoupon: Coupon[];
user: ShopUserInfo;
shopInfo: ShopInfo;
limitTimeDiscount?: TimeLimitDiscountConfig | null | undefined;
}
export interface returnPriceArgs {
goods: BaseCartItem;
selCoupon: Coupon[];
user: ShopUserInfo;
shopInfo: ShopInfo;
shopUserInfo: ShopUserInfo;
limitTimeDiscountRes?: TimeLimitDiscountConfig | null | undefined;
idKey?: keyof BaseCartItem;
}
export interface CanReturnMemberPriceArgs {
shopInfo?: ShopInfo;
shopUserInfo: ShopUserInfo;
}

33
lib/utils.ts Normal file
View File

@@ -0,0 +1,33 @@
/**
* 通用字段兼容工具函数:处理驼峰/下划线命名的字段取值
* @param obj 目标对象(如商品信息 BaseCartItem
* @param camelCaseKey 驼峰命名字段(如 'isTemporary'
* @param snakeCaseKey 下划线命名字段(如 'is_temporary'
* @param defaultValue 默认值(默认 false适配布尔类型字段
* @returns 字段值(优先取存在的字段,无则返回默认值)
*/
export function getCompatibleFieldValue(
obj: Record<string, any>,
camelCaseKey: string,
snakeCaseKey: string,
defaultValue: boolean = false
): boolean {
// 优先判断驼峰字段(如果存在且不是 undefined/null
if (
obj.hasOwnProperty(camelCaseKey) &&
obj[camelCaseKey] !== undefined &&
obj[camelCaseKey] !== null
) {
return Boolean(obj[camelCaseKey]);
}
// 再判断下划线字段
if (
obj.hasOwnProperty(snakeCaseKey) &&
obj[snakeCaseKey] !== undefined &&
obj[snakeCaseKey] !== null
) {
return Boolean(obj[snakeCaseKey]);
}
// 都不存在时返回默认值(布尔类型字段默认 false
return defaultValue;
}

View File

@@ -69,6 +69,8 @@
</view>
</view>
</view>
</view>
</template>
@@ -552,4 +554,9 @@ const showOldPrice = computed(() => {});
text-decoration: line-through;
text-align: right;
}
.total{
padding-top: 32rpx;
border-top: 1px solid #EDEDED;
text-align: right;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,6 @@
<template>
<view>
<view class="card_box">
<view class="card_head_box">
<view class="card_head_item" v-for="(item,index) in 8" :key="index"></view>
</view>
<!-- 先付款 -->
<view class="tabBox" v-if="listinfo.status == 'unpaid'">
@@ -44,6 +41,21 @@
</view>
</view> -->
</view>
<view class="tabBox" v-else-if="listinfo.tableName">
<view class="table" >
<view class="table_left">
<image class="icon"
src="https://czg-qr-order.oss-cn-beijing.aliyuncs.com/confirmOrder/table.png"
mode="aspectFill" />
<text class="title">桌台</text>
</view>
<view class="value" v-if="listinfo.tableName"> {{ listinfo.tableName || '' }} </view>
</view>
</view>
<view class="card">
<!-- 订单头部 -->
<view class="card_item" v-for="(value, key) in listinfo.detailMap" :key="key">
@@ -162,31 +174,57 @@
</view>
</view>
</block>
<block v-else>
<!-- <block v-else>
<view class="cell-item column" v-if="listinfo.discountInfo">
<view class="label">优惠折扣</view>
<view class="val column">
<view class="productCoupon" v-for="(item,index) in listinfo.discountInfo" :key="index">
<view class="name">{{item.name}}</view>
<!-- <view class="num">{{item.amount}}</view> -->
<view class="amount" style="margin-left: 10rpx;">{{item.amount}}</view>
</view>
</view>
</view>
</block>
</block> -->
<view class="total-wrap" v-if="listinfo.status == 'unpaid'">
<view>总计</view>
<view class="price"> {{listinfo.totalCost}} </view>
<text>总计</text>
<text class="u-font-32"></text>
<text class="price"> {{listinfo.totalCost}} </text>
</view>
<view class="total-wrap" v-else>
<view>实付</view>
<view class="price"> {{listinfo.payAmount}} </view>
<view>实付</view>
<text class="u-font-32"></text>
<text class="price"> {{listinfo.payAmount}} </text>
</view>
</view>
</view>
<view class="disocunt " v-if="showDiscount">
<view class="row" v-if="listinfo.productCouponDiscountAmount">
<text class="t">商品券</text>
<text class="info price">-{{listinfo.productCouponDiscountAmount}}</text>
</view>
<view class="row" v-if="listinfo.otherCouponDiscountAmount">
<text class="t">优惠券</text>
<text class="price">-{{listinfo.otherCouponDiscountAmount}}</text>
</view>
<view class="row" v-if="listinfo.pointsDiscountAmount">
<text class="t">积分抵扣</text>
<text class="price">-{{listinfo.pointsDiscountAmount}}</text>
</view>
<view class="row" v-if="listinfo.discountActAmount">
<text class="t">满减活动</text>
<text class="price">-{{listinfo.discountActAmount}}</text>
</view>
<view class="row" v-if="listinfo.newCustomerDiscountAmount">
<text class="t">新客立减</text>
<text class="price">-{{listinfo.newCustomerDiscountAmount}}</text>
</view>
</view>
<view class="orderInfo">
<view class="row" @click="copyHandle(listinfo.orderNo)">
<text class="t">订单编号</text>
@@ -295,6 +333,7 @@
])
const props = defineProps({
freeCheck: {
type: Boolean
@@ -330,6 +369,47 @@
})
/**
* 判断一个对象里的某些属性是否存在且值不等于0满足其中一个就返回true否则false
* @param {Object} obj - 要检测的目标对象若为非对象类型直接返回false
* @param {Array<string>} keys - 要检测的属性名数组(若为非数组/空数组直接返回false
* @returns {boolean} 满足条件返回true否则返回false
*/
function isObjHasPropertyAndNotNull(obj, keys) {
console.log(obj)
// 1. 边界校验obj必须是有效对象keys必须是非空数组
if (
!obj || // 排除null/undefined
typeof obj !== 'object' || // 排除字符串/数字/布尔等非对象类型
!Array.isArray(keys) || // 确保keys是数组
keys.length === 0 // 空数组直接返回false
) {
return false;
}
// 2. 遍历所有要检测的属性
for (const key of keys) {
console.log(obj[key])
// 检查属性是否是对象自身的(排除原型链上的属性) + 属性值不等于0
if (obj.hasOwnProperty(key) && obj[key] !== 0) {
return true; // 只要有一个满足立即返回true
}
}
// 3. 所有属性都不满足条件
return false;
}
const showDiscount = computed(() => {
const keys = ['productCouponDiscountAmount', 'otherCouponDiscountAmount',
'pointsDiscountAmount', 'discountActAmount', 'newCustomerDiscountAmount'
]
if (isObjHasPropertyAndNotNull(props.listinfo, keys)) {
return true
}
return false
})
const is_type = ref(0)
// 监听送餐/打包切换
const tabClick = (item, index) => {
@@ -477,11 +557,9 @@
<style lang="scss" scoped>
.card_box {
background-color: #fff;
// box-shadow: 0rpx 8rpx 12rpx 2rpx rgba(87,86,86,0.35);
position: relative;
width: 100%;
height: 100%;
// box-shadow: 0rpx 4rpx 12rpx 2rpx rgba(87,86,86,0.35);
border-radius: 18rpx;
padding-bottom: 32rpx;
@@ -1050,7 +1128,31 @@
}
}
.disocunt{
background: #FFFFFF;
border-radius: 18rpx 18rpx 18rpx 18rpx;overflow: hidden;
margin-top: 32rpx;
.row{
padding: 16rpx 24rpx;
display: flex;
justify-content: space-between;
.t {
font-weight: bold;
font-size: 28rpx;
color: #333333;
flex-shrink: 0;
}
.info {
font-weight: 400;
font-size: 28rpx;
color: #666666;
}
}
.price {
color: #FF1C1C;
}
}
.orderInfo {
background: #FFFFFF;
border-radius: 18rpx 18rpx 18rpx 18rpx;
@@ -1129,4 +1231,6 @@
}
}
}
</style>

View File

@@ -5,9 +5,7 @@
<view class="left">
<view class="icon">优惠</view>
<view class="text">
充值消费{{ freeDineConfig.rechargeTimes }}订单满{{
freeDineConfig.rechargeThreshold
}}元可用本单立享免单</view
充值消费{{ freeDineConfig.rechargeTimes }}本单立享免单</view
>
</view>
<view @click.stop="()=>{}">
@@ -92,12 +90,11 @@ const changeFree = (e) => {
font-weight: 500;
font-size: 20rpx;
color: #ffffff;
margin-right: 12rpx;
margin-right: 18rpx;
}
.text {
width: 80%;
font-weight: 500;
font-weight: 700;
font-size: 28rpx;
color: #333333;
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,51 +16,32 @@
</view>
</view> -->
<view class="status-wrap">
<view
class="item"
:class="{ active: querForm.statusActiveIndex == 0 }"
@click="tabChange(0)"
>
<view class="item" :class="{ active: querForm.statusActiveIndex == 0 }" @click="tabChange(0)">
<text class="t">商品兑换券 {{ returnSelNumber(0) }}</text>
</view>
<view
class="item"
:class="{ active: querForm.statusActiveIndex == 1 }"
@click="tabChange(1)"
>
<view class="item" :class="{ active: querForm.statusActiveIndex == 1 }" @click="tabChange(1)">
<text class="t">折扣优惠券{{ returnSelNumber(1) }}</text>
</view>
<view
class="icon-wrap"
:style="{
<view class="icon-wrap" :style="{
width: `${100 / statusList.length}%`,
left: `${(100 / statusList.length) * querForm.statusActiveIndex}%`,
}"
>
<image
class="active-icon"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAACKUlEQVR4AaRTS2sTURT+MpkxUzNtRpuYpBsrqbgQH6BYRHGllloQN+5cuNeV6MKfoj9BwYUgIsXHRqE+SluliFLbBqmENJNMMpMm87qecw1NglJse+HMPeee833nce8oIgpFq7wsGt/fCb9eFrtdfmNd1L+9Jc4Vog6E4jcqqM0/R+3zNOwv09jtshdfSx7mDJwKqAMfIvAAEaFVWkLgWjvOEbVdtNa+Epf4wxmFUNTkfqiDGUkqogDu8icKiKS9nQ9jnR8fqM5AwuJJE/G9JhRF05E8dAqIKeDlrsyiWVxg9f+Fum+uzsFZmtnEGIVxKHsGIFn1bAF6ZlQ6I28D9uIrmYSrkodbfETgw6GubZo9Yzk0kR4Fc7IuE8QUFebJKSTSB/kM4UYd1scnKL18QInm4Vk/6W6qiNoOwpZDuoX2elFWXHrzELW5Z+RzJVbPHca+09doIKq0ZQLW+C44iWbm2ZQSNMqozj5F5f1jWCSVGd4fwerstYUXCOplGcsfxponJqHS7Nlm2UyAWAza0AFkzt1A6uhFqEYaoHsR9BLCpg2vukZVr5IU4dV+yU7oRikkTrHDMI9PIHPhJrhQ9Kxugs6hkkhi8Mh5DI9flyCep6ImOt7uxnF6dgypYxMy1hg7S0/yH3FdSL+mpbIw6CVwVSNX7yM/eQfZS7eQu3wb+St3MTJ1D2nq1iicgZbK9YN7rL866PH1qfGBIWj0v/Do4rrR59vK+A0AAP//GfTndQAAAAZJREFUAwCu+SjIaSGpLwAAAABJRU5ErkJggg=="
></image>
}">
<image class="active-icon"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAACKUlEQVR4AaRTS2sTURT+MpkxUzNtRpuYpBsrqbgQH6BYRHGllloQN+5cuNeV6MKfoj9BwYUgIsXHRqE+SluliFLbBqmENJNMMpMm87qecw1NglJse+HMPeee833nce8oIgpFq7wsGt/fCb9eFrtdfmNd1L+9Jc4Vog6E4jcqqM0/R+3zNOwv09jtshdfSx7mDJwKqAMfIvAAEaFVWkLgWjvOEbVdtNa+Epf4wxmFUNTkfqiDGUkqogDu8icKiKS9nQ9jnR8fqM5AwuJJE/G9JhRF05E8dAqIKeDlrsyiWVxg9f+Fum+uzsFZmtnEGIVxKHsGIFn1bAF6ZlQ6I28D9uIrmYSrkodbfETgw6GubZo9Yzk0kR4Fc7IuE8QUFebJKSTSB/kM4UYd1scnKL18QInm4Vk/6W6qiNoOwpZDuoX2elFWXHrzELW5Z+RzJVbPHca+09doIKq0ZQLW+C44iWbm2ZQSNMqozj5F5f1jWCSVGd4fwerstYUXCOplGcsfxponJqHS7Nlm2UyAWAza0AFkzt1A6uhFqEYaoHsR9BLCpg2vukZVr5IU4dV+yU7oRikkTrHDMI9PIHPhJrhQ9Kxugs6hkkhi8Mh5DI9flyCep6ImOt7uxnF6dgypYxMy1hg7S0/yH3FdSL+mpbIw6CVwVSNX7yM/eQfZS7eQu3wb+St3MTJ1D2nq1iicgZbK9YN7rL866PH1qfGBIWj0v/Do4rrR59vK+A0AAP//GfTndQAAAAZJREFUAwCu+SjIaSGpLwAAAABJRU5ErkJggg==">
</image>
</view>
</view>
</view>
<view class="list-wrap">
<view class="tips">
<text class="t"
>使用商品兑换券的商品不再计入同享优惠券门槛和折扣计算</text
>
<text class="t">使用商品兑换券的商品不再计入同享优惠券门槛和折扣计算</text>
</view>
<view class="title-wrap">
<text class="t">可用红包</text>
<text class="n">{{ list.canUseCoupons.length }}</text>
</view>
<view
class="item"
v-for="item in list.canUseCoupons"
:key="item.id"
@click="changeSelCoupon(item)"
>
<view class="item" v-for="item in list.canUseCoupons" :key="item.id" @click="changeSelCoupon(item)">
<view class="top">
<view class="icon">
<couponIcon :item="item" />
@@ -70,29 +51,21 @@
<text class="t">{{ item.name }}</text>
</view>
<view class="view time">
<text class="t"
>{{ dayjs(item.effectStartTime).format("YYYY.M.D") }} -
{{ dayjs(item.effectEndTime).format("YYYY.M.D") }}</text
>
<text class="t">{{ dayjs(item.effectStartTime).format("YYYY.M.D") }} -
{{ dayjs(item.effectEndTime).format("YYYY.M.D") }}</text>
</view>
</view>
<view class="btn">
<view class="active" v-if="isActive(item)">
<up-icon
name="checkmark-circle-fill"
size="24"
color="#FF3232"
></up-icon>
<up-icon name="checkmark-circle-fill" size="24" color="#FF3232"></up-icon>
</view>
<view class="round" v-else></view>
</view>
</view>
<view class="btm">
<view class="left"
>1可适用门店{{ item.useShops }} 2可适用商品{{
<view class="left">1可适用门店{{ item.useShops }} 2可适用商品{{
item.foods
}}3可使用类型{{ convertValuesToLabels(item.useType) }}</view
>
}}3可使用类型{{ convertValuesToLabels(item.useType) }}</view>
<view class="right" @click.stop="showDetailHandle(item)">
<text class="t">查看详情</text>
</view>
@@ -102,11 +75,7 @@
<text class="t">不可用红包</text>
<text class="n">{{ list.noCanUseCoupons.length }}</text>
</view>
<view
class="item disabled"
v-for="item in list.noCanUseCoupons"
:key="item.id"
>
<view class="item disabled" v-for="item in list.noCanUseCoupons" :key="item.id">
<view class="top">
<view class="icon">
<couponIcon :item="item" />
@@ -116,10 +85,8 @@
<text class="t">{{ item.name }}</text>
</view>
<view class="view time">
<text class="t"
>{{ dayjs(item.effectStartTime).format("YYYY.M.D") }} -
{{ dayjs(item.effectEndTime).format("YYYY.M.D") }}</text
>
<text class="t">{{ dayjs(item.effectStartTime).format("YYYY.M.D") }} -
{{ dayjs(item.effectEndTime).format("YYYY.M.D") }}</text>
</view>
</view>
<view class="btn">
@@ -144,17 +111,8 @@
<view class="title">
<text class="t">店铺列表</text>
</view>
<scroll-view
class="popup-list"
direction="vertical"
@scrollend="scrollBottom"
>
<view
class="item"
v-for="item in shopList"
:key="item.shopId"
@click="selectShopHandle(item)"
>
<scroll-view class="popup-list" direction="vertical" @scrollend="scrollBottom">
<view class="item" v-for="item in shopList" :key="item.shopId" @click="selectShopHandle(item)">
<text class="t">{{ item.shopName }}</text>
<text class="intro">地址{{ item.shopAddress }}</text>
</view>
@@ -162,24 +120,16 @@
</scroll-view>
</view>
</u-popup>
<u-popup
:show="showDetail"
round="20"
closeable
@close="showDetail = false"
>
<u-popup :show="showDetail" round="20" closeable @close="showDetail = false">
<view class="shoplist-popup">
<view class="title">
<text class="t">详情说明</text>
</view>
<scroll-view class="popup-list" direction="vertical">
<view class="ul">
<view
class="li"
v-for="(item, index) in selectListItemDetails"
:key="index"
>{{ index + 1 }}{{ item }}</view
>
<view class="li" v-for="(item, index) in selectListItemDetails" :key="index">
{{ index + 1 }}{{ item }}
</view>
</view>
</scroll-view>
</view>
@@ -188,31 +138,41 @@
</template>
<script setup>
import dayjs from "dayjs";
import { ref, reactive, onMounted, computed, watch } from "vue";
import {
import dayjs from "dayjs";
import {
ref,
reactive,
onMounted,
computed,
watch
} from "vue";
import {
onLoad,
onReady,
onShow,
onPageScroll,
onReachBottom,
onBackPress,
} from "@dcloudio/uni-app";
import {
} from "@dcloudio/uni-app";
import {
APIcouponfindByUserId,
APIfindCoupon,
getCouponShops,
} from "@/common/api/member.js";
import { findCoupon } from "@/common/api/market/coupon.js";
import couponIcon from "@/components/coupon-icon/index";
// import * as UTILS from '@/utils/goods-utils.js';
import yskUtils from "ysk-utils";
const UTILS = yskUtils.couponUtils;
import { useCartsStore } from "@/stores/carts.js";
const cartStore = useCartsStore();
} from "@/common/api/member.js";
import {
findCoupon
} from "@/common/api/market/coupon.js";
import couponIcon from "@/components/coupon-icon/index";
// import * as UTILS from '@/utils/goods-utils.js';
import yskUtils from "ysk-utils";
const UTILS = yskUtils.couponUtils;
import {
useCartsStore
} from "@/stores/carts.js";
const cartStore = useCartsStore();
//返回不可用原因
function returnNoUseRestrictions(item) {
//返回不可用原因
function returnNoUseRestrictions(item) {
if (item.noUseRestrictions) {
return item.noUseRestrictions;
}
@@ -220,19 +180,18 @@ function returnNoUseRestrictions(item) {
return item.canuseResult.reason;
}
return "";
}
}
const show = ref(false);
const show = ref(false);
const querForm = ref({
const querForm = ref({
searchValue: "",
shopId: "",
shopName: "",
statusActiveIndex: 0,
});
});
const statusList = ref([
{
const statusList = ref([{
value: 0,
label: "商品兑换券",
bg: "#333333",
@@ -244,43 +203,43 @@ const statusList = ref([
bg: "#F8F8F8",
color: "#999999",
},
]);
const list = reactive({
]);
const list = reactive({
page: 1,
size: 10,
status: "nomore",
data: [],
noCanUseCoupons: [],
canUseCoupons: [],
});
});
const showDetail = ref(false);
const selectListItem = ref("");
const selectListItemDetails = ref([]);
const showDetail = ref(false);
const selectListItem = ref("");
const selectListItemDetails = ref([]);
function showDetailHandle(item) {
function showDetailHandle(item) {
showDetail.value = true;
// 1. 定义每个规则的独立描述仅“其他优惠券”需判断item.type
const ruleList = [];
// 规则1限时折扣同享始终显示
const discountRule = item.discountShare
? "与限时折扣同享"
: "不与限时折扣同享";
const discountRule = item.discountShare ?
"与限时折扣同享" :
"不与限时折扣同享";
ruleList.push(discountRule);
// 规则2会员价/会员折扣同享(始终显示)
const vipRule = item.vipPriceShare
? "与会员价/会员折扣同享"
: "不与会员价/会员折扣同享";
const vipRule = item.vipPriceShare ?
"与会员价/会员折扣同享" :
"不与会员价/会员折扣同享";
ruleList.push(vipRule);
// 规则3其他优惠券同享仅item.type=2时显示
if (item.type === 2) {
const otherCouponRule = item.otherCouponShare
? "与其他优惠券同享"
: "不与其他优惠券同享";
const otherCouponRule = item.otherCouponShare ?
"与其他优惠券同享" :
"不与其他优惠券同享";
ruleList.push(otherCouponRule);
}
const shareRuleText = `${ruleList.join("、")}`;
@@ -316,9 +275,9 @@ function showDetailHandle(item) {
if (item.type == 3) {
selectListItemDetails.value.unshift(`最高抵扣${item.maxDiscountAmount}`);
}
}
}
function returnSelNumber(index) {
function returnSelNumber(index) {
if (index) {
if (couponSel.value.id) {
return "(1)";
@@ -332,23 +291,23 @@ function returnSelNumber(index) {
return "(0)";
}
}
}
// 搜索
function searchHandle() {
}
// 搜索
function searchHandle() {
list.page = 1;
list.status = "nomore";
getCouponList();
}
}
// 切换类型
function tabChange(index) {
// 切换类型
function tabChange(index) {
querForm.value.statusActiveIndex = index;
list.page = 1;
list.status = "nomore";
formatCoupon();
}
}
function changeSelCoupon(item) {
function changeSelCoupon(item) {
if (querForm.value.statusActiveIndex) {
if (couponSel.value.id == item.id) {
couponSel.value = {
@@ -366,39 +325,41 @@ function changeSelCoupon(item) {
goodsCouponSel.value = item;
}
}
}
}
const couponSel = ref({
const couponSel = ref({
id: "",
});
const goodsCouponSel = ref({
});
const goodsCouponSel = ref({
id: "",
});
const quansSelArr = computed(() => {
});
const quansSelArr = computed(() => {
return [couponSel.value, goodsCouponSel.value].filter((v) => v.id);
});
watch(
});
watch(
() => couponSel.value.id,
(newval) => {
formatCoupon();
}
);
watch(
);
watch(
() => goodsCouponSel.value.id,
(newval) => {
formatCoupon();
}
);
function isActive(item) {
);
function isActive(item) {
if (querForm.value.statusActiveIndex) {
return couponSel.value.id == item.id;
} else {
return goodsCouponSel.value.id == item.id;
}
}
}
const couponList = ref([]);
function formatCoupon() {
const couponList = ref([]);
function formatCoupon() {
let canUseGoodsCoupon = [];
let canUseDiscountCoupon = [];
@@ -420,9 +381,9 @@ function formatCoupon() {
for (let i = 0; i < couponList.value.length; i++) {
const coupon = couponList.value[i];
const selCoupon =
querForm.value.statusActiveIndex != 1
? quansSelArr.value.filter((v) => v.type != 2)
: quansSelArr.value.filter((v) => v.type == 2);
querForm.value.statusActiveIndex != 1 ?
quansSelArr.value.filter((v) => v.type != 2) :
quansSelArr.value.filter((v) => v.type == 2);
const canuseResult = UTILS.returnCouponCanUse({
canDikouGoodsArr,
coupon,
@@ -432,7 +393,10 @@ function formatCoupon() {
shopInfo,
limitTimeDiscount: cartStore.limitTimeDiscount,
});
const { canUse, reason } = canuseResult;
const {
canUse,
reason
} = canuseResult;
if (coupon.type == 2) {
if (canUse || goodsCouponSel.value.id == coupon.id) {
canUseGoodsCoupon.push(coupon);
@@ -460,7 +424,7 @@ function formatCoupon() {
v,
user,
goodsOrderPrice,
quansSelArr.value,
quansSelArr.value.filter((v) => v.type != 2),
shopInfo,
cartStore.limitTimeDiscount
);
@@ -477,7 +441,7 @@ function formatCoupon() {
v,
user,
goodsOrderPrice,
quansSelArr.value,
quansSelArr.value.filter((v) => v.type == 2),
shopInfo,
cartStore.limitTimeDiscount
);
@@ -500,10 +464,10 @@ function formatCoupon() {
console.log("noUseGoodsCoupon", noUseGoodsCoupon);
console.log("canUseDiscountCoupon", canUseDiscountCoupon);
console.log("noUseDiscountCoupon", noUseDiscountCoupon);
}
}
// 获取优惠券列表
async function getCouponList() {
// 获取优惠券列表
async function getCouponList() {
try {
uni.showLoading({
title: "加载中...",
@@ -518,24 +482,23 @@ async function getCouponList() {
console.log(error);
}
uni.hideLoading();
}
}
// 店铺列表滚动到底部了
function scrollBottom() {
// 店铺列表滚动到底部了
function scrollBottom() {
console.log("店铺列表滚动到底部了");
}
}
/**
/**
* 将value数组字符串转换为对应的label拼接字符串
* @param {Array} options - 包含value和label的选项数组格式如[{value: 'xxx', label: 'xxx'}, ...]
* @param {string} valueStr - 包含value的数组字符串格式如'["dine","pickup"]'
* @param {string} separator - 标签拼接分隔符,默认值为'、'
* @returns {string} 拼接后的label字符串如"堂食、自取"
*/
function convertValuesToLabels(valueStr, options, separator = "、") {
function convertValuesToLabels(valueStr, options, separator = "、") {
try {
options = [
{
options = [{
value: "dine",
label: "堂食",
},
@@ -589,28 +552,28 @@ function convertValuesToLabels(valueStr, options, separator = "、") {
console.error("转换失败:", error.message);
return ""; // 出错时返回空字符串
}
}
}
// 选择店铺
function selectShopHandle(item) {
// 选择店铺
function selectShopHandle(item) {
querForm.value.shopId = item.shopId;
querForm.value.shopName = item.shopName;
list.page = 1;
show.value = false;
getCouponList();
}
// 获取当前店铺会员信息
const shopList = ref([]);
async function getCouponShopsAjax() {
}
// 获取当前店铺会员信息
const shopList = ref([]);
async function getCouponShopsAjax() {
try {
const res = await getCouponShops();
shopList.value = res;
} catch (error) {
console.log(error);
}
}
}
onShow(() => {
onShow(() => {
const couponArr = cartStore.backendCoupons.filter((v) => v.type != 2);
const goodsCouponArr = cartStore.backendCoupons.filter((v) => v.type == 2);
if (couponArr.length) {
@@ -620,12 +583,12 @@ onShow(() => {
goodsCouponSel.value = goodsCouponArr[0];
}
getCouponList();
});
});
onLoad(() => {
onLoad(() => {
getCouponShopsAjax();
});
watch(
});
watch(
() => quansSelArr.value,
(newval) => {
// getCouponList()
@@ -661,6 +624,16 @@ watch(
};
});
otherCoupon = otherCoupon.map((v) => {
const canuseResult = UTILS.returnCouponCanUse({
canDikouGoodsArr,
coupon:v,
goodsOrderPrice,
user,
selCoupon: goodsCoupon,
shopInfo,
limitTimeDiscount: cartStore.limitTimeDiscount,
});
const discount = UTILS.returnCouponDiscount(
canDikouGoodsArr,
v,
@@ -672,29 +645,56 @@ watch(
);
return {
...v,
canuseResult,
discount,
discountAmount: discount ? discount.discountPrice : v.discountAmount,
};
});
uni.$emit("selCoupon", [...goodsCoupon, ...otherCoupon]);
},
{
let noCanUseCoupon = null
for (let item of otherCoupon) {
console.log('item',item)
if (!item.canuseResult.canUse) {
noCanUseCoupon = item
couponSel.value={id:''}
console.log('couponSel.value',couponSel.value)
return uni.showModal({
title: '提示',
showCancel:false,
content: '优惠券' + item.name + '已不满足使用门槛,已剔除',
success() {
}
})
break
}
}
if(noCanUseCoupon){
return
}
const newArr = [...goodsCoupon, ...otherCoupon]
uni.$emit("selCoupon", newArr);
}, {
deep: true,
}
);
);
</script>
<style>
page {
page {
background-color: #f7f7f7;
}
}
</style>
<style scoped lang="scss">
.container {
.container {
padding: 136upx 28upx 28upx;
}
}
.header-wrap {
.header-wrap {
width: 100%;
background-color: #fff;
position: fixed;
@@ -790,9 +790,9 @@ page {
}
}
}
}
}
.list-wrap {
.list-wrap {
padding-top: 28upx;
.tips {
@@ -963,9 +963,9 @@ page {
}
}
}
}
}
.shoplist-popup {
.shoplist-popup {
padding: 0 28upx 28upx;
.title {
@@ -1058,5 +1058,5 @@ page {
}
}
}
}
}
</style>

View File

@@ -217,7 +217,6 @@
listinfo.discountInfo = tempArray;
}
// 回填先质控
listinfo.pointsDiscountAmount = 0
// console.log(listinfo)
console.log("orderorderInfo list info: ", listinfo);
@@ -686,7 +685,6 @@
position: relative;
width: 100%;
height: 100%;
box-shadow: 0rpx 4rpx 12rpx 2rpx rgba(87, 86, 86, 0.35);
border-radius: 18rpx;
.card_head_box {

View File

@@ -73,16 +73,23 @@
<view class="shop-amount">
<text
class="orderAmount">{{item.status == 'unpaid'?item.originAmount:item.orderAmount}}</text>
<text class="totalNumber">{{item.goods.length}}</text>
<text class="totalNumber">{{totalGoodsNum(item.goods) }}</text>
</view>
</view>
</view>
<!-- <view class="footer-wrap">
<view class="take_food_number u-m-b-16" v-if="item.takeCode">
<text class="u-font-24 color-333"> 取餐号</text>
<text class="u-font-32 font-700 color-333">{{item.takeCode}}</text>
</view>
<view class="footer-wrap">
<view class="btn" @click.stop="$u.debounce(isRemoveOrder(item,index),1000)"
v-if="item.status != 'unpaid' && item.status != 'paying'"> 删除订单 </view>
v-if="item.status == 'done' || item.status == 'cancelled'"> 删除订单 </view>
<view class="btn s" @click.stop="$u.debounce(showpopupclick(item),1000)"
v-if="item.status == 'unpaid' || item.status == 'paying'"> 去付款 </view>
</view> -->
<view class="btn s" @click.stop="agignOrder(item)" v-if="item.status == 'done'"> 再来一单 </view>
</view>
</view>
</view>
<view class="flex-colum" v-if="orderForm.list.length <= 0">
@@ -116,14 +123,60 @@
} from '@dcloudio/uni-app'
import Nav from '@/components/CustomNavbar.vue'; //导航栏
import {
APIuserorder
APIuserorder,
APIputuserorder
} from '@/common/api/order/index.js'
// pinia管理
import {
useNavbarStore
} from '@/stores/navbarStore';
import {APIshopUserInfo} from '@/common/api/member.js'
const store = useNavbarStore();
async function agignOrder(item){
await APIshopUserInfo({
shopId:item.shopId
}).then(shopUserInfo=>{
if(shopUserInfo){
uni.cache.set("dinersNum", 1);
uni.cache.set("tableCode", shopUserInfo.id);
uni.cache.set("shopId", item.shopId);
uni.navigateTo({
url: "/pages/product/index?type=beforehand&order_id="+item.id+'&one_more_order=1',
});
}
})
}
function totalGoodsNum(arr){
if(!arr){
return 0
}
return arr.reduce((prve,cur)=>{
return prve+cur.num
},0)
}
function isRemoveOrder(item) {
uni.showModal({
title: '提示',
content: '订单一旦删除不可恢复,确认删除该订单吗?',
showCancel: true,
success(res) {
if (res.confirm) {
APIputuserorder(item.id).then(res => {
uni.showToast({
title: '删除成功',
icon: 'none'
})
setTimeout(() => {
init_fn()
}, 1000)
})
}
}
})
}
// 导航栏
const tabs = [{
name: '全部',
@@ -218,8 +271,8 @@
}
const orderinfo = (e) => {
if(e.status=='unpaid'){
uni.cache.set('shopId',e.shopId)
if (e.status == 'unpaid') {
uni.cache.set('shopId', e.shopId)
uni.pro.navigateTo('order/confirm-order', {
orderId: e.id,
shopId: e.shopId,
@@ -340,7 +393,7 @@
}
.header-wrap {
padding: 16rpx 18rpx;
padding: 32rpx 24rpx;
display: flex;
justify-content: space-between;
align-items: center;
@@ -378,7 +431,7 @@
}
.content {
padding: 0 18rpx 18rpx 18rpx;
padding: 0 24rpx 16rpx 30rpx;
.shop-info {
display: flex;
@@ -450,11 +503,9 @@
padding: 0 18rpx 32rpx 18rpx;
.btn {
width: 128rpx;
height: 48rpx;
line-height: 43rpx;
text-align: center;
background: #FFFFFF;
padding: 6rpx 14rpx;
border-radius: 10rpx 10rpx 10rpx 10rpx;
border: 2rpx solid #EDEDED;
font-weight: 400;
@@ -527,4 +578,10 @@
.ml-20 {
margin-left: 20rpx;
}
.take_food_number{
padding: 20rpx;
background-color: #F8F8F8;
margin-left: 36rpx;
margin-right: 24rpx;
}
</style>

View File

@@ -0,0 +1,43 @@
// 套餐比较两个对象是否相等
export function isObjectEqual(obj1, obj2) {
if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
return obj1 === obj2;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
if (!isArrayEqual(obj1[key], obj2[key])) {
return false;
}
} else if (!isObjectEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}
// 比较两个数组是否相等(忽略顺序)
export function isArrayEqual(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
const usedIndices = new Array(arr2.length).fill(false);
for (const item1 of arr1) {
let found = false;
for (let i = 0; i < arr2.length; i++) {
if (!usedIndices[i] && isObjectEqual(item1, arr2[i])) {
usedIndices[i] = true;
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
<!-- 账单明细 -->
<view style="padding-bottom: 40rpx;">
<up-navbar bgColor="transparent" title="明细" @leftClick="back"></up-navbar>
<view class="bild" >
<view class="bild">
<view class="bg">
<image class="image" src="/static/czzx_header_bg.png" mode=""></image>
</view>
@@ -12,7 +12,7 @@
</view>
<view class="bildRight">
<text>我的积分</text>
<view>{{shopUserInfo.accountPoints||0}}</view>
<view>{{shopUserInfo.pointsUser?shopUserInfo.pointsUser.pointBalance:0}}</view>
</view>
</view>
<view class="bottom">
@@ -109,7 +109,8 @@
} from 'vue'
import {
onReachBottom,onLoad
onReachBottom,
onLoad
} from '@dcloudio/uni-app'
import {
@@ -121,7 +122,7 @@
APIshopUserInfo
} from '@/common/api/member.js'
function back(){
function back() {
uni.navigateBack()
}
const formData = reactive({
@@ -154,7 +155,7 @@
size: formData.form.size,
// status: formData.form.status,
shopId: formData.shopId,
id:formData.id
id: formData.id
})
}
if (res.totalPage == 0 || res.totalPage == 1 && res.totalRow <= 10) {
@@ -201,27 +202,28 @@
getlist()
})
const shopUserInfo=reactive({})
async function getShopUserInfo(){
const res=await APIshopUserInfo({
const shopUserInfo = reactive({})
async function getShopUserInfo() {
const res = await APIshopUserInfo({
shopId: options.shopId
})
if(res){
Object.assign(shopUserInfo,res)
if (res) {
Object.assign(shopUserInfo, res)
formData.id =res.pointsUser?res.pointsUser.id:''
formData.shopId =res.pointsUser?res.pointsUser.shopId:''
}
}
const options=reactive({})
onLoad((opt)=>{
Object.assign(options,opt)
console.log('options',options);
const options = reactive({})
onLoad(async (opt) => {
Object.assign(options, opt)
console.log('options', options);
formData.shopId = options.shopId
formData.active = options.type
formData.id=options.id||''
formData.id = options.id || ''
console.log(formData.info)
await getShopUserInfo()
getlist()
getShopUserInfo()
})
</script>
<style scoped lang="less">
@@ -231,19 +233,22 @@
display: flex;
justify-content: space-around;
align-items: center;
position:relative;
.bg{
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
z-index:-1;
.image{
width:100%;
height:100%;
position: relative;
.bg {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: -1;
.image {
width: 100%;
height: 100%;
}
}
.bildLeft,
.bildRight {
font-weight: 400;
@@ -261,12 +266,14 @@
}
}
}
.bottom{
.bottom {
background-color: rgba(255, 255, 255, .3);
padding: 40rpx 28rpx 0 28rpx;
transform: translateY(-140rpx);
border-radius: 74rpx 74rpx 0 0;
}
.navTop {
display: flex;
justify-content: space-around;

View File

@@ -33,7 +33,7 @@
<view class="u-flex">
<view class="color-666 no-wrap">领取方式</view>
<view class="u-m-l-16" v-if="item.goodsCategory=='优惠券'">系统发放</view>
<view class="u-m-l-16" v-else>店内自</view>
<view class="u-m-l-16" v-else>需前往店铺自行兑换领</view>
</view>
<view class="u-flex u-m-t-16 u-col-baseline" v-if="item.goodsCategory=='优惠券'">
<view class="color-666 no-wrap">特别说明</view>
@@ -53,9 +53,12 @@
</view>
</view>
<view style="height: 100px"></view>
<view style="height: 140px"></view>
<view class="fixed-bottom u-flex u-row-center">
<view class="btn" @click="exchangeClick" :class="[isCanExchange?'':'gray']">
<view v-if="isCanExchange" class="btn" @click="exchangeClick" >
{{returnBtmText}}
</view>
<view class="btn gray" v-else >
{{returnBtmText}}
</view>
</view>
@@ -77,7 +80,7 @@
<view class="popup-content-top">
<text class="color-666">领取方式</text>
<text class="u-m-l-16" v-if="item.goodsCategory=='优惠券'">系统发放</text>
<text class="u-m-l-16" v-else>店内自</text>
<text class="u-m-l-16" v-else>需前往店铺自行兑换领</text>
</view>
<view class="goods-info">
<view class="u-flex">
@@ -414,7 +417,7 @@
background-color: #fff;
left: 0;
right: 0;
padding-bottom: calc(env(safe-area-inset-bottom) + 2rpx);
padding-bottom: 40px;
padding-top: 32rpx;
background-color: #fff;
bottom: 0;

View File

@@ -3,7 +3,7 @@
<view v-for="(item, index) in list" :key="index" @click="toDetail(item)">
<template v-if="layout === 'list'">
<view class="item">
<view class="img coupon" v-if="item.goodsCategory=='优惠券'&&item.couponInfo">
<view class="img coupon" v-if="item.goodsCategory=='优惠券'&&item.couponInfo" style="width: 142rpx;">
<couponIcon :item="item.couponInfo" typeKey="couponType" />
</view>
<image class="img" v-else lazy-load :src="item.goodsImageUrl" mode="aspectFill"></image>

View File

@@ -7,7 +7,7 @@
</view>
<view class="u-m-t-22 u-flex u-col-center">
<up-image width="132rpx" height="132rpx" :src="item.goodsImageUrl" v-if="item.goodsCategory!='优惠券'"></up-image>
<view class="img" v-else>
<view class="img" style="width: 138rpx;" v-else>
<couponIcon :item="item.couponInfo" typeKey="couponType" />
</view>
<view class="u-p-l-36">

View File

@@ -10,13 +10,17 @@
<view class="u-p-l-28 u-flex-1">
<view class="font-bold">{{item.pointsGoodsName}}</view>
<view class="u-flex u-row-between u-m-t-8">
<text class="color1 font-bold">{{item.spendPoints}}积分</text>
<view class="u-flex color1 font-bold">
<text >{{item.spendPoints}}积分</text>
<text v-if="item.extraPaymentAmount">+ {{item.extraPaymentAmount}}</text>
</view>
<text class="status " :class="[returnStatusClass(item)]">{{item.status}}</text>
</view>
<view class="u-m-t-8 font-bold color1"> X{{item.number}} </view>
</view>
</view>
<template v-if="item.goodsCategory=='其它商品'&&item.status!='已退款'">
<template v-if="item.goodsCategory=='其它商品'&&item.status!='已退款'&&item.status!='已完成'">
<view class="u-m-t-16">
<view class="u-flex u-row-center">
<up-qrcode cid="ex1" :size="104" :val="qrcode"></up-qrcode>

View File

@@ -13,7 +13,7 @@
<up-loadmore :status="isEnd?'nomore':'loadmore'"></up-loadmore>
</view>
<modal v-model="modalData.show" title="立即兑换确认" :showBottom="false">
<modal v-model="modalData.show" title="查看券码" :showBottom="false">
<view class="u-p-28">
<view class="u-flex u-row-center">
<up-qrcode cid="ex1" :size="104" :val="qrcode"></up-qrcode>

View File

@@ -93,6 +93,9 @@ export const useWebSocket = defineStore('socketTask', () => {
function setOnMessage(onMessageBallBack){
onMessage=onMessageBallBack
}
function chnageInitMessage(data){
initMessage=data
}
// 连接 WebSocket
const connect = async (connectMsg, onMessageBallBack) => {
if (!isNetworkConnected.value) {
@@ -363,6 +366,6 @@ export const useWebSocket = defineStore('socketTask', () => {
initNetworkListener,
connect,
allowReconnect,
socketTask,setOnMessage
socketTask,setOnMessage,chnageInitMessage
};
})

View File

@@ -1,4 +1,6 @@
import { defineStore } from "pinia";
import {
defineStore
} from "pinia";
// import yskUtils from 'ysk-utils'
// const {
// OrderPriceCalculator,
@@ -10,11 +12,19 @@ import { defineStore } from "pinia";
// MerchantReductionType,
// GoodsType
// } = yskUtils
import yskUtils from '@/lib/index'
// import yskUtils from 'ysk-utils'
const {
OrderPriceCalculator
} = yskUtils
import yskUtils from 'ysk-utils'
const {OrderPriceCalculator}=yskUtils
import { ref, computed, reactive, watchEffect, watch } from "vue";
import {
ref,
computed,
reactive,
watchEffect,
watch
} from "vue";
import {
productminiApphotsquery,
APIgroupquery,
@@ -35,21 +45,21 @@ export const useCartsStore = defineStore("cart", () => {
// 适配工具库 BaseCartItem 接口的商品数据转换函数
const convertToBaseCartItem = (item) => {
const skuData = item.skuData
? {
const skuData = item.skuData ? {
id: item.skuData.id || item.sku_id,
salePrice: item.skuData.salePrice || 0,
memberPrice: item.skuData.memberPrice || 0,
}
: undefined;
} :
undefined;
const goods = getProductDetails({
...item,
product_id: item.product_id || item.productId,
sku_id: item.skuId || item.sku_id,
});
console.log('convertToBaseCartItem',item)
const discountSaleAmount=item.discount_sale_amount?(item.discount_sale_amount*1) : (item.discountSaleAmount?item.discountSaleAmount*1:0)
console.log('convertToBaseCartItem', item)
const discountSaleAmount = item.discount_sale_amount ? (item.discount_sale_amount * 1) : (item
.discountSaleAmount ? item.discountSaleAmount * 1 : 0)
return {
...item,
id: item.id,
@@ -60,21 +70,19 @@ export const useCartsStore = defineStore("cart", () => {
product_type: item.productType,
is_temporary: !!(item.is_temporary || item.isTemporary),
is_gift: !!(item.is_gift || item.isGift),
is_time_discount: item.is_time_discount || item.isTimeDiscount ,
is_time_discount: item.is_time_discount || item.isTimeDiscount,
returnNum: item.returnNum || 0,
memberPrice: item.memberPrice || 0,
discountSaleAmount:discountSaleAmount,
discountSaleAmount: discountSaleAmount,
packFee: item.packFee || (goods ? goods.packFee : 0) || 0,
packNumber: item.pack_number || item.packNumber || 0,
activityInfo: item.activityInfo
? {
activityInfo: item.activityInfo ? {
type: item.activityInfo.type,
discountRate: OrderPriceCalculator.formatDiscountRate(
item.activityInfo.discountRate
),
vipPriceShare: !!item.activityInfo.vipPriceShare,
}
: undefined,
} : undefined,
skuData,
};
};
@@ -90,8 +98,8 @@ export const useCartsStore = defineStore("cart", () => {
.flat()
.map(convertToBaseCartItem);
console.log('oldOrder.value',oldOrder.value)
if(!oldOrder.value.id){
console.log('oldOrder.value', oldOrder.value)
if (!oldOrder.value.id) {
}
return [...currentGoods, ...giftGoods, ...oldOrderGoods];
@@ -117,8 +125,7 @@ export const useCartsStore = defineStore("cart", () => {
(newval) => {
seatFeeConfig.value.isEnabled = !shopInfo.value.isTableFee;
seatFeeConfig.value.pricePerPerson = shopInfo.value.tableFee || 0;
},
{
}, {
deep: true,
}
);
@@ -130,21 +137,36 @@ export const useCartsStore = defineStore("cart", () => {
() => seatFeeConfig.value,
(newval) => {
console.log("seatFeeConfig", seatFeeConfig.value);
},
{
}, {
deep: true,
}
);
//积分规则
const pointDeductionRule = ref({
enableRewards: 0, //是否开启
pointsPerYuan: 0,
maxDeductionAmount: Infinity,
maxDeductionRatio: 0 ,//积分抵扣比例
minPaymentAmount:0,//门槛
});
function setPointDeductionRule(pointsPerYuan, maxDeductionAmount) {
pointDeductionRule.value.pointsPerYuan = pointsPerYuan;
pointDeductionRule.value.maxDeductionAmount = maxDeductionAmount;
function setPointDeductionRule(args) {
const {
equivalentPoints,
maxDeductionAmount,enableRewards,minPaymentAmount,
maxDeductionRatio
} = args
pointDeductionRule.value.pointsPerYuan =equivalentPoints||0;
pointDeductionRule.value.maxDeductionAmount = maxDeductionAmount||0;
pointDeductionRule.value.maxDeductionRatio = maxDeductionRatio||0;
pointDeductionRule.value.enableRewards = enableRewards||0;
pointDeductionRule.value.minPaymentAmount = minPaymentAmount||0;
}
// 初始配置:默认无减免(固定金额 0 元)
@@ -289,8 +311,8 @@ export const useCartsStore = defineStore("cart", () => {
//购物车商品信息补全初始化
function cartsGoodsInfoInit(arr) {
console.log('cartsGoodsInfoInit',arr)
if(arr&&Array.isArray(arr)){
console.log('cartsGoodsInfoInit', arr)
if (arr && Array.isArray(arr)) {
carts.value = arr
.map((v) => {
return getProductDetails(v);
@@ -321,7 +343,7 @@ export const useCartsStore = defineStore("cart", () => {
if (Message.operate_type == "init") {
console.log("carts init Message", Message);
console.log("carts init", msgData);
if(!oldOrder.value.id){
if (!oldOrder.value.id) {
limitTimeDiscount.value = Message.time_dis_info;
}
cartsGoodsInfoInit(msgData);
@@ -351,8 +373,7 @@ export const useCartsStore = defineStore("cart", () => {
}
// 历史订单
if (Message.operate_type == "clearOrder") {
}
if (Message.operate_type == "clearOrder") {}
// 购物车数据更新从新请求
if (
@@ -372,11 +393,11 @@ export const useCartsStore = defineStore("cart", () => {
});
}
//获取限时折扣
if(Message.operate_type == "time_discount_get"){
if (Message.operate_type == "time_discount_get") {
console.log("time_discount_get", Message.data);
limitTimeDiscount.value = Message.data;
}
if(Message.operate_type == "time_discount_save"){
if (Message.operate_type == "time_discount_save") {
console.log("time_discount_save", Message.data);
limitTimeDiscount.value = Message.data;
}
@@ -431,9 +452,10 @@ export const useCartsStore = defineStore("cart", () => {
return false;
}
const isUse =
shopUserInfo.value.isVip && shopUserInfo.value.isMemberPrice && shopInfo.value.isMemberPrice==1
? true
: false;
shopUserInfo.value.isVip && shopUserInfo.value.isMemberPrice && shopInfo.value
.isMemberPrice == 1 ?
true :
false;
return isUse;
});
@@ -648,7 +670,7 @@ export const useCartsStore = defineStore("cart", () => {
orderCostSummary,
setCoupons,
userPoints,
setUserPoints,
setUserPoints,pointDeductionRule,
setPointDeductionRule,
setOldOrder,
//返回商品信息