init: initial commit
This commit is contained in:
+85
@@ -0,0 +1,85 @@
|
||||
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
import AdminLayout from '@/layouts/AdminLayout'
|
||||
import LoginPage from '@/pages/LoginPage'
|
||||
import ErrorBoundary from '@/components/ErrorBoundary'
|
||||
import { Suspense, useMemo, lazy, useEffect } from 'react'
|
||||
import { Loader2 } from 'lucide-react'
|
||||
import type { SystemMenu } from '@/api/system'
|
||||
|
||||
const pages = import.meta.glob('./pages/**/*.tsx')
|
||||
|
||||
const dynamicComponentMap: Record<string, React.LazyExoticComponent<any>> = {}
|
||||
for (const path in pages) {
|
||||
let routePath = path.replace(/^\.\/pages/, '').replace(/\.tsx$/, '').replace(/\/index$/, '').toLowerCase()
|
||||
if (routePath === '/loginpage') continue
|
||||
dynamicComponentMap[routePath] = lazy(pages[path] as any)
|
||||
}
|
||||
|
||||
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||
const isAuthenticated = useAuthStore(s => s.isAuthenticated)
|
||||
if (!isAuthenticated) return <Navigate to="/login" replace />
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
function PublicRoute({ children }: { children: React.ReactNode }) {
|
||||
const isAuthenticated = useAuthStore(s => s.isAuthenticated)
|
||||
if (isAuthenticated) return <Navigate to="/dashboard" replace />
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
function AppRoutes() {
|
||||
const menus = useAuthStore(s => s.menus)
|
||||
const isAuthenticated = useAuthStore(s => s.isAuthenticated)
|
||||
const refreshMenus = useAuthStore(s => s.refreshMenus)
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated && menus.length === 0) refreshMenus()
|
||||
}, [isAuthenticated, menus.length, refreshMenus])
|
||||
|
||||
const dynamicRoutes = useMemo(() => {
|
||||
const routes: { path: string; Component: React.ComponentType }[] = []
|
||||
const traverse = (items: SystemMenu[]) => {
|
||||
items.forEach(item => {
|
||||
if (item.children?.length) traverse(item.children)
|
||||
const routeKey = item.path || item.code
|
||||
if (routeKey && dynamicComponentMap[routeKey]) {
|
||||
routes.push({ path: routeKey, Component: dynamicComponentMap[routeKey] })
|
||||
}
|
||||
})
|
||||
}
|
||||
if (menus) traverse(menus)
|
||||
return routes
|
||||
}, [menus])
|
||||
|
||||
const Loading = <div className="flex justify-center p-8"><Loader2 className="h-8 w-8 animate-spin text-muted-foreground" /></div>
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/login" element={<PublicRoute><LoginPage /></PublicRoute>} />
|
||||
<Route path="/" element={<ProtectedRoute><AdminLayout /></ProtectedRoute>}>
|
||||
<Route index element={<Navigate to="/dashboard" replace />} />
|
||||
{dynamicRoutes.map(({ path, Component }) => (
|
||||
<Route key={path} path={path.startsWith('/') ? path.substring(1) : path}
|
||||
element={<ErrorBoundary><Suspense fallback={Loading}><Component /></Suspense></ErrorBoundary>} />
|
||||
))}
|
||||
{!dynamicRoutes.some(r => r.path === '/dashboard') && dynamicComponentMap['/dashboard'] && (
|
||||
<Route path="dashboard" element={
|
||||
<ErrorBoundary><Suspense fallback={Loading}>
|
||||
{(() => { const D = dynamicComponentMap['/dashboard']; return <D /> })()}
|
||||
</Suspense></ErrorBoundary>
|
||||
} />
|
||||
)}
|
||||
</Route>
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
)
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<AppRoutes />
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user