diff --git a/components/AdminPanel.js b/components/AdminPanel.js index 52e5cb0..b207794 100644 --- a/components/AdminPanel.js +++ b/components/AdminPanel.js @@ -266,7 +266,7 @@ const PERIODS = [ { v: 'today', label: 'Сегодня' }, { v: 'week', label: '7 дней' }, { v: 'month', label: '30 дней' }, - { v: 'alltime', label: 'Всё время' }, + { v: 'all', label: 'Всё время' }, ]; const TYPE_LABELS = { @@ -281,7 +281,7 @@ function fmt(n) { return Number(n || 0).toFixed(2); } function fmtI(n) { return Number(n || 0).toLocaleString('ru-RU'); } function SpendingSection() { - const [period, setPeriod] = useState('month'); + const [period, setPeriod] = useState('all'); const [data, setData] = useState(null); const [byProv, setByProv] = useState(null); const [loading, setLoading] = useState(false); @@ -290,8 +290,8 @@ function SpendingSection() { setLoading(true); try { const [r1, r2] = await Promise.all([ - fetch(`/api/usage/summary?range=${p}&group_by=request_type`).then(r => r.json()), - fetch(`/api/usage/summary?range=${p}&group_by=provider`).then(r => r.json()), + fetch(`/api/usage/summary?range=${p === 'alltime' ? 'all' : p}&group_by=request_type`).then(r => r.json()), + fetch(`/api/usage/summary?range=${p === 'alltime' ? 'all' : p}&group_by=provider`).then(r => r.json()), ]); setData(r1); setByProv(r2); } catch {} @@ -342,27 +342,63 @@ function SpendingSection() { {/* По провайдерам */}
{[ - { key: 'aiprimetech', label: 'aiprimetech.io', icon: '💬', desc: 'Текст', data: aiprimetech }, - { key: 'routerai', label: 'routerai.ru', icon: '🖼', desc: 'Картинки', data: routerai }, - ].map(p => ( -
-
- {p.icon} -
-
{p.label}
-
{p.desc}
+ { key: 'aiprimetech', label: 'aiprimetech.io', icon: '💬', desc: 'Текст' }, + { key: 'routerai', label: 'routerai.ru', icon: '🖼', desc: 'Картинки' }, + ].map(({ key, label, icon, desc }) => { + const d = byProv?.breakdown?.find(b => b.key === key); + return ( +
+
+ {icon} +
+
{label}
+
{desc}
+
+
₽ {fmt(d?.cost_rub)}
+
+
+
{fmtI(d?.calls)}
запросов
+
{d?.failed||0}
ошибок
+
{fmtI(d?.image_count || (d?.prompt_tokens||0)+(d?.completion_tokens||0))}
{key==='routerai'?'картинок':'токенов'}
-
₽ {fmt(p.data?.cost_rub)}
-
-
{fmtI(p.data?.calls)}
запросов
-
{p.data?.failed||0}
ошибок
-
{fmtI(p.data?.image_count || (p.data?.prompt_tokens||0)+(p.data?.completion_tokens||0))}
{p.key==='routerai'?'картинок':'токенов'}
-
-
- ))} + ); + })}
+ {/* Все провайдеры (включая fallback) */} + {byProv?.breakdown?.length > 2 && ( +
+
+ Все провайдеры +
+ + + + + + + + + + + + {byProv.breakdown.map((row, i) => ( + + + + + + + + ))} + +
ПровайдерЗапросовОшибокОбъёмСтоимость
{row.key}{fmtI(row.calls)}{row.failed||0} + {row.image_count > 0 ? `${row.image_count} шт.` : fmtI((row.prompt_tokens||0)+(row.completion_tokens||0))} + ₽ {fmt(row.cost_rub)}
+
+ )} + {/* Таблица по операциям */}