blob: a955b7bdfe615cc8dcfb456abeb1def0b3740a56 [file] [log] [blame]
刘嘉昕07fee5f2025-06-09 17:18:47 +08001import React, { useEffect, useState } from 'react';
2import { useParams, useNavigate } from 'react-router-dom'; // 添加 useNavigate
3import axios from 'axios';
4import {
5 Row,
6 Col,
7 Card,
8 Descriptions,
9 Table,
10 Typography,
11 Spin,
12 Tag,
13 Button, // 添加 Button 组件
14} from 'antd';
15import { Image as AntdImage } from 'antd';
16import '../TorrentDetail.css'; // 引入样式
17
18const { Title, Text } = Typography;
19
20const TorrentDetail = () => {
21 const { id } = useParams();
22 const navigate = useNavigate(); // 获取导航函数
23 const [torrent, setTorrent] = useState(null);
24 const [seeders, setSeeders] = useState([]);
25 const [loading, setLoading] = useState(true);
26 const [torrentLoading, setTorrentLoading] = useState(true);
27 const [seedersLoading, setSeedersLoading] = useState(false);
28
29 useEffect(() => {
30 const fetchTorrentDetails = async () => {
31 try {
32 setTorrentLoading(true);
33 const torrentRes = await axios.get(`http://localhost:8080/torrent/${id}`);
34 setTorrent(torrentRes.data);
35
36 setSeedersLoading(true);
37 const seedersRes = await axios.get(`http://localhost:8080/torrent/${torrentRes.data.infoHash}/seeders`);
38 setSeeders(seedersRes.data);
39 } catch (err) {
40 console.error('获取数据失败', err);
41 } finally {
42 setTorrentLoading(false);
43 setSeedersLoading(false);
44 setLoading(false);
45 }
46 };
47
48 fetchTorrentDetails();
49 }, [id]);
50
51 const formatSize = (bytes) => {
52 if (bytes === 0) return '0 B';
53 const k = 1024;
54 const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
55 const i = Math.floor(Math.log(bytes) / Math.log(k));
56 return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
57 };
58
59 const formatSpeed = (bytesPerSec) => {
60 if (bytesPerSec < 1024) return bytesPerSec.toFixed(2) + ' B/s';
61 if (bytesPerSec < 1024 * 1024) return (bytesPerSec / 1024).toFixed(2) + ' KB/s';
62 return (bytesPerSec / (1024 * 1024)).toFixed(2) + ' MB/s';
63 };
64
65 const columns = [
66 {
67 title: '用户名',
68 dataIndex: 'username',
69 key: 'username',
70 align: 'center',
71 render: (text) => <Tag color="orange">{text}</Tag>,
72 },
73 {
74 title: '已上传',
75 dataIndex: 'uploaded',
76 key: 'uploaded',
77 align: 'center',
78 render: (text) => <Text>{formatSize(text)}</Text>,
79 },
80 {
81 title: '上传速度',
82 dataIndex: 'uploadSpeed',
83 key: 'uploadSpeed',
84 align: 'center',
85 render: (text) => <Text>{formatSpeed(text)}</Text>,
86 },
87 {
88 title: '已下载',
89 dataIndex: 'downloaded',
90 key: 'downloaded',
91 align: 'center',
92 render: (text) => <Text>{formatSize(text)}</Text>,
93 },
94 {
95 title: '下载速度',
96 dataIndex: 'downloadSpeed',
97 key: 'downloadSpeed',
98 align: 'center',
99 render: (text) => text > 0 ? <Text>{formatSpeed(text)}</Text> : <Text>-</Text>,
100 },
101 {
102 title: '客户端',
103 dataIndex: 'client',
104 key: 'client',
105 align: 'center',
106 },
107 {
108 title: '最后活动',
109 dataIndex: 'lastEvent',
110 key: 'lastEvent',
111 align: 'center',
112 },
113 ];
114
115 if (loading) return <div className="page-wrapper"><Spin size="large" /></div>;
116
117 return (
118 <div className="page-wrapper">
119 {/* 添加返回按钮 */}
120 <div className="mb-4">
121 <Button
122 type="primary"
123 onClick={() => navigate(-1)} // 返回上一页
124 style={{ marginBottom: '16px' }}
125 >
126 返回列表
127 </Button>
128 </div>
129
130 <Row gutter={[16, 16]}>
131 <Col xs={24} md={8}>
132 <Card bordered={false} className="custom-card h-full">
133 {torrent.coverImagePath ? (
134 <AntdImage
135 src={torrent.coverImagePath}
136 alt="Torrent Cover"
137 className="w-full h-64 object-cover rounded"
138 placeholder={
139 <div className="w-full h-64 flex items-center justify-center bg-gray-100">
140 <Spin size="small" />
141 </div>
142 }
143 preview={false}
144 />
145 ) : (
146 <div className="w-full h-64 flex items-center justify-center bg-gray-100 rounded">
147 <Text type="secondary">无封面图片</Text>
148 </div>
149 )}
150 </Card>
151 </Col>
152
153 <Col xs={24} md={16}>
154 <Card className="info-card">
155 <Title level={1} className="info-title">
156 {torrent?.torrentTitle || '加载中...'}
157 </Title>
158
159 <Descriptions
160 bordered
161 column={{ xs: 1, sm: 2 }}
162 size="middle"
163 className="custom-descriptions"
164 labelStyle={{ fontWeight: 'bold', color: '#a15c00', fontSize: '16px' }}
165 contentStyle={{ fontSize: '15px' }}
166 >
167 <Descriptions.Item label="简介">{torrent.description || '暂无简介'}</Descriptions.Item>
168 <Descriptions.Item label="上传人">{torrent.uploader_id || '未知用户'}</Descriptions.Item>
169 <Descriptions.Item label="上传时间">{new Date(torrent.uploadTime).toLocaleString()}</Descriptions.Item>
170 <Descriptions.Item label="文件大小"><Text>{formatSize(torrent.torrentSize)}</Text></Descriptions.Item>
171 <Descriptions.Item label="下载数"><Text>{torrent.downloadCount || 0}</Text></Descriptions.Item>
172 <Descriptions.Item label="做种数"><Text>{seeders.length}</Text></Descriptions.Item>
173 <Descriptions.Item label="文件分辨率">{torrent.dpi || '未知'}</Descriptions.Item>
174 <Descriptions.Item label="文件字幕">{torrent.caption || '无'}</Descriptions.Item>
175 <Descriptions.Item label="最后做种时间">
176 {torrent.lastseed ? new Date(torrent.lastseed).toLocaleString() : '暂无'}
177 </Descriptions.Item>
178 </Descriptions>
179 </Card>
180 </Col>
181 </Row>
182
183 <Card className="custom-card mt-4">
184 <Title level={4} style={{ color: '#d46b08' }}>当前做种用户 ({seeders.length})</Title>
185 {seedersLoading ? (
186 <div className="p-4 text-center"><Spin size="small" /></div>
187 ) : seeders.length > 0 ? (
188 <Table
189 columns={columns}
190 dataSource={seeders}
191 rowKey={(record, index) => index}
192 pagination={false}
193 size="small"
194 className="custom-table"
195 />
196 ) : (
197 <div className="p-4 text-center text-gray-500 bg-gray-50 rounded">
198 当前没有用户在做种
199 </div>
200 )}
201 </Card>
202 </div>
203 );
204};
205
206export default TorrentDetail;