refactor(shop): 移除水票套票商品配送时间选择功能

- 删除了配送时间相关的状态管理和日期选择器组件
- 移除了配送时间验证和格式化逻辑
- 更新了订单提交流程,不再传递配送时间参数
- 修改支付回调处理,支持自定义成功行为和跳转逻辑
- 简化了水票商品的购买流程,移除配送时间相关校验
This commit is contained in:
2026-03-09 12:17:29 +08:00
parent 58d3e884ab
commit 3248315f6e
2 changed files with 73 additions and 95 deletions

View File

@@ -1,4 +1,4 @@
import {useEffect, useMemo, useState} from "react";
import {useEffect, useState} from "react";
import {
Image,
Button,
@@ -9,7 +9,6 @@ import {
ActionSheet,
Popup,
InputNumber,
DatePicker,
ConfigProvider
} from '@nutui/nutui-react-taro'
import {Location, ArrowRight} from '@nutui/icons-react-taro'
@@ -39,7 +38,6 @@ import {
filterUsableCoupons,
filterUnusableCoupons
} from "@/utils/couponUtils";
import dayjs from 'dayjs'
import type {ShopStore} from "@/api/shop/shopStore/model";
import {getShopStore, listShopStore} from "@/api/shop/shopStore";
import {getSelectedStoreFromStorage, saveSelectedStoreToStorage} from "@/utils/storeSelection";
@@ -57,18 +55,6 @@ const OrderConfirm = () => {
const [loading, setLoading] = useState<boolean>(true)
const [error, setError] = useState<string>('')
const [payLoading, setPayLoading] = useState<boolean>(false)
// 配送时间(仅水票套票商品需要)
// 当日截单时间:超过该时间下单,最早配送日顺延到次日(避免 21:00 下单仍显示“当天配送”)
const DELIVERY_CUTOFF_HOUR = 21
const getMinSendDate = () => {
const now = dayjs()
const cutoff = now.hour(DELIVERY_CUTOFF_HOUR).minute(0).second(0).millisecond(0)
const startOfToday = now.startOf('day')
// >= 截单时间则最早只能选次日
return now.isSame(cutoff) || now.isAfter(cutoff) ? startOfToday.add(1, 'day') : startOfToday
}
const [sendTime, setSendTime] = useState<Date>(() => getMinSendDate().toDate())
const [sendTimePickerVisible, setSendTimePickerVisible] = useState(false)
// 水票套票活动(若存在则按规则限制最小购买量等)
const [ticketTemplate, setTicketTemplate] = useState<GltTicketTemplate | null>(null)
@@ -122,10 +108,6 @@ const OrderConfirm = () => {
})()
const minBuyQty = isTicketTemplateActive ? ticketMinBuyQty : 1
const sendTimeText = useMemo(() => {
return dayjs(sendTime).format('YYYY-MM-DD')
}, [sendTime])
const getGiftTicketQty = (buyQty: number) => {
if (!isTicketTemplateActive) return 0
const multiplier = Number(ticketTemplate?.giftMultiplier || 0)
@@ -451,22 +433,7 @@ const OrderConfirm = () => {
return;
}
// 水票套票商品:保存配送时间到 ShopOrder.sendStartTime
if (hasTicketTemplate && !sendTime) {
Taro.showToast({ title: '请选择配送时间', icon: 'none' })
return
}
if (hasTicketTemplate) {
const min = getMinSendDate()
if (dayjs(sendTime).isBefore(min, 'day')) {
setSendTime(min.toDate())
Taro.showToast({
title: `已过当日${DELIVERY_CUTOFF_HOUR}点截单,最早配送:${min.format('YYYY-MM-DD')}`,
icon: 'none'
})
return
}
}
// 购买水票(囤券预付费)与水票核销(下单履约)为两个独立动作:下单页不再选择配送时间。
// 水票套票活动:最小购买量校验
if (isTicketTemplateActive && quantity < minBuyQty) {
@@ -530,9 +497,6 @@ const OrderConfirm = () => {
comments: goods.name,
deliveryType: 0,
buyerRemarks: orderRemark,
sendStartTime: hasTicketTemplate
? dayjs(sendTime).startOf('day').format('YYYY-MM-DD HH:mm:ss')
: undefined,
couponId: parseInt(String(bestCoupon.id), 10)
}
);
@@ -540,7 +504,31 @@ const OrderConfirm = () => {
console.log('🎯 使用推荐优惠券的订单数据:', updatedOrderData);
// 执行支付
await PaymentHandler.pay(updatedOrderData, currentPaymentType);
await PaymentHandler.pay(updatedOrderData, currentPaymentType, hasTicketTemplate ? {
onSuccess: async () => {
const id = goods.goodsId
try {
const res = await Taro.showModal({
title: '提示',
content: '是否立刻送水?',
confirmText: '立刻送水',
cancelText: '稍后'
})
if (res?.confirm) {
if (id) {
await Taro.redirectTo({ url: `/user/ticket/use?goodsId=${id}` })
} else {
await Taro.redirectTo({ url: '/user/ticket/index' })
}
} else {
await Taro.redirectTo({ url: '/user/ticket/index' })
}
} catch (_e) {
await Taro.redirectTo({ url: '/user/ticket/index' })
}
return false
}
} : undefined);
return; // 提前返回,避免重复执行支付
} else {
// 用户选择不使用优惠券,继续支付
@@ -558,9 +546,6 @@ const OrderConfirm = () => {
comments: '桂乐淘',
deliveryType: 0,
buyerRemarks: orderRemark,
sendStartTime: hasTicketTemplate
? dayjs(sendTime).startOf('day').format('YYYY-MM-DD HH:mm:ss')
: undefined,
// 🔧 确保 couponId 是正确的数字类型,且不传递 undefined
couponId: selectedCoupon ? parseInt(String(selectedCoupon.id), 10) : undefined
}
@@ -595,7 +580,31 @@ const OrderConfirm = () => {
});
// 执行支付 - 移除这里的成功提示让PaymentHandler统一处理
await PaymentHandler.pay(orderData, paymentType);
await PaymentHandler.pay(orderData, paymentType, hasTicketTemplate ? {
onSuccess: async () => {
const id = goods.goodsId
try {
const res = await Taro.showModal({
title: '提示',
content: '是否立刻送水?',
confirmText: '立刻送水',
cancelText: '稍后'
})
if (res?.confirm) {
if (id) {
await Taro.redirectTo({ url: `/user/ticket/use?goodsId=${id}` })
} else {
await Taro.redirectTo({ url: '/user/ticket/index' })
}
} else {
await Taro.redirectTo({ url: '/user/ticket/index' })
}
} catch (_e) {
await Taro.redirectTo({ url: '/user/ticket/index' })
}
return false
}
} : undefined);
// ✅ 移除双重成功提示 - PaymentHandler会处理成功提示
// Taro.showToast({
@@ -760,10 +769,7 @@ const OrderConfirm = () => {
})
useEffect(() => {
// 切换商品时重置配送时间,避免沿用上一次选择
if (!isLoggedIn()) return
setSendTime(getMinSendDate().toDate())
setSendTimePickerVisible(false)
loadAllData()
}, [goodsId]);
@@ -822,28 +828,6 @@ const OrderConfirm = () => {
)}
</CellGroup>
{hasTicketTemplate && (
<CellGroup>
<Cell
title={'配送时间'}
extra={(
<View className={'flex items-center gap-2'}>
<View className={'text-gray-900'}>{sendTimeText}</View>
<ArrowRight className={'text-gray-400'} size={14}/>
</View>
)}
onClick={() => {
// 若页面停留跨过截单时间,打开选择器前再校正一次最早可选日期
const min = getMinSendDate()
if (dayjs(sendTime).isBefore(min, 'day')) {
setSendTime(min.toDate())
}
setSendTimePickerVisible(true)
}}
/>
</CellGroup>
)}
{/*<CellGroup>*/}
{/* <Cell*/}
{/* title={(*/}
@@ -1138,23 +1122,6 @@ const OrderConfirm = () => {
<Gap height={50}/>
<DatePicker
visible={sendTimePickerVisible}
title="选择配送时间"
type="date"
startDate={getMinSendDate().toDate()}
endDate={dayjs().add(30, 'day').toDate()}
value={sendTime}
onClose={() => setSendTimePickerVisible(false)}
onCancel={() => setSendTimePickerVisible(false)}
onConfirm={(_options, selectedValue) => {
const [y, m, d] = (selectedValue || []).map(v => Number(v))
const next = new Date(y, (m || 1) - 1, d || 1, 0, 0, 0)
setSendTime(next)
setSendTimePickerVisible(false)
}}
/>
<div className={'fixed z-50 bg-white w-full bottom-0 left-0 pt-4 pb-10 border-t border-gray-200'}>
<View className={'btn-bar flex justify-between items-center'}>
<div className={'flex flex-col justify-center items-start mx-4'}>

View File

@@ -19,7 +19,8 @@ export enum PaymentType {
* 支付结果回调
*/
export interface PaymentCallback {
onSuccess?: () => void;
// Return `false` to skip default "支付成功" toast + redirect.
onSuccess?: () => void | boolean | Promise<void | boolean>;
onError?: (error: string) => void;
onComplete?: () => void;
}
@@ -118,17 +119,27 @@ export class PaymentHandler {
if (paymentSuccess) {
console.log('支付成功,订单号:', result.orderNo);
Taro.showToast({
title: '支付成功',
icon: 'success'
});
// 先收起 loading避免遮挡 modal/toast
try {
Taro.hideLoading();
} catch (_e) {
// ignore
}
callback?.onSuccess?.();
const onSuccessResult = await callback?.onSuccess?.();
const skipDefaultSuccessBehavior = onSuccessResult === false;
// 跳转到订单页面
setTimeout(() => {
Taro.navigateTo({ url: '/user/order/order' });
}, 2000);
if (!skipDefaultSuccessBehavior) {
Taro.showToast({
title: '支付成功',
icon: 'success'
});
// 跳转到订单页面
setTimeout(() => {
Taro.navigateTo({ url: '/user/order/order' });
}, 2000);
}
} else {
throw new Error('支付未完成');
}