feat(web): стабилизация UI, Gemini-скроллинг, роутеры контекста/снапшотов и актуализация роадмапа

This commit is contained in:
2026-09-07 17:29:21 +03:00
parent 1bb95cd8e1
commit d391a08224
33 changed files with 7768 additions and 1832 deletions
+50 -37
View File
@@ -1,62 +1,75 @@
/**
* ===============================================================================
* FILE: static/js/auth.js
* ROLE: Управление сессией пользователя, токенами и корректным выходом (Logout).
* FILE: modules/web_api/static/js/auth.js
* ROLE: Менеджер сессий, токенов, ФИО и авторизационных заголовков.
* ===============================================================================
*/
const AUTH_STORAGE_KEY = "scud_auth_token";
const USERNAME_STORAGE_KEY = "scud_username";
const FULLNAME_STORAGE_KEY = "scud_full_name";
const IS_ADMIN_STORAGE_KEY = "scud_is_admin";
const USER_ID_STORAGE_KEY = "scud_user_id";
const AuthManager = {
getToken() {
let token = localStorage.getItem("auth_token") || localStorage.getItem("token");
if (!token) {
// Если токена нет — инициализируем рабочий дефолтный токен
token = "dev_token_1";
localStorage.setItem("auth_token", token);
localStorage.setItem("user_id", "1");
}
return token;
return localStorage.getItem(AUTH_STORAGE_KEY) || "";
},
getUserId() {
return parseInt(localStorage.getItem("user_id") || "1", 10);
const uid = localStorage.getItem(USER_ID_STORAGE_KEY);
return uid ? parseInt(uid, 10) : 1;
},
getUsername() {
return localStorage.getItem(USERNAME_STORAGE_KEY) || "";
},
getFullName() {
return localStorage.getItem(FULLNAME_STORAGE_KEY) || this.getUsername() || "Пользователь";
},
isAdmin() {
return localStorage.getItem(IS_ADMIN_STORAGE_KEY) === "true";
},
isAuthenticated() {
return Boolean(this.getToken());
},
setSession(token, username, fullName, isAdmin, userId = 1) {
localStorage.setItem(AUTH_STORAGE_KEY, token);
localStorage.setItem(USERNAME_STORAGE_KEY, username);
localStorage.setItem(FULLNAME_STORAGE_KEY, fullName || username);
localStorage.setItem(IS_ADMIN_STORAGE_KEY, String(isAdmin));
localStorage.setItem(USER_ID_STORAGE_KEY, String(userId));
localStorage.setItem("scud_api_auth_token", token);
localStorage.setItem("auth_token", token);
},
getAuthHeaders() {
const token = this.getToken();
const headers = { "Content-Type": "application/json" };
if (token) {
headers["Authorization"] = `Bearer ${token}`;
}
return headers;
},
logout() {
console.log("[Auth] Выполняется выход из учетной записи...");
// 1. Полная очистка хранилищ браузера
localStorage.removeItem("auth_token");
localStorage.removeItem("token");
localStorage.removeItem("user_id");
console.log("[Auth] Полный выход из системы...");
localStorage.clear();
sessionStorage.clear();
// 2. Сброс авторизационных cookies (если присутствуют)
document.cookie.split(";").forEach((cookie) => {
const eqPos = cookie.indexOf("=");
const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : cookie.trim();
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
});
// 3. Перезагрузка страницы для сброса состояния интерфейса
window.location.reload();
},
init() {
// Привязка клика ко всем элементам с классом или id logout
document.addEventListener("DOMContentLoaded", () => {
const logoutBtns = document.querySelectorAll("#logout-btn, .logout-btn, [data-action='logout']");
logoutBtns.forEach(btn => {
btn.addEventListener("click", (e) => {
e.preventDefault();
AuthManager.logout();
});
});
});
window.location.href = "/";
}
};
// Инициализация при загрузке скрипта
AuthManager.init();
// Глобальная доступность функции для onclick в HTML
window.AuthManager = AuthManager;
window.logout = () => AuthManager.logout();