分销问题修复,订单问题修复
This commit is contained in:
@@ -12,41 +12,41 @@ export function returnGoodsPrice(goods, user, shopInfo, limitTimeDiscount) {
|
||||
if (!goods) {
|
||||
return 0;
|
||||
}
|
||||
//是否可以使用会员价
|
||||
const canUseVipPrice =
|
||||
user && user.isVip && user.isMemberPrice && goods.memberPrice * 1 > 0;
|
||||
// 商家改价
|
||||
if (goods.discount_sale_amount * 1 > 0) {
|
||||
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}`)
|
||||
) {
|
||||
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" &&
|
||||
!canUseVipPrice
|
||||
) {
|
||||
if (canUseVipPrice) {
|
||||
return goods.memberPrice;
|
||||
} else {
|
||||
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
|
||||
) {
|
||||
if (canUseVipPrice) {
|
||||
return goods.memberPrice;
|
||||
}
|
||||
return goods.salePrice;
|
||||
@@ -124,12 +124,12 @@ export function returnCanDikouGoodsArr(args) {
|
||||
return v;
|
||||
})
|
||||
.filter((v) => {
|
||||
const canUseNum=v.num-(v.returnNum||0)
|
||||
if(canUseNum <= 0||v.is_temporary==1||v.is_gift==1){
|
||||
return false
|
||||
const canUseNum = v.num - (v.returnNum || 0);
|
||||
if (canUseNum <= 0 || v.is_temporary == 1 || v.is_gift == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true
|
||||
return true;
|
||||
}); // 过滤掉数量<=0的商品,赠菜,临时菜
|
||||
|
||||
return arr;
|
||||
@@ -139,20 +139,19 @@ export function returnCanDikouGoodsArr(args) {
|
||||
* 返回商品是否享用了会员价/会员折扣
|
||||
* @param {*} goods
|
||||
*/
|
||||
function returnGoodsIsUseVipPrice(shopInfo,user,goods) {
|
||||
if(goods.is_time_discount){
|
||||
return false
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
if(shopInfo.isMemberPrice==1&&user.isVip==1){
|
||||
if(goods.memberPrice<=0){
|
||||
return false
|
||||
if (shopInfo.isMemberPrice == 1 && user.isVip == 1) {
|
||||
if (goods.memberPrice <= 0) {
|
||||
return false;
|
||||
}
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,10 +159,15 @@ function returnGoodsIsUseVipPrice(shopInfo,user,goods) {
|
||||
*/
|
||||
function returnCanCalcGoodsList(canCalcGoodsArr, coupon, shopInfo, user) {
|
||||
return canCalcGoodsArr.filter((goods) => {
|
||||
if (!coupon.discountShare && goods.is_time_discount) {
|
||||
console.log("goods");
|
||||
console.log(goods);
|
||||
if (!coupon.discountShare && (goods.is_time_discount||goods.isTimeDiscount)) {
|
||||
return false;
|
||||
}
|
||||
if(!coupon.vipPriceShare&& returnGoodsIsUseVipPrice(shopInfo,user,goods)){
|
||||
if (
|
||||
!coupon.vipPriceShare &&
|
||||
returnGoodsIsUseVipPrice(shopInfo, user, goods)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -240,6 +244,8 @@ export function returnCouponCanUse(args) {
|
||||
shopInfo,
|
||||
user
|
||||
);
|
||||
console.log("canCalcGoodsArr");
|
||||
console.log(canCalcGoodsArr);
|
||||
fullAmount = canCalcGoodsArr.reduce((pre, cur) => {
|
||||
return (
|
||||
pre + returnGoodsPrice(cur, user, shopInfo, limitTimeDiscount) * cur.num
|
||||
@@ -291,8 +297,8 @@ export function returnCouponCanUse(args) {
|
||||
}
|
||||
// 商品兑换券,第二件半价和买一送一判断是否有可用商品
|
||||
if ([2, 4, 5].includes(coupon.type)) {
|
||||
// 没有符合条件的商品
|
||||
if (isDikouAll && canDikouGoodsArr.length === 0) {
|
||||
// 没有符合条件的商品
|
||||
if (isDikouAll && canDikouGoodsArr.length === 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合条件的商品",
|
||||
@@ -304,23 +310,20 @@ export function returnCouponCanUse(args) {
|
||||
reason: "没有符合条件的商品",
|
||||
};
|
||||
}
|
||||
if (coupon.type == 2 ) {
|
||||
if(canCalcGoodsArr.length<=0){
|
||||
if (coupon.type == 2) {
|
||||
if (canCalcGoodsArr.length <= 0) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: "没有符合计算门槛条件的商品",
|
||||
};
|
||||
}
|
||||
if(fullAmount < coupon.fullAmount){
|
||||
if (fullAmount < coupon.fullAmount) {
|
||||
return {
|
||||
canUse: false,
|
||||
reason: `满${coupon.fullAmount}元可用,当前可参与金额${fullAmount}元`,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//商品兑换券是否达到门槛金额
|
||||
if (coupon.type == 2 && goodsOrderPrice < coupon.fullAmount) {
|
||||
|
||||
101
utils/goods.ts
101
utils/goods.ts
@@ -455,18 +455,23 @@ export function returnCanUseLimitTimeDiscount(
|
||||
return false;
|
||||
}
|
||||
const canUseFoods = (limitTimeDiscount.foods || "").split(",");
|
||||
const goodsCanUse =
|
||||
limitTimeDiscount.foodType == 1 || canUseFoods.includes("" + goods[idKey]);
|
||||
if (!goodsCanUse) {
|
||||
return false;
|
||||
}
|
||||
if (limitTimeDiscount.discountPriority == "limit-time") {
|
||||
if (
|
||||
limitTimeDiscount.foodType == 1 ||
|
||||
canUseFoods.includes("" + goods[idKey])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (limitTimeDiscount.discountPriority == "vip-price") {
|
||||
if (!useVipPrice) {
|
||||
return true;
|
||||
}
|
||||
if (useVipPrice && goods.hasOwnProperty("memberPrice")) {
|
||||
if (goods.memberPrice && goods.memberPrice * 1 <= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -512,7 +517,7 @@ function returnLimitPrice(
|
||||
}
|
||||
if (limitTimeDiscount.discountPriority == "vip-price") {
|
||||
//会员价优先
|
||||
if (useVipPrice) {
|
||||
if (useVipPrice && goods.memberPrice && goods.memberPrice * 1 > 0) {
|
||||
//使用会员价
|
||||
return returnMemberPrice(useVipPrice, goods);
|
||||
} else {
|
||||
@@ -598,7 +603,9 @@ export function calcFullReductionActivityFullAmount(
|
||||
goodsList: BaseCartItem[],
|
||||
fullReductionActivitie: FullReductionActivity | undefined,
|
||||
limitTimeDiscount: TimeLimitDiscountConfig | null | undefined,
|
||||
useVipPrice: boolean
|
||||
useVipPrice: boolean,
|
||||
seatFee: number,
|
||||
packFee: number
|
||||
): number {
|
||||
if (!fullReductionActivitie) {
|
||||
return 0;
|
||||
@@ -621,7 +628,7 @@ export function calcFullReductionActivityFullAmount(
|
||||
amount += calcPrice * availableNum;
|
||||
}
|
||||
}
|
||||
return amount;
|
||||
return amount + seatFee + packFee;
|
||||
console.log("amount", amount);
|
||||
}
|
||||
|
||||
@@ -902,6 +909,7 @@ export function calcSingleGoodsRealPrice(
|
||||
>
|
||||
): number {
|
||||
const { isMember, memberDiscountRate, limitTimeDiscount: activity } = config;
|
||||
console.log("activity", activity);
|
||||
|
||||
//如果是增菜价格为0
|
||||
if (goods.is_gift) {
|
||||
@@ -912,7 +920,6 @@ export function calcSingleGoodsRealPrice(
|
||||
if (goods.discountSaleAmount && goods.discountSaleAmount > 0) {
|
||||
return truncateToTwoDecimals(goods.discountSaleAmount);
|
||||
}
|
||||
console.log("calcSingleGoodsRealPrice:goods", goods);
|
||||
|
||||
// 2. 优先级2:会员价(含会员折扣率,SKU会员价优先)
|
||||
const memberPrice = new BigNumber(
|
||||
@@ -934,15 +941,18 @@ export function calcSingleGoodsRealPrice(
|
||||
if (!activity || !isActivityApplicable) {
|
||||
return memberPrice.toNumber();
|
||||
}
|
||||
console.log("isMember", isMember);
|
||||
//限时折扣优先或者会员价优先但是不是会员或者未开启会员价格时限时折扣优先
|
||||
if (
|
||||
activity.discountPriority == "limit-time" ||
|
||||
(activity.discountPriority == "vip-price" && !isMember)
|
||||
(activity.discountPriority == "vip-price" && !isMember) ||
|
||||
(activity.discountPriority == "vip-price" && isMember && !goods.memberPrice)
|
||||
) {
|
||||
//限时折扣优先
|
||||
return truncateToTwoDecimals(
|
||||
new BigNumber(goods.salePrice)
|
||||
.multipliedBy(activity.discountRate / 100)
|
||||
.times(activity.discountRate / 100)
|
||||
.decimalPlaces(2, BigNumber.ROUND_UP)
|
||||
.toNumber()
|
||||
);
|
||||
}
|
||||
@@ -1017,6 +1027,7 @@ export function calcGoodsRealAmount(
|
||||
for (const goods of goodsList) {
|
||||
const availableNum = Math.max(0, goods.number - (goods.returnNum || 0));
|
||||
if (availableNum <= 0) continue;
|
||||
console.log("goods", goods);
|
||||
const realPrice = new BigNumber(calcSingleGoodsRealPrice(goods, config));
|
||||
total = total.plus(realPrice.multipliedBy(availableNum));
|
||||
}
|
||||
@@ -1065,11 +1076,15 @@ export function selectOptimalThreshold(
|
||||
const validThresholds = thresholds.filter((threshold) => {
|
||||
const fullAmount = new BigNumber(threshold.fullAmount || 0);
|
||||
const discountAmount = new BigNumber(threshold.discountAmount || 0);
|
||||
console.log("fullAmount", fullAmount);
|
||||
console.log("discountAmount", discountAmount);
|
||||
|
||||
return (
|
||||
fullAmount.isLessThanOrEqualTo(thresholdBase) &&
|
||||
discountAmount.isGreaterThan(0)
|
||||
);
|
||||
});
|
||||
console.log("validThresholds", validThresholds);
|
||||
|
||||
if (!validThresholds.length) return undefined;
|
||||
|
||||
@@ -1298,9 +1313,11 @@ function calcVipDiscountAmount(
|
||||
if (shopUserInfo.isVip == 1 && shopUserInfo.isMemberPrice != 1) {
|
||||
return 0;
|
||||
}
|
||||
console.log("goodsRealAmount", goodsRealAmount);
|
||||
console.log("discount", (100 - (shopUserInfo.discount || 0)) / 100);
|
||||
return truncateToTwoDecimals(
|
||||
new BigNumber(goodsRealAmount)
|
||||
.multipliedBy((100 - (shopUserInfo.discount || 0)) / 100)
|
||||
.times((100 - (shopUserInfo.discount || 0)) / 100)
|
||||
.decimalPlaces(2, BigNumber.ROUND_UP)
|
||||
.toNumber()
|
||||
);
|
||||
@@ -1348,26 +1365,32 @@ export function calculateOrderCostSummary(
|
||||
limitTimeDiscount: config.limitTimeDiscount,
|
||||
}
|
||||
);
|
||||
|
||||
// 会员折扣减免
|
||||
const vipDiscountAmount = calcVipDiscountAmount(
|
||||
goodsRealAmount,
|
||||
shopUserInfo
|
||||
); // 会员折扣减免金额
|
||||
|
||||
const goodsDiscountAmount = calcGoodsDiscountAmount(
|
||||
goodsOriginalAmount,
|
||||
goodsRealAmount
|
||||
); // 商品折扣金额
|
||||
|
||||
|
||||
|
||||
const newUserDiscount = config.newUserDiscount || 0; // 新客立减
|
||||
|
||||
// 其他费用计算(原有逻辑不变) ------------------------------
|
||||
const packFee = calcTotalPackFee(goodsList, dinnerType); // 打包费
|
||||
let seatFee = calcSeatFee(config.seatFeeConfig); // 餐位费
|
||||
seatFee = dinnerType === "dine-in" ? seatFee : 0; // 外卖不收餐位费
|
||||
const additionalFee = Math.max(0, config.additionalFee); // 附加费
|
||||
|
||||
// ------------------------------ 2. 满减活动计算(核心步骤) ------------------------------
|
||||
let usedFullReductionActivity: FullReductionActivity | undefined;
|
||||
let usedFullReductionThreshold: FullReductionThreshold | undefined;
|
||||
let fullReductionAmount = 0;
|
||||
let usedFullReductionActivityFullAmount = calcFullReductionActivityFullAmount(
|
||||
goodsList,
|
||||
usedFullReductionActivity,
|
||||
config.limitTimeDiscount,
|
||||
config.isMember,
|
||||
seatFee,
|
||||
packFee
|
||||
);
|
||||
|
||||
// 2.1 筛选最优满减活动(后端活动列表、当前店铺、就餐类型、时间)
|
||||
usedFullReductionActivity = filterOptimalFullReductionActivity(
|
||||
config.fullReductionActivities,
|
||||
@@ -1376,12 +1399,6 @@ export function calculateOrderCostSummary(
|
||||
currentTime
|
||||
);
|
||||
|
||||
// 其他费用计算(原有逻辑不变) ------------------------------
|
||||
const packFee = calcTotalPackFee(goodsList, dinnerType); // 打包费
|
||||
let seatFee = calcSeatFee(config.seatFeeConfig); // 餐位费
|
||||
seatFee = dinnerType === "dine-in" ? seatFee : 0; // 外卖不收餐位费
|
||||
const additionalFee = Math.max(0, config.additionalFee); // 附加费
|
||||
|
||||
// 2.2 计算满减基数(先扣新客立减)
|
||||
let baseAfterNewUserDiscount = new BigNumber(
|
||||
limitTimeDiscount &&
|
||||
@@ -1400,14 +1417,15 @@ export function calculateOrderCostSummary(
|
||||
baseAfterNewUserDiscount > 0 ? baseAfterNewUserDiscount : 0;
|
||||
|
||||
// 2.3 选择最优满减阈值(多门槛场景)
|
||||
let usedFullReductionActivityFullAmount = 0;
|
||||
if (usedFullReductionActivity) {
|
||||
//计算当前满减活动的门槛金额
|
||||
usedFullReductionActivityFullAmount = calcFullReductionActivityFullAmount(
|
||||
goodsList,
|
||||
usedFullReductionActivity,
|
||||
config.limitTimeDiscount,
|
||||
config.isMember
|
||||
config.isMember,
|
||||
seatFee,
|
||||
packFee
|
||||
);
|
||||
|
||||
usedFullReductionThreshold = selectOptimalThreshold(
|
||||
@@ -1425,6 +1443,7 @@ export function calculateOrderCostSummary(
|
||||
usedFullReductionThreshold
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------ 3. 优惠券抵扣(适配满减同享规则) ------------------------------
|
||||
let couponDeductionAmount = 0;
|
||||
let productCouponDeduction = 0;
|
||||
@@ -1446,6 +1465,7 @@ export function calculateOrderCostSummary(
|
||||
currentTime,
|
||||
}
|
||||
);
|
||||
console.log("couponResult", couponResult);
|
||||
couponDeductionAmount = couponResult.deductionAmount;
|
||||
productCouponDeduction = couponResult.productCouponDeduction;
|
||||
fullCouponDeduction = couponResult.fullCouponDeduction;
|
||||
@@ -1453,7 +1473,10 @@ export function calculateOrderCostSummary(
|
||||
excludedProductIds = couponResult.excludedProductIds;
|
||||
|
||||
// 若满减与优惠券同享(couponShare=1),才计算优惠券;否则优惠券抵扣为0
|
||||
if (usedFullReductionActivity && !usedFullReductionActivity.couponShare) {
|
||||
if (
|
||||
usedFullReductionThreshold &&
|
||||
(!usedFullReductionActivity || !usedFullReductionActivity.couponShare)
|
||||
) {
|
||||
couponDeductionAmount = 0;
|
||||
productCouponDeduction = 0;
|
||||
fullCouponDeduction = 0;
|
||||
@@ -1486,7 +1509,10 @@ export function calculateOrderCostSummary(
|
||||
pointDeductionAmount = pointResult.deductionAmount;
|
||||
usedPoints = pointResult.usedPoints;
|
||||
// 若满减与积分不同享(pointsShare=1)积分抵扣为0
|
||||
if (usedFullReductionActivity && !usedFullReductionActivity.pointsShare) {
|
||||
if (
|
||||
usedFullReductionThreshold &&
|
||||
(!usedFullReductionActivity || !usedFullReductionActivity.pointsShare)
|
||||
) {
|
||||
pointDeductionAmount = 0;
|
||||
usedPoints = 0;
|
||||
}
|
||||
@@ -1550,6 +1576,17 @@ export function calculateOrderCostSummary(
|
||||
truncateToTwoDecimals(merchantReductionActualAmount)
|
||||
);
|
||||
|
||||
// 会员折扣减免
|
||||
const vipDiscountAmount = calcVipDiscountAmount(
|
||||
new BigNumber(goodsRealAmount)
|
||||
.minus(couponDeductionAmount)
|
||||
.plus(packFee)
|
||||
.plus(seatFee)
|
||||
.minus(newUserDiscount)
|
||||
.minus(fullReductionAmount)
|
||||
.toNumber(),
|
||||
shopUserInfo
|
||||
); // 会员折扣减免金额
|
||||
// ------------------------------ 6. 最终实付金额计算 ------------------------------
|
||||
const finalPayAmountBn = new BigNumber(goodsRealAmount)
|
||||
.minus(newUserDiscount)
|
||||
|
||||
@@ -8,26 +8,32 @@ export function canUseLimitTimeDiscount(
|
||||
shopUserInfo,
|
||||
idKey = "id"
|
||||
) {
|
||||
shopInfo=shopInfo||{}
|
||||
shopUserInfo=shopUserInfo||{}
|
||||
shopInfo = shopInfo || {};
|
||||
shopUserInfo = shopUserInfo || {};
|
||||
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") {
|
||||
if (
|
||||
limitTimeDiscountRes.foodType == 1 ||
|
||||
canUseFoods.includes("" + goods[idKey])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (limitTimeDiscountRes.discountPriority == "vip-price") {
|
||||
if (shopUserInfo.isVip != 1 || shopUserInfo.isMemberPrice != 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
limitTimeDiscountRes.discountPriority == "vip-price"
|
||||
|
||||
) {
|
||||
|
||||
if(shopUserInfo.isVip != 1 || shopInfo.isMemberPrice != 1){
|
||||
|
||||
if (
|
||||
shopUserInfo.isVip == 1 &&
|
||||
shopUserInfo.isMemberPrice == 1 &&
|
||||
goods.memberPrice * 1 <= 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -53,9 +59,10 @@ export function returnPrice(args) {
|
||||
idKey = "product_id",
|
||||
} = args;
|
||||
const canUseFoods = (limitTimeDiscountRes.foods || "").split(",");
|
||||
shopInfo=shopInfo||{}
|
||||
shopUserInfo=shopUserInfo||{}
|
||||
if (shopInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
|
||||
shopInfo = shopInfo || {};
|
||||
shopUserInfo = shopUserInfo || {};
|
||||
|
||||
if (shopUserInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
|
||||
const memberPrice = goods.memberPrice || goods.salePrice;
|
||||
|
||||
//是会员而且启用会员价
|
||||
@@ -76,8 +83,18 @@ export function returnPrice(args) {
|
||||
}
|
||||
}
|
||||
if (limitTimeDiscountRes.discountPriority == "vip-price") {
|
||||
//会员优先
|
||||
return memberPrice;
|
||||
if (goods.memberPrice * 1 > 0) {
|
||||
//会员优先
|
||||
return memberPrice;
|
||||
} else {
|
||||
const price = returnLimitPrice({
|
||||
price: goods.salePrice,
|
||||
limitTimeDiscountRes,
|
||||
goods: goods,
|
||||
});
|
||||
|
||||
return price;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//是会员没有限时折扣
|
||||
@@ -135,7 +152,7 @@ export function returnLimitPrice(args) {
|
||||
*/
|
||||
export function canReturnMemberPrice(args) {
|
||||
const { shopInfo, shopUserInfo } = args;
|
||||
if (shopInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
|
||||
if (shopUserInfo.isMemberPrice == 1 && shopUserInfo.isVip == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
143
utils/util.js
Normal file
143
utils/util.js
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* 手机号脱敏:隐藏中间4位(11位手机号通用)
|
||||
* @param {string} phone - 原始手机号(可带非数字字符,如138-1234-5678)
|
||||
* @returns {string} 脱敏后手机号
|
||||
*/
|
||||
export function desensitizePhone(phone) {
|
||||
// 1. 提取纯数字(过滤非数字字符)
|
||||
const purePhone = (phone || "").replace(/[^\d]/g, "");
|
||||
|
||||
// 2. 边界判断:非11位手机号返回原字符串(或自定义提示)
|
||||
if (purePhone.length !== 11) {
|
||||
console.warn("手机号格式不正确,需11位纯数字");
|
||||
return phone; // 或返回 ''、'手机号格式错误' 等
|
||||
}
|
||||
|
||||
// 3. 脱敏:前3位 + **** + 后4位
|
||||
return purePhone.replace(/(\d{3})(\d{4})(\d{4})/, "$1****$3");
|
||||
}
|
||||
|
||||
/**
|
||||
* 姓名合法性校验
|
||||
* @param {string} name - 待校验的姓名
|
||||
* @returns {Object} 校验结果:{ valid: boolean, msg: string }
|
||||
*/
|
||||
export function validateName(name) {
|
||||
// 1. 空值校验
|
||||
if (!name || name.trim() === '') {
|
||||
return { valid: false, msg: '姓名不能为空' };
|
||||
}
|
||||
const pureName = name.trim();
|
||||
|
||||
// 2. 长度校验(2-6位,含少数民族中间点)
|
||||
if (pureName.length < 2 || pureName.length > 6) {
|
||||
return { valid: false, msg: '姓名长度应为2-6位' };
|
||||
}
|
||||
|
||||
// 3. 正则校验:仅允许中文、少数民族中间点(·),且中间点不能在开头/结尾
|
||||
// 中文范围:[\u4e00-\u9fa5],中间点:[\u00b7](Unicode 标准中间点,非小数点)
|
||||
const nameReg = /^[\u4e00-\u9fa5]+([\u00b7][\u4e00-\u9fa5]+)*$/;
|
||||
if (!nameReg.test(pureName)) {
|
||||
return {
|
||||
valid: false,
|
||||
msg: '姓名仅支持中文和少数民族中间点(·),且不能包含数字、字母或特殊符号'
|
||||
};
|
||||
}
|
||||
|
||||
// 4. 额外限制:中间点不能连续(如“李··四”)
|
||||
if (/[\u00b7]{2,}/.test(pureName)) {
|
||||
return { valid: false, msg: '姓名中的中间点(·)不能连续' };
|
||||
}
|
||||
|
||||
// 校验通过
|
||||
return { valid: true, msg: '姓名格式合法' };
|
||||
}
|
||||
|
||||
/**
|
||||
* 身份证号码合法性校验(支持18位/15位)
|
||||
* @param {string} idCard - 待校验的身份证号
|
||||
* @returns {Object} 校验结果:{ valid: boolean, msg: string, info?: Object }
|
||||
* info 可选返回:{ birthDate: string, gender: string }(出生日期、性别)
|
||||
*/
|
||||
export function validateIdCard(idCard) {
|
||||
// 1. 空值校验
|
||||
if (!idCard || idCard.trim() === '') {
|
||||
return { valid: false, msg: '身份证号码不能为空' };
|
||||
}
|
||||
const pureIdCard = idCard.trim().toUpperCase(); // 统一转为大写(处理X)
|
||||
|
||||
// 2. 格式校验(18位或15位)
|
||||
const id18Reg = /^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))((0[1-9])|([12]\d)|(3[01]))\d{3}([0-9]|X)$/;
|
||||
const id15Reg = /^[1-9]\d{5}\d{2}((0[1-9])|(1[0-2]))((0[1-9])|([12]\d)|(3[01]))\d{3}$/;
|
||||
|
||||
if (!id18Reg.test(pureIdCard) && !id15Reg.test(pureIdCard)) {
|
||||
return {
|
||||
valid: false,
|
||||
msg: '身份证号码格式错误(需18位,最后一位可含X;或15位纯数字)'
|
||||
};
|
||||
}
|
||||
|
||||
// 3. 提取出生日期并校验合法性
|
||||
let birthDateStr, birthDate;
|
||||
if (pureIdCard.length === 18) {
|
||||
// 18位:第7-14位为出生日期(YYYYMMDD)
|
||||
birthDateStr = pureIdCard.slice(6, 14);
|
||||
birthDate = new Date(`${birthDateStr.slice(0,4)}-${birthDateStr.slice(4,6)}-${birthDateStr.slice(6,8)}`);
|
||||
} else {
|
||||
// 15位:第7-12位为出生日期(YYMMDD),补全为YYYYMMDD(19xx或20xx,默认19xx)
|
||||
const year = `19${pureIdCard.slice(6, 8)}`;
|
||||
const month = pureIdCard.slice(8, 10);
|
||||
const day = pureIdCard.slice(10, 12);
|
||||
birthDateStr = `${year}${month}${day}`;
|
||||
birthDate = new Date(`${year}-${month}-${day}`);
|
||||
}
|
||||
|
||||
// 校验出生日期有效性(如20230230 → 日期对象会是Invalid Date)
|
||||
if (
|
||||
isNaN(birthDate.getTime()) ||
|
||||
birthDateStr.slice(0,4) !== birthDate.getFullYear().toString() ||
|
||||
birthDateStr.slice(4,6) !== (birthDate.getMonth() + 1).toString().padStart(2, '0') ||
|
||||
birthDateStr.slice(6,8) !== birthDate.getDate().toString().padStart(2, '0')
|
||||
) {
|
||||
return { valid: false, msg: '身份证中的出生日期无效' };
|
||||
}
|
||||
|
||||
// 4. 18位身份证额外校验:校验码合法性(加权算法)
|
||||
if (pureIdCard.length === 18) {
|
||||
// 加权因子
|
||||
const weightFactors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
||||
// 校验码对应值(0-10 → 10对应X)
|
||||
const checkCodeMap = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
|
||||
// 计算前17位与加权因子的乘积和
|
||||
let sum = 0;
|
||||
for (let i = 0; i < 17; i++) {
|
||||
sum += parseInt(pureIdCard[i]) * weightFactors[i];
|
||||
}
|
||||
// 计算预期校验码
|
||||
const expectedCheckCode = checkCodeMap[sum % 11];
|
||||
// 对比实际校验码(最后一位)
|
||||
if (pureIdCard[17] !== expectedCheckCode) {
|
||||
return { valid: false, msg: '身份证校验码错误,可能是无效身份证' };
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 可选:提取性别(18位第17位,15位第15位;奇数=男,偶数=女)
|
||||
let gender = '';
|
||||
if (pureIdCard.length === 18) {
|
||||
const genderCode = parseInt(pureIdCard[16]);
|
||||
gender = genderCode % 2 === 1 ? '男' : '女';
|
||||
} else {
|
||||
const genderCode = parseInt(pureIdCard[14]);
|
||||
gender = genderCode % 2 === 1 ? '男' : '女';
|
||||
}
|
||||
|
||||
// 校验通过,返回额外信息(出生日期、性别)
|
||||
return {
|
||||
valid: true,
|
||||
msg: '身份证号码合法',
|
||||
info: {
|
||||
birthDate: `${birthDate.getFullYear()}-${(birthDate.getMonth() + 1).toString().padStart(2, '0')}-${birthDate.getDate().toString().padStart(2, '0')}`,
|
||||
gender: gender
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user