59 lines
2.0 KiB
JavaScript
59 lines
2.0 KiB
JavaScript
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');
|
|
}
|
|
});
|
|
});
|
|
|