22301009 | 1e2aea7 | 2025-06-08 16:35:54 +0800 | [diff] [blame] | 1 | import React, { useEffect, useState } from 'react'; |
| 2 | import { useRoute } from 'wouter'; // ✅ 修改这里 |
| 3 | import axios from 'axios'; |
| 4 | import Header from '../../../components/Header'; |
| 5 | import './PlaylistDetailPage.css'; |
| 6 | import { useUser } from '../../../context/UserContext'; |
| 7 | import toast from 'react-hot-toast'; |
| 8 | import { confirmAlert } from 'react-confirm-alert'; |
| 9 | import 'react-confirm-alert/src/react-confirm-alert.css'; |
| 10 | |
| 11 | const PlaylistDetailPage = () => { |
| 12 | const [match, params] = useRoute('/playlist/:id'); // ✅ 使用 useRoute |
| 13 | const id = params?.id; |
| 14 | const { user } = useUser(); |
| 15 | const userId = user?.userId; |
| 16 | |
| 17 | const [detail, setDetail] = useState(null); |
| 18 | const [loading, setLoading] = useState(true); |
| 19 | const [error, setError] = useState(''); |
| 20 | |
| 21 | const fetchDetail = async () => { |
| 22 | if (!id) { |
| 23 | setError('无效的片单ID'); |
| 24 | setLoading(false); |
| 25 | return; |
| 26 | } |
| 27 | if (!userId) { |
| 28 | setError('请先登录'); |
| 29 | setLoading(false); |
| 30 | return; |
| 31 | } |
| 32 | |
| 33 | try { |
| 34 | setLoading(true); |
| 35 | setError(''); |
| 36 | const res = await axios.get(`/playlist/${id}`, { |
| 37 | params: { userId } |
| 38 | }); |
| 39 | if (res.data.code === 0) { |
| 40 | setDetail(res.data.data); |
| 41 | } else { |
| 42 | setError(res.data.msg || '加载失败'); |
| 43 | } |
| 44 | } catch (err) { |
| 45 | console.error(err); |
| 46 | setError('请求失败,请检查网络'); |
| 47 | } finally { |
| 48 | setLoading(false); |
| 49 | } |
| 50 | }; |
| 51 | |
| 52 | useEffect(() => { |
| 53 | if (id && userId) fetchDetail(); // ✅ 防止空 ID 反复触发 |
| 54 | }, [id, userId]); |
| 55 | |
| 56 | if (loading) return <div>加载中...</div>; |
| 57 | |
| 58 | if (error) { |
| 59 | return ( |
| 60 | <div className="error"> |
| 61 | {error} |
| 62 | <button onClick={fetchDetail} className="retry-button">重试</button> |
| 63 | </div> |
| 64 | ); |
| 65 | } |
| 66 | |
| 67 | return ( |
| 68 | <div className="playlist-detail"> |
| 69 | <Header /> |
| 70 | <h1>{detail.title}</h1> |
| 71 | <img |
| 72 | src={detail.coverUrl || '/default-cover.jpg'} |
| 73 | alt={detail.title} |
| 74 | onError={e => { e.target.src = '/default-cover.jpg'; }} |
Krishya | dbfadaa | 2025-06-09 20:33:15 +0800 | [diff] [blame^] | 75 | className="cover-img" |
22301009 | 1e2aea7 | 2025-06-08 16:35:54 +0800 | [diff] [blame] | 76 | /> |
| 77 | <p>{detail.description}</p> |
| 78 | |
| 79 | <h3>包含的种子:</h3> |
| 80 | {detail.torrentList && detail.torrentList.length > 0 ? ( |
| 81 | <ul> |
| 82 | {detail.torrentList.map(seed => ( |
| 83 | <li key={seed.id}>{seed.title}</li> |
| 84 | ))} |
| 85 | </ul> |
| 86 | ) : ( |
| 87 | <p>暂无种子数据</p> |
| 88 | )} |
| 89 | </div> |
| 90 | ); |
| 91 | }; |
| 92 | export default PlaylistDetailPage; |