diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 55ef925..ee7e18b 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -32,6 +32,7 @@ import IPRangesManager from './IPRangesManager';
import ASNsNewManager from './ASNsNewManager';
import AutoUrlManager from './AutoUrlManager';
import BillingManager from './BillingManager';
+import Dashboard from './Dashboard';
import './App.css';
import axios from 'axios';
import {
@@ -107,7 +108,7 @@ function MainLayout() {
id: 'home',
title: 'Главная',
icon: IconHome,
- path: '/',
+ path: '/dashboard',
single: true
},
{
@@ -136,11 +137,7 @@ function MainLayout() {
title: 'Инструменты',
icon: IconSettings,
items: [
- { id: 'auto-urls', title: 'Авто URL', path: '/auto-urls', icon: IconDownload },
- { id: 'files', title: 'Файлы', path: '/files', icon: IconFileText },
- { id: 'cloud', title: 'Облако', path: '/cloud', icon: IconCloud },
- { id: 'security', title: 'Безопасность', path: '/security', icon: IconShield },
- { id: 'activity', title: 'Активность', path: '/activity', icon: IconActivity }
+ { id: 'auto-urls', title: 'Авто URL', path: '/auto-urls', icon: IconDownload }
]
},
{
@@ -288,6 +285,7 @@ function MainLayout() {
+ } />
} />
} />
} />
- } />
+ } />
);
}
-function StatCard({ icon: Icon, color, value, title, subtitle }) {
- return (
-
-
-
-
-
-
-
{value} {title}
-
{subtitle}
-
-
-
- );
-}
-function Dashboard() {
- const [stats, setStats] = useState({ domainsCount: null, asnsCount: null, serversCount: null, lastModified: null });
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- async function fetchStats() {
- setLoading(true);
- try {
- const [domainsRes, asnsRes, serversRes, s3Res] = await Promise.all([
- axios.get('/api/domains'),
- axios.get('/api/asns'),
- axios.get('/api/servers'),
- axios.get('/api/s3/last-modified')
- ]);
- setStats({
- domainsCount: domainsRes.data.length,
- asnsCount: asnsRes.data.length,
- serversCount: serversRes.data.length,
- lastModified: s3Res.data.domainsLastModified
- });
- } catch (e) {
- setStats({ domainsCount: null, asnsCount: null, serversCount: null, lastModified: null });
- } finally {
- setLoading(false);
- }
- }
- fetchStats();
- }, []);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Dashboard
-
Главная / Dashboard
-
-
-
-
- );
-}
export default App;
diff --git a/frontend/src/Dashboard.jsx b/frontend/src/Dashboard.jsx
new file mode 100644
index 0000000..d37296f
--- /dev/null
+++ b/frontend/src/Dashboard.jsx
@@ -0,0 +1,297 @@
+import { useState, useEffect } from 'react';
+import axios from 'axios';
+import {
+ IconWorld,
+ IconNetwork,
+ IconServer,
+ IconDatabase,
+ IconActivity,
+ IconTrendingUp,
+ IconTrendingDown,
+ IconClock,
+ IconMapPin,
+ IconCloud,
+ IconShield,
+ IconAlertTriangle
+} from '@tabler/icons-react';
+
+function StatCard({ icon: Icon, color, value, title, subtitle, trend, trendValue }) {
+ return (
+
+
+
+
+
+
+
{value} {title}
+
{subtitle}
+ {trend && (
+
+ {trend === 'up' ? : }
+ {trendValue}
+
+ )}
+
+
+
+ );
+}
+
+function MetricCard({ title, value, icon: Icon, color, description }) {
+ return (
+
+
+
+ {description && (
+
{description}
+ )}
+
+
+ );
+}
+
+function Dashboard() {
+ const [stats, setStats] = useState({
+ domainsCount: null,
+ ipRangesCount: null,
+ asnsCount: null,
+ serversCount: null,
+ lastModified: null,
+ countriesCount: null,
+ providersCount: null,
+ onlineServers: null,
+ totalServers: null
+ });
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ async function fetchStats() {
+ setLoading(true);
+ setError(null);
+ try {
+ const [domainsRes, ipRangesRes, asnsRes, serversRes, s3Res] = await Promise.all([
+ axios.get('/api/domains'),
+ axios.get('/api/ip-ranges'),
+ axios.get('/api/asns'),
+ axios.get('/api/servers'),
+ axios.get('/api/s3/last-modified')
+ ]);
+
+ // Подсчет уникальных стран и провайдеров из серверов
+ const servers = serversRes.data;
+ const countries = new Set(servers.map(server => server.country).filter(Boolean));
+ const providers = new Set(servers.map(server => server.provider).filter(Boolean));
+ const onlineServers = servers.filter(server => server.status === 'Онлайн').length;
+
+ setStats({
+ domainsCount: domainsRes.data.length,
+ ipRangesCount: ipRangesRes.data.length,
+ asnsCount: asnsRes.data.length,
+ serversCount: servers.length,
+ lastModified: s3Res.data?.domainsLastModified || null,
+ countriesCount: countries.size,
+ providersCount: providers.size,
+ onlineServers,
+ totalServers: servers.length
+ });
+ } catch (e) {
+ console.error('Ошибка загрузки статистики:', e);
+ setError('Не удалось загрузить статистику');
+ setStats({
+ domainsCount: null,
+ ipRangesCount: null,
+ asnsCount: null,
+ serversCount: null,
+ lastModified: null,
+ countriesCount: null,
+ providersCount: null,
+ onlineServers: null,
+ totalServers: null
+ });
+ } finally {
+ setLoading(false);
+ }
+ }
+ fetchStats();
+ }, []);
+
+ if (error) {
+ return (
+
+
+ {error}
+
+ );
+ }
+
+ return (
+
+ {/* Заголовок страницы */}
+
+
+
+
Dashboard
+
Главная / Dashboard
+
+
+
+
+
+
+
+
+
+ {/* Основные метрики */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Дополнительные метрики */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Графики и диаграммы (заглушки для будущего) */}
+
+
+
+
+
Распределение по странам
+
+
+
+
+
График распределения серверов по странам
+
Будет добавлен в следующем обновлении
+
+
+
+
+
+
+
+
Активность обновлений
+
+
+
+
+
График активности обновлений данных
+
Будет добавлен в следующем обновлении
+
+
+
+
+
+
+ );
+}
+
+export default Dashboard;
\ No newline at end of file