127 lines
5.3 KiB
React
127 lines
5.3 KiB
React
import React, { lazy, Suspense, useEffect, useState } from 'react';
|
||
import { createRoot } from 'react-dom/client';
|
||
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
||
import { ThemeProvider } from '@mui/material/styles';
|
||
import CssBaseline from '@mui/material/CssBaseline';
|
||
import Box from '@mui/material/Box';
|
||
import CircularProgress from '@mui/material/CircularProgress';
|
||
import { createMD3Theme } from './theme.js';
|
||
import './theme.css';
|
||
import { getToken } from '../api/client.js';
|
||
import { me } from '../api/auth.js';
|
||
import { getSettings } from '../api/settings.js';
|
||
import AdminLayout from './AdminLayout.jsx';
|
||
import Dashboard from './pages/Dashboard.jsx';
|
||
import Settings from './pages/Settings.jsx';
|
||
import CaptchaSettings from './pages/CaptchaSettings.jsx';
|
||
import ThemeSettings from './pages/ThemeSettings.jsx';
|
||
import Homepage from './pages/Homepage.jsx';
|
||
import EmailSettings from './pages/EmailSettings.jsx';
|
||
import BlogManage from './pages/BlogManage.jsx';
|
||
import CommentManage from './pages/CommentManage.jsx';
|
||
import ForumManage from './pages/ForumManage.jsx';
|
||
import PostManage from './pages/PostManage.jsx';
|
||
import RssManage from './pages/RssManage.jsx';
|
||
import Users from './pages/Users.jsx';
|
||
import Announcements from './pages/Announcements.jsx';
|
||
import Links from './pages/Links.jsx';
|
||
import Uploads from './pages/Uploads.jsx';
|
||
import ImportDb from './pages/ImportDb.jsx';
|
||
import TicketManage from './pages/TicketManage.jsx';
|
||
// 工作台独立分包:仅访问 /admin/workbench 时才加载(vite 自动 code-split)
|
||
const Workbench = lazy(() => import('../tools/workbench/Workbench.jsx'));
|
||
|
||
// 生产:/admin/* 由后端 fallback 到 dist/admin.html(Phase 6 需求),basename=/admin;
|
||
// 开发:vite 多入口直接访问 /admin.html,basename 自适应为空。
|
||
const pathname = window.location.pathname;
|
||
const basename = (pathname === '/admin' || pathname.startsWith('/admin/')) ? '/admin' : '';
|
||
|
||
function AdminApp() {
|
||
const [status, setStatus] = useState('checking'); // checking | ok
|
||
const [primary, setPrimary] = useState('#6750a4');
|
||
|
||
// 深色模式跟随前台偏好:整页跳转后 data-theme 属性不保留,
|
||
// 以 localStorage 的 theme 为兜底(前台 theme.jsx 持久化同一 key)。
|
||
const dark = document.documentElement.getAttribute('data-theme') === 'dark'
|
||
|| localStorage.getItem('theme') === 'dark';
|
||
useEffect(() => {
|
||
if (dark) document.documentElement.setAttribute('data-theme', 'dark');
|
||
}, [dark]);
|
||
|
||
useEffect(() => {
|
||
const token = getToken();
|
||
if (!token) { window.location.href = '/login.html'; return; }
|
||
me()
|
||
.then((u) => {
|
||
if (u.role !== 'admin') {
|
||
window.alert('需要管理员权限');
|
||
window.location.href = '/';
|
||
return;
|
||
}
|
||
setStatus('ok');
|
||
})
|
||
.catch(() => { window.location.href = '/login.html'; });
|
||
getSettings()
|
||
.then((s) => { if (s.primary_color) setPrimary(s.primary_color); })
|
||
.catch(() => {});
|
||
}, []);
|
||
|
||
if (status !== 'ok') {
|
||
return (
|
||
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
|
||
<CircularProgress />
|
||
</Box>
|
||
);
|
||
}
|
||
|
||
const theme = createMD3Theme({ mode: dark ? 'dark' : 'light', primary });
|
||
|
||
return (
|
||
<ThemeProvider theme={theme}>
|
||
<CssBaseline />
|
||
<BrowserRouter basename={basename}>
|
||
<Routes>
|
||
{/* 工作台:独立全屏布局,不套 AdminLayout(自带 Toolbar+Sidebar+内容区);懒加载分包 */}
|
||
<Route
|
||
path="/workbench"
|
||
element={
|
||
<Suspense
|
||
fallback={
|
||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh' }}>
|
||
<CircularProgress />
|
||
</Box>
|
||
}
|
||
>
|
||
<Workbench />
|
||
</Suspense>
|
||
}
|
||
/>
|
||
<Route element={<AdminLayout />}>
|
||
<Route index element={<Navigate to="/dashboard" replace />} />
|
||
<Route path="/dashboard" element={<Dashboard />} />
|
||
<Route path="/settings" element={<Settings />} />
|
||
<Route path="/captcha" element={<CaptchaSettings />} />
|
||
<Route path="/theme" element={<ThemeSettings />} />
|
||
<Route path="/homepage" element={<Homepage />} />
|
||
<Route path="/email" element={<EmailSettings />} />
|
||
<Route path="/blog" element={<BlogManage />} />
|
||
<Route path="/comments" element={<CommentManage />} />
|
||
<Route path="/forum" element={<ForumManage />} />
|
||
<Route path="/posts" element={<PostManage />} />
|
||
<Route path="/rss" element={<RssManage />} />
|
||
<Route path="/users" element={<Users />} />
|
||
<Route path="/announcements" element={<Announcements />} />
|
||
<Route path="/links" element={<Links />} />
|
||
<Route path="/uploads" element={<Uploads />} />
|
||
<Route path="/import" element={<ImportDb />} />
|
||
<Route path="/tickets" element={<TicketManage />} />
|
||
<Route path="*" element={<Navigate to="/dashboard" replace />} />
|
||
</Route>
|
||
</Routes>
|
||
</BrowserRouter>
|
||
</ThemeProvider>
|
||
);
|
||
}
|
||
|
||
createRoot(document.getElementById('root')).render(<AdminApp />);
|