diff --git a/src/App.tsx b/src/App.tsx
index 97f2e10..0d1f1df 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -17,18 +17,24 @@ import { MainLayout } from '@/components/layout/MainLayout';
import { ProtectedRoute } from '@/router/ProtectedRoute';
import { useAuthStore, useLanguageStore, useThemeStore } from '@/stores';
+const SPLASH_DURATION = 1500;
+const SPLASH_FADE_DURATION = 400;
+
function App() {
const initializeTheme = useThemeStore((state) => state.initializeTheme);
const language = useLanguageStore((state) => state.language);
const setLanguage = useLanguageStore((state) => state.setLanguage);
const restoreSession = useAuthStore((state) => state.restoreSession);
- const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
+ const [splashReadyToFade, setSplashReadyToFade] = useState(false);
const [showSplash, setShowSplash] = useState(true);
+ const [authReady, setAuthReady] = useState(false);
useEffect(() => {
initializeTheme();
- restoreSession();
+ void restoreSession().finally(() => {
+ setAuthReady(true);
+ });
}, [initializeTheme, restoreSession]);
useEffect(() => {
@@ -36,13 +42,25 @@ function App() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // 仅用于首屏同步 i18n 语言
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setSplashReadyToFade(true);
+ }, SPLASH_DURATION - SPLASH_FADE_DURATION);
+
+ return () => clearTimeout(timer);
+ }, []);
+
const handleSplashFinish = useCallback(() => {
setShowSplash(false);
}, []);
- // 仅在已认证时显示闪屏
- if (showSplash && isAuthenticated) {
- return ;
+ if (showSplash) {
+ return (
+
+ );
}
return (
diff --git a/src/components/common/SplashScreen.tsx b/src/components/common/SplashScreen.tsx
index 1233d8e..ffee1d3 100644
--- a/src/components/common/SplashScreen.tsx
+++ b/src/components/common/SplashScreen.tsx
@@ -1,29 +1,25 @@
-import { useEffect, useState } from 'react';
+import { useEffect } from 'react';
import { INLINE_LOGO_JPEG } from '@/assets/logoInline';
import './SplashScreen.scss';
interface SplashScreenProps {
onFinish: () => void;
- duration?: number;
+ fadeOut?: boolean;
}
-export function SplashScreen({ onFinish, duration = 1500 }: SplashScreenProps) {
- const [fadeOut, setFadeOut] = useState(false);
+const FADE_OUT_DURATION = 400;
+export function SplashScreen({ onFinish, fadeOut = false }: SplashScreenProps) {
useEffect(() => {
- const fadeTimer = setTimeout(() => {
- setFadeOut(true);
- }, duration - 400);
-
+ if (!fadeOut) return;
const finishTimer = setTimeout(() => {
onFinish();
- }, duration);
+ }, FADE_OUT_DURATION);
return () => {
- clearTimeout(fadeTimer);
clearTimeout(finishTimer);
};
- }, [duration, onFinish]);
+ }, [fadeOut, onFinish]);
return (
diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx
index b66e6a8..7b4bca4 100644
--- a/src/pages/LoginPage.tsx
+++ b/src/pages/LoginPage.tsx
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from 'react';
-import { useNavigate, useLocation } from 'react-router-dom';
+import { Navigate, useNavigate, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
@@ -44,12 +44,10 @@ export function LoginPage() {
init();
}, [detectedBase, restoreSession, storedBase, storedKey]);
- useEffect(() => {
- if (isAuthenticated) {
- const redirect = (location.state as any)?.from?.pathname || '/';
- navigate(redirect, { replace: true });
- }
- }, [isAuthenticated, navigate, location.state]);
+ if (isAuthenticated) {
+ const redirect = (location.state as any)?.from?.pathname || '/';
+ return ;
+ }
const handleUseCurrent = () => {
setApiBase(detectedBase);