Files
EventHubFrontAdmin/src/pages/dashboard/DashboardPage.tsx
T
aleksey a1bd11afee fix(dashboard): ролевые виды и ссылка на аудит вместо дубля
Moderator/support видят свою статистику; admin_activity заменён ссылкой на /audit.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 17:54:51 +03:00

218 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React from 'react';
import { Card, Col, Row, Statistic, Spin, Alert, Button } from 'antd';
import {
UserOutlined,
CalendarOutlined,
StarOutlined,
TeamOutlined,
WarningOutlined,
BugOutlined,
ClockCircleOutlined,
DollarOutlined,
} from '@ant-design/icons';
import { Link, useNavigate } from 'react-router-dom';
import { useDashboardStats } from '../../hooks/useDashboard';
import { useAuthStore } from '../../store/authStore';
import DailyLineChartCard from '../../components/DailyLineChartCard';
import StatisticSparklineCard from '../../components/StatisticSparklineCard';
const DashboardPage: React.FC = () => {
const { data, isLoading, error } = useDashboardStats();
const role = useAuthStore((s) => s.user?.role);
const navigate = useNavigate();
if (isLoading) return <Spin size="large" style={{ display: 'block', margin: '100px auto' }} />;
if (error) return <Alert type="error" message="Ошибка загрузки статистики" />;
if (!data) return null;
if (role === 'moderator') {
return (
<div>
<h2>Модерация</h2>
<Row gutter={[16, 16]}>
<Col xs={24} sm={8}>
<Card><Statistic title="Рассмотрено" value={data.reports_reviewed ?? 0} prefix={<WarningOutlined />} /></Card>
</Col>
<Col xs={24} sm={8}>
<Card><Statistic title="Отклонено" value={data.reports_dismissed ?? 0} /></Card>
</Col>
<Col xs={24} sm={8}>
<Card><Statistic title="Ср. время (ч)" value={data.avg_report_resolution_h ?? 0} precision={1} prefix={<ClockCircleOutlined />} /></Card>
</Col>
</Row>
<Button type="primary" style={{ marginTop: 16 }} onClick={() => navigate('/reports')}>
Перейти к жалобам
</Button>
</div>
);
}
if (role === 'support') {
return (
<div>
<h2>Поддержка</h2>
<Row gutter={[16, 16]}>
<Col xs={24} sm={8}>
<Card><Statistic title="Назначено открытых" value={data.tickets_assigned_open ?? 0} prefix={<BugOutlined />} /></Card>
</Col>
<Col xs={24} sm={8}>
<Card><Statistic title="Всего назначено" value={data.tickets_assigned_total ?? 0} /></Card>
</Col>
<Col xs={24} sm={8}>
<Card><Statistic title="Ср. решение (ч)" value={data.avg_ticket_resolution_h ?? 0} precision={1} prefix={<ClockCircleOutlined />} /></Card>
</Col>
</Row>
<Button type="primary" style={{ marginTop: 16 }} onClick={() => navigate('/tickets')}>
Перейти к тикетам
</Button>
</div>
);
}
const registrationsSparkline = data.registrations_by_day?.map((item) => ({
date: item.date,
value: item.count,
})) ?? [];
const eventsSparkline = data.events_by_day?.map((item) => ({
date: item.date,
value: item.count,
})) ?? [];
return (
<div>
<h2>Общая статистика</h2>
<Row gutter={[16, 16]}>
<Col xs={24} sm={12} lg={6}>
<StatisticSparklineCard
title="Пользователи"
value={data.users_total}
prefix={<UserOutlined />}
data={registrationsSparkline}
color="#52c41a"
gradientId="colorRegistrations"
/>
</Col>
<Col xs={24} sm={12} lg={6}>
<StatisticSparklineCard
title="События"
value={data.events_total}
prefix={<TeamOutlined />}
data={eventsSparkline}
color="#1890ff"
gradientId="colorEvents"
/>
</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>
{data.pending_users_total !== undefined && (
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Неподтверждённые" value={data.pending_users_total} prefix={<UserOutlined />} />
</Card>
</Col>
)}
{data.reports_pending !== undefined && (
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Жалобы: pending" value={data.reports_pending} />
</Card>
</Col>
)}
{data.reports_reviewed !== undefined && (
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Жалобы: reviewed" value={data.reports_reviewed} />
</Card>
</Col>
)}
{data.reports_dismissed !== undefined && (
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Жалобы: dismissed" value={data.reports_dismissed} />
</Card>
</Col>
)}
{data.subscriptions_total !== undefined && (
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Подписки" value={data.subscriptions_total} prefix={<DollarOutlined />} />
</Card>
</Col>
)}
{data.trial_subscriptions !== undefined && (
<Col xs={24} sm={12} lg={6}>
<Card>
<Statistic title="Пробные подписки" value={data.trial_subscriptions} />
</Card>
</Col>
)}
</Row>
<Row gutter={[16, 16]} style={{ marginTop: 32 }}>
<DailyLineChartCard title="События по дням" data={data.events_by_day} color="#1890ff" />
<DailyLineChartCard title="Регистрации по дням" data={data.registrations_by_day} color="#52c41a" />
<DailyLineChartCard title="Отзывы по дням" data={data.reviews_by_day} color="#faad14" />
<DailyLineChartCard title="Календари по дням" data={data.calendars_by_day} color="#722ed1" />
<DailyLineChartCard title="Жалобы по дням" data={data.reports_by_day} color="#ff4d4f" />
<DailyLineChartCard title="Тикеты по дням" data={data.tickets_by_day} color="#13c2c2" />
<DailyLineChartCard title="Подписки по дням" data={data.subscriptions_by_day} color="#eb2f96" />
<DailyLineChartCard title="Неподтверждённые по дням" data={data.pending_users_by_day} color="#fa8c16" />
</Row>
{role === 'superadmin' && (
<Alert
style={{ marginTop: 32 }}
type="info"
showIcon
message="Активность администраторов"
description={<>Подробный журнал действий в разделе <Link to="/audit">Аудит</Link>.</>}
/>
)}
</div>
);
};
export default DashboardPage;