create-seed-detail

Change-Id: I7dcce81a7510b6fa97781d3ce509a8dc2ac229d4
diff --git a/src/pages/PublishSeed/PublishSeed.css b/src/pages/PublishSeed/PublishSeed.css
index e69de29..61b1405 100644
--- a/src/pages/PublishSeed/PublishSeed.css
+++ b/src/pages/PublishSeed/PublishSeed.css
@@ -0,0 +1,145 @@
+.publish-seed-container {
+    background-color: #5c3f31;
+    color: white;
+    padding: 20px;
+    border-radius: 12px;
+    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  }
+  
+  h2 {
+    text-align: center;
+    font-size: 1.8rem;
+    margin-bottom: 20px;
+    color: #fff;
+  }
+  
+  .message {
+    text-align: center;
+    margin-bottom: 20px;
+    color: #ff6f61;
+    font-weight: bold;
+  }
+  
+  .form-group {
+    margin-bottom: 20px;
+  }
+  
+  label {
+    font-size: 1rem;
+    margin-bottom: 8px;
+    display: block;
+  }
+  
+  input[type="text"],
+  textarea,
+  select,
+  input[type="url"],
+  input[type="file"] {
+    width: 100%;
+    padding: 8px 12px;
+    border-radius: 6px;
+    border: 1px solid #ddd;
+    background-color: #f9f9f9;
+    color: #333;
+    font-size: 1rem;
+  }
+  
+  textarea {
+    height: 100px;
+    resize: none;
+  }
+  
+  input[type="file"] {
+    padding: 6px;
+  }
+  
+  input[type="url"] {
+    padding: 8px 12px;
+  }
+  
+  input[type="text"]:focus,
+  textarea:focus,
+  select:focus,
+  input[type="url"]:focus,
+  input[type="file"]:focus {
+    outline: none;
+    border-color: #b38867;
+  }
+  
+  button[type="submit"] {
+    padding: 12px 20px;
+    border: none;
+    background-color: #007bff;
+    color: white;
+    font-size: 1rem;
+    border-radius: 6px;
+    cursor: pointer;
+    width: 100%;
+    transition: background-color 0.2s ease;
+  }
+  
+  button[type="submit"]:disabled {
+    background-color: #d6d6d6;
+    cursor: not-allowed;
+  }
+  
+  button[type="submit"]:hover {
+    background-color: #0056b3;
+  }
+  
+  input[type="text"],
+  input[type="url"],
+  select {
+    margin-bottom: 10px;
+  }
+  
+  input[type="file"] {
+    margin-bottom: 10px;
+  }
+  
+  .publish-seed-container .form-group:last-child {
+    margin-bottom: 0;
+  }
+  
+  .publish-seed-container .form-group label {
+    color: #ddd;
+    font-size: 1rem;
+  }
+  
+  .publish-seed-container .form-group input,
+  .publish-seed-container .form-group select,
+  .publish-seed-container .form-group textarea {
+    background-color: #4e3b30;
+    color: white;
+  }
+  
+  .publish-seed-container .form-group input:focus,
+  .publish-seed-container .form-group select:focus,
+  .publish-seed-container .form-group textarea:focus {
+    border-color: #b38867;
+    outline: none;
+  }
+  
+  input[type="file"] {
+    border: none;
+    background-color: #4e3b30;
+  }
+  
+  input[type="file"]:focus {
+    outline: none;
+  }
+  
+  .form-group button {
+    background-color: #5c3f31;
+    color: #fff;
+    padding: 12px;
+    font-size: 1rem;
+    border-radius: 8px;
+    cursor: pointer;
+    width: 100%;
+  }
+  
+  .form-group button:hover {
+    background-color: #b38867;
+  }
+  
\ No newline at end of file
diff --git a/src/pages/PublishSeed/PublishSeed.jsx b/src/pages/PublishSeed/PublishSeed.jsx
index e69de29..7ead11d 100644
--- a/src/pages/PublishSeed/PublishSeed.jsx
+++ b/src/pages/PublishSeed/PublishSeed.jsx
@@ -0,0 +1,136 @@
+import React, { useState } from 'react';
+import axios from 'axios';
+import Header from '../../components/Header'; // 导入 Header 组件
+
+const API_BASE = process.env.REACT_APP_API_BASE;
+
+const PublishSeed = () => {
+  const [title, setTitle] = useState('');
+  const [description, setDescription] = useState('');
+  const [tags, setTags] = useState([]);
+  const [category, setCategory] = useState('movie');
+  const [file, setFile] = useState(null);
+  const [imageUrl, setImageUrl] = useState('');
+  const [message, setMessage] = useState('');
+  const [isLoading, setIsLoading] = useState(false);
+
+  const handleTagsChange = (e) => {
+    setTags(e.target.value.split(',').map(tag => tag.trim()));
+  };
+
+  const handleFileChange = (e) => {
+    setFile(e.target.files[0]);
+  };
+
+  const handleSubmit = async (e) => {
+    e.preventDefault();
+    setIsLoading(true);
+    setMessage('');
+
+    const formData = new FormData();
+    formData.append('title', title);
+    formData.append('description', description);
+    formData.append('tags', JSON.stringify(tags)); // Tags as JSON array
+    formData.append('category', category);
+    formData.append('file', file);
+    formData.append('image_url', imageUrl);
+
+    try {
+      const response = await axios.post(`${API_BASE}/echo/seeds/upload`, formData, {
+        headers: {
+          'Content-Type': 'multipart/form-data',
+        },
+      });
+
+      if (response.data.status === 'success') {
+        setMessage('种子上传成功');
+      } else {
+        setMessage('上传失败,请稍后再试');
+      }
+    } catch (error) {
+      console.error(error);
+      setMessage('上传失败,发生了错误');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  return (
+    <div className="publish-seed-container">
+      <Header /> {/* 在这里插入导航栏 */}
+      {message && <div className="message">{message}</div>}
+      <form onSubmit={handleSubmit} encType="multipart/form-data">
+        <div className="form-group">
+          <label>标题</label>
+          <input
+            type="text"
+            value={title}
+            onChange={(e) => setTitle(e.target.value)}
+            required
+          />
+        </div>
+
+        <div className="form-group">
+          <label>描述</label>
+          <textarea
+            value={description}
+            onChange={(e) => setDescription(e.target.value)}
+            required
+          />
+        </div>
+
+        <div className="form-group">
+          <label>标签 (逗号分隔)</label>
+          <input
+            type="text"
+            value={tags.join(', ')}
+            onChange={handleTagsChange}
+            placeholder="例如:科幻, 动作"
+            required
+          />
+        </div>
+
+        <div className="form-group">
+          <label>分类</label>
+          <select
+            value={category}
+            onChange={(e) => setCategory(e.target.value)}
+            required
+          >
+            <option value="movie">电影</option>
+            <option value="tv">电视剧</option>
+            <option value="music">音乐</option>
+          </select>
+        </div>
+
+        <div className="form-group">
+          <label>种子文件</label>
+          <input
+            type="file"
+            onChange={handleFileChange}
+            required
+          />
+        </div>
+
+        <div className="form-group">
+          <label>封面图URL</label>
+          <input
+            type="url"
+            value={imageUrl}
+            onChange={(e) => setImageUrl(e.target.value)}
+            placeholder="例如:http://example.com/images/cover.jpg"
+            required
+          />
+        </div>
+
+        <div className="form-group">
+          <button type="submit" disabled={isLoading}>
+            {isLoading ? '正在上传...' : '上传种子'}
+          </button>
+        </div>
+      </form>
+    </div>
+  );
+};
+
+export default PublishSeed;
diff --git a/src/pages/SeedList/SeedDetail/SeedDetail.css b/src/pages/SeedList/SeedDetail/SeedDetail.css
new file mode 100644
index 0000000..ce4d70e
--- /dev/null
+++ b/src/pages/SeedList/SeedDetail/SeedDetail.css
@@ -0,0 +1,30 @@
+.seed-detail-container {
+    padding: 20px;
+  }
+  
+  .seed-header {
+    display: flex;
+  }
+  
+  .cover-image {
+    width: 200px;
+    height: auto;
+    margin-right: 20px;
+    border-radius: 8px;
+  }
+  
+  .seed-basic-info p, .seed-media-info p {
+    margin: 6px 0;
+  }
+  
+  .uploader-info {
+    margin-top: 30px;
+    border-top: 1px solid #ccc;
+    padding-top: 10px;
+  }
+  
+  .uploader-info .avatar {
+    width: 60px;
+    border-radius: 50%;
+  }
+  
\ No newline at end of file
diff --git a/src/pages/SeedList/SeedDetail/SeedDetail.jsx b/src/pages/SeedList/SeedDetail/SeedDetail.jsx
new file mode 100644
index 0000000..464da3d
--- /dev/null
+++ b/src/pages/SeedList/SeedDetail/SeedDetail.jsx
@@ -0,0 +1,89 @@
+import React, { useEffect, useState } from 'react';
+import axios from 'axios';
+import { useParams } from 'react-router-dom';
+import Header from '../../../components/Header';
+import './SeedDetail.css';
+
+const API_BASE = process.env.REACT_APP_API_BASE;
+
+const SeedDetail = () => {
+  const { seed_id } = useParams();
+  const [seed, setSeed] = useState(null);
+  const [error, setError] = useState(null);
+
+  useEffect(() => {
+    axios
+      .get(`${API_BASE}/echo/seeds/${seed_id}`)
+      .then((res) => {
+        if (res.data.status === 'success') {
+          setSeed(res.data.seed);
+        } else {
+          setError('未能获取种子信息');
+        }
+      })
+      .catch(() => {
+        setError('获取种子详情失败');
+      });
+  }, [seed_id]);
+
+  if (error) {
+    return (
+      <div>
+        <Header />
+        <div className="seed-detail-container">
+          <p className="error">{error}</p>
+        </div>
+      </div>
+    );
+  }
+
+  if (!seed) {
+    return (
+      <div>
+        <Header />
+        <div className="seed-detail-container">
+          <p>加载中...</p>
+        </div>
+      </div>
+    );
+  }
+
+  return (
+    <div>
+      <Header />
+      <div className="seed-detail-container">
+        <div className="seed-header">
+          <img src={seed.cover_url} alt={seed.title} className="cover-image" />
+          <div className="seed-basic-info">
+            <h1>{seed.title}</h1>
+            <p><strong>分类:</strong>{seed.category}</p>
+            <p><strong>标签:</strong>{seed.tags.join(' / ')}</p>
+            <p><strong>简介:</strong>{seed.description}</p>
+            <p><strong>大小:</strong>{seed.size} GB</p>
+            <p><strong>分辨率:</strong>{seed.resolution}</p>
+            <p><strong>片长:</strong>{seed.duration}</p>
+            <p><strong>地区:</strong>{seed.region}</p>
+            <p><strong>发布时间:</strong>{new Date(seed.upload_time).toLocaleString()}</p>
+            <p><strong>下载次数:</strong>{seed.downloads}</p>
+          </div>
+        </div>
+
+        {(seed.category === '电影' || seed.category === '电视剧') && (
+          <div className="seed-media-info">
+            <p><strong>导演:</strong>{seed.director}</p>
+            <p><strong>编剧:</strong>{seed.writer}</p>
+            <p><strong>主演:</strong>{seed.actors.join(' / ')}</p>
+          </div>
+        )}
+
+        <div className="uploader-info">
+          <h3>发种人</h3>
+          <img src={seed.user.avatar_url} alt={seed.user.username} className="avatar" />
+          <p>{seed.user.username}</p>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default SeedDetail;
diff --git a/src/pages/SeedList/SeedList.css b/src/pages/SeedList/SeedList.css
index 5d17275..9187c56 100644
--- a/src/pages/SeedList/SeedList.css
+++ b/src/pages/SeedList/SeedList.css
@@ -1,173 +1,231 @@
- .main-page {
-    background-color: #5c3f31;
-    color: white;
-  }
-  
-  .header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: 10px;
-  }
-  
-  .logo-and-name {
-    display: flex;
-    align-items: center;
-  }
-  
-  .logo {
-    height: 30px;
-    margin-right: 10px;
-  }
-  
-  .site-name {
-    font-size: 24px;
-  }
-  
-  .user-and-message {
-    display: flex;
-    align-items: center;
-  }
-  
-  .user-avatar {
-    height: 40px;
-    margin-right: 10px;
-  }
-  
-  .message-center {
-    font-size: 16px;
-  }
-  
-  .nav {
-    background-color: #b38867;
-    display: flex;
-    justify-content: center;
-  }
-  
-  .nav-item {
-    color: white;
-    text-decoration: none;
-    padding: 10px 20px;
-  }
-  
-  .active {
-    background-color: #996633;
-  }
-  
-  /* 搜索、排序控件 */
-  .controls {
-    display: flex;
-    justify-content: center;
-    gap: 16px;
-    padding: 10px 20px;
-    background-color: #704c3b;
-  }
-  
-  .search-input {
-    padding: 6px 10px;
-    border-radius: 6px;
-    border: none;
-    width: 200px;
-  }
-  
-  .sort-select {
-    padding: 6px;
-    border-radius: 6px;
-    border: none;
-  }
-  
-  /* 标签过滤 */
-  .tag-filters {
-    display: flex;
-    justify-content: center;
-    flex-wrap: wrap;
-    gap: 8px;
-    padding: 10px;
-  }
-  
-  .tag-button {
-    background-color: #b38867;
-    color: white;
-    border: none;
-    border-radius: 20px;
-    padding: 6px 12px;
-    cursor: pointer;
-  }
-  
-  .active-tag {
-    background-color: #d17c4f;
-  }
-  
-  /* 卡片展示 */
-  .seed-list-content {
-    padding: 20px;
-  }
-  
-  .seed-cards {
-    display: grid;
-    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
-    gap: 20px;
-  }
-  
-  .seed-card {
-    background-color: #fff;
-    border-radius: 12px;
-    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-    padding: 16px;
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-    color: #333;
-    transition: transform 0.2s ease;
-  }
-  
-  .seed-card:hover {
-    transform: translateY(-5px);
-  }
-  
-  .seed-card-header h3 {
-    font-size: 1.2rem;
-    margin-bottom: 10px;
-    color: #333;
-  }
-  
-  .seed-card-body p {
-    margin: 4px 0;
-    font-size: 0.95rem;
-    color: #666;
-  }
-  
-  .seed-card-actions {
-    display: flex;
-    gap: 10px;
-    margin-top: 12px;
-  }
-  
-  .btn-primary,
-  .btn-secondary,
-  .btn-outline {
-    padding: 6px 12px;
-    border: none;
-    border-radius: 6px;
-    cursor: pointer;
-    font-size: 0.9rem;
-  }
-  
-  .btn-primary {
-    background-color: #007bff;
-    color: white;
-  }
-  
-  .btn-secondary {
-    background-color: #28a745;
-    color: white;
-    text-decoration: none;
-    text-align: center;
-  }
-  
-  .btn-outline {
-    background-color: transparent;
-    border: 1px solid #ccc;
-    color: #333;
-  }
-  
\ No newline at end of file
+.main-page {
+  background-color: #5c3f31;
+  color: white;
+}
+
+.header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px;
+}
+
+.logo-and-name {
+  display: flex;
+  align-items: center;
+}
+
+.logo {
+  height: 30px;
+  margin-right: 10px;
+}
+
+.site-name {
+  font-size: 24px;
+}
+
+.user-and-message {
+  display: flex;
+  align-items: center;
+}
+
+.user-avatar {
+  height: 40px;
+  margin-right: 10px;
+}
+
+.message-center {
+  font-size: 16px;
+}
+
+.nav {
+  background-color: #b38867;
+  display: flex;
+  justify-content: center;
+}
+
+.nav-item {
+  color: white;
+  text-decoration: none;
+  padding: 10px 20px;
+}
+
+.active {
+  background-color: #996633;
+}
+
+/* 搜索、排序控件 */
+.controls {
+  display: flex;
+  justify-content: center;
+  gap: 16px;
+  padding: 10px 20px;
+  background-color: #704c3b;
+}
+
+.search-input {
+  padding: 6px 10px;
+  border-radius: 6px;
+  border: none;
+  width: 200px;
+}
+
+.sort-select {
+  padding: 6px;
+  border-radius: 6px;
+  border: none;
+}
+
+/* 标签过滤 */
+.tag-filters {
+  display: flex;
+  justify-content: center;
+  flex-wrap: wrap;
+  gap: 8px;
+  padding: 10px;
+}
+
+.tag-button {
+  background-color: #b38867;
+  color: white;
+  border: none;
+  border-radius: 20px;
+  padding: 6px 12px;
+  cursor: pointer;
+}
+
+.active-tag {
+  background-color: #d17c4f;
+}
+
+.clear-filter-btn {
+  background: transparent;
+  border: none;
+  color: #888;
+  font-size: 1rem;
+  cursor: pointer;
+  margin-left: 4px;
+}
+
+.clear-filter-btn:hover {
+  color: red;
+}
+
+/* 卡片展示 */
+.seed-list-content {
+  padding: 20px;
+}
+
+.seed-cards {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+  gap: 20px;
+  padding: 20px 0;
+}
+
+.seed-card {
+  background-color: #fff;
+  border-radius: 12px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  padding: 16px;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  color: #333;
+  transition: transform 0.2s ease;
+}
+
+.seed-card:hover {
+  transform: translateY(-5px);
+}
+
+.seed-card-header h3 {
+  font-size: 1.2rem;
+  margin-bottom: 10px;
+  color: #333;
+  word-break: break-word;
+}
+
+.seed-card-body {
+  display: flex;
+  flex-direction: column;
+}
+
+.seed-info {
+  display: flex;
+  justify-content: space-between;
+  font-size: 0.9rem;
+  color: #666;
+  margin-bottom: 8px;
+}
+
+.seed-card-tags {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 6px;
+  margin-top: 6px;
+}
+
+.tag-label {
+  background-color: #f0f0f0;
+  color: #555;
+  padding: 4px 10px;
+  font-size: 0.75rem;
+  border-radius: 12px;
+  white-space: nowrap;
+}
+
+.seed-card-actions {
+  display: flex;
+  justify-content: space-between;
+  gap: 10px;
+  margin-top: 12px;
+}
+
+.btn-primary,
+.btn-secondary,
+.btn-outline {
+  padding: 6px 12px;
+  border: none;
+  border-radius: 6px;
+  cursor: pointer;
+  font-size: 0.9rem;
+  text-align: center;
+  white-space: nowrap;
+  transition: background-color 0.2s ease;
+}
+
+.btn-primary {
+  background-color: #007bff;
+  color: white;
+}
+
+.btn-primary:hover {
+  background-color: #0056b3;
+}
+
+.btn-secondary {
+  background-color: #28a745;
+  color: white;
+}
+
+.btn-secondary:hover {
+  background-color: #218838;
+}
+
+.btn-outline {
+  background-color: transparent;
+  border: 1px solid #ccc;
+  color: #333;
+}
+
+.btn-outline:hover {
+  background-color: #f8f9fa;
+}
+.seed-cover {
+  width: 100%;
+  height: 180px;
+  object-fit: cover;
+  border-radius: 8px;
+  margin-bottom: 12px;
+}
diff --git a/src/pages/SeedList/SeedList.jsx b/src/pages/SeedList/SeedList.jsx
index 3519f17..f32224e 100644
--- a/src/pages/SeedList/SeedList.jsx
+++ b/src/pages/SeedList/SeedList.jsx
@@ -1,246 +1,3 @@
-// import React, { useState, useEffect } from 'react';
-// import { Link } from 'wouter';
-// import axios from 'axios';
-// import logo from '../../assets/logo.png';
-// import Recommend from './Recommend/Recommend';
-// import './SeedList.css';
-
-// const API_BASE = process.env.REACT_APP_API_BASE;
-
-// const SeedList = () => {
-//     const [seeds, setSeeds] = useState([]);
-//     const [filteredSeeds, setFilteredSeeds] = useState([]);
-//     const [loading, setLoading] = useState(true);
-//     const [searchTerm, setSearchTerm] = useState('');
-//     const [sortOption, setSortOption] = useState('最新');
-//     const [activeTab, setActiveTab] = useState('种子列表');
-
-//     const [filters, setFilters] = useState({});
-//     const [selectedFilters, setSelectedFilters] = useState({});
-
-//     const TAGS = ['猜你喜欢', '电影', '电视剧', '动漫', '音乐', '游戏', '综艺', '软件', '体育', '学习', '纪录片', '其他'];
-
-//     const CATEGORY_MAP = {
-//         '电影': 'movie',
-//         '电视剧': 'tv',
-//         '动漫': 'anime',
-//         '音乐': 'music',
-//         '游戏': 'game',
-//         '综艺': 'variety',
-//         '软件': 'software',
-//         '体育': 'sports',
-//         '学习': 'study',
-//         '纪录片': 'documentary',
-//         '其他': 'other'
-//     };
-
-//     const buildQueryParams = () => {
-//         const category = CATEGORY_MAP[activeTab];
-
-//         const params = {
-//             category,
-//             sort_by: sortOption === '最新' ? 'newest'
-//                     : sortOption === '最热' ? 'downloads'
-//                     : undefined,
-//             page: 1,
-//             limit: 20,
-//         };
-
-//         const tags = Object.entries(selectedFilters)
-//             .filter(([_, value]) => value !== '不限')
-//             .map(([_, value]) => value);
-
-//         if (tags.length > 0) params.tags = tags.join(',');
-
-//         return params;
-//     };
-
-//     const fetchSeeds = async () => {
-//         setLoading(true);
-//         try {
-//             const params = buildQueryParams();
-//             const queryString = new URLSearchParams(params).toString();
-//             const response = await fetch(`${API_BASE}/echo/seeds?${queryString}`);
-//             const data = await response.json();
-//             const seeds = data?.seeds || [];
-//             setSeeds(seeds);
-//             setFilteredSeeds(seeds);
-//         } catch (error) {
-//             console.error('获取种子列表失败:', error);
-//         } finally {
-//             setLoading(false);
-//         }
-//     };
-
-//     const fetchFilterOptions = async () => {
-//         if (activeTab === '猜你喜欢') return;
-//         const category = CATEGORY_MAP[activeTab];
-//         try {
-//             const res = await axios.get(`${API_BASE}/echo/seed-filters?category=${category}`);
-//             setFilters(res.data || {});
-//             const defaultSelections = {};
-//             for (const key in res.data) {
-//                 defaultSelections[key] = '不限';
-//             }
-//             setSelectedFilters(defaultSelections);
-//         } catch (err) {
-//             console.error('获取筛选项失败:', err);
-//             setFilters({});
-//             setSelectedFilters({});
-//         }
-//     };
-
-//     useEffect(() => {
-//         if (activeTab !== '猜你喜欢') {
-//             fetchFilterOptions();
-//         }
-//     }, [activeTab]);
-
-//     useEffect(() => {
-//         if (activeTab !== '猜你喜欢') {
-//             fetchSeeds();
-//         }
-//     }, [activeTab, sortOption, selectedFilters]);
-
-//     const handleDownload = async (seedId) => {
-//         const peer_id = 'echo-' + Math.random().toString(36).substring(2, 10);
-//         const ip = '127.0.0.1';
-//         const port = 6881;
-//         const uploaded = 0;
-//         const downloaded = 0;
-//         const left = 0;
-
-//         try {
-//             const response = await axios.get(`${API_BASE}/echo/seeds/${seedId}/download`, {
-//                 params: {
-//                     peer_id,
-//                     ip,
-//                     port,
-//                     uploaded,
-//                     downloaded,
-//                     left,
-//                 },
-//                 responseType: 'blob'
-//             });
-
-//             const blob = new Blob([response.data], { type: 'application/x-bittorrent' });
-//             const downloadUrl = URL.createObjectURL(blob);
-//             const a = document.createElement('a');
-//             a.href = downloadUrl;
-//             a.download = `${seedId}.torrent`;
-//             a.click();
-//             URL.revokeObjectURL(downloadUrl);
-//         } catch (error) {
-//             console.error('下载失败:', error);
-//             alert('下载失败,请稍后再试。');
-//         }
-//     };
-
-//     return (
-//         <div className="main-page">
-//             <header className="header">
-//                 <div className="logo-and-name">
-//                     <img src={logo} alt="网站logo" className="logo" />
-//                     <span className="site-name">Echo</span>
-//                 </div>
-//                 <div className="user-and-message">
-//                     <img src="user-avatar.png" alt="用户头像" className="user-avatar" />
-//                     <span className="message-center">消息</span>
-//                 </div>
-//             </header>
-
-//             <nav className="nav">
-//                 <Link to="/friend-moments" className="nav-item">好友动态</Link>
-//                 <Link to="/forum" className="nav-item">论坛</Link>
-//                 <Link to="/interest-groups" className="nav-item">兴趣小组</Link>
-//                 <Link to="/seed-list" className="nav-item active">种子列表</Link>
-//                 <Link to="/publish-seed" className="nav-item">发布种子</Link>
-//             </nav>
-
-//             <div className="controls">
-//                 <input
-//                     type="text"
-//                     placeholder="搜索种子..."
-//                     value={searchTerm}
-//                     onChange={(e) => setSearchTerm(e.target.value)}
-//                     className="search-input"
-//                 />
-//                 <select value={sortOption} onChange={(e) => setSortOption(e.target.value)} className="sort-select">
-//                     <option value="最新">最新</option>
-//                     <option value="最热">最热</option>
-//                 </select>
-//             </div>
-
-//             <div className="tag-filters">
-//                 {TAGS.map((tag) => (
-//                     <button
-//                         key={tag}
-//                         className={`tag-button ${activeTab === tag ? 'active-tag' : ''}`}
-//                         onClick={() => {
-//                             setActiveTab(tag);
-//                             setFilters({});
-//                             setSelectedFilters({});
-//                         }}
-//                     >
-//                         {tag}
-//                     </button>
-//                 ))}
-//             </div>
-
-//             {activeTab !== '猜你喜欢' && Object.keys(filters).length > 0 && (
-//                 <div className="filter-bar">
-//                     {Object.entries(filters).map(([key, options]) => (
-//                         <div className="filter-group" key={key}>
-//                             <label>{key}:</label>
-//                             <select
-//                                 value={selectedFilters[key]}
-//                                 onChange={(e) =>
-//                                     setSelectedFilters({ ...selectedFilters, [key]: e.target.value })
-//                                 }
-//                             >
-//                                 {options.map((opt) => (
-//                                     <option key={opt} value={opt}>{opt}</option>
-//                                 ))}
-//                             </select>
-//                         </div>
-//                     ))}
-//                 </div>
-//             )}
-
-//             <div className="seed-list-content">
-//                 {activeTab === '猜你喜欢' ? (
-//                     <Recommend />
-//                 ) : loading ? (
-//                     <p>加载中...</p>
-//                 ) : filteredSeeds.length === 0 ? (
-//                     <p>未找到符合条件的种子。</p>
-//                 ) : (
-//                     <div className="seed-cards">
-//                         {filteredSeeds.map((seed, index) => (
-//                             <div key={index} className="seed-card">
-//                                 <div className="seed-card-header">
-//                                     <h3>{seed.title}</h3>
-//                                 </div>
-//                                 <div className="seed-card-body">
-//                                     <p><strong>大小:</strong> {seed.size || '未知'} GB</p>
-//                                     <p><strong>时间:</strong> {seed.upload_time?.split('T')[0] || '未知'}</p>
-//                                     <p><strong>下载数:</strong> {seed.downloads ?? 0}</p>
-//                                 </div>
-//                                 <div className="seed-card-actions">
-//                                     <button className="btn-primary" onClick={() => handleDownload(seed.seed_id)}>下载</button>
-//                                     <Link href={`/seed/${seed.seed_id}`} className="btn-secondary">详情</Link>
-//                                     <button className="btn-outline">收藏</button>
-//                                 </div>
-//                             </div>
-//                         ))}
-//                     </div>
-//                 )}
-//             </div>
-//         </div>
-//     );
-// };
-
-// export default SeedList;
 import React, { useState, useEffect } from 'react';
 import { Link } from 'wouter';
 import axios from 'axios';
@@ -259,7 +16,7 @@
     const [activeTab, setActiveTab] = useState('种子列表');
     const [filters, setFilters] = useState({});
     const [selectedFilters, setSelectedFilters] = useState({});
-    const [tagMode, setTagMode] = useState('all'); // 支持 tag_mode 参数
+    const [tagMode, setTagMode] = useState('all');
     const [errorMsg, setErrorMsg] = useState('');
 
     const TAGS = ['猜你喜欢', '电影', '电视剧', '动漫', '音乐', '游戏', '综艺', '软件', '体育', '学习', '纪录片', '其他'];
@@ -285,12 +42,10 @@
             sort_by: sortOption === '最新' ? 'newest' : sortOption === '最热' ? 'downloads' : undefined,
             page: 1,
             limit: 20,
-            include_fields: 'seed_id,title,category,tags,size,upload_time,downloads',
+            include_fields: 'seed_id,title,category,tags,size,upload_time,downloads,image_url',
         };
 
-        if (searchTerm.trim()) {
-            params.search = searchTerm.trim();
-        }
+        if (searchTerm.trim()) params.search = searchTerm.trim();
 
         const tags = Object.entries(selectedFilters)
             .filter(([_, value]) => value !== '不限')
@@ -332,9 +87,11 @@
         const category = CATEGORY_MAP[activeTab];
         try {
             const res = await axios.get(`${API_BASE}/echo/seed-filters?category=${category}`);
-            setFilters(res.data || {});
+            const filterData = res.data || {};
+            setFilters(filterData);
+
             const defaultSelections = {};
-            for (const key in res.data) {
+            for (const key in filterData) {
                 defaultSelections[key] = '不限';
             }
             setSelectedFilters(defaultSelections);
@@ -384,6 +141,20 @@
         }
     };
 
+    const handleFilterChange = (key, value) => {
+        setSelectedFilters((prev) => ({
+            ...prev,
+            [key]: value
+        }));
+    };
+
+    const clearFilter = (key) => {
+        setSelectedFilters((prev) => ({
+            ...prev,
+            [key]: '不限'
+        }));
+    };
+
     return (
         <div className="main-page">
             <header className="header">
@@ -446,14 +217,15 @@
                             <label>{key}:</label>
                             <select
                                 value={selectedFilters[key]}
-                                onChange={(e) =>
-                                    setSelectedFilters({ ...selectedFilters, [key]: e.target.value })
-                                }
+                                onChange={(e) => handleFilterChange(key, e.target.value)}
                             >
                                 {options.map((opt) => (
                                     <option key={opt} value={opt}>{opt}</option>
                                 ))}
                             </select>
+                            {selectedFilters[key] !== '不限' && (
+                                <button className="clear-filter-btn" onClick={() => clearFilter(key)}>✕</button>
+                            )}
                         </div>
                     ))}
                 </div>
@@ -472,14 +244,28 @@
                     <div className="seed-cards">
                         {filteredSeeds.map((seed, index) => (
                             <div key={index} className="seed-card">
+                                {seed.image_url && (
+                                    <img src={seed.image_url} alt={seed.title} className="seed-cover" />
+                                )}
                                 <div className="seed-card-header">
                                     <h3>{seed.title}</h3>
                                 </div>
+
                                 <div className="seed-card-body">
-                                    <p><strong>大小:</strong> {seed.size || '未知'} GB</p>
-                                    <p><strong>时间:</strong> {seed.upload_time?.split('T')[0] || '未知'}</p>
-                                    <p><strong>下载数:</strong> {seed.downloads ?? 0}</p>
+                                    <div className="seed-info">
+                                        <span>{seed.size || '未知'} GB</span>
+                                        <span>{seed.upload_time?.split('T')[0] || '未知'}</span>
+                                        <span>{seed.downloads ?? 0} 次下载</span>
+                                    </div>
+                                    {seed.tags && seed.tags.length > 0 && (
+                                        <div className="seed-card-tags">
+                                            {seed.tags.map((tag, i) => (
+                                                <span key={i} className="tag-label">{tag}</span>
+                                            ))}
+                                        </div>
+                                    )}
                                 </div>
+
                                 <div className="seed-card-actions">
                                     <button className="btn-primary" onClick={() => handleDownload(seed.seed_id)}>下载</button>
                                     <Link href={`/seed/${seed.seed_id}`} className="btn-secondary">详情</Link>