From 7a21c83d3e7dbdcfeb3868c0351992816b574646 Mon Sep 17 00:00:00 2001 From: nns <278048682+nurdotnet@users.noreply.github.com> Date: Sun, 26 Apr 2026 15:47:13 +0500 Subject: [PATCH] =?UTF-8?q?ui(super-admin):=20SaaS-=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D0=BA=D0=B8=20=D0=BD=D0=B0=20=D0=B3=D0=BB=D0=B0?= =?UTF-8?q?=D0=B2=D0=BD=D0=BE=D0=B9=20=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D0=BA=D0=BE=D0=BD=D1=81=D0=BE=D0=BB=D0=B8?= =?UTF-8?q?=20(placeholders)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Food Market — SaaS для розницы, SuperAdmin это владелец платформы, а не сотрудник магазина. Операционные метрики магазинов («Товаров 29540», «Приёмок за месяц») для него бесполезны — это для tenant dashboard'а конкретной орги. KPI блок на /super-admin переработан под кабинет SaaS-провайдера: Top row (4 карточки): - Организаций (как было — клиентская база) - Платящих клиентов — placeholder, accent emerald, muted - MRR (₸ / мес) — placeholder, accent violet, muted - Должники — placeholder, accent rose, muted Second row (2 карточки): - Пользователей (всего/активных) - Регистраций за 30 дней — реальное значение (COUNT Organizations WHERE CreatedAt >= now-30d) Заглушки получили проп muted=true: фон чуть серее (slate-50/60), значение «—» более бледным slate-400, иконка остаётся полноцветной чтобы было видно «здесь будут данные после Phase 4». В hint — «Скоро · после внедрения биллинга». API: DashboardStats потерял TotalProducts/TotalSuppliesThisMonth, получил RegistrationsLast30Days. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../SuperAdmin/SuperAdminController.cs | 8 ++-- .../src/pages/SuperAdminDashboardPage.tsx | 41 +++++++++++++++---- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/food-market.api/Controllers/SuperAdmin/SuperAdminController.cs b/src/food-market.api/Controllers/SuperAdmin/SuperAdminController.cs index cda385c..c04f68a 100644 --- a/src/food-market.api/Controllers/SuperAdmin/SuperAdminController.cs +++ b/src/food-market.api/Controllers/SuperAdmin/SuperAdminController.cs @@ -29,11 +29,14 @@ public async Task> GetSetupStatus(CancellationToken public record DashboardStats( int TotalOrgs, int ActiveOrgs, int ArchivedOrgs, int TotalUsers, int ActiveUsers, - int TotalProducts, int TotalSuppliesThisMonth); + int RegistrationsLast30Days); [HttpGet("dashboard")] public async Task> Dashboard(CancellationToken ct) { + // Метрики SuperAdmin'а — кабинет SaaS-владельца, не операционные + // показатели магазинов. Биллинговые KPI (MRR, должники, платящие) + // считаем на UI как заглушки — отдельный модуль подписки в Phase 4+. var monthAgo = DateTime.UtcNow.AddDays(-30); return new DashboardStats( TotalOrgs: await _db.Organizations.IgnoreQueryFilters().CountAsync(ct), @@ -41,8 +44,7 @@ public async Task> Dashboard(CancellationToken ct) ArchivedOrgs: await _db.Organizations.IgnoreQueryFilters().CountAsync(o => o.IsArchived, ct), TotalUsers: await _db.Users.CountAsync(ct), ActiveUsers: await _db.Users.CountAsync(u => u.IsActive, ct), - TotalProducts: await _db.Products.IgnoreQueryFilters().CountAsync(ct), - TotalSuppliesThisMonth: await _db.Supplies.IgnoreQueryFilters().CountAsync(s => s.Date >= monthAgo, ct)); + RegistrationsLast30Days: await _db.Organizations.IgnoreQueryFilters().CountAsync(o => o.CreatedAt >= monthAgo, ct)); } public record AuditRow( diff --git a/src/food-market.web/src/pages/SuperAdminDashboardPage.tsx b/src/food-market.web/src/pages/SuperAdminDashboardPage.tsx index 5d23ff6..adf77f3 100644 --- a/src/food-market.web/src/pages/SuperAdminDashboardPage.tsx +++ b/src/food-market.web/src/pages/SuperAdminDashboardPage.tsx @@ -1,15 +1,17 @@ import { useQuery } from '@tanstack/react-query' import { Link } from 'react-router-dom' import { - Building2, Users, Package, ShoppingCart, FileClock, + Building2, Users, FileClock, CheckCircle2, AlertCircle, Activity, Inbox, ShieldCheck, + CreditCard, TrendingUp, AlertTriangle, UserPlus, } from 'lucide-react' import { api } from '@/lib/api' +import { cn } from '@/lib/utils' interface DashboardStats { totalOrgs: number; activeOrgs: number; archivedOrgs: number totalUsers: number; activeUsers: number - totalProducts: number; totalSuppliesThisMonth: number + registrationsLast30Days: number } interface AuditRow { @@ -19,26 +21,36 @@ interface AuditRow { const fmt = new Intl.NumberFormat('ru') -function Kpi({ icon: Icon, label, value, hint, accent = 'indigo' }: { +function Kpi({ icon: Icon, label, value, hint, accent = 'indigo', muted = false }: { icon: React.ComponentType<{ className?: string }> label: string; value: string | number; hint?: string - accent?: 'indigo' | 'emerald' | 'amber' | 'sky' + accent?: 'indigo' | 'emerald' | 'amber' | 'sky' | 'rose' | 'violet' + /** «Скоро» — заглушка под будущий биллинг. Тонировка фона сильнее, + * но иконка остаётся цветной чтобы было ясно «здесь будет данные». */ + muted?: boolean }) { const accents: Record = { indigo: 'bg-indigo-100 text-indigo-600 dark:bg-indigo-900/40 dark:text-indigo-300', emerald: 'bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-300', amber: 'bg-amber-100 text-amber-600 dark:bg-amber-900/40 dark:text-amber-300', sky: 'bg-sky-100 text-sky-600 dark:bg-sky-900/40 dark:text-sky-300', + rose: 'bg-rose-100 text-rose-600 dark:bg-rose-900/40 dark:text-rose-300', + violet: 'bg-violet-100 text-violet-600 dark:bg-violet-900/40 dark:text-violet-300', } return ( -
+
{label}
-
{value}
+
{value}
{hint &&
{hint}
}
@@ -98,14 +110,25 @@ export function SuperAdminDashboardPage() {
- {/* KPI cards */} + {/* KPI: SaaS-владелец платформы. Главный ряд — клиентская база + * и биллинг (последние 3 — заглушки до Phase 4 «Подписки»). + * Второй ряд — инфраструктура учёток. Операционные метрики + * магазинов (товары/приёмки) выкинуты — это для tenant-дашборда. */}
+ + + +
+
- - +
{/* Three side-by-side blocks */}