refactor(shop): 移除水票套票商品配送时间选择功能
- 删除了配送时间相关的状态管理和日期选择器组件 - 移除了配送时间验证和格式化逻辑 - 更新了订单提交流程,不再传递配送时间参数 - 修改支付回调处理,支持自定义成功行为和跳转逻辑 - 简化了水票商品的购买流程,移除配送时间相关校验
This commit is contained in:
@@ -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'}>
|
||||
|
||||
@@ -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('支付未完成');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user