Часовой пояс и формат времени (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.
81 lines
4.1 KiB
HTML
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> |