docs: 新增 AI 代理学习偏好与信用盘术语规范
feat: 优化登录与入口页面加载体验 - 为登录页面添加 Suspense 边界,统一 fallback 样式 - 重构入口守卫逻辑,在布局阶段处理未登录重定向,避免闪烁 - 登录页面支持会话过期提示,并自动清理 URL 参数 feat: 信用盘与钱包盘文案差异化展示 - 底部导航「钱包」标签在信用盘模式下显示为「信用」 - 大厅余额条在信用盘模式下使用「可
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import axios, {
|
||||
isAxiosError,
|
||||
type AxiosError,
|
||||
type AxiosRequestConfig,
|
||||
type AxiosResponse,
|
||||
} from "axios";
|
||||
|
||||
import { isInIframe } from "@/components/iframe-bridge";
|
||||
import { withPlayerAuthHeader } from "@/lib/lottery-auth";
|
||||
import { usePlayerSessionStore } from "@/stores/player-session-store";
|
||||
import { withLotteryLocaleHeaders } from "@/lib/lottery-locale";
|
||||
@@ -14,6 +16,7 @@ import {
|
||||
import { isApiEnvelope } from "@/types/api/envelope";
|
||||
import { useErrorStore } from "@/stores/error-store";
|
||||
import { resolveLotteryApiV1Base } from "@/lib/lottery-api-base";
|
||||
import i18n from "@/i18n";
|
||||
|
||||
/**
|
||||
* **第一层**:`baseURL` 对齐 Laravel `api/v1`;各 `api/*.ts` 只写业务 path(如 `/currencies`)。
|
||||
@@ -24,6 +27,34 @@ export const lotteryHttp = axios.create({
|
||||
headers: { Accept: "application/json" },
|
||||
});
|
||||
|
||||
/** 凭据类 401(非 token 失效),不应触发「会话过期」跳转 */
|
||||
const PLAYER_CREDENTIAL_BIZ_CODES = new Set([8006]);
|
||||
|
||||
function isPlayerAuthLoginRequest(config: AxiosRequestConfig | undefined): boolean {
|
||||
if (!config || (config.method ?? "get").toLowerCase() !== "post") {
|
||||
return false;
|
||||
}
|
||||
return `${config.url ?? ""}`.includes("/player/auth/login");
|
||||
}
|
||||
|
||||
/** 是否应将 401 视为已登录态失效并跳转入口(见 {@link EntryGate} `session=expired`) */
|
||||
function shouldRedirectPlayerSessionExpired(error: AxiosError): boolean {
|
||||
if (isPlayerAuthLoginRequest(error.config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof window !== "undefined" && window.location.pathname === "/login") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const body = error.response?.data;
|
||||
if (isApiEnvelope(body) && PLAYER_CREDENTIAL_BIZ_CODES.has(body.code)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 站内接口 401:清本地会话并回入口,与 {@link EntryGate} `session=expired` 衔接 */
|
||||
/** 500 错误:更新全局服务器错误状态 */
|
||||
lotteryHttp.interceptors.response.use(
|
||||
@@ -32,20 +63,28 @@ lotteryHttp.interceptors.response.use(
|
||||
if (isAxiosError(error) && typeof window !== "undefined") {
|
||||
const status = error.response?.status;
|
||||
|
||||
// 401: 会话过期,清除令牌并重定向
|
||||
// 401: 已登录态 token 失效 → 清会话并回入口;登录凭据错误等由页面自行提示
|
||||
if (status === 401) {
|
||||
usePlayerSessionStore.getState().clearBearerToken();
|
||||
const onEntry = window.location.pathname === "/";
|
||||
const alreadyExpired = window.location.search.includes("session=expired");
|
||||
if (!onEntry || !alreadyExpired) {
|
||||
window.location.replace("/?session=expired");
|
||||
const redirectSessionExpired = shouldRedirectPlayerSessionExpired(error);
|
||||
if (redirectSessionExpired || window.location.pathname === "/login") {
|
||||
usePlayerSessionStore.getState().clearBearerToken();
|
||||
}
|
||||
if (redirectSessionExpired) {
|
||||
const pathname = window.location.pathname;
|
||||
const alreadyExpired = window.location.search.includes("session=expired");
|
||||
const expiredTarget = isInIframe() ? "/?session=expired" : "/login?session=expired";
|
||||
const onExpiredPage =
|
||||
(pathname === "/" || pathname === "/login") && alreadyExpired;
|
||||
if (!onExpiredPage) {
|
||||
window.location.replace(expiredTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 500/502/503: 服务器错误,更新全局错误状态
|
||||
if (status === 500 || status === 502 || status === 503) {
|
||||
const setServerError = useErrorStore.getState().setServerError;
|
||||
let message = "服务器暂时不可用,请稍后重试";
|
||||
let message = i18n.t("serverError.serverMessage", { ns: "player" });
|
||||
|
||||
// 尝试从响应中获取更详细的错误信息
|
||||
const responseData = error.response?.data;
|
||||
|
||||
Reference in New Issue
Block a user