美化前端

Change-Id: I46437caf832dd8f18358354f024724f7e31524cb
diff --git a/src/pages/Torrent/torrentAudit.tsx b/src/pages/Torrent/torrentAudit.tsx
new file mode 100644
index 0000000..278a3cd
--- /dev/null
+++ b/src/pages/Torrent/torrentAudit.tsx
@@ -0,0 +1,160 @@
+import React, { useEffect, useState } from 'react';
+import { 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';
+
+// 状态映射
+const statusMap: Record<number, string> = {
+    0: '审核中',
+    1: '已发布',
+    2: '审核不通过',
+    3: '已上架修改重审中',
+    10: '已下架',
+};
+
+const TorrentAudit: React.FC = () => {
+    const [searchParams] = useSearchParams();
+    const id = searchParams.get('id');
+    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 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={{
+                                    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;
\ No newline at end of file
diff --git a/src/pages/Torrent/torrentAuditList.tsx b/src/pages/Torrent/torrentAuditList.tsx
new file mode 100644
index 0000000..7c30eb8
--- /dev/null
+++ b/src/pages/Torrent/torrentAuditList.tsx
@@ -0,0 +1,333 @@
+import React, { useEffect, useState } from "react";
+import { styled } from "@mui/material/styles";
+
+import { getCategories, getTorrentList } from "../../services/bt/index";
+import {
+Box,
+Button,
+Card,
+CardContent,
+Chip,
+CircularProgress,
+Container,
+MenuItem,
+Pagination,
+Select,
+Typography,
+} from "@mui/material";
+
+// 星空背景
+const StarBg = styled("div")({
+minHeight: "100vh",
+width: "auto",
+background: "radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%)",
+overflow: "auto",
+position: "relative",
+top: 0,
+left: 0,
+"&:before, &:after": {
+    content: '""',
+    position: "absolute",
+    top: 0,
+    left: 0,
+    width: "100%",
+    height: "100%",
+    pointerEvents: "none",
+},
+"&:before": {
+    background: `
+        radial-gradient(1px 1px at 20% 30%, rgba(255,255,255,0.8), rgba(255,255,255,0)),
+        radial-gradient(1px 1px at 40% 70%, rgba(255,255,255,0.8), rgba(255,255,255,0)),
+        radial-gradient(1.5px 1.5px at 60% 20%, rgba(255,255,255,0.9), rgba(255,255,255,0)),
+        radial-gradient(1.5px 1.5px at 80% 90%, rgba(255,255,255,0.9), rgba(255,255,255,0))
+    `,
+    backgroundRepeat: "repeat",
+    backgroundSize: "200px 200px",
+    animation: "twinkle 10s infinite ease-in-out",
+},
+"&:after": {
+    background: `
+        radial-gradient(1px 1px at 70% 40%, rgba(255,255,255,0.7), rgba(255,255,255,0)),
+        radial-gradient(1.2px 1.2px at 10% 80%, rgba(255,255,255,0.7), rgba(255,255,255,0)),
+        radial-gradient(1.5px 1.5px at 30% 60%, rgba(255,255,255,0.8), rgba(255,255,255,0))
+    `,
+    backgroundRepeat: "repeat",
+    backgroundSize: "300px 300px",
+    animation: "twinkle 15s infinite 5s ease-in-out",
+},
+"@keyframes twinkle": {
+    "0%, 100%": { opacity: 0.3 },
+    "50%": { opacity: 0.8 },
+}
+});
+
+const CategoryBar = styled(Box)({
+display: "flex",
+gap: 12,
+alignItems: "center",
+marginBottom: 24,
+flexWrap: "wrap",
+});
+
+const TorrentCard = styled(Card)({
+background: "rgba(30, 41, 59, 0.85)",
+color: "#fff",
+borderRadius: 16,
+boxShadow: "0 4px 24px 0 rgba(0,0,0,0.4)",
+border: "1px solid #334155",
+transition: "transform 0.2s",
+"&:hover": {
+    transform: "scale(1.025)",
+    boxShadow: "0 8px 32px 0 #0ea5e9",
+},
+});
+
+const sortOptions = [
+{ label: "最新", value: { sortField: "createTime", sortDirection: "desc" } },
+{ label: "下载量", value: { sortField: "completions", sortDirection: "desc" } },
+{ label: "推荐", value: { sortField: "seeders", sortDirection: "desc" } },
+];
+
+const statusMap: Record<number, string> = {
+0: '审核中',
+1: '已发布',
+2: '审核不通过',
+3: '已上架修改重审中',
+10: '已下架',
+};
+
+const PAGE_SIZE = 20;
+
+const TorrentAuditListPage: React.FC = () => {
+const [categories, setCategories] = useState<
+    { id: number; name: string; remark?: string | null; type?: number | null }[]
+>([]);
+const [selectedCat, setSelectedCat] = useState<number | null>(null);
+const [sort, setSort] = useState(sortOptions[0].value);
+const [torrents, setTorrents] = useState<any[]>([]);
+const [loading, setLoading] = useState(false);
+const [page, setPage] = useState(1);
+const [total, setTotal] = useState(0);
+
+useEffect(() => {
+    getCategories().then((res) => {
+        setCategories(res.data || []);
+    });
+}, []);
+
+useEffect(() => {
+    setLoading(true);
+    getTorrentList({
+        category: selectedCat !== null ? String(selectedCat) : undefined,
+        sortField: sort.sortField,
+        sortDirection: sort.sortDirection,
+        pageNum: page,
+        pageSize: PAGE_SIZE,
+    })
+        .then((res) => {
+            setTorrents(res.data || []);
+            setTotal(res.page?.total || 0);
+        })
+        .finally(() => setLoading(false));
+}, [selectedCat, sort, page]);
+
+return (
+    <StarBg>
+        <Container maxWidth="lg" sx={{ pt: 6, pb: 6, position: "relative" }}>
+            <Typography
+                variant="h3"
+                sx={{
+                    color: "#fff",
+                    fontWeight: 700,
+                    mb: 3,
+                    letterSpacing: 2,
+                    textShadow: "0 2px 16px #0ea5e9",
+                }}
+            >
+                ThunderHub 种子审核
+            </Typography>
+            <CategoryBar>
+                <Chip
+                    label="全部"
+                    color={selectedCat === null ? "primary" : "default"}
+                    onClick={() => {
+                        setSelectedCat(null);
+                        setPage(1);
+                    }}
+                    sx={{
+                        fontWeight: 600,
+                        fontSize: 16,
+                        color: selectedCat === null ? undefined : "#fff",
+                    }}
+                />
+                {categories.map((cat) => (
+                    <Chip
+                        key={cat.id}
+                        label={cat.name}
+                        color={selectedCat === cat.id ? "primary" : "default"}
+                        onClick={() => {
+                            setSelectedCat(cat.id);
+                            setPage(1);
+                        }}
+                        sx={{
+                            fontWeight: 600,
+                            fontSize: 16,
+                            color: selectedCat === cat.id ? undefined : "#fff",
+                        }}
+                    />
+                ))}
+                <Box sx={{ flex: 1 }} />
+                <Select
+                    size="small"
+                    value={JSON.stringify(sort)}
+                    onChange={(e) => {
+                        setSort(JSON.parse(e.target.value));
+                        setPage(1);
+                    }}
+                    sx={{
+                        color: "#fff",
+                        background: "#1e293b",
+                        borderRadius: 2,
+                        ".MuiOutlinedInput-notchedOutline": { border: 0 },
+                        minWidth: 120,
+                    }}
+                >
+                    {sortOptions.map((opt) => (
+                        <MenuItem key={opt.label} value={JSON.stringify(opt.value)}>
+                            {opt.label}
+                        </MenuItem>
+                    ))}
+                </Select>
+            </CategoryBar>
+            {loading ? (
+                <Box sx={{ display: "flex", justifyContent: "center", mt: 8 }}>
+                    <CircularProgress color="info" />
+                </Box>
+            ) : (
+                <>
+                    <Box
+                        sx={{
+                            display: "flex",
+                            flexWrap: "wrap",
+                            gap: 3,
+                            justifyContent: { xs: "center", md: "flex-start" },
+                        }}
+                    >
+                        {torrents.map((torrent) => (
+                            <Box
+                                key={torrent.id}
+                                sx={{
+                                    flex: "1 1 320px",
+                                    maxWidth: { xs: "100%", sm: "48%", md: "32%" },
+                                    minWidth: 300,
+                                    mb: 3,
+                                    display: "flex",
+                                    cursor: "pointer",
+                                }}
+                                onClick={() => window.open(`/torrent-audit/${torrent.id}`, "_self")}
+                            >
+                                <TorrentCard sx={{ width: "100%" }}>
+                                    <CardContent>
+                                        <Typography
+                                            variant="h6"
+                                            sx={{
+                                                color: "#38bdf8",
+                                                fontWeight: 700,
+                                                mb: 1,
+                                                textOverflow: "ellipsis",
+                                                overflow: "hidden",
+                                                whiteSpace: "nowrap",
+                                            }}
+                                            title={torrent.title}
+                                        >
+                                            {torrent.title}
+                                        </Typography>
+                                        <Box
+                                            sx={{
+                                                display: "flex",
+                                                gap: 1,
+                                                alignItems: "center",
+                                                mb: 1,
+                                                flexWrap: "wrap",
+                                            }}
+                                        >
+                                            <Chip
+                                                size="small"
+                                                label={
+                                                    categories.find((c) => c.id === torrent.category)?.name ||
+                                                    "未知"
+                                                }
+                                                sx={{
+                                                    background: "#0ea5e9",
+                                                    color: "#fff",
+                                                    fontWeight: 600,
+                                                }}
+                                            />
+                                            {torrent.free === "1" && (
+                                                <Chip
+                                                    size="small"
+                                                    label="促销"
+                                                    sx={{
+                                                        background: "#fbbf24",
+                                                        color: "#1e293b",
+                                                        fontWeight: 600,
+                                                    }}
+                                                />
+                                            )}
+                                            {typeof torrent.status !== "undefined" && (
+                                                <Chip
+                                                    size="small"
+                                                    label={statusMap[torrent.status] || "未知状态"}
+                                                    sx={{
+                                                        background: "#64748b",
+                                                        color: "#fff",
+                                                        fontWeight: 600,
+                                                    }}
+                                                />
+                                            )}
+                                        </Box>
+                                        <Typography variant="body2" sx={{ color: "#cbd5e1", mb: 1 }}>
+                                            上传时间:{torrent.createTime}
+                                        </Typography>
+                                        <Box sx={{ display: "flex", gap: 2, mt: 1 }}>
+                                            <Typography variant="body2" sx={{ color: "#38bdf8" }}>
+                                                做种:{torrent.seeders}
+                                            </Typography>
+                                            <Typography variant="body2" sx={{ color: "#f472b6" }}>
+                                                下载量:{torrent.completions}
+                                            </Typography>
+                                            <Typography variant="body2" sx={{ color: "#fbbf24" }}>
+                                                下载中:{torrent.leechers}
+                                            </Typography>
+                                        </Box>
+                                    </CardContent>
+                                </TorrentCard>
+                            </Box>
+                        ))}
+                    </Box>
+                    <Box sx={{ display: "flex", justifyContent: "center", mt: 4 }}>
+                        <Pagination
+                            count={Math.ceil(total / PAGE_SIZE)}
+                            page={page}
+                            onChange={(_, v) => setPage(v)}
+                            color="primary"
+                            sx={{
+                                ".MuiPaginationItem-root": {
+                                    color: "#fff",
+                                    background: "#1e293b",
+                                    border: "1px solid #334155",
+                                },
+                                ".Mui-selected": {
+                                    background: "#0ea5e9 !important",
+                                },
+                            }}
+                        />
+                    </Box>
+                </>
+            )}
+        </Container>
+    </StarBg>
+);
+};
+
+export default TorrentAuditListPage;
\ No newline at end of file
diff --git a/src/pages/Torrent/torrentDetail.tsx b/src/pages/Torrent/torrentDetail.tsx
index d841b04..7a25162 100644
--- a/src/pages/Torrent/torrentDetail.tsx
+++ b/src/pages/Torrent/torrentDetail.tsx
@@ -77,7 +77,7 @@
 };
 
 const statusMap: Record<number, string> = {
-    0: '候选中',
+    0: '审核中',
     1: '已发布',
     2: '审核不通过',
     3: '已上架修改重审中',
diff --git a/src/pages/Torrent/torrentList.tsx b/src/pages/Torrent/torrentList.tsx
index b881aea..c97e13e 100644
--- a/src/pages/Torrent/torrentList.tsx
+++ b/src/pages/Torrent/torrentList.tsx
@@ -2,98 +2,105 @@
 import { styled } from "@mui/material/styles";
 import axios from "axios";
 import {
-  Box,
-  Button,
-  Card,
-  CardContent,
-  Chip,
-  CircularProgress,
-  Container,
-  MenuItem,
-  Pagination,
-  Select,
-  Typography,
+    Box,
+    Button,
+    Card,
+    CardContent,
+    Chip,
+    CircularProgress,
+    Container,
+    MenuItem,
+    Pagination,
+    Select,
+    Typography,
+    TextField,
+    InputAdornment,
+    IconButton,
 } from "@mui/material";
-import { getCategories, getTorrentList } from "../../services/bt/index";
+import { getCategories, getTorrentList,searchTorrents } from "../../services/bt/index";
+
 // 优化后的星空背景
 const StarBg = styled("div")({
-  minHeight: "100vh",
-  width: "auto",
-  background: "radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%)",
-  overflow: "auto",
-  position: "relative",
-  top: 0,
-  left: 0,
-
-
-  
-  // 使用CSS动画实现星空
-  "&:before, &:after": {
-    content: '""',
-    position: "absolute",
+    minHeight: "100vh",
+    width: "auto",
+    background: "radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%)",
+    overflow: "auto",
+    position: "relative",
     top: 0,
     left: 0,
-    width: "100%",
-    height: "100%",
-    pointerEvents: "none",
-  },
-  "&:before": {
-    background: `
-      radial-gradient(1px 1px at 20% 30%, rgba(255,255,255,0.8), rgba(255,255,255,0)),
-      radial-gradient(1px 1px at 40% 70%, rgba(255,255,255,0.8), rgba(255,255,255,0)),
-      radial-gradient(1.5px 1.5px at 60% 20%, rgba(255,255,255,0.9), rgba(255,255,255,0)),
-      radial-gradient(1.5px 1.5px at 80% 90%, rgba(255,255,255,0.9), rgba(255,255,255,0))
-    `,
-    backgroundRepeat: "repeat",
-    backgroundSize: "200px 200px",
-    animation: "twinkle 10s infinite ease-in-out",
-  },
-  "&:after": {
-    background: `
-      radial-gradient(1px 1px at 70% 40%, rgba(255,255,255,0.7), rgba(255,255,255,0)),
-      radial-gradient(1.2px 1.2px at 10% 80%, rgba(255,255,255,0.7), rgba(255,255,255,0)),
-      radial-gradient(1.5px 1.5px at 30% 60%, rgba(255,255,255,0.8), rgba(255,255,255,0))
-    `,
-    backgroundRepeat: "repeat",
-    backgroundSize: "300px 300px",
-    animation: "twinkle 15s infinite 5s ease-in-out",
-  },
-  
-  "@keyframes twinkle": {
-    "0%, 100%": { opacity: 0.3 },
-    "50%": { opacity: 0.8 },
-  }
+    "&:before, &:after": {
+        content: '""',
+        position: "absolute",
+        top: 0,
+        left: 0,
+        width: "100%",
+        height: "100%",
+        pointerEvents: "none",
+    },
+    "&:before": {
+        background: `
+            radial-gradient(1px 1px at 20% 30%, rgba(255,255,255,0.8), rgba(255,255,255,0)),
+            radial-gradient(1px 1px at 40% 70%, rgba(255,255,255,0.8), rgba(255,255,255,0)),
+            radial-gradient(1.5px 1.5px at 60% 20%, rgba(255,255,255,0.9), rgba(255,255,255,0)),
+            radial-gradient(1.5px 1.5px at 80% 90%, rgba(255,255,255,0.9), rgba(255,255,255,0))
+        `,
+        backgroundRepeat: "repeat",
+        backgroundSize: "200px 200px",
+        animation: "twinkle 10s infinite ease-in-out",
+    },
+    "&:after": {
+        background: `
+            radial-gradient(1px 1px at 70% 40%, rgba(255,255,255,0.7), rgba(255,255,255,0)),
+            radial-gradient(1.2px 1.2px at 10% 80%, rgba(255,255,255,0.7), rgba(255,255,255,0)),
+            radial-gradient(1.5px 1.5px at 30% 60%, rgba(255,255,255,0.8), rgba(255,255,255,0))
+        `,
+        backgroundRepeat: "repeat",
+        backgroundSize: "300px 300px",
+        animation: "twinkle 15s infinite 5s ease-in-out",
+    },
+    "@keyframes twinkle": {
+        "0%, 100%": { opacity: 0.3 },
+        "50%": { opacity: 0.8 },
+    }
 });
 
 // 分类标签栏
 const CategoryBar = styled(Box)({
-display: "flex",
-gap: 12,
-alignItems: "center",
-marginBottom: 24,
-flexWrap: "wrap",
+    display: "flex",
+    gap: 12,
+    alignItems: "center",
+    marginBottom: 24,
+    flexWrap: "wrap",
 });
 
 // 种子卡片
 const TorrentCard = styled(Card)({
-background: "rgba(30, 41, 59, 0.85)",
-color: "#fff",
-borderRadius: 16,
-boxShadow: "0 4px 24px 0 rgba(0,0,0,0.4)",
-border: "1px solid #334155",
-transition: "transform 0.2s",
-"&:hover": {
-    transform: "scale(1.025)",
-    boxShadow: "0 8px 32px 0 #0ea5e9",
-},
+    background: "rgba(30, 41, 59, 0.85)",
+    color: "#fff",
+    borderRadius: 16,
+    boxShadow: "0 4px 24px 0 rgba(0,0,0,0.4)",
+    border: "1px solid #334155",
+    transition: "transform 0.2s",
+    "&:hover": {
+        transform: "scale(1.025)",
+        boxShadow: "0 8px 32px 0 #0ea5e9",
+    },
 });
 
 const sortOptions = [
-{ label: "最新", value: { sortField: "createTime", sortDirection: "desc" } },
-{ label: "下载量", value: { sortField: "completions", sortDirection: "desc" } },
-{ label: "推荐", value: { sortField: "seeders", sortDirection: "desc" } },
+    { label: "最新", value: { sortField: "create_time", sortDirection: "desc" } },
+    { label: "下载量", value: { sortField: "completions", sortDirection: "desc" } },
+    { label: "推荐", value: { sortField: "seeders", sortDirection: "desc" } },
 ];
 
+const statusMap: Record<number, string> = {
+    0: '审核中',
+    1: '已发布',
+    2: '审核不通过',
+    3: '已上架修改重审中',
+    10: '已下架',
+};
+
 const PAGE_SIZE = 20;
 
 const TorrentListPage: React.FC = () => {
@@ -107,16 +114,21 @@
     const [page, setPage] = useState(1);
     const [total, setTotal] = useState(0);
 
+    // 搜索相关
+    const [searchKeyword, setSearchKeyword] = useState("");
+    const [searching, setSearching] = useState(false);
+    const [isSearchMode, setIsSearchMode] = useState(false);
+
     // 获取分类
     useEffect(() => {
         getCategories().then((res) => {
-            // 直接使用返回的data数组
             setCategories(res.data || []);
         });
     }, []);
 
     // 获取种子列表
     useEffect(() => {
+        if (isSearchMode) return;
         setLoading(true);
         getTorrentList({
             category: selectedCat !== null ? String(selectedCat) : undefined,
@@ -126,200 +138,374 @@
             pageSize: PAGE_SIZE,
         })
             .then((res) => {
-                // 直接使用返回的data数组和page对象
                 setTorrents(res.data || []);
                 setTotal(res.page?.total || 0);
             })
             .finally(() => setLoading(false));
-    }, [selectedCat, sort, page]);
+    }, [selectedCat, sort, page, isSearchMode]);
 
-return (
-    <StarBg>
-        <Container maxWidth="lg" sx={{ pt: 6, pb: 6, position: "relative" }}>
-            {/* 原有内容 */}
-            <Typography
-                variant="h3"
-                sx={{
-                    color: "#fff",
-                    fontWeight: 700,
-                    mb: 3,
-                    letterSpacing: 2,
-                    textShadow: "0 2px 16px #0ea5e9",
-                }}
-            >
-                ThunderHub 星空PT种子广场
-            </Typography>
-            <CategoryBar>
-                <Chip
-                    label="全部"
-                    color={selectedCat === null ? "primary" : "default"}
-                    onClick={() => {
-                        setSelectedCat(null);
-                        setPage(1);
-                    }}
+    // 搜索
+    const handleSearch = async () => {
+        if (!searchKeyword.trim()) {
+            setIsSearchMode(false);
+            setPage(1);
+            return;
+        }
+        setSearching(true);
+        setIsSearchMode(true);
+        try {
+            const res = await searchTorrents({
+                titleKeyword: searchKeyword.trim(),
+                category: selectedCat !== null ? selectedCat : undefined,
+                sortField: sort.sortField,
+                sortDirection: sort.sortDirection,
+                pageNum: page,
+                pageSize: PAGE_SIZE,
+            });
+            setTorrents((res.records || []).map((r: any) => ({
+                ...r.torrent,
+                ownerInfo: r.ownerInfo,
+            })));
+            setTotal(res.total || 0);
+        } finally {
+            setSearching(false);
+        }
+    };
+
+    // 搜索模式下翻页
+    useEffect(() => {
+        if (!isSearchMode) return;
+        handleSearch();
+        // eslint-disable-next-line
+    }, [page, sort, selectedCat]);
+
+    // 切换分类/排序时退出搜索模式
+    useEffect(() => {
+        setIsSearchMode(false);
+        setSearchKeyword("");
+        setPage(1);
+    }, [selectedCat, sort]);
+
+    return (
+        <StarBg>
+            <Container maxWidth="lg" sx={{ pt: 6, pb: 6, position: "relative" }}>
+                <Typography
+                    variant="h3"
                     sx={{
-                        fontWeight: 600,
-                        fontSize: 16,
-                        color: selectedCat === null ? undefined : "#fff",
+                        color: "#fff",
+                        fontWeight: 700,
+                        mb: 3,
+                        letterSpacing: 2,
+                        textShadow: "0 2px 16px #0ea5e9",
                     }}
-                />
-                {categories.map((cat) => (
+                >
+                    ThunderHub 星空PT种子广场
+                </Typography>
+                {/* 搜索框 */}
+                <Box
+                    sx={{
+                        mb: 4,
+                        display: "flex",
+                        alignItems: "center",
+                        gap: 2,
+                        background: "rgba(30,41,59,0.7)",
+                        borderRadius: 3,
+                        px: 2,
+                        py: 1.5,
+                        boxShadow: "0 2px 12px 0 #0ea5e950",
+                        border: "1px solid #334155",
+                        maxWidth: 700,
+                        mx: { xs: "auto", md: 0 },
+                    }}
+                >
+                    <TextField
+                        variant="outlined"
+                        size="small"
+                        placeholder="🔍 搜索种子标题"
+                        value={searchKeyword}
+                        onChange={(e) => setSearchKeyword(e.target.value)}
+                        onKeyDown={(e) => {
+                            if (e.key === "Enter") {
+                                setPage(1);
+                                handleSearch();
+                            }
+                        }}
+                        sx={{
+                            background: "rgba(17,24,39,0.95)",
+                            borderRadius: 2,
+                            input: {
+                                color: "#fff",
+                                fontSize: 17,
+                                fontWeight: 500,
+                                letterSpacing: 1,
+                                px: 1,
+                            },
+                            width: 320,
+                            ".MuiOutlinedInput-notchedOutline": { border: 0 },
+                            boxShadow: "0 1px 4px 0 #0ea5e930",
+                        }}
+                        InputProps={{
+                            endAdornment: (
+                                <InputAdornment position="end">
+                                    <IconButton
+                                        onClick={() => {
+                                            setPage(1);
+                                            handleSearch();
+                                        }}
+                                        edge="end"
+                                        sx={{
+                                            color: "#0ea5e9",
+                                            bgcolor: "#1e293b",
+                                            borderRadius: 2,
+                                            "&:hover": { bgcolor: "#0ea5e9", color: "#fff" },
+                                            transition: "all 0.2s",
+                                        }}
+                                    >
+                                        <svg width="22" height="22" fill="none" viewBox="0 0 24 24">
+                                            <circle cx="11" cy="11" r="7" stroke="currentColor" strokeWidth="2"/>
+                                            <path stroke="currentColor" strokeWidth="2" strokeLinecap="round" d="M20 20l-3.5-3.5"/>
+                                        </svg>
+                                    </IconButton>
+                                </InputAdornment>
+                            ),
+                        }}
+                    />
+                    {isSearchMode && (
+                        <Button
+                            variant="outlined"
+                            color="secondary"
+                            onClick={() => {
+                                setIsSearchMode(false);
+                                setSearchKeyword("");
+                                setPage(1);
+                            }}
+                            sx={{
+                                ml: 1,
+                                color: "#fff",
+                                borderColor: "#64748b",
+                                borderRadius: 2,
+                                fontWeight: 600,
+                                letterSpacing: 1,
+                                px: 2,
+                                py: 0.5,
+                                background: "rgba(51,65,85,0.7)",
+                                "&:hover": {
+                                    borderColor: "#0ea5e9",
+                                    background: "#0ea5e9",
+                                    color: "#fff",
+                                },
+                                transition: "all 0.2s",
+                            }}
+                        >
+                            清除搜索
+                        </Button>
+                    )}
+                    <Box sx={{ flex: 1 }} />
+                    <Button
+                        variant="contained"
+                        color="primary"
+                        onClick={() => window.open("/torrent-upload", "_self")}
+                        sx={{
+                            borderRadius: 2,
+                            fontWeight: 700,
+                            letterSpacing: 1,
+                            px: 3,
+                            py: 1,
+                            boxShadow: "0 2px 8px 0 #0ea5e950",
+                            background: "#0ea5e9",
+                            color: "#fff",
+                            "&:hover": {
+                                background: "#38bdf8",
+                            },
+                            transition: "all 0.2s",
+                        }}
+                    >
+                        分享资源
+                    </Button>
+                </Box>
+                <CategoryBar>
                     <Chip
-                        key={cat.id}
-                        label={cat.name}
-                        color={selectedCat === cat.id ? "primary" : "default"}
+                        label="全部"
+                        color={selectedCat === null ? "primary" : "default"}
                         onClick={() => {
-                            setSelectedCat(cat.id);
+                            setSelectedCat(null);
                             setPage(1);
                         }}
                         sx={{
                             fontWeight: 600,
                             fontSize: 16,
-                            color: selectedCat === cat.id ? undefined : "#fff",
+                            color: selectedCat === null ? undefined : "#fff",
                         }}
                     />
-                ))}
-                <Box sx={{ flex: 1 }} />
-                <Select
-                    size="small"
-                    value={JSON.stringify(sort)}
-                    onChange={(e) => {
-                        setSort(JSON.parse(e.target.value));
-                        setPage(1);
-                    }}
-                    sx={{
-                        color: "#fff",
-                        background: "#1e293b",
-                        borderRadius: 2,
-                        ".MuiOutlinedInput-notchedOutline": { border: 0 },
-                        minWidth: 120,
-                    }}
-                >
-                    {sortOptions.map((opt) => (
-                        <MenuItem key={opt.label} value={JSON.stringify(opt.value)}>
-                            {opt.label}
-                        </MenuItem>
+                    {categories.map((cat) => (
+                        <Chip
+                            key={cat.id}
+                            label={cat.name}
+                            color={selectedCat === cat.id ? "primary" : "default"}
+                            onClick={() => {
+                                setSelectedCat(cat.id);
+                                setPage(1);
+                            }}
+                            sx={{
+                                fontWeight: 600,
+                                fontSize: 16,
+                                color: selectedCat === cat.id ? undefined : "#fff",
+                            }}
+                        />
                     ))}
-                </Select>
-            </CategoryBar>
-            {loading ? (
-                <Box sx={{ display: "flex", justifyContent: "center", mt: 8 }}>
-                    <CircularProgress color="info" />
-                </Box>
-            ) : (
-                <>
-                    <Box
+                    <Box sx={{ flex: 1 }} />
+                    <Select
+                        size="small"
+                        value={JSON.stringify(sort)}
+                        onChange={(e) => {
+                            setSort(JSON.parse(e.target.value));
+                            setPage(1);
+                        }}
                         sx={{
-                            display: "flex",
-                            flexWrap: "wrap",
-                            gap: 3,
-                            justifyContent: { xs: "center", md: "flex-start" },
+                            color: "#fff",
+                            background: "#1e293b",
+                            borderRadius: 2,
+                            ".MuiOutlinedInput-notchedOutline": { border: 0 },
+                            minWidth: 120,
                         }}
                     >
-                        {torrents.map((torrent) => (
-                            <Box
-                                key={torrent.id}
-                                sx={{
-                                    flex: "1 1 320px",
-                                    maxWidth: { xs: "100%", sm: "48%", md: "32%" },
-                                    minWidth: 300,
-                                    mb: 3,
-                                    display: "flex",
-                                    cursor: "pointer",
-                                }}
-                                onClick={() => window.open(`/torrent-detail/${torrent.id}`, "_self")}
-                            >
-                                <TorrentCard sx={{ width: "100%" }}>
-                                    <CardContent>
-                                        <Typography
-                                            variant="h6"
-                                            sx={{
-                                                color: "#38bdf8",
-                                                fontWeight: 700,
-                                                mb: 1,
-                                                textOverflow: "ellipsis",
-                                                overflow: "hidden",
-                                                whiteSpace: "nowrap",
-                                            }}
-                                            title={torrent.title}
-                                        >
-                                            {torrent.title}
-                                        </Typography>
-                                        <Box
-                                            sx={{
-                                                display: "flex",
-                                                gap: 1,
-                                                alignItems: "center",
-                                                mb: 1,
-                                                flexWrap: "wrap",
-                                            }}
-                                        >
-                                            <Chip
-                                                size="small"
-                                                label={
-                                                    categories.find((c) => c.id === torrent.category)?.name ||
-                                                    "未知"
-                                                }
+                        {sortOptions.map((opt) => (
+                            <MenuItem key={opt.label} value={JSON.stringify(opt.value)}>
+                                {opt.label}
+                            </MenuItem>
+                        ))}
+                    </Select>
+                </CategoryBar>
+                {(loading || searching) ? (
+                    <Box sx={{ display: "flex", justifyContent: "center", mt: 8 }}>
+                        <CircularProgress color="info" />
+                    </Box>
+                ) : (
+                    <>
+                        <Box
+                            sx={{
+                                display: "flex",
+                                flexWrap: "wrap",
+                                gap: 3,
+                                justifyContent: { xs: "center", md: "flex-start" },
+                            }}
+                        >
+                            {torrents.map((torrent) => (
+                                <Box
+                                    key={torrent.id}
+                                    sx={{
+                                        flex: "1 1 320px",
+                                        maxWidth: { xs: "100%", sm: "48%", md: "32%" },
+                                        minWidth: 300,
+                                        mb: 3,
+                                        display: "flex",
+                                        cursor: "pointer",
+                                    }}
+                                    onClick={() => window.open(`/torrent-detail/${torrent.id}`, "_self")}
+                                >
+                                    <TorrentCard sx={{ width: "100%" }}>
+                                        <CardContent>
+                                            <Typography
+                                                variant="h6"
                                                 sx={{
-                                                    background: "#0ea5e9",
-                                                    color: "#fff",
-                                                    fontWeight: 600,
+                                                    color: "#38bdf8",
+                                                    fontWeight: 700,
+                                                    mb: 1,
+                                                    textOverflow: "ellipsis",
+                                                    overflow: "hidden",
+                                                    whiteSpace: "nowrap",
                                                 }}
-                                            />
-                                            {torrent.free === "1" && (
+                                                title={torrent.title}
+                                            >
+                                                {torrent.title}
+                                            </Typography>
+                                            <Box
+                                                sx={{
+                                                    display: "flex",
+                                                    gap: 1,
+                                                    alignItems: "center",
+                                                    mb: 1,
+                                                    flexWrap: "wrap",
+                                                }}
+                                            >
                                                 <Chip
                                                     size="small"
-                                                    label="促销"
+                                                    label={
+                                                        categories.find((c) => c.id === torrent.category)?.name ||
+                                                        "未知"
+                                                    }
                                                     sx={{
-                                                        background: "#fbbf24",
-                                                        color: "#1e293b",
+                                                        background: "#0ea5e9",
+                                                        color: "#fff",
                                                         fontWeight: 600,
                                                     }}
                                                 />
-                                            )}
-                                        </Box>
-                                        <Typography variant="body2" sx={{ color: "#cbd5e1", mb: 1 }}>
-                                            上传时间:{torrent.createTime}
-                                        </Typography>
-                                        <Box sx={{ display: "flex", gap: 2, mt: 1 }}>
-                                            <Typography variant="body2" sx={{ color: "#38bdf8" }}>
-                                                做种:{torrent.seeders}
+                                                {torrent.free === "1" && (
+                                                    <Chip
+                                                        size="small"
+                                                        label="促销"
+                                                        sx={{
+                                                            background: "#fbbf24",
+                                                            color: "#1e293b",
+                                                            fontWeight: 600,
+                                                        }}
+                                                    />
+                                                )}
+                                                {/* 状态标签 */}
+                                                {typeof torrent.status !== "undefined" && (
+                                                    <Chip
+                                                        size="small"
+                                                        label={statusMap[torrent.status] || "未知状态"}
+                                                        sx={{
+                                                            background: "#64748b",
+                                                            color: "#fff",
+                                                            fontWeight: 600,
+                                                        }}
+                                                    />
+                                                )}
+                                            </Box>
+                                            <Typography variant="body2" sx={{ color: "#cbd5e1", mb: 1 }}>
+                                                上传时间:{torrent.createTime}
                                             </Typography>
-                                            <Typography variant="body2" sx={{ color: "#f472b6" }}>
-                                                下载量:{torrent.completions}
-                                            </Typography>
-                                            <Typography variant="body2" sx={{ color: "#fbbf24" }}>
-                                                下载中:{torrent.leechers}
-                                            </Typography>
-                                        </Box>
-                                    </CardContent>
-                                </TorrentCard>
-                            </Box>
-                        ))}
-                    </Box>
-                    <Box sx={{ display: "flex", justifyContent: "center", mt: 4 }}>
-                        <Pagination
-                            count={Math.ceil(total / PAGE_SIZE)}
-                            page={page}
-                            onChange={(_, v) => setPage(v)}
-                            color="primary"
-                            sx={{
-                                ".MuiPaginationItem-root": {
-                                    color: "#fff",
-                                    background: "#1e293b",
-                                    border: "1px solid #334155",
-                                },
-                                ".Mui-selected": {
-                                    background: "#0ea5e9 !important",
-                                },
-                            }}
-                        />
-                    </Box>
-                </>
-            )}
-        </Container>
-    </StarBg>
-);
+                                            <Box sx={{ display: "flex", gap: 2, mt: 1 }}>
+                                                <Typography variant="body2" sx={{ color: "#38bdf8" }}>
+                                                    做种:{torrent.seeders}
+                                                </Typography>
+                                                <Typography variant="body2" sx={{ color: "#f472b6" }}>
+                                                    下载量:{torrent.completions}
+                                                </Typography>
+                                                <Typography variant="body2" sx={{ color: "#fbbf24" }}>
+                                                    下载中:{torrent.leechers}
+                                                </Typography>
+                                            </Box>
+                                        </CardContent>
+                                    </TorrentCard>
+                                </Box>
+                            ))}
+                        </Box>
+                        <Box sx={{ display: "flex", justifyContent: "center", mt: 4 }}>
+                            <Pagination
+                                count={Math.ceil(total / PAGE_SIZE)}
+                                page={page}
+                                onChange={(_, v) => setPage(v)}
+                                color="primary"
+                                sx={{
+                                    ".MuiPaginationItem-root": {
+                                        color: "#fff",
+                                        background: "#1e293b",
+                                        border: "1px solid #334155",
+                                    },
+                                    ".Mui-selected": {
+                                        background: "#0ea5e9 !important",
+                                    },
+                                }}
+                            />
+                        </Box>
+                    </>
+                )}
+            </Container>
+        </StarBg>
+    );
 };
 
 export default TorrentListPage;
\ No newline at end of file
diff --git a/src/pages/Torrent/torrentUpload.tsx b/src/pages/Torrent/torrentUpload.tsx
index b5d45bc..434d65b 100644
--- a/src/pages/Torrent/torrentUpload.tsx
+++ b/src/pages/Torrent/torrentUpload.tsx
@@ -15,7 +15,9 @@
 import{
     getCategories,
     addTorrent,
-    uploadTorrentFile
+    uploadTorrentFile,
+    deleteTorrent,
+    getTracker,
 }  from '../../services/bt/index';
 
 const { Option } = Select;
@@ -89,16 +91,41 @@
             subheading: values.subheading || '',
             remark: values.remark || '',
         });
-        if (!addRes?.id) {
+        if (!addRes?.data) {
             throw new Error('种子信息添加失败');
         }
         // 2. 上传.torrent文件
-        await uploadTorrentFile(fileList[0], addRes.id);
-
+        let upRes =  await uploadTorrentFile(fileList[0], addRes.data);
+        console.log('上传结果:', upRes);
+        if (upRes.code == 500) {
+            throw new Error(upRes.msg);
+            await deleteTorrent( addRes.data);
+        }else{
         message.success('种子上传成功');
         form.resetFields();
         setFileList([]);
         setCustomTags([]);
+        // 获取并显示 trackerUrl
+        const trackerRes = await getTracker();
+        if (trackerRes.data) {
+            const trackerUrl = trackerRes.data;
+            Modal.info({
+            title: 'Tracker 服务器',
+            content: (
+                <div style={{ marginTop: 12, color: '#232946', wordBreak: 'break-all' }}>
+                {trackerUrl}
+                <br />
+                <span style={{ color: '#667eea', fontWeight: 500 }}>
+                    &nbsp;torrentId={addRes.data}
+                </span>
+                </div>
+            ),
+            width: 480,
+            okText: '关闭',
+            });
+        }
+        }
+
     } catch (err: any) {
         message.error(err.message || '上传失败');
     } finally {
@@ -270,7 +297,11 @@
                         }}
                     >
                         {categories.map((cat) => (
-                            <Option key={cat.id} value={cat.id}>
+                            <Option
+                                key={cat.id}
+                                value={cat.id}
+                                style={{ color: '#fff', background: '#232946' }}
+                            >
                                 {cat.name}
                             </Option>
                         ))}
@@ -424,6 +455,41 @@
                     >
                         上传
                     </Button>
+                    <Button
+                        type="default"
+                        block
+                        style={{
+                            marginTop: 16,
+                            background: 'rgba(102,126,234,0.10)',
+                            border: '1px solid #667eea',
+                            color: '#bfcfff',
+                            fontWeight: 500,
+                            letterSpacing: 1,
+                        }}
+                        onClick={async () => {
+                            try {
+                                const res = await getTracker();
+                                if (res.data) {
+                                    Modal.info({
+                                        title: 'Tracker 服务器',
+                                        content: (
+                                            <div style={{ marginTop: 12, color: '#232946' }}>
+                                                {res.data}
+                                            </div>
+                                        ),
+                                        width: 480,
+                                        okText: '关闭',
+                                    });
+                                } else {
+                                    message.info('暂无可用的 Tracker 服务器');
+                                }
+                            } catch (err) {
+                                message.error('获取 Tracker 服务器失败');
+                            }
+                        }}
+                    >
+                        查看 Tracker 服务器
+                    </Button>
                 </Form.Item>
             </Form>
         </div>
diff --git a/src/services/bt/index.tsx b/src/services/bt/index.tsx
index 4a97406..5d9a25c 100644
--- a/src/services/bt/index.tsx
+++ b/src/services/bt/index.tsx
@@ -145,8 +145,6 @@
     return request('/api/torrent/upload', {
         method: 'POST',
         data: formData,
-        requestType: 'form',
-        responseType: 'blob',
     });
 }
 
@@ -171,4 +169,96 @@
     return request('/api/torrent/tracker', {
         method: 'POST',
     });
+}
+
+export interface TorrentSearchRequest {
+    infoHash?: string;
+    category?: number;
+    status?: number;
+    fileStatus?: number;
+    owner?: number;
+    type?: number;
+    nameKeyword?: string;
+    titleKeyword?: string;
+    descriptionKeyword?: string;
+    minSize?: number;
+    maxSize?: number;
+    createTimeStart?: string; // ISO string
+    createTimeEnd?: string;   // ISO string
+    sortField?: string;
+    sortDirection?: string;
+    pageNum?: number;
+    pageSize?: number;
+}
+
+export interface UserEntity {
+    user_id: number;
+    user_name: string;
+    nick_name: string;
+    user_type: string;
+    email: string;
+    phonenumber: string;
+    gender: string;
+    avatar: string;
+    password: string;
+    status: number;
+    login_ip: string;
+    login_date: string;
+    create_by: string;
+    create_time: string;
+    update_by: string;
+    update_time: string;
+    remark: string;
+    full_name: string;
+    state: number;
+    added: string;
+    last_login: string;
+    last_access: string;
+    last_home: string;
+    last_offer: string;
+    forum_access: string;
+    last_staffmsg: string;
+    last_pm: string;
+    last_comment: string;
+    last_post: string;
+    last_active: string;
+    privacy: number;
+    reg_ip: string;
+    level: number;
+    seedtime: number;
+    leechtime: number;
+    real_uploaded: number;
+    real_downloaded: number;
+    modcomment: string;
+    warning_by: number;
+    warning_times: number;
+    warning: boolean;
+    warning_until: string;
+    download: number;
+    upload: number;
+    invited_by: number;
+    bonus: number;
+    exp: number;
+    check_code: string;
+    reg_type: number;
+}
+
+export interface TorrentSearchResult {
+    torrent: TorrentEntity;
+    ownerInfo: UserEntity;
+}
+
+export interface TorrentSearchResponse {
+    records: TorrentSearchResult[];
+    total: number;
+    size: number;
+    current: number;
+    pages: number;
+}
+
+export async function searchTorrents(params: TorrentSearchRequest) {
+    return request<TorrentSearchResponse>('/api/torrent/search', {
+        method: 'POST',
+        data: params,
+    });
 }
\ No newline at end of file