修改注册登录界面,新增路由保护

Change-Id: I6c665d9e92813506158113fe97c1119d7ad09d92
diff --git a/front/src/AnimePage.js b/front/src/AnimePage.js
index 118d8fb..3cf5ac9 100644
--- a/front/src/AnimePage.js
+++ b/front/src/AnimePage.js
@@ -10,6 +10,7 @@
 import "./App.css";

 import { useNavigate } from "react-router-dom";

 import { API_BASE_URL } from "./config";

+import ForumIcon from "@mui/icons-material/Forum";

 

 const navItems = [

   { label: "电影", icon: <MovieIcon />, path: "/movie" },

@@ -19,6 +20,7 @@
   { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },

   { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },

   { label: "资料", icon: <PersonIcon />, path: "/info" },

+  { label: "论坛", icon: <ForumIcon />, path: "/forum" },

   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];

 

diff --git a/front/src/App.js b/front/src/App.js
index 52f3a83..2f85943 100644
--- a/front/src/App.js
+++ b/front/src/App.js
@@ -24,7 +24,7 @@
 import PostDetailPage from "./PostDetailPage";
 import LoginPage from './LoginPage';
 import RegisterPage from './RegisterPage';
-
+import RequireAuth from './RequireAuth';
 
 const navItems = [
   { label: "电影", icon: <MovieIcon />, path: "/movie" },
@@ -150,18 +150,21 @@
         <Route path="/login" element={<LoginPage />} />
         <Route path="/register" element={<RegisterPage />} />
         <Route path="/" element={<Navigate to="/login" replace />} />
-        <Route path="/movie" element={<MoviePage />} />
-        <Route path="/tv" element={<TVPage />} />
-        <Route path="/music" element={<MusicPage />} />
-        <Route path="/anime" element={<AnimePage />} />
-        <Route path="/game" element={<GamePage />} />
-        <Route path="/sport" element={<SportPage />} />
-        <Route path="/forum" element={<ForumPage />} />
-        <Route path="/forum/:postId" element={<PostDetailPage />} />
-        <Route path="/info" element={<InfoPage />} />
-        <Route path="/user" element={<UserProfile />} />
-        <Route path="/publish" element={<PublishPage />} />
-        <Route path="/torrent/:torrentId" element={<TorrentDetailPage />} />
+        {/* Protected routes */}
+        <Route element={<RequireAuth />}>
+          <Route path="/movie" element={<MoviePage />} />
+          <Route path="/tv" element={<TVPage />} />
+          <Route path="/music" element={<MusicPage />} />
+          <Route path="/anime" element={<AnimePage />} />
+          <Route path="/game" element={<GamePage />} />
+          <Route path="/sport" element={<SportPage />} />
+          <Route path="/forum" element={<ForumPage />} />
+          <Route path="/forum/:postId" element={<PostDetailPage />} />
+          <Route path="/info" element={<InfoPage />} />
+          <Route path="/user" element={<UserProfile />} />
+          <Route path="/publish" element={<PublishPage />} />
+          <Route path="/torrent/:torrentId" element={<TorrentDetailPage />} />
+        </Route>
       </Routes>
     </Router>
   );
diff --git a/front/src/ForumPage.js b/front/src/ForumPage.js
index ed94e0f..abcba7d 100644
--- a/front/src/ForumPage.js
+++ b/front/src/ForumPage.js
@@ -1,5 +1,6 @@
-import React from "react";
+import React, { useState, useEffect } from "react";
 import { useNavigate } from "react-router-dom";
+import { API_BASE_URL } from "./config";
 
 // 示例数据
 const posts = [
@@ -27,6 +28,20 @@
 
 export default function ForumPage() {
     const navigate = useNavigate();
+    const [posts, setPosts] = useState([]);
+
+    useEffect(() => {
+        // get userId from cookie
+        const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
+        const userId = match ? match[2] : null;
+        console.log("User ID from cookie:", userId);
+        if (!userId) return;
+        fetch(`${API_BASE_URL}/api/forum`)
+            .then(res => res.json())
+            .then(data => setPosts(data))
+            .catch(() => setPosts([]));
+    }, []);
+
     return (
         <div style={{ maxWidth: 700, margin: "40px auto" }}>
             <div style={{ display: "flex", alignItems: "center", marginBottom: 24 }}>
diff --git a/front/src/GamePage.js b/front/src/GamePage.js
index 1de4d30..c1ce231 100644
--- a/front/src/GamePage.js
+++ b/front/src/GamePage.js
@@ -10,6 +10,7 @@
 import "./App.css";

 import { useNavigate } from "react-router-dom";

 import { API_BASE_URL } from "./config";

+import ForumIcon from "@mui/icons-material/Forum";

 

 const navItems = [

   { label: "电影", icon: <MovieIcon />, path: "/movie" },

@@ -19,6 +20,7 @@
   { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },

   { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },

   { label: "资料", icon: <PersonIcon />, path: "/info" },

+  { label: "论坛", icon: <ForumIcon />, path: "/forum" },

   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];

 

diff --git a/front/src/InfoPage.js b/front/src/InfoPage.js
index 0ed6ade..90dc449 100644
--- a/front/src/InfoPage.js
+++ b/front/src/InfoPage.js
@@ -10,6 +10,7 @@
 import "./App.css";

 import { useNavigate } from "react-router-dom";

 import { API_BASE_URL } from "./config";

+import ForumIcon from "@mui/icons-material/Forum";

 

 const navItems = [

   { label: "电影", icon: <MovieIcon />, path: "/movie" },

@@ -19,6 +20,7 @@
   { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },

   { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },

   { label: "资料", icon: <PersonIcon />, path: "/info" },

+  { label: "论坛", icon: <ForumIcon />, path: "/forum" },

   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];

 

diff --git a/front/src/LoginPage.js b/front/src/LoginPage.js
index acbde03..5bb3603 100644
--- a/front/src/LoginPage.js
+++ b/front/src/LoginPage.js
@@ -2,6 +2,7 @@
 import { useNavigate } from 'react-router-dom';

 import { Input } from 'antd';

 import './App.css';

+import { API_BASE_URL } from './config';

 

 const LoginPage = () => {

   const [formData, setFormData] = useState({ username: '', password: '' });

@@ -13,15 +14,38 @@
     setFormData({ ...formData, [name]: value });

   };

 

-  const handleLogin = () => {

+  const handleLogin = async () => {

     if (formData.password.length < 8) {

       setErrorMessage('密码必须至少包含八位字符!');

       return;

     }

 

-    // Simulate successful login

-    setErrorMessage('');

-    navigate('/movie');

+    // send login request to backend

+    try {

+      // console.log('登录信息:', formData);

+      const response = await fetch(`${API_BASE_URL}/api/login`, {

+        method: 'POST',

+        headers: { 'Content-Type': 'application/json' },

+        body: JSON.stringify({ email: formData.username, password: formData.password })

+      });

+      console.log(response);

+      const data = await response.json();

+      if (!response.ok) {

+        setErrorMessage(data.message || '登录失败,请检查账号密码');

+        return;

+      }

+      // store returned userId in cookie

+      const userId = data.userId || data.userid || data.id;

+      if (!userId) {

+        setErrorMessage('登录失败,未返回用户ID');

+        return;

+      }

+      document.cookie = `userId=${userId}; path=/`;

+      setErrorMessage('');

+      navigate('/movie');

+    } catch (error) {

+      setErrorMessage('网络错误,请稍后重试');

+    }

   };

 

   const handleRegister = () => {

@@ -46,9 +70,9 @@
         <h1 style={{ textAlign: 'center', marginBottom: 32, color: '#222', fontWeight: 700, fontSize: 32, letterSpacing: 2 }}>欢迎登录</h1>

         <form className="login-form">

           <div className="form-row" style={{ marginBottom: 24 }}>

-            <label htmlFor="username" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>用户名</label>

+            <label htmlFor="username" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>邮箱</label>

             <Input

-              placeholder="请输入用户名"

+              placeholder="请输入邮箱"

               id="username"

               name="username"

               value={formData.username}

diff --git a/front/src/MoviePage.js b/front/src/MoviePage.js
index 83ccad1..faef3bd 100644
--- a/front/src/MoviePage.js
+++ b/front/src/MoviePage.js
@@ -7,6 +7,7 @@
 import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";

 import PersonIcon from "@mui/icons-material/Person";

 import AccountCircleIcon from "@mui/icons-material/AccountCircle";

+import ForumIcon from "@mui/icons-material/Forum";

 import { useNavigate } from "react-router-dom";

 import "./App.css";

 import { API_BASE_URL } from "./config";

@@ -19,6 +20,7 @@
   { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },

   { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },

   { label: "资料", icon: <PersonIcon />, path: "/info" },

+  { label: "论坛", icon: <ForumIcon />, path: "/forum" },

   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];

 

diff --git a/front/src/MusicPage.js b/front/src/MusicPage.js
index fb03fe1..d244629 100644
--- a/front/src/MusicPage.js
+++ b/front/src/MusicPage.js
@@ -10,6 +10,7 @@
 import "./App.css";

 import { useNavigate } from "react-router-dom";

 import { API_BASE_URL } from "./config";

+import ForumIcon from "@mui/icons-material/Forum";

 

 const navItems = [

   { label: "电影", icon: <MovieIcon />, path: "/movie" },

@@ -19,6 +20,7 @@
   { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },

   { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },

   { label: "资料", icon: <PersonIcon />, path: "/info" },

+  { label: "论坛", icon: <ForumIcon />, path: "/forum" },

   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];

 

diff --git a/front/src/RegisterPage.js b/front/src/RegisterPage.js
index ffd11a4..a527850 100644
--- a/front/src/RegisterPage.js
+++ b/front/src/RegisterPage.js
@@ -1,6 +1,7 @@
 import React, { useState } from 'react';

 import { useNavigate } from 'react-router-dom';

 import { Input } from 'antd';

+import { API_BASE_URL } from './config';

 import './App.css';

 

 const RegisterPage = () => {

@@ -13,7 +14,7 @@
     setFormData({ ...formData, [name]: value });

   };

 

-  const handleRegister = () => {

+  const handleRegister = async () => {

     if (formData.password.length !== 8) {

       setErrorMessage('密码必须为八位字符!');

       return;

@@ -24,12 +25,25 @@
       return;

     }

 

-    // Simulate successful registration

-    setErrorMessage('');

-    // 存储注册信息到 sessionStorage

-    sessionStorage.setItem('registeredUser', JSON.stringify({ username: formData.username, password: formData.password }));

-    alert('注册成功!');

-    navigate('/login');

+    // send registration request to backend

+    try {

+      console.log('注册信息:', formData);

+      const response = await fetch(`${API_BASE_URL}/api/register`, {

+        method: 'POST',

+        headers: { 'Content-Type': 'application/json' },

+        body: JSON.stringify({ username: formData.username, password: formData.password, invite_email: formData.inviteCode })

+      });

+      const data = await response.json();

+      if (!response.ok) {

+        setErrorMessage(data.message || '注册失败,请重试');

+        return;

+      }

+      setErrorMessage('');

+      navigate('/login');

+      alert('注册成功!');

+    } catch (error) {

+      setErrorMessage('网络错误,请稍后重试');

+    }

   };

 

   return (

diff --git a/front/src/RequireAuth.js b/front/src/RequireAuth.js
new file mode 100644
index 0000000..77cde56
--- /dev/null
+++ b/front/src/RequireAuth.js
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Navigate, Outlet } from 'react-router-dom';
+
+// Component to protect routes that require authentication
+const RequireAuth = () => {
+  // Check if userId cookie exists
+  const getCookie = (name) => {
+    const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
+    return match ? match[2] : null;
+  };
+
+  const userId = getCookie('userId');
+  // If not authenticated, redirect to login
+  return userId ? <Outlet /> : <Navigate to="/login" replace />;
+};
+
+export default RequireAuth;
diff --git a/front/src/SportPage.js b/front/src/SportPage.js
index 4c9d17d..a221c09 100644
--- a/front/src/SportPage.js
+++ b/front/src/SportPage.js
@@ -10,6 +10,7 @@
 import "./App.css";

 import { useNavigate } from "react-router-dom";

 import { API_BASE_URL } from "./config";

+import ForumIcon from "@mui/icons-material/Forum";

 

 const navItems = [

   { label: "电影", icon: <MovieIcon />, path: "/movie" },

@@ -19,6 +20,7 @@
   { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },

   { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },

   { label: "资料", icon: <PersonIcon />, path: "/info" },

+  { label: "论坛", icon: <ForumIcon />, path: "/forum" },

   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];

 

diff --git a/front/src/TVPage.js b/front/src/TVPage.js
index 216dfcc..1bc9a07 100644
--- a/front/src/TVPage.js
+++ b/front/src/TVPage.js
@@ -10,6 +10,7 @@
 import { useNavigate } from "react-router-dom";

 import "./App.css";

 import { API_BASE_URL } from "./config";

+import ForumIcon from "@mui/icons-material/Forum";

 

 const navItems = [

   { label: "电影", icon: <MovieIcon />, path: "/movie" },

@@ -19,6 +20,7 @@
   { label: "游戏", icon: <SportsEsportsIcon />, path: "/game" },

   { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },

   { label: "资料", icon: <PersonIcon />, path: "/info" },

+  { label: "论坛", icon: <ForumIcon />, path: "/forum" },

   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option

 ];