diff --git a/src/pages/ConfigPanel.tsx b/src/pages/ConfigPanel.tsx index 59a2fcd..6d3e448 100644 --- a/src/pages/ConfigPanel.tsx +++ b/src/pages/ConfigPanel.tsx @@ -670,10 +670,9 @@ export function ConfigPanelPage() { - + disabled={controlsDisabled} + onClick={generateManagementSecret} + > {t('config.webuiKey.generate')} new Intl.NumberFormat(getCurrentLocale(), { - notation: value >= 10_000 ? 'compact' : 'standard', - maximumFractionDigits: 1, -}).format(Number.isFinite(value) ? value : 0); +const compactNumber = (value: number) => formatUsageNumber(value, getCurrentLocale()); const formatUsd = (value: number) => { const amount = Number.isFinite(value) ? value : 0; diff --git a/src/services/usageNumber.ts b/src/services/usageNumber.ts new file mode 100644 index 0000000..15ac5fb --- /dev/null +++ b/src/services/usageNumber.ts @@ -0,0 +1,16 @@ +const MILLION = 1_000_000; +const BILLION = 1_000_000_000; + +export const formatUsageNumber = (value: number, locale: string) => { + const amount = Number.isFinite(value) ? value : 0; + const absolute = Math.abs(amount); + const roundedMillions = Math.round((absolute / MILLION) * 10) / 10; + const useBillions = absolute >= BILLION || roundedMillions >= 1_000; + const divisor = useBillions ? BILLION : absolute >= MILLION ? MILLION : 1; + const unit = useBillions ? 'B' : absolute >= MILLION ? 'M' : ''; + const formatted = new Intl.NumberFormat(locale, { + maximumFractionDigits: divisor === 1 ? 0 : 1, + }).format(amount / divisor); + + return `${formatted}${unit}`; +}; diff --git a/tests/usageNumber.test.ts b/tests/usageNumber.test.ts new file mode 100644 index 0000000..9f34b47 --- /dev/null +++ b/tests/usageNumber.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from 'bun:test'; +import { formatUsageNumber } from '../src/services/usageNumber'; + +describe('使用统计数量单位', () => { + test('百万以下保持普通数字格式', () => { + expect(formatUsageNumber(999_999, 'en-US')).toBe('999,999'); + expect(formatUsageNumber(Number.NaN, 'en-US')).toBe('0'); + }); + + test('百万级使用 M 并在达到阈值时自动切换为 B', () => { + expect(formatUsageNumber(1_000_000, 'en-US')).toBe('1M'); + expect(formatUsageNumber(12_340_000, 'en-US')).toBe('12.3M'); + expect(formatUsageNumber(999_949_999, 'en-US')).toBe('999.9M'); + expect(formatUsageNumber(999_950_000, 'en-US')).toBe('1B'); + expect(formatUsageNumber(1_250_000_000, 'en-US')).toBe('1.3B'); + }); +});