Files
mihomo-patchbay/shared/format.ts
T
im0o 129a76696b 仪表盘和订阅详情的操作按钮改 text-button,公网 IP 带旗帜
检测公网 IP、重启内核、订阅详情右上三个按钮都去掉边框,hover 出浅底。
检测结果由国家代码换成旗帜 emoji 加 IP;Windows 的系统字体没有旗帜
字形,浏览器会退回显示两个字母,和原来的效果一致。
2026-08-12 13:17:21 +08:00

56 lines
2.5 KiB
TypeScript

/**
* 流量数字显示成人读的样子。连接页和仪表盘共用。
*
* 1024 进制。B 一档不带小数;其余不满 100 的保留一位小数,够 100 的取整——
* 「23.4 MB」有信息量,「234.7 MB」的小数就只是噪音了。
*/
const UNITS = ['B', 'KB', 'MB', 'GB', 'TB'] as const
export function formatBytes(bytes: number): string {
if (!Number.isFinite(bytes) || bytes < 0) return '0 B'
let value = bytes
let unit = 0
while (value >= 1024 && unit < UNITS.length - 1) {
value /= 1024
unit += 1
}
const digits = unit === 0 || value >= 100 ? 0 : 1
// Number() 去掉无意义的尾零:1.0 KB → 1 KB
return `${String(Number(value.toFixed(digits)))} ${UNITS[unit]}`
}
/**
* 一个过去时刻距今多久,「21 分钟前」的形态。now 由调用方传,纯函数才测得了。
* 超过 30 天相对时间就没有信息量了,直接给日期。
*/
export function formatAgo(at: Date, now: Date): string {
const seconds = Math.max(0, (now.getTime() - at.getTime()) / 1000)
if (seconds < 60) return '刚刚'
if (seconds < 3600) return `${String(Math.floor(seconds / 60))} 分钟前`
if (seconds < 86400) return `${String(Math.floor(seconds / 3600))} 小时前`
if (seconds < 30 * 86400) return `${String(Math.floor(seconds / 86400))} 天前`
const p = (n: number) => String(n).padStart(2, '0')
return `${String(at.getFullYear())}-${p(at.getMonth() + 1)}-${p(at.getDate())}`
}
/**
* 两位国家代码转成旗帜 emoji(区域指示符对)。不像国家代码的输入原样返回,
* 显示端至少还有字母可看。注意 Windows 的系统字体没有旗帜字形,浏览器会
* 把区域指示符退回显示成两个字母。
*/
export function flagEmoji(countryCode: string): string {
const code = countryCode.trim().toUpperCase()
if (!/^[A-Z]{2}$/.test(code)) return countryCode
return String.fromCodePoint(...[...code].map((ch) => 0x1f1e6 + (ch.codePointAt(0) ?? 65) - 65))
}
/** 运行时长。一小时内说分钟,一天内说时分,再长说天和小时;秒级抖动没有信息量。 */
export function formatUptime(seconds: number): string {
if (!Number.isFinite(seconds) || seconds < 0) return '—'
const minutes = Math.floor(seconds / 60)
if (minutes < 60) return `${String(minutes)} 分钟`
const hours = Math.floor(minutes / 60)
if (hours < 24) return `${String(hours)} 小时 ${String(minutes % 60)} 分`
return `${String(Math.floor(hours / 24))} 天 ${String(hours % 24)} 小时`
}