fix(usage): update chart labels when locale changes

This commit is contained in:
Supra4E8C
2026-02-13 15:24:00 +08:00
parent c53a231c41
commit 9ef7d439d2
2 changed files with 36 additions and 38 deletions

View File

@@ -8,7 +8,7 @@ import {
buildHourlyCostSeries, buildHourlyCostSeries,
buildDailyCostSeries, buildDailyCostSeries,
formatUsd, formatUsd,
type ModelPrice, type ModelPrice
} from '@/utils/usage'; } from '@/utils/usage';
import { buildChartOptions, getHourChartMinWidth } from '@/utils/usage/chartConfig'; import { buildChartOptions, getHourChartMinWidth } from '@/utils/usage/chartConfig';
import type { UsagePayload } from './hooks/useUsageData'; import type { UsagePayload } from './hooks/useUsageData';
@@ -43,7 +43,7 @@ export function CostTrendChart({
isDark, isDark,
isMobile, isMobile,
modelPrices, modelPrices,
hourWindowHours, hourWindowHours
}: CostTrendChartProps) { }: CostTrendChartProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const [period, setPeriod] = useState<'hour' | 'day'>('hour'); const [period, setPeriod] = useState<'hour' | 'day'>('hour');
@@ -70,9 +70,9 @@ export function CostTrendChart({
pointBackgroundColor: COST_COLOR, pointBackgroundColor: COST_COLOR,
pointBorderColor: COST_COLOR, pointBorderColor: COST_COLOR,
fill: true, fill: true,
tension: 0.35, tension: 0.35
}, }
], ]
}; };
const baseOptions = buildChartOptions({ period, labels: series.labels, isDark, isMobile }); const baseOptions = buildChartOptions({ period, labels: series.labels, isDark, isMobile });
@@ -84,15 +84,14 @@ export function CostTrendChart({
...baseOptions.scales?.y, ...baseOptions.scales?.y,
ticks: { ticks: {
...(baseOptions.scales?.y && 'ticks' in baseOptions.scales.y ? baseOptions.scales.y.ticks : {}), ...(baseOptions.scales?.y && 'ticks' in baseOptions.scales.y ? baseOptions.scales.y.ticks : {}),
callback: (value: string | number) => formatUsd(Number(value)), callback: (value: string | number) => formatUsd(Number(value))
}, }
}, }
}, }
}; };
return { chartData: data, chartOptions: options, hasData: series.hasData }; return { chartData: data, chartOptions: options, hasData: series.hasData };
// eslint-disable-next-line react-hooks/exhaustive-deps }, [usage, period, isDark, isMobile, modelPrices, hasPrices, hourWindowHours, t]);
}, [usage, period, isDark, isMobile, modelPrices, hasPrices, hourWindowHours]);
return ( return (
<Card <Card

View File

@@ -6,17 +6,17 @@ import { Button } from '@/components/ui/Button';
import { import {
buildHourlyTokenBreakdown, buildHourlyTokenBreakdown,
buildDailyTokenBreakdown, buildDailyTokenBreakdown,
type TokenCategory, type TokenCategory
} from '@/utils/usage'; } from '@/utils/usage';
import { buildChartOptions, getHourChartMinWidth } from '@/utils/usage/chartConfig'; import { buildChartOptions, getHourChartMinWidth } from '@/utils/usage/chartConfig';
import type { UsagePayload } from './hooks/useUsageData'; import type { UsagePayload } from './hooks/useUsageData';
import styles from '@/pages/UsagePage.module.scss'; import styles from '@/pages/UsagePage.module.scss';
const TOKEN_COLORS: Record<TokenCategory, { border: string; bg: string }> = { const TOKEN_COLORS: Record<TokenCategory, { border: string; bg: string }> = {
input: { border: '#3b82f6', bg: 'rgba(59, 130, 246, 0.25)' }, input: { border: '#3b82f6', bg: 'rgba(59, 130, 246, 0.25)' },
output: { border: '#22c55e', bg: 'rgba(34, 197, 94, 0.25)' }, output: { border: '#22c55e', bg: 'rgba(34, 197, 94, 0.25)' },
cached: { border: '#f59e0b', bg: 'rgba(245, 158, 11, 0.25)' }, cached: { border: '#f59e0b', bg: 'rgba(245, 158, 11, 0.25)' },
reasoning: { border: '#8b5cf6', bg: 'rgba(139, 92, 246, 0.25)' }, reasoning: { border: '#8b5cf6', bg: 'rgba(139, 92, 246, 0.25)' }
}; };
const CATEGORIES: TokenCategory[] = ['input', 'output', 'cached', 'reasoning']; const CATEGORIES: TokenCategory[] = ['input', 'output', 'cached', 'reasoning'];
@@ -34,56 +34,55 @@ export function TokenBreakdownChart({
loading, loading,
isDark, isDark,
isMobile, isMobile,
hourWindowHours, hourWindowHours
}: TokenBreakdownChartProps) { }: TokenBreakdownChartProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const [period, setPeriod] = useState<'hour' | 'day'>('hour'); const [period, setPeriod] = useState<'hour' | 'day'>('hour');
const CATEGORY_LABELS: Record<TokenCategory, string> = {
input: t('usage_stats.input_tokens'),
output: t('usage_stats.output_tokens'),
cached: t('usage_stats.cached_tokens'),
reasoning: t('usage_stats.reasoning_tokens'),
};
const { chartData, chartOptions } = useMemo(() => { const { chartData, chartOptions } = useMemo(() => {
const series = const series =
period === 'hour' period === 'hour'
? buildHourlyTokenBreakdown(usage, hourWindowHours) ? buildHourlyTokenBreakdown(usage, hourWindowHours)
: buildDailyTokenBreakdown(usage); : buildDailyTokenBreakdown(usage);
const categoryLabels: Record<TokenCategory, string> = {
input: t('usage_stats.input_tokens'),
output: t('usage_stats.output_tokens'),
cached: t('usage_stats.cached_tokens'),
reasoning: t('usage_stats.reasoning_tokens')
};
const data = { const data = {
labels: series.labels, labels: series.labels,
datasets: CATEGORIES.map((cat) => ({ datasets: CATEGORIES.map((cat) => ({
label: CATEGORY_LABELS[cat], label: categoryLabels[cat],
data: series.dataByCategory[cat], data: series.dataByCategory[cat],
borderColor: TOKEN_COLORS[cat].border, borderColor: TOKEN_COLORS[cat].border,
backgroundColor: TOKEN_COLORS[cat].bg, backgroundColor: TOKEN_COLORS[cat].bg,
pointBackgroundColor: TOKEN_COLORS[cat].border, pointBackgroundColor: TOKEN_COLORS[cat].border,
pointBorderColor: TOKEN_COLORS[cat].border, pointBorderColor: TOKEN_COLORS[cat].border,
fill: true, fill: true,
tension: 0.35, tension: 0.35
})), }))
}; };
const baseOptions = buildChartOptions({ period, labels: series.labels, isDark, isMobile });
const options = { const options = {
...buildChartOptions({ period, labels: series.labels, isDark, isMobile }), ...baseOptions,
scales: { scales: {
...buildChartOptions({ period, labels: series.labels, isDark, isMobile }).scales, ...baseOptions.scales,
y: { y: {
...buildChartOptions({ period, labels: series.labels, isDark, isMobile }).scales?.y, ...baseOptions.scales?.y,
stacked: true, stacked: true
}, },
x: { x: {
...buildChartOptions({ period, labels: series.labels, isDark, isMobile }).scales?.x, ...baseOptions.scales?.x,
stacked: true, stacked: true
}, }
}, }
}; };
return { chartData: data, chartOptions: options, hasData: series.hasData }; return { chartData: data, chartOptions: options };
// eslint-disable-next-line react-hooks/exhaustive-deps }, [usage, period, isDark, isMobile, hourWindowHours, t]);
}, [usage, period, isDark, isMobile, hourWindowHours]);
return ( return (
<Card <Card