/
MashkoA
/
web-nodejs
Обзор
Документация
Войти
/
MashkoA
/
web-nodejs
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
public/lab11/task2/script.js
580 строк
20 KB
vSUS1w8OErscaPzljeOMKk86GKFCBmeQUlgjKJCmRenysib5Ll
lab11
15 май 2026, 08:21
15 май 2026, 08:21
60e2fdd
Код
Авторство
О чём код?
// script.js - Задание 2: Управление пользователями const API = "/api/lab11"; const TOKEN = "lab11_token_task2"; const USER = "lab11_user_task2"; const qs = (id) => document.getElementById(id); // Переменные состояния let currentUser = null; let editingUserId = null; let usersList = []; let userToDelete = null; // Инициализация document.addEventListener('DOMContentLoaded', () => { // Загружаем данные пользователя из localStorage const userData = localStorage.getItem(USER); const token = localStorage.getItem(TOKEN); if (userData && token) { currentUser = JSON.parse(userData); updateUIForUserRole(); } else { updateUIForUserRole(); } // Настройка событий - с проверкой существования элементов const loginForm = qs('login-form'); if (loginForm) loginForm.onsubmit = handleLogin; const userForm = qs('user-form'); if (userForm) userForm.onsubmit = handleUserSubmit; const refreshBtn = qs('btn-refresh'); if (refreshBtn) refreshBtn.onclick = checkAuthAndLoadUsers; const createNewBtn = qs('btn-create-new'); if (createNewBtn) createNewBtn.onclick = showCreateForm; const cancelBtn = qs('btn-cancel'); if (cancelBtn) cancelBtn.onclick = resetForm; const generatePwdBtn = qs('btn-generate-password'); if (generatePwdBtn) generatePwdBtn.onclick = generatePassword; const logoutBtn = qs('btn-logout'); if (logoutBtn) logoutBtn.onclick = handleLogout; const confirmDeleteBtn = qs('btn-confirm-delete'); if (confirmDeleteBtn) confirmDeleteBtn.onclick = confirmDelete; checkAuthAndLoadUsers(); }); // Функции управления состоянием function setAuth(token, user) { token ? localStorage.setItem(TOKEN, token) : localStorage.removeItem(TOKEN); user ? localStorage.setItem(USER, JSON.stringify(user)) : localStorage.removeItem(USER); currentUser = user; updateUIForUserRole(); checkAuthAndLoadUsers(); } function showMessage(elementId, message, isError = false) { const element = qs(elementId); if (element) { element.textContent = message; element.className = isError ? "error" : "success"; setTimeout(() => { element.textContent = ""; element.className = ""; }, 5000); } } function updateUIForUserRole() { const isAuthenticated = !!currentUser; const isAdmin = currentUser?.role === 'admin'; // Обновляем информацию о пользователе const statusText = currentUser ? `${currentUser.login} (${currentUser.role})` : 'не авторизован'; const currentUserElement = qs('current-user'); if (currentUserElement) { currentUserElement.textContent = statusText; } // Показываем/скрываем кнопки входа/выхода const logoutBtn = qs('btn-logout'); if (logoutBtn) { logoutBtn.style.display = isAuthenticated ? 'block' : 'none'; } // Показываем/скрываем форму управления (только для админов) const adminActions = qs('admin-actions'); if (adminActions) { adminActions.classList.toggle('hidden', !isAdmin); } const createNewBtn = qs('btn-create-new'); if (createNewBtn) { createNewBtn.classList.toggle('hidden', !isAdmin); } if (isAdmin) { resetForm(); } else if (adminActions) { adminActions.classList.add('hidden'); } } // Аутентификация async function handleLogin(e) { e.preventDefault(); const login = qs('login-login')?.value; const password = qs('login-password')?.value; if (!login || !password) { showMessage('table-msg', 'Введите логин и пароль', true); return; } try { const response = await fetch(`${API}/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ login, password }) }); const data = await response.json(); if (response.ok) { setAuth(data.token, data.user); showMessage('table-msg', 'Вход выполнен успешно!'); const loginForm = qs('login-form'); if (loginForm) loginForm.reset(); } else { showMessage('table-msg', data.error || 'Ошибка входа', true); } } catch (error) { showMessage('table-msg', 'Ошибка сети', true); } } async function handleLogout() { const token = localStorage.getItem(TOKEN); if (token) { try { await fetch(`${API}/logout`, { method: "POST", headers: { "Authorization": `Bearer ${token}` } }); } catch (error) { console.log("Logout request failed"); } } setAuth("", null); showMessage('table-msg', 'Выход выполнен успешно'); } // Управление пользователями function checkAuthAndLoadUsers() { const token = localStorage.getItem(TOKEN); const tableBody = qs('users-table-body'); if (!tableBody) return; if (!token) { tableBody.innerHTML = ` <tr> <td colspan="5" class="loading">Для просмотра списка пользователей войдите в систему</td> </tr> `; return; } loadUsers(); } async function loadUsers() { try { const response = await fetch(`${API}/users`); if (!response.ok) { if (response.status === 401) { showMessage('table-msg', 'Требуется авторизация', true); return; } throw new Error(`Ошибка ${response.status}`); } usersList = await response.json(); renderUsersTable(); } catch (error) { console.error('Ошибка загрузки пользователей:', error); showMessage('table-msg', 'Ошибка загрузки пользователей', true); } } function renderUsersTable() { const tbody = qs('users-table-body'); const thead = qs('users-table-head'); if (!tbody || !thead) return; if (!usersList || usersList.length === 0) { tbody.innerHTML = ` <tr> <td colspan="5" class="loading">Пользователи не найдены</td> </tr> `; return; } // Создаем заголовки таблицы let headers = '<tr><th>ID</th><th>Логин</th><th>Роль</th><th>Дата создания</th>'; if (currentUser && currentUser.role === 'admin') { headers += '<th>Действия</th>'; } headers += '</tr>'; thead.innerHTML = headers; // Тело таблицы let html = ''; usersList.forEach(user => { const roleClass = user.role === 'admin' ? 'role-admin' : 'role-user'; const createdAt = new Date(user.createdAt).toLocaleString('ru-RU'); const isCurrentUser = currentUser && currentUser.id === user.id; html += ` <tr id="user-${user.id}"> <td>${user.id}</td> <td>${user.login} ${isCurrentUser ? '(вы)' : ''}</td> <td><span class="role-badge ${roleClass}">${user.role}</span></td> <td>${createdAt}</td> `; // Кнопки действий только для админов if (currentUser && currentUser.role === 'admin') { if (isCurrentUser) { html += `<td><em>Это ваш аккаунт</em></td>`; } else { html += ` <td class="actions-cell"> <div class="actions-buttons"> <button class="btn btn-action btn-edit" data-user-id="${user.id}" data-user-name="${user.login}"> Редактировать </button> <button class="btn btn-action btn-delete" data-user-id="${user.id}" data-user-name="${user.login}"> Удалить </button> </div> </td> `; } } else { html += `<td></td>`; } html += `</tr>`; }); tbody.innerHTML = html; // Назначаем обработчики событий для кнопок setupTableEventListeners(); } // Функция для настройки обработчиков событий таблицы function setupTableEventListeners() { // Обработчик кнопок удаления document.querySelectorAll('.btn-delete').forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); const userId = parseInt(this.dataset.userId); const userName = this.dataset.userName; console.log('Кнопка удаления нажата:', userId, userName); openDeleteModal(userId, userName); }); }); // Обработчик кнопок редактирования document.querySelectorAll('.btn-edit').forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); const userId = parseInt(this.dataset.userId); const userName = this.dataset.userName; console.log('Кнопка редактирования нажата:', userId, userName); editUser(userId, userName); }); }); } async function handleUserSubmit(e) { e.preventDefault(); const login = qs('user-login')?.value.trim(); const password = qs('user-password')?.value; const confirmPassword = qs('confirm-password')?.value; const role = qs('user-role')?.value; // Валидация if (!login || !role) { showMessage('form-msg', 'Логин и роль обязательны', true); return; } if (!editingUserId && (!password || !confirmPassword)) { showMessage('form-msg', 'Пароль обязателен при создании', true); return; } if (password && password !== confirmPassword) { showMessage('form-msg', 'Пароли не совпадают', true); return; } if (password && password.length < 6) { showMessage('form-msg', 'Пароль должен содержать минимум 6 символов', true); return; } const token = localStorage.getItem(TOKEN); if (!token) { showMessage('form-msg', 'Требуется авторизация', true); return; } const url = editingUserId ? `${API}/users/${editingUserId}` : `${API}/users`; const method = editingUserId ? 'PUT' : 'POST'; try { const response = await fetch(url, { method: method, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ login, password: password || undefined, role }) }); const data = await response.json(); if (response.ok) { showMessage('form-msg', data.message); resetForm(); loadUsers(); } else { showMessage('form-msg', data.error || 'Ошибка операции', true); } } catch (error) { console.error('Ошибка операции:', error); showMessage('form-msg', 'Ошибка сети', true); } } function showCreateForm() { resetForm(); const adminActions = qs('admin-actions'); if (adminActions) { adminActions.classList.remove('hidden'); } } function resetForm() { const userForm = qs('user-form'); if (!userForm) return; userForm.reset(); const userIdInput = qs('user-id'); if (userIdInput) userIdInput.value = ''; editingUserId = null; const formTitle = qs('form-title'); const passwordLabel = qs('password-label'); const btnSubmit = qs('btn-submit'); const btnCancel = qs('btn-cancel'); if (formTitle) formTitle.textContent = 'Создание нового пользователя'; if (passwordLabel) passwordLabel.textContent = 'Пароль *'; if (btnSubmit) btnSubmit.textContent = 'Создать пользователя'; if (btnCancel) btnCancel.classList.add('hidden'); showMessage('form-msg', ''); } async function generatePassword() { const token = localStorage.getItem(TOKEN); if (!token) { showMessage('form-msg', 'Требуется авторизация', true); return; } try { const response = await fetch(`${API}/generate-password`, { headers: { "Authorization": `Bearer ${token}` } }); if (response.ok) { const data = await response.json(); const pwdInput = qs('user-password'); const confirmInput = qs('confirm-password'); if (pwdInput) pwdInput.value = data.password; if (confirmInput) confirmInput.value = data.password; return; } // Если эндпоинт не реализован или ошибка доступа, генерируем локально } catch (error) { // Генерируем локально при ошибке } // Локальная генерация пароля const length = 12; const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"; let password = ""; for (let i = 0; i < length; i++) { const randomIndex = Math.floor(Math.random() * charset.length); password += charset[randomIndex]; } const pwdInput = qs('user-password'); const confirmInput = qs('confirm-password'); if (pwdInput) pwdInput.value = password; if (confirmInput) confirmInput.value = password; } async function viewUser(userId) { const token = localStorage.getItem(TOKEN); if (!token) { showMessage('table-msg', 'Требуется авторизация', true); return; } try { const response = await fetch(`${API}/users/${userId}`, { headers: { "Authorization": `Bearer ${token}` } }); if (!response.ok) { throw new Error(`Ошибка ${response.status}`); } const user = await response.json(); alert(`Информация о пользователе:\n\nID: ${user.id}\nЛогин: ${user.login}\nРоль: ${user.role}\nДата создания: ${new Date(user.createdAt).toLocaleString('ru-RU')}`); } catch (error) { console.error('Ошибка загрузки пользователя:', error); showMessage('table-msg', 'Ошибка загрузки данных пользователя', true); } } // Обновленная функция editUser для работы с data-атрибутами function editUser(userId, userName) { const user = usersList.find(u => u.id === userId); if (!user) { console.error('Пользователь не найден для редактирования:', userId); return; } editingUserId = userId; const userIdInput = qs('user-id'); if (userIdInput) userIdInput.value = user.id; const loginInput = qs('user-login'); const roleSelect = qs('user-role'); const pwdInput = qs('user-password'); const confirmInput = qs('confirm-password'); const formTitle = qs('form-title'); const passwordLabel = qs('password-label'); const btnSubmit = qs('btn-submit'); const btnCancel = qs('btn-cancel'); const adminActions = qs('admin-actions'); if (loginInput) loginInput.value = user.login; if (roleSelect) roleSelect.value = user.role; if (pwdInput) pwdInput.value = ''; if (confirmInput) confirmInput.value = ''; if (formTitle) formTitle.textContent = `Редактирование пользователя: ${userName}`; if (passwordLabel) passwordLabel.textContent = 'Новый пароль (оставьте пустым, чтобы не менять)'; if (btnSubmit) btnSubmit.textContent = 'Сохранить изменения'; if (btnCancel) btnCancel.classList.remove('hidden'); if (adminActions) { adminActions.classList.remove('hidden'); adminActions.scrollIntoView({ behavior: 'smooth' }); } } // Обновленная функция openDeleteModal для отладки function openDeleteModal(userId, userName) { console.log('openDeleteModal вызван с параметрами:', userId, userName); userToDelete = userId; const deleteUserName = qs('delete-user-name'); const deleteModal = qs('delete-modal'); if (deleteUserName) { deleteUserName.textContent = userName; console.log('Установлено имя для удаления:', userName); } if (deleteModal) { // Удаляем класс hidden и добавляем show deleteModal.classList.remove('hidden'); deleteModal.classList.add('show'); console.log('Модальное окно показано'); // Проверяем, что окно действительно видно console.log('Состояние модального окна:', { classList: deleteModal.classList.toString(), computedDisplay: window.getComputedStyle(deleteModal).display }); } else { console.error('Элемент delete-modal не найден в DOM'); } } function closeDeleteModal() { userToDelete = null; const deleteModal = qs('delete-modal'); if (deleteModal) { deleteModal.classList.remove('show'); deleteModal.classList.add('hidden'); } } async function confirmDelete() { if (!userToDelete) return; const token = localStorage.getItem(TOKEN); if (!token) { showMessage('table-msg', 'Требуется авторизация', true); closeDeleteModal(); return; } try { const response = await fetch(`${API}/users/${userToDelete}`, { method: 'DELETE', headers: { "Authorization": `Bearer ${token}` } }); const data = await response.json(); if (response.ok) { showMessage('table-msg', data.message); loadUsers(); } else { showMessage('table-msg', data.error || 'Ошибка удаления', true); } } catch (error) { console.error('Ошибка удаления:', error); showMessage('table-msg', 'Ошибка сети', true); } closeDeleteModal(); } // Тестовая функция для проверки модального окна window.testModal = function() { console.log('Тест модального окна'); openDeleteModal(999, 'Тестовый пользователь'); }; // Глобальные функции для вызова из HTML window.editUser = editUser; window.openDeleteModal = openDeleteModal; window.closeDeleteModal = closeDeleteModal; window.testModal = testModal;