blob: 2764f5ae1c750740ea72e61282a71c987e31109b [file] [log] [blame]
223010144ce05872025-06-08 22:33:28 +08001// src/routes/ProtectedRoute.tsx
2
3import React, { useEffect, useState } from 'react';
4import { useAppSelector, useAppDispatch } from '../store/hooks';
22301014b1477f72025-06-07 22:54:40 +08005import { useNavigate } from 'react-router';
223010144ce05872025-06-08 22:33:28 +08006import { refreshToken } from '../feature/auth/authSlice';
7import { Spin } from 'antd';
22301014b1477f72025-06-07 22:54:40 +08008
9interface ProtectedRouteProps {
10 children: React.ReactNode;
11}
12
13const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
14 const { isAuth, token } = useAppSelector((state) => state.auth);
15 const navigate = useNavigate();
16 const dispatch = useAppDispatch();
223010144ce05872025-06-08 22:33:28 +080017 const [isLoading, setIsLoading] = useState(false);
22301014b1477f72025-06-07 22:54:40 +080018
19 useEffect(() => {
20 const tryRefreshToken = async () => {
223010144ce05872025-06-08 22:33:28 +080021 // 如果没有token,直接跳转到登录页
22301014b1477f72025-06-07 22:54:40 +080022 if (!token) {
223010144ce05872025-06-08 22:33:28 +080023 navigate('/login', { replace: true });
24 return;
22301014b1477f72025-06-07 22:54:40 +080025 }
223010144ce05872025-06-08 22:33:28 +080026
27 // 如果有token但未认证,尝试刷新token
22301014b1477f72025-06-07 22:54:40 +080028 if (!isAuth && token) {
223010144ce05872025-06-08 22:33:28 +080029 setIsLoading(true);
22301014b1477f72025-06-07 22:54:40 +080030 try {
223010144ce05872025-06-08 22:33:28 +080031 await dispatch(refreshToken(token)).unwrap();
32 } catch (error) {
33 console.error('Token refresh failed:', error);
34 navigate('/login', { replace: true });
35 } finally {
36 setIsLoading(false);
22301014b1477f72025-06-07 22:54:40 +080037 }
38 }
39 };
40
223010144ce05872025-06-08 22:33:28 +080041 tryRefreshToken();
22301014b1477f72025-06-07 22:54:40 +080042 }, [isAuth, token, dispatch, navigate]);
43
223010144ce05872025-06-08 22:33:28 +080044 // 显示加载状态
45 if (isLoading) {
46 return (
47 <div style={{
48 display: 'flex',
49 justifyContent: 'center',
50 alignItems: 'center',
51 height: '100vh'
52 }}>
53 <Spin size="large" tip="验证身份中..." />
54 </div>
55 );
56 }
57
58 // 如果没有token,返回null(会触发导航)
59 if (!token) {
60 return null;
61 }
62
63 // 如果已认证,渲染children
64 if (isAuth) {
65 return <>{children}</>;
66 }
67
68 // 如果有token但还在验证中,显示加载状态
69 return (
70 <div style={{
71 display: 'flex',
72 justifyContent: 'center',
73 alignItems: 'center',
74 height: '100vh'
75 }}>
76 <Spin size="large" tip="验证身份中..." />
77 </div>
78 );
22301014b1477f72025-06-07 22:54:40 +080079};
80
223010144ce05872025-06-08 22:33:28 +080081export default ProtectedRoute;