function setStatus(msg, type = "info") { const el = document.getElementById("status"); el.textContent = msg || ""; el.style.color = type === 'error' ? '#b91c1c' : type === 'ok' ? '#16a34a' : ''; } function decodeRoleFromJWT(token) { try { const payload = JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))); return payload.role || null; } catch { return null; } } async function login(username, password) { const params = new URLSearchParams(); params.set('username', username); params.set('password', password); try { const res = await fetch('/auth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params.toString(), }); if (!res.ok) { const txt = await res.text(); throw new Error(`Ошибка входа (${res.status}): ${txt}`); } const data = await res.json(); const token = data.access_token; if (!token) throw new Error('Токен не получен'); localStorage.setItem('access_token', token); const role = decodeRoleFromJWT(token); if (role) localStorage.setItem('role', role); return { token, role }; } catch (e) { throw e; } } document.addEventListener('DOMContentLoaded', () => { const form = document.getElementById('login-form'); form.addEventListener('submit', async (ev) => { ev.preventDefault(); setStatus('Входим…'); const username = document.getElementById('username').value.trim(); const password = document.getElementById('password').value; try { const { role } = await login(username, password); setStatus(`Успешный вход${role ? ' (' + role + ')' : ''}`, 'ok'); // Небольшая задержка для визуального отклика setTimeout(() => { window.location.href = '/app/'; }, 400); } catch (e) { console.error(e); setStatus(e.message || 'Ошибка авторизации', 'error'); } }); });