В архив экспорта студента (GET /api/export/student, кнопка «Профиль»
на /students.html) добавлена секция «Отчёты о занятиях»: тема, дата,
время, группа и текст конспекта преподавателя. Секция рендерится между
«Занятия» и «О себе», попадает в навигацию и футер, появляется только
если есть хотя бы один отчёт.
Отчёты привязаны к группе (в lesson_reports нет student_id), поэтому
выбираются по группам резидента: текущая группа плюс все группы, где
у него есть записи. Фильтры филиалов (branchWhere) и период из
date_from/date_to соблюдаются, как и в остальной выборке. Ограничение
60 последних отчётов, при усечении в подзаголовке секции есть
соответствующая пометка. Новый флаг include_reports (по умолчанию
включён) + чекбокс в модалке экспорта.
Даты lesson_date/lesson_time форматируются как чистые DATE/TIME
строки, без new Date(), чтобы не сдвинуть день; учёт настройки
time_format сделан через appHour12.
Заодно в отчёте и в сообщениях эндпоинта «ученик» заменён на
«резидент».
Co-Authored-By: Cline <cline@cline.bot>
Часовой пояс и формат времени (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.
Круглый аватар слева от поля имени: миниатюра главного фото через thumbSrc, иначе инициалы. Клик по фото открывает imgModal с полным размером, клик по пустому — карточку профиля для загрузки. Аватар синхронизируется после загрузки, смены и удаления фото.
- renderStudentReport: детский учебный дизайн (крупные скругления, sticky-навигация, секции-карточки)
- журнал занятий в две колонки (одна на мобильных)
- единая галерея фото и видео: листание кнопками/стрелками, счётчик
- воспроизведение видео прямо в лайтбоксе
- кнопка закрытия ✕, закрытие по фону и Esc
- модалка экспорта отчёта ученика (период и выбор содержимого)