229 lines
6.4 KiB
TypeScript
229 lines
6.4 KiB
TypeScript
import { createBrowserRouter, Navigate, useLocation, Outlet } from 'react-router-dom';
|
|
import { lazy, Suspense } from 'react';
|
|
import LoadingSpinner from './components/LoadingSpinner';
|
|
|
|
// 懒加载组件
|
|
const Home = lazy(() => import('./pages/Home'));
|
|
const Daily = lazy(() => import('./pages/Daily'));
|
|
const Article = lazy(() => import('./pages/Article'));
|
|
const AdminLayout = lazy(() => import('./pages/admin/layout/AdminLayout'));
|
|
const Login = lazy(() => import('./pages/admin/login'));
|
|
const Header = lazy(() => import('./components/layout/Header'));
|
|
const Footer = lazy(() => import('./components/Footer'));
|
|
|
|
// 管理页面组件
|
|
const Dashboard = lazy(() => import('./pages/admin/dashboard/Dashboard'));
|
|
const PostsManagement = lazy(() => import('./pages/admin/posts/PostsManagement'));
|
|
const PostEditor = lazy(() => import('./pages/admin/posts/PostEditor'));
|
|
const DailyManagement = lazy(() => import('./pages/admin/daily/DailyManagement'));
|
|
const MediasManagement = lazy(() => import('./pages/admin/medias/MediasManagement'));
|
|
const CategoriesManagement = lazy(() => import('./pages/admin/categories/CategoriesManagement'));
|
|
const UsersManagement = lazy(() => import('./pages/admin/users/UsersManagement'));
|
|
const ContributorsManagement = lazy(() => import('./pages/admin/contributors/ContributorsManagement'));
|
|
const Settings = lazy(() => import('./pages/admin/settings/Settings'));
|
|
|
|
// 检查是否已登录
|
|
const checkAuth = () => {
|
|
const token = localStorage.getItem('token');
|
|
console.debug('[Auth] Token exists:', !!token);
|
|
return !!token;
|
|
};
|
|
|
|
// 受保护的路由组件
|
|
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
|
|
const location = useLocation();
|
|
const isAuthenticated = checkAuth();
|
|
|
|
console.debug('[Router] Current location:', location.pathname);
|
|
console.debug('[Router] Is authenticated:', isAuthenticated);
|
|
|
|
if (!isAuthenticated) {
|
|
console.debug('[Router] Redirecting to login');
|
|
return <Navigate to="/admin/login" replace />;
|
|
}
|
|
|
|
return <>{children}</>;
|
|
};
|
|
|
|
// 登录路由组件
|
|
const LoginRoute = () => {
|
|
const isAuthenticated = checkAuth();
|
|
|
|
console.debug('[Login] Checking auth status');
|
|
|
|
if (isAuthenticated) {
|
|
console.debug('[Login] Already authenticated, redirecting to admin');
|
|
return <Navigate to="/admin" replace />;
|
|
}
|
|
|
|
return (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<Login />
|
|
</Suspense>
|
|
);
|
|
};
|
|
|
|
// 页面布局组件
|
|
const PageLayout = () => (
|
|
<div className="flex flex-col min-h-screen bg-white dark:bg-neutral-900 text-gray-900 dark:text-gray-100">
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<Header />
|
|
<div className="w-[95%] mx-auto">
|
|
<div className="border-t-2 border-gray-900 dark:border-gray-100 w-full mb-2" />
|
|
</div>
|
|
<main className="flex-1 w-[95%] mx-auto py-8">
|
|
<Outlet />
|
|
</main>
|
|
<Footer />
|
|
</Suspense>
|
|
</div>
|
|
);
|
|
|
|
const router = createBrowserRouter([
|
|
{
|
|
path: '/',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<PageLayout />
|
|
</Suspense>
|
|
),
|
|
children: [
|
|
{
|
|
index: true,
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<Home />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'daily',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<Daily />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'posts/:articleId',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<Article />
|
|
</Suspense>
|
|
),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
path: '/admin',
|
|
children: [
|
|
{
|
|
path: 'login',
|
|
element: <LoginRoute />,
|
|
},
|
|
{
|
|
path: '',
|
|
element: (
|
|
<ProtectedRoute>
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<AdminLayout />
|
|
</Suspense>
|
|
</ProtectedRoute>
|
|
),
|
|
children: [
|
|
{
|
|
index: true,
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<Dashboard />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'posts',
|
|
children: [
|
|
{
|
|
index: true,
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<PostsManagement />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'new',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<PostEditor />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: ':postId',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<PostEditor />
|
|
</Suspense>
|
|
),
|
|
},
|
|
],
|
|
},
|
|
{
|
|
path: 'daily',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<DailyManagement />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'medias',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<MediasManagement />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'categories',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<CategoriesManagement />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'users',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<UsersManagement />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'contributors',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<ContributorsManagement />
|
|
</Suspense>
|
|
),
|
|
},
|
|
{
|
|
path: 'settings',
|
|
element: (
|
|
<Suspense fallback={<LoadingSpinner fullScreen />}>
|
|
<Settings />
|
|
</Suspense>
|
|
),
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
path: '*',
|
|
element: <Navigate to="/" />,
|
|
},
|
|
]);
|
|
|
|
export default router;
|