blob: 8ea3f6b5d213397c96089ccbb04c8fb730e141d8 [file] [log] [blame] [edit]
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { API_BASE_URL } from "./config";
// 求种任务示例数据(作为后备数据)
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, setBeg] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [seeds, setSeeds] = useState([]);
const [seedInfoMap, setSeedInfoMap] = useState({});
const [showForm, setShowForm] = useState(false);
const [userSeeds, setUserSeeds] = useState([]);
const [loadingUserSeeds, setLoadingUserSeeds] = useState(false);
const [formData, setFormData] = useState({
selectedSeedId: "",
});
// 从后端获取求种详情
const fetchBegSeedDetail = async () => {
setLoading(true);
try {
const response = await fetch(`${API_BASE_URL}/api/begseed-detail?begid=${begid}`);
if (!response.ok) {
throw new Error(`请求失败,状态码: ${response.status}`);
}
const data = await response.json();
// 格式化数据以匹配前端期望的格式
const formattedBeg = {
beg_id: data.beg_id || data.begid || data.id,
info: data.info || data.description || data.content,
beg_count: data.beg_count || data.begCount || 1,
reward_magic: data.reward_magic || data.rewardMagic || data.magic,
deadline: data.deadline || data.endtime,
has_match: data.has_match || data.hasMatch || data.completed || 0,
};
setBeg(formattedBeg);
setError(null);
} catch (err) {
console.error('获取求种详情失败:', err);
setError(err.message);
// 如果API调用失败,使用默认数据
const fallbackBeg = begSeedList.find((b) => b.beg_id === begid);
setBeg(fallbackBeg || null);
} finally {
setLoading(false);
}
};
// 从后端获取已提交的种子列表
const fetchSubmittedSeeds = async () => {
try {
const response = await fetch(`${API_BASE_URL}/api/begseed-submissions?begid=${begid}`);
if (!response.ok) {
throw new Error(`请求失败,状态码: ${response.status}`);
}
const data = await response.json();
console.log('获取到的种子提交数据:', data);
// 新的数据结构:数组,每个元素包含seed对象和votes字段
const submissions = Array.isArray(data) ? data : [];
// 格式化种子数据
const formattedSeeds = submissions.map(item => ({
seed_id: item.seed?.seedid || item.seedid,
beg_id: begid,
votes: item.votes || 0, // 每个种子单独的投票数
title: item.seed?.title || item.title || "未知标题",
subtitle: item.seed?.subtitle || item.subtitle || "无简介",
seedsize: item.seed?.seedsize || item.seedsize,
downloadtimes: item.seed?.downloadtimes || item.downloadtimes || 0,
url: item.seed?.url || item.url,
user: item.seed?.user || item.user
}));
// 构建种子信息映射
const newSeedInfoMap = {};
submissions.forEach(item => {
const seedId = item.seed?.seedid || item.seedid;
if (seedId) {
newSeedInfoMap[seedId] = {
title: item.seed?.title || item.title || "未知标题",
subtitle: item.seed?.subtitle || item.subtitle || "无简介",
};
}
});
setSeeds(formattedSeeds);
setSeedInfoMap(newSeedInfoMap);
} catch (err) {
console.error('获取种子提交列表失败:', err);
// 如果API调用失败,使用默认数据
const fallbackSeeds = submitSeedList.filter((s) => s.beg_id === begid);
setSeeds(fallbackSeeds);
setSeedInfoMap(seedInfoMap);
}
};
// 组件挂载时获取数据
useEffect(() => {
fetchBegSeedDetail();
fetchSubmittedSeeds();
}, [begid]);
// 加载状态
if (loading) {
return (
<div className="container">
<div style={{ textAlign: "center", margin: "40px 0", color: "#666" }}>
正在加载求种详情...
</div>
</div>
);
}
// 未找到求种信息
if (!beg) {
return (
<div className="container">
<div style={{ padding: 40, textAlign: "center", color: "#666" }}>
未找到该求种信息
</div>
</div>
);
}
const isExpired = new Date(beg.deadline) < new Date();
const isFinished = beg.has_match === 1;
const isActive = !isExpired && !isFinished;
// 获取用户的所有种子
const fetchUserSeeds = async () => {
setLoadingUserSeeds(true);
try {
// 获取用户ID
const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
const userId = match ? match[2] : null;
if (!userId) {
alert("请先登录后再获取种子列表");
setLoadingUserSeeds(false);
return;
}
const response = await fetch(`${API_BASE_URL}/api/user-seeds?userid=${userId}`);
if (!response.ok) {
throw new Error(`请求失败,状态码: ${response.status}`);
}
const data = await response.json();
// 格式化种子数据
const formattedSeeds = Array.isArray(data) ? data.map(seed => ({
seedid: seed.seedid || seed.id,
title: seed.title || "未知标题",
subtitle: seed.subtitle || "无简介",
seedsize: seed.seedsize,
downloadtimes: seed.downloadtimes || 0,
url: seed.url
})) : [];
setUserSeeds(formattedSeeds);
} catch (err) {
console.error('获取用户种子失败:', err);
alert(`获取种子列表失败: ${err.message}`);
} finally {
setLoadingUserSeeds(false);
}
};
// 投票功能(发送到后端)
const handleVote = async (seed_id) => {
try {
// 获取用户ID
const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
const userId = match ? match[2] : null;
if (!userId) {
alert("请先登录后再投票");
return;
}
const response = await fetch(`${API_BASE_URL}/api/vote-seed`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userid: userId,
seedid: seed_id,
begid: begid,
}),
});
if (response.ok) {
// 投票成功,重新获取数据以更新投票计数
await fetchSubmittedSeeds();
alert("投票成功!");
} else if (response.status === 409) {
alert("您已投过票,不能重复投票");
}
else {
const errorData = await response.json();
alert(`投票失败: ${errorData.message || '未知错误'}`);
}
} catch (err) {
console.error('投票失败:', err);
// 如果后端调用失败,更新本地状态作为后备
setSeeds((prev) =>
prev.map((s) =>
s.seed_id === seed_id ? { ...s, votes: s.votes + 1 } : s
)
);
alert("投票成功(前端演示)");
}
};
// 上传表单处理
const handleFormChange = (e) => {
const { name, value } = e.target;
setFormData((f) => ({ ...f, [name]: value }));
};
const handleSubmitSeed = async (e) => {
e.preventDefault();
if (!formData.selectedSeedId) {
alert("请选择一个种子");
return;
}
try {
// 获取用户ID
const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
const userId = match ? match[2] : null;
if (!userId) {
alert("请先登录后再提交种子");
return;
}
// console.log('提交种子数据:', {
// userid: userId,
// begid: begid,
// seedid: formData.selectedSeedId,
// });
const response = await fetch(`${API_BASE_URL}/api/submit-seed`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userid: userId,
begid: begid,
seedid: formData.selectedSeedId,
}),
});
if (response.ok) {
// 提交成功,重新获取所有数据以刷新页面
await Promise.all([
fetchBegSeedDetail(),
fetchSubmittedSeeds()
]);
setShowForm(false);
setFormData({ selectedSeedId: "" });
setUserSeeds([]);
alert("提交成功!");
} else {
const errorData = await response.json();
alert(`提交失败: ${errorData.message || '未知错误'}`);
}
} catch (err) {
console.error('提交种子失败:', err);
// 如果后端调用失败,使用前端演示逻辑
const newSeedId = "seed" + Math.floor(Math.random() * 10000);
// 从用户种子列表中找到选中种子的信息
const selectedSeed = userSeeds.find(seed => seed.seedid === formData.selectedSeedId);
setSeeds((prev) => [
...prev,
{
beg_id: begid,
seed_id: newSeedId,
votes: 0,
title: selectedSeed?.title || "未知标题",
subtitle: selectedSeed?.subtitle || "无简介",
seedsize: selectedSeed?.seedsize,
downloadtimes: selectedSeed?.downloadtimes || 0,
url: selectedSeed?.url,
user: { username: "当前用户" }
},
]);
setSeedInfoMap(prev => ({
...prev,
[newSeedId]: {
title: selectedSeed?.title || "未知标题",
subtitle: selectedSeed?.subtitle || "无简介",
}
}));
setShowForm(false);
setFormData({ selectedSeedId: "" });
setUserSeeds([]);
alert("提交成功(前端演示)");
}
};
return (
<div className="container">
<h1 style={{ margin: "24px 0 32px 0", color: "#1976d2" }}>
求种详情
</h1>
{/* 错误状态 */}
{error && (
<div style={{
textAlign: "center",
margin: "20px 0",
padding: "10px",
background: "#ffebee",
color: "#c62828",
borderRadius: "4px"
}}>
加载失败: {error} (已显示默认数据)
</div>
)}
<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: 1000, margin: "0 auto" }}>
<thead>
<tr>
<th>标题</th>
<th>简介</th>
<th>文件大小</th>
<th>下载次数</th>
<th>投票数</th>
<th>上传者</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{seeds.length === 0 ? (
<tr>
<td colSpan={7} style={{ textAlign: "center" }}>暂无提交的种子</td>
</tr>
) : (
seeds.map((s) => (
<tr key={s.seed_id}>
<td>
<a href={`/torrent/${s.seed_id}`} style={{ color: '#1a237e', textDecoration: 'none' }}>
{s.title}
</a>
</td>
<td>{s.subtitle || "无简介"}</td>
<td>{s.seedsize ? `${s.seedsize} MB` : "未知"}</td>
<td>{s.downloadtimes || 0}</td>
<td style={{ fontWeight: 'bold', color: '#1976d2' }}>{s.votes || 0}</td>
<td>{s.user?.username || "未知用户"}</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>
{/* 显示总投票数 */}
{seeds.length > 0 && (
<div style={{ textAlign: "center", margin: "16px 0", color: "#666" }}>
总投票数: {seeds.reduce((total, seed) => total + (seed.votes || 0), 0)}
</div>
)}
{isActive && (
<div style={{ margin: "32px 0", textAlign: "center" }}>
<button
onClick={() => {
setShowForm(true);
fetchUserSeeds();
}}
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>
{/* 加载用户种子状态 */}
{loadingUserSeeds && (
<div style={{ textAlign: "center", margin: "16px 0", color: "#666" }}>
正在加载您的种子列表...
</div>
)}
{/* 选择已有种子 */}
{userSeeds.length > 0 ? (
<div style={{ marginBottom: 24 }}>
<div style={{ marginBottom: 16 }}>
<label style={{ display: "inline-block", width: 80, fontWeight: 500 }}>选择种子:</label>
<select
name="selectedSeedId"
value={formData.selectedSeedId}
onChange={handleFormChange}
style={{
padding: "8px 12px",
borderRadius: 6,
border: "1px solid #b2d8ea",
width: 300,
background: "#fff",
fontSize: 14,
}}
>
<option value="">请选择一个种子</option>
{userSeeds.map((seed) => (
<option key={seed.seedid} value={seed.seedid}>
{seed.title} - {seed.subtitle || "无简介"} ({seed.seedsize ? `${seed.seedsize} MB` : "未知大小"})
</option>
))}
</select>
</div>
{formData.selectedSeedId && (
<div style={{
padding: 12,
background: "#e8f5e8",
borderRadius: 6,
border: "1px solid #4caf50",
color: "#2e7d32"
}}>
已选择种子,点击提交即可使用此种子
</div>
)}
</div>
) : (
!loadingUserSeeds && (
<div style={{
textAlign: "center",
margin: "20px 0",
padding: "16px",
background: "#fff3cd",
color: "#856404",
border: "1px solid #ffeaa7",
borderRadius: 6
}}>
您还没有上传过种子,无法参与悬赏
</div>
)
)}
<form onSubmit={handleSubmitSeed}>
<div style={{ marginTop: 18 }}>
<button
type="submit"
disabled={!formData.selectedSeedId}
style={{
background: formData.selectedSeedId ? "#1976d2" : "#b0b0b0",
color: "#fff",
border: "none",
borderRadius: 6,
padding: "8px 28px",
fontWeight: 500,
fontSize: 16,
marginRight: 18,
cursor: formData.selectedSeedId ? "pointer" : "not-allowed",
}}
>
提交种子
</button>
<button
type="button"
onClick={() => {
setShowForm(false);
setFormData({ selectedSeedId: "" });
setUserSeeds([]);
}}
style={{
background: "#b0b0b0",
color: "#fff",
border: "none",
borderRadius: 6,
padding: "8px 28px",
fontWeight: 500,
fontSize: 16,
cursor: "pointer",
}}
>
取消
</button>
</div>
</form>
</div>
)}
</div>
);
}