新增求种页面

Change-Id: I8b4fd771aa9ea25ca086998be6103957dc3df1cc
diff --git a/front/src/App.js b/front/src/App.js
index 372fa62..58fb58c 100644
--- a/front/src/App.js
+++ b/front/src/App.js
@@ -9,6 +9,7 @@
 import PersonIcon from "@mui/icons-material/Person";
 import AccountCircleIcon from "@mui/icons-material/AccountCircle";
 import ForumIcon from "@mui/icons-material/Forum";
+import HelpIcon from "@mui/icons-material/Help";
 import "./App.css";
 import MoviePage from "./MoviePage";
 import TVPage from "./TVPage";
@@ -28,6 +29,8 @@
 import AdminPage from './AdminPage';
 import AppealPage from './AppealPage';
 import MigrationPage from './MigrationPage';
+import BegSeedPage from "./BegSeedPage";
+import BegInfo from "./BegInfo";
 
 
 const navItems = [
@@ -40,6 +43,7 @@
   { label: "资料", icon: <PersonIcon />, path: "/info" },
   { label: "论坛", icon: <ForumIcon />, path: "/forum" },
   { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },
+  { label: "求种", icon: <HelpIcon />, path: "/begseed" },
 ];
 
 function Home() {
@@ -171,6 +175,8 @@
           <Route path="/admin" element={<AdminPage />} />
           <Route path="/appeal-review" element={<AppealPage />} />
           <Route path="/migration-review" element={<MigrationPage />} />
+          <Route path="/begseed" element={<BegSeedPage />} />
+          <Route path="/begseed/:begid" element={<BegInfo />} />
         </Route>
       </Routes>
     </Router>
diff --git a/front/src/BegInfo.js b/front/src/BegInfo.js
new file mode 100644
index 0000000..1b3e2af
--- /dev/null
+++ b/front/src/BegInfo.js
@@ -0,0 +1,307 @@
+import React, { useState } from "react";
+import { useParams } from "react-router-dom";
+
+// 求种任务示例数据
+const begSeedList = [
+    {
+        beg_id: "beg001",
+        info: "求《三体》高清资源",
+        beg_count: 5,
+        reward_magic: 100,
+        deadline: "2025-06-10T23:59:59",
+        has_match: 0,
+    },
+    {
+        beg_id: "beg002",
+        info: "求《灌篮高手》国语配音版",
+        beg_count: 3,
+        reward_magic: 50,
+        deadline: "2024-05-01T23:59:59",
+        has_match: 1,
+    },
+    {
+        beg_id: "beg003",
+        info: "求《黑暗之魂3》PC版种子",
+        beg_count: 2,
+        reward_magic: 80,
+        deadline: "2024-04-01T23:59:59",
+        has_match: 0,
+    },
+];
+
+// SubmitSeed表示例数据
+const submitSeedList = [
+    { beg_id: "beg001", seed_id: "seed001", votes: 3 },
+    { beg_id: "beg001", seed_id: "seed002", votes: 1 },
+    { beg_id: "beg002", seed_id: "seed003", votes: 2 },
+];
+
+// 种子信息映射
+const seedInfoMap = {
+    seed001: { title: "三体 1080P 蓝光", subtitle: "高码率无水印" },
+    seed002: { title: "三体 720P", subtitle: "清晰版" },
+    seed003: { title: "灌篮高手 国语配音", subtitle: "全剧集" },
+};
+
+export default function BegInfo() {
+    const { begid } = useParams();
+    const beg = begSeedList.find((b) => b.beg_id === begid);
+    const [seeds, setSeeds] = useState(
+        submitSeedList.filter((s) => s.beg_id === begid)
+    );
+    const [showForm, setShowForm] = useState(false);
+    const [formData, setFormData] = useState({
+        title: "",
+        subtitle: "",
+        torrentFile: null,
+    });
+
+    if (!beg) return <div style={{ padding: 40 }}>未找到该求种信息</div>;
+
+    const isExpired = new Date(beg.deadline) < new Date();
+    const isFinished = beg.has_match === 1;
+    const isActive = !isExpired && !isFinished;
+
+    // 投票功能(前端+1)
+    const handleVote = (seed_id) => {
+        setSeeds((prev) =>
+            prev.map((s) =>
+                s.seed_id === seed_id ? { ...s, votes: s.votes + 1 } : s
+            )
+        );
+    };
+
+    // 上传表单处理
+    const handleFormChange = (e) => {
+        const { name, value, files } = e.target;
+        if (name === "torrentFile") {
+            setFormData((f) => ({ ...f, torrentFile: files[0] }));
+        } else {
+            setFormData((f) => ({ ...f, [name]: value }));
+        }
+    };
+
+    const handleSubmitSeed = (e) => {
+        e.preventDefault();
+        // 这里只做前端演示,实际应上传到后端
+        const newSeedId = "seed" + Math.floor(Math.random() * 10000);
+        setSeeds((prev) => [
+            ...prev,
+            {
+                beg_id: begid,
+                seed_id: newSeedId,
+                votes: 0,
+            },
+        ]);
+        seedInfoMap[newSeedId] = {
+            title: formData.title,
+            subtitle: formData.subtitle,
+        };
+        setShowForm(false);
+        setFormData({ title: "", subtitle: "", torrentFile: null });
+        alert("提交成功(前端演示)");
+    };
+
+    return (
+        <div className="container">
+            <h1 style={{ margin: "24px 0 32px 0", color: "#1976d2" }}>
+                求种详情
+            </h1>
+            <div
+                style={{
+                    background: "#e3f7e7",
+                    border: "1.5px solid #b2d8ea",
+                    borderRadius: 12,
+                    padding: 24,
+                    maxWidth: 600,
+                    margin: "0 auto 32px auto",
+                    boxShadow: "0 2px 8px #e0e7ff",
+                }}
+            >
+                <div style={{ fontWeight: 600, fontSize: 20, marginBottom: 12 }}>
+                    {beg.info}
+                </div>
+                <div>求种人数:{beg.beg_count}</div>
+                <div>悬赏魔力值:{beg.reward_magic}</div>
+                <div>截止时间:{new Date(beg.deadline).toLocaleString()}</div>
+                <div>
+                    状态:
+                    {isFinished
+                        ? "已完成"
+                        : isExpired
+                            ? "已过期"
+                            : "进行中"}
+                </div>
+            </div>
+
+            <h2 style={{ margin: "24px 0 12px 0" }}>已提交种子</h2>
+            <table className="movie-table" style={{ maxWidth: 700, margin: "0 auto" }}>
+                <thead>
+                    <tr>
+                        <th>标题</th>
+                        <th>简介</th>
+                        <th>投票数</th>
+                        <th>操作</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {seeds.length === 0 ? (
+                        <tr>
+                            <td colSpan={4} style={{ textAlign: "center" }}>暂无提交的种子</td>
+                        </tr>
+                    ) : (
+                        seeds.map((s) => (
+                            <tr key={s.seed_id}>
+                                <td>{seedInfoMap[s.seed_id]?.title || "未知标题"}</td>
+                                <td>{seedInfoMap[s.seed_id]?.subtitle || "无简介"}</td>
+                                <td>{s.votes}</td>
+                                <td>
+                                    {isActive ? (
+                                        <button
+                                            onClick={() => handleVote(s.seed_id)}
+                                            style={{
+                                                background: "#1976d2",
+                                                color: "#fff",
+                                                border: "none",
+                                                borderRadius: 6,
+                                                padding: "6px 18px",
+                                                fontWeight: 500,
+                                                cursor: "pointer",
+                                                transition: "background 0.2s",
+                                            }}
+                                        >
+                                            投票
+                                        </button>
+                                    ) : (
+                                        <span style={{ color: "#b0b0b0" }}>不可投票</span>
+                                    )}
+                                </td>
+                            </tr>
+                        ))
+                    )}
+                </tbody>
+            </table>
+
+            {isActive && (
+                <div style={{ margin: "32px 0", textAlign: "center" }}>
+                    <button
+                        onClick={() => setShowForm(true)}
+                        style={{
+                            fontSize: 18,
+                            padding: "12px 36px",
+                            background: "linear-gradient(90deg, #42a5f5 0%, #1976d2 100%)",
+                            color: "#fff",
+                            border: "none",
+                            borderRadius: 8,
+                            fontWeight: 600,
+                            boxShadow: "0 2px 8px #b2d8ea",
+                            cursor: "pointer",
+                            transition: "background 0.2s",
+                        }}
+                    >
+                        提交悬赏种子
+                    </button>
+                </div>
+            )}
+
+            {showForm && isActive && (
+                <div
+                    style={{
+                        background: "#fff",
+                        border: "1.5px solid #b2d8ea",
+                        borderRadius: 12,
+                        padding: 24,
+                        maxWidth: 480,
+                        margin: "0 auto",
+                        boxShadow: "0 2px 8px #e0e7ff",
+                    }}
+                >
+                    <h3 style={{ color: "#1976d2", marginBottom: 18 }}>上传种子</h3>
+                    <form onSubmit={handleSubmitSeed}>
+                        <div style={{ marginBottom: 16 }}>
+                            <label style={{ display: "inline-block", width: 60 }}>标题:</label>
+                            <input
+                                type="text"
+                                name="title"
+                                value={formData.title}
+                                onChange={handleFormChange}
+                                required
+                                style={{
+                                    padding: "6px 12px",
+                                    borderRadius: 6,
+                                    border: "1px solid #b2d8ea",
+                                    width: 280,
+                                }}
+                            />
+                        </div>
+                        <div style={{ marginBottom: 16 }}>
+                            <label style={{ display: "inline-block", width: 60 }}>简介:</label>
+                            <input
+                                type="text"
+                                name="subtitle"
+                                value={formData.subtitle}
+                                onChange={handleFormChange}
+                                style={{
+                                    padding: "6px 12px",
+                                    borderRadius: 6,
+                                    border: "1px solid #b2d8ea",
+                                    width: 280,
+                                }}
+                            />
+                        </div>
+                        <div style={{ marginBottom: 16 }}>
+                            <label style={{ display: "inline-block", width: 60 }}>种子文件:</label>
+                            <input
+                                type="file"
+                                name="torrentFile"
+                                accept=".torrent"
+                                onChange={handleFormChange}
+                                required
+                                style={{
+                                    padding: "6px 0",
+                                    borderRadius: 6,
+                                    border: "1px solid #b2d8ea",
+                                    width: 280,
+                                }}
+                            />
+                        </div>
+                        <div style={{ marginTop: 18 }}>
+                            <button
+                                type="submit"
+                                style={{
+                                    background: "#1976d2",
+                                    color: "#fff",
+                                    border: "none",
+                                    borderRadius: 6,
+                                    padding: "8px 28px",
+                                    fontWeight: 500,
+                                    fontSize: 16,
+                                    marginRight: 18,
+                                    cursor: "pointer",
+                                }}
+                            >
+                                提交
+                            </button>
+                            <button
+                                type="button"
+                                onClick={() => setShowForm(false)}
+                                style={{
+                                    background: "#b0b0b0",
+                                    color: "#fff",
+                                    border: "none",
+                                    borderRadius: 6,
+                                    padding: "8px 28px",
+                                    fontWeight: 500,
+                                    fontSize: 16,
+                                    cursor: "pointer",
+                                }}
+                            >
+                                取消
+                            </button>
+                        </div>
+                    </form>
+                </div>
+            )}
+        </div>
+    );
+}
\ No newline at end of file
diff --git a/front/src/BegSeedPage.js b/front/src/BegSeedPage.js
new file mode 100644
index 0000000..a456147
--- /dev/null
+++ b/front/src/BegSeedPage.js
@@ -0,0 +1,243 @@
+import React, { useState } from "react";
+import HelpIcon from "@mui/icons-material/Help";
+import { useNavigate } from "react-router-dom";
+
+// 初始硬编码数据
+const initialBegSeedList = [
+    {
+        beg_id: "beg001",
+        info: "求《三体》高清资源",
+        beg_count: 5,
+        reward_magic: 100,
+        deadline: "2025-06-10T23:59:59",
+        has_match: 0,
+    },
+    {
+        beg_id: "beg002",
+        info: "求《灌篮高手》国语配音版",
+        beg_count: 3,
+        reward_magic: 50,
+        deadline: "2024-05-01T23:59:59",
+        has_match: 1,
+    },
+    {
+        beg_id: "beg003",
+        info: "求《黑暗之魂3》PC版种子",
+        beg_count: 2,
+        reward_magic: 80,
+        deadline: "2024-04-01T23:59:59",
+        has_match: 0,
+    },
+];
+
+export default function BegSeedPage() {
+    const navigate = useNavigate();
+    const now = new Date();
+    const [begSeedList, setBegSeedList] = useState(initialBegSeedList);
+    const [showForm, setShowForm] = useState(false);
+    const [formData, setFormData] = useState({
+        info: "",
+        reward_magic: "",
+        deadline: "",
+    });
+
+    // 表单输入处理
+    const handleFormChange = (e) => {
+        const { name, value } = e.target;
+        setFormData((prev) => ({
+            ...prev,
+            [name]: value,
+        }));
+    };
+
+    // 提交新求种任务
+    const handleSubmit = (e) => {
+        e.preventDefault();
+        const newBegId = "beg" + Math.floor(Math.random() * 10000);
+        setBegSeedList([
+            {
+                beg_id: newBegId,
+                info: formData.info,
+                beg_count: 1,
+                reward_magic: Number(formData.reward_magic),
+                deadline: formData.deadline,
+                has_match: 0,
+            },
+            ...begSeedList,
+        ]);
+        setShowForm(false);
+        setFormData({ info: "", reward_magic: "", deadline: "" });
+        alert("发布成功(前端演示)");
+    };
+
+    return (
+        <div className="container">
+            <h1 style={{ margin: "24px 0 32px 0", color: "#1976d2" }}>
+                <HelpIcon style={{ verticalAlign: "middle", marginRight: 8 }} />
+                求种列表
+            </h1>
+            <div style={{ margin: "0 0 32px 0", textAlign: "center" }}>
+                <button
+                    onClick={() => setShowForm(true)}
+                    style={{
+                        fontSize: 18,
+                        padding: "12px 36px",
+                        background: "linear-gradient(90deg, #42a5f5 0%, #1976d2 100%)",
+                        color: "#fff",
+                        border: "none",
+                        borderRadius: 8,
+                        fontWeight: 600,
+                        boxShadow: "0 2px 8px #b2d8ea",
+                        cursor: "pointer",
+                        transition: "background 0.2s",
+                    }}
+                >
+                    发布求种任务
+                </button>
+            </div>
+            {showForm && (
+                <div
+                    style={{
+                        background: "#fff",
+                        border: "1.5px solid #b2d8ea",
+                        borderRadius: 12,
+                        padding: 24,
+                        maxWidth: 480,
+                        margin: "0 auto 32px auto",
+                        boxShadow: "0 2px 8px #e0e7ff",
+                    }}
+                >
+                    <h3 style={{ color: "#1976d2", marginBottom: 18 }}>发布求种任务</h3>
+                    <form onSubmit={handleSubmit}>
+                        <div style={{ marginBottom: 16 }}>
+                            <label style={{ display: "inline-block", width: 80 }}>求种信息:</label>
+                            <input
+                                type="text"
+                                name="info"
+                                value={formData.info}
+                                onChange={handleFormChange}
+                                required
+                                style={{
+                                    padding: "6px 12px",
+                                    borderRadius: 6,
+                                    border: "1px solid #b2d8ea",
+                                    width: 260,
+                                }}
+                            />
+                        </div>
+                        <div style={{ marginBottom: 16 }}>
+                            <label style={{ display: "inline-block", width: 80 }}>悬赏魔力值:</label>
+                            <input
+                                type="number"
+                                name="reward_magic"
+                                value={formData.reward_magic}
+                                onChange={handleFormChange}
+                                required
+                                min={1}
+                                style={{
+                                    padding: "6px 12px",
+                                    borderRadius: 6,
+                                    border: "1px solid #b2d8ea",
+                                    width: 120,
+                                }}
+                            />
+                        </div>
+                        <div style={{ marginBottom: 16 }}>
+                            <label style={{ display: "inline-block", width: 80 }}>截止日期:</label>
+                            <input
+                                type="datetime-local"
+                                name="deadline"
+                                value={formData.deadline}
+                                onChange={handleFormChange}
+                                required
+                                style={{
+                                    padding: "6px 12px",
+                                    borderRadius: 6,
+                                    border: "1px solid #b2d8ea",
+                                    width: 200,
+                                }}
+                            />
+                        </div>
+                        <div style={{ marginTop: 18 }}>
+                            <button
+                                type="submit"
+                                style={{
+                                    background: "#1976d2",
+                                    color: "#fff",
+                                    border: "none",
+                                    borderRadius: 6,
+                                    padding: "8px 28px",
+                                    fontWeight: 500,
+                                    fontSize: 16,
+                                    marginRight: 18,
+                                    cursor: "pointer",
+                                }}
+                            >
+                                提交
+                            </button>
+                            <button
+                                type="button"
+                                onClick={() => setShowForm(false)}
+                                style={{
+                                    background: "#b0b0b0",
+                                    color: "#fff",
+                                    border: "none",
+                                    borderRadius: 6,
+                                    padding: "8px 28px",
+                                    fontWeight: 500,
+                                    fontSize: 16,
+                                    cursor: "pointer",
+                                }}
+                            >
+                                取消
+                            </button>
+                        </div>
+                    </form>
+                </div>
+            )}
+            <div style={{ display: "flex", flexWrap: "wrap", gap: 24 }}>
+                {begSeedList.map((beg) => {
+                    const isExpired =
+                        new Date(beg.deadline) < now || beg.has_match === 1;
+                    return (
+                        <div
+                            key={beg.beg_id}
+                            style={{
+                                background: isExpired ? "#f0f0f0" : "#e3f7e7",
+                                color: isExpired ? "#b0b0b0" : "#222",
+                                border: "1.5px solid #b2d8ea",
+                                borderRadius: 12,
+                                padding: 18,
+                                minWidth: 320,
+                                maxWidth: 420,
+                                boxShadow: "0 2px 8px #e0e7ff",
+                                opacity: isExpired ? 0.6 : 1,
+                                cursor: "pointer",
+                                marginBottom: 12,
+                                transition: "box-shadow 0.2s",
+                            }}
+                            onClick={() => navigate(`/begseed/${beg.beg_id}`)}
+                        >
+                            <div style={{ fontWeight: 600, fontSize: 18, marginBottom: 8 }}>
+                                {beg.info}
+                            </div>
+                            <div>求种人数:{beg.beg_count}</div>
+                            <div>悬赏魔力值:{beg.reward_magic}</div>
+                            <div>
+                                截止时间:{new Date(beg.deadline).toLocaleString()}
+                            </div>
+                            <div>
+                                状态:
+                                {beg.has_match === 1
+                                    ? "已完成"
+                                    : new Date(beg.deadline) < now
+                                        ? "已过期"
+                                        : "进行中"}
+                            </div>
+                        </div>
+                    );
+                })}
+            </div>
+        </div>
+    );
+}
\ No newline at end of file
diff --git a/front/src/MoviePage.js b/front/src/MoviePage.js
index b01d324..cdc8112 100644
--- a/front/src/MoviePage.js
+++ b/front/src/MoviePage.js
@@ -8,6 +8,7 @@
 import PersonIcon from "@mui/icons-material/Person";

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

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

+import HelpIcon from "@mui/icons-material/Help";

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

 import "./App.css";

 import { API_BASE_URL } from "./config";

@@ -21,7 +22,8 @@
   { label: "体育", icon: <SportsMartialArtsIcon />, path: "/sport" },

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

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

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

+  { label: "发布", icon: <AccountCircleIcon />, path: "/publish" },

+  { label: "求种", icon: <HelpIcon />, path: "/begseed" },

 ];

 

 const areaTabs = [