feat(usage): format statistics with automatic M and B units
This commit is contained in:
1 parent
31c0ceaf08
commit
5924faaac3
4 files changed
+38
-8
No files matched your search
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}`;
|
||||
};
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user