Files
magistr/frontend/admin/js/views/users.js
2026-06-02 16:07:30 +03:00

123 lines
4.6 KiB
JavaScript

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');
async function loadUsers() {
try {
const users = await api.get('/api/users?includeArchived=true');
renderUsers(users);
} catch (e) {
usersTbody.innerHTML =
'<tr><td colspan="7" class="loading-row">Ошибка загрузки: ' +
escapeHtml(e.message) + '</td></tr>';
}
}
function renderUsers(users) {
if (!users || !users.length) {
usersTbody.innerHTML = '<tr><td colspan="7" class="loading-row">Нет пользователей</td></tr>';
return;
}
usersTbody.innerHTML = users.map(u => `
<tr>
<td>${u.id}</td>
<td>${escapeHtml(u.username)}</td>
<td>${escapeHtml(u.fullName || '-')}</td>
<td>${escapeHtml(u.jobTitle || '-')}</td>
<td>${escapeHtml(u.departmentName || '-')}</td>
<td><span class="badge ${ROLE_BADGE[u.role] || ''}">${ROLE_LABELS[u.role] || escapeHtml(u.role)}</span></td>
<td>
${u.status === 'ARCHIVED'
? `<button class="btn-restore-user" data-id="${u.id}">Восстановить</button>`
: `<button class="btn btn-sm btn-danger-subtle btn-archive-user" data-id="${u.id}">Архивировать</button>`}
</td>
</tr>
`).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');
}
});
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 loadUsers();
}