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();