Files
minicrm/public/admin-script.js
2026-03-06 11:11:56 +05:00

568 lines
20 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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');
const createUserForm = document.getElementById('create-user-form');
if (loginForm) {
loginForm.addEventListener('submit', login);
}
if (editUserForm) {
editUserForm.addEventListener('submit', updateUser);
}
if (createUserForm) {
createUserForm.addEventListener('submit', createUser);
}
}
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 formatRole(role) {
const roleMap = {
'admin': 'Администратор',
'teacher': 'Учитель'
// при необходимости можно добавить другие соответствия
};
return roleMap[role] || role;
}
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>
${formatRole(user.role)}
${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('');
}
// Функция для открытия модального окна создания пользователя
function openCreateUserModal() {
const modal = document.getElementById('create-user-modal');
if (modal) {
// Сбрасываем форму
const form = document.getElementById('create-user-form');
if (form) {
form.reset();
}
modal.style.display = 'block';
}
}
// Функция для закрытия модального окна создания пользователя
function closeCreateUserModal() {
const modal = document.getElementById('create-user-modal');
if (modal) {
modal.style.display = 'none';
}
}
// Функция для создания нового пользователя
async function createUser(event) {
event.preventDefault();
const login = document.getElementById('create-login').value;
const password = document.getElementById('create-password').value;
const name = document.getElementById('create-name').value;
const email = document.getElementById('create-email').value;
const role = document.getElementById('create-role').value;
const auth_type = document.getElementById('create-auth-type').value;
const groups = document.getElementById('create-groups').value;
const description = document.getElementById('create-description').value;
// Валидация
if (!login || !password || !name || !email) {
alert('Заполните все обязательные поля');
return;
}
if (password.length < 6) {
alert('Пароль должен содержать не менее 6 символов');
return;
}
const userData = {
login,
password,
name,
email,
role,
auth_type,
groups: groups || '[]',
description
};
try {
const response = await fetch('/admin/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
if (response.ok) {
const result = await response.json();
alert(`Пользователь успешно создан! ID: ${result.id}`);
closeCreateUserModal();
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 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.openCreateUserModal = openCreateUserModal;
window.closeCreateUserModal = closeCreateUserModal;
window.createUser = createUser;
window.updateUser = updateUser;
window.deleteUser = deleteUser;