reset the rebase code
Change-Id: I50bb95e75cd5679667fb6e4053e0d1e60e28f6a5
diff --git a/src/pages/Torrent/torrentDetail.tsx b/src/pages/Torrent/torrentDetail.tsx
new file mode 100644
index 0000000..d841b04
--- /dev/null
+++ b/src/pages/Torrent/torrentDetail.tsx
@@ -0,0 +1,334 @@
+import React, { useEffect, useState } from 'react';
+import { useParams, useNavigate } from 'react-router-dom';
+import { Button, Input, message, Spin, Tag, Card, Avatar, List, Pagination } from 'antd';
+import { DownloadOutlined, ArrowLeftOutlined, SendOutlined } from '@ant-design/icons';
+import {
+ getTorrentInfo,
+ downloadTorrent,
+ addComment,
+ getComments,
+ getCategories,
+} from '../../services/bt/index';
+
+const PAGE_SIZE = 10;
+
+const TorrentDetail: React.FC = () => {
+const { id } = useParams<{ id: string }>();
+const navigate = useNavigate();
+
+const [loading, setLoading] = useState(true);
+const [torrent, setTorrent] = useState<any>(null);
+const [categories, setCategories] = useState<any[]>([]);
+const [comments, setComments] = useState<any[]>([]);
+const [commentLoading, setCommentLoading] = useState(false);
+const [comment, setComment] = useState('');
+const [commentsTotal, setCommentsTotal] = useState(0);
+const [pageNum, setPageNum] = useState(1);
+
+useEffect(() => {
+ setLoading(true);
+ getTorrentInfo({ id: id! })
+ .then((res) => setTorrent(res.data))
+ .finally(() => setLoading(false));
+ getCategories().then((res) => setCategories(res.data || []));
+}, [id]);
+
+useEffect(() => {
+ fetchComments(pageNum);
+ // eslint-disable-next-line
+}, [id, pageNum]);
+
+const fetchComments = (page: number) => {
+ setCommentLoading(true);
+ getComments({ torrentId: Number(id), pageNum: page, pageSize: PAGE_SIZE })
+ .then((res) => {0
+ setComments(res.data?.list || []);
+ setCommentsTotal(res.data?.total || 0);
+ })
+ .finally(() => setCommentLoading(false));
+};
+
+const handleDownload = async () => {
+ try {
+ const res = await downloadTorrent({ id: id! });
+ const blob = new Blob([res], { type: 'application/x-bittorrent' });
+ const url = window.URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = `${torrent?.title || 'torrent'}.torrent`;
+ a.click();
+ window.URL.revokeObjectURL(url);
+ } catch {
+ message.error('下载失败');
+ }
+};
+
+const handleAddComment = async () => {
+ if (!comment.trim()) return;
+ await addComment({ torrentId: Number(id), comment });
+ setComment('');
+ fetchComments(1);
+ setPageNum(1);
+ message.success('评论成功');
+};
+
+const getCategoryName = (catId: number) => {
+ return categories.find((c) => c.id === catId)?.name || '未知分类';
+};
+
+const statusMap: Record<number, string> = {
+ 0: '候选中',
+ 1: '已发布',
+ 2: '审核不通过',
+ 3: '已上架修改重审中',
+ 10: '已下架',
+};
+
+// 星球主题样式
+const planetBg = {
+ background: 'radial-gradient(circle at 60% 40%, #2b6cb0 0%, #1a202c 100%)',
+ minHeight: '100vh',
+ padding: '32px 0',
+};
+
+return (
+ <div style={planetBg}>
+ <div style={{ maxWidth: 900, margin: '0 auto', background: 'rgba(255,255,255,0.08)', borderRadius: 16, boxShadow: '0 8px 32px rgba(0,0,0,0.2)', padding: 24 }}>
+ <Button
+ icon={<ArrowLeftOutlined />}
+ type="link"
+ onClick={() => navigate(-1)}
+ style={{ color: '#fff', marginBottom: 16 }}
+ >
+ 返回
+ </Button>
+ {loading ? (
+ <Spin size="large" />
+ ) : (
+ <>
+ {torrent?.status !== 1 ? (
+ <div style={{ color: '#fff', fontSize: 24, textAlign: 'center', padding: '80px 0' }}>
+ 当前状态:{statusMap[torrent?.status] || '未知状态'}
+ </div>
+ ) : (
+ <>
+ <div style={{ display: 'flex', alignItems: 'center', gap: 24 }}>
+ <Avatar
+ size={96}
+ src={torrent?.cover || 'https://img.icons8.com/color/96/planet.png'}
+ style={{ boxShadow: '0 0 24px #4299e1' }}
+ />
+ <div>
+ <h1 style={{ color: '#fff', fontSize: 32, marginBottom: 8 }}>
+ {torrent?.title}
+ </h1>
+ <div style={{ marginBottom: 8 }}>
+ <Tag color="geekblue">{getCategoryName(torrent?.categoryId)}</Tag>
+ {torrent?.tags?.map((tag: string) => (
+ <Tag key={tag} color="blue">{tag}</Tag>
+ ))}
+ </div>
+ <div style={{ color: '#cbd5e1', marginBottom: 8 }}>
+ 上传者:{torrent?.owner} | 上传时间:{torrent?.createdAt}
+ </div>
+ <Button
+ type="primary"
+ icon={<DownloadOutlined />}
+ onClick={handleDownload}
+ style={{ background: 'linear-gradient(90deg,#4299e1,#805ad5)', border: 'none' }}
+ >
+ 下载种子
+ </Button>
+ </div>
+ </div>
+ <Card
+ style={{
+ marginTop: 32,
+ background: 'rgba(255,255,255,0.12)',
+ border: 'none',
+ borderRadius: 12,
+ color: '#fff',
+ }}
+ title={<span style={{ color: '#fff' }}>种子详情</span>}
+ >
+ <div dangerouslySetInnerHTML={{ __html: torrent?.description || '' }} />
+ <div style={{ marginTop: 16, color: '#cbd5e1' }}>
+ <span>文件大小:{torrent?.size}</span>
+ <span style={{ marginLeft: 24 }}>做种人数:{torrent?.seeders}</span>
+ <span style={{ marginLeft: 24 }}>下载人数:{torrent?.leechers}</span>
+ <span style={{ marginLeft: 24 }}>完成次数:{torrent?.completed}</span>
+ </div>
+ </Card>
+ <Card
+ style={{
+ marginTop: 32,
+ background: 'rgba(255,255,255,0.10)',
+ border: 'none',
+ borderRadius: 12,
+ color: '#fff',
+ }}
+ title={<span style={{ color: '#fff' }}>星球评论</span>}
+ >
+ <List
+ loading={commentLoading}
+ dataSource={comments}
+ locale={{ emptyText: '暂无评论' }}
+ renderItem={(item: any) => {
+ // 只渲染顶级评论(pid为null)
+ if (item.pid !== null) return null;
+ const [expanded, setExpanded] = useState(false);
+ const [replyContent, setReplyContent] = useState('');
+ const [replying, setReplying] = useState(false);
+
+ const handleReply = async () => {
+ if (!replyContent.trim()) return;
+ setReplying(true);
+ await addComment({ torrentId: Number(id), comment: replyContent, pid: item.id });
+ setReplyContent('');
+ setReplying(false);
+ fetchComments(pageNum);
+ message.success('回复成功');
+ };
+
+ return (
+ <List.Item
+ style={{
+ alignItems: 'flex-start',
+ border: 'none',
+ background: 'transparent',
+ padding: '20px 0',
+ borderBottom: '1px solid rgba(255,255,255,0.08)',
+ }}
+ >
+ <List.Item.Meta
+ avatar={
+ <Avatar
+ src={item.avatar ? item.avatar.startsWith('http') ? item.avatar : `${item.avatar}` : 'https://img.icons8.com/color/48/planet.png'}
+ size={48}
+ style={{ boxShadow: '0 2px 8px #4299e1' }}
+ />
+ }
+ title={
+ <span style={{ color: '#fff', fontWeight: 500 }}>
+ {item.username || '匿名用户'}
+ </span>
+ }
+ description={
+ <span style={{ color: '#cbd5e1', fontSize: 16 }}>
+ {item.comment}
+ <span style={{ marginLeft: 16, fontSize: 12, color: '#a0aec0' }}>
+ {item.createTime}
+ </span>
+ <Button
+ type="link"
+ size="small"
+ style={{ marginLeft: 16, color: '#4299e1' }}
+ onClick={() => setExpanded((v) => !v)}
+ >
+ {expanded ? '收起回复' : `展开回复${item.children?.length ? ` (${item.children.length})` : ''}`}
+ </Button>
+ </span>
+ }
+ />
+ {expanded && (
+ <div style={{ width: '100%', marginTop: 12, marginLeft: 56 }}>
+ <List
+ dataSource={item.children}
+ itemLayout="horizontal"
+ locale={{ emptyText: '暂无子评论' }}
+ renderItem={(child: any) => (
+ <List.Item
+ style={{
+ border: 'none',
+ background: 'transparent',
+ padding: '12px 0 0 0',
+ marginLeft: 0,
+ }}
+ >
+ <List.Item.Meta
+ avatar={
+ <Avatar
+ src={child.avatar ? child.avatar.startsWith('http') ? child.avatar : `${child.avatar}` : 'https://img.icons8.com/color/48/planet.png'}
+ size={36}
+ style={{ boxShadow: '0 1px 4px #805ad5' }}
+ />
+ }
+ title={
+ <span style={{ color: '#c3bfff', fontWeight: 500, fontSize: 15 }}>
+ {child.username || '匿名用户'}
+ </span>
+ }
+ description={
+ <span style={{ color: '#e0e7ef', fontSize: 15 }}>
+ {child.comment}
+ <span style={{ marginLeft: 12, fontSize: 12, color: '#a0aec0' }}>
+ {child.createTime}
+ </span>
+ </span>
+ }
+ />
+ </List.Item>
+ )}
+ />
+ <div style={{ display: 'flex', marginTop: 12, gap: 8 }}>
+ <Input.TextArea
+ value={replyContent}
+ onChange={e => setReplyContent(e.target.value)}
+ placeholder="回复该评论"
+ autoSize={{ minRows: 1, maxRows: 3 }}
+ style={{ background: 'rgba(255,255,255,0.15)', color: '#fff', border: 'none' }}
+ />
+ <Button
+ type="primary"
+ icon={<SendOutlined />}
+ loading={replying}
+ onClick={handleReply}
+ disabled={!replyContent.trim()}
+ style={{ background: 'linear-gradient(90deg,#4299e1,#805ad5)', border: 'none', height: 40 }}
+ >
+ 发送
+ </Button>
+ </div>
+ </div>
+ )}
+ </List.Item>
+ );
+ }}
+ />
+ <Pagination
+ style={{ marginTop: 16, textAlign: 'right' }}
+ current={pageNum}
+ pageSize={PAGE_SIZE}
+ total={commentsTotal}
+ onChange={setPageNum}
+ showSizeChanger={false}
+ />
+ <div style={{ display: 'flex', marginTop: 24, gap: 8 }}>
+ <Input.TextArea
+ value={comment}
+ onChange={e => setComment(e.target.value)}
+ placeholder="在星球上留下你的评论吧~"
+ autoSize={{ minRows: 2, maxRows: 4 }}
+ style={{ background: 'rgba(255,255,255,0.15)', color: '#fff', border: 'none' }}
+ />
+ <Button
+ type="primary"
+ icon={<SendOutlined />}
+ onClick={handleAddComment}
+ disabled={!comment.trim()}
+ style={{ background: 'linear-gradient(90deg,#4299e1,#805ad5)', border: 'none', height: 48 }}
+ >
+ 发送
+ </Button>
+ </div>
+ </Card>
+ </>
+ )}
+ </>
+ )}
+ </div>
+ </div>
+);
+};
+
+export default TorrentDetail;
\ No newline at end of file