返回 AiToEarn
format.ts
根目录 / project / aitoearn-web / src / utils / format.ts
1 /**
2 * 格式化工具函数
3 */
4
5 import dayjs from 'dayjs'
6
7 /**
8 * 格式化数字,大数字显示为 k/w 形式
9 * @example formatNumber(1234) -> "1.2k"
10 * @example formatNumber(12345) -> "1.2w"
11 */
12 export function formatNumber(value: number): string {
13 if (!value)
14 return `${value ?? 0}`
15
16 if (value >= 10000) {
17 return `${(value / 10000).toFixed(1).replace(/\.0$/, '')}w`
18 }
19 else if (value >= 1000) {
20 return `${(value / 1000).toFixed(1).replace(/\.0$/, '')}k`
21 }
22 return value.toString()
23 }
24
25 /**
26 * 格式化 AI 推荐分,保留最多 1 位小数
27 */
28 export function formatRecommendationScore(score?: number | null) {
29 if (typeof score !== 'number' || !Number.isFinite(score))
30 return null
31
32 return Number.isInteger(score)
33 ? score.toString()
34 : score.toFixed(1).replace(/\.0$/, '')
35 }
36
37 /**
38 * 格式化文件大小,自动使用 B / KB / MB / GB / TB 单位
39 */
40 export function formatFileSize(bytes: number): string {
41 if (!Number.isFinite(bytes) || bytes <= 0)
42 return '0 B'
43
44 const unitBase = 1024
45 const units = ['B', 'KB', 'MB', 'GB', 'TB']
46 const unitIndex = Math.min(
47 Math.floor(Math.log(bytes) / Math.log(unitBase)),
48 units.length - 1,
49 )
50 const value = bytes / unitBase ** unitIndex
51 const formattedValue = Number.isInteger(value)
52 ? value.toString()
53 : value.toFixed(2).replace(/\.?0+$/, '')
54
55 return `${formattedValue} ${units[unitIndex]}`
56 }
57
58 export interface DurationParts {
59 hours: number
60 minutes: number
61 seconds: number
62 }
63
64 /** 将秒数拆分为小时、分钟、秒,小时不按天折算 */
65 export function getDurationPartsFromSeconds(seconds: number): DurationParts {
66 const safeSeconds = Number.isFinite(seconds) ? Math.max(0, Math.floor(seconds)) : 0
67 return {
68 hours: Math.floor(safeSeconds / 3600),
69 minutes: Math.floor((safeSeconds % 3600) / 60),
70 seconds: safeSeconds % 60,
71 }
72 }
73
74 /**
75 * 格式化日期
76 * @param date 日期
77 * @param format 格式,默认 'YYYY-MM-DD HH:mm'
78 */
79 export function formatDate(
80 date: string | number | Date,
81 format: string = 'YYYY-MM-DD HH:mm',
82 ): string {
83 return dayjs(date).format(format)
84 }
85
86 /**
87 * 格式化相对时间。
88 */
89 export function formatRelativeTime(date: Date | number): string {
90 const now = new Date()
91 const target = date instanceof Date ? date : new Date(date)
92 const diffMs = now.getTime() - target.getTime()
93 const diffSec = Math.floor(diffMs / 1000)
94 const diffMin = Math.floor(diffSec / 60)
95 const diffHour = Math.floor(diffMin / 60)
96 const diffDay = Math.floor(diffHour / 24)
97
98 if (diffSec < 60)
99 return 'Just now'
100
101 if (diffMin < 60)
102 return `${diffMin}m ago`
103
104 if (diffHour < 24)
105 return `${diffHour}h ago`
106
107 if (diffDay < 7)
108 return `${diffDay}d ago`
109
110 return dayjs(target).format('YYYY-MM-DD')
111 }
112
113 /**
114 * 格式化时间。
115 */
116 export function formatTime(time: string | number | Date, format: string = 'YYYY-MM-DD HH:mm:ss') {
117 return dayjs(time).format(format)
118 }
119
120 /**
121 * 将秒数转换为 hh:mm:ss 格式的字符串。
122 */
123 export function formatSeconds(seconds: number): string {
124 const hours = Math.floor(seconds / 3600)
125 const minutes = Math.floor((seconds % 3600) / 60)
126 const secs = seconds % 60
127 const padNumber = (value: number) => value.toString().padStart(2, '0')
128
129 return `${padNumber(hours)}:${padNumber(minutes)}:${padNumber(secs)}`
130 }
131
132 /**
133 * 根据输入数值返回 k/w 简写描述。
134 */
135 export function describeNumber(value: number): string {
136 if (!value)
137 return `${value ?? 0}`
138
139 if (value >= 10000)
140 return `${(value / 10000).toFixed(2).replace(/\.?0+$/, '')}w`
141
142 if (value >= 1000)
143 return `${(value / 1000).toFixed(2).replace(/\.?0+$/, '')}k`
144
145 return value.toString()
146 }
147
147 lines TYPESCRIPT