From 0725cd2e8a82638a15b275eb462f6e3b209c1e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Mon, 22 Sep 2025 11:15:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(order):=20=E5=AE=9E=E7=8E=B0=E4=BC=98?= =?UTF-8?q?=E6=83=A0=E5=88=B8=E6=99=BA=E8=83=BD=E6=8E=A8=E8=8D=90=E4=B8=8E?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=BA=94=E7=94=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增优惠券智能推荐逻辑,在订单确认页面中根据商品总价自动筛选并推荐最优优惠券。支持以下特性:- 自动识别可用优惠券并排序 - 未选择优惠券时自动应用最优券- 已选优惠券时提示是否存在更优选项 - 支付前再次提醒用户使用可用优惠券 - UI 上显示可用优惠券数量及选择状态 同时更新开发环境 API 地址为本地调试地址。 --- config/env.ts | 2 +- src/shop/orderConfirm/index.tsx | 133 +++++++++++++++++++++++++++++++- src/utils/couponUtils.ts | 26 +++---- 3 files changed, 145 insertions(+), 16 deletions(-) diff --git a/config/env.ts b/config/env.ts index c92883b..44ddb26 100644 --- a/config/env.ts +++ b/config/env.ts @@ -2,7 +2,7 @@ export const ENV_CONFIG = { // 开发环境 development: { - API_BASE_URL: 'https://cms-api.websoft.top/api', + API_BASE_URL: 'http://127.0.0.1:9200/api', APP_NAME: '开发环境', DEBUG: 'true', }, diff --git a/src/shop/orderConfirm/index.tsx b/src/shop/orderConfirm/index.tsx index 399e0c4..769b654 100644 --- a/src/shop/orderConfirm/index.tsx +++ b/src/shop/orderConfirm/index.tsx @@ -106,6 +106,7 @@ const OrderConfirm = () => { if (availableCoupons.length > 0) { const newTotal = parseFloat(goods?.price || '0') * finalQuantity const sortedCoupons = sortCoupons(availableCoupons, newTotal) + const usableCoupons = filterUsableCoupons(sortedCoupons, newTotal) setAvailableCoupons(sortedCoupons) // 检查当前选中的优惠券是否还可用 @@ -115,6 +116,56 @@ const OrderConfirm = () => { title: '当前优惠券不满足使用条件,已自动取消', icon: 'none' }) + + // 🎯 自动推荐新的最优优惠券 + if (usableCoupons.length > 0) { + const bestCoupon = usableCoupons[0] + const discount = calculateCouponDiscount(bestCoupon, newTotal) + + if (discount > 0) { + setSelectedCoupon(bestCoupon) + Taro.showToast({ + title: `已为您重新推荐最优优惠券,可省¥${discount.toFixed(2)}`, + icon: 'success', + duration: 3000 + }) + } + } + } else if (!selectedCoupon && usableCoupons.length > 0) { + // 🔔 如果没有选中优惠券但有可用的,推荐最优的 + const bestCoupon = usableCoupons[0] + const discount = calculateCouponDiscount(bestCoupon, newTotal) + + if (discount > 0) { + setSelectedCoupon(bestCoupon) + Taro.showToast({ + title: `已为您推荐最优优惠券,可省¥${discount.toFixed(2)}`, + icon: 'success', + duration: 3000 + }) + } + } else if (selectedCoupon && usableCoupons.length > 0) { + // 🔍 检查是否有更好的优惠券 + const bestCoupon = usableCoupons[0] + const currentDiscount = calculateCouponDiscount(selectedCoupon, newTotal) + const bestDiscount = calculateCouponDiscount(bestCoupon, newTotal) + + // 如果有更好的优惠券(优惠超过0.01元) + if (bestDiscount > currentDiscount + 0.01 && bestCoupon.id !== selectedCoupon.id) { + Taro.showModal({ + title: '发现更优惠的优惠券', + content: `有更好的优惠券可用,额外节省¥${(bestDiscount - currentDiscount).toFixed(2)},是否更换?`, + success: (res) => { + if (res.confirm) { + setSelectedCoupon(bestCoupon) + Taro.showToast({ + title: '优惠券已更换', + icon: 'success' + }) + } + } + }) + } } } } @@ -165,13 +216,38 @@ const OrderConfirm = () => { // 按优惠金额排序 const total = getGoodsTotal() const sortedCoupons = sortCoupons(transformedCoupons, total) + const usableCoupons = filterUsableCoupons(sortedCoupons, total) setAvailableCoupons(sortedCoupons) + // 🎯 智能推荐:自动应用最优惠的可用优惠券 + if (usableCoupons.length > 0 && !selectedCoupon) { + const bestCoupon = usableCoupons[0] // 已经按优惠金额排序,第一个就是最优的 + const discount = calculateCouponDiscount(bestCoupon, total) + + if (discount > 0) { + setSelectedCoupon(bestCoupon) + + // 显示智能推荐提示 + Taro.showToast({ + title: `已为您推荐最优优惠券,可省¥${discount.toFixed(2)}`, + icon: 'success', + duration: 3000 + }) + } + } + + // 🔔 优惠券提示:如果有可用优惠券,显示提示 + if (usableCoupons.length > 0) { + console.log(`发现${usableCoupons.length}张可用优惠券,已为您推荐最优惠券`) + } + console.log('加载优惠券成功:', { originalData: res, transformedData: transformedCoupons, - sortedData: sortedCoupons + sortedData: sortedCoupons, + usableCoupons: usableCoupons, + recommendedCoupon: usableCoupons[0] || null }) } else { setAvailableCoupons([]) @@ -233,6 +309,35 @@ const OrderConfirm = () => { }) return; } + } else { + // 🔔 支付前最后一次检查:提醒用户是否有可用优惠券 + const total = getGoodsTotal() + const usableCoupons = filterUsableCoupons(availableCoupons, total) + + if (usableCoupons.length > 0) { + const bestCoupon = usableCoupons[0] + const discount = calculateCouponDiscount(bestCoupon, total) + + if (discount > 0) { + // 用模态框提醒用户 + const confirmResult = await new Promise((resolve) => { + Taro.showModal({ + title: '发现可用优惠券', + content: `您有优惠券可使用,可省¥${discount.toFixed(2)},是否使用?`, + success: (res) => resolve(res.confirm), + fail: () => resolve(false) + }) + }) + + if (confirmResult) { + setSelectedCoupon(bestCoupon) + // 使用优惠券后重新计算价格,然后继续支付 + // 注意:这里不直接return,让代码继续执行支付逻辑 + } else { + // 用户选择不使用优惠券,继续支付 + } + } + } } // 构建订单数据 @@ -474,7 +579,31 @@ const OrderConfirm = () => { {selectedCoupon ? `-¥${getCouponDiscount().toFixed(2)}` : '暂未使用'} - + {(() => { + const usableCoupons = filterUsableCoupons(availableCoupons, getGoodsTotal()) + if (usableCoupons.length > 0 && !selectedCoupon) { + return ( + + + {usableCoupons.length}张可用 + + + + ) + } else if (usableCoupons.length > 0) { + return ( + + + 已选择 + + + + ) + } else { + return + } + })() + } )} onClick={() => setCouponVisible(true)} diff --git a/src/utils/couponUtils.ts b/src/utils/couponUtils.ts index 56fd9e3..b39c46c 100644 --- a/src/utils/couponUtils.ts +++ b/src/utils/couponUtils.ts @@ -25,7 +25,7 @@ export const transformCouponData = (coupon: ShopUserCoupon): CouponCardProps => const getTheme = (type?: number): CouponCardProps['theme'] => { switch (type) { case 10: return 'red' // 满减券-红色 - case 20: return 'orange' // 折扣券-橙色 + case 20: return 'orange' // 折扣券-橙色 case 30: return 'green' // 免费券-绿色 default: return 'blue' } @@ -53,7 +53,7 @@ export const transformCouponData = (coupon: ShopUserCoupon): CouponCardProps => * 计算优惠券折扣金额 */ export const calculateCouponDiscount = ( - coupon: CouponCardProps, + coupon: CouponCardProps, totalAmount: number ): number => { // 检查是否满足使用条件 @@ -82,7 +82,7 @@ export const calculateCouponDiscount = ( * 检查优惠券是否可用 */ export const isCouponUsable = ( - coupon: CouponCardProps, + coupon: CouponCardProps, totalAmount: number ): boolean => { // 状态检查 @@ -102,13 +102,13 @@ export const isCouponUsable = ( * 获取优惠券不可用原因 */ export const getCouponUnusableReason = ( - coupon: CouponCardProps, + coupon: CouponCardProps, totalAmount: number ): string => { if (coupon.status === 1) { return '优惠券已使用' } - + if (coupon.status === 2) { return '优惠券已过期' } @@ -151,30 +151,30 @@ export const formatCouponTitle = (coupon: CouponCardProps): string => { * 按照优惠金额从大到小排序,同等优惠金额按过期时间排序 */ export const sortCoupons = ( - coupons: CouponCardProps[], + coupons: CouponCardProps[], totalAmount: number ): CouponCardProps[] => { return [...coupons].sort((a, b) => { // 先按可用性排序 const aUsable = isCouponUsable(a, totalAmount) const bUsable = isCouponUsable(b, totalAmount) - + if (aUsable && !bUsable) return -1 if (!aUsable && bUsable) return 1 - + // 都可用或都不可用时,按优惠金额排序 const aDiscount = calculateCouponDiscount(a, totalAmount) const bDiscount = calculateCouponDiscount(b, totalAmount) - + if (aDiscount !== bDiscount) { return bDiscount - aDiscount // 优惠金额大的在前 } - + // 优惠金额相同时,按过期时间排序(即将过期的在前) if (a.endTime && b.endTime) { return new Date(a.endTime).getTime() - new Date(b.endTime).getTime() } - + return 0 }) } @@ -183,7 +183,7 @@ export const sortCoupons = ( * 过滤可用优惠券 */ export const filterUsableCoupons = ( - coupons: CouponCardProps[], + coupons: CouponCardProps[], totalAmount: number ): CouponCardProps[] => { return coupons.filter(coupon => isCouponUsable(coupon, totalAmount)) @@ -193,7 +193,7 @@ export const filterUsableCoupons = ( * 过滤不可用优惠券 */ export const filterUnusableCoupons = ( - coupons: CouponCardProps[], + coupons: CouponCardProps[], totalAmount: number ): CouponCardProps[] => { return coupons.filter(coupon => !isCouponUsable(coupon, totalAmount))