oeos-components 0.4.8 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-fB92g3RO.js +1419 -0
- package/dist/day-BvhluvJ1.js +111 -0
- package/dist/format-C8GLxsTu.js +488 -0
- package/dist/index-wRPkJ8A4.js +10 -0
- package/dist/is-DCY_JULj.js +298 -0
- package/dist/oeos-components-es.js +5310 -5
- package/dist/oeos-components-umd.js +2583 -24
- package/dist/style.css +1 -1
- package/dist/test-BeRG3MRO.js +18 -0
- package/dist/ws-CdL4IiDX.js +252 -0
- package/package.json +1 -1
- package/dist/index-CAJ0GRWZ.js +0 -6790
- package/dist/index-lVUKuuOW.js +0 -1105
- package/dist/utilities.scss +0 -497
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const n = `import dayjs from 'dayjs'
|
|
2
|
+
import type { ConfigType, OpUnitType, QUnitType } from 'dayjs'
|
|
3
|
+
|
|
4
|
+
type DayUnit = QUnitType | OpUnitType
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 使用 \`dayjs\` 格式化日期。
|
|
8
|
+
*
|
|
9
|
+
* @param date 要格式化的日期值。为空时默认使用当前时间。
|
|
10
|
+
* @param format 输出格式,默认 \`YYYY-MM-DD HH:mm:ss\`。
|
|
11
|
+
* @returns 格式化后的日期字符串。
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* formatDate('2026-04-24 12:30:45')
|
|
15
|
+
* // => '2026-04-24 12:30:45'
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* formatDate('2026-04-24 12:30:45', 'YYYY/MM/DD')
|
|
19
|
+
* // => '2026/04/24'
|
|
20
|
+
*/
|
|
21
|
+
export function formatDate(date?: ConfigType, format = 'YYYY-MM-DD HH:mm:ss'): string {
|
|
22
|
+
return dayjs(date || new Date()).format(format)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 将日期格式化为 \`YYYY-MM-DD\`。
|
|
27
|
+
*
|
|
28
|
+
* @param date 要格式化的日期值。
|
|
29
|
+
* @returns 形如 \`2026-04-24\` 的字符串。
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* formatDateToDay(new Date())
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* formatDateToDay('2026-04-24 12:30:45')
|
|
36
|
+
* // => '2026-04-24'
|
|
37
|
+
*/
|
|
38
|
+
export const formatDateToDay = (date: ConfigType): string => formatDate(date, 'YYYY-MM-DD')
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 将日期格式化为 \`YYYY-MM-DD HH:mm\`。
|
|
42
|
+
*
|
|
43
|
+
* @param date 要格式化的日期值。
|
|
44
|
+
* @returns 形如 \`2026-04-24 12:30\` 的字符串。
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* formatDateToMinute(new Date())
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* formatDateToMinute('2026-04-24 12:30:45')
|
|
51
|
+
* // => '2026-04-24 12:30'
|
|
52
|
+
*/
|
|
53
|
+
export const formatDateToMinute = (date: ConfigType): string => formatDate(date, 'YYYY-MM-DD HH:mm')
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 计算两个日期之间的差值。
|
|
57
|
+
*
|
|
58
|
+
* @param date1 起始时间。未传时返回 \`undefined\`。
|
|
59
|
+
* @param date2 对比时间,默认取当前时间。
|
|
60
|
+
* @param format 差值单位,默认 \`second\`。
|
|
61
|
+
* @returns 两个时间的差值。
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* diffDate('2026-04-24 12:00:00', '2026-04-24 11:59:00')
|
|
65
|
+
* // => 60
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* diffDate('2026-04-24 12:00:00', '2026-04-24 11:30:00', 'minute')
|
|
69
|
+
* // => 30
|
|
70
|
+
*/
|
|
71
|
+
export function diffDate(date1: ConfigType, date2: ConfigType = dayjs(), format: DayUnit = 'second'): number | undefined {
|
|
72
|
+
if (!date1) return
|
|
73
|
+
return dayjs(date1).diff(dayjs(date2), format)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 将秒数转换成“几秒前 / 几分钟前 / 几小时前 / 几天前”这类相对时间文案。
|
|
78
|
+
*
|
|
79
|
+
* @param second 距离当前时间的秒数。
|
|
80
|
+
* @returns 中文相对时间描述。
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* diffDateFromCurrent(45)
|
|
84
|
+
* // => '45秒前'
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* diffDateFromCurrent(3600)
|
|
88
|
+
* // => '1小时前'
|
|
89
|
+
*/
|
|
90
|
+
export function diffDateFromCurrent(second: number): string {
|
|
91
|
+
if (second >= 60 * 60 * 24 * 365) {
|
|
92
|
+
return \`\${parseInt(String(second / (60 * 60 * 24 * 365)))}年前\`
|
|
93
|
+
}
|
|
94
|
+
if (second >= 60 * 60 * 24 * 30) {
|
|
95
|
+
return \`\${parseInt(String(second / (60 * 60 * 24 * 30)))}月前\`
|
|
96
|
+
}
|
|
97
|
+
if (second >= 60 * 60 * 24) {
|
|
98
|
+
return \`\${parseInt(String(second / (60 * 60 * 24)))}天前\`
|
|
99
|
+
}
|
|
100
|
+
if (second >= 60 * 60) {
|
|
101
|
+
return \`\${parseInt(String(second / (60 * 60)))}小时前\`
|
|
102
|
+
}
|
|
103
|
+
if (second >= 60) {
|
|
104
|
+
return \`\${parseInt(String(second / 60))}分钟前\`
|
|
105
|
+
}
|
|
106
|
+
return \`\${parseInt(String(second))}秒前\`
|
|
107
|
+
}
|
|
108
|
+
`;
|
|
109
|
+
export {
|
|
110
|
+
n as default
|
|
111
|
+
};
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
const n = `import { getType } from './base'
|
|
2
|
+
import { isNumber, isStringNumber } from './is'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* \`formatBytes\` 的配置项。
|
|
6
|
+
*/
|
|
7
|
+
export interface FormatBytesOptions {
|
|
8
|
+
/**
|
|
9
|
+
* 小数位数,默认 \`2\`。
|
|
10
|
+
*/
|
|
11
|
+
digit?: number
|
|
12
|
+
/**
|
|
13
|
+
* 是否加千分位,默认 \`false\`。
|
|
14
|
+
*/
|
|
15
|
+
thousands?: boolean
|
|
16
|
+
/**
|
|
17
|
+
* 文本前缀,例如 \`$\`。
|
|
18
|
+
*/
|
|
19
|
+
prefix?: string
|
|
20
|
+
/**
|
|
21
|
+
* 文本后缀,例如 \`/s\`。
|
|
22
|
+
*/
|
|
23
|
+
suffix?: string
|
|
24
|
+
/**
|
|
25
|
+
* 取整方式,默认 \`floor\`。
|
|
26
|
+
*/
|
|
27
|
+
roundType?: 'floor' | 'ceil' | 'round'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* \`formatBytesConvert\` 的配置项。
|
|
32
|
+
*/
|
|
33
|
+
export interface FormatBytesConvertOptions {
|
|
34
|
+
/**
|
|
35
|
+
* 是否使用千分位输出。
|
|
36
|
+
*/
|
|
37
|
+
thounsands?: boolean
|
|
38
|
+
/**
|
|
39
|
+
* 保留小数位数。
|
|
40
|
+
*/
|
|
41
|
+
digit?: number
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* \`formatImg\` 的配置项。
|
|
46
|
+
*/
|
|
47
|
+
export interface FormatImgOptions {
|
|
48
|
+
/**
|
|
49
|
+
* 静态资源根目录,默认 \`assets/images\`。
|
|
50
|
+
*/
|
|
51
|
+
basePath?: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* \`formatToFixed\` 的配置项。
|
|
56
|
+
*/
|
|
57
|
+
export interface FormatToFixedOptions {
|
|
58
|
+
/**
|
|
59
|
+
* 小数位数,默认 \`2\`。
|
|
60
|
+
*/
|
|
61
|
+
digit?: number
|
|
62
|
+
/**
|
|
63
|
+
* 文本前缀,例如 \`$\`。
|
|
64
|
+
*/
|
|
65
|
+
prefix?: string
|
|
66
|
+
/**
|
|
67
|
+
* 文本后缀,例如 \`%\`。
|
|
68
|
+
*/
|
|
69
|
+
suffix?: string
|
|
70
|
+
/**
|
|
71
|
+
* 是否保留原单位,默认 \`true\`。
|
|
72
|
+
*/
|
|
73
|
+
unit?: boolean
|
|
74
|
+
/**
|
|
75
|
+
* 是否添加千分位,默认 \`false\`。
|
|
76
|
+
*/
|
|
77
|
+
thousands?: boolean
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type FormatTimeInput = Date | string | number
|
|
81
|
+
export type FormatTimeFallback = string | ((time: FormatTimeInput) => string)
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 将字节数格式化成更易读的单位字符串。
|
|
85
|
+
*
|
|
86
|
+
* @param bytes 字节数,支持数字和数字字符串。
|
|
87
|
+
* @param options 配置项。
|
|
88
|
+
* @returns 格式化后的字节字符串;如果输入不是合法数字,则原样返回。
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* formatBytes(1024)
|
|
92
|
+
* // => '1.00 KB'
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* formatBytes(1040000, {
|
|
96
|
+
* digit: 3,
|
|
97
|
+
* prefix: '$',
|
|
98
|
+
* suffix: '/s',
|
|
99
|
+
* roundType: 'round',
|
|
100
|
+
* thousands: true,
|
|
101
|
+
* })
|
|
102
|
+
* // => '$1,015.625 KB/s'
|
|
103
|
+
*/
|
|
104
|
+
export function formatBytes(bytes: number | string, options: FormatBytesOptions = {}): string | number {
|
|
105
|
+
let { digit = 2, thousands = false, prefix = '', suffix = '', roundType = 'floor' } = options
|
|
106
|
+
if (isStringNumber(bytes as any) || isNumber(bytes)) {
|
|
107
|
+
bytes = Number(bytes)
|
|
108
|
+
} else {
|
|
109
|
+
return bytes
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (bytes <= 1) {
|
|
113
|
+
return Math[roundType](bytes * Math.pow(10, digit)) / Math.pow(10, digit) + ' B'
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const k = 1024
|
|
117
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
|
118
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
119
|
+
const power = Math.pow(k, i)
|
|
120
|
+
|
|
121
|
+
let num = bytes / power
|
|
122
|
+
num = Math[roundType](num * Math.pow(10, digit)) / Math.pow(10, digit)
|
|
123
|
+
|
|
124
|
+
let res = num.toFixed(digit) + ' ' + sizes[i]
|
|
125
|
+
if (thousands) {
|
|
126
|
+
res = String(formatThousands(res))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return \`\${prefix}\${res}\${suffix}\`
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 将带单位的字节字符串转换为原始字节数。
|
|
134
|
+
*
|
|
135
|
+
* @param oBytes 字节字符串,例如 \`1.5GB\`、\`1,024 KB\`,也支持纯数字。
|
|
136
|
+
* @param options 配置项。
|
|
137
|
+
* @returns 字节数;如启用了 \`digit\` 或 \`thounsands\`,返回格式化后的字符串。
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* formatBytesConvert('0.5GB')
|
|
141
|
+
* // => 536870912
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* formatBytesConvert('1,234 GB', { thounsands: true })
|
|
145
|
+
* // => '1,324,997,410,816'
|
|
146
|
+
*/
|
|
147
|
+
export function formatBytesConvert(
|
|
148
|
+
oBytes: unknown,
|
|
149
|
+
options: FormatBytesConvertOptions = {},
|
|
150
|
+
): string | number | undefined {
|
|
151
|
+
let { thounsands = false, digit = 0 } = options
|
|
152
|
+
let bytes = oBytes
|
|
153
|
+
|
|
154
|
+
const parseDigitThounsands = (val: unknown) => {
|
|
155
|
+
let finalRes = val as any
|
|
156
|
+
if (digit) {
|
|
157
|
+
finalRes = Number(finalRes).toFixed(digit)
|
|
158
|
+
}
|
|
159
|
+
if (thounsands) {
|
|
160
|
+
finalRes = formatThousands(finalRes)
|
|
161
|
+
}
|
|
162
|
+
return finalRes
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (isStringNumber(oBytes as string) || isNumber(oBytes) || getType(oBytes) !== 'string') {
|
|
166
|
+
return parseDigitThounsands(oBytes)
|
|
167
|
+
}
|
|
168
|
+
if (!oBytes) {
|
|
169
|
+
return parseDigitThounsands(oBytes)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const regex = /^\\d{1,3}(,\\d{3})*(\\.\\d+)?[a-zA-Z ]*$/
|
|
173
|
+
if (typeof oBytes === 'string' && regex.test(oBytes)) {
|
|
174
|
+
bytes = oBytes.replace(/,/g, '')
|
|
175
|
+
if (isStringNumber(bytes) || isNumber(bytes) || getType(bytes) !== 'string') {
|
|
176
|
+
return parseDigitThounsands(bytes)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const bytesRegex = /^(\\d+(?:\\.\\d+)?)\\s*([BKMGTPEZY]?B|Byte)$/i
|
|
181
|
+
const units = {
|
|
182
|
+
B: 1,
|
|
183
|
+
BYTE: 1,
|
|
184
|
+
KB: 1024,
|
|
185
|
+
MB: 1024 ** 2,
|
|
186
|
+
GB: 1024 ** 3,
|
|
187
|
+
TB: 1024 ** 4,
|
|
188
|
+
PB: 1024 ** 5,
|
|
189
|
+
EB: 1024 ** 6,
|
|
190
|
+
ZB: 1024 ** 7,
|
|
191
|
+
YB: 1024 ** 8,
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (typeof bytes !== 'string') {
|
|
195
|
+
return parseDigitThounsands(bytes)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const match = bytes.match(bytesRegex)
|
|
199
|
+
if (!match) {
|
|
200
|
+
console.warn("Invalid bytes format. Please provide a valid bytes string, like '100GB'.")
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const size = parseFloat(match[1])
|
|
205
|
+
const unit = match[2].toUpperCase() as keyof typeof units
|
|
206
|
+
if (!Object.prototype.hasOwnProperty.call(units, unit)) {
|
|
207
|
+
console.warn(
|
|
208
|
+
"Invalid bytes unit. Please provide a valid unit, like 'B', 'BYTE', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', or 'YB'.",
|
|
209
|
+
)
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return parseDigitThounsands(size * units[unit])
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* 为数字或数字字符串添加千分位分隔符。
|
|
218
|
+
*
|
|
219
|
+
* @param value 需要格式化的值。
|
|
220
|
+
* @returns 添加千分位后的字符串;如果不符合规则则原样返回。
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* formatThousands(1234567)
|
|
224
|
+
* // => '1,234,567'
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* formatThousands('1234.12MB')
|
|
228
|
+
* // => '1,234.12MB'
|
|
229
|
+
*/
|
|
230
|
+
export function formatThousands(value: string | number): string | number {
|
|
231
|
+
const matches = ('' + value).match(/^([\\d,]+)(\\.?)(\\d+)?(\\D+)?$/)
|
|
232
|
+
if (!matches) {
|
|
233
|
+
return value
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const numericString = matches[1].replace(/\\D/g, '')
|
|
237
|
+
const decimalString = matches[3] ? \`.\${matches[3]}\` : ''
|
|
238
|
+
const unit = matches[4] || ''
|
|
239
|
+
const numberWithSeparator = numericString.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',')
|
|
240
|
+
|
|
241
|
+
return \`\${numberWithSeparator}\${decimalString}\${unit}\`
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 将时间值格式化为指定模板字符串。
|
|
246
|
+
*
|
|
247
|
+
* 支持 \`Date\`、毫秒时间戳、秒级时间戳、ISO 字符串和普通日期字符串。
|
|
248
|
+
* 纯日期字符串(如 \`2022-03-04\`)会按本地时区的 \`00:00:00\` 解析。
|
|
249
|
+
*
|
|
250
|
+
* @param time 时间值,默认当前时间。
|
|
251
|
+
* @param cFormat 格式模板,默认 \`{y}-{m}-{d} {h}:{i}:{s}\`。
|
|
252
|
+
* @param fallback 非法日期时的兜底返回值,默认返回原始输入。
|
|
253
|
+
* @returns 格式化后的时间字符串。
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* formatTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}')
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* formatTime(1713926400, '{y}/{m}/{d}')
|
|
260
|
+
* // => '2024/04/24'
|
|
261
|
+
*/
|
|
262
|
+
export function formatTime(
|
|
263
|
+
time: FormatTimeInput = new Date(),
|
|
264
|
+
cFormat = '{y}-{m}-{d} {h}:{i}:{s}',
|
|
265
|
+
fallback: FormatTimeFallback = (value) => String(value),
|
|
266
|
+
): string {
|
|
267
|
+
let date: Date
|
|
268
|
+
const timeStr = String(time)
|
|
269
|
+
|
|
270
|
+
if (typeof time === 'object' && time instanceof Date) {
|
|
271
|
+
date = time
|
|
272
|
+
} else {
|
|
273
|
+
const isoRegex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,3})?)?$/
|
|
274
|
+
const dateOnlyRegex = /^(\\d{4})-(\\d{2})-(\\d{2})$/
|
|
275
|
+
|
|
276
|
+
if (isoRegex.test(timeStr)) {
|
|
277
|
+
date = new Date(time)
|
|
278
|
+
} else if (dateOnlyRegex.test(timeStr)) {
|
|
279
|
+
const [, year, month, day] = timeStr.match(dateOnlyRegex)!
|
|
280
|
+
date = new Date(Number(year), Number(month) - 1, Number(day))
|
|
281
|
+
} else if (timeStr.includes('.') && !isNaN(parseFloat(timeStr))) {
|
|
282
|
+
date = new Date(parseFloat(timeStr) * 1000)
|
|
283
|
+
} else if (/^\\d{10}$/.test(timeStr)) {
|
|
284
|
+
date = new Date(parseInt(timeStr) * 1000)
|
|
285
|
+
} else {
|
|
286
|
+
date = new Date(time)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (isNaN(date.getTime())) {
|
|
291
|
+
return typeof fallback === 'function' ? fallback(time) : fallback
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const formatObj = {
|
|
295
|
+
y: date.getFullYear(),
|
|
296
|
+
m: date.getMonth() + 1,
|
|
297
|
+
d: date.getDate(),
|
|
298
|
+
h: date.getHours(),
|
|
299
|
+
i: date.getMinutes(),
|
|
300
|
+
s: date.getSeconds(),
|
|
301
|
+
a: date.getDay(),
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return cFormat.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
|
305
|
+
const value = formatObj[key as keyof typeof formatObj]
|
|
306
|
+
|
|
307
|
+
if (key === 'a') {
|
|
308
|
+
return ['日', '一', '二', '三', '四', '五', '六'][value]
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (result.length > 0 && value < 10) {
|
|
312
|
+
return '0' + value
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return String(value)
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 将持续时间时间戳格式化为“天 / 时 / 分 / 秒”文本。
|
|
321
|
+
*
|
|
322
|
+
* @param timestamp 持续时间,单位毫秒。
|
|
323
|
+
* @param cFormat 输出模板,默认 \`{d}天{h}时{i}分{s}秒\`。
|
|
324
|
+
* @returns 格式化后的持续时间文本。
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* formatDurationTime(1162821)
|
|
328
|
+
* // => '19分24秒'
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* formatDurationTime(5 * 60 * 1000, '{i}分{s}秒')
|
|
332
|
+
* // => '05分00秒'
|
|
333
|
+
*/
|
|
334
|
+
export function formatDurationTime(timestamp: number, cFormat = '{d}天{h}时{i}分{s}秒'): string {
|
|
335
|
+
const secondsPerMinute = 60
|
|
336
|
+
const minutesPerHour = 60
|
|
337
|
+
const hoursPerDay = 24
|
|
338
|
+
let totalSeconds = Math.floor(timestamp / 1000)
|
|
339
|
+
let days = 0
|
|
340
|
+
|
|
341
|
+
if (cFormat.indexOf('d') !== -1) {
|
|
342
|
+
days = Math.floor(totalSeconds / (secondsPerMinute * minutesPerHour * hoursPerDay))
|
|
343
|
+
totalSeconds %= secondsPerMinute * minutesPerHour * hoursPerDay
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const hours = Math.floor(totalSeconds / (secondsPerMinute * minutesPerHour))
|
|
347
|
+
totalSeconds %= secondsPerMinute * minutesPerHour
|
|
348
|
+
const minutes = Math.floor(totalSeconds / secondsPerMinute)
|
|
349
|
+
const seconds = totalSeconds % secondsPerMinute
|
|
350
|
+
|
|
351
|
+
const formatObj = {
|
|
352
|
+
d: days,
|
|
353
|
+
h: hours,
|
|
354
|
+
i: minutes,
|
|
355
|
+
s: seconds,
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
let parseFormat = cFormat
|
|
359
|
+
if (days === 0) {
|
|
360
|
+
parseFormat = cFormat.match(/{h}.*/g)?.[0] ?? ''
|
|
361
|
+
if (hours === 0) {
|
|
362
|
+
parseFormat = cFormat.match(/{i}.*/g)?.[0] ?? ''
|
|
363
|
+
if (minutes === 0) {
|
|
364
|
+
parseFormat = cFormat.match(/{s}.*/g)?.[0] ?? ''
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return parseFormat.replace(/{(y|m|d|h|i|s)+}/g, (result, key) => {
|
|
370
|
+
let value = formatObj[key as keyof typeof formatObj]
|
|
371
|
+
if (result.length > 0 && value < 10 && value !== 0) {
|
|
372
|
+
return \`0\${value}\`
|
|
373
|
+
}
|
|
374
|
+
return String(value || '00')
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* 获取 \`assets\` 目录下的静态资源地址。
|
|
380
|
+
*
|
|
381
|
+
* @param photoName 文件名;未带后缀时会自动补 \`.png\`。
|
|
382
|
+
* @param addPath 额外子目录,例如 \`menu\`。
|
|
383
|
+
* @param options 配置项。
|
|
384
|
+
* @returns 静态资源的完整 URL;如果本身已是 \`http/https\` 地址,则原样返回。
|
|
385
|
+
*
|
|
386
|
+
* @example
|
|
387
|
+
* formatImg('logo')
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* formatImg('avatar.png', 'user')
|
|
391
|
+
*/
|
|
392
|
+
export function formatImg(
|
|
393
|
+
photoName: string,
|
|
394
|
+
addPath = '',
|
|
395
|
+
{ basePath = 'assets/images' }: FormatImgOptions = {},
|
|
396
|
+
): string {
|
|
397
|
+
if (photoName.startsWith('http') || photoName.startsWith('https')) {
|
|
398
|
+
return photoName
|
|
399
|
+
}
|
|
400
|
+
if (photoName.indexOf('.') === -1) {
|
|
401
|
+
photoName = photoName + '.png'
|
|
402
|
+
}
|
|
403
|
+
const addLastSlash = addPath.endsWith('/') || !addPath ? addPath : \`\${addPath}/\`
|
|
404
|
+
const addLastBasePathSlash = basePath.endsWith('/') || !basePath ? basePath : \`\${basePath}/\`
|
|
405
|
+
const mergeSrc = \`\${addLastSlash}\${photoName}\`
|
|
406
|
+
return new URL(\`../\${addLastBasePathSlash}\${mergeSrc}\`, import.meta.url).href
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* 按指定小数位格式化数字,并可附带前后缀、单位和千分位。
|
|
411
|
+
*
|
|
412
|
+
* @param value 需要格式化的值。
|
|
413
|
+
* @param options 小数位数或配置项。
|
|
414
|
+
* @returns 格式化后的字符串。
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* formatToFixed('22.1', 2)
|
|
418
|
+
* // => '22.10'
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* formatToFixed('22 TB', { digit: 2, unit: false, prefix: '$' })
|
|
422
|
+
* // => '$22.00'
|
|
423
|
+
*/
|
|
424
|
+
export function formatToFixed(value: unknown, options?: FormatToFixedOptions | number): string {
|
|
425
|
+
if (typeof options === 'number') {
|
|
426
|
+
options = { digit: options }
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const finalOptions: Required<FormatToFixedOptions> = {
|
|
430
|
+
digit: 2,
|
|
431
|
+
prefix: '',
|
|
432
|
+
suffix: '',
|
|
433
|
+
unit: true,
|
|
434
|
+
thousands: false,
|
|
435
|
+
...options,
|
|
436
|
+
}
|
|
437
|
+
const { digit, prefix, suffix, unit, thousands } = finalOptions
|
|
438
|
+
|
|
439
|
+
const matches = ('' + value).match(/^([\\d,]+)(\\.?)(\\d+)?(\\D+)?$/)
|
|
440
|
+
if (!matches) {
|
|
441
|
+
return String(value)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const numericString = matches[1].replace(/\\D/g, '')
|
|
445
|
+
const decimalString = matches[3] ? \`.\${matches[3]}\` : ''
|
|
446
|
+
let finalUnit = matches[4] || ''
|
|
447
|
+
let res = numericString
|
|
448
|
+
|
|
449
|
+
if (isStringNumber(numericString) || isNumber(numericString)) {
|
|
450
|
+
res = Number(numericString + decimalString).toFixed(digit)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (thousands) {
|
|
454
|
+
res = String(formatThousands(res))
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (!unit) {
|
|
458
|
+
finalUnit = ''
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return \`\${prefix}\${res}\${finalUnit}\${suffix}\`
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* 将纯文本中的换行和制表符转换成可直接渲染的 HTML 片段。
|
|
466
|
+
*
|
|
467
|
+
* @param str 需要格式化的文本。
|
|
468
|
+
* @returns 字符串输入会返回转换后的 HTML;非字符串输入会原样返回。
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* formatTextToHtml('第1行\\n\\t第2行')
|
|
472
|
+
* // => '第1行<br> 第2行'
|
|
473
|
+
*/
|
|
474
|
+
export function formatTextToHtml(str: string): string
|
|
475
|
+
export function formatTextToHtml<T>(str: T): T
|
|
476
|
+
export function formatTextToHtml(str: unknown): unknown {
|
|
477
|
+
if (!str || typeof str !== 'string') {
|
|
478
|
+
return str
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
str = str.replace(/\\n/g, '<br>')
|
|
482
|
+
str = str.replace(/\\t/g, ' ')
|
|
483
|
+
return str
|
|
484
|
+
}
|
|
485
|
+
`;
|
|
486
|
+
export {
|
|
487
|
+
n as default
|
|
488
|
+
};
|