From 04db1718aa477bc2e5e36cbbc0b4685bd68a0e06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=9A=D0=B0=D0=BB=D1=83=D0=B3=D0=B8=D0=BD=20=D0=9E=D0=BB?=
=?UTF-8?q?=D0=B5=D0=B3=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4?=
=?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B8=D1=87?=
<134477kalugin66@users.no-reply.gitverse.ru>
Date: Fri, 19 Dec 2025 06:42:04 +0000
Subject: [PATCH] upload files
---
public/admin-script.js | 720 ++++++++++++++++----------------
public/admin.html | 922 ++++++++++++++++++++---------------------
public/script.js | 62 ++-
public/style.css | 88 ++++
4 files changed, 967 insertions(+), 825 deletions(-)
diff --git a/public/admin-script.js b/public/admin-script.js
index d4caf4b..cd389b2 100644
--- a/public/admin-script.js
+++ b/public/admin-script.js
@@ -1,361 +1,361 @@
-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();
- loadDashboardStats();
-}
-
-function setupEventListeners() {
- document.getElementById('login-form').addEventListener('submit', login);
- document.getElementById('edit-user-form').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) {
- 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');
-
- if (sectionName === 'users') {
- loadUsers();
- } else if (sectionName === 'dashboard') {
- loadDashboardStats();
- }
-}
-
-async function loadUsers() {
- try {
- 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', 'Ошибка загрузки пользователей');
- }
-}
-
-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();
- 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)
- );
- renderUsersTable();
-}
-
-function renderUsersTable() {
- const tbody = document.getElementById('users-table-body');
-
- if (!filteredUsers || filteredUsers.length === 0) {
- tbody.innerHTML = '
Пользователи не найдены ';
- return;
- }
-
- tbody.innerHTML = filteredUsers.map(user => `
-
- ${user.id}
-
- ${user.login}
- ${user.auth_type === 'ldap' ? 'LDAP ' : ''}
-
- ${user.name}
- ${user.email}
-
- ${user.role === 'admin' ? 'Администратор' : 'Учитель'}
- ${user.role === 'admin' ? 'ADMIN ' : ''}
-
- ${user.auth_type === 'ldap' ? 'LDAP' : 'Локальная'}
- ${formatDate(user.created_at)}
- ${user.last_login ? formatDateTime(user.last_login) : 'Никогда'}
-
- ✏️
- 🗑️
-
-
- `).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 || '';
-
- document.getElementById('edit-user-modal').style.display = 'block';
- } catch (error) {
- console.error('Ошибка:', error);
- alert('Ошибка загрузки пользователя');
- }
-}
-
-function closeEditUserModal() {
- document.getElementById('edit-user-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();
- loadDashboardStats();
- } 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();
- loadDashboardStats();
- } else {
- const error = await response.json();
- alert(error.error || 'Ошибка удаления пользователя');
- }
- } catch (error) {
- console.error('Ошибка:', error);
- alert('Ошибка удаления пользователя');
- }
-}
-
-function formatDateTime(dateTimeString) {
- if (!dateTimeString) return '';
- const date = new Date(dateTimeString);
- return date.toLocaleString('ru-RU');
-}
-
-function formatDate(dateString) {
- if (!dateString) return '';
- const date = new Date(dateString);
- return date.toLocaleDateString('ru-RU');
-}
-
-function showError(elementId, message) {
- const element = document.getElementById(elementId);
- if (element) {
- element.innerHTML = `${message} `;
- }
-}
-
-// Автоматическое обновление статистики каждые 30 секунд
-setInterval(() => {
- if (document.getElementById('admin-dashboard').classList.contains('active')) {
- loadDashboardStats();
- }
+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();
+ loadDashboardStats();
+}
+
+function setupEventListeners() {
+ document.getElementById('login-form').addEventListener('submit', login);
+ document.getElementById('edit-user-form').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) {
+ 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');
+
+ if (sectionName === 'users') {
+ loadUsers();
+ } else if (sectionName === 'dashboard') {
+ loadDashboardStats();
+ }
+}
+
+async function loadUsers() {
+ try {
+ 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', 'Ошибка загрузки пользователей');
+ }
+}
+
+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();
+ 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)
+ );
+ renderUsersTable();
+}
+
+function renderUsersTable() {
+ const tbody = document.getElementById('users-table-body');
+
+ if (!filteredUsers || filteredUsers.length === 0) {
+ tbody.innerHTML = 'Пользователи не найдены ';
+ return;
+ }
+
+ tbody.innerHTML = filteredUsers.map(user => `
+
+ ${user.id}
+
+ ${user.login}
+ ${user.auth_type === 'ldap' ? 'LDAP ' : ''}
+
+ ${user.name}
+ ${user.email}
+
+ ${user.role === 'admin' ? 'Администратор' : 'Учитель'}
+ ${user.role === 'admin' ? 'ADMIN ' : ''}
+
+ ${user.auth_type === 'ldap' ? 'LDAP' : 'Локальная'}
+ ${formatDate(user.created_at)}
+ ${user.last_login ? formatDateTime(user.last_login) : 'Никогда'}
+
+ ✏️
+ 🗑️
+
+
+ `).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 || '';
+
+ document.getElementById('edit-user-modal').style.display = 'block';
+ } catch (error) {
+ console.error('Ошибка:', error);
+ alert('Ошибка загрузки пользователя');
+ }
+}
+
+function closeEditUserModal() {
+ document.getElementById('edit-user-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();
+ loadDashboardStats();
+ } 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();
+ loadDashboardStats();
+ } else {
+ const error = await response.json();
+ alert(error.error || 'Ошибка удаления пользователя');
+ }
+ } catch (error) {
+ console.error('Ошибка:', error);
+ alert('Ошибка удаления пользователя');
+ }
+}
+
+function formatDateTime(dateTimeString) {
+ if (!dateTimeString) return '';
+ const date = new Date(dateTimeString);
+ return date.toLocaleString('ru-RU');
+}
+
+function formatDate(dateString) {
+ if (!dateString) return '';
+ const date = new Date(dateString);
+ return date.toLocaleDateString('ru-RU');
+}
+
+function showError(elementId, message) {
+ const element = document.getElementById(elementId);
+ if (element) {
+ element.innerHTML = `${message} `;
+ }
+}
+
+// Автоматическое обновление статистики каждые 30 секунд
+setInterval(() => {
+ if (document.getElementById('admin-dashboard').classList.contains('active')) {
+ loadDashboardStats();
+ }
}, 30000);
\ No newline at end of file
diff --git a/public/admin.html b/public/admin.html
index e467589..357a137 100644
--- a/public/admin.html
+++ b/public/admin.html
@@ -1,462 +1,462 @@
-
-
-
-
-
- School CRM - Административная панель
-
-
-
-
-
-
-
Вход в School CRM
-
-
-
Тестовые пользователи:
-
- admin / admin123 (Администратор)
- teacher / teacher123
-
-
-
-
-
-
-
-
-
- Дашборд
- Пользователи
- test
-
-
-
-
Статистика системы
-
-
-
-
Задачи
-
0
-
Всего задач в системе
-
-
-
- Активные:
- 0
-
-
- Закрытые:
- 0
-
-
- Удаленные:
- 0
-
-
-
-
-
-
Статусы назначений
-
0
-
Всего назначений
-
-
- Назначено:
- 0
-
-
- В работе:
- 0
-
-
- Выполнено:
- 0
-
-
- Просрочено:
- 0
-
-
- На доработке:
- 0
-
-
-
-
-
-
Пользователи
-
0
-
Зарегистрировано пользователей
-
-
- Администраторы:
- 0
-
-
- Учителя:
- 0
-
-
- LDAP:
- 0
-
-
- Локальные:
- 0
-
-
-
-
-
-
Файлы
-
0
-
Всего загружено файлов
-
0 MB
-
-
-
-
-
-
Управление пользователями
-
-
-
- Сбросить
-
-
-
-
-
- ID
- Логин
- Имя
- Email
- Роль
- Тип
- Дата создания
- Последний вход
- Действия
-
-
-
-
- Загрузка пользователей...
-
-
-
-
-
-
-
-
-
×
-
Редактировать пользователя
-
-
-
-
-
-
+
+
+
+
+
+ School CRM - Административная панель
+
+
+
+
+
+
+
Вход в School CRM
+
+
+ Логин:
+
+
+
+ Пароль:
+
+
+ Войти
+
+
+
Тестовые пользователи:
+
+ admin / admin123 (Администратор)
+ teacher / teacher123
+
+
+
+
+
+
+
+
+
+ Дашборд
+ Пользователи
+ test
+
+
+
+
Статистика системы
+
+
+
+
Задачи
+
0
+
Всего задач в системе
+
+
+
+ Активные:
+ 0
+
+
+ Закрытые:
+ 0
+
+
+ Удаленные:
+ 0
+
+
+
+
+
+
Статусы назначений
+
0
+
Всего назначений
+
+
+ Назначено:
+ 0
+
+
+ В работе:
+ 0
+
+
+ Выполнено:
+ 0
+
+
+ Просрочено:
+ 0
+
+
+ На доработке:
+ 0
+
+
+
+
+
+
Пользователи
+
0
+
Зарегистрировано пользователей
+
+
+ Администраторы:
+ 0
+
+
+ Учителя:
+ 0
+
+
+ LDAP:
+ 0
+
+
+ Локальные:
+ 0
+
+
+
+
+
+
Файлы
+
0
+
Всего загружено файлов
+
0 MB
+
+
+
+
+
+
Управление пользователями
+
+
+
+ Сбросить
+
+
+
+
+
+ ID
+ Логин
+ Имя
+ Email
+ Роль
+ Тип
+ Дата создания
+ Последний вход
+ Действия
+
+
+
+
+ Загрузка пользователей...
+
+
+
+
+
+
+
+
+
×
+
Редактировать пользователя
+
+
+
+
+
+
+
+
+
+
+ Описание
+
+
+
+ Сохранить изменения
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/script.js b/public/script.js
index e6893df..9d0470c 100644
--- a/public/script.js
+++ b/public/script.js
@@ -427,10 +427,10 @@ function renderTasks() {
Исполнители:
- ${task.assignments && task.assignments.length > 0 ?
- task.assignments.map(assignment => renderAssignment(assignment, task.id, canEdit)).join('') :
- '
Не назначены
'
- }
+${task.assignments && task.assignments.length > 0 ?
+ renderAssignmentList(task.assignments, task.id, canEdit) :
+ '
Не назначены
'
+}