async function init() { if (!(await checkAuth())) return; if (!isAdmin()) { location.href = 'journal.html'; return; } buildSidebar('users'); document.getElementById('addUserBtn').addEventListener('click', () => openModal(null)); document.getElementById('uCancel').addEventListener('click', closeModal); document.getElementById('uSave').addEventListener('click', saveUser); document.getElementById('uRole').addEventListener('change', () => { document.getElementById('uBranchesField').style.display = document.getElementById('uRole').value === 'admin' ? 'none' : ''; }); await loadUsers(); } let branches = []; let editingId = null; async function loadUsers() { const [uRes, bRes] = await Promise.all([ fetch(`${API}/api/users`, { headers: hdr() }), fetch(`${API}/api/branches`, { headers: hdr() }), ]); if (!uRes.ok) { showToast('Ошибка загрузки пользователей'); return; } branches = await bRes.json(); renderUsers(await uRes.json()); } function renderUsers(users) { const tbody = document.querySelector('#usersTable tbody'); const empty = document.getElementById('usersEmpty'); tbody.innerHTML = ''; empty.style.display = users.length ? 'none' : 'block'; const branchById = {}; branches.forEach(b => { branchById[b.id] = b.name; }); users.forEach(u => { const tr = document.createElement('tr'); const branchNames = (u.branch_ids || []).map(id => branchById[id] || `#${id}`).join(', ') || '—'; const roleCls = u.role === 'admin' ? 'badge-admin' : 'badge-tutor'; const roleTxt = u.role === 'admin' ? 'Администратор' : 'Тутор'; const status = u.is_active ? 'Активен' : 'Заблокирован'; const delBtn = u.id === currentUser.id ? '' : ``; tr.innerHTML = ` ${u.id} ${esc(u.username)} ${esc(u.name || '')} ${roleTxt} ${esc(branchNames)} ${status} ${delBtn} `; tbody.appendChild(tr); }); tbody.querySelectorAll('[data-edit]').forEach(b => { const userId = Number(b.dataset.edit); const user = users.find(u => u.id === userId); b.addEventListener('click', () => openModal(user)); }); tbody.querySelectorAll('[data-del]').forEach(b => b.addEventListener('click', () => delUser(Number(b.dataset.del)))); } function openModal(user) { editingId = user ? user.id : null; document.getElementById('userModalTitle').textContent = user ? `Пользователь: ${user.username}` : 'Новый пользователь'; document.getElementById('uUsername').value = user ? user.username : ''; document.getElementById('uName').value = user ? (user.name || '') : ''; document.getElementById('uRole').value = user ? user.role : 'tutor'; document.getElementById('uPassword').value = ''; document.getElementById('uActive').checked = user ? user.is_active : true; document.getElementById('pwdHint').textContent = user ? '(оставьте пустым, чтобы не менять)' : '(мин. 6 символов)'; document.getElementById('uRole').disabled = !!user && user.id === currentUser.id; const sel = document.getElementById('uBranches'); sel.innerHTML = ''; branches.forEach(b => { const o = document.createElement('option'); o.value = b.id; o.textContent = b.name; if (user && (user.branch_ids || []).includes(b.id)) o.selected = true; sel.appendChild(o); }); document.getElementById('uBranchesField').style.display = document.getElementById('uRole').value === 'admin' ? 'none' : ''; document.getElementById('userModal').classList.add('open'); } function closeModal() { document.getElementById('userModal').classList.remove('open'); } async function saveUser() { const username = document.getElementById('uUsername').value.trim(); const name = document.getElementById('uName').value.trim() || null; const role = document.getElementById('uRole').value; const password = document.getElementById('uPassword').value; const is_active = document.getElementById('uActive').checked; const branchSel = document.getElementById('uBranches'); const branch_ids = role === 'admin' ? [] : [...branchSel.selectedOptions].map(o => Number(o.value)); if (!username) { showToast('Укажите логин'); return; } if (!editingId && password.length < 6) { showToast('Пароль должен быть не короче 6 символов'); return; } const payload = { username, name, role, is_active, branch_ids }; if (password) payload.password = password; const res = await fetch(editingId ? `${API}/api/users/${editingId}` : `${API}/api/users`, { method: editingId ? 'PUT' : 'POST', headers: hdrJson(), body: JSON.stringify(payload), }); const data = await res.json().catch(() => ({})); if (!res.ok) { showToast(data.error || 'Ошибка сохранения'); return; } showToast('Сохранено'); closeModal(); loadUsers(); } async function delUser(id) { if (!confirm('Удалить пользователя?')) return; const res = await fetch(`${API}/api/users/${id}`, { method: 'DELETE', headers: hdr() }); if (!res.ok) { const data = await res.json().catch(() => ({})); showToast(data.error || 'Ошибка удаления'); return; } showToast('Пользователь удалён'); loadUsers(); } init();