451 lines
15 KiB
JavaScript
451 lines
15 KiB
JavaScript
// admin-script.js (обновленный)
|
||
let currentUser = null;
|
||
let users = [];
|
||
let filteredUsers = [];
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
checkAuth();
|
||
setupEventListeners();
|
||
});
|
||
|
||
async function checkAuth() {
|
||
try {
|
||
const response = await fetch('/api/user');
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
currentUser = data.user;
|
||
|
||
if (currentUser.role !== 'admin') {
|
||
window.location.href = '/';
|
||
return;
|
||
}
|
||
|
||
showAdminInterface();
|
||
} else {
|
||
showLoginInterface();
|
||
}
|
||
} catch (error) {
|
||
showLoginInterface();
|
||
}
|
||
}
|
||
|
||
function showLoginInterface() {
|
||
document.getElementById('login-modal').style.display = 'block';
|
||
document.querySelector('.admin-container').style.display = 'none';
|
||
}
|
||
|
||
function showAdminInterface() {
|
||
document.getElementById('login-modal').style.display = 'none';
|
||
document.querySelector('.admin-container').style.display = 'block';
|
||
|
||
let userInfo = `Администратор: ${currentUser.name}`;
|
||
if (currentUser.auth_type === 'ldap') {
|
||
userInfo += ` (LDAP)`;
|
||
}
|
||
|
||
document.getElementById('current-user').textContent = userInfo;
|
||
|
||
loadUsers();
|
||
// Если дашборд активен, рендерим его
|
||
if (document.getElementById('admin-dashboard').classList.contains('active')) {
|
||
if (typeof renderDashboard === 'function') {
|
||
renderDashboard();
|
||
}
|
||
}
|
||
// Если статистика активна, рендерим ее
|
||
if (document.getElementById('admin-stats-section').classList.contains('active')) {
|
||
if (typeof renderStatsSection === 'function') {
|
||
renderStatsSection();
|
||
}
|
||
}
|
||
}
|
||
|
||
function setupEventListeners() {
|
||
const loginForm = document.getElementById('login-form');
|
||
const editUserForm = document.getElementById('edit-user-form');
|
||
|
||
if (loginForm) {
|
||
loginForm.addEventListener('submit', login);
|
||
}
|
||
|
||
if (editUserForm) {
|
||
editUserForm.addEventListener('submit', updateUser);
|
||
}
|
||
}
|
||
|
||
async function login(event) {
|
||
event.preventDefault();
|
||
|
||
const login = document.getElementById('login').value;
|
||
const password = document.getElementById('password').value;
|
||
|
||
try {
|
||
const response = await fetch('/api/login', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ login, password })
|
||
});
|
||
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
currentUser = data.user;
|
||
|
||
if (currentUser.role !== 'admin') {
|
||
window.location.href = '/';
|
||
return;
|
||
}
|
||
|
||
showAdminInterface();
|
||
} else {
|
||
const error = await response.json();
|
||
alert(error.error || 'Ошибка входа');
|
||
}
|
||
} catch (error) {
|
||
console.error('Ошибка:', error);
|
||
alert('Ошибка подключения к серверу');
|
||
}
|
||
}
|
||
|
||
async function logout() {
|
||
try {
|
||
await fetch('/api/logout', { method: 'POST' });
|
||
currentUser = null;
|
||
showLoginInterface();
|
||
} catch (error) {
|
||
console.error('Ошибка выхода:', error);
|
||
}
|
||
}
|
||
|
||
function showAdminSection(sectionName) {
|
||
console.log('showAdminSection called with:', sectionName);
|
||
|
||
// Убираем активный класс у всех вкладок
|
||
document.querySelectorAll('.admin-tab').forEach(tab => {
|
||
tab.classList.remove('active');
|
||
});
|
||
|
||
// Убираем активный класс у всех секций
|
||
document.querySelectorAll('.admin-section').forEach(section => {
|
||
section.classList.remove('active');
|
||
});
|
||
|
||
// Находим и активируем соответствующую вкладку
|
||
const tabs = document.querySelectorAll('.admin-tab');
|
||
let tabFound = false;
|
||
|
||
tabs.forEach(tab => {
|
||
const onclick = tab.getAttribute('onclick');
|
||
if (onclick && onclick.includes(`showAdminSection('${sectionName}')`)) {
|
||
tab.classList.add('active');
|
||
tabFound = true;
|
||
}
|
||
});
|
||
|
||
// Если не нашли по onclick, ищем по тексту
|
||
if (!tabFound) {
|
||
tabs.forEach(tab => {
|
||
const tabText = tab.textContent.toLowerCase();
|
||
if (tabText.includes(sectionName.toLowerCase())) {
|
||
tab.classList.add('active');
|
||
}
|
||
});
|
||
}
|
||
|
||
// Активируем соответствующую секцию
|
||
const sectionId = `admin-${sectionName}-section`;
|
||
let section = document.getElementById(sectionId);
|
||
|
||
// Если не нашли по такому ID, пробуем другие варианты
|
||
if (!section) {
|
||
if (sectionName === 'users') {
|
||
section = document.getElementById('admin-users-section');
|
||
} else if (sectionName === 'dashboard') {
|
||
section = document.getElementById('admin-dashboard');
|
||
} else if (sectionName === 'stats') {
|
||
section = document.getElementById('admin-stats-section');
|
||
} else {
|
||
// Пробуем найти по частичному совпадению
|
||
const sections = document.querySelectorAll('.admin-section');
|
||
sections.forEach(s => {
|
||
if (s.id.includes(sectionName)) {
|
||
section = s;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
if (section) {
|
||
section.classList.add('active');
|
||
console.log('Activated section:', section.id);
|
||
} else {
|
||
console.error('Section not found for:', sectionName);
|
||
}
|
||
|
||
// Загружаем данные для активной секции
|
||
setTimeout(() => {
|
||
if (sectionName === 'users') {
|
||
console.log('Loading users...');
|
||
loadUsers();
|
||
} else if (sectionName === 'dashboard') {
|
||
console.log('Loading dashboard...');
|
||
if (typeof renderDashboard === 'function') {
|
||
renderDashboard();
|
||
}
|
||
} else if (sectionName === 'stats') {
|
||
console.log('Loading stats...');
|
||
if (typeof renderStatsSection === 'function') {
|
||
renderStatsSection();
|
||
}
|
||
}
|
||
}, 50);
|
||
}
|
||
|
||
async function loadUsers() {
|
||
try {
|
||
const tbody = document.getElementById('users-table-body');
|
||
if (tbody) {
|
||
tbody.innerHTML = '<tr><td colspan="9" class="loading">Загрузка пользователей...</td></tr>';
|
||
}
|
||
|
||
const response = await fetch('/admin/users');
|
||
if (!response.ok) {
|
||
throw new Error('Ошибка загрузки пользователей');
|
||
}
|
||
users = await response.json();
|
||
filteredUsers = [...users];
|
||
renderUsersTable();
|
||
} catch (error) {
|
||
console.error('Ошибка загрузки пользователей:', error);
|
||
showError('users-table-body', 'Ошибка загрузки пользователей');
|
||
}
|
||
}
|
||
|
||
function searchUsers() {
|
||
const searchInput = document.getElementById('user-search');
|
||
if (!searchInput) return;
|
||
|
||
const search = searchInput.value.toLowerCase();
|
||
filteredUsers = users.filter(user =>
|
||
(user.login && user.login.toLowerCase().includes(search)) ||
|
||
(user.name && user.name.toLowerCase().includes(search)) ||
|
||
(user.email && user.email.toLowerCase().includes(search)) ||
|
||
(user.role && user.role.toLowerCase().includes(search)) ||
|
||
(user.auth_type && user.auth_type.toLowerCase().includes(search))
|
||
);
|
||
renderUsersTable();
|
||
}
|
||
|
||
function renderUsersTable() {
|
||
const tbody = document.getElementById('users-table-body');
|
||
if (!tbody) return;
|
||
|
||
if (!filteredUsers || filteredUsers.length === 0) {
|
||
tbody.innerHTML = '<tr><td colspan="9" class="loading">Пользователи не найдены</td></tr>';
|
||
return;
|
||
}
|
||
|
||
tbody.innerHTML = filteredUsers.map(user => `
|
||
<tr>
|
||
<td>${user.id}</td>
|
||
<td>
|
||
${user.login || 'Нет логина'}
|
||
${user.auth_type === 'ldap' ? '<span class="ldap-badge">LDAP</span>' : ''}
|
||
</td>
|
||
<td>${user.name || 'Не указано'}</td>
|
||
<td>${user.email || 'Нет email'}</td>
|
||
<td>
|
||
${user.role === 'admin' ? 'Администратор' : 'Учитель'}
|
||
${user.role === 'admin' ? '<span class="admin-badge">ADMIN</span>' : ''}
|
||
</td>
|
||
<td>${user.auth_type === 'ldap' ? 'LDAP' : 'Локальная'}</td>
|
||
<td>${formatDate(user.created_at)}</td>
|
||
<td>${user.last_login ? formatDateTime(user.last_login) : 'Никогда'}</td>
|
||
<td class="user-actions">
|
||
<button class="edit-btn" onclick="openEditUserModal(${user.id})" title="Редактировать">✏️</button>
|
||
<button class="delete-btn" onclick="deleteUser(${user.id})" title="Удалить" ${user.id === currentUser?.id ? 'disabled' : ''}>🗑️</button>
|
||
</td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
|
||
async function openEditUserModal(userId) {
|
||
try {
|
||
const response = await fetch(`/admin/users/${userId}`);
|
||
if (!response.ok) {
|
||
throw new Error('Ошибка загрузки пользователя');
|
||
}
|
||
|
||
const user = await response.json();
|
||
|
||
document.getElementById('edit-user-id').value = user.id;
|
||
document.getElementById('edit-login').value = user.login;
|
||
document.getElementById('edit-name').value = user.name;
|
||
document.getElementById('edit-email').value = user.email;
|
||
document.getElementById('edit-role').value = user.role;
|
||
document.getElementById('edit-auth-type').value = user.auth_type;
|
||
document.getElementById('edit-groups').value = user.groups || '[]';
|
||
document.getElementById('edit-description').value = user.description || '';
|
||
|
||
const modal = document.getElementById('edit-user-modal');
|
||
if (modal) {
|
||
modal.style.display = 'block';
|
||
}
|
||
} catch (error) {
|
||
console.error('Ошибка:', error);
|
||
alert('Ошибка загрузки пользователя');
|
||
}
|
||
}
|
||
|
||
function closeEditUserModal() {
|
||
const modal = document.getElementById('edit-user-modal');
|
||
if (modal) {
|
||
modal.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
async function updateUser(event) {
|
||
event.preventDefault();
|
||
|
||
const userId = document.getElementById('edit-user-id').value;
|
||
const login = document.getElementById('edit-login').value;
|
||
const name = document.getElementById('edit-name').value;
|
||
const email = document.getElementById('edit-email').value;
|
||
const role = document.getElementById('edit-role').value;
|
||
const auth_type = document.getElementById('edit-auth-type').value;
|
||
const groups = document.getElementById('edit-groups').value;
|
||
const description = document.getElementById('edit-description').value;
|
||
|
||
if (!login || !name || !email) {
|
||
alert('Заполните обязательные поля');
|
||
return;
|
||
}
|
||
|
||
const userData = {
|
||
login,
|
||
name,
|
||
email,
|
||
role,
|
||
auth_type,
|
||
groups: groups || '[]',
|
||
description
|
||
};
|
||
|
||
try {
|
||
const response = await fetch(`/admin/users/${userId}`, {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify(userData)
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert('Пользователь успешно обновлен!');
|
||
closeEditUserModal();
|
||
loadUsers();
|
||
|
||
// Обновляем статистику если она видна
|
||
if (document.getElementById('admin-dashboard')?.classList.contains('active')) {
|
||
if (typeof loadDashboardStats === 'function') {
|
||
loadDashboardStats();
|
||
}
|
||
}
|
||
if (document.getElementById('admin-stats-section')?.classList.contains('active')) {
|
||
if (typeof loadUsersStats === 'function') {
|
||
loadUsersStats();
|
||
}
|
||
if (typeof loadOverallStats === 'function') {
|
||
loadOverallStats();
|
||
}
|
||
}
|
||
} else {
|
||
const error = await response.json();
|
||
alert(error.error || 'Ошибка обновления пользователя');
|
||
}
|
||
} catch (error) {
|
||
console.error('Ошибка:', error);
|
||
alert('Ошибка обновления пользователя');
|
||
}
|
||
}
|
||
|
||
async function deleteUser(userId) {
|
||
if (userId === currentUser?.id) {
|
||
alert('Нельзя удалить самого себя');
|
||
return;
|
||
}
|
||
|
||
if (!confirm('Вы уверены, что хотите удалить этого пользователя?')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`/admin/users/${userId}`, {
|
||
method: 'DELETE'
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert('Пользователь успешно удален!');
|
||
loadUsers();
|
||
|
||
// Обновляем статистику если она видна
|
||
if (document.getElementById('admin-dashboard')?.classList.contains('active')) {
|
||
if (typeof loadDashboardStats === 'function') {
|
||
loadDashboardStats();
|
||
}
|
||
}
|
||
if (document.getElementById('admin-stats-section')?.classList.contains('active')) {
|
||
if (typeof loadUsersStats === 'function') {
|
||
loadUsersStats();
|
||
}
|
||
if (typeof loadOverallStats === 'function') {
|
||
loadOverallStats();
|
||
}
|
||
}
|
||
} else {
|
||
const error = await response.json();
|
||
alert(error.error || 'Ошибка удаления пользователя');
|
||
}
|
||
} catch (error) {
|
||
console.error('Ошибка:', error);
|
||
alert('Ошибка удаления пользователя');
|
||
}
|
||
}
|
||
|
||
function formatDateTime(dateTimeString) {
|
||
if (!dateTimeString) return '';
|
||
try {
|
||
const date = new Date(dateTimeString);
|
||
return date.toLocaleString('ru-RU');
|
||
} catch (e) {
|
||
return dateTimeString;
|
||
}
|
||
}
|
||
|
||
function formatDate(dateString) {
|
||
if (!dateString) return '';
|
||
try {
|
||
const date = new Date(dateString);
|
||
return date.toLocaleDateString('ru-RU');
|
||
} catch (e) {
|
||
return dateString;
|
||
}
|
||
}
|
||
|
||
function showError(elementId, message) {
|
||
const element = document.getElementById(elementId);
|
||
if (element) {
|
||
element.innerHTML = `<tr><td colspan="9" class="error">${message}</td></tr>`;
|
||
}
|
||
}
|
||
|
||
// Делаем функции глобально доступными
|
||
window.logout = logout;
|
||
window.showAdminSection = showAdminSection;
|
||
window.searchUsers = searchUsers;
|
||
window.loadUsers = loadUsers;
|
||
window.openEditUserModal = openEditUserModal;
|
||
window.closeEditUserModal = closeEditUserModal;
|
||
window.updateUser = updateUser;
|
||
window.deleteUser = deleteUser; |