/
Cooolprogrammers
/
web-nodejs-labs
Обзор
Документация
Войти
/
Cooolprogrammers
/
web-nodejs-labs
Код
Запросы
0
Задачи
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
public/lab11/task2/script.js
311 строк
10 KB
darkvoid6@mail.ru
ЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫ
18 дек 2025, 07:59
18 дек 2025, 07:59
f2c4f06
Код
Авторство
О чём код?
const API_BASE = '/api/lab11'; // Глобальное состояние let currentUser = null; // { id, login, role } let usersList = []; document.addEventListener('DOMContentLoaded', () => { checkAuth(); loadUsers(); }); // ========================================== // 1. АУТЕНТИФИКАЦИЯ И UI // ========================================== function checkAuth() { const token = localStorage.getItem('token'); const userJson = localStorage.getItem('user'); const userInfoEl = document.getElementById('userInfo'); const authBtn = document.getElementById('authBtn'); const subtitle = document.getElementById('listSubtitle'); const guestWarning = document.getElementById('guestWarning'); const addUserBtn = document.getElementById('addUserBtn'); const actionsHeader = document.getElementById('actionsHeader'); if (token && userJson) { // --- АВТОРИЗОВАН --- currentUser = JSON.parse(userJson); const roleLabel = currentUser.role === 'admin' ? 'Администратор' : 'Пользователь'; userInfoEl.innerHTML = ` <span class="status-dot online"></span> <div> <div style="font-weight:600; line-height:1">${currentUser.login}</div> <div style="font-size:0.8em; opacity:0.8">${roleLabel}</div> </div> `; authBtn.textContent = 'Выйти'; authBtn.classList.replace('btn-primary', 'btn-outline'); authBtn.onclick = logout; subtitle.textContent = currentUser.role === 'admin' ? 'Полный доступ (Редактирование)' : 'Полный список (Только чтение)'; guestWarning.classList.add('hidden'); // Элементы админа if (currentUser.role === 'admin') { addUserBtn.classList.remove('hidden'); actionsHeader.classList.remove('hidden'); } else { addUserBtn.classList.add('hidden'); actionsHeader.classList.add('hidden'); } } else { // --- ГОСТЬ --- currentUser = null; userInfoEl.innerHTML = ` <span class="status-dot offline"></span> Гость (Демо-режим) `; authBtn.textContent = 'Войти'; authBtn.classList.replace('btn-outline', 'btn-primary'); authBtn.onclick = toggleAuthModal; subtitle.textContent = 'Публичный список (данные скрыты)'; guestWarning.classList.remove('hidden'); addUserBtn.classList.add('hidden'); actionsHeader.classList.add('hidden'); } } async function login(e) { e.preventDefault(); const formData = new FormData(e.target); try { const res = await fetch(`${API_BASE}/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(Object.fromEntries(formData)) }); if (res.ok) { const data = await res.json(); localStorage.setItem('token', data.token); localStorage.setItem('user', JSON.stringify(data.user)); location.reload(); } else { alert('Ошибка входа! Проверьте логин/пароль.'); } } catch (err) { alert('Ошибка сети'); } } function logout() { if (confirm('Выйти из системы?')) { localStorage.removeItem('token'); localStorage.removeItem('user'); location.reload(); } } // ========================================== // 2. ЗАГРУЗКА ДАННЫХ // ========================================== async function loadUsers() { const token = localStorage.getItem('token'); // Если есть токен -> /users (защищенный), иначе -> /public/users const url = token ? `${API_BASE}/users` : `${API_BASE}/public/users`; const headers = token ? { 'Authorization': `Bearer ${token}` } : {}; try { const res = await fetch(url, { headers }); if (res.ok) { usersList = await res.json(); renderTable(usersList); } else { console.error('Ошибка загрузки данных'); } } catch (e) { console.error(e); } finally { document.getElementById('loader').classList.add('hidden'); } } function renderTable(users) { const tbody = document.getElementById('usersTableBody'); tbody.innerHTML = ''; const isAdmin = currentUser && currentUser.role === 'admin'; if (users.length === 0) { tbody.innerHTML = '<tr><td colspan="5" style="text-align:center; padding:2rem">Список пуст</td></tr>'; return; } users.forEach(user => { const tr = document.createElement('tr'); // Обработка скрытых данных для гостей const isMasked = user.id === '***'; const dateDisplay = isMasked ? '<span style="color:#cbd5e1">••••••••••</span>' : new Date(user.created_at).toLocaleDateString('ru-RU', { day: 'numeric', month: 'long', year: 'numeric' }); const roleClass = user.role_name === 'admin' ? 'role-admin' : 'role-user'; // Кнопки действий let actionsHtml = ''; if (isAdmin) { actionsHtml = ` <td class="text-right"> <button class="btn btn-icon" onclick="openModal('edit', ${user.id})" title="Изменить">✏️</button> <button class="btn btn-icon delete" onclick="deleteUser(${user.id})" title="Удалить">🗑️</button> </td> `; } else if (currentUser) { actionsHtml = `<td class="text-right"><span style="color:#cbd5e1">—</span></td>`; } tr.innerHTML = ` <td><span style="font-family:monospace; color:#64748b">#${user.id}</span></td> <td style="font-weight:500">${user.login}</td> <td><span class="role-badge ${roleClass}">${user.role_name}</span></td> <td>${dateDisplay}</td> ${actionsHtml} `; tbody.appendChild(tr); }); } // ========================================== // 3. УПРАВЛЕНИЕ ПОЛЬЗОВАТЕЛЯМИ (CRUD) // ========================================== async function handleUserSubmit(e) { e.preventDefault(); const form = e.target; const formData = new FormData(form); const body = Object.fromEntries(formData); const id = body.id; // Очистка пустых полей (пароль) if (id && !body.password) delete body.password; const method = id ? 'PUT' : 'POST'; const url = id ? `${API_BASE}/users/${id}` : `${API_BASE}/users`; const token = localStorage.getItem('token'); try { const res = await fetch(url, { method: method, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify(body) }); const result = await res.json(); if (res.ok) { closeModal(); loadUsers(); // Перезагружаем список } else { alert(`Ошибка: ${result.error}`); } } catch (err) { alert('Ошибка сервера'); } } async function deleteUser(id) { if (id === currentUser.id) { alert('Нельзя удалить самого себя!'); return; } if (!confirm('Вы уверены? Это действие нельзя отменить.')) return; try { const res = await fetch(`${API_BASE}/users/${id}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }); if (res.ok) loadUsers(); else alert('Не удалось удалить пользователя'); } catch (e) { alert('Ошибка сети'); } } // ========================================== // 4. ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ (Модалки) // ========================================== // Auth Modal function toggleAuthModal() { const modal = document.getElementById('authModal'); modal.classList.toggle('hidden'); modal.classList.toggle('active'); // для анимации } document.getElementById('loginForm').addEventListener('submit', login); // User Modal function openModal(mode, userId = null) { const modal = document.getElementById('userModal'); const form = document.getElementById('userForm'); const title = document.getElementById('modalTitle'); const passHint = document.getElementById('passHint'); modal.classList.remove('hidden'); setTimeout(() => modal.classList.add('active'), 10); form.reset(); if (mode === 'edit') { const user = usersList.find(u => u.id === userId); title.textContent = `Редактирование: ${user.login}`; form.elements.id.value = user.id; form.elements.login.value = user.login; form.elements.role.value = user.role_name; form.elements.password.placeholder = "••••••••"; form.elements.password.required = false; passHint.classList.remove('hidden'); } else { title.textContent = 'Новый пользователь'; form.elements.id.value = ''; form.elements.password.placeholder = "Придумайте пароль"; form.elements.password.required = true; passHint.classList.add('hidden'); } } function closeModal() { const modals = document.querySelectorAll('.modal'); modals.forEach(m => { m.classList.remove('active'); setTimeout(() => m.classList.add('hidden'), 200); }); } document.getElementById('userForm').addEventListener('submit', handleUserSubmit); function generatePassword() { const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; const pass = Array(10).fill(0).map(() => chars[Math.floor(Math.random() * chars.length)]).join(''); const input = document.getElementById('passInput'); input.value = pass; input.type = "text"; // Мигание для эффекта input.style.backgroundColor = "#dcfce7"; setTimeout(() => input.style.backgroundColor = "", 300); }