refactor(auth): centralize login status sync

This commit is contained in:
2026-06-18 12:52:49 +08:00
parent 0d0dabaace
commit f600e11d55
11 changed files with 115 additions and 128 deletions
+4 -68
View File
@@ -10,22 +10,18 @@
* - BrowserHintOverlay:浏览器提示
*
* 鉴权解耦(事件驱动):
* - chat 机器不感知鉴权 / 不管 WebSocket —— 由 chat-screen 派生 loginStatus
* - chat-screen 只派 3 个事件:
* - `ChatGuestLogin` → 游客会话(断 WS = 不连)
* - `ChatNonGuestLogin { token }` → 非游客会话(连 WS)
* - `ChatLogout` → 登出(机器自动 cleanup WS actor
* - chat 机器内部用 fromCallback actor 完整管理 WS 生命周期
* - chat 机器不感知鉴权 / 不管 WebSocket
* - auth → chat 的生命周期同步由根级 <ChatAuthSync /> 负责
* - ChatScreen 只派生 UI 展示所需的 isGuest
*/
import { useEffect, useRef, useState } from "react";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useAuthState } from "@/stores/auth/auth-context";
import type { LoginStatus } from "@/data/dto/auth";
import { AuthStorage } from "@/data/storage/auth/auth_storage";
import { UserStorage } from "@/data/storage/user/user_storage";
import { useChatDispatch, useChatState } from "@/stores/chat/chat-context";
import { useChatState } from "@/stores/chat/chat-context";
import { AppEnvUtil, BrowserDetector, UrlLauncherUtil } from "@/utils";
import { ROUTE_BUILDERS, ROUTES } from "@/router/routes";
@@ -50,39 +46,9 @@ function deriveIsGuest(loginStatus: LoginStatus): boolean {
return loginStatus === "guest";
}
/**
* 按 loginStatus 派鉴权生命周期事件(chat 机器不感知 loginStatus —— 这层转换在此)
*
* 设计:不直接管理 WS / 不读 AuthStorage(除取 token
*/
function dispatchAuthLifecycle(
loginStatus: LoginStatus,
chatDispatch: ReturnType<typeof useChatDispatch>,
): void {
if (loginStatus === "guest") {
// 游客:派 ChatGuestLoginchat 机器不连 WS —— 业务事实"断 WS"
chatDispatch({ type: "ChatGuestLogin" });
return;
}
if (loginStatus === "notLoggedIn") {
// 登出:派 ChatLogoutchat 机器自动 cleanup WS actor + 清消息)
chatDispatch({ type: "ChatLogout" });
return;
}
// 非游客:拿 loginToken → 派 ChatNonGuestLogin { token }
void (async () => {
const tokenR = await AuthStorage.getInstance().getLoginToken();
if (tokenR.success && tokenR.data) {
chatDispatch({ type: "ChatNonGuestLogin", token: tokenR.data });
}
})();
}
export function ChatScreen() {
const router = useRouter();
const state = useChatState();
const authState = useAuthState();
const chatDispatch = useChatDispatch();
const [showExternalBrowserDialog, setShowExternalBrowserDialog] =
useState(false);
@@ -98,37 +64,7 @@ export function ChatScreen() {
const showExhaustedBanner =
isGuest && state.quotaLoaded && state.quotaExceededTrigger > 0;
// ─────────────────────────────────────────────────────────────
// loginStatus 变化 → 派对应鉴权生命周期事件
//
// 规则:
// - AuthInit 未完成 → 等,避免初始 notLoggedIn 把 /chat 变成死状态
// - AuthInit 完成后仍 "notLoggedIn" → 清 chat 并回 splash
// - 登录态变化(guest→email 等)→ 派 ChatGuestLogin 或 ChatNonGuestLogin
// ─────────────────────────────────────────────────────────────
const prevLoginStatusRef = useRef<LoginStatus | null>(null);
const externalBrowserPromptShownRef = useRef(false);
useEffect(() => {
if (!authState.hasInitialized || authState.isLoading) return;
const prev = prevLoginStatusRef.current;
if (prev === authState.loginStatus) return; // 登录态没变
prevLoginStatusRef.current = authState.loginStatus;
if (authState.loginStatus === "notLoggedIn") {
chatDispatch({ type: "ChatLogout" });
router.replace(ROUTES.splash);
return;
}
dispatchAuthLifecycle(authState.loginStatus, chatDispatch);
}, [
authState.hasInitialized,
authState.isLoading,
authState.loginStatus,
chatDispatch,
router,
]);
useEffect(() => {
if (!authState.hasInitialized || authState.isLoading) return;