所有模块添加路由守卫

This commit is contained in:
2026-08-27 16:46:52 +08:00
parent 989120cab8
commit cd5a385cda
4 changed files with 55 additions and 20 deletions
+11 -10
View File
@@ -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 (
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/sso-login" element={<SSOLogin />} />
<Route path="/ai-matching" element={<AIMCockpit />} />
<Route path="/cost-analysis" element={<CostCockpit />} />
<Route path="/knowledge-graph" element={<KnowledgeGraphHome />} />
<Route path="/knowledge-graph/space" element={<SpaceCockpit />} />
<Route path="/bomx-reuse-analyzer" element={<BomxReuseHome />} />
<Route path="/order-cost-analysis" element={<CostCockpitFull />} />
<Route path="/order-cost-analysis/aim" element={<AIMCockpitFull />} />
<Route path="/bexell-scheduling-ai/*" element={<BexellSchedulingApp />} />
<Route path="/sanrui-ai-design" element={<SanruiAIDesignHome />} />
<Route path="/" element={<RequireAuth><HomePage /></RequireAuth>} />
<Route path="/ai-matching" element={<RequireAuth><AIMCockpit /></RequireAuth>} />
<Route path="/cost-analysis" element={<RequireAuth><CostCockpit /></RequireAuth>} />
<Route path="/knowledge-graph" element={<RequireAuth><KnowledgeGraphHome /></RequireAuth>} />
<Route path="/knowledge-graph/space" element={<RequireAuth><SpaceCockpit /></RequireAuth>} />
<Route path="/bomx-reuse-analyzer" element={<RequireAuth><BomxReuseHome /></RequireAuth>} />
<Route path="/order-cost-analysis" element={<RequireAuth><CostCockpitFull /></RequireAuth>} />
<Route path="/order-cost-analysis/aim" element={<RequireAuth><AIMCockpitFull /></RequireAuth>} />
<Route path="/bexell-scheduling-ai/*" element={<RequireAuth><BexellSchedulingApp /></RequireAuth>} />
<Route path="/sanrui-ai-design" element={<RequireAuth><SanruiAIDesignHome /></RequireAuth>} />
</Routes>
);
}
-8
View File
@@ -24,14 +24,6 @@ export default function HomePage() {
const [searchParams] = useSearchParams();
const [userInfo, setUserInfo] = useState<SessionUserInfo | null>(() => getUserInfo());
// 登录守卫:未登录跳转 /login
useEffect(() => {
const token = sessionStorage.getItem('userToken');
if (!token) {
navigate('/login', { replace: true });
}
}, [navigate]);
// 首页模块多时需纵向滚动;离开后恢复全局 overflow:hidden(其他模块自管布局)
useEffect(() => {
document.body.style.overflow = 'auto';
+5 -2
View File
@@ -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 {
+39
View File
@@ -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 (
<div style={{
width: '100vw', height: '100vh',
display: 'flex', alignItems: 'center', justifyContent: 'center',
background: '#0a1628',
}}>
<Spin size="large" />
</div>
);
}
return <>{children}</>;
}