import { api } from '../api.js'; import { escapeHtml, showAlert, hideAlert } from '../utils.js'; const ROLE_LABELS = { ADMIN: 'Администратор', EDUCATION_OFFICE: 'Учебный отдел', DEPARTMENT: 'Кафедра', SCHEDULE_VIEWER: 'Просмотр расписаний', TEACHER: 'Преподаватель', STUDENT: 'Студент' }; const ROLE_BADGE = { ADMIN: 'badge-admin', EDUCATION_OFFICE: 'badge-admin', DEPARTMENT: 'badge-teacher', SCHEDULE_VIEWER: 'badge-student', TEACHER: 'badge-teacher', STUDENT: 'badge-student' }; export async function initUsers() { const usersTbody = document.getElementById('users-tbody'); const createForm = document.getElementById('create-form'); const teacherRequestsTbody = document.getElementById('teacher-requests-tbody'); const teacherRequestsRefresh = document.getElementById('teacher-requests-refresh'); let departments = []; async function loadUsers() { try { const users = await api.get('/api/users?includeArchived=true'); renderUsers(users); } catch (e) { usersTbody.innerHTML = 'Ошибка загрузки: ' + escapeHtml(e.message) + ''; } } async function loadDepartments() { departments = await api.get('/api/departments'); } async function loadTeacherRequests() { if (!teacherRequestsTbody) return; teacherRequestsTbody.innerHTML = 'Загрузка...'; hideAlert('teacher-requests-alert'); try { const requests = await api.get('/api/teacher-requests?status=PENDING'); renderTeacherRequests(Array.isArray(requests) ? requests : []); } catch (error) { teacherRequestsTbody.innerHTML = `${escapeHtml(error.message || 'Ошибка загрузки заявок')}`; } } function renderTeacherRequests(requests) { if (!requests.length) { teacherRequestsTbody.innerHTML = 'Нет заявок на рассмотрении'; return; } teacherRequestsTbody.innerHTML = requests.map(request => ` ${escapeHtml(request.comment || '-')}
`).join(''); } function renderUsers(users) { if (!users || !users.length) { usersTbody.innerHTML = 'Нет пользователей'; return; } usersTbody.innerHTML = users.map(u => ` ${u.id} ${escapeHtml(u.username)} ${escapeHtml(u.fullName || '-')} ${escapeHtml(u.jobTitle || '-')} ${escapeHtml(u.departmentName || '-')} ${ROLE_LABELS[u.role] || escapeHtml(u.role)} ${u.status === 'ARCHIVED' ? `` : ``} `).join(''); } createForm.addEventListener('submit', async (e) => { e.preventDefault(); hideAlert('create-alert'); const username = document.getElementById('new-username').value.trim(); const password = document.getElementById('new-password').value; const role = document.getElementById('new-role').value; const fullName = document.getElementById('new-fullname').value.trim(); const jobTitle = document.getElementById('new-jobtitle').value.trim(); const departmentId = document.getElementById('new-department').value; if (!username || !password || !fullName || !jobTitle || !departmentId) { showAlert('create-alert', 'Заполните все поля', 'error'); return; } if (password.length < 8) { showAlert('create-alert', 'Пароль должен быть не короче 8 символов', 'error'); return; } try { const data = await api.post('/api/users', { username, password, role, fullName, jobTitle, departmentId: Number(departmentId) }); showAlert('create-alert', `Пользователь "${escapeHtml(data.username)}" создан`, 'success'); createForm.reset(); loadUsers(); } catch (err) { showAlert('create-alert', err.message || 'Ошибка соединения', 'error'); } }); teacherRequestsRefresh?.addEventListener('click', loadTeacherRequests); teacherRequestsTbody?.addEventListener('click', async (event) => { const approveButton = event.target.closest('.teacher-request-approve'); const rejectButton = event.target.closest('.teacher-request-reject'); if (!approveButton && !rejectButton) return; const row = event.target.closest('tr[data-request-id]'); const requestId = row?.dataset.requestId; if (!requestId) return; if (approveButton) { const payload = { departmentId: Number(row.querySelector('.teacher-request-department')?.value), username: row.querySelector('.teacher-request-username')?.value.trim(), fullName: row.querySelector('.teacher-request-fullname')?.value.trim(), jobTitle: row.querySelector('.teacher-request-jobtitle')?.value.trim(), password: row.querySelector('.teacher-request-password')?.value }; if (!payload.departmentId || !payload.username || !payload.fullName || !payload.password) { showAlert('teacher-requests-alert', 'Заполните кафедру, логин, ФИО и пароль', 'error'); return; } if (payload.password.length < 8) { showAlert('teacher-requests-alert', 'Пароль должен быть не короче 8 символов', 'error'); return; } try { await api.post(`/api/teacher-requests/${encodeURIComponent(requestId)}/approve`, payload); showAlert('teacher-requests-alert', 'Преподаватель создан, заявка одобрена', 'success'); await Promise.all([loadTeacherRequests(), loadUsers()]); } catch (error) { showAlert('teacher-requests-alert', error.message || 'Ошибка одобрения заявки', 'error'); } return; } const reviewComment = prompt('Причина отклонения'); if (reviewComment === null) return; try { await api.post(`/api/teacher-requests/${encodeURIComponent(requestId)}/reject`, { reviewComment }); showAlert('teacher-requests-alert', 'Заявка отклонена', 'success'); await loadTeacherRequests(); } catch (error) { showAlert('teacher-requests-alert', error.message || 'Ошибка отклонения заявки', 'error'); } }); usersTbody.addEventListener('click', async (e) => { const deleteBtn = e.target.closest('.btn-archive-user'); if (!deleteBtn) return; if (!confirm('Архивировать пользователя? История расписания и связей сохранится.')) return; try { await api.delete('/api/users/' + deleteBtn.dataset.id); loadUsers(); } catch (err) { alert(err.message || 'Ошибка архивирования'); } }); usersTbody.addEventListener('click', async (e) => { const restoreBtn = e.target.closest('.btn-restore-user'); if (!restoreBtn) return; try { await api.post('/api/users/' + restoreBtn.dataset.id + '/restore', {}); loadUsers(); } catch (err) { alert(err.message || 'Ошибка восстановления'); } }); await loadDepartments(); await Promise.all([loadUsers(), loadTeacherRequests()]); }