登陆优化

This commit is contained in:
Azmat@qq.com
2026-09-17 10:28:37 +08:00
parent b487b65575
commit bd4799151c
8 changed files with 222 additions and 95 deletions
+12
View File
@@ -57,6 +57,8 @@ const API_BASE = import.meta.env.VITE_API_BASE_URL || "";
const TOKEN_KEY = "airshelf_token";
const REMEMBER_KEY = "airshelf_remember"; // { username, expireAt } · 勾选「记住我 7 天」时写
const REMEMBER_DAYS = 7;
export const AUTH_INVALIDATED_EVENT = "airshelf:auth-invalidated";
let authInvalidationNotified = false;
const AUTH_MISSING_MESSAGES = new Set([
"身份认证信息未提供。",
"Authentication credentials were not provided."
@@ -159,10 +161,17 @@ export function setToken(token: string | null, remember = true) {
localStorage.removeItem(TOKEN_KEY);
sessionStorage.removeItem(TOKEN_KEY);
if (!token) return;
authInvalidationNotified = false;
if (remember) localStorage.setItem(TOKEN_KEY, token);
else sessionStorage.setItem(TOKEN_KEY, token);
}
function notifyAuthInvalidated() {
if (authInvalidationNotified || typeof window === "undefined") return;
authInvalidationNotified = true;
window.dispatchEvent(new CustomEvent(AUTH_INVALIDATED_EVENT));
}
async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
const token = getToken();
const headers = new Headers(options.headers);
@@ -173,6 +182,9 @@ async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
const response = await fetch(`${API_BASE}${path}`, { ...options, headers });
if (!response.ok) {
// 已携带凭证却收到 401,说明 Token 已被服务端吊销。先通知应用壳弹出
// 单设备登录提示,再保留原始错误给具体调用方处理。
if (response.status === 401 && token && path !== "/api/auth/logout/") notifyAuthInvalidated();
const text = await response.text();
// DRF 错误体是 JSON({"detail": "..."} 或 {field: ["..."]}),提取人话给 toast,别把原始 JSON 怼到用户脸上
let message = text || `${response.status} ${response.statusText}`;