feat(usage): format statistics with automatic M and B units

This commit is contained in:
lzt404 committed 2026-08-02 14:30:08 +08:00
1 parent 31c0ceaf08
commit 5924faaac3
4 files changed
+38 -8

No files matched your search

+3 -4
View File
@@ -670,10 +670,9 @@ export function ConfigPanelPage() {
<button
type="button"
className="secondary-button compact-button"
disabled={controlsDisabled}
onClick={generateManagementSecret}
>
<Sparkles size={16} aria-hidden="true" />
disabled={controlsDisabled}
onClick={generateManagementSecret}
>
{t('config.webuiKey.generate')}
</button>
<button
+2 -4
View File
@@ -3,6 +3,7 @@ import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import { Activity, BarChart3, CircleDollarSign, Clock3, Database, List, Pencil, RefreshCw, ShieldCheck, Sparkles, Trash2, TriangleAlert, X } from 'lucide-react';
import { getCurrentLocale, useI18n } from '../i18n';
import { formatUsageNumber } from '../services/usageNumber';
type UsageTab = 'overview' | 'analysis' | 'events' | 'pricing';
type UsageRange = '4h' | '24h' | 'today' | '7d' | '30d' | 'all' | 'custom';
@@ -190,10 +191,7 @@ const rangeQuery = (range: UsageRange, customStart: string, customEnd: string):
return { start: new Date(now.getTime() - hours * 3_600_000).toISOString(), end: now.toISOString() };
};
const compactNumber = (value: number) => 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;
+16
View File
@@ -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}`;
};
+17
View File
@@ -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');
});
});