修复种子评论区错误
Change-Id: Ifaf42c7ba9e71b9f394d7aceaa80fcc29d1d5767
diff --git a/config/routes.ts b/config/routes.ts
index 47b2774..fa049b0 100644
--- a/config/routes.ts
+++ b/config/routes.ts
@@ -167,7 +167,7 @@
},
{
name: '审核种子详情界面',
- path: '/torrent-audit',
+ path: '/torrent-audit/:id',
component: './Torrent/torrentAudit.tsx',
hideInMenu: true,
},
diff --git a/src/pages/Torrent/torrentAudit.tsx b/src/pages/Torrent/torrentAudit.tsx
index 278a3cd..e90af3c 100644
--- a/src/pages/Torrent/torrentAudit.tsx
+++ b/src/pages/Torrent/torrentAudit.tsx
@@ -1,8 +1,9 @@
import React, { useEffect, useState } from 'react';
-import { useSearchParams, useNavigate } from 'react-router-dom';
+import { useParams,useSearchParams, useNavigate } from 'react-router-dom';
import { Card, Button, Spin, Tag, message, Input } from 'antd';
import { ArrowLeftOutlined, CheckOutlined, CloseOutlined } from '@ant-design/icons';
-import { getTorrentInfo,auditTorrent } from '../../services/bt/index';
+import { getTorrentInfo,auditTorrent,downloadTorrent } from '../../services/bt/index';
+
// 状态映射
const statusMap: Record<number, string> = {
@@ -14,8 +15,7 @@
};
const TorrentAudit: React.FC = () => {
- const [searchParams] = useSearchParams();
- const id = searchParams.get('id');
+ const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
@@ -34,7 +34,20 @@
.then(res => setTorrent(res.data))
.finally(() => setLoading(false));
}, [id, navigate]);
-
+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 handleAudit = async (status: 1 | 2) => {
if (status === 2 && !rejectReason.trim()) {
message.warning('请填写拒绝理由');
@@ -102,6 +115,16 @@
<span style={{ marginLeft: 24 }}>下载人数:{torrent.leechers}</span>
<span style={{ marginLeft: 24 }}>完成次数:{torrent.completed}</span>
</div>
+ <div style={{ marginBottom: 16 }}>
+ <Button
+ type="primary"
+ icon={<CheckOutlined />}
+ onClick={() => downloadTorrent(torrent.id)}
+ disabled={!torrent.infoHash}
+ >
+ 下载种子
+ </Button>
+ </div>
<div
style={{
background: '#f6f8fa',
diff --git a/src/pages/Torrent/torrentDetail.tsx b/src/pages/Torrent/torrentDetail.tsx
index 7a25162..a5262fc 100644
--- a/src/pages/Torrent/torrentDetail.tsx
+++ b/src/pages/Torrent/torrentDetail.tsx
@@ -90,7 +90,160 @@
minHeight: '100vh',
padding: '32px 0',
};
+// 创建独立的评论项组件
+interface CommentItemProps {
+ item: any;
+ torrentId: string | undefined;
+ refreshComments: () => void;
+}
+const CommentItem: React.FC<CommentItemProps> = ({ item, torrentId, refreshComments }) => {
+ const [expanded, setExpanded] = useState(false);
+ const [replyContent, setReplyContent] = useState('');
+ const [replying, setReplying] = useState(false);
+ const handleReply = async () => {
+ if (!replyContent.trim()) return;
+ setReplying(true);
+ try {
+ await addComment({
+ torrentId: Number(torrentId),
+ comment: replyContent,
+ pid: item.id
+ });
+ setReplyContent('');
+ setReplying(false);
+ refreshComments();
+ message.success('回复成功');
+ } catch (error) {
+ message.error('回复失败');
+ setReplying(false);
+ }
+ };
+
+ 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={
+ <div>
+ <span style={{ color: '#cbd5e1', fontSize: 16, display: 'block' }}>
+ {item.comment}
+ </span>
+ <div style={{ marginTop: 8 }}>
+ <span style={{ 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>
+ </div>
+ </div>
+ }
+ />
+ {expanded && (
+ <div style={{ width: '100%', marginTop: 12, marginLeft: 56 }}>
+ {item.children?.length > 0 && (
+ <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={
+ <div>
+ <span style={{ color: '#e0e7ef', fontSize: 15, display: 'block' }}>
+ {child.comment}
+ </span>
+ <span style={{ marginLeft: 12, fontSize: 12, color: '#a0aec0' }}>
+ {child.createTime}
+ </span>
+ </div>
+ }
+ />
+ </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', flex: 1 }}
+ />
+ <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>
+ );
+};
+
+// 在return中使用修复后的代码
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 }}>
@@ -144,24 +297,6 @@
<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,
@@ -169,154 +304,51 @@
}}
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}
- />
+
+ <List
+ loading={commentLoading}
+ dataSource={comments.filter((item: any) => item.pid === null)}
+ locale={{ emptyText: '暂无评论' }}
+ renderItem={(item: any) => (
+ <CommentItem
+ item={item}
+ torrentId={id}
+ refreshComments={() => fetchComments(pageNum)}
+ />
+ )}
+ />
+ <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' }}
+ style={{
+ background: 'rgba(255,255,255,0.15)',
+ color: '#fff',
+ border: 'none',
+ flex: 1
+ }}
/>
<Button
type="primary"
icon={<SendOutlined />}
onClick={handleAddComment}
disabled={!comment.trim()}
- style={{ background: 'linear-gradient(90deg,#4299e1,#805ad5)', border: 'none', height: 48 }}
+ style={{
+ background: 'linear-gradient(90deg,#4299e1,#805ad5)',
+ border: 'none',
+ height: 48,
+ alignSelf: 'flex-end'
+ }}
>
发送
</Button>
@@ -329,6 +361,222 @@
</div>
</div>
);
+// 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>
+// ) : (
+// <>
+
+
+
+
+
+
+
+// <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