Files
WhatIDo/public/dashboard.html
T
dev 3c127b895e feat(datetime): timezone/time_format в настройках + единый хелпер дат
Часовой пояс и формат времени (24h/12h) перенесены из браузера в настройки
приложения: валидация IANA-зоны, сид в db/init.sql + db/migration.sql, отдача
в GET /api/public-settings, раздел #sec-datetime в настройках с живым превью.

Границы суток в SQL переведены на tzDayStart/tzDayEnd + bindTz ($TZ$) — раньше
$n::date по TIMESTAMPTZ считал дни в UTC (у контейнера TimeZone=UTC) и молча
сдвигал выборку на день; хардкод Europe/Moscow вычищен, now() заменён на
tzWall().

Новый public/js/datetime.js: три семейства хелперов (instant / чистая
DATE-строка без Date() / чистая TIME-строка), подключён на всех страницах
включая публичные share/report/index, initDateTime() встроен в checkAuth().
Прямые toLocale*/getFullYear/toISOString().slice(0,10) в public/ выпилены.

Попутно: bindTz добавляет параметр только при наличии $TZ$ в SQL (иначе запрос
виснет вечно без global error handler) — регрессия закрыта в api.smoketest.js;
починены off-by-one месяца в report.js и группировка по дате в share.js.
2026-10-04 10:49:48 +03:00

81 lines
4.1 KiB
HTML

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Дашборд — Админ-панель</title>
<link rel="stylesheet" href="admin.css">
</head>
<body data-page="dashboard">
<div class="layout">
<div class="sidebar" id="sidebar"></div>
<div class="main">
<div class="page-head">
<h2>Дашборд</h2>
<p class="page-sub">Сводка по журналу и группам</p>
</div>
<div class="stats" id="stats"></div>
<div class="dash-grid">
<div class="dash-col">
<div class="dash-card">
<h3><span class="ic"><i data-lucide="bar-chart-3"></i></span> Динамика записей (14 дней)</h3>
<div class="chart" id="activityChart" title=""></div>
<div class="dash-link-row"><a href="journal.html">Открыть журнал →</a></div>
</div>
<div class="dash-card">
<h3><span class="ic"><i data-lucide="clock"></i></span> Последние записи</h3>
<div class="recent" id="recentList"></div>
<div class="dash-link-row"><a href="journal.html">Все записи →</a></div>
</div>
<div class="dash-card">
<h3><span class="ic"><i data-lucide="notebook-pen"></i></span> Что прошли на занятиях</h3>
<div class="recent" id="lessonList"></div>
<div class="dash-link-row"><a href="lessons.html">Все отчёты →</a></div>
</div>
<div class="dash-card">
<h3><span class="ic"><i data-lucide="camera"></i></span> Фото групп</h3>
<div class="photos-grid-dash" id="dashPhotos"></div>
<div class="dash-link-row"><a href="groups.html">Фото групп →</a></div>
</div>
</div>
<div class="dash-col">
<div class="dash-card">
<h3><span class="ic"><i data-lucide="zap"></i></span> Быстрые действия</h3>
<div class="actions-grid">
<a class="action-btn" href="journal.html"><span class="aic"><i data-lucide="book-open"></i></span>Журнал</a>
<button type="button" class="action-btn" id="lessonReportBtn" style="border:1px solid var(--border);cursor:pointer;font-family:inherit"><span class="aic"><i data-lucide="notebook-pen"></i></span>Что прошли на занятии</button>
<a class="action-btn" href="files.html"><span class="aic"><i data-lucide="folder"></i></span>Файлы</a>
<a class="action-btn" href="photos.html"><span class="aic"><i data-lucide="Image"></i></span>Фото</a>
<a class="action-btn" href="groups.html"><span class="aic"><i data-lucide="users"></i></span>Группы</a>
<a class="action-btn" href="links.html"><span class="aic"><i data-lucide="link"></i></span>Ссылки</a>
<a class="action-btn" href="trash.html"><span class="aic"><i data-lucide="trash-2"></i></span>Корзина</a>
<a class="action-btn" href="worker.html"><span class="aic"><i data-lucide="bot"></i></span>Воркер ИИ</a>
<a class="action-btn" href="settings.html"><span class="aic"><i data-lucide="shield"></i></span>Бэкап</a>
<a class="action-btn" href="bans.html"><span class="aic"><i data-lucide="ban"></i></span>Блокировки</a>
</div>
</div>
<div class="dash-card">
<h3><span class="ic"><i data-lucide="activity"></i></span> Активные сейчас группы</h3>
<div class="active-list" id="activeList"></div>
</div>
<div class="dash-card">
<h3><span class="ic"><i data-lucide="trophy"></i></span> Топ учеников</h3>
<div class="top-list" id="topList"></div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-overlay" id="imgModal">
<img id="imgModalSrc" alt="">
</div>
<div class="toast" id="toast"></div>
<script src="vendor/lucide.min.js"></script>
<script src="js/datetime.js"></script>
<script src="admin.js"></script>
<script src="js/dashboard.js"></script>
</body>
</html>