- 新增文章添加页面,支持文章基本信息、设置、高级设置和图片上传 - 新增经销商申请页面,支持申请信息填写和审核状态显示 - 新增用户地址添加页面,支持地址信息填写和地址识别功能 - 新增礼物添加页面,功能与文章添加类似 - 统一使用 .tsx 文件格式 - 添加 .editorconfig、.eslintrc 和 .gitignore 文件,规范代码风格和项目结构
164 lines
3.9 KiB
TypeScript
164 lines
3.9 KiB
TypeScript
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;
|