From 3815ac767cf0a622f7488e9f81105968a7e9ee1b Mon Sep 17 00:00:00 2001 From: "Nik (Claude)" Date: Tue, 16 Jun 2026 14:08:36 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20spending=20=E2=80=94=20beautiful=20prov?= =?UTF-8?q?ider=20cards=20with=20progress=20bar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/AdminPanel.js | 116 ++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/components/AdminPanel.js b/components/AdminPanel.js index b207794..cb0103e 100644 --- a/components/AdminPanel.js +++ b/components/AdminPanel.js @@ -339,65 +339,67 @@ function SpendingSection() { ))} - {/* По провайдерам */} -
- {[ - { 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}
+ {/* По провайдерам — крупные карточки */} + {(() => { + const providers = [ + { key: 'aiprimetech', label: 'aiprimetech.io', icon: '💬', desc: 'Текст — статьи и посты', color: 'text-blue-400', bg: 'bg-blue-500/10', border: 'border-blue-500/20' }, + { key: 'routerai', label: 'routerai.ru', icon: '🖼', desc: 'Картинки к постам', color: 'text-purple-400', bg: 'bg-purple-500/10', border: 'border-purple-500/20' }, + ]; + const totalRub = providers.reduce((sum, p) => { + const d = byProv?.breakdown?.find(b => b.key === p.key); + return sum + Number(d?.cost_rub || 0); + }, 0); + return ( +
+
Расходы по провайдерам
+ {providers.map(({ key, label, icon, desc, color, bg, border }) => { + const d = byProv?.breakdown?.find(b => b.key === key); + const rub = Number(d?.cost_rub || 0); + const pct = totalRub > 0 ? Math.round(rub / totalRub * 100) : 0; + const vol = key === 'routerai' + ? `${fmtI(d?.image_count || 0)} картинок` + : `${fmtI((d?.prompt_tokens||0)+(d?.completion_tokens||0))} токенов`; + return ( +
+
+
+ {icon} +
+
{label}
+
{desc}
+
+
+
+
₽ {fmt(rub)}
+
{pct}% от общего
+
+
+ {/* Прогресс-бар */} +
+
+
+ {/* Метрики */} +
+
+
{fmtI(d?.calls)}
+
запросов
+
+
+
0 ? 'text-red-400' : 'text-gray-200'}`}>{d?.failed||0}
+
ошибок
+
+
+
{vol}
+
объём
+
+
-
₽ {fmt(d?.cost_rub)}
-
-
-
{fmtI(d?.calls)}
запросов
-
{d?.failed||0}
ошибок
-
{fmtI(d?.image_count || (d?.prompt_tokens||0)+(d?.completion_tokens||0))}
{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)}
-
- )} + ); + })()} {/* Таблица по операциям */}