刘嘉昕 | 07fee5f | 2025-06-09 17:18:47 +0800 | [diff] [blame] | 1 | import React, { useState, useEffect } from 'react'; |
| 2 | import { useParams, useNavigate } from 'react-router-dom'; |
| 3 | import { |
| 4 | Descriptions, |
| 5 | Table, |
| 6 | Button, |
| 7 | Modal, |
| 8 | Image, |
| 9 | message, |
| 10 | Spin, |
| 11 | Input, |
| 12 | Select, |
| 13 | Pagination, |
| 14 | Space, |
| 15 | Card |
| 16 | } from 'antd'; |
| 17 | import { ExclamationCircleOutlined } from '@ant-design/icons'; |
| 18 | import axios from 'axios'; |
| 19 | import '../torrentdetailmanage.css'; // 引入样式 |
| 20 | |
| 21 | const { confirm } = Modal; |
| 22 | const { Option } = Select; |
| 23 | |
| 24 | //const { confirm } = Modal; |
| 25 | |
| 26 | const TorrentDetailmanage = () => { |
| 27 | const { id } = useParams(); // 从URL获取种子ID |
| 28 | const navigate = useNavigate(); // 用于返回上一页 |
| 29 | const [torrent, setTorrent] = useState(null); |
| 30 | const [loading, setLoading] = useState(true); |
| 31 | const [error, setError] = useState(null); |
| 32 | const [isLoading, setIsLoading] = useState(false); |
| 33 | |
| 34 | console.log('Torrent ID:', id); |
| 35 | |
| 36 | const currentUserId = 1; // 示例,实际应从认证系统获取 |
| 37 | |
| 38 | |
| 39 | // 格式化日期 |
| 40 | const formatDate = (dateString) => { |
| 41 | if (!dateString) return '未知'; |
| 42 | const date = new Date(dateString); |
| 43 | return date.toLocaleString('zh-CN', { |
| 44 | year: 'numeric', |
| 45 | month: '2-digit', |
| 46 | day: '2-digit', |
| 47 | hour: '2-digit', |
| 48 | minute: '2-digit' |
| 49 | }); |
| 50 | }; |
| 51 | |
| 52 | // 处理删除种子 |
| 53 | const handleDeleteTorrent = async (torrentId) => { |
| 54 | if (!currentUserId) { |
| 55 | message.warning('请先登录'); |
| 56 | return; |
| 57 | } |
| 58 | |
| 59 | confirm({ |
| 60 | title: '确认删除', |
| 61 | icon: <ExclamationCircleOutlined />, |
| 62 | content: '确定要删除这个种子吗?此操作不可恢复!', |
| 63 | onOk: async () => { |
| 64 | try { |
| 65 | await axios.delete(`http://localhost:8080/torrent/delete/${torrentId}`, { |
| 66 | params: { userid: currentUserId } |
| 67 | }); |
| 68 | // 成功删除后,更新状态或返回上一页 |
| 69 | setTorrent(null); // 清空当前种子详情 |
| 70 | navigate(-1); // 返回上一页 |
| 71 | message.success('种子删除成功'); |
| 72 | } catch (err) { |
| 73 | console.error('删除种子失败', err); |
| 74 | if (err.response && err.response.status === 403) { |
| 75 | message.error('无权删除此种子'); |
| 76 | } else { |
| 77 | message.error('删除种子失败'); |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | }); |
| 82 | }; |
| 83 | |
| 84 | |
| 85 | const handleDownloadTorrent = async (torrentId) => { |
| 86 | if (!currentUserId) { |
| 87 | message.warning('请先登录'); |
| 88 | return; |
| 89 | } |
| 90 | |
| 91 | setIsLoading(true); // 开始加载 |
| 92 | try { |
| 93 | // 使用axios发送带有参数的GET请求 |
| 94 | // const response = await axios.get(`http://localhost:8080/torrent/download/${torrentId}`, { |
| 95 | // params: { userId: currentUserId }, // 正确添加请求参数 |
| 96 | // responseType: 'blob' // 重要:指定响应类型为blob以处理文件下载 |
| 97 | // }); |
| 98 | |
| 99 | // // 创建下载链接 |
| 100 | // const url = window.URL.createObjectURL(new Blob([response.data])); |
| 101 | // const link = document.createElement('a'); |
| 102 | // link.href = url; |
| 103 | // //link.setAttribute('download', 'torrent_file.torrent'); // 可以设置为动态文件名 |
| 104 | // document.body.appendChild(link); |
| 105 | // link.click(); |
| 106 | // document.body.removeChild(link); |
| 107 | // window.URL.revokeObjectURL(url); |
| 108 | open(`http://localhost:8080/torrent/download/${torrentId}?userId=${currentUserId}`, '_blank'); |
| 109 | |
| 110 | message.success('种子下载开始'); |
| 111 | } catch (err) { |
| 112 | console.error('下载种子失败', err); |
| 113 | if (err.response?.status === 404) { |
| 114 | message.error('种子不存在'); |
| 115 | } else { |
| 116 | message.error('下载失败: ' + (err.response?.data?.message || err.message)); |
| 117 | } |
| 118 | } finally { |
| 119 | setIsLoading(false); // 结束加载 |
| 120 | } |
| 121 | }; |
| 122 | |
| 123 | |
| 124 | // 格式化文件大小 |
| 125 | const formatFileSize = (bytes) => { |
| 126 | if (bytes === 0) return '0 Bytes'; |
| 127 | const k = 1024; |
| 128 | const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; |
| 129 | const i = Math.floor(Math.log(bytes) / Math.log(k)); |
| 130 | return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; |
| 131 | }; |
| 132 | |
| 133 | // 在组件函数内部添加这个函数 |
| 134 | const getPromotionName = (promotionId) => { |
| 135 | const promotionMap = { |
| 136 | 1: '上传加倍', |
| 137 | 2: '下载减半', |
| 138 | 3: '免费下载', |
| 139 | 0: '无促销' |
| 140 | }; |
| 141 | |
| 142 | return promotionMap[promotionId] || '未知促销'; |
| 143 | }; |
| 144 | |
| 145 | // 获取种子详情 |
| 146 | useEffect(() => { |
| 147 | const fetchTorrentDetail = async () => { |
| 148 | try { |
| 149 | const response = await axios.get(`http://localhost:8080/torrent/${id}`); |
| 150 | if (response.status === 200) { |
| 151 | setTorrent(response.data); |
| 152 | } else { |
| 153 | setError('获取种子详情失败'); |
| 154 | } |
| 155 | } catch (err) { |
| 156 | console.error('获取种子详情失败:', err); |
| 157 | if (err.response) { |
| 158 | if (err.response.status === 404) { |
| 159 | setError('种子不存在'); |
| 160 | } else { |
| 161 | setError('获取种子详情失败: ' + err.response.data); |
| 162 | } |
| 163 | } else { |
| 164 | setError('网络错误,请稍后重试'); |
| 165 | } |
| 166 | } finally { |
| 167 | setLoading(false); |
| 168 | } |
| 169 | }; |
| 170 | |
| 171 | fetchTorrentDetail(); |
| 172 | }, [id]); |
| 173 | |
| 174 | console.log('Torrent Detail:', torrent); |
| 175 | |
| 176 | // 返回上一页 |
| 177 | const handleBack = () => { |
| 178 | navigate(-1); // 返回上一页 |
| 179 | }; |
| 180 | |
| 181 | // 如果正在加载 |
| 182 | if (loading) { |
| 183 | return ( |
| 184 | <div className="flex justify-center items-center h-96"> |
| 185 | <Spin size="large" tip="加载中..." /> |
| 186 | </div> |
| 187 | ); |
| 188 | } |
| 189 | |
| 190 | // 如果有错误 |
| 191 | if (error) { |
| 192 | return ( |
| 193 | <div className="p-6"> |
| 194 | <Card> |
| 195 | <div className="text-center p-6"> |
| 196 | <ExclamationCircleOutlined className="text-2xl text-red-500 mb-4" /> |
| 197 | <h3 className="text-lg font-medium text-red-600 mb-2">错误</h3> |
| 198 | <p className="text-gray-600">{error}</p> |
| 199 | <Button type="primary" onClick={handleBack} className="mt-4"> |
| 200 | 返回 |
| 201 | </Button> |
| 202 | </div> |
| 203 | </Card> |
| 204 | </div> |
| 205 | ); |
| 206 | } |
| 207 | |
| 208 | // 如果种子不存在 |
| 209 | if (!torrent) { |
| 210 | return ( |
| 211 | <div className="p-6"> |
| 212 | <Card> |
| 213 | <div className="text-center p-6"> |
| 214 | <ExclamationCircleOutlined className="text-2xl text-yellow-500 mb-4" /> |
| 215 | <h3 className="text-lg font-medium text-yellow-600 mb-2">种子不存在</h3> |
| 216 | <p className="text-gray-600">抱歉,您查找的种子不存在或已被删除。</p> |
| 217 | <Button type="primary" onClick={handleBack} className="mt-4"> |
| 218 | 返回 |
| 219 | </Button> |
| 220 | </div> |
| 221 | </Card> |
| 222 | </div> |
| 223 | ); |
| 224 | } |
| 225 | |
| 226 | return ( |
| 227 | <div className="torrent-detail-page"> |
| 228 | <Card |
| 229 | className="torrent1-card" |
| 230 | title={<div className="torrent-title">种子详情</div>} |
| 231 | extra={ |
| 232 | <Button type="primary" onClick={handleBack}> |
| 233 | 返回列表 |
| 234 | </Button> |
| 235 | } |
| 236 | > |
| 237 | <Descriptions bordered column={1} size="middle"> |
| 238 | <Descriptions.Item label="ID">{torrent.torrentid}</Descriptions.Item> |
| 239 | |
| 240 | {torrent.coverImagePath && ( |
| 241 | <Descriptions.Item label="封面图片"> |
| 242 | <Image |
| 243 | className="torrent-cover-image" |
| 244 | src={torrent.coverImagePath} |
| 245 | alt="种子封面" |
| 246 | width={260} |
| 247 | height={160} |
| 248 | placeholder={ |
| 249 | <div className="w-60 h-40 bg-gray-200 flex items-center justify-center"> |
| 250 | 加载中... |
| 251 | </div> |
| 252 | } |
| 253 | /> |
| 254 | </Descriptions.Item> |
| 255 | )} |
| 256 | |
| 257 | <Descriptions.Item label="文件名">{torrent.filename}</Descriptions.Item> |
| 258 | <Descriptions.Item label="大小">{formatFileSize(torrent.torrentSize)}</Descriptions.Item> |
| 259 | <Descriptions.Item label="上传者ID">{torrent.uploader_id}</Descriptions.Item> |
| 260 | <Descriptions.Item label="上传时间">{formatDate(torrent.uploadTime)}</Descriptions.Item> |
| 261 | <Descriptions.Item label="下载次数">{torrent.downloadCount}</Descriptions.Item> |
| 262 | <Descriptions.Item label="促销">{getPromotionName(torrent.promotionid)}</Descriptions.Item> |
| 263 | <Descriptions.Item label="描述">{torrent.description || '无描述'}</Descriptions.Item> |
| 264 | </Descriptions> |
| 265 | |
| 266 | <div className="torrent-buttons"> |
| 267 | <Button |
| 268 | danger |
| 269 | onClick={() => handleDeleteTorrent(torrent.torrentid)} |
| 270 | loading={isLoading} |
| 271 | > |
| 272 | 删除 |
| 273 | </Button> |
| 274 | <Button |
| 275 | type="primary" |
| 276 | onClick={() => handleDownloadTorrent(torrent.torrentid)} |
| 277 | loading={isLoading} |
| 278 | > |
| 279 | 下载 |
| 280 | </Button> |
| 281 | </div> |
| 282 | </Card> |
| 283 | </div> |
| 284 | ); |
| 285 | }; |
| 286 | |
| 287 | export default TorrentDetailmanage; |