diff --git a/src/components/PaymentCountdown.md b/src/components/PaymentCountdown.md index abe4137..b4c7d9a 100644 --- a/src/components/PaymentCountdown.md +++ b/src/components/PaymentCountdown.md @@ -1,6 +1,6 @@ # PaymentCountdown 支付倒计时组件 -基于订单创建时间的支付倒计时组件,支持静态显示和实时更新两种模式。 +基于订单过期时间(`expirationTime`)的支付倒计时组件,支持静态显示和实时更新两种模式。 ## 功能特性 @@ -19,7 +19,7 @@ import PaymentCountdown from '@/components/PaymentCountdown'; // 订单列表页 - 静态显示 { - const timeLeft = usePaymentCountdown( - order.createTime, - order.payStatus, - true, // 实时更新 - 24 // 24小时超时 - ); + const timeLeft = usePaymentCountdown({ + expirationTime: order.expirationTime, + createTime: order.createTime, // expirationTime 缺失时回退 + payStatus: order.payStatus, + realTime: true, + timeoutHours: 24 + }); const countdownText = formatCountdownText(timeLeft, true); diff --git a/src/components/PaymentCountdown.tsx b/src/components/PaymentCountdown.tsx index 447c2c2..2d6048e 100644 --- a/src/components/PaymentCountdown.tsx +++ b/src/components/PaymentCountdown.tsx @@ -11,6 +11,8 @@ import './PaymentCountdown.scss'; export interface PaymentCountdownProps { /** 订单创建时间 */ createTime?: string; + /** 订单过期时间(推荐直接传后端返回的 expirationTime) */ + expirationTime?: string; /** 支付状态 */ payStatus?: boolean; /** 是否实时更新(详情页用true,列表页用false) */ @@ -29,6 +31,7 @@ export interface PaymentCountdownProps { const PaymentCountdown: React.FC = ({ createTime, + expirationTime, payStatus = false, realTime = false, timeoutHours = 24, @@ -37,10 +40,16 @@ const PaymentCountdown: React.FC = ({ onExpired, mode = 'badge' }) => { - const timeLeft = usePaymentCountdown(createTime, payStatus, realTime, timeoutHours); + const timeLeft = usePaymentCountdown({ + createTime, + expirationTime, + payStatus, + realTime, + timeoutHours + }); - // 如果已支付或没有创建时间,不显示倒计时 - if (payStatus || !createTime) { + // 如果已支付或没有可计算的截止时间,不显示倒计时 + if (payStatus || (!expirationTime && !createTime)) { return null; } diff --git a/src/hooks/usePaymentCountdown.ts b/src/hooks/usePaymentCountdown.ts index a4caa5f..0377f65 100644 --- a/src/hooks/usePaymentCountdown.ts +++ b/src/hooks/usePaymentCountdown.ts @@ -13,19 +13,30 @@ export interface CountdownTime { totalMinutes: number; // 总剩余分钟数 } +export interface UsePaymentCountdownParams { + /** 订单创建时间(用于兼容:当 expirationTime 缺失时按 createTime + timeoutHours 计算) */ + createTime?: string; + /** 订单过期时间(推荐直接传后端返回的 expirationTime) */ + expirationTime?: string; + /** 支付状态 */ + payStatus?: boolean; + /** 是否实时更新(详情页用true,列表页用false) */ + realTime?: boolean; + /** 超时小时数,默认24小时(仅在 expirationTime 缺失时生效) */ + timeoutHours?: number; +} + /** * 支付倒计时Hook - * @param createTime 订单创建时间 - * @param payStatus 支付状态 - * @param realTime 是否实时更新(详情页用true,列表页用false) - * @param timeoutHours 超时小时数,默认24小时 + * 优先使用 expirationTime;当 expirationTime 缺失时回退到 createTime + timeoutHours。 */ -export const usePaymentCountdown = ( - createTime?: string, - payStatus?: boolean, - realTime: boolean = false, - timeoutHours: number = 24 -): CountdownTime => { +export const usePaymentCountdown = ({ + createTime, + expirationTime, + payStatus, + realTime = false, + timeoutHours = 24 +}: UsePaymentCountdownParams): CountdownTime => { const [timeLeft, setTimeLeft] = useState({ hours: 0, minutes: 0, @@ -37,7 +48,7 @@ export const usePaymentCountdown = ( // 计算剩余时间的函数 const calculateTimeLeft = useMemo(() => { return (): CountdownTime => { - if (!createTime || payStatus) { + if (payStatus || (!expirationTime && !createTime)) { return { hours: 0, minutes: 0, @@ -47,8 +58,27 @@ export const usePaymentCountdown = ( }; } - const createTimeObj = dayjs(createTime); - const expireTime = createTimeObj.add(timeoutHours, 'hour'); + // 优先使用后端过期时间;如果无法解析,再回退到 createTime + timeoutHours + const expireTimeFromExpiration = expirationTime ? dayjs(expirationTime) : null; + const expireTimeFromCreate = + createTime ? dayjs(createTime).add(timeoutHours, 'hour') : null; + const expireTime = + expireTimeFromExpiration?.isValid() + ? expireTimeFromExpiration + : expireTimeFromCreate?.isValid() + ? expireTimeFromCreate + : null; + + if (!expireTime) { + return { + hours: 0, + minutes: 0, + seconds: 0, + isExpired: true, + totalMinutes: 0 + }; + } + const now = dayjs(); const diff = expireTime.diff(now); @@ -76,10 +106,10 @@ export const usePaymentCountdown = ( totalMinutes }; }; - }, [createTime, payStatus, timeoutHours]); + }, [createTime, expirationTime, payStatus, timeoutHours]); useEffect(() => { - if (!createTime || payStatus) { + if (payStatus || (!expirationTime && !createTime)) { setTimeLeft({ hours: 0, minutes: 0, @@ -111,7 +141,7 @@ export const usePaymentCountdown = ( }, 1000); return () => clearInterval(timer); - }, [createTime, payStatus, realTime, calculateTimeLeft]); + }, [createTime, expirationTime, payStatus, realTime, calculateTimeLeft]); return timeLeft; }; diff --git a/src/shop/orderDetail/index.tsx b/src/shop/orderDetail/index.tsx index 6350bcb..14ee4db 100644 --- a/src/shop/orderDetail/index.tsx +++ b/src/shop/orderDetail/index.tsx @@ -175,6 +175,7 @@ const OrderDetail = () => { {!order.payStatus && order.orderStatus !== 2 && (
{!item.payStatus && item.orderStatus !== 2 ? (