(() => { 'use strict'; const token = localStorage.getItem('token'); const role = localStorage.getItem('role'); if (!token || role !== 'ADMIN') { window.location.href = '/'; return; } // ---- DOM refs ---- const pageTitle = document.getElementById('page-title'); const btnLogout = document.getElementById('btn-logout'); const menuToggle = document.getElementById('menu-toggle'); const sidebar = document.querySelector('.sidebar'); const sidebarOverlay = document.getElementById('sidebar-overlay'); // Users const usersTbody = document.getElementById('users-tbody'); const createForm = document.getElementById('create-form'); const createAlert = document.getElementById('create-alert'); // Groups const groupsTbody = document.getElementById('groups-tbody'); const createGroupForm = document.getElementById('create-group-form'); const createGroupAlert = document.getElementById('create-group-alert'); const newGroupEfSelect = document.getElementById('new-group-ef'); const filterEfSelect = document.getElementById('filter-ef'); // Education Forms const efTbody = document.getElementById('ef-tbody'); const createEfForm = document.getElementById('create-ef-form'); const createEfAlert = document.getElementById('create-ef-alert'); const navItems = document.querySelectorAll('.nav-item[data-tab]'); const tabContents = document.querySelectorAll('.tab-content'); // ---- State ---- let allGroups = []; let allEducationForms = []; // ---- Tab Switching ---- const TAB_TITLES = { users: 'Управление пользователями', groups: 'Управление группами', 'edu-forms': 'Формы обучения', }; navItems.forEach(item => { item.addEventListener('click', (e) => { e.preventDefault(); switchTab(item.dataset.tab); }); }); function switchTab(tab) { navItems.forEach(n => n.classList.remove('active')); document.querySelector(`.nav-item[data-tab="${tab}"]`)?.classList.add('active'); tabContents.forEach(tc => tc.style.display = 'none'); const target = document.getElementById('tab-' + tab); if (target) target.style.display = ''; pageTitle.textContent = TAB_TITLES[tab] || ''; if (tab === 'users') loadUsers(); if (tab === 'groups') { loadEducationForms().then(() => loadGroups()); } if (tab === 'edu-forms') loadEducationForms(); sidebar.classList.remove('open'); sidebarOverlay.classList.remove('open'); } // ---- Mobile Menu ---- menuToggle.addEventListener('click', () => { sidebar.classList.toggle('open'); sidebarOverlay.classList.toggle('open'); }); sidebarOverlay.addEventListener('click', () => { sidebar.classList.remove('open'); sidebarOverlay.classList.remove('open'); }); // ---- Helpers ---- const ROLE_LABELS = { ADMIN: 'Администратор', TEACHER: 'Преподаватель', STUDENT: 'Студент' }; const ROLE_BADGE = { ADMIN: 'badge-admin', TEACHER: 'badge-teacher', STUDENT: 'badge-student' }; function escapeHtml(str) { const div = document.createElement('div'); div.textContent = str; return div.innerHTML; } function showAlert(el, msg, type) { el.className = 'form-alert ' + type; el.textContent = msg; } function hideAlert(el) { el.className = 'form-alert'; el.textContent = ''; } // ============================================================ // USERS // ============================================================ async function loadUsers() { try { const res = await fetch('/api/users', { headers: { 'Authorization': 'Bearer ' + token }, }); const users = await res.json(); renderUsers(users); } catch (e) { usersTbody.innerHTML = 'Ошибка загрузки'; } } function renderUsers(users) { if (!users.length) { usersTbody.innerHTML = 'Нет пользователей'; return; } usersTbody.innerHTML = users.map(u => ` ${u.id} ${escapeHtml(u.username)} ${ROLE_LABELS[u.role] || u.role} `).join(''); } createForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert(createAlert); const username = document.getElementById('new-username').value.trim(); const password = document.getElementById('new-password').value; const role = document.getElementById('new-role').value; if (!username || !password) { showAlert(createAlert, 'Заполните все поля', 'error'); return; } try { const res = await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify({ username, password, role }), }); const data = await res.json(); if (res.ok) { showAlert(createAlert, `Пользователь "${data.username}" создан`, 'success'); createForm.reset(); loadUsers(); } else { showAlert(createAlert, data.message || 'Ошибка создания', 'error'); } } catch (e) { showAlert(createAlert, 'Ошибка соединения', 'error'); } }); usersTbody.addEventListener('click', async (e) => { const btn = e.target.closest('.btn-delete'); if (!btn) return; if (!confirm('Удалить пользователя?')) return; try { const res = await fetch('/api/users/' + btn.dataset.id, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token }, }); if (res.ok) loadUsers(); else alert('Ошибка удаления'); } catch (e) { alert('Ошибка соединения'); } }); // ============================================================ // EDUCATION FORMS // ============================================================ async function loadEducationForms() { try { const res = await fetch('/api/education-forms', { headers: { 'Authorization': 'Bearer ' + token }, }); allEducationForms = await res.json(); renderEfTable(allEducationForms); populateEfSelects(allEducationForms); } catch (e) { efTbody.innerHTML = 'Ошибка загрузки'; } } function renderEfTable(forms) { if (!forms.length) { efTbody.innerHTML = 'Нет форм обучения'; return; } efTbody.innerHTML = forms.map(ef => ` ${ef.id} ${escapeHtml(ef.name)} `).join(''); } function populateEfSelects(forms) { // Group creation select const currentVal = newGroupEfSelect.value; newGroupEfSelect.innerHTML = forms.map(ef => `` ).join(''); if (currentVal && forms.find(f => f.id == currentVal)) { newGroupEfSelect.value = currentVal; } // Filter select const currentFilter = filterEfSelect.value; filterEfSelect.innerHTML = '' + forms.map(ef => `` ).join(''); if (currentFilter) filterEfSelect.value = currentFilter; } createEfForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert(createEfAlert); const name = document.getElementById('new-ef-name').value.trim(); if (!name) { showAlert(createEfAlert, 'Введите название', 'error'); return; } try { const res = await fetch('/api/education-forms', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify({ name }), }); const data = await res.json(); if (res.ok) { showAlert(createEfAlert, `Форма "${data.name}" создана`, 'success'); createEfForm.reset(); loadEducationForms(); } else { showAlert(createEfAlert, data.message || 'Ошибка создания', 'error'); } } catch (e) { showAlert(createEfAlert, 'Ошибка соединения', 'error'); } }); efTbody.addEventListener('click', async (e) => { const btn = e.target.closest('.btn-delete'); if (!btn) return; if (!confirm('Удалить форму обучения?')) return; try { const res = await fetch('/api/education-forms/' + btn.dataset.id, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token }, }); if (res.ok) { loadEducationForms(); } else { const data = await res.json(); alert(data.message || 'Ошибка удаления'); } } catch (e) { alert('Ошибка соединения'); } }); // ============================================================ // GROUPS // ============================================================ async function loadGroups() { try { const res = await fetch('/api/groups', { headers: { 'Authorization': 'Bearer ' + token }, }); allGroups = await res.json(); applyGroupFilter(); } catch (e) { groupsTbody.innerHTML = 'Ошибка загрузки'; } } function applyGroupFilter() { const filterId = filterEfSelect.value; const filtered = filterId ? allGroups.filter(g => g.educationFormId == filterId) : allGroups; renderGroups(filtered); } filterEfSelect.addEventListener('change', applyGroupFilter); function renderGroups(groups) { if (!groups.length) { groupsTbody.innerHTML = 'Нет групп'; return; } groupsTbody.innerHTML = groups.map(g => ` ${g.id} ${escapeHtml(g.name)} ${escapeHtml(g.educationFormName)} `).join(''); } createGroupForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert(createGroupAlert); const name = document.getElementById('new-group-name').value.trim(); const educationFormId = newGroupEfSelect.value; if (!name) { showAlert(createGroupAlert, 'Введите название группы', 'error'); return; } if (!educationFormId) { showAlert(createGroupAlert, 'Выберите форму обучения', 'error'); return; } try { const res = await fetch('/api/groups', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify({ name, educationFormId: Number(educationFormId) }), }); const data = await res.json(); if (res.ok) { showAlert(createGroupAlert, `Группа "${data.name}" создана`, 'success'); createGroupForm.reset(); loadGroups(); } else { showAlert(createGroupAlert, data.message || 'Ошибка создания', 'error'); } } catch (e) { showAlert(createGroupAlert, 'Ошибка соединения', 'error'); } }); groupsTbody.addEventListener('click', async (e) => { const btn = e.target.closest('.btn-delete'); if (!btn) return; if (!confirm('Удалить группу?')) return; try { const res = await fetch('/api/groups/' + btn.dataset.id, { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token }, }); if (res.ok) loadGroups(); else alert('Ошибка удаления'); } catch (e) { alert('Ошибка соединения'); } }); // ============================================================ // LOGOUT & INIT // ============================================================ btnLogout.addEventListener('click', () => { localStorage.removeItem('token'); localStorage.removeItem('role'); window.location.href = '/'; }); loadUsers(); })();