Download vetcopilot-app/src/components/ProtectedRoute.tsx from WWsCa/VetNet-LCPS: direct link, hf CLI and curl.
- Browser
- Download file 2.1 kB
-
https://huggingface.co/WWsCa/VetNet-LCPS/resolve/main/vetcopilot-app/src/components/ProtectedRoute.tsx
- Command line
-
hf download hf://WWsCa/VetNet-LCPS/vetcopilot-app/src/components/ProtectedRoute.tsx
-
curl -L -o ProtectedRoute.tsx https://huggingface.co/WWsCa/VetNet-LCPS/resolve/main/vetcopilot-app/src/components/ProtectedRoute.tsx
2.1 kB
| import React from 'react' | |
| import { Navigate, useLocation } from 'react-router-dom' | |
| import { useAuth } from '../contexts/AuthContext' | |
| import { useTranslation } from '../i18n' | |
| interface ProtectedRouteProps { | |
| children: React.ReactNode | |
| /** 可指定的最小角色。admin = 超级管理员 */ | |
| requiredRole?: string | |
| } | |
| /** | |
| * 路由守卫组件 | |
| * | |
| * - 正在验证 token 时,显示加载中状态 | |
| * - 未认证时,重定向到 /login 并携带来源路径 | |
| * - 已认证时,检查 requiredRole 角色匹配,不匹配则重定向到首页 | |
| * - 已认证时,正常渲染子组件 | |
| */ | |
| export default function ProtectedRoute({ children, requiredRole }: ProtectedRouteProps) { | |
| const { t } = useTranslation() | |
| const { isAuthenticated, isLoading, user } = useAuth() | |
| const location = useLocation() | |
| if (isLoading) { | |
| return ( | |
| <div className="h-screen flex items-center justify-center bg-surface-50"> | |
| <div className="flex flex-col items-center gap-3"> | |
| <svg | |
| className="animate-spin h-8 w-8 text-medical-600" | |
| xmlns="http://www.w3.org/2000/svg" | |
| fill="none" | |
| viewBox="0 0 24 24" | |
| > | |
| <circle | |
| className="opacity-25" | |
| cx="12" | |
| cy="12" | |
| r="10" | |
| stroke="currentColor" | |
| strokeWidth="4" | |
| /> | |
| <path | |
| className="opacity-75" | |
| fill="currentColor" | |
| d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" | |
| /> | |
| </svg> | |
| <span className="text-sm text-gray-500">{t('components.protectedRoute.verifying')}</span> | |
| </div> | |
| </div> | |
| ) | |
| } | |
| if (!isAuthenticated) { | |
| // 将当前路径作为 state 传递,登录后可跳回 | |
| return <Navigate to="/login" state={{ from: location.pathname }} replace /> | |
| } | |
| // 角色检查:如果指定了 requiredRole,且用户角色不匹配,则重定向到首页 | |
| if (requiredRole && user?.role !== requiredRole) { | |
| return <Navigate to="/" replace /> | |
| } | |
| return <>{children}</> | |
| } | |