| import React, { useEffect, useState } from 'react'; |
| 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,downloadTorrent } from '../../services/bt/index'; |
| |
| |
| // 状态映射 |
| const statusMap: Record<number, string> = { |
| 0: '审核中', |
| 1: '已发布', |
| 2: '审核不通过', |
| 3: '已上架修改重审中', |
| 10: '已下架', |
| }; |
| |
| const TorrentAudit: React.FC = () => { |
| const { id } = useParams<{ id: string }>(); |
| const navigate = useNavigate(); |
| |
| const [loading, setLoading] = useState(true); |
| const [torrent, setTorrent] = useState<any>(null); |
| const [auditLoading, setAuditLoading] = useState(false); |
| const [rejectReason, setRejectReason] = useState(''); |
| |
| useEffect(() => { |
| if (!id) { |
| message.error('未指定种子ID'); |
| navigate(-1); |
| return; |
| } |
| setLoading(true); |
| getTorrentInfo({ id }) |
| .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('请填写拒绝理由'); |
| return; |
| } |
| setAuditLoading(true); |
| try { |
| await auditTorrent({ |
| id: Number(id), |
| status, |
| remark: status === 2 ? rejectReason.trim() : undefined, |
| }); |
| message.success(status === 1 ? '审核通过' : '审核拒绝'); |
| navigate(-1); |
| } catch { |
| message.error('操作失败'); |
| } finally { |
| setAuditLoading(false); |
| } |
| }; |
| |
| return ( |
| <div style={{ minHeight: '100vh', background: '#f4f8ff', padding: 32 }}> |
| <div style={{ maxWidth: 800, margin: '0 auto' }}> |
| <Button |
| icon={<ArrowLeftOutlined />} |
| type="link" |
| onClick={() => navigate(-1)} |
| style={{ marginBottom: 16 }} |
| > |
| 返回 |
| </Button> |
| <Card |
| loading={loading} |
| title={ |
| <span> |
| 审核种子 |
| {torrent && ( |
| <Tag color={torrent.status === 0 ? 'orange' : torrent.status === 1 ? 'green' : 'red'} style={{ marginLeft: 16 }}> |
| {statusMap[torrent.status]} |
| </Tag> |
| )} |
| </span> |
| } |
| > |
| {loading ? ( |
| <Spin /> |
| ) : !torrent ? ( |
| <div>未找到种子信息</div> |
| ) : ( |
| <> |
| <h2>{torrent.title}</h2> |
| <div style={{ marginBottom: 8 }}> |
| <Tag color="blue">{torrent.categoryName || '未知分类'}</Tag> |
| {torrent.tags?.map((tag: string) => ( |
| <Tag key={tag}>{tag}</Tag> |
| ))} |
| </div> |
| <div style={{ color: '#888', marginBottom: 8 }}> |
| 上传者:{torrent.owner} | 上传时间:{torrent.createdAt} |
| </div> |
| <div style={{ marginBottom: 16 }}> |
| <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> |
| <div style={{ marginBottom: 16 }}> |
| <Button |
| type="primary" |
| icon={<CheckOutlined />} |
| onClick={() => downloadTorrent(torrent.id)} |
| disabled={!torrent.infoHash} |
| > |
| 下载种子 |
| </Button> |
| </div> |
| <div |
| style={{ |
| background: '#f6f8fa', |
| padding: 16, |
| borderRadius: 8, |
| marginBottom: 24, |
| minHeight: 80, |
| }} |
| dangerouslySetInnerHTML={{ __html: torrent.description || '' }} |
| /> |
| {torrent.status === 0 ? ( |
| <> |
| <div style={{ display: 'flex', gap: 16, alignItems: 'center', marginBottom: 16 }}> |
| <Button |
| type="primary" |
| icon={<CheckOutlined />} |
| loading={auditLoading} |
| onClick={() => handleAudit(1)} |
| > |
| 审核通过 |
| </Button> |
| <Button |
| danger |
| icon={<CloseOutlined />} |
| loading={auditLoading} |
| onClick={() => handleAudit(2)} |
| > |
| 审核拒绝 |
| </Button> |
| <Input.TextArea |
| value={rejectReason} |
| onChange={e => setRejectReason(e.target.value)} |
| placeholder="拒绝理由(仅拒绝时填写)" |
| autoSize={{ minRows: 1, maxRows: 3 }} |
| style={{ width: 260 }} |
| disabled={auditLoading} |
| /> |
| </div> |
| </> |
| ) : ( |
| <div style={{ color: '#888', marginTop: 16 }}> |
| 当前状态:{statusMap[torrent.status]} |
| {torrent.status === 2 && torrent.reason && ( |
| <div style={{ color: '#d4380d', marginTop: 8 }}>拒绝理由:{torrent.reason}</div> |
| )} |
| </div> |
| )} |
| </> |
| )} |
| </Card> |
| </div> |
| </div> |
| ); |
| }; |
| |
| export default TorrentAudit; |