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));