修改提示框样式、完成付费片单、推荐跳转

Change-Id: Ie84c53d4e306435144b1f26ceb39cc182e99d57a
diff --git a/src/pages/SeedList/SeedList.jsx b/src/pages/SeedList/SeedList.jsx
index a74d008..263038b 100644
--- a/src/pages/SeedList/SeedList.jsx
+++ b/src/pages/SeedList/SeedList.jsx
@@ -1,11 +1,14 @@
-// export default SeedList;
 import React, { useState, useEffect } from 'react';
 import { Link } from 'wouter';
 import axios from 'axios';
 import Recommend from './Recommend/Recommend';
-import Header from '../../components/Header';  // 引入 Header 组件
+import Header from '../../components/Header';
 import './SeedList.css';
 import { useUser } from '../../context/UserContext';
+import toast from 'react-hot-toast';
+import { confirmAlert } from 'react-confirm-alert';
+import 'react-confirm-alert/src/react-confirm-alert.css';
+import AuthButton from '../../components/AuthButton';
 
 const SeedList = () => {
     const [seeds, setSeeds] = useState([]);
@@ -15,13 +18,13 @@
     const [activeTab, setActiveTab] = useState('种子列表');
     const [filters, setFilters] = useState({});
     const [selectedFilters, setSelectedFilters] = useState({});
-    const [tagMode, setTagMode] = useState('any'); // 与接口对应,any / all
+    const [tagMode, setTagMode] = useState('any');
     const [errorMsg, setErrorMsg] = useState('');
     const { user } = useUser();
 
     const TAGS = ['猜你喜欢', '电影', '电视剧', '动漫', '音乐', '游戏', '综艺', '软件', '体育', '学习', '纪录片', '其他'];
 
-const CATEGORY_MAP = {
+    const CATEGORY_MAP = {
         '电影': 'movie',
         '电视剧': 'tv',
         '动漫': 'anime',
@@ -33,10 +36,9 @@
         '学习': 'study',
         '纪录片': 'documentary',
         '其他': 'other',
-        '猜你喜欢': '',        
-        '种子列表': '',        
-};
-
+        '猜你喜欢': '',
+        '种子列表': '',
+    };
 
     const buildQueryParams = () => {
         const category = CATEGORY_MAP[activeTab] || '';
@@ -61,26 +63,22 @@
 
         if (tags.length > 0) {
             params.tags = tags;
-            params.tagMode = tagMode; // any 或 all
+            params.tagMode = tagMode;
         }
 
         return params;
     };
 
     const fetchSeeds = async () => {
-        if (activeTab === '猜你喜欢') return; 
+        if (activeTab === '猜你喜欢') return;
         setLoading(true);
         setErrorMsg('');
         try {
             const params = buildQueryParams();
             const response = await axios.get('/seeds/list', { params });
-
             const data = response.data;
 
-            if (data.code !== 0) {
-                throw new Error(data.msg || '获取失败');
-            }
-
+            if (data.code !== 0) throw new Error(data.msg || '获取失败');
             setSeeds(data.data || []);
         } catch (error) {
             console.error('获取种子列表失败:', error);
@@ -120,16 +118,9 @@
     }, [activeTab, sortOption, selectedFilters, tagMode, searchTerm]);
 
     const handleDownload = async (seedId) => {
-        if (!user || !user.userId) {
-            alert('请先登录再下载种子文件');
-            return;
-        }
-
         try {
             const response = await axios.get(`/seeds/${seedId}/download`, {
-                params: {
-                    passkey: user.userId,
-                },
+                params: { passkey: user.userId },
                 responseType: 'blob'
             });
 
@@ -142,22 +133,16 @@
             URL.revokeObjectURL(downloadUrl);
         } catch (error) {
             console.error('下载失败:', error);
-            alert('下载失败,请稍后再试。');
+            toast.error('下载失败,请稍后再试。');
         }
     };
 
     const handleFilterChange = (key, value) => {
-        setSelectedFilters(prev => ({
-            ...prev,
-            [key]: value
-        }));
+        setSelectedFilters(prev => ({ ...prev, [key]: value }));
     };
 
     const clearFilter = (key) => {
-        setSelectedFilters(prev => ({
-            ...prev,
-            [key]: '不限'
-        }));
+        setSelectedFilters(prev => ({ ...prev, [key]: '不限' }));
     };
 
     return (
@@ -172,19 +157,11 @@
                     onChange={(e) => setSearchTerm(e.target.value)}
                     className="search-input"
                 />
-                <select
-                    value={sortOption}
-                    onChange={(e) => setSortOption(e.target.value)}
-                    className="sort-select"
-                >
+                <select value={sortOption} onChange={(e) => setSortOption(e.target.value)} className="sort-select">
                     <option value="最新">最新</option>
                     <option value="最热">最热</option>
                 </select>
-                <select
-                    value={tagMode}
-                    onChange={(e) => setTagMode(e.target.value)}
-                    className="tag-mode-select"
-                >
+                <select value={tagMode} onChange={(e) => setTagMode(e.target.value)} className="tag-mode-select">
                     <option value="any">包含任意标签</option>
                     <option value="all">包含所有标签</option>
                 </select>
@@ -192,7 +169,8 @@
 
             <div className="tag-filters">
                 {TAGS.map(tag => (
-                    <button
+                    <AuthButton
+                        roles={["test"]}
                         key={tag}
                         className={`tag-button ${activeTab === tag ? 'active-tag' : ''}`}
                         onClick={() => {
@@ -202,7 +180,7 @@
                         }}
                     >
                         {tag}
-                    </button>
+                    </AuthButton>
                 ))}
             </div>
 
@@ -211,21 +189,13 @@
                     {Object.entries(filters).map(([key, options]) => (
                         <div className="filter-group" key={key}>
                             <label>{key}:</label>
-                            <select
-                                value={selectedFilters[key]}
-                                onChange={(e) => handleFilterChange(key, e.target.value)}
-                            >
+                            <select value={selectedFilters[key]} 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>
+                                <button className="clear-filter-btn" onClick={() => clearFilter(key)}>✕</button>
                             )}
                         </div>
                     ))}
@@ -270,16 +240,11 @@
                                 }
 
                                 return (
-                                   <Link to={`/seed/${seed.id}`} key={index} className="seed-item-link">
+                                    <Link to={`/seed/${seed.id}`} key={index} className="seed-item-link">
                                         <div className="seed-item">
                                             {seed.imageUrl && (
-                                                <img
-                                                    src={seed.imageUrl}
-                                                    alt={seed.title}
-                                                    className="seed-item-cover"
-                                                />
+                                                <img src={seed.imageUrl} alt={seed.title} className="seed-item-cover" />
                                             )}
-
                                             <div className="seed-item-title">
                                                 <div className="seed-title-row">
                                                     <h3 className="seed-title">{seed.title}</h3>
@@ -293,16 +258,30 @@
                                             <div className="seed-item-size">{seed.size || '未知'}</div>
                                             <div className="seed-item-upload-time">{seed.upload_time?.split('T')[0] || '未知'}</div>
                                             <div className="seed-item-downloads">{seed.downloads ?? 0} 次下载</div>
-                                            <div
-                                                className="seed-item-actions"
-                                                onClick={e => e.stopPropagation()}
-                                            >
+                                            <div className="seed-item-actions" onClick={e => e.stopPropagation()}>
                                                 <button
                                                     className="btn-primary"
                                                     onClick={e => {
                                                         e.preventDefault();
                                                         e.stopPropagation();
-                                                        handleDownload(seed.id);
+                                                        if (!user || !user.userId) {
+                                                            toast.error('请先登录再下载种子文件');
+                                                            return;
+                                                        }
+                                                        confirmAlert({
+                                                            title: '确认下载',
+                                                            message: `是否下载种子「${seed.title}」?`,
+                                                            buttons: [
+                                                                {
+                                                                    label: '确认',
+                                                                    onClick: () => handleDownload(seed.id)
+                                                                },
+                                                                {
+                                                                    label: '取消',
+                                                                    onClick: () => { }
+                                                                }
+                                                            ]
+                                                        });
                                                     }}
                                                 >
                                                     下载
@@ -314,7 +293,7 @@
                                                         e.stopPropagation();
 
                                                         if (!user || !user.userId) {
-                                                            alert('请先登录再收藏');
+                                                            toast.error('请先登录再收藏');
                                                             return;
                                                         }
 
@@ -324,13 +303,13 @@
                                                             });
 
                                                             if (res.data.code === 0) {
-                                                                alert('操作成功');
+                                                                toast.success('操作成功');
                                                             } else {
-                                                                alert(res.data.msg || '操作失败');
+                                                                toast.error(res.data.msg || '操作失败');
                                                             }
                                                         } catch (err) {
                                                             console.error('收藏失败:', err);
-                                                            alert('收藏失败,请稍后再试。');
+                                                            toast.error('收藏失败,请稍后再试。');
                                                         }
                                                     }}
                                                 >