From cd5a385cdadffde1bd4814fb5ea27a8a893bb725 Mon Sep 17 00:00:00 2001 From: dongsk Date: Thu, 27 Aug 2026 16:46:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=80=E6=9C=89=E6=A8=A1=E5=9D=97=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=B7=AF=E7=94=B1=E5=AE=88=E5=8D=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 21 ++++++++------- src/pages/HomePage.tsx | 8 ------ src/pages/LoginPage.tsx | 7 +++-- src/shared/components/RequireAuth.tsx | 39 +++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 src/shared/components/RequireAuth.tsx diff --git a/src/App.tsx b/src/App.tsx index 0e33858..b2678ef 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,6 +2,7 @@ import { Routes, Route } from 'react-router-dom'; import HomePage from '@/pages/HomePage'; import SSOLogin from '@/pages/SSOLogin'; import LoginPage from '@/pages/LoginPage'; +import RequireAuth from '@/shared/components/RequireAuth'; import AIMCockpit from '@/modules/ai-matching/pages/AIMCockpit'; import CostCockpit from '@/modules/cost-analysis/pages/CostCockpit'; import KnowledgeGraphHome from '@/modules/knowledge-graph/pages/KnowledgeGraphHome'; @@ -15,18 +16,18 @@ import SanruiAIDesignHome from '@/modules/sanrui-ai-design/pages/SanruiAIDesignH export default function App() { return ( - } /> } /> } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> ); } diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 07507b4..0581026 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -24,14 +24,6 @@ export default function HomePage() { const [searchParams] = useSearchParams(); const [userInfo, setUserInfo] = useState(() => getUserInfo()); - // 登录守卫:未登录跳转 /login - useEffect(() => { - const token = sessionStorage.getItem('userToken'); - if (!token) { - navigate('/login', { replace: true }); - } - }, [navigate]); - // 首页模块多时需纵向滚动;离开后恢复全局 overflow:hidden(其他模块自管布局) useEffect(() => { document.body.style.overflow = 'auto'; diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx index 99f9fa2..c0ead1f 100644 --- a/src/pages/LoginPage.tsx +++ b/src/pages/LoginPage.tsx @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useLocation } from 'react-router-dom'; import { User, Lock, LogIn, AlertCircle, Loader2 } from 'lucide-react'; import StarBackground from '@/shared/components/StarBackground'; import { iamLogin, saveSession } from '@/shared/services/iamAuth'; @@ -28,6 +28,7 @@ const iconStyle = (isDark: boolean): React.CSSProperties => ({ export default function LoginPage() { const navigate = useNavigate(); + const location = useLocation(); const { theme } = useTheme(); const isDark = theme === 'dark'; @@ -52,7 +53,9 @@ export default function LoginPage() { try { const result = await iamLogin({ userId: userId.trim(), password }); saveSession(result.token, result.userInfo); - navigate('/', { replace: true }); + // 回跳原页面(RequireAuth 记录的 from),否则去首页 + const from = (location.state as { from?: string })?.from ?? '/'; + navigate(from, { replace: true }); } catch (ex) { setError(ex instanceof Error ? ex.message : '登录失败,请稍后重试'); } finally { diff --git a/src/shared/components/RequireAuth.tsx b/src/shared/components/RequireAuth.tsx new file mode 100644 index 0000000..40e1730 --- /dev/null +++ b/src/shared/components/RequireAuth.tsx @@ -0,0 +1,39 @@ +import { ReactNode, useEffect, useState } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { Spin } from 'antd'; + +/** + * 登录守卫:未登录跳转 /login + * + * 检查 sessionStorage 中的 userToken,若不存在则跳转登录页。 + * 登录后会带上 from state,便于登录成功后回跳原页面。 + */ +export default function RequireAuth({ children }: { children: ReactNode }) { + const navigate = useNavigate(); + const location = useLocation(); + const [checked, setChecked] = useState(false); + + useEffect(() => { + const token = sessionStorage.getItem('userToken'); + if (!token) { + // 记录原路径,登录后可回跳 + navigate('/login', { replace: true, state: { from: location.pathname + location.search } }); + return; + } + setChecked(true); + }, [navigate, location]); + + if (!checked) { + return ( +
+ +
+ ); + } + + return <>{children}; +}