Статистика
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// admin-script.js (обновленный)
|
||||
let currentUser = null;
|
||||
let users = [];
|
||||
let filteredUsers = [];
|
||||
@@ -45,12 +46,31 @@ function showAdminInterface() {
|
||||
document.getElementById('current-user').textContent = userInfo;
|
||||
|
||||
loadUsers();
|
||||
loadDashboardStats();
|
||||
// Если дашборд активен, рендерим его
|
||||
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() {
|
||||
document.getElementById('login-form').addEventListener('submit', login);
|
||||
document.getElementById('edit-user-form').addEventListener('submit', updateUser);
|
||||
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) {
|
||||
@@ -99,26 +119,68 @@ async function logout() {
|
||||
}
|
||||
|
||||
function showAdminSection(sectionName) {
|
||||
// Убираем активный класс у всех вкладок
|
||||
document.querySelectorAll('.admin-tab').forEach(tab => {
|
||||
tab.classList.remove('active');
|
||||
});
|
||||
|
||||
// Убираем активный класс у всех секций
|
||||
document.querySelectorAll('.admin-section').forEach(section => {
|
||||
section.classList.remove('active');
|
||||
});
|
||||
|
||||
document.querySelector(`.admin-tab[onclick="showAdminSection('${sectionName}')"]`).classList.add('active');
|
||||
document.getElementById(`admin-${sectionName}`).classList.add('active');
|
||||
// Находим и активируем соответствующую вкладку
|
||||
const tab = document.querySelector(`.admin-tab[onclick*="showAdminSection('${sectionName}')"]`);
|
||||
if (tab) {
|
||||
tab.classList.add('active');
|
||||
} else {
|
||||
// Альтернативный поиск если выше не сработал
|
||||
const tabs = document.querySelectorAll('.admin-tab');
|
||||
tabs.forEach(t => {
|
||||
if (t.textContent.toLowerCase().includes(sectionName)) {
|
||||
t.classList.add('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Активируем соответствующую секцию
|
||||
const section = document.getElementById(`admin-${sectionName}`);
|
||||
if (section) {
|
||||
section.classList.add('active');
|
||||
} else {
|
||||
// Если секция не найдена по ID, ищем по другому шаблону
|
||||
const sections = document.querySelectorAll('.admin-section');
|
||||
sections.forEach(s => {
|
||||
if (s.id.includes(sectionName)) {
|
||||
s.classList.add('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Загружаем данные для активной секции
|
||||
if (sectionName === 'users') {
|
||||
loadUsers();
|
||||
} else if (sectionName === 'dashboard') {
|
||||
loadDashboardStats();
|
||||
if (typeof renderDashboard === 'function') {
|
||||
renderDashboard();
|
||||
}
|
||||
} else if (sectionName === 'stats') {
|
||||
if (typeof renderStatsSection === 'function') {
|
||||
renderStatsSection();
|
||||
} else if (typeof checkAndRenderStats === 'function') {
|
||||
// Альтернативный вызов если функция переименована
|
||||
checkAndRenderStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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('Ошибка загрузки пользователей');
|
||||
@@ -132,69 +194,24 @@ async function loadUsers() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDashboardStats() {
|
||||
try {
|
||||
const response = await fetch('/admin/stats');
|
||||
if (!response.ok) {
|
||||
throw new Error('Ошибка загрузки статистики');
|
||||
}
|
||||
|
||||
const stats = await response.json();
|
||||
updateStatsUI(stats);
|
||||
} catch (error) {
|
||||
console.error('Ошибка загрузки статистики:', error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatsUI(stats) {
|
||||
// Задачи
|
||||
document.getElementById('total-tasks').textContent = stats.totalTasks;
|
||||
document.getElementById('active-tasks').textContent = stats.activeTasks;
|
||||
document.getElementById('closed-tasks').textContent = stats.closedTasks;
|
||||
document.getElementById('deleted-tasks').textContent = stats.deletedTasks;
|
||||
|
||||
// Процент активных задач
|
||||
if (stats.totalTasks > 0) {
|
||||
const activePercentage = Math.round((stats.activeTasks / stats.totalTasks) * 100);
|
||||
document.getElementById('active-tasks-bar').style.width = `${activePercentage}%`;
|
||||
}
|
||||
|
||||
// Назначения
|
||||
document.getElementById('total-assignments').textContent = stats.totalAssignments;
|
||||
document.getElementById('assigned-count').textContent = stats.assignedCount;
|
||||
document.getElementById('in-progress-count').textContent = stats.inProgressCount;
|
||||
document.getElementById('completed-count').textContent = stats.completedCount;
|
||||
document.getElementById('overdue-count').textContent = stats.overdueCount;
|
||||
document.getElementById('rework-count').textContent = stats.reworkCount;
|
||||
|
||||
// Пользователи
|
||||
document.getElementById('total-users').textContent = stats.totalUsers;
|
||||
document.getElementById('admin-users').textContent = stats.adminUsers;
|
||||
document.getElementById('teacher-users').textContent = stats.teacherUsers;
|
||||
document.getElementById('ldap-users').textContent = stats.ldapUsers;
|
||||
document.getElementById('local-users').textContent = stats.localUsers;
|
||||
|
||||
// Файлы
|
||||
document.getElementById('total-files').textContent = stats.totalFiles;
|
||||
const fileSizeMB = (stats.totalFilesSize / 1024 / 1024).toFixed(2);
|
||||
document.getElementById('total-files-size').textContent = `${fileSizeMB} MB`;
|
||||
|
||||
}
|
||||
|
||||
function searchUsers() {
|
||||
const search = document.getElementById('user-search').value.toLowerCase();
|
||||
const searchInput = document.getElementById('user-search');
|
||||
if (!searchInput) return;
|
||||
|
||||
const search = searchInput.value.toLowerCase();
|
||||
filteredUsers = users.filter(user =>
|
||||
user.login.toLowerCase().includes(search) ||
|
||||
user.name.toLowerCase().includes(search) ||
|
||||
user.email.toLowerCase().includes(search) ||
|
||||
user.role.toLowerCase().includes(search) ||
|
||||
user.auth_type.toLowerCase().includes(search)
|
||||
(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>';
|
||||
@@ -205,11 +222,11 @@ function renderUsersTable() {
|
||||
<tr>
|
||||
<td>${user.id}</td>
|
||||
<td>
|
||||
${user.login}
|
||||
${user.login || 'Нет логина'}
|
||||
${user.auth_type === 'ldap' ? '<span class="ldap-badge">LDAP</span>' : ''}
|
||||
</td>
|
||||
<td>${user.name}</td>
|
||||
<td>${user.email}</td>
|
||||
<td>${user.name || 'Не указано'}</td>
|
||||
<td>${user.email || 'Нет email'}</td>
|
||||
<td>
|
||||
${user.role === 'admin' ? 'Администратор' : 'Учитель'}
|
||||
${user.role === 'admin' ? '<span class="admin-badge">ADMIN</span>' : ''}
|
||||
@@ -219,7 +236,7 @@ function renderUsersTable() {
|
||||
<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>
|
||||
<button class="delete-btn" onclick="deleteUser(${user.id})" title="Удалить" ${user.id === currentUser?.id ? 'disabled' : ''}>🗑️</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
@@ -243,7 +260,10 @@ async function openEditUserModal(userId) {
|
||||
document.getElementById('edit-groups').value = user.groups || '[]';
|
||||
document.getElementById('edit-description').value = user.description || '';
|
||||
|
||||
document.getElementById('edit-user-modal').style.display = 'block';
|
||||
const modal = document.getElementById('edit-user-modal');
|
||||
if (modal) {
|
||||
modal.style.display = 'block';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка:', error);
|
||||
alert('Ошибка загрузки пользователя');
|
||||
@@ -251,7 +271,10 @@ async function openEditUserModal(userId) {
|
||||
}
|
||||
|
||||
function closeEditUserModal() {
|
||||
document.getElementById('edit-user-modal').style.display = 'none';
|
||||
const modal = document.getElementById('edit-user-modal');
|
||||
if (modal) {
|
||||
modal.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
async function updateUser(event) {
|
||||
@@ -294,7 +317,21 @@ async function updateUser(event) {
|
||||
alert('Пользователь успешно обновлен!');
|
||||
closeEditUserModal();
|
||||
loadUsers();
|
||||
loadDashboardStats();
|
||||
|
||||
// Обновляем статистику если она видна
|
||||
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 || 'Ошибка обновления пользователя');
|
||||
@@ -306,7 +343,7 @@ async function updateUser(event) {
|
||||
}
|
||||
|
||||
async function deleteUser(userId) {
|
||||
if (userId === currentUser.id) {
|
||||
if (userId === currentUser?.id) {
|
||||
alert('Нельзя удалить самого себя');
|
||||
return;
|
||||
}
|
||||
@@ -323,7 +360,21 @@ async function deleteUser(userId) {
|
||||
if (response.ok) {
|
||||
alert('Пользователь успешно удален!');
|
||||
loadUsers();
|
||||
loadDashboardStats();
|
||||
|
||||
// Обновляем статистику если она видна
|
||||
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 || 'Ошибка удаления пользователя');
|
||||
@@ -336,14 +387,22 @@ async function deleteUser(userId) {
|
||||
|
||||
function formatDateTime(dateTimeString) {
|
||||
if (!dateTimeString) return '';
|
||||
const date = new Date(dateTimeString);
|
||||
return date.toLocaleString('ru-RU');
|
||||
try {
|
||||
const date = new Date(dateTimeString);
|
||||
return date.toLocaleString('ru-RU');
|
||||
} catch (e) {
|
||||
return dateTimeString;
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(dateString) {
|
||||
if (!dateString) return '';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('ru-RU');
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('ru-RU');
|
||||
} catch (e) {
|
||||
return dateString;
|
||||
}
|
||||
}
|
||||
|
||||
function showError(elementId, message) {
|
||||
@@ -353,9 +412,12 @@ function showError(elementId, message) {
|
||||
}
|
||||
}
|
||||
|
||||
// Автоматическое обновление статистики каждые 30 секунд
|
||||
setInterval(() => {
|
||||
if (document.getElementById('admin-dashboard').classList.contains('active')) {
|
||||
loadDashboardStats();
|
||||
}
|
||||
}, 30000);
|
||||
// Делаем функции глобально доступными
|
||||
window.logout = logout;
|
||||
window.showAdminSection = showAdminSection;
|
||||
window.searchUsers = searchUsers;
|
||||
window.loadUsers = loadUsers;
|
||||
window.openEditUserModal = openEditUserModal;
|
||||
window.closeEditUserModal = closeEditUserModal;
|
||||
window.updateUser = updateUser;
|
||||
window.deleteUser = deleteUser;
|
||||
Reference in New Issue
Block a user