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