Files
XQKqueue/web/src/App.tsx
brother7 d782227a23 开放多项目大屏免登录访问
需求描述:/admin/display 需要无需管理员登录即可直接查看多项目公开运行状态。

实现思路:新增公开字段白名单接口与独立大屏页面,移除该路由的管理员会话依赖,同时保留 /api/admin/overview 的鉴权并补充隐私、路由和页面回归测试。

验证:Go 全量测试通过;前端 18 个测试文件共 59 项通过,TypeScript 检查通过。
2026-07-31 16:36:03 +08:00

60 lines
3.9 KiB
TypeScript

import type { ReactNode } from "react";
import { BrowserRouter, Navigate, Route, Routes, useLocation } from "react-router-dom";
import { AuthProvider, useAuth } from "./auth/AuthContext";
import { LoadingState } from "./components/Feedback";
import { AdminPage } from "./pages/AdminPage";
import { DisplayPage } from "./pages/DisplayPage";
import { PublicDisplayCenterPage } from "./pages/PublicDisplayCenterPage";
import { LoginPage } from "./pages/LoginPage";
import { HistoryPage } from "./pages/HistoryPage";
import { StaffPage } from "./pages/StaffPage";
import { VisitorPage } from "./pages/VisitorPage";
import { VisitorLookupPage } from "./pages/VisitorLookupPage";
import { VisitorPhonePage } from "./pages/VisitorPhonePage";
function RequireStaff({ children }: { children: ReactNode }) {
const { user, loading } = useAuth();
const location = useLocation();
if (loading) return <main className="route-loading"><LoadingState label="正在确认访问权限" /></main>;
if (!user) return <Navigate to="/staff/login" replace state={{ from: `${location.pathname}${location.search}` }} />;
return children;
}
function RequireAdmin({ children }: { children: ReactNode }) {
const { user, loading } = useAuth();
if (loading) return <main className="route-loading"><LoadingState label="正在确认管理权限" /></main>;
if (!user) return <Navigate to="/admin/login" replace />;
return children;
}
export function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Navigate to="/staff" replace />} />
<Route path="/login" element={<Navigate to="/staff/login" replace />} />
<Route path="/staff/login" element={<AuthProvider portal="staff"><LoginPage portal="staff" /></AuthProvider>} />
<Route path="/staff" element={<AuthProvider portal="staff"><RequireStaff><StaffPage /></RequireStaff></AuthProvider>} />
<Route path="/staff/tickets" element={<AuthProvider portal="staff"><RequireStaff><StaffPage /></RequireStaff></AuthProvider>} />
<Route path="/staff/me" element={<AuthProvider portal="staff"><RequireStaff><StaffPage /></RequireStaff></AuthProvider>} />
<Route path="/staff/verify" element={<Navigate to="/staff" replace />} />
<Route path="/visitor" element={<VisitorLookupPage />} />
<Route path="/visitor/phone" element={<VisitorPhonePage />} />
<Route path="/visitor/:token" element={<VisitorPage />} />
<Route path="/display/:token" element={<DisplayPage />} />
<Route path="/admin/login" element={<AuthProvider portal="admin"><LoginPage portal="admin" /></AuthProvider>} />
<Route path="/admin" element={<AuthProvider portal="admin"><RequireAdmin><AdminPage /></RequireAdmin></AuthProvider>} />
<Route path="/admin/history" element={<AuthProvider portal="admin"><RequireAdmin><HistoryPage /></RequireAdmin></AuthProvider>} />
<Route path="/admin/projects" element={<AuthProvider portal="admin"><RequireAdmin><AdminPage /></RequireAdmin></AuthProvider>} />
<Route path="/admin/projects/new" element={<AuthProvider portal="admin"><RequireAdmin><AdminPage /></RequireAdmin></AuthProvider>} />
<Route path="/admin/projects/:projectId" element={<AuthProvider portal="admin"><RequireAdmin><AdminPage /></RequireAdmin></AuthProvider>} />
<Route path="/admin/accounts" element={<AuthProvider portal="admin"><RequireAdmin><AdminPage /></RequireAdmin></AuthProvider>} />
<Route path="/admin/accounts/new" element={<AuthProvider portal="admin"><RequireAdmin><AdminPage /></RequireAdmin></AuthProvider>} />
<Route path="/admin/accounts/:accountId" element={<AuthProvider portal="admin"><RequireAdmin><AdminPage /></RequireAdmin></AuthProvider>} />
<Route path="/admin/display" element={<PublicDisplayCenterPage />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</BrowserRouter>
);
}