From 3f96c9c6502243b06efd4bb34a189e72e3a5557c Mon Sep 17 00:00:00 2001
From: yearning <10538594+wangweifeng1999@user.noreply.gitee.com>
Date: 星期一, 28 九月 2026 19:24:55 +0800
Subject: [PATCH] 复制项目
---
frontend/src/App.tsx | 69 ++++++++++++++++++++++++++++++++++
1 files changed, 69 insertions(+), 0 deletions(-)
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
new file mode 100644
index 0000000..db4ab1e
--- /dev/null
+++ b/frontend/src/App.tsx
@@ -0,0 +1,69 @@
+import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
+import { useEffect, useState } from "react";
+import { Spin } from "antd";
+import { api, getToken } from "./api";
+import LoginPage from "./pages/LoginPage";
+import MainLayout from "./layout/MainLayout";
+import ScoreQueryPage from "./pages/ScoreQueryPage";
+import AttemptReviewPage from "./pages/AttemptReviewPage";
+import AdminImportPage from "./pages/AdminImportPage";
+import AdminGradersPage from "./pages/AdminGradersPage";
+import AdminSystemSettingsPage from "./pages/AdminSystemSettingsPage";
+import AdminRoute from "./AdminRoute";
+
+export type UserMe = { id: number; username: string; display_name: string; role: string };
+
+function App() {
+ const [user, setUser] = useState<UserMe | null>(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ if (!getToken()) {
+ setLoading(false);
+ return;
+ }
+ api
+ .get<UserMe>("/api/auth/me")
+ .then((r) => setUser(r.data))
+ .catch(() => setUser(null))
+ .finally(() => setLoading(false));
+ }, []);
+
+ if (loading) {
+ return (
+ <div style={{ display: "flex", height: "100vh", alignItems: "center", justifyContent: "center" }}>
+ <Spin size="large" />
+ </div>
+ );
+ }
+
+ return (
+ <BrowserRouter>
+ <Routes>
+ <Route path="/login" element={<LoginPage onLogin={setUser} />} />
+ <Route
+ path="/"
+ element={user ? <MainLayout user={user} onLogout={() => setUser(null)} /> : <Navigate to="/login" />}
+ >
+ <Route index element={<Navigate to="/scores" replace />} />
+ <Route path="scores" element={<ScoreQueryPage />} />
+ <Route path="attempts/:attemptId" element={<AttemptReviewPage />} />
+ <Route
+ path="admin/import"
+ element={<AdminRoute user={user}><AdminImportPage /></AdminRoute>}
+ />
+ <Route
+ path="admin/graders"
+ element={<AdminRoute user={user}><AdminGradersPage /></AdminRoute>}
+ />
+ <Route
+ path="admin/settings"
+ element={<AdminRoute user={user}><AdminSystemSettingsPage /></AdminRoute>}
+ />
+ </Route>
+ </Routes>
+ </BrowserRouter>
+ );
+}
+
+export default App;
--
Gitblit v1.8.0