优化后台界面与无操作退出体验

This commit is contained in:
Cheng Zhou
2026-06-10 15:20:06 +08:00
parent ea3f19e241
commit 84e55af8fe
39 changed files with 793 additions and 608 deletions
+4 -35
View File
@@ -5,8 +5,7 @@ import { getToken } from "../utils/auth";
import type { ApiError } from "../types/api";
import { useStudyStore } from "../store/study";
import { TEXT } from "../locales";
import { extendAccessToken, forceLogout, lockSession, markNetworkActive } from "../session/sessionManager";
import { useSessionStore } from "../store/session";
import { extendAccessToken, forceLogout, LOGOUT_REASON_AUTH_EXPIRED } from "../session/sessionManager";
const instance: AxiosInstance = axios.create({
baseURL: "/",
@@ -14,59 +13,29 @@ const instance: AxiosInstance = axios.create({
});
export type ApiRequestConfig = AxiosRequestConfig & {
ignoreIdle?: boolean;
allowWhileLocked?: boolean;
suppressErrorMessage?: boolean;
_retry?: boolean;
};
class LockedError extends Error {
constructor() {
super("LOCKED");
this.name = "LockedError";
}
}
instance.interceptors.request.use((config: InternalAxiosRequestConfig & ApiRequestConfig) => {
const session = useSessionStore();
const reqUrl = config.url || "";
const allowWhileLocked =
config.allowWhileLocked ||
reqUrl.includes("/api/v1/auth/login") ||
reqUrl.includes("/api/v1/auth/register") ||
reqUrl.includes("/api/v1/auth/unlock");
if (session.locked && !allowWhileLocked) {
return Promise.reject(new LockedError());
}
const token = getToken();
if (token) {
config.headers = config.headers || {};
(config.headers as Record<string, string>).Authorization = `Bearer ${token}`;
}
if (!config.ignoreIdle) {
markNetworkActive();
}
return config;
});
instance.interceptors.response.use(
(response: AxiosResponse) => response,
async (error: AxiosError<ApiError>) => {
if (error instanceof LockedError) {
const lockedConfig = error.config as ApiRequestConfig | undefined;
if (!lockedConfig?.suppressErrorMessage) {
ElMessage.warning(TEXT.common.messages.sessionLocked || "请解锁后继续操作");
}
return Promise.reject(error);
}
const status = error.response?.status;
const data = error.response?.data;
const reqUrl = error.config?.url || "";
const isAuthEndpoint =
reqUrl.includes("/api/v1/auth/login") ||
reqUrl.includes("/api/v1/auth/register") ||
reqUrl.includes("/api/v1/auth/extend") ||
reqUrl.includes("/api/v1/auth/unlock");
reqUrl.includes("/api/v1/auth/extend");
if (isAuthEndpoint) {
// 认证相关的错误由具体页面自行处理,避免重复提示
return Promise.reject(error);
@@ -92,11 +61,11 @@ instance.interceptors.response.use(
return instance(config);
}
if (result.authFailed) {
lockSession("token_invalid");
forceLogout(LOGOUT_REASON_AUTH_EXPIRED);
}
}
} else if (status === 403 && (data as any)?.detail === "账号已停用") {
forceLogout();
forceLogout(LOGOUT_REASON_AUTH_EXPIRED);
} else {
const suppressErrorMessage = (error.config as ApiRequestConfig | undefined)?.suppressErrorMessage;
if (!suppressErrorMessage) {