const API = location.origin; let token = sessionStorage.getItem('adminToken'); function hdr() { return { 'X-Admin-Token': token }; } function hdrJson() { return { 'Content-Type': 'application/json', 'X-Admin-Token': token }; } function esc(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; } // --- Auth check --- async function checkAuth() { if (!token) { location.href = 'login.html'; return false; } try { const res = await fetch(`${API}/api/stats`, { headers: hdr() }); if (!res.ok) { sessionStorage.removeItem('adminToken'); location.href = 'login.html'; return false; } return true; } catch { sessionStorage.removeItem('adminToken'); location.href = 'login.html'; return false; } } function doLogout() { sessionStorage.removeItem('adminToken'); location.href = 'login.html'; } // --- Sidebar --- const NAV = [ { page: 'dashboard', label: 'Дашборд' }, { page: 'journal', label: 'Журнал' }, { page: 'links', label: 'Ссылки' }, { page: 'students', label: 'Ученики' }, { page: 'groups', label: 'Группы' }, { page: 'settings', label: 'Настройки' } ]; function buildSidebar(active) { const el = document.getElementById('sidebar'); if (!el) return; el.innerHTML = `
На главную Выйти
`; } // --- Common UI --- function showToast(msg) { const t = document.getElementById('toast'); t.textContent = msg; t.classList.add('show'); setTimeout(() => t.classList.remove('show'), 3000); } function showImg(src) { const img = document.getElementById('imgModalSrc'); const m = document.getElementById('imgModal'); if (img && m) { img.src = src; m.classList.add('open'); } } async function fillAutocomplete() { const res = await fetch(`${API}/api/students`); const students = await res.json(); const names = students.map(s => s.name); const dlEdit = document.getElementById('studentEditList'); if (dlEdit) { dlEdit.innerHTML = ''; names.forEach(n => { const o = document.createElement('option'); o.value = n; dlEdit.appendChild(o); }); } const dlAdd = document.getElementById('studentAddList'); if (dlAdd) { dlAdd.innerHTML = ''; names.forEach(n => { const o = document.createElement('option'); o.value = n; dlAdd.appendChild(o); }); } } function copyStudentLink(name) { const url = `${location.origin}/?nameInput=${encodeURIComponent(name)}`; const done = () => showToast('Ссылка скопирована: ' + url); if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(url).then(done).catch(() => fallbackCopy(url, done)); } else { fallbackCopy(url, done); } } function fallbackCopy(text, done) { const ta = document.createElement('textarea'); ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); done(); } catch { prompt('Скопируйте вручную:', text); } document.body.removeChild(ta); } function studentUrlContent(name) { const url = `${location.origin}/?nameInput=${encodeURIComponent(name)}`; return `[InternetShortcut]\r\nURL=${url}\r\n`; } function safeWindowsName(name) { return String(name).replace(/[\\/:*?"<>|]/g, '_').replace(/\s+/g, '_'); } function downloadBlob(blob, filename) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } async function exportStudentUrlZip(students, zipName) { if (typeof JSZip === 'undefined') { alert('JSZip не загружен'); return; } const zip = new JSZip(); students.forEach(s => { zip.file(safeWindowsName(s.name) + '.url', studentUrlContent(s.name)); }); const blob = await zip.generateAsync({ type: 'blob' }); downloadBlob(blob, zipName); } function copyText(text) { const done = () => showToast('Скопировано: ' + text); if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(text).then(done).catch(() => fallbackCopy(text, done)); } else { fallbackCopy(text, done); } } function renderPager(el, page, totalPages, onPage) { if (!el) return; if (totalPages <= 1) { el.innerHTML = ''; return; } let html = ``; for (let i = 1; i <= totalPages; i++) { if (totalPages > 9 && i > 2 && i < totalPages - 1 && Math.abs(i - page) > 2) { if (i === 3) html += ``; continue; } html += ``; } html += ``; el.innerHTML = html; }