新增求种页面
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 = [