diff --git a/public/js/students.js b/public/js/students.js index 336c643..a647429 100644 --- a/public/js/students.js +++ b/public/js/students.js @@ -47,6 +47,7 @@ function renderStudents() {
+
@@ -80,6 +81,81 @@ async function saveStudent(id) { else { const e = await res.json(); alert(e.error); } } +let exportPendingName = null; + +function openExportModal(name) { + exportPendingName = name; + document.getElementById('exportName').textContent = name; + document.getElementById('exportForm').reset(); + document.getElementById('exportDateFrom').value = ''; + document.getElementById('expEntries').checked = true; + document.getElementById('expPhotos').checked = true; + document.getElementById('expCaptions').checked = true; + document.getElementById('expFiles').checked = true; + document.getElementById('expDates').checked = true; + document.getElementById('exportModal').classList.add('open'); +} + +function closeExportModal() { + document.getElementById('exportModal').classList.remove('open'); + exportPendingName = null; +} + +function onExportPhotosToggle() { + const on = document.getElementById('expPhotos').checked; + document.getElementById('expCaptions').disabled = !on; +} + +async function exportStudent(name, opts) { + showToast(`Формируем отчёт: ${name}...`); + try { + const q = new URLSearchParams({ name }); + 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_photos', opts.photos ? '1' : '0'); + q.set('include_captions', opts.captions ? '1' : '0'); + q.set('include_files', opts.files ? '1' : '0'); + q.set('show_dates', opts.dates ? '1' : '0'); + const res = await fetch(`${API}/api/export/student?${q}`, { headers: hdr() }); + if (!res.ok) { + const e = await res.json(); + alert(e.error || 'Не удалось сформировать отчёт'); + return; + } + const blob = await res.blob(); + downloadBlob(blob, `student_${safeWindowsName(name)}_report.zip`); + showToast(`Готово: ${name}`); + } catch (err) { + alert('Ошибка при формировании отчёта'); + } +} + +async function submitExport() { + const name = exportPendingName; + if (!name) return; + const captionsEl = document.getElementById('expCaptions'); + const opts = { + entries: document.getElementById('expEntries').checked, + photos: document.getElementById('expPhotos').checked, + files: document.getElementById('expFiles').checked, + captions: captionsEl.checked && !captionsEl.disabled, + dates: document.getElementById('expDates').checked, + dateFrom: document.getElementById('exportDateFrom').value, + dateTo: document.getElementById('exportDateTo').value, + }; + if (!opts.entries && !opts.photos && !opts.files) { + alert('Выберите хотя бы одну категорию: записи, фото или файлы'); + return; + } + if (opts.dateFrom && opts.dateTo && opts.dateFrom > opts.dateTo) { + alert('Дата «С» позже даты «По»'); + return; + } + closeExportModal(); + await exportStudent(name, opts); +} + async function delStudent(id) { if (!confirm('Удалить ученика из списка? Старые записи останутся.')) return; await fetch(`${API}/api/students/${id}`, { method: 'DELETE', headers: hdr() }); @@ -217,6 +293,14 @@ document.getElementById('attachSearch').addEventListener('input', () => { aSearchTimer = setTimeout(renderAttachList, 300); }); +document.getElementById('exportForm').addEventListener('submit', e => { + e.preventDefault(); + submitExport(); +}); +document.getElementById('exportCancelBtn').addEventListener('click', closeExportModal); +document.getElementById('expPhotos').addEventListener('change', onExportPhotosToggle); +document.getElementById('exportModal').addEventListener('click', e => { if (e.target === e.currentTarget) closeExportModal(); }); + document.getElementById('addStudentBtn').addEventListener('click', addStudent); document.getElementById('batchAddBtn').addEventListener('click', openBatchAdd); document.getElementById('batchAttachBtn').addEventListener('click', openBatchAttach); @@ -232,6 +316,8 @@ document.getElementById('studentList').addEventListener('click', e => { if (sv) { saveStudent(parseInt(sv.dataset.saveStudent, 10)); return; } const cp = e.target.closest('[data-copy-student]'); if (cp) { copyStudentLink(cp.dataset.copyStudent); return; } + const ex = e.target.closest('[data-export-student]'); + if (ex) { openExportModal(ex.dataset.exportStudent.trim()); return; } const dl = e.target.closest('[data-del-student]'); if (dl) { delStudent(parseInt(dl.dataset.delStudent, 10)); } }); diff --git a/public/students.html b/public/students.html index f4d0fb1..85e077f 100644 --- a/public/students.html +++ b/public/students.html @@ -53,6 +53,58 @@ + +