import { useState, useEffect, useMemo } from 'react'; import dayjs from 'dayjs'; import duration from 'dayjs/plugin/duration'; // 扩展dayjs支持duration dayjs.extend(duration); export interface CountdownTime { hours: number; minutes: number; seconds: number; isExpired: boolean; totalMinutes: number; // 总剩余分钟数 } /** * 支付倒计时Hook * @param createTime 订单创建时间 * @param payStatus 支付状态 * @param realTime 是否实时更新(详情页用true,列表页用false) * @param timeoutHours 超时小时数,默认24小时 */ export const usePaymentCountdown = ( createTime?: string, payStatus?: boolean, realTime: boolean = false, timeoutHours: number = 24 ): CountdownTime => { const [timeLeft, setTimeLeft] = useState({ hours: 0, minutes: 0, seconds: 0, isExpired: false, totalMinutes: 0 }); // 计算剩余时间的函数 const calculateTimeLeft = useMemo(() => { return (): CountdownTime => { if (!createTime || payStatus) { return { hours: 0, minutes: 0, seconds: 0, isExpired: false, totalMinutes: 0 }; } const createTimeObj = dayjs(createTime); const expireTime = createTimeObj.add(timeoutHours, 'hour'); const now = dayjs(); const diff = expireTime.diff(now); if (diff <= 0) { return { hours: 0, minutes: 0, seconds: 0, isExpired: true, totalMinutes: 0 }; } const durationObj = dayjs.duration(diff); const hours = Math.floor(durationObj.asHours()); const minutes = durationObj.minutes(); const seconds = durationObj.seconds(); const totalMinutes = Math.floor(durationObj.asMinutes()); return { hours, minutes, seconds, isExpired: false, totalMinutes }; }; }, [createTime, payStatus, timeoutHours]); useEffect(() => { if (!createTime || payStatus) { setTimeLeft({ hours: 0, minutes: 0, seconds: 0, isExpired: false, totalMinutes: 0 }); return; } // 立即计算一次 const initialTime = calculateTimeLeft(); setTimeLeft(initialTime); // 如果不需要实时更新,直接返回 if (!realTime) { return; } // 如果需要实时更新,设置定时器 const timer = setInterval(() => { const newTimeLeft = calculateTimeLeft(); setTimeLeft(newTimeLeft); // 如果已过期,清除定时器 if (newTimeLeft.isExpired) { clearInterval(timer); } }, 1000); return () => clearInterval(timer); }, [createTime, payStatus, realTime, calculateTimeLeft]); return timeLeft; }; /** * 格式化倒计时文本 * @param timeLeft 倒计时时间对象 * @param showSeconds 是否显示秒数 */ export const formatCountdownText = ( timeLeft: CountdownTime, showSeconds: boolean = false ): string => { if (timeLeft.isExpired) { return '已过期'; } if (timeLeft.hours > 0) { if (showSeconds) { return `${timeLeft.hours}小时${timeLeft.minutes}分${timeLeft.seconds}秒`; } else { return `${timeLeft.hours}小时${timeLeft.minutes}分钟`; } } else if (timeLeft.minutes > 0) { if (showSeconds) { return `${timeLeft.minutes}分${timeLeft.seconds}秒`; } else { return `${timeLeft.minutes}分钟`; } } else { return `${timeLeft.seconds}秒`; } }; /** * 判断是否为紧急状态(剩余时间少于1小时) */ export const isUrgentCountdown = (timeLeft: CountdownTime): boolean => { return !timeLeft.isExpired && timeLeft.totalMinutes < 60; }; /** * 判断是否为非常紧急状态(剩余时间少于10分钟) */ export const isCriticalCountdown = (timeLeft: CountdownTime): boolean => { return !timeLeft.isExpired && timeLeft.totalMinutes < 10; }; export default usePaymentCountdown;