feat(shop): 添加套票活动功能并优化购买数量控制

- 在仓库模型中添加状态字段
- 实现套票活动最低购买量的灵活配置,优先取模板配置值
- 优化数量输入逻辑,支持套票活动下的默认数量设置
- 改进优惠券加载逻辑,使用初始数量对应总价进行推荐
- 修复商品信息加载顺序,确保套票模板数据正确应用
- 更新支付工具类中的仓库类型引用
- 调整数量输入组件的最小值和禁用状态逻辑
This commit is contained in:
2026-02-09 16:02:33 +08:00
parent 231723e960
commit 37c2f030f2
3 changed files with 58 additions and 24 deletions

View File

@@ -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 = () => {
<ConfigProvider theme={customTheme}>
<InputNumber
value={quantity}
min={1}
min={isTicketTemplateActive ? minBuyQty : 1}
max={goods.stock || 999}
disabled={goods.canBuyNumber != 0}
disabled={((goods.canBuyNumber ?? 0) !== 0) && !isTicketTemplateActive}
onChange={handleQuantityChange}
/>
</ConfigProvider>