ssq页面
Change-Id: I11f58d72d9e33eae9ec84f46473fa6144b480501
diff --git a/front/src/AnimePage.js b/front/src/AnimePage.js
index d17f3cc..97bf453 100644
--- a/front/src/AnimePage.js
+++ b/front/src/AnimePage.js
@@ -30,17 +30,16 @@
];
const areaTabs = [
- { label: "国创", icon: <EmojiPeopleIcon fontSize="small" /> },
- { label: "日漫", icon: <EmailIcon fontSize="small" /> },
- { label: "欧美动漫", icon: <PersonIcon fontSize="small" /> },
- { label: "韩漫", icon: <EmojiPeopleIcon fontSize="small" /> },
- // { label: "其他", icon: <PersonIcon fontSize="small" /> },
+ { label: "大陆", icon: <EmojiPeopleIcon fontSize="small" /> },
+ { label: "港台", icon: <EmailIcon fontSize="small" /> },
+ { label: "欧美", icon: <PersonIcon fontSize="small" /> },
+ { label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },
+ { label: "其他", icon: <PersonIcon fontSize="small" /> },
];
export default function AnimePage() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = React.useState(0);
- const [animeList, setAnimeList] = React.useState([]);
// 每个tab对应的动漫类型
const animeTypesList = [
@@ -52,15 +51,6 @@
];
const animeTypes = animeTypesList[activeTab] || [];
- React.useEffect(() => {
- // 假设后端接口为 /api/animes?area=大陆
- const area = areaTabs[activeTab].label;
- fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
- .then(res => res.json())
- .then(data => setAnimeList(data))
- .catch(() => setAnimeList([]));
- }, [activeTab]);
-
return (
<div className="container">
{/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}
@@ -118,39 +108,21 @@
</tr>
</thead>
<tbody>
- {animeList.length > 0 ? (
- animeList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.user.username}</td>
- </tr>
- ))
- ) : (
- animeTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- </tr>
- ))
- )}
+ {animeTypes.map((type, index) => (
+ <tr key={type}>
+ <td>
+ <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+ {type}
+ </a>
+ </td>
+ <td>
+ <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ </tr>
+ ))}
</tbody>
</table>
</div>
diff --git a/front/src/App.js b/front/src/App.js
index 240f958..225689e 100644
--- a/front/src/App.js
+++ b/front/src/App.js
@@ -1,5 +1,5 @@
import React from "react";
-import { BrowserRouter as Router, Routes, Route, useNavigate, Link } from "react-router-dom";
+import { BrowserRouter as Router, Routes, Route, useNavigate, Link, Navigate } from "react-router-dom";
import MovieIcon from "@mui/icons-material/Movie";
import EmailIcon from "@mui/icons-material/Email";
import MusicNoteIcon from "@mui/icons-material/MusicNote";
@@ -19,6 +19,8 @@
import UserProfile from "./UserProfile";
import PublishPage from "./PublishPage";
import TorrentDetailPage from './TorrentDetailPage';
+import LoginPage from './LoginPage';
+import RegisterPage from './RegisterPage';
const navItems = [
{ label: "电影", icon: <MovieIcon />, path: "/movie" },
@@ -142,7 +144,9 @@
return (
<Router>
<Routes>
- <Route path="/" element={<Home />} />
+ <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 />} />
diff --git a/front/src/GamePage.js b/front/src/GamePage.js
index 2528acd..23383b6 100644
--- a/front/src/GamePage.js
+++ b/front/src/GamePage.js
@@ -21,13 +21,7 @@
{ label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option
];
-const gameTypesList = [
- ["PC"],
- ["主机"],
- ["移动"],
- ["掌机"],
- ["视频"]
-];
+const gameTypes = ["PC", "主机", "移动", "掌机", "视频"];
const areaTabs = [
{ label: "PC", icon: <MovieIcon fontSize="small" /> },
@@ -37,20 +31,15 @@
{ label: "视频", icon: <PersonIcon fontSize="small" /> },
];
+const exampleTorrents = [
+ { type: "RPG", title: "实例1", id: 1 },
+ { type: "Shooter", title: "实例2", id: 2 },
+ { type: "Adventure", title: "实例3", id: 3 },
+];
+
export default function GamePage() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState(0);
- const [gameList, setGameList] = useState([]);
-
- const gameTypes = gameTypesList[activeTab] || [];
-
- React.useEffect(() => {
- const area = areaTabs[activeTab].label;
- fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
- .then(res => res.json())
- .then(data => setGameList(data))
- .catch(() => setGameList([]));
- }, [activeTab]);
return (
<div className="container">
@@ -164,39 +153,27 @@
</tr>
</thead>
<tbody>
- {gameList.length > 0 ? (
- gameList.map((item, idx) => (
- <tr key={item.id || idx}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {item.title}
- </a>
- </td>
- <td>{item.user.username}</td>
- </tr>
- ))
- ) : (
- gameTypes.map((type, idx) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- 种子{idx + 1}
- </a>
- </td>
- <td></td>
- </tr>
- ))
- )}
+ {gameTypes.map((type, idx) => (
+ <tr key={type}>
+ <td>
+ <a
+ href={`/torrent/${type}`}
+ style={{ color: "#1a237e", textDecoration: "none" }}
+ >
+ {type}
+ </a>
+ </td>
+ <td>
+ <a
+ href={`/torrent/${type}`}
+ style={{ color: "#1a237e", textDecoration: "none" }}
+ >
+ 种子{idx + 1}
+ </a>
+ </td>
+ <td></td>
+ </tr>
+ ))}
</tbody>
</table>
</div>
diff --git a/front/src/InfoPage.js b/front/src/InfoPage.js
index 755d922..1e00527 100644
--- a/front/src/InfoPage.js
+++ b/front/src/InfoPage.js
@@ -40,7 +40,6 @@
export default function InfoPage() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = React.useState(0);
- const [infoList, setInfoList] = React.useState(0);
// 每个tab对应的资料类型
const infoTypesList = [
@@ -52,18 +51,6 @@
];
const infoTypes = infoTypesList[activeTab] || [];
- React.useEffect(() => {
- // 这里假设后端接口为 /api/get-seed-list-by-tag?tag=大陆
- const area = areaTabs[activeTab].label;
- fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
- .then(res => res.json())
- .then(data => {
- console.log('资料区返回数据:', data);
- setInfoList(data);
- })
- .catch(() => setInfoList([]));
- }, [activeTab]);
-
return (
<div className="container">
{/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}
@@ -176,39 +163,27 @@
</tr>
</thead>
<tbody>
- {infoList.length > 0 ? (
- infoList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.user.username}</td>
- </tr>
- ))
- ) : (
- infoTypesList.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- </tr>
- ))
- )}
+ {infoTypes.map((type, index) => (
+ <tr key={type}>
+ <td>
+ <a
+ href={`/torrent/${type}`}
+ style={{ color: "#1a237e", textDecoration: "none" }}
+ >
+ {type}
+ </a>
+ </td>
+ <td>
+ <a
+ href={`/torrent/${type}`}
+ style={{ color: "#1a237e", textDecoration: "none" }}
+ >
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ </tr>
+ ))}
</tbody>
</table>
</div>
diff --git a/front/src/LoginPage.js b/front/src/LoginPage.js
new file mode 100644
index 0000000..59a1b2b
--- /dev/null
+++ b/front/src/LoginPage.js
@@ -0,0 +1,100 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { Input } from 'antd';
+import './App.css';
+
+const LoginPage = () => {
+ const [formData, setFormData] = useState({ username: '', password: '' });
+ const [errorMessage, setErrorMessage] = useState('');
+ const navigate = useNavigate();
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData({ ...formData, [name]: value });
+ };
+
+ const handleLogin = () => {
+ if (formData.password.length < 8) {
+ setErrorMessage('密码必须至少包含八位字符!');
+ return;
+ }
+
+ // Simulate successful login
+ setErrorMessage('');
+ navigate('/');
+ };
+
+ const handleRegister = () => {
+ navigate('/register');
+ };
+
+ // 自动填充注册信息
+ React.useEffect(() => {
+ const regUser = sessionStorage.getItem('registeredUser');
+ if (regUser) {
+ try {
+ const { username, password } = JSON.parse(regUser);
+ setFormData({ username, password });
+ sessionStorage.removeItem('registeredUser');
+ } catch {}
+ }
+ }, []);
+
+ return (
+ <div className="login-page" style={{ minHeight: '100vh', background: 'linear-gradient(135deg, #e0e7ff 0%, #f0f8ff 100%)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
+ <div className="login-form-container" style={{ width: 360, padding: '40px 32px 80px 32px', borderRadius: 18, boxShadow: '0 8px 32px rgba(60, 80, 180, 0.10)', background: '#fff', position: 'relative' }}>
+ <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>
+ <Input
+ placeholder="请输入用户名"
+ id="username"
+ name="username"
+ value={formData.username}
+ onChange={handleChange}
+ required
+ style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}
+ />
+ </div>
+ <div className="form-row" style={{ marginBottom: 24 }}>
+ <label htmlFor="password" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>密码</label>
+ <div style={{ display: 'flex', alignItems: 'center' }}>
+ <Input
+ placeholder="请输入密码"
+ type="password"
+ id="password"
+ name="password"
+ value={formData.password}
+ onChange={handleChange}
+ required
+ style={{ flex: 1, padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}
+ />
+ </div>
+ </div>
+ {errorMessage && <p style={{ color: '#e53935', textAlign: 'center', marginBottom: 18, fontWeight: 500 }}>{errorMessage}</p>}
+ <div className="form-row button-row" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 32, position: 'static', gap: 16 }}>
+ <button
+ type="button"
+ className="login-button"
+ onClick={handleLogin}
+ style={{ width: 120, padding: '10px 0', borderRadius: 8, border: 'none', background: 'linear-gradient(90deg, #34c759 0%, #5be584 100%)', color: '#fff', fontWeight: 600, fontSize: 16, cursor: 'pointer', boxShadow: '0 2px 8px #b2eac2', marginBottom: 12 }}
+ >
+ 登录
+ </button>
+ <button
+ type="button"
+ className="register-button"
+ onClick={handleRegister}
+ style={{ width: 120, padding: '10px 0', borderRadius: 8, border: 'none', background: 'linear-gradient(90deg, #4f8cff 0%, #6ad1ff 100%)', color: '#fff', fontWeight: 600, fontSize: 16, cursor: 'pointer', boxShadow: '0 2px 8px #b2d8ea' }}
+ >
+ 注册
+ </button>
+ </div>
+ </form>
+ </div>
+ </div>
+ );
+};
+
+export default LoginPage;
diff --git a/front/src/MoviePage.js b/front/src/MoviePage.js
index c84797b..20e4a4f 100644
--- a/front/src/MoviePage.js
+++ b/front/src/MoviePage.js
@@ -26,7 +26,7 @@
{ label: "港台", icon: <EmailIcon fontSize="small" /> },
{ label: "欧美", icon: <PersonIcon fontSize="small" /> },
{ label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },
- // { label: "其他", icon: <PersonIcon fontSize="small" /> },
+ { label: "其他", icon: <PersonIcon fontSize="small" /> },
];
const exampleTorrents = [
@@ -38,7 +38,6 @@
export default function MoviePage() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = React.useState(0);
- const [movieList, setMovieList] = React.useState([]);
// 每个tab对应的电影类型
const movieTypesList = [
@@ -50,18 +49,6 @@
];
const movieTypes = movieTypesList[activeTab] || [];
- React.useEffect(() => {
- // 这里假设后端接口为 /api/get-seed-list-by-tag?tag=大陆
- const area = areaTabs[activeTab].label;
- fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
- .then(res => res.json())
- .then(data => {
- console.log('电影区返回数据:', data);
- setMovieList(data);
- })
- .catch(() => setMovieList([]));
- }, [activeTab]);
-
return (
<div className="container">
{/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}
@@ -119,39 +106,21 @@
</tr>
</thead>
<tbody>
- {movieList.length > 0 ? (
- movieList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.user.username}</td>
- </tr>
- ))
- ) : (
- movieTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- </tr>
- ))
- )}
+ {movieTypes.map((type, index) => (
+ <tr key={type}>
+ <td>
+ <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+ {type}
+ </a>
+ </td>
+ <td>
+ <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ </tr>
+ ))}
</tbody>
</table>
</div>
diff --git a/front/src/MusicPage.js b/front/src/MusicPage.js
index b39b0ee..4a9c465 100644
--- a/front/src/MusicPage.js
+++ b/front/src/MusicPage.js
@@ -22,11 +22,11 @@
];
const areaTabs = [
- { label: "古典音乐", icon: <MovieIcon fontSize="small" /> },
- { label: "流行音乐", icon: <EmailIcon fontSize="small" /> },
- { label: "摇滚", icon: <PersonIcon fontSize="small" /> },
- { label: "电子音乐", icon: <EmojiPeopleIcon fontSize="small" /> },
- { label: "说唱", icon: <PersonIcon fontSize="small" /> },
+ { label: "大陆", icon: <MovieIcon fontSize="small" /> },
+ { label: "港台", icon: <EmailIcon fontSize="small" /> },
+ { label: "欧美", icon: <PersonIcon fontSize="small" /> },
+ { label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },
+ { label: "其他", icon: <PersonIcon fontSize="small" /> },
];
const exampleTorrents = [
@@ -38,7 +38,6 @@
export default function MusicPage() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = React.useState(0);
- const [musicList, setMusicList] = React.useState([]);
// 每个tab对应的音乐类型
const musicTypesList = [
@@ -50,15 +49,6 @@
];
const musicTypes = musicTypesList[activeTab] || [];
- React.useEffect(() => {
- // 假设后端接口为 /api/musics?area=大陆
- const area = areaTabs[activeTab].label;
- fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
- .then(res => res.json())
- .then(data => setMusicList(data))
- .catch(() => setMusicList([]));
- }, [activeTab]);
-
return (
<div className="container music-bg">
{/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}
@@ -116,39 +106,21 @@
</tr>
</thead>
<tbody>
- {musicList.length > 0 ? (
- musicList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.user.username}</td>
- </tr>
- ))
- ) : (
- musicTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- </tr>
- ))
- )}
+ {musicTypes.map((type, index) => (
+ <tr key={type}>
+ <td>
+ <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+ {type}
+ </a>
+ </td>
+ <td>
+ <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ </tr>
+ ))}
</tbody>
</table>
</div>
diff --git a/front/src/PublishPage.js b/front/src/PublishPage.js
index a1a0e8f..81ac790 100644
--- a/front/src/PublishPage.js
+++ b/front/src/PublishPage.js
@@ -9,17 +9,6 @@
title: '',
subtitle: ''
});
- const [subType, setSubType] = useState('');
-
- const typeOptions = {
- '电影': ['大陆', '港台', '欧美', '日韩'],
- '剧集': ['国产电视剧', '港剧', '欧美剧', '日韩剧'],
- '音乐': ['古典音乐', '流行音乐', '摇滚', '电子音乐', '说唱'],
- '动漫': ['国创', '日漫', '欧美动漫', '韩漫'],
- '游戏': ['PC', '主机', '移动', '掌机', '视频'],
- '体育': ['篮球', '足球', '羽毛球', '排球', '电竞'],
- '资料': ['出版物', '学习教程', '素材模板', '演讲交流', '日常娱乐'],
- };
const handleChange = (e) => {
const { name, value } = e.target;
@@ -36,37 +25,9 @@
}
};
- const handleSubmit = async (e) => {
+ const handleSubmit = (e) => {
e.preventDefault();
- // 假设userid和tag可以从表单或用户信息中获取,这里用示例数据
- const userid = '550e8400-e29b-41d4-a716-446655440000';
- const tag = formData.type ? formData.type : '高清';
- if (!formData.torrentFile) {
- alert('请上传.torrent文件');
- return;
- }
- const data = new FormData();
- data.append('userid', userid);
- data.append('title', formData.title);
- data.append('tag', subType);
- data.append('file', formData.torrentFile);
- data.append('subtitle', formData.subtitle);
- // data.append('subtype', subType);
- // console.log(data.get('tag'));
-
- try {
- const response = await fetch('http://192.168.5.9:8080/api/save-torrent', {
- method: 'POST',
- body: data,
- });
- if (response.ok) {
- alert('上传成功!');
- } else {
- alert('上传失败');
- }
- } catch (err) {
- alert('网络错误');
- }
+ console.log('Form Data Submitted:', formData);
};
return (
@@ -75,7 +36,7 @@
<form onSubmit={handleSubmit} className="publish-form">
<div className="form-row">
<label htmlFor="type">类型</label>
- <select name="type" id="type" value={formData.type} onChange={e => { handleChange(e); setSubType(''); }} required>
+ <select name="type" id="type" value={formData.type} onChange={handleChange} required>
<option value="">请选择类型</option>
<option value="电影">电影</option>
<option value="剧集">剧集</option>
@@ -86,17 +47,6 @@
<option value="资料">资料</option>
</select>
</div>
- {formData.type && typeOptions[formData.type] && (
- <div className="form-row">
- <label htmlFor="subtype">具体类型</label>
- <select name="subtype" id="subtype" value={subType} onChange={e => setSubType(e.target.value)} required>
- <option value="">请选择具体类型</option>
- {typeOptions[formData.type].map(opt => (
- <option key={opt} value={opt}>{opt}</option>
- ))}
- </select>
- </div>
- )}
<div className="form-row">
<label htmlFor="torrentFile">种子文件</label>
@@ -123,7 +73,7 @@
</div>
<div className="form-row">
- <label htmlFor="subtitle">副标题</label>
+ <label htmlFor="subtitle">种子简介</label>
<input
type="text"
id="subtitle"
diff --git a/front/src/RegisterPage.js b/front/src/RegisterPage.js
new file mode 100644
index 0000000..ffd11a4
--- /dev/null
+++ b/front/src/RegisterPage.js
@@ -0,0 +1,109 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { Input } from 'antd';
+import './App.css';
+
+const RegisterPage = () => {
+ const [formData, setFormData] = useState({ username: '', password: '', inviteCode: '', confirmPassword: '' });
+ const [errorMessage, setErrorMessage] = useState('');
+ const navigate = useNavigate();
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData({ ...formData, [name]: value });
+ };
+
+ const handleRegister = () => {
+ if (formData.password.length !== 8) {
+ setErrorMessage('密码必须为八位字符!');
+ return;
+ }
+
+ if (formData.password !== formData.confirmPassword) {
+ setErrorMessage('两次输入的密码不匹配!');
+ return;
+ }
+
+ // Simulate successful registration
+ setErrorMessage('');
+ // 存储注册信息到 sessionStorage
+ sessionStorage.setItem('registeredUser', JSON.stringify({ username: formData.username, password: formData.password }));
+ alert('注册成功!');
+ navigate('/login');
+ };
+
+ return (
+ <div className="register-page" style={{ minHeight: '100vh', background: 'linear-gradient(135deg, #e0e7ff 0%, #f0f8ff 100%)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
+ <div className="register-form-container" style={{ width: 360, padding: '40px 32px 64px 32px', borderRadius: 18, boxShadow: '0 8px 32px rgba(60, 80, 180, 0.10)', background: '#fff', position: 'relative' }}>
+ <h1 style={{ textAlign: 'center', marginBottom: 32, color: '#222', fontWeight: 700, fontSize: 32, letterSpacing: 2 }}>欢迎注册</h1>
+ <form className="register-form">
+ <div className="form-row" style={{ marginBottom: 24 }}>
+ <label htmlFor="inviteCode" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>被邀请邮箱</label>
+ <Input
+ placeholder="请输入被邀请邮箱"
+ id="inviteCode"
+ name="inviteCode"
+ value={formData.inviteCode || ''}
+ onChange={handleChange}
+ required
+ style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}
+ />
+ </div>
+ <div className="form-row" style={{ marginBottom: 24 }}>
+ <label htmlFor="username" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>用户名</label>
+ <Input
+ placeholder="请输入用户名"
+ id="username"
+ name="username"
+ value={formData.username}
+ onChange={handleChange}
+ required
+ style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}
+ />
+ </div>
+ <div className="form-row" style={{ marginBottom: 24 }}>
+ <label htmlFor="password" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>密码</label>
+ <div style={{ display: 'flex', alignItems: 'center' }}>
+ <Input
+ placeholder="请输入密码"
+ type="password"
+ id="password"
+ name="password"
+ value={formData.password}
+ onChange={handleChange}
+ required
+ style={{ flex: 1, padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}
+ />
+ </div>
+ </div>
+ <div className="form-row" style={{ marginBottom: 24 }}>
+ <label htmlFor="confirmPassword" style={{ display: 'block', marginBottom: 8, color: '#333', fontWeight: 500, fontSize: 16 }}>确认密码</label>
+ <Input
+ placeholder="请再次输入密码"
+ type="password"
+ id="confirmPassword"
+ name="confirmPassword"
+ value={formData.confirmPassword || ''}
+ onChange={handleChange}
+ required
+ style={{ width: '100%', padding: '12px', borderRadius: 8, fontSize: 16, background: '#f7faff' }}
+ />
+ </div>
+ {errorMessage && <p style={{ color: '#e53935', textAlign: 'center', marginBottom: 18, fontWeight: 500 }}>{errorMessage}</p>}
+ <div className="form-row button-row" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', position: 'absolute', left: 0, right: 0, bottom: 24 }}>
+ <button
+ type="button"
+ className="register-button"
+ onClick={handleRegister}
+ style={{ width: 120, padding: '10px 0', borderRadius: 8, border: 'none', background: 'linear-gradient(90deg, #4f8cff 0%, #6ad1ff 100%)', color: '#fff', fontWeight: 600, fontSize: 16, cursor: 'pointer', boxShadow: '0 2px 8px #b2d8ea' }}
+ >
+ 注册
+ </button>
+ </div>
+ </form>
+ </div>
+ </div>
+ );
+};
+
+export default RegisterPage;
diff --git a/front/src/SportPage.js b/front/src/SportPage.js
index 3299a93..569f022 100644
--- a/front/src/SportPage.js
+++ b/front/src/SportPage.js
@@ -40,7 +40,6 @@
export default function SportPage() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = React.useState(0);
- const [sportList, setSportList] = React.useState([]);
// 每个tab对应的运动类型
const sportTypesList = [
@@ -52,15 +51,6 @@
];
const sportTypes = sportTypesList[activeTab] || [];
- React.useEffect(() => {
- // 假设后端接口为 /api/sports?area=篮球
- const area = areaTabs[activeTab].label;
- fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
- .then(res => res.json())
- .then(data => setSportList(data))
- .catch(() => setSportList([]));
- }, [activeTab]);
-
return (
<div className="container">
{/* 顶部空白与音乐界面一致,用户栏绝对定位在页面右上角 */}
@@ -173,39 +163,27 @@
</tr>
</thead>
<tbody>
- {sportList.length > 0 ? (
- sportList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {item.title}
- </a>
- </td>
- <td>{item.user.username}</td>
- </tr>
- ))
- ) : (
- sportTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: "#1a237e", textDecoration: "none" }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- </tr>
- ))
- )}
+ {sportTypes.map((type, index) => (
+ <tr key={type}>
+ <td>
+ <a
+ href={`/torrent/${type}`}
+ style={{ color: "#1a237e", textDecoration: "none" }}
+ >
+ {type}
+ </a>
+ </td>
+ <td>
+ <a
+ href={`/torrent/${type}`}
+ style={{ color: "#1a237e", textDecoration: "none" }}
+ >
+ 种子{index + 1}
+ </a>
+ </td>
+ <td>发布者{index + 1}</td>
+ </tr>
+ ))}
</tbody>
</table>
</div>
diff --git a/front/src/TVPage.js b/front/src/TVPage.js
index bf1db6c..13b7391 100644
--- a/front/src/TVPage.js
+++ b/front/src/TVPage.js
@@ -21,37 +21,40 @@
{ label: "发布", icon: <AccountCircleIcon />, path: "/publish" }, // Added Publish option
];
-const tvTypesList = [
- ["华语剧集(大陆)", "欧美剧集", "日韩剧集", "港台剧集", "其他"], // 大陆
- ["港台都市", "港台爱情", "港台悬疑", "港台其他"], // 港台
- ["欧美悬疑", "欧美历史", "欧美其他"], // 欧美
- ["日韩青春", "日韩家庭", "日韩其他"], // 日韩
- ["其他类型1", "其他类型2"] // 其他
+const tvTypes = [
+ "华语剧集(大陆)",
+ "欧美剧集",
+ "日韩剧集",
+ "港台剧集",
+ "其他"
];
const areaTabs = [
- { label: "国产电视剧", icon: <MovieIcon fontSize="small" /> },
- { label: "港剧", icon: <EmailIcon fontSize="small" /> },
- { label: "欧美剧", icon: <PersonIcon fontSize="small" /> },
- { label: "日韩剧", icon: <EmojiPeopleIcon fontSize="small" /> },
- // { label: "其他", icon: <PersonIcon fontSize="small" /> },
+ { label: "大陆", icon: <MovieIcon fontSize="small" /> },
+ { label: "港台", icon: <EmailIcon fontSize="small" /> },
+ { label: "欧美", icon: <PersonIcon fontSize="small" /> },
+ { label: "日韩", icon: <EmojiPeopleIcon fontSize="small" /> },
+ { label: "其他", icon: <PersonIcon fontSize="small" /> },
+];
+
+const exampleTorrents = [
+ { type: "Drama", title: "实例1", id: 1 },
+ { type: "Comedy", title: "实例2", id: 2 },
+ { type: "Sci-Fi", title: "实例3", id: 3 },
];
export default function TVPage() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = React.useState(0);
- const [tvList, setTvList] = React.useState([]);
-
- React.useEffect(() => {
- // 假设后端接口为 /api/tvs?area=大陆
- const area = areaTabs[activeTab].label;
- fetch(`http://192.168.5.9:8080/api/get-seed-list-by-tag?tag=${encodeURIComponent(area)}`)
- .then(res => res.json())
- .then(data => setTvList(data))
- .catch(() => setTvList([]));
- }, [activeTab]);
// 每个tab对应的剧集类型
+ const tvTypesList = [
+ ["华语剧集(大陆)", "欧美剧集", "日韩剧集", "港台剧集", "其他"], // 大陆
+ ["港台都市", "港台爱情", "港台悬疑", "港台其他"], // 港台
+ ["欧美悬疑", "欧美历史", "欧美其他"], // 欧美
+ ["日韩青春", "日韩家庭", "日韩其他"], // 日韩
+ ["其他类型1", "其他类型2"] // 其他
+ ];
const tvTypes = tvTypesList[activeTab] || [];
return (
@@ -111,39 +114,21 @@
</tr>
</thead>
<tbody>
- {tvList.length > 0 ? (
- tvList.map((item, index) => (
- <tr key={item.id || index}>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.seedtag}
- </a>
- </td>
- <td>
- <a href={`/torrent/${item.seedid}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {item.title}
- </a>
- </td>
- <td>{item.user.username}</td>
- </tr>
- ))
- ) : (
- tvTypes.map((type, index) => (
- <tr key={type}>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- {type}
- </a>
- </td>
- <td>
- <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
- 种子{index + 1}
- </a>
- </td>
- <td>发布者{index + 1}</td>
- </tr>
- ))
- )}
+ {tvTypes.map((type, index) => (
+ <tr key={type}>
+ <td>
+ <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+ {type}
+ </a>
+ </td>
+ <td>
+ <a href={`/torrent/${type}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
+ 种子{index + 1}
+ </a>
+ </td>
+ <td></td>
+ </tr>
+ ))}
</tbody>
</table>
</div>
diff --git a/front/src/TorrentDetailPage.js b/front/src/TorrentDetailPage.js
index 8d3ee43..a23dce7 100644
--- a/front/src/TorrentDetailPage.js
+++ b/front/src/TorrentDetailPage.js
@@ -4,81 +4,14 @@
export default function TorrentDetailPage() {
const { torrentId } = useParams();
- const [detail, setDetail] = React.useState(null);
- const [loading, setLoading] = React.useState(true);
- const [error, setError] = React.useState(null);
- // 假设你从某个地方获取了 userId(例如登录状态、localStorage 等)
- const [userId] = React.useState('user1550e8400-e29b-41d4-a716-44665544000023'); // 替换为实际的用户 ID
-
- const handleClick = () => {
- // 构造下载 URL,包含 userId 和 torrentId 参数
- console.log(torrentId)
- const downloadUrl = `http://192.168.5.9:8080/api/get-torrent?userId=${encodeURIComponent(userId)}&torrentId=${encodeURIComponent(torrentId)}`;
-
- // 发起 GET 请求下载文件
- fetch(downloadUrl)
- .then(response => {
- if (!response.ok) {
- throw new Error('下载失败');
- }
- return response.blob();
- })
- .then(blob => {
- // 创建下载链接并触发下载
- const url = window.URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = `torrent-${torrentId}.torrent`;
- document.body.appendChild(a);
- a.click();
- window.URL.revokeObjectURL(url);
- document.body.removeChild(a);
- })
- .catch(error => {
- console.error('下载错误:', error);
- alert('下载失败: ' + error.message);
- });
- };
-
- React.useEffect(() => {
- setLoading(true);
- setError(null);
- fetch(`http://192.168.5.9:8080/api/torrent-detail?id=${encodeURIComponent(torrentId)}`)
- .then(res => {
- if (!res.ok) throw new Error('网络错误');
- return res.json();
- })
- .then(data => {
- setDetail(data);
- setLoading(false);
- })
- .catch(err => {
- setError(err.message);
- setLoading(false);
- });
- }, [torrentId]);
-
- if (loading) return <div className="container"><h1>加载中...</h1></div>;
- if (error) return <div className="container"><h1>加载失败: {error}</h1></div>;
- if (!detail) return <div className="container"><h1>未找到详情</h1></div>;
return (
<div className="container">
<h1>种子详情页</h1>
- <h2 style={{ fontSize: 'inherit', fontWeight: 'normal', textAlign: 'left' }}>标题: {detail.title || `种子${torrentId}`}</h2>
- <p style={{ fontSize: 'inherit', textAlign: 'left' }}>简介: {detail.description || `这是种子${torrentId}的详细信息。`}</p>
+ <h2 style={{ fontSize: 'inherit', fontWeight: 'normal', textAlign: 'left' }}>标题: 种子{torrentId}</h2>
+ <p style={{ fontSize: 'inherit', textAlign: 'left' }}>简介: 这是种子{torrentId}的详细信息。</p>
<div style={{ textAlign: 'center', marginTop: '20px' }}>
- <button
- style={{
- padding: '10px 20px',
- fontSize: '16px',
- cursor: 'pointer',
- backgroundColor: '#d3f0ff',
- border: 'none',
- borderRadius: '4px'
- }}
- onClick={handleClick}
- >
+ <button style={{ padding: '10px 20px', fontSize: '16px', cursor: 'pointer', backgroundColor: '#d3f0ff', border: 'none', borderRadius: '4px' }}>
下载
</button>
</div>
diff --git a/front/src/UserProfile.js b/front/src/UserProfile.js
index 4737033..0269723 100644
--- a/front/src/UserProfile.js
+++ b/front/src/UserProfile.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState } from "react";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import { useNavigate } from "react-router-dom";
import "./App.css";
@@ -6,109 +6,21 @@
export default function UserProfile() {
const navigate = useNavigate();
const [userInfo, setUserInfo] = useState({
- avatar_url: "",
username: "示例用户",
email: "user@example.com",
- invite_left: "",
+ company: "",
school: "",
- account_status: "",
- gender: "",
+ birthday: "",
});
const [tempUserInfo, setTempUserInfo] = useState({ ...userInfo });
- const [userSeeds, setUserSeeds] = useState([]);
- const [userStats, setUserStats] = useState({
- magic: 0,
- upload: 0,
- download: 0,
- ratio: 0,
- });
-
- // 新增:根据userid从后端获取用户信息
- useEffect(() => {
- const fetchUserInfo = async () => {
- // 假设userid存储在localStorage或其他地方
- // const userid = localStorage.getItem("userid");
- const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid
- if (!userid) return;
- try {
- const res = await fetch(`/api/user-profile?userid=${userid}`);
- if (res.ok) {
- const data = await res.json();
- setUserInfo(data);
- setTempUserInfo(data);
- }
- } catch (err) {
- // 可以根据需要处理错误
- console.error("获取用户信息失败", err);
- }
- };
- fetchUserInfo();
- }, []);
-
- // 动态加载用户上传种子列表
- useEffect(() => {
- const fetchUserSeeds = async () => {
- // const userid = localStorage.getItem("userid");
- const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid
- if (!userid) return;
- try {
- const res = await fetch(`/api/user-seeds?userid=${userid}`);
- if (res.ok) {
- const data = await res.json();
- setUserSeeds(data);
- }
- } catch (err) {
- console.error("获取种子列表失败", err);
- }
- };
- fetchUserSeeds();
- }, []);
-
- // 动态加载用户活跃度信息
- useEffect(() => {
- const fetchUserStats = async () => {
- // const userid = localStorage.getItem("userid");
- const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid
- if (!userid) return;
- try {
- const res = await fetch(`/api/user-stats?userid=${userid}`);
- if (res.ok) {
- const data = await res.json();
- setUserStats(data);
- }
- } catch (err) {
- console.error("获取活跃度信息失败", err);
- }
- };
- fetchUserStats();
- }, []);
const handleInputChange = (field, value) => {
setTempUserInfo({ ...tempUserInfo, [field]: value });
};
- const handleSave = async () => {
+ const handleSave = () => {
setUserInfo({ ...tempUserInfo });
- // 获取userid
- // const userid = localStorage.getItem("userid");
- const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid
- try {
- const res = await fetch('/api/change-profile', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ userid, ...tempUserInfo }),
- });
- if (res.ok) {
- alert("信息已保存!");
- } else {
- alert("保存失败,请重试。");
- }
- } catch (err) {
- alert("保存失败,请检查网络连接。");
- console.error("保存用户信息失败", err);
- }
+ alert("信息已保存!");
};
const handleAvatarClick = () => {
@@ -127,7 +39,7 @@
<AccountCircleIcon style={{ fontSize: 90, color: '#1a237e', marginBottom: 12 }} />
{tempUserInfo.avatar && (
<img
- src={tempUserInfo.avatar_url}
+ src={tempUserInfo.avatar}
alt="用户头像"
style={{
position: 'absolute',
@@ -155,19 +67,21 @@
</div>
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}>
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>邮箱:</b>
- <span
- style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }}
- >
- {tempUserInfo.email}
- </span>
+ <input
+ type="email"
+ value={tempUserInfo.email}
+ onChange={(e) => handleInputChange("email", e.target.value)}
+ style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}
+ />
</div>
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}>
- <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>邀请剩余:</b>
- <span
- style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }}
- >
- {tempUserInfo.invite_left}
- </span>
+ <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>公司:</b>
+ <input
+ type="text"
+ value={tempUserInfo.company}
+ onChange={(e) => handleInputChange("company", e.target.value)}
+ style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}
+ />
</div>
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}>
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>学校:</b>
@@ -179,21 +93,22 @@
/>
</div>
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}>
- <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>账号状态:</b>
- <span
- style={{ flex: 1, display: 'flex', alignItems: 'center', padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15, backgroundColor: '#f5f5f5', color: '#888' }}
- >
- {tempUserInfo.account_status === 1 || tempUserInfo.account_status === "1" ? "封禁" : "正常"}
- <span style={{
- display: 'inline-block',
- width: 12,
- height: 12,
- borderRadius: '50%',
- backgroundColor: tempUserInfo.account_status === 1 || tempUserInfo.account_status === "1" ? '#e53935' : '#43a047',
- marginLeft: 10,
- border: '1px solid #b2b2b2',
- }} />
- </span>
+ <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>生日:</b>
+ <input
+ type="date"
+ value={tempUserInfo.birthday}
+ onChange={(e) => handleInputChange("birthday", e.target.value)}
+ style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}
+ />
+ </div>
+ <div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}>
+ <b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>密码:</b>
+ <input
+ type="password"
+ value={tempUserInfo.password || ""}
+ onChange={(e) => handleInputChange("password", e.target.value)}
+ style={{ flex: 1, padding: '6px 10px', borderRadius: 7, border: '1px solid #b2b2b2', minWidth: 0, fontSize: 15 }}
+ />
</div>
<div style={{ marginBottom: 18, display: 'flex', alignItems: 'center' }}>
<b style={{ width: 72, textAlign: 'left', marginRight: 0, fontSize: 16 }}>性别:</b>
@@ -272,61 +187,15 @@
{/* 上传种子列表 */}
<div style={{ gridColumn: '2 / 3', gridRow: '1 / 2', background: '#fff', borderRadius: 18, boxShadow: '0 4px 24px #e0e7ff', padding: '20px' }}>
<h3 style={{ color: '#1a237e', fontSize: 22, marginBottom: 18 }}>个人上传种子列表</h3>
- <div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, minHeight: 60, padding: 12 }}>
- {userSeeds.length === 0 ? (
- <div style={{ color: '#b2b2b2', fontSize: 18, textAlign: 'center' }}>(暂无上传种子)</div>
- ) : (
- <ul style={{ listStyle: 'none', margin: 0, padding: 0 }}>
- {userSeeds.map((seed, idx) => (
- <li
- key={seed.seed_id || idx}
- style={{ display: 'flex', alignItems: 'center', padding: '10px 0', borderBottom: '1px solid #e0e7ff', cursor: 'pointer' }}
- onClick={e => {
- // 阻止点击删除按钮时跳转
- if (e.target.classList.contains('delete-btn')) return;
- navigate(`/torrent/${seed.seed_id}`);
- }}
- >
- <span style={{ flex: 2, fontWeight: 500, color: '#1a237e', textDecoration: 'underline' }}>{seed.title}</span>
- <span style={{ flex: 1, color: '#5c6bc0' }}>{seed.tags}</span>
- <span style={{ flex: 1, color: '#ff9800', textAlign: 'right' }}>人气: {seed.popularity}</span>
- <button
- className="delete-btn"
- style={{ marginLeft: 18, background: '#e53935', color: '#fff', border: 'none', borderRadius: 6, padding: '4px 14px', cursor: 'pointer', fontSize: 14 }}
- onClick={async (e) => {
- e.stopPropagation();
- // const userid = localStorage.getItem("userid");
- const userid = "550e8400-e29b-41d4-a716-446655440000"; // 示例userid
- try {
- const res = await fetch('/api/delete-seed', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ seed_id: seed.seed_id, userid }),
- });
- if (res.ok) {
- setUserSeeds(userSeeds.filter((s, i) => (s.seed_id || i) !== (seed.seed_id || idx)));
- } else {
- alert('删除失败,请重试');
- }
- } catch (err) {
- alert('删除失败,请检查网络');
- }
- }}
- >删除</button>
- </li>
- ))}
- </ul>
- )}
+ <div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#b2b2b2', fontSize: 18 }}>
+ (此处显示上传种子列表)
</div>
</div>
{/* 活跃度模块 */}
<div style={{ gridColumn: '2 / 3', gridRow: '2 / 3', background: '#fff', borderRadius: 18, boxShadow: '0 4px 24px #e0e7ff', padding: '20px' }}>
<h3 style={{ color: '#1a237e', fontSize: 22, marginBottom: 18 }}>活跃度</h3>
- <div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, minHeight: 60, padding: 18, display: 'flex', flexDirection: 'column', gap: 12, fontSize: 18 }}>
- <div>魔力值:<b style={{ color: '#1976d2' }}>{userStats.magic}</b></div>
- <div>上传量:<b style={{ color: '#43a047' }}>{userStats.upload} GB</b></div>
- <div>下载量:<b style={{ color: '#e53935' }}>{userStats.download} GB</b></div>
- <div>上传/下载值:<b style={{ color: '#ff9800' }}>{userStats.ratio}</b></div>
+ <div style={{ border: '1px dashed #b2b2b2', borderRadius: 12, height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#b2b2b2', fontSize: 18 }}>
+ (此处显示活跃度信息)
</div>
</div>
</div>