Часовой пояс и формат времени (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.
48 lines
2.0 KiB
HTML
48 lines
2.0 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">
|
||
<style>
|
||
.file-icon{width:80px;height:80px;border-radius:8px;background:var(--bg);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;font-size:1.6rem;flex-shrink:0;color:var(--muted)}
|
||
.file-name{font-weight:600;font-size:.95rem}
|
||
.file-name a{color:var(--text);text-decoration:none}
|
||
.file-name a:hover{color:var(--accent)}
|
||
</style>
|
||
</head>
|
||
<body data-page="files">
|
||
<div class="layout">
|
||
<div class="sidebar" id="sidebar"></div>
|
||
<div class="main">
|
||
<h2>Файлы</h2>
|
||
<div class="filters">
|
||
<div><label>Поиск</label><input type="text" id="searchInput" class="search-input" placeholder="Имя файла"></div>
|
||
<div><label>Студент</label><input type="text" id="studentFilter" list="studentFilterList" placeholder="Все / введите имя..."><datalist id="studentFilterList"></datalist></div>
|
||
<div><label>Группа</label><select id="groupFilter"><option value="">Все группы</option></select></div>
|
||
<div><label>С</label><input type="date" id="dateFrom"></div>
|
||
<div><label>По</label><input type="date" id="dateTo"></div>
|
||
<div><label>Тип</label>
|
||
<div class="view-toggle" id="tabToggle">
|
||
<button data-mode="attached" type="button">Прикреплённые</button>
|
||
<button data-mode="detached" type="button" id="detachedTab">Откреплённые</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="grid" id="grid"><div class="empty">Загрузка...</div></div>
|
||
<div class="pager" id="pager"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal-overlay" id="imgModal">
|
||
<img id="imgModalSrc">
|
||
</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/files.js"></script>
|
||
</body>
|
||
</html> |