feat(stats): переписать дашборд статистики с Flet на React
stats/ (Flet) генерировал графики через matplotlib в PNG и отдавал их через Flutter web с WebSocket — та же архитектура, что подводила основной фронтенд (см. известные ошибки в README). Плавающая версия flet>=0.82.2 недавно подтянула 0.86.0 с несовместимым протоколом фреймирования, и дашборд перестал открываться в браузере. stats-react/ — SPA по тому же паттерну, что и web-react (Vite+React+TS, свой Dockerfile+nginx, same-origin прокси /api вместо WebSocket). Функциональность 1:1: 4 summary-карточки, общие фильтры (тест/ организация/группа/год), два таба (прохождения / результаты тестов), 8 графиков, топ-10 таблица, фильтр по оси + сравнение по организациям/ группам. Круговая диаграмма заменена на 100%-stacked bar (dataviz: "part-to-whole rides on the stacked bar chart; donut stays deprioritized") с фолдингом длинного хвоста категорий в "Другое" — у оригинала было 32 категории на 8 цветов, из-за чего сегменты становились неразличимы. Категориальная палитра графиков провалидирована на CVD-безопасность (scripts/validate_palette.js, light+dark) — 8-цветная палитра из исходного designer.py не проходила проверку (hard fail по normal-vision floor). Бренд-оранжевый сохранён в палитре, остальные 7 слотов — из референсного набора skill'а. stats/ и Dockerfile.stats удалены, docker-compose.yml переключён на stats-react. Проверено сборкой всех трёх образов, полным compose up и визуально (headless Chrome, light+dark, обе вкладки, реальные данные с прод-сервера). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
33
stats-react/src/components/TopUsersTable.tsx
Normal file
33
stats-react/src/components/TopUsersTable.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { TopUserRow } from "../api/client";
|
||||
|
||||
export function TopUsersTable({ rows }: { rows: TopUserRow[] }) {
|
||||
if (rows.length === 0) {
|
||||
return <div className="chart-empty">Нет данных</div>;
|
||||
}
|
||||
return (
|
||||
<div style={{ overflowX: "auto" }}>
|
||||
<table className="stats-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Участник</th>
|
||||
<th>Тест</th>
|
||||
<th style={{ textAlign: "right" }}>Балл</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((r, i) => (
|
||||
<tr key={i}>
|
||||
<td>{r.name}</td>
|
||||
<td className="poll-cell" title={r.poll}>
|
||||
{r.poll}
|
||||
</td>
|
||||
<td className="value-cell" style={{ textAlign: "right" }}>
|
||||
{r.value}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user