/
Centermant
/
web-nodejs
Обзор
Документация
Войти
/
Centermant
/
web-nodejs
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
public/lab11/task2/index.html
574 строки
25 KB
Centermant
feat(lab11)
16 дек 2025, 00:57
16 дек 2025, 00:57
01b83c7
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>LR11 - Задание 2: Управление пользователями</title> <link rel="stylesheet" href="/css/styles_lab.css"> <style> .login-section { background: rgba(0, 0, 0, 0.3) !important; padding: 20px !important; border-radius: 15px !important; margin-bottom: 20px !important; } .login-form-group { margin-bottom: 15px !important; } .login-label { display: block !important; margin-bottom: 5px !important; font-weight: bold !important; color: #a0a0ff !important; } .login-input { width: 100% !important; padding: 10px !important; border: 1px solid rgba(255, 255, 255, 0.2) !important; border-radius: 10px !important; background: rgba(0, 0, 0, 0.3) !important; color: white !important; font-family: 'Exo 2', sans-serif !important; font-size: 14px !important; box-sizing: border-box !important; } #editForm { display: none; margin-top: 15px; padding: 15px; background: rgba(0, 0, 0, 0.2) !important; border-radius: 10px !important; } .notification { padding: 10px !important; margin: 10px 0 !important; border-radius: 8px !important; display: none !important; } .success { background-color: rgba(29, 209, 161, 0.2) !important; color: #1dd1a1 !important; } .error { background-color: rgba(255, 107, 107, 0.2) !important; color: #ff6b6b !important; } .table-section { display: block !important; opacity: 1 !important; visibility: visible !important; } #usersTable { display: table !important; width: 100% !important; table-layout: fixed !important; } #usersTable tbody { display: table-row-group !important; } </style> </head> <body> <div class="wrapper"> <div class="header"> <h1>Лабораторная работа 11 - Задание 2</h1> </div> <div class="container"> <div id="notification" class="notification"></div> <div class="login-section"> <h2>Авторизация</h2> <div class="login-form-group"> <label class="login-label" for="loginEmail">Email:</label> <input type="email" id="loginEmail" class="login-input" placeholder="Введите email"> </div> <div class="login-form-group"> <label class="login-label" for="loginPassword">Пароль:</label> <input type="password" id="loginPassword" class="login-input" placeholder="Введите пароль"> </div> <button class="btn-primary" onclick="login()">Войти</button> <button class="btn-danger" onclick="logout()">Выйти</button> </div> <div class="form-section"> <h2>Список пользователей</h2> <button class="btn-primary" onclick="loadUsers()">Обновить список</button> <div class="table-section"> <table id="usersTable"> <thead> <tr><th>ID</th><th>Имя</th><th>Email</th><th>Роль</th><th>Дата создания</th><th>Действия</th></tr> </thead> <tbody> <!-- Строки будут добавляться здесь динамически --> </tbody> </table> </div> </div> <div class="form-section"> <h2>Создать пользователя</h2> <div class="form-group"> <label for="createName">Имя:</label> <input type="text" id="createName" placeholder="Введите имя"> </div> <div class="form-group"> <label for="createEmail">Email:</label> <input type="email" id="createEmail" placeholder="Введите email"> </div> <div class="form-group"> <label for="createRole">Роль:</label> <select id="createRole"> <option value="user">user</option> <option value="guest">guest</option> <option value="admin">admin</option> </select> </div> <button class="btn-primary" onclick="createUser()">Создать</button> </div> <div id="editForm"> <h2>Редактировать пользователя</h2> <input type="hidden" id="editUserId"> <div class="form-group"> <label for="editName">Имя:</label> <input type="text" id="editName" placeholder="Введите имя"> </div> <div class="form-group"> <label for="editEmail">Email:</label> <input type="email" id="editEmail" placeholder="Введите email"> </div> <div class="form-group"> <label for="editRole">Роль:</label> <select id="editRole"> <option value="user">user</option> <option value="guest">guest</option> <option value="admin">admin</option> </select> </div> <button class="btn-primary" onclick="updateUser()">Сохранить</button> <button class="btn-danger" onclick="cancelEdit()">Отмена</button> </div> <div class="form-section"> <h2>Генерация пароля</h2> <div class="form-group"> <label for="generatedPassword">Сгенерированный пароль:</label> <input type="text" id="generatedPassword" readonly> </div> <button class="btn-primary" onclick="generatePassword()">Сгенерировать</button> </div> <div class="form-section"> <h2>Права доступа</h2> <ul> <li><strong>Guest:</strong> Только просмотр списка пользователей (GET /users).</li> <li><strong>User:</strong> Просмотр всех данных (GET /users, GET /users/:id) без возможности создания/редактирования.</li> <li><strong>Admin:</strong> Полный доступ (POST, PUT, DELETE).</li> </ul> </div> </div> </div> <script> const BASE_URL = '/api/lab11'; let currentUser = null; function showNotification(message, isSuccess) { const el = document.getElementById('notification'); el.textContent = message; el.className = `notification ${isSuccess ? 'success' : 'error'}`; el.style.display = 'block'; setTimeout(() => { el.style.display = 'none'; }, 3000); } function getToken() { return localStorage.getItem('token'); } function setToken(token) { if (token) { localStorage.setItem('token', token); } else { localStorage.removeItem('token'); } } async function getCurrentUser() { const token = getToken(); if (!token) { currentUser = null; updateUI(); return; } try { const response = await fetch(`${BASE_URL}/profile`, { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { const user = await response.json(); currentUser = user; updateUI(); } else { const error = await response.json(); console.log('Ошибка получения профиля:', error.error || 'Неизвестная ошибка'); currentUser = null; setToken(null); updateUI(); } } catch (e) { console.log('Ошибка запроса профиля:', e.message); currentUser = null; setToken(null); updateUI(); } } function updateUI() { const token = getToken(); const isAdmin = currentUser && currentUser.role === 'admin'; const isAuth = !!currentUser; const createNameInput = document.getElementById('createName'); const createEmailInput = document.getElementById('createEmail'); const createRoleSelect = document.getElementById('createRole'); const editNameInput = document.getElementById('editName'); const editEmailInput = document.getElementById('editEmail'); const editRoleSelect = document.getElementById('editRole'); if (createNameInput) createNameInput.disabled = !isAdmin; if (createEmailInput) createEmailInput.disabled = !isAdmin; if (createRoleSelect) createRoleSelect.disabled = !isAdmin; if (editNameInput) editNameInput.disabled = !isAdmin; if (editEmailInput) editEmailInput.disabled = !isAdmin; if (editRoleSelect) editRoleSelect.disabled = !isAdmin; const createButton = document.querySelector('button[onclick="createUser"]'); const updateButton = document.querySelector('button[onclick="updateUser"]'); const cancelButton = document.querySelector('button[onclick="cancelEdit"]'); const generatePasswordButton = document.querySelector('button[onclick="generatePassword"]'); if (createButton) createButton.disabled = !isAdmin; if (updateButton) updateButton.disabled = !isAdmin; if (cancelButton) cancelButton.disabled = !isAdmin; if (generatePasswordButton) generatePasswordButton.disabled = !isAuth; const logoutButton = document.querySelector('button[onclick="logout"]'); if (logoutButton) { logoutButton.textContent = isAuth ? 'Выйти' : 'Выйти'; } const loginButton = document.querySelector('button[onclick="login"]'); if (loginButton) { loginButton.disabled = isAuth; loginButton.textContent = isAuth ? 'Уже вошли' : 'Войти'; } const loginEmailInput = document.getElementById('loginEmail'); const loginPasswordInput = document.getElementById('loginPassword'); if (loginEmailInput && loginPasswordInput) { if (isAuth) { loginEmailInput.value = currentUser.email; loginPasswordInput.value = ''; } else { loginEmailInput.value = ''; loginPasswordInput.value = ''; } } } async function loadUsers() { try { const token = getToken(); const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; console.log('Отправляю запрос на загрузку пользователей'); const response = await fetch(`${BASE_URL}/users`, { headers }); console.log('Статус ответа:', response.status); if (response.ok) { const users = await response.json(); console.log('Полученные данные о пользователях:', users); const tbody = document.querySelector('#usersTable tbody'); if (!tbody) { console.error('Не найден элемент tbody в таблице'); return; } tbody.innerHTML = ''; if (users.length === 0) { const row = tbody.insertRow(); const cell = row.insertCell(0); cell.colSpan = 6; cell.textContent = 'Нет данных'; cell.style.textAlign = 'center'; return; } users.forEach(u => { try { const row = tbody.insertRow(); // Создаем ячейки по порядку const idCell = row.insertCell(0); const nameCell = row.insertCell(1); const emailCell = row.insertCell(2); const roleCell = row.insertCell(3); const createdAtCell = row.insertCell(4); const actionsCell = row.insertCell(5); // Заполняем ячейки данными idCell.textContent = u.id; nameCell.textContent = u.name || 'Без имени'; emailCell.textContent = u.email || 'Без email'; roleCell.textContent = u.role || 'user'; createdAtCell.textContent = u.created_at ? new Date(u.created_at).toLocaleString() : 'Нет данных'; // Кнопки действий доступны только админу if (currentUser && currentUser.role === 'admin') { actionsCell.innerHTML = ` <button class="select-btn" data-action="edit" data-id="${u.id}">E</button> <button class="delete-btn" data-action="delete" data-id="${u.id}">X</button> `; // Добавляем обработчики событий для кнопок actionsCell.querySelector(`button[data-action="edit"][data-id="${u.id}"]`) .addEventListener('click', () => editUser(u.id)); actionsCell.querySelector(`button[data-action="delete"][data-id="${u.id}"]`) .addEventListener('click', () => deleteUser(u.id)); } else { actionsCell.textContent = 'Нет прав'; } } catch (error) { console.error('Ошибка при создании строки для пользователя:', error, u); } }); console.log('Таблица успешно заполнена'); } else { const errorText = await response.text(); console.log('Ошибка сервера:', errorText); showNotification('Ошибка загрузки пользователей', false); if (response.status === 401) { setToken(null); currentUser = null; updateUI(); } } } catch (e) { console.error('Ошибка в loadUsers:', e); showNotification('Ошибка: ' + e.message, false); } } async function login() { const email = document.getElementById('loginEmail').value; const password = document.getElementById('loginPassword').value; if (!email || !password) { showNotification('Заполните email и пароль', false); return; } try { const response = await fetch(`${BASE_URL}/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }); if (response.ok) { const data = await response.json(); setToken(data.token); showNotification('Успешный вход', true); await getCurrentUser(); loadUsers(); } else { const error = await response.json(); showNotification(error.error || 'Ошибка входа', false); } } catch (e) { showNotification(e.message, false); } } async function logout() { setToken(null); currentUser = null; updateUI(); showNotification('Вы вышли из системы', true); document.getElementById('loginEmail').value = ''; document.getElementById('loginPassword').value = ''; loadUsers(); } async function createUser() { const name = document.getElementById('createName').value; const email = document.getElementById('createEmail').value; const role = document.getElementById('createRole').value; if (!name || !email) { showNotification('Заполните имя и email', false); return; } // Генерируем пароль с помощью сервера try { const token = getToken(); const response = await fetch(`${BASE_URL}/generate-password`, { headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) { const error = await response.json(); showNotification(error.error || 'Ошибка генерации пароля', false); return; } const data = await response.json(); const generatedPassword = data.password; // Регистрируем пользователя с сгенерированным паролем const registerResponse = await fetch(`${BASE_URL}/register`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ name: name, email: email, password: generatedPassword, role: role // Передаем роль }) }); if (registerResponse.ok) { showNotification(`Пользователь ${name} создан. Пароль: ${generatedPassword}`, true); loadUsers(); } else { const error = await registerResponse.json(); showNotification(error.error || 'Ошибка создания пользователя', false); } } catch (e) { showNotification(e.message, false); } } async function editUser(id) { const token = getToken(); if (!token) { showNotification('Требуется авторизация', false); return; } try { const response = await fetch(`${BASE_URL}/users/${id}`, { headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { const user = await response.json(); document.getElementById('editUserId').value = user.id; document.getElementById('editName').value = user.name; document.getElementById('editEmail').value = user.email; document.getElementById('editRole').value = user.role; document.getElementById('editForm').style.display = 'block'; } else { const error = await response.json(); showNotification(error.error || 'Ошибка загрузки пользователя', false); } } catch (e) { showNotification(e.message, false); } } async function updateUser() { const id = document.getElementById('editUserId').value; const name = document.getElementById('editName').value; const email = document.getElementById('editEmail').value; const role = document.getElementById('editRole').value; if (!name || !email) { showNotification('Заполните имя и email', false); return; } const token = getToken(); if (!token) { showNotification('Требуется авторизация', false); return; } try { const response = await fetch(`${BASE_URL}/users/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ name, email, role }) }); if (response.ok) { const user = await response.json(); showNotification('Пользователь обновлен', true); document.getElementById('editForm').style.display = 'none'; loadUsers(); } else { const error = await response.json(); showNotification(error.error || 'Ошибка обновления пользователя', false); } } catch (e) { showNotification(e.message, false); } } async function deleteUser(id) { if (!confirm('Удалить пользователя?')) return; const token = getToken(); if (!token) { showNotification('Требуется авторизация', false); return; } try { const response = await fetch(`${BASE_URL}/users/${id}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); if (response.ok) { showNotification('Пользователь удален', true); loadUsers(); } else { const error = await response.json(); showNotification(error.error || 'Ошибка удаления пользователя', false); } } catch (e) { showNotification(e.message, false); } } function cancelEdit() { document.getElementById('editForm').style.display = 'none'; } function generatePassword() { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()'; let password = ''; for (let i = 0; i < 12; i++) { password += chars.charAt(Math.floor(Math.random() * chars.length)); } document.getElementById('generatedPassword').value = password; } // Загружаем информацию о текущем пользователе при загрузке страницы document.addEventListener('DOMContentLoaded', async () => { console.log('Страница загружена, начинаю инициализацию'); await getCurrentUser(); updateUI(); loadUsers(); }); </script> </body> </html>