ybt | 3ec62e4 | 2025-06-11 22:46:22 +0800 | [diff] [blame^] | 1 | import { getTorrentInfo, downloadTorrent } from "@/api/torrents"; |
| 2 | import { useState, useEffect } from "react"; |
| 3 | import { useParams, useLocation } from "react-router-dom"; |
| 4 | import { useAuth } from "../../auth/contexts/AuthContext"; |
| 5 | import { message } from "antd"; |
| 6 | |
| 7 | const TorrentInfo = () => { |
| 8 | const { id } = useParams(); |
| 9 | const location = useLocation(); |
| 10 | const [torrentData, setTorrentData] = useState(null); |
| 11 | const [loading, setLoading] = useState(true); |
| 12 | const [error, setError] = useState(null); |
| 13 | const { user } = useAuth(); |
| 14 | |
| 15 | // 从路由状态或其他方式获取username |
| 16 | const username = user?.username; |
| 17 | |
| 18 | useEffect(() => { |
| 19 | const fetchTorrentInfo = async () => { |
| 20 | if (!id || !username) { |
| 21 | setError('缺少必要参数:ID或用户名'); |
| 22 | setLoading(false); |
| 23 | return; |
| 24 | } |
| 25 | |
| 26 | try { |
| 27 | setLoading(true); |
| 28 | setError(null); |
| 29 | |
| 30 | const response = await getTorrentInfo({ id, username }); |
| 31 | |
| 32 | if (response && response.data) { |
| 33 | setTorrentData(response.data); |
| 34 | } else { |
| 35 | setError('未找到种子信息'); |
| 36 | } |
| 37 | } catch (err) { |
| 38 | console.error('获取种子信息失败:', err); |
| 39 | setError(err.message || '获取种子信息失败'); |
| 40 | } finally { |
| 41 | setLoading(false); |
| 42 | } |
| 43 | }; |
| 44 | |
| 45 | fetchTorrentInfo(); |
| 46 | }, [id, username]); |
| 47 | |
| 48 | // 处理种子下载 |
| 49 | const handleDownload = async () => { |
| 50 | try { |
| 51 | const resourceId = torrentData.resourceId || id; |
| 52 | if (!resourceId) { |
| 53 | message.error('无法获取资源ID'); |
| 54 | return; |
| 55 | } |
| 56 | |
| 57 | message.loading('正在准备下载...', 1); |
| 58 | |
| 59 | // 调用下载API |
| 60 | const response = await downloadTorrent(resourceId, username); |
| 61 | |
| 62 | // 创建下载链接 |
| 63 | const blob = new Blob([response], { type: 'application/x-bittorrent' }); |
| 64 | const url = window.URL.createObjectURL(blob); |
| 65 | |
| 66 | // 创建临时链接并触发下载 |
| 67 | const link = document.createElement('a'); |
| 68 | link.href = url; |
| 69 | link.download = `${torrentData.name || 'torrent'}.torrent`; |
| 70 | document.body.appendChild(link); |
| 71 | link.click(); |
| 72 | |
| 73 | // 清理 |
| 74 | document.body.removeChild(link); |
| 75 | window.URL.revokeObjectURL(url); |
| 76 | |
| 77 | message.success('种子文件下载成功!'); |
| 78 | } catch (error) { |
| 79 | console.error('下载种子文件时出错:', error); |
| 80 | if (error.response) { |
| 81 | const status = error.response.status; |
| 82 | const errorMessage = error.response.data?.message || '未知错误'; |
| 83 | message.error(`下载失败 (${status}): ${errorMessage}`); |
| 84 | } else { |
| 85 | message.error('下载失败:' + (error.message || '网络错误,请重试')); |
| 86 | } |
| 87 | } |
| 88 | }; |
| 89 | |
| 90 | const formatDate = (dateString) => { |
| 91 | try { |
| 92 | const date = new Date(dateString); |
| 93 | return date.toLocaleString('zh-CN', { |
| 94 | year: 'numeric', |
| 95 | month: '2-digit', |
| 96 | day: '2-digit', |
| 97 | hour: '2-digit', |
| 98 | minute: '2-digit', |
| 99 | second: '2-digit' |
| 100 | }); |
| 101 | } catch { |
| 102 | return dateString; |
| 103 | } |
| 104 | }; |
| 105 | |
| 106 | if (loading) { |
| 107 | return ( |
| 108 | <div className="flex justify-center items-center min-h-screen"> |
| 109 | <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div> |
| 110 | <span className="ml-3 text-gray-600">加载中...</span> |
| 111 | </div> |
| 112 | ); |
| 113 | } |
| 114 | |
| 115 | if (error) { |
| 116 | return ( |
| 117 | <div className="max-w-4xl mx-auto p-6"> |
| 118 | <div className="bg-red-50 border border-red-200 rounded-lg p-6"> |
| 119 | <div className="flex items-center"> |
| 120 | <div className="flex-shrink-0"> |
| 121 | <svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor"> |
| 122 | <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" /> |
| 123 | </svg> |
| 124 | </div> |
| 125 | <div className="ml-3"> |
| 126 | <h3 className="text-sm font-medium text-red-800">错误</h3> |
| 127 | <div className="mt-2 text-sm text-red-700">{error}</div> |
| 128 | <div className="mt-2 text-sm text-red-600"> |
| 129 | <p>调试信息:</p> |
| 130 | <p>ID: {id}</p> |
| 131 | <p>用户名: {username}</p> |
| 132 | <p>路径: {location.pathname}</p> |
| 133 | </div> |
| 134 | </div> |
| 135 | </div> |
| 136 | </div> |
| 137 | </div> |
| 138 | ); |
| 139 | } |
| 140 | |
| 141 | if (!torrentData) { |
| 142 | return ( |
| 143 | <div className="max-w-4xl mx-auto p-6"> |
| 144 | <div className="text-center text-gray-500"> |
| 145 | <p>未找到种子信息</p> |
| 146 | </div> |
| 147 | </div> |
| 148 | ); |
| 149 | } |
| 150 | |
| 151 | return ( |
| 152 | <div className="max-w-4xl mx-auto p-6"> |
| 153 | <div className="bg-white shadow-lg rounded-lg overflow-hidden"> |
| 154 | {/* 头部 */} |
| 155 | <div className="bg-gradient-to-r from-blue-500 to-purple-600 px-6 py-4"> |
| 156 | <h1 className="text-2xl font-bold text-white">种子详情</h1> |
| 157 | </div> |
| 158 | |
| 159 | {/* 内容 */} |
| 160 | <div className="p-6"> |
| 161 | <div className="grid grid-cols-1 md:grid-cols-2 gap-6"> |
| 162 | {/* 基本信息 */} |
| 163 | <div className="space-y-4"> |
| 164 | <div className="border-b border-gray-200 pb-4"> |
| 165 | <h2 className="text-lg font-semibold text-gray-800 mb-3">基本信息</h2> |
| 166 | |
| 167 | <div className="space-y-3"> |
| 168 | <div className="flex items-start"> |
| 169 | <span className="text-sm font-medium text-gray-500 w-20 flex-shrink-0">名称:</span> |
| 170 | <span className="text-sm text-gray-900 break-all">{torrentData.name}</span> |
| 171 | </div> |
| 172 | |
| 173 | <div className="flex items-start"> |
| 174 | <span className="text-sm font-medium text-gray-500 w-20 flex-shrink-0">作者:</span> |
| 175 | <span className="text-sm text-gray-900">{torrentData.author}</span> |
| 176 | </div> |
| 177 | |
| 178 | <div className="flex items-start"> |
| 179 | <span className="text-sm font-medium text-gray-500 w-20 flex-shrink-0">资源ID:</span> |
| 180 | <span className="text-sm text-gray-900">{torrentData.resourceId}</span> |
| 181 | </div> |
| 182 | |
| 183 | <div className="flex items-start"> |
| 184 | <span className="text-sm font-medium text-gray-500 w-20 flex-shrink-0">发布时间:</span> |
| 185 | <span className="text-sm text-gray-900">{formatDate(torrentData.publishTime)}</span> |
| 186 | </div> |
| 187 | </div> |
| 188 | </div> |
| 189 | </div> |
| 190 | |
| 191 | {/* 描述信息 */} |
| 192 | <div className="space-y-4"> |
| 193 | <div className="border-b border-gray-200 pb-4"> |
| 194 | <h2 className="text-lg font-semibold text-gray-800 mb-3">描述信息</h2> |
| 195 | <div className="bg-gray-50 rounded-lg p-4"> |
| 196 | <p className="text-sm text-gray-700 whitespace-pre-wrap"> |
| 197 | {torrentData.description || '暂无描述'} |
| 198 | </p> |
| 199 | </div> |
| 200 | </div> |
| 201 | </div> |
| 202 | </div> |
| 203 | |
| 204 | {/* 操作按钮 */} |
| 205 | <div className="mt-8 pt-6 border-t border-gray-200"> |
| 206 | <div className="flex flex-wrap gap-3"> |
| 207 | <button |
| 208 | onClick={handleDownload} |
| 209 | className="px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors duration-200 flex items-center gap-2" |
| 210 | > |
| 211 | <svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"> |
| 212 | <path fillRule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clipRule="evenodd" /> |
| 213 | </svg> |
| 214 | 下载种子 |
| 215 | </button> |
| 216 | <button |
| 217 | onClick={() => window.history.back()} |
| 218 | className="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600 transition-colors duration-200" |
| 219 | > |
| 220 | 返回 |
| 221 | </button> |
| 222 | <button |
| 223 | onClick={() => window.location.reload()} |
| 224 | className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors duration-200" |
| 225 | > |
| 226 | 刷新 |
| 227 | </button> |
| 228 | </div> |
| 229 | </div> |
| 230 | </div> |
| 231 | </div> |
| 232 | </div> |
| 233 | ); |
| 234 | }; |
| 235 | |
| 236 | export default TorrentInfo; |