/** * 把范围 [0,1] 的数值格式化为更易读的百分比字符串 * * @param value 要格式化的数字,[0,1] * * @example * readablePercent(0.5) // "50%" * readablePercent(0.5, { precision: 2 }) // "50.00%" * readablePercent(0.5, { art: "shadow" }) // "█████░░░░░ 50%" * readablePercent(0.5, { art: "ascii" }) // "[=====-----] 50%" */ export function readablePercent( value: number, options?: { /** 小数点后保留的位数,默认 0 */ precision?: number /** 显示为字符画 * 如: * ██████░░░░ 50% * [==========----------] 50% */ art?: boolean | "shadow" | "ascii" /** 字符画的宽度,默认 10 */ artWidth?: number } ): string { // 确保值在 [0, 1] 范围内 const clampedValue = Math.max(0, Math.min(1, value)) // 转换为百分比 const percent = clampedValue * 100 // 格式化百分比数字 const precision = options?.precision ?? 0 const percentStr = percent.toFixed(precision) + "%" // 如果不需要字符画,直接返回百分比字符串 const art = options?.art if (!art) { return percentStr } const artWidth = options?.artWidth ?? 10 const filledCount = Math.round(clampedValue * artWidth) const emptyCount = artWidth - filledCount let artStr: string if (art === "ascii") { // ASCII 风格: [=====-----] const filled = "=".repeat(filledCount) const empty = "-".repeat(emptyCount) artStr = `[${filled}${empty}]` } else { // shadow 风格 (默认): █████░░░░░ const filled = "█".repeat(filledCount) const empty = "░".repeat(emptyCount) artStr = `${filled}${empty}` } return `${artStr} ${percentStr}` }