feat(export): отчёты о занятиях в ZIP-профиле резидента

В архив экспорта студента (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>
This commit is contained in:
dev
2026-10-04 13:37:57 +03:00
co-authored by Cline
parent c994edbed7
commit 9fbd696c84
4 changed files with 156 additions and 19 deletions
+3
View File
@@ -144,6 +144,7 @@ function openExportModal(name) {
document.getElementById('exportForm').reset();
document.getElementById('exportDateFrom').value = '';
document.getElementById('expEntries').checked = true;
document.getElementById('expReports').checked = true;
document.getElementById('expPhotos').checked = true;
document.getElementById('expCaptions').checked = true;
document.getElementById('expFiles').checked = true;
@@ -168,6 +169,7 @@ async function exportStudent(name, opts) {
if (opts.dateFrom) q.set('date_from', opts.dateFrom);
if (opts.dateTo) q.set('date_to', opts.dateTo);
q.set('include_entries', opts.entries ? '1' : '0');
q.set('include_reports', opts.reports === false ? '0' : '1');
q.set('include_photos', opts.photos ? '1' : '0');
q.set('include_captions', opts.captions ? '1' : '0');
q.set('include_files', opts.files ? '1' : '0');
@@ -192,6 +194,7 @@ async function submitExport() {
const captionsEl = document.getElementById('expCaptions');
const opts = {
entries: document.getElementById('expEntries').checked,
reports: document.getElementById('expReports').checked,
photos: document.getElementById('expPhotos').checked,
files: document.getElementById('expFiles').checked,
captions: captionsEl.checked && !captionsEl.disabled,
+6
View File
@@ -73,6 +73,12 @@
Записи занятий (текст)
</label>
</div>
<div class="settings-field full">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
<input type="checkbox" id="expReports" checked>
Отчёты о занятиях (конспекты преподавателя)
</label>
</div>
<div class="settings-field full">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
<input type="checkbox" id="expPhotos" checked>