Initial commit
This commit is contained in:
214
src/router/index.tsx
Normal file
214
src/router/index.tsx
Normal file
@@ -0,0 +1,214 @@
|
||||
import { createBrowserRouter, Navigate, useLocation } from 'react-router-dom'
|
||||
import { Suspense, lazy } from 'react'
|
||||
import { useAuthStore, ROLES } from '@/stores/authStore'
|
||||
|
||||
// 路由守卫组件
|
||||
export function AuthGuard({ children }: { children: React.ReactNode }) {
|
||||
const { isAuthenticated, isLoading } = useAuthStore()
|
||||
const location = useLocation()
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex h-screen items-center justify-center">
|
||||
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return <Navigate to="/login" state={{ from: location }} replace />
|
||||
}
|
||||
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
export function RoleGuard({
|
||||
children,
|
||||
roles
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
roles: string[]
|
||||
}) {
|
||||
const { hasAnyRole, isAuthenticated, isLoading } = useAuthStore()
|
||||
const location = useLocation()
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex h-screen items-center justify-center">
|
||||
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return <Navigate to="/login" state={{ from: location }} replace />
|
||||
}
|
||||
|
||||
if (!hasAnyRole(roles)) {
|
||||
return <Navigate to="/403" replace />
|
||||
}
|
||||
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
export function AdminGuard({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<RoleGuard roles={[ROLES.SUPER_ADMIN, ROLES.ADMIN]}>
|
||||
{children}
|
||||
</RoleGuard>
|
||||
)
|
||||
}
|
||||
|
||||
export function ModeratorGuard({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<RoleGuard roles={[ROLES.SUPER_ADMIN, ROLES.ADMIN, ROLES.MODERATOR]}>
|
||||
{children}
|
||||
</RoleGuard>
|
||||
)
|
||||
}
|
||||
|
||||
// 公开路由守卫(已登录用户重定向到dashboard)
|
||||
export function PublicGuard({ children }: { children: React.ReactNode }) {
|
||||
const { isAuthenticated, isLoading } = useAuthStore()
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex h-screen items-center justify-center">
|
||||
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (isAuthenticated) {
|
||||
return <Navigate to="/dashboard" replace />
|
||||
}
|
||||
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
// 加载指示器组件
|
||||
function PageLoader() {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center p-8">
|
||||
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// 懒加载页面组件
|
||||
const Login = lazy(() => import('@/pages/Login'))
|
||||
const Dashboard = lazy(() => import('@/pages/Dashboard'))
|
||||
const Users = lazy(() => import('@/pages/Users'))
|
||||
const Roles = lazy(() => import('@/pages/Roles'))
|
||||
const Posts = lazy(() => import('@/pages/Posts'))
|
||||
const Comments = lazy(() => import('@/pages/Comments'))
|
||||
const Groups = lazy(() => import('@/pages/Groups'))
|
||||
const Forbidden = lazy(() => import('@/pages/Forbidden'))
|
||||
const NotFound = lazy(() => import('@/pages/NotFound'))
|
||||
|
||||
// 布局组件
|
||||
import MainLayout from '@/components/Layout/MainLayout'
|
||||
|
||||
// 创建路由
|
||||
export const router = createBrowserRouter([
|
||||
{
|
||||
path: '/login',
|
||||
element: (
|
||||
<PublicGuard>
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Login />
|
||||
</Suspense>
|
||||
</PublicGuard>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
element: (
|
||||
<AuthGuard>
|
||||
<MainLayout />
|
||||
</AuthGuard>
|
||||
),
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
element: <Navigate to="/dashboard" replace />,
|
||||
},
|
||||
{
|
||||
path: 'dashboard',
|
||||
element: (
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Dashboard />
|
||||
</Suspense>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'users',
|
||||
element: (
|
||||
<AdminGuard>
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Users />
|
||||
</Suspense>
|
||||
</AdminGuard>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'roles',
|
||||
element: (
|
||||
<AdminGuard>
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Roles />
|
||||
</Suspense>
|
||||
</AdminGuard>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'posts',
|
||||
element: (
|
||||
<ModeratorGuard>
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Posts />
|
||||
</Suspense>
|
||||
</ModeratorGuard>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'comments',
|
||||
element: (
|
||||
<ModeratorGuard>
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Comments />
|
||||
</Suspense>
|
||||
</ModeratorGuard>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'groups',
|
||||
element: (
|
||||
<ModeratorGuard>
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Groups />
|
||||
</Suspense>
|
||||
</ModeratorGuard>
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/403',
|
||||
element: (
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<Forbidden />
|
||||
</Suspense>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
element: (
|
||||
<Suspense fallback={<PageLoader />}>
|
||||
<NotFound />
|
||||
</Suspense>
|
||||
),
|
||||
},
|
||||
])
|
||||
|
||||
export default router
|
||||
Reference in New Issue
Block a user