Разработка админ-панели EventHubFrontAdmin v1.0 #1

This commit is contained in:
2026-05-23 20:43:21 +03:00
parent 36c95b71a4
commit f5961c5529
68 changed files with 10374 additions and 3 deletions
+238
View File
@@ -0,0 +1,238 @@
import React from 'react';
import { Card, Col, Row, Statistic, Spin, Alert, Table, Tag } from 'antd';
import {
UserOutlined,
CalendarOutlined,
StarOutlined,
TeamOutlined,
WarningOutlined,
BugOutlined,
ClockCircleOutlined,
} from '@ant-design/icons';
import { useDashboardStats } from '../../hooks/useDashboard';
import type { ColumnsType } from 'antd/es/table';
import { AdminActivity } from '../../types/api';
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
AreaChart,
Area,
} from 'recharts';
const DashboardPage: React.FC = () => {
const { data, isLoading, error } = useDashboardStats();
if (isLoading) return <Spin size="large" style={{ display: 'block', margin: '100px auto' }} />;
if (error) return <Alert type="error" message="Ошибка загрузки статистики" />;
if (!data) return null;
const roleColors: Record<string, string> = {
superadmin: 'red',
admin: 'blue',
moderator: 'purple',
support: 'cyan',
};
const adminColumns: ColumnsType<AdminActivity> = [
{ title: 'Email', dataIndex: 'email', key: 'email' },
{ title: 'Ник', dataIndex: 'nickname', key: 'nickname' },
{
title: 'Роль',
dataIndex: 'role',
key: 'role',
render: (role: string) => (
<Tag color={roleColors[role] || 'default'}>{role}</Tag>
),
},
{ title: 'Действий', dataIndex: 'actions', key: 'actions' },
{ title: 'Последний вход', dataIndex: 'last_login', key: 'last_login' },
];
const eventsChartData = data.events_by_day?.map(item => ({
date: item.date,
events: item.count,
})) || [];
const registrationsChartData = data.registrations_by_day?.map(item => ({
date: item.date,
registrations: item.count,
})) || [];
return (
<div>
<h2>Общая статистика</h2>
<Row gutter={[16, 16]}>
{/* Пользователи с мини-графиком */}
<Col xs={24} sm={12} lg={6}>
<Card>
<div style={{ display: 'flex', alignItems: 'center' }}>
<Statistic
title="Пользователи"
value={data.users_total}
prefix={<UserOutlined />}
style={{ flex: '0 0 auto', marginRight: 16 }}
/>
{registrationsChartData.length > 0 && (
<AreaChart
width={150}
height={50}
data={registrationsChartData}
margin={{ top: 5, right: 0, left: 0, bottom: 0 }}
>
<defs>
<linearGradient id="colorRegistrations" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#52c41a" stopOpacity={0.4} />
<stop offset="95%" stopColor="#52c41a" stopOpacity={0.05} />
</linearGradient>
</defs>
<XAxis dataKey="date" hide />
<Tooltip labelFormatter={(label) => `Дата: ${label}`} />
<Area
type="monotone"
dataKey="registrations"
name="Регистрации"
stroke="#52c41a"
fill="url(#colorRegistrations)"
strokeWidth={2}
dot={false}
activeDot={{ r: 3, strokeWidth: 0 }}
/>
</AreaChart>
)}
</div>
</Card>
</Col>
{/* События с мини-графиком */}
<Col xs={24} sm={12} lg={6}>
<Card>
<div style={{ display: 'flex', alignItems: 'center' }}>
<Statistic
title="События"
value={data.events_total}
prefix={<TeamOutlined />}
style={{ flex: '0 0 auto', marginRight: 16 }}
/>
{eventsChartData.length > 0 && (
<AreaChart
width={150}
height={50}
data={eventsChartData}
margin={{ top: 5, right: 0, left: 0, bottom: 0 }}
>
<defs>
<linearGradient id="colorEvents" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#1890ff" stopOpacity={0.4} />
<stop offset="95%" stopColor="#1890ff" stopOpacity={0.05} />
</linearGradient>
</defs>
<XAxis dataKey="date" hide />
<Tooltip labelFormatter={(label) => `Дата: ${label}`} />
<Area
type="monotone"
dataKey="events"
name="События"
stroke="#1890ff"
fill="url(#colorEvents)"
strokeWidth={2}
dot={false}
activeDot={{ r: 3, strokeWidth: 0 }}
/>
</AreaChart>
)}
</div>
</Card>
</Col>
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Отзывы" value={data.reviews_total} prefix={<StarOutlined />} />
</Card>
</Col>
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Календари" value={data.calendars_total} prefix={<CalendarOutlined />} />
</Card>
</Col>
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Жалобы" value={data.reports_total} prefix={<WarningOutlined />} />
</Card>
</Col>
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Тикеты (всего)" value={data.tickets_total} prefix={<BugOutlined />} />
</Card>
</Col>
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic
title="Открытых тикетов"
value={data.tickets_open}
prefix={<ClockCircleOutlined />}
/>
</Card>
</Col>
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic
title="Среднее время решения (ч)"
value={data.avg_ticket_resolution_h}
precision={1}
/>
</Card>
</Col>
</Row>
<Row gutter={[16, 16]} style={{ marginTop: 32 }}>
<Col xs={24} lg={12}>
<Card title="События по дням">
<ResponsiveContainer width="100%" height={300}>
<LineChart data={eventsChartData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis allowDecimals={false} />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="events" stroke="#1890ff" name="События" />
</LineChart>
</ResponsiveContainer>
</Card>
</Col>
<Col xs={24} lg={12}>
<Card title="Регистрации по дням">
<ResponsiveContainer width="100%" height={300}>
<LineChart data={registrationsChartData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis allowDecimals={false} />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="registrations" stroke="#52c41a" name="Регистрации" />
</LineChart>
</ResponsiveContainer>
</Card>
</Col>
</Row>
<h2 style={{ marginTop: 32 }}>Активность администраторов</h2>
<Table
columns={adminColumns}
dataSource={data.admin_activity}
rowKey="admin_id"
pagination={false}
size="small"
/>
</div>
);
};
export default DashboardPage;