184 lines
5.4 KiB
TypeScript
184 lines
5.4 KiB
TypeScript
/**
|
||
* 格式化工具函数
|
||
*
|
||
* 统一管理各种格式化逻辑(日期、时间、数字等)
|
||
* 包括:日期时间格式化、文件大小格式化、数字格式化、百分比格式化等
|
||
* 确保整个应用的格式化一致性
|
||
*
|
||
* @created 2025-01-XX(从各组件提取)
|
||
* @utils
|
||
*/
|
||
|
||
import { format } from 'date-fns'
|
||
|
||
/**
|
||
* 格式化日期时间(完整格式)
|
||
* @param date - 日期对象或时间戳字符串
|
||
* @param formatStr - 格式化字符串,默认为 'yyyy-MM-dd HH:mm:ss'
|
||
* @returns 格式化后的日期时间字符串
|
||
*/
|
||
export function formatDateTime(date: Date | string | number, formatStr: string = 'yyyy-MM-dd HH:mm:ss'): string {
|
||
try {
|
||
const dateObj = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date
|
||
if (isNaN(dateObj.getTime())) {
|
||
return '无效日期'
|
||
}
|
||
return format(dateObj, formatStr)
|
||
} catch (error) {
|
||
console.error('Date formatting error:', error)
|
||
return '无效日期'
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 格式化日期(仅日期部分)
|
||
* @param date - 日期对象或时间戳字符串
|
||
* @returns 格式化后的日期字符串(yyyy-MM-dd)
|
||
*/
|
||
export function formatDate(date: Date | string | number): string {
|
||
return formatDateTime(date, 'yyyy-MM-dd')
|
||
}
|
||
|
||
/**
|
||
* 格式化时间(仅时间部分)
|
||
* @param date - 日期对象或时间戳字符串
|
||
* @returns 格式化后的时间字符串(HH:mm:ss)
|
||
*/
|
||
export function formatTime(date: Date | string | number): string {
|
||
return formatDateTime(date, 'HH:mm:ss')
|
||
}
|
||
|
||
/**
|
||
* 格式化日期时间(简短格式,不含秒)
|
||
* @param date - 日期对象或时间戳字符串
|
||
* @returns 格式化后的日期时间字符串(yyyy-MM-dd HH:mm)
|
||
*/
|
||
export function formatDateTimeShort(date: Date | string | number): string {
|
||
return formatDateTime(date, 'yyyy-MM-dd HH:mm')
|
||
}
|
||
|
||
/**
|
||
* 使用本地化格式格式化日期时间
|
||
* @param date - 日期对象或时间戳字符串
|
||
* @param locale - 语言环境,默认为 'zh-CN'
|
||
* @param options - Intl.DateTimeFormat 选项
|
||
* @returns 格式化后的日期时间字符串
|
||
*/
|
||
export function formatDateTimeLocale(
|
||
date: Date | string | number,
|
||
locale: string = 'zh-CN',
|
||
options?: Intl.DateTimeFormatOptions
|
||
): string {
|
||
try {
|
||
const dateObj = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date
|
||
if (isNaN(dateObj.getTime())) {
|
||
return '无效日期'
|
||
}
|
||
|
||
const defaultOptions: Intl.DateTimeFormatOptions = {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
second: '2-digit',
|
||
hour12: false,
|
||
}
|
||
|
||
return new Intl.DateTimeFormat(locale, options || defaultOptions).format(dateObj)
|
||
} catch (error) {
|
||
console.error('Date formatting error:', error)
|
||
return '无效日期'
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 格式化相对时间(如:2小时前、3天前)
|
||
* @param date - 日期对象或时间戳字符串
|
||
* @returns 相对时间字符串
|
||
*/
|
||
export function formatRelativeTime(date: Date | string | number): string {
|
||
try {
|
||
const dateObj = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date
|
||
if (isNaN(dateObj.getTime())) {
|
||
return '无效日期'
|
||
}
|
||
|
||
const now = new Date()
|
||
const diffMs = now.getTime() - dateObj.getTime()
|
||
const diffSeconds = Math.floor(diffMs / 1000)
|
||
const diffMinutes = Math.floor(diffSeconds / 60)
|
||
const diffHours = Math.floor(diffMinutes / 60)
|
||
const diffDays = Math.floor(diffHours / 24)
|
||
|
||
if (diffSeconds < 60) {
|
||
return '刚刚'
|
||
} else if (diffMinutes < 60) {
|
||
return `${diffMinutes}分钟前`
|
||
} else if (diffHours < 24) {
|
||
return `${diffHours}小时前`
|
||
} else if (diffDays < 7) {
|
||
return `${diffDays}天前`
|
||
} else {
|
||
return formatDateTimeShort(dateObj)
|
||
}
|
||
} catch (error) {
|
||
console.error('Relative time formatting error:', error)
|
||
return '无效日期'
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 格式化文件大小
|
||
* @param bytes - 字节数
|
||
* @param decimals - 小数位数,默认为 2
|
||
* @returns 格式化后的文件大小字符串
|
||
*/
|
||
export function formatFileSize(bytes: number, decimals: number = 2): string {
|
||
if (bytes === 0) return '0 Bytes'
|
||
|
||
const k = 1024
|
||
const dm = decimals < 0 ? 0 : decimals
|
||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||
|
||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||
|
||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
|
||
}
|
||
|
||
/**
|
||
* 格式化数字(添加千位分隔符)
|
||
* @param num - 数字
|
||
* @param decimals - 小数位数,默认为 0
|
||
* @returns 格式化后的数字字符串
|
||
*/
|
||
export function formatNumber(num: number, decimals: number = 0): string {
|
||
try {
|
||
return num.toLocaleString('zh-CN', {
|
||
minimumFractionDigits: decimals,
|
||
maximumFractionDigits: decimals,
|
||
})
|
||
} catch (error) {
|
||
console.error('Number formatting error:', error)
|
||
return String(num)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 格式化百分比
|
||
* @param value - 数值(0-1 或 0-100)
|
||
* @param isDecimal - 是否为小数格式(0-1),默认为 false(0-100)
|
||
* @param decimals - 小数位数,默认为 1
|
||
* @returns 格式化后的百分比字符串
|
||
*/
|
||
export function formatPercent(value: number, isDecimal: boolean = false, decimals: number = 1): string {
|
||
try {
|
||
const percent = isDecimal ? value * 100 : value
|
||
return `${percent.toFixed(decimals)}%`
|
||
} catch (error) {
|
||
console.error('Percent formatting error:', error)
|
||
return '0%'
|
||
}
|
||
}
|
||
|