- 更新 DashboardLayout 组件,统一使用演示模式布局 - 实现仪表盘页面的完整演示数据和功能 - 完成用户管理页面的演示模式,包含搜索、过滤、分页等功能 - 实现通话记录页面的演示数据和录音播放功能 - 完成翻译员管理页面的演示模式 - 实现订单管理页面的完整功能 - 完成发票管理页面的演示数据 - 更新文档管理页面 - 添加 utils.ts 工具函数库 - 完善 API 路由和数据库结构 - 修复各种 TypeScript 类型错误 - 统一界面风格和用户体验
180 lines
4.3 KiB
TypeScript
180 lines
4.3 KiB
TypeScript
/**
|
|
* 格式化时间
|
|
* @param dateString - ISO 时间字符串
|
|
* @returns 格式化后的时间字符串
|
|
*/
|
|
export const formatTime = (dateString: string): string => {
|
|
if (!dateString) return '';
|
|
|
|
const date = new Date(dateString);
|
|
const now = new Date();
|
|
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
|
|
|
|
if (diffInSeconds < 60) {
|
|
return '刚刚';
|
|
} else if (diffInSeconds < 3600) {
|
|
const minutes = Math.floor(diffInSeconds / 60);
|
|
return `${minutes}分钟前`;
|
|
} else if (diffInSeconds < 86400) {
|
|
const hours = Math.floor(diffInSeconds / 3600);
|
|
return `${hours}小时前`;
|
|
} else if (diffInSeconds < 604800) {
|
|
const days = Math.floor(diffInSeconds / 86400);
|
|
return `${days}天前`;
|
|
} else {
|
|
return date.toLocaleDateString('zh-CN', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 格式化货币
|
|
* @param amount - 金额
|
|
* @returns 格式化后的货币字符串
|
|
*/
|
|
export const formatCurrency = (amount: number): string => {
|
|
return new Intl.NumberFormat('zh-CN', {
|
|
style: 'currency',
|
|
currency: 'CNY'
|
|
}).format(amount);
|
|
};
|
|
|
|
/**
|
|
* 格式化文件大小
|
|
* @param bytes - 字节数
|
|
* @returns 格式化后的文件大小字符串
|
|
*/
|
|
export const formatFileSize = (bytes: number): string => {
|
|
if (bytes === 0) return '0 Bytes';
|
|
|
|
const k = 1024;
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
};
|
|
|
|
/**
|
|
* 生成随机字符串
|
|
* @param length - 字符串长度
|
|
* @returns 随机字符串
|
|
*/
|
|
export const generateRandomString = (length: number): string => {
|
|
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
let result = '';
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* 防抖函数
|
|
* @param func - 要防抖的函数
|
|
* @param wait - 等待时间(毫秒)
|
|
* @returns 防抖后的函数
|
|
*/
|
|
export const debounce = <T extends (...args: any[]) => any>(
|
|
func: T,
|
|
wait: number
|
|
): ((...args: Parameters<T>) => void) => {
|
|
let timeout: NodeJS.Timeout;
|
|
|
|
return (...args: Parameters<T>) => {
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(() => func.apply(null, args), wait);
|
|
};
|
|
};
|
|
|
|
/**
|
|
* 节流函数
|
|
* @param func - 要节流的函数
|
|
* @param limit - 限制时间(毫秒)
|
|
* @returns 节流后的函数
|
|
*/
|
|
export const throttle = <T extends (...args: any[]) => any>(
|
|
func: T,
|
|
limit: number
|
|
): ((...args: Parameters<T>) => void) => {
|
|
let inThrottle: boolean;
|
|
|
|
return (...args: Parameters<T>) => {
|
|
if (!inThrottle) {
|
|
func.apply(null, args);
|
|
inThrottle = true;
|
|
setTimeout(() => (inThrottle = false), limit);
|
|
}
|
|
};
|
|
};
|
|
|
|
/**
|
|
* 深拷贝对象
|
|
* @param obj - 要拷贝的对象
|
|
* @returns 拷贝后的对象
|
|
*/
|
|
export const deepClone = <T>(obj: T): T => {
|
|
if (obj === null || typeof obj !== 'object') {
|
|
return obj;
|
|
}
|
|
|
|
if (obj instanceof Date) {
|
|
return new Date(obj.getTime()) as any;
|
|
}
|
|
|
|
if (obj instanceof Array) {
|
|
return obj.map(item => deepClone(item)) as any;
|
|
}
|
|
|
|
if (typeof obj === 'object') {
|
|
const cloned = {} as any;
|
|
Object.keys(obj).forEach(key => {
|
|
cloned[key] = deepClone((obj as any)[key]);
|
|
});
|
|
return cloned;
|
|
}
|
|
|
|
return obj;
|
|
};
|
|
|
|
/**
|
|
* 获取查询参数
|
|
* @param url - URL 字符串
|
|
* @returns 查询参数对象
|
|
*/
|
|
export const getQueryParams = (url: string): Record<string, string> => {
|
|
const params: Record<string, string> = {};
|
|
const urlObj = new URL(url);
|
|
|
|
urlObj.searchParams.forEach((value, key) => {
|
|
params[key] = value;
|
|
});
|
|
|
|
return params;
|
|
};
|
|
|
|
/**
|
|
* 验证邮箱格式
|
|
* @param email - 邮箱地址
|
|
* @returns 是否为有效邮箱
|
|
*/
|
|
export const validateEmail = (email: string): boolean => {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailRegex.test(email);
|
|
};
|
|
|
|
/**
|
|
* 验证手机号格式
|
|
* @param phone - 手机号
|
|
* @returns 是否为有效手机号
|
|
*/
|
|
export const validatePhone = (phone: string): boolean => {
|
|
const phoneRegex = /^1[3-9]\d{9}$/;
|
|
return phoneRegex.test(phone);
|
|
};
|