refactor(shop): 移除水票套票商品配送时间选择功能
- 删除了配送时间相关的状态管理和日期选择器组件 - 移除了配送时间验证和格式化逻辑 - 更新了订单提交流程,不再传递配送时间参数 - 修改支付回调处理,支持自定义成功行为和跳转逻辑 - 简化了水票商品的购买流程,移除配送时间相关校验
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import {useEffect, useMemo, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {
|
import {
|
||||||
Image,
|
Image,
|
||||||
Button,
|
Button,
|
||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
ActionSheet,
|
ActionSheet,
|
||||||
Popup,
|
Popup,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
DatePicker,
|
|
||||||
ConfigProvider
|
ConfigProvider
|
||||||
} from '@nutui/nutui-react-taro'
|
} from '@nutui/nutui-react-taro'
|
||||||
import {Location, ArrowRight} from '@nutui/icons-react-taro'
|
import {Location, ArrowRight} from '@nutui/icons-react-taro'
|
||||||
@@ -39,7 +38,6 @@ import {
|
|||||||
filterUsableCoupons,
|
filterUsableCoupons,
|
||||||
filterUnusableCoupons
|
filterUnusableCoupons
|
||||||
} from "@/utils/couponUtils";
|
} from "@/utils/couponUtils";
|
||||||
import dayjs from 'dayjs'
|
|
||||||
import type {ShopStore} from "@/api/shop/shopStore/model";
|
import type {ShopStore} from "@/api/shop/shopStore/model";
|
||||||
import {getShopStore, listShopStore} from "@/api/shop/shopStore";
|
import {getShopStore, listShopStore} from "@/api/shop/shopStore";
|
||||||
import {getSelectedStoreFromStorage, saveSelectedStoreToStorage} from "@/utils/storeSelection";
|
import {getSelectedStoreFromStorage, saveSelectedStoreToStorage} from "@/utils/storeSelection";
|
||||||
@@ -57,18 +55,6 @@ const OrderConfirm = () => {
|
|||||||
const [loading, setLoading] = useState<boolean>(true)
|
const [loading, setLoading] = useState<boolean>(true)
|
||||||
const [error, setError] = useState<string>('')
|
const [error, setError] = useState<string>('')
|
||||||
const [payLoading, setPayLoading] = useState<boolean>(false)
|
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)
|
const [ticketTemplate, setTicketTemplate] = useState<GltTicketTemplate | null>(null)
|
||||||
@@ -122,10 +108,6 @@ const OrderConfirm = () => {
|
|||||||
})()
|
})()
|
||||||
const minBuyQty = isTicketTemplateActive ? ticketMinBuyQty : 1
|
const minBuyQty = isTicketTemplateActive ? ticketMinBuyQty : 1
|
||||||
|
|
||||||
const sendTimeText = useMemo(() => {
|
|
||||||
return dayjs(sendTime).format('YYYY-MM-DD')
|
|
||||||
}, [sendTime])
|
|
||||||
|
|
||||||
const getGiftTicketQty = (buyQty: number) => {
|
const getGiftTicketQty = (buyQty: number) => {
|
||||||
if (!isTicketTemplateActive) return 0
|
if (!isTicketTemplateActive) return 0
|
||||||
const multiplier = Number(ticketTemplate?.giftMultiplier || 0)
|
const multiplier = Number(ticketTemplate?.giftMultiplier || 0)
|
||||||
@@ -451,22 +433,7 @@ const OrderConfirm = () => {
|
|||||||
return;
|
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) {
|
if (isTicketTemplateActive && quantity < minBuyQty) {
|
||||||
@@ -530,9 +497,6 @@ const OrderConfirm = () => {
|
|||||||
comments: goods.name,
|
comments: goods.name,
|
||||||
deliveryType: 0,
|
deliveryType: 0,
|
||||||
buyerRemarks: orderRemark,
|
buyerRemarks: orderRemark,
|
||||||
sendStartTime: hasTicketTemplate
|
|
||||||
? dayjs(sendTime).startOf('day').format('YYYY-MM-DD HH:mm:ss')
|
|
||||||
: undefined,
|
|
||||||
couponId: parseInt(String(bestCoupon.id), 10)
|
couponId: parseInt(String(bestCoupon.id), 10)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -540,7 +504,31 @@ const OrderConfirm = () => {
|
|||||||
console.log('🎯 使用推荐优惠券的订单数据:', updatedOrderData);
|
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; // 提前返回,避免重复执行支付
|
return; // 提前返回,避免重复执行支付
|
||||||
} else {
|
} else {
|
||||||
// 用户选择不使用优惠券,继续支付
|
// 用户选择不使用优惠券,继续支付
|
||||||
@@ -558,9 +546,6 @@ const OrderConfirm = () => {
|
|||||||
comments: '桂乐淘',
|
comments: '桂乐淘',
|
||||||
deliveryType: 0,
|
deliveryType: 0,
|
||||||
buyerRemarks: orderRemark,
|
buyerRemarks: orderRemark,
|
||||||
sendStartTime: hasTicketTemplate
|
|
||||||
? dayjs(sendTime).startOf('day').format('YYYY-MM-DD HH:mm:ss')
|
|
||||||
: undefined,
|
|
||||||
// 🔧 确保 couponId 是正确的数字类型,且不传递 undefined
|
// 🔧 确保 couponId 是正确的数字类型,且不传递 undefined
|
||||||
couponId: selectedCoupon ? parseInt(String(selectedCoupon.id), 10) : undefined
|
couponId: selectedCoupon ? parseInt(String(selectedCoupon.id), 10) : undefined
|
||||||
}
|
}
|
||||||
@@ -595,7 +580,31 @@ const OrderConfirm = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 执行支付 - 移除这里的成功提示,让PaymentHandler统一处理
|
// 执行支付 - 移除这里的成功提示,让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会处理成功提示
|
// ✅ 移除双重成功提示 - PaymentHandler会处理成功提示
|
||||||
// Taro.showToast({
|
// Taro.showToast({
|
||||||
@@ -760,10 +769,7 @@ const OrderConfirm = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 切换商品时重置配送时间,避免沿用上一次选择
|
|
||||||
if (!isLoggedIn()) return
|
if (!isLoggedIn()) return
|
||||||
setSendTime(getMinSendDate().toDate())
|
|
||||||
setSendTimePickerVisible(false)
|
|
||||||
loadAllData()
|
loadAllData()
|
||||||
}, [goodsId]);
|
}, [goodsId]);
|
||||||
|
|
||||||
@@ -822,28 +828,6 @@ const OrderConfirm = () => {
|
|||||||
)}
|
)}
|
||||||
</CellGroup>
|
</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>*/}
|
{/*<CellGroup>*/}
|
||||||
{/* <Cell*/}
|
{/* <Cell*/}
|
||||||
{/* title={(*/}
|
{/* title={(*/}
|
||||||
@@ -1138,23 +1122,6 @@ const OrderConfirm = () => {
|
|||||||
|
|
||||||
<Gap height={50}/>
|
<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'}>
|
<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'}>
|
<View className={'btn-bar flex justify-between items-center'}>
|
||||||
<div className={'flex flex-col justify-center items-start mx-4'}>
|
<div className={'flex flex-col justify-center items-start mx-4'}>
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ export enum PaymentType {
|
|||||||
* 支付结果回调
|
* 支付结果回调
|
||||||
*/
|
*/
|
||||||
export interface PaymentCallback {
|
export interface PaymentCallback {
|
||||||
onSuccess?: () => void;
|
// Return `false` to skip default "支付成功" toast + redirect.
|
||||||
|
onSuccess?: () => void | boolean | Promise<void | boolean>;
|
||||||
onError?: (error: string) => void;
|
onError?: (error: string) => void;
|
||||||
onComplete?: () => void;
|
onComplete?: () => void;
|
||||||
}
|
}
|
||||||
@@ -118,17 +119,27 @@ export class PaymentHandler {
|
|||||||
if (paymentSuccess) {
|
if (paymentSuccess) {
|
||||||
console.log('支付成功,订单号:', result.orderNo);
|
console.log('支付成功,订单号:', result.orderNo);
|
||||||
|
|
||||||
|
// 先收起 loading,避免遮挡 modal/toast
|
||||||
|
try {
|
||||||
|
Taro.hideLoading();
|
||||||
|
} catch (_e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSuccessResult = await callback?.onSuccess?.();
|
||||||
|
const skipDefaultSuccessBehavior = onSuccessResult === false;
|
||||||
|
|
||||||
|
if (!skipDefaultSuccessBehavior) {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: '支付成功',
|
title: '支付成功',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
|
|
||||||
callback?.onSuccess?.();
|
|
||||||
|
|
||||||
// 跳转到订单页面
|
// 跳转到订单页面
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Taro.navigateTo({ url: '/user/order/order' });
|
Taro.navigateTo({ url: '/user/order/order' });
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error('支付未完成');
|
throw new Error('支付未完成');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user