From 37c2f030f2a03d122a275cf1be2e23a5892d29d9 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, 9 Feb 2026 16:02:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(shop):=20=E6=B7=BB=E5=8A=A0=E5=A5=97?= =?UTF-8?q?=E7=A5=A8=E6=B4=BB=E5=8A=A8=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E8=B4=AD=E4=B9=B0=E6=95=B0=E9=87=8F=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在仓库模型中添加状态字段 - 实现套票活动最低购买量的灵活配置,优先取模板配置值 - 优化数量输入逻辑,支持套票活动下的默认数量设置 - 改进优惠券加载逻辑,使用初始数量对应总价进行推荐 - 修复商品信息加载顺序,确保套票模板数据正确应用 - 更新支付工具类中的仓库类型引用 - 调整数量输入组件的最小值和禁用状态逻辑 --- .../shop/shopStoreWarehouse/model/index.ts | 2 + src/shop/orderConfirm/index.tsx | 70 ++++++++++++++----- src/utils/payment.ts | 10 +-- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/src/api/shop/shopStoreWarehouse/model/index.ts b/src/api/shop/shopStoreWarehouse/model/index.ts index 8dc7421..90d5d84 100644 --- a/src/api/shop/shopStoreWarehouse/model/index.ts +++ b/src/api/shop/shopStoreWarehouse/model/index.ts @@ -28,6 +28,8 @@ export interface ShopStoreWarehouse { lngAndLat?: string; // 用户ID userId?: number; + // 状态 + status?: number; // 备注 comments?: string; // 排序号 diff --git a/src/shop/orderConfirm/index.tsx b/src/shop/orderConfirm/index.tsx index 33a48f8..1facf57 100644 --- a/src/shop/orderConfirm/index.tsx +++ b/src/shop/orderConfirm/index.tsx @@ -89,8 +89,12 @@ const OrderConfirm = () => { ticketTemplate.status !== 1 && ticketTemplate.deleted !== 1 - // 需求:套票活动最低购买量固定为 20 桶 - const minBuyQty = isTicketTemplateActive ? 20 : 1 + // 套票活动最低购买量:优先取模板配置 + const ticketMinBuyQty = (() => { + const n = Number(ticketTemplate?.minBuyQty) + return Number.isFinite(n) && n > 0 ? Math.floor(n) : 1 + })() + const minBuyQty = isTicketTemplateActive ? ticketMinBuyQty : 1 const getGiftTicketQty = (buyQty: number) => { if (!isTicketTemplateActive) return 0 @@ -165,8 +169,9 @@ const OrderConfirm = () => { // 处理数量变化 const handleQuantityChange = (value: string | number) => { - const newQuantity = typeof value === 'string' ? parseInt(value) || 1 : value - const finalQuantity = Math.max(1, Math.min(newQuantity, goods?.stock || 999)) + const fallback = isTicketTemplateActive ? minBuyQty : 1 + const newQuantity = typeof value === 'string' ? parseInt(value, 10) || fallback : value + const finalQuantity = Math.max(fallback, Math.min(newQuantity, goods?.stock || 999)) setQuantity(finalQuantity) // 数量变化时,重新排序优惠券并检查当前选中的优惠券是否还可用 @@ -305,7 +310,7 @@ const OrderConfirm = () => { } // 加载用户优惠券 - const loadUserCoupons = async () => { + const loadUserCoupons = async (totalOverride?: number) => { try { setCouponLoading(true) @@ -317,7 +322,7 @@ const OrderConfirm = () => { const transformedCoupons = res.map(transformCouponData) // 按优惠金额排序 - const total = getGoodsTotal() + const total = totalOverride ?? getGoodsTotal() const sortedCoupons = sortCoupons(transformedCoupons, total) const usableCoupons = filterUsableCoupons(sortedCoupons, total) @@ -592,22 +597,42 @@ const OrderConfirm = () => { ]) // 设置商品信息 - if (goodsRes) { - setGoods(goodsRes) - } - // 查询当前商品是否存在水票套票活动(失败/无数据时不影响正常下单) + let tpl: GltTicketTemplate | null = null if (goodsId) { try { - const tpl = await getGltTicketTemplateByGoodsId(Number(goodsId)) - setTicketTemplate(tpl) + tpl = await getGltTicketTemplateByGoodsId(Number(goodsId)) } catch (e) { - setTicketTemplate(null) + tpl = null } - } else { - setTicketTemplate(null) } + const tplActive = + !!tpl && + tpl.enabled !== false && + tpl.status !== 1 && + tpl.deleted !== 1 + + const tplMinBuyQty = (() => { + const n = Number(tpl?.minBuyQty) + return Number.isFinite(n) && n > 0 ? Math.floor(n) : 1 + })() + + // 设置商品信息(若存在套票模板,则默认 canBuyNumber 使用模板最小购买量) + if (goodsRes) { + const patchedGoods: ShopGoods = { ...goodsRes } + if (tplActive && ((patchedGoods.canBuyNumber ?? 0) === 0)) { + patchedGoods.canBuyNumber = tplMinBuyQty + } + setGoods(patchedGoods) + + // 设置默认购买数量:优先使用 canBuyNumber,否则使用 1 + const initQty = (patchedGoods.canBuyNumber ?? 0) > 0 ? (patchedGoods.canBuyNumber as number) : 1 + setQuantity(initQty) + } + + setTicketTemplate(tpl) + // 设置默认收货地址 if (addressRes && addressRes.length > 0) { setAddress(addressRes[0]) @@ -622,9 +647,16 @@ const OrderConfirm = () => { setPayment(paymentRes[0]) } - // 加载优惠券(在商品信息加载完成后) + // 加载优惠券:使用“初始数量”对应的总价做推荐,避免默认数量变化导致推荐不准 if (goodsRes) { - await loadUserCoupons() + const initQty = (() => { + const n = Number(goodsRes?.canBuyNumber) + if (Number.isFinite(n) && n > 0) return Math.floor(n) + if (tplActive) return tplMinBuyQty + return 1 + })() + const total = parseFloat(goodsRes.price || '0') * initQty + await loadUserCoupons(total) } } catch (err) { console.error('加载数据失败:', err) @@ -737,9 +769,9 @@ const OrderConfirm = () => { diff --git a/src/utils/payment.ts b/src/utils/payment.ts index de0e5d1..63c51fb 100644 --- a/src/utils/payment.ts +++ b/src/utils/payment.ts @@ -3,7 +3,7 @@ import { createOrder, WxPayResult } from '@/api/shop/shopOrder'; import { OrderCreateRequest } from '@/api/shop/shopOrder/model'; import { getSelectedStoreFromStorage, getSelectedStoreIdFromStorage } from '@/utils/storeSelection'; import type { ShopStoreRider } from '@/api/shop/shopStoreRider/model'; -import type { ShopWarehouse } from '@/api/shop/shopWarehouse/model'; +import type { ShopStoreWarehouse } from '@/api/shop/shopStoreWarehouse/model'; import request from '@/utils/request'; /** @@ -30,7 +30,7 @@ export interface PaymentCallback { export class PaymentHandler { // 简单缓存,避免频繁请求(小程序单次运行生命周期内有效) private static storeRidersCache = new Map(); - private static warehousesCache: ShopWarehouse[] | null = null; + private static warehousesCache: ShopStoreWarehouse[] | null = null; /** * 执行支付 @@ -220,10 +220,10 @@ export class PaymentHandler { return sorted[0]?.userId; } - private static async getWarehouses(): Promise { + private static async getWarehouses(): Promise { if (this.warehousesCache) return this.warehousesCache; - const list = await this.listByCompatEndpoint( - ['/shop/shop-warehouse'], + const list = await this.listByCompatEndpoint( + ['/shop/shop-store-warehouse'], {} ); const usable = (list || []).filter(w => w?.isDelete !== 1 && (w.status === undefined || w.status === 1));