fix(stats): top-списки и группировка по типу на list-страницах
Refs EventHub/EventHubFrontAdmin#27 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -204,8 +204,37 @@ const CalendarListPage: React.FC = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
|
{Object.entries(stats.calendars_by_type || {}).map(([type, count]) => (
|
||||||
|
<Col xs={12} sm={6} md={4} key={`type-${type}`}>
|
||||||
|
<Card>
|
||||||
|
<Statistic title={`Тип: ${type}`} value={count} />
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
|
{stats?.top_calendars_by_rating && stats.top_calendars_by_rating.length > 0 && (
|
||||||
|
<Card title="Топ календарей по рейтингу" style={{ marginBottom: 16 }}>
|
||||||
|
<Table
|
||||||
|
size="small"
|
||||||
|
pagination={false}
|
||||||
|
rowKey="id"
|
||||||
|
dataSource={stats.top_calendars_by_rating}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
title: 'Название',
|
||||||
|
dataIndex: 'title',
|
||||||
|
key: 'title',
|
||||||
|
render: (title: string, record) => (
|
||||||
|
<Link to={`/calendars/${record.id}`}>{title || record.id}</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ title: 'Рейтинг', dataIndex: 'rating_avg', key: 'rating_avg' },
|
||||||
|
{ title: 'Отзывов', dataIndex: 'review_count', key: 'review_count' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
<Space style={{ marginBottom: 16 }} wrap>
|
<Space style={{ marginBottom: 16 }} wrap>
|
||||||
<Input.Search
|
<Input.Search
|
||||||
placeholder="Поиск"
|
placeholder="Поиск"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { Table, Button, Tag, Space, Modal, Form, Select, Spin, Input, Tooltip, DatePicker, InputNumber, Card, Col, Row, Statistic } from 'antd';
|
import { Table, Button, Tag, Space, Modal, Form, Select, Spin, Input, Tooltip, DatePicker, InputNumber, Card, Col, Row, Statistic } from 'antd';
|
||||||
import { InfoCircleOutlined, EditOutlined, DeleteOutlined, CalendarOutlined } from '@ant-design/icons';
|
import { InfoCircleOutlined, EditOutlined, DeleteOutlined, CalendarOutlined } from '@ant-design/icons';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { useEvents, useUpdateEvent, useDeleteEvent, useEvent, useEventStats } from '../../hooks/useEvents';
|
import { useEvents, useUpdateEvent, useDeleteEvent, useEvent, useEventStats } from '../../hooks/useEvents';
|
||||||
import { Event, EventListParams } from '../../types/api';
|
import { Event, EventListParams } from '../../types/api';
|
||||||
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
import type { ColumnsType, SorterResult } from 'antd/es/table/interface';
|
||||||
@@ -228,8 +228,37 @@ const EventListPage: React.FC = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
|
{Object.entries(stats.events_by_type || {}).map(([type, count]) => (
|
||||||
|
<Col xs={12} sm={6} md={4} key={`type-${type}`}>
|
||||||
|
<Card>
|
||||||
|
<Statistic title={`Тип: ${type}`} value={count} />
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
|
{stats?.top_events_by_rating && stats.top_events_by_rating.length > 0 && (
|
||||||
|
<Card title="Топ событий по рейтингу" style={{ marginBottom: 16 }}>
|
||||||
|
<Table
|
||||||
|
size="small"
|
||||||
|
pagination={false}
|
||||||
|
rowKey="id"
|
||||||
|
dataSource={stats.top_events_by_rating}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
title: 'Название',
|
||||||
|
dataIndex: 'title',
|
||||||
|
key: 'title',
|
||||||
|
render: (title: string, record) => (
|
||||||
|
<Link to={`/events/${record.id}`}>{title || record.id}</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ title: 'Рейтинг', dataIndex: 'rating_avg', key: 'rating_avg' },
|
||||||
|
{ title: 'Отзывов', dataIndex: 'review_count', key: 'review_count' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={data?.data}
|
dataSource={data?.data}
|
||||||
|
|||||||
@@ -219,8 +219,37 @@ const ReportListPage: React.FC = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
|
{Object.entries(stats.reports_by_target_type || {}).map(([type, count]) => (
|
||||||
|
<Col xs={12} sm={6} md={4} key={`type-${type}`}>
|
||||||
|
<Card>
|
||||||
|
<Statistic title={`Цель: ${type}`} value={count} />
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
|
{stats?.top_targets_by_reports && stats.top_targets_by_reports.length > 0 && (
|
||||||
|
<Card title="Топ целей по жалобам" style={{ marginBottom: 16 }}>
|
||||||
|
<Table
|
||||||
|
size="small"
|
||||||
|
pagination={false}
|
||||||
|
rowKey={(r) => `${r.target_type}-${r.target_id}`}
|
||||||
|
dataSource={stats.top_targets_by_reports}
|
||||||
|
columns={[
|
||||||
|
{ title: 'Тип', dataIndex: 'target_type', key: 'target_type' },
|
||||||
|
{
|
||||||
|
title: 'ID цели',
|
||||||
|
dataIndex: 'target_id',
|
||||||
|
key: 'target_id',
|
||||||
|
render: (id: string, record) => (
|
||||||
|
<Link to={`/${record.target_type}s/${id}`}>{id}</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ title: 'Жалоб', dataIndex: 'report_count', key: 'report_count' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={data?.data}
|
dataSource={data?.data}
|
||||||
|
|||||||
@@ -253,8 +253,37 @@ const ReviewListPage: React.FC = () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
))}
|
||||||
|
{Object.entries(stats.reviews_by_target_type || {}).map(([type, count]) => (
|
||||||
|
<Col xs={12} sm={6} md={4} key={`type-${type}`}>
|
||||||
|
<Card>
|
||||||
|
<Statistic title={`Цель: ${type}`} value={count} />
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
|
{stats?.top_targets_by_reviews && stats.top_targets_by_reviews.length > 0 && (
|
||||||
|
<Card title="Топ целей по отзывам" style={{ marginBottom: 16 }}>
|
||||||
|
<Table
|
||||||
|
size="small"
|
||||||
|
pagination={false}
|
||||||
|
rowKey={(r) => `${r.target_type}-${r.target_id}`}
|
||||||
|
dataSource={stats.top_targets_by_reviews}
|
||||||
|
columns={[
|
||||||
|
{ title: 'Тип', dataIndex: 'target_type', key: 'target_type' },
|
||||||
|
{
|
||||||
|
title: 'ID цели',
|
||||||
|
dataIndex: 'target_id',
|
||||||
|
key: 'target_id',
|
||||||
|
render: (id: string, record) => (
|
||||||
|
<Link to={`/${record.target_type}s/${id}`}>{id}</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ title: 'Отзывов', dataIndex: 'review_count', key: 'review_count' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
<Space style={{ marginBottom: 16 }}>
|
<Space style={{ marginBottom: 16 }}>
|
||||||
<Button onClick={() => openBulkStatusModal('hidden')} disabled={selectedRowKeys.length === 0}>
|
<Button onClick={() => openBulkStatusModal('hidden')} disabled={selectedRowKeys.length === 0}>
|
||||||
Скрыть выбранные
|
Скрыть выбранные
|
||||||
|
|||||||
Reference in New Issue
Block a user