Files
template-10560/src/hooks/usePaymentCountdown.ts
赵忠林 217bfacadd feat(src): 新增文章、经销商申请、用户地址和礼物添加功能
- 新增文章添加页面,支持文章基本信息、设置、高级设置和图片上传
- 新增经销商申请页面,支持申请信息填写和审核状态显示
- 新增用户地址添加页面,支持地址信息填写和地址识别功能
- 新增礼物添加页面,功能与文章添加类似
- 统一使用 .tsx 文件格式
- 添加 .editorconfig、.eslintrc 和 .gitignore 文件,规范代码风格和项目结构
2025-08-20 14:56:38 +08:00

164 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<CountdownTime>({
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;