Merge "修复种子列表搜索排序"
diff --git a/src/pages/PublishSeed/PublishSeed.jsx b/src/pages/PublishSeed/PublishSeed.jsx
index 6528b0d..2f5bddb 100644
--- a/src/pages/PublishSeed/PublishSeed.jsx
+++ b/src/pages/PublishSeed/PublishSeed.jsx
@@ -92,25 +92,31 @@
       formData.append('coverImage', imageFile);
     }
 
-    try {
+        try {
       console.log('[DEBUG] 发送上传请求...');
-      const response = await axios.post('/seeds/upload', formData, {
-        // axios 会自动处理 multipart/form-data Content-Type 边界,不用手动设置
-        // headers: { 'Content-Type': 'multipart/form-data' },
-      });
+      const response = await axios.post('/seeds/upload', formData);
+
       console.log('[DEBUG] 请求成功,响应:', response.data);
 
       if (response.data.code === 0) {
         setMessage('种子上传成功');
+      } else if (response.data.code === 401) {
+        setMessage('未登录或登录已过期,请重新登录');
       } else {
         setMessage(response.data.message || '上传失败,请稍后再试');
       }
     } catch (error) {
       console.error('[handleSubmit] 上传失败:', error);
-      setMessage('上传失败,发生了错误');
+
+      if (error.response?.status === 401 || error.response?.data?.code === 401) {
+        setMessage('未登录或登录已过期,请重新登录');
+      } else {
+        setMessage(error.response?.data?.msg || '上传失败,发生了错误');
+      }
     } finally {
       setIsLoading(false);
     }
+
   };
 
   return (
diff --git a/src/pages/SeedList/SeedList.css b/src/pages/SeedList/SeedList.css
index cdbf651..a850dfd 100644
--- a/src/pages/SeedList/SeedList.css
+++ b/src/pages/SeedList/SeedList.css
@@ -216,4 +216,8 @@
   border-radius: 8px;
   margin-bottom: 12px;
   box-shadow: 0 4px 12px rgb(107 79 59 / 0.2);
-}
\ No newline at end of file
+}
+a {
+    color: inherit; /* 使用父元素颜色 */
+    text-decoration: none; /* 去掉下划线 */
+}
diff --git a/src/pages/SeedList/SeedList.jsx b/src/pages/SeedList/SeedList.jsx
index 45b9f8c..18a0587 100644
--- a/src/pages/SeedList/SeedList.jsx
+++ b/src/pages/SeedList/SeedList.jsx
@@ -40,9 +40,18 @@
         '种子列表': '',
     };
 
+    const formatBytes = (bytes) => {
+    if (bytes === 0 || bytes === null || bytes === undefined) return '0 B';
+    const k = 1024;
+    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+    };
+
+
     const buildQueryParams = () => {
         const category = CATEGORY_MAP[activeTab] || '';
-        const orderKey = sortOption === '最新' ? 'upload_time' : (sortOption === '最热' ? 'downloads' : 'upload_time');
+        const orderKey = sortOption === '最新' ? 'create_time' : (sortOption === '最热' ? 'leechers' : 'create_time');
         const params = {
             page: 1,
             size: 20,
@@ -51,7 +60,7 @@
         };
 
         if (searchTerm.trim()) {
-            params.title = searchTerm.trim();
+            params.keyword = searchTerm.trim();
         }
         if (category) {
             params.category = category;
@@ -69,6 +78,7 @@
         return params;
     };
 
+
     const fetchSeeds = async () => {
         if (activeTab === '猜你喜欢') return;
         setLoading(true);
@@ -121,9 +131,30 @@
         try {
             const response = await axios.get(`/seeds/${seedId}/download`, {
                 params: { passkey: user.userId },
-                responseType: 'blob'
+                responseType: 'blob',
+                validateStatus: () => true  // 允许处理非 2xx 响应
             });
 
+            if (response.data && response.data.type === 'application/json') {
+                // 服务端返回的是 JSON 而不是 torrent 文件,尝试解析内容
+                const reader = new FileReader();
+                reader.onload = () => {
+                    try {
+                        const json = JSON.parse(reader.result);
+                        if (json.code === 403 && json.msg === '您没有权限') {
+                            toast.error('您已被封禁,如有疑问请联系管理员');
+                        } else {
+                            toast.error(json.msg || '下载失败,请稍后再试。');
+                        }
+                    } catch {
+                        toast.error('下载失败,请稍后再试。');
+                    }
+                };
+                reader.readAsText(response.data);
+                return;
+            }
+
+            // 如果是 torrent 文件
             const blob = new Blob([response.data], { type: 'application/x-bittorrent' });
             const downloadUrl = URL.createObjectURL(blob);
             const a = document.createElement('a');
@@ -137,6 +168,7 @@
         }
     };
 
+
     const handleFilterChange = (key, value) => {
         setSelectedFilters(prev => ({ ...prev, [key]: value }));
     };
@@ -161,16 +193,15 @@
                     <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>
+                </select> */}
             </div>
 
             <div className="tag-filters">
                 {TAGS.map(tag => (
-                     <button
-                        // roles={["test"]}
+                    <button
                         key={tag}
                         className={`tag-button ${activeTab === tag ? 'active-tag' : ''}`}
                         onClick={() => {
@@ -240,7 +271,8 @@
                                 }
 
                                 return (
-                                    <Link to={`/seed/${seed.id}`} key={index} className="seed-item-link">
+                                    // <Link to={`/seed/${seed.id}`} key={index} className="seed-item-link">
+                                     <Link to={`/seed/${seed.id}`} key={seed.id} className="seed-item-link">
                                         <div className="seed-item">
                                             {seed.imageUrl && (
                                                 <img src={seed.imageUrl} alt={seed.title} className="seed-item-cover" />
@@ -255,12 +287,34 @@
                                                     </div>
                                                 </div>
                                             </div>
-                                            <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-size">{seed.size || '未知'}</div> */}
+                                            <div className="seed-item-size">{seed.size ? formatBytes(seed.size) : '未知'}</div>
+
+                                                <div className="seed-item-upload-time">
+                                                    {
+                                                        (() => {
+                                                        if (!seed.createdTime || !Array.isArray(seed.createdTime)) return '未知';
+                                                        const [year, month, day, hour, minute, second] = seed.createdTime;
+                                                        if ([year, month, day, hour, minute, second].some(v => typeof v !== 'number')) return '未知';
+
+                                                        const date = new Date(year, month - 1, day, hour, minute, second);
+                                                        if (isNaN(date.getTime())) return '未知';
+
+                                                        // 格式化为 yyyy-mm-dd
+                                                        const yyyy = date.getFullYear();
+                                                        const mm = String(date.getMonth() + 1).padStart(2, '0');  // 月份要加1,补0
+                                                        const dd = String(date.getDate()).padStart(2, '0');
+
+                                                        return `${yyyy}-${mm}-${dd}`;
+                                                        })()
+                                                    }
+                                                </div>
+
+
                                             <div className="seed-item-downloads">{seed.leechers ?? 0} 次下载</div>
                                             <div className="seed-item-actions" onClick={e => e.stopPropagation()}>
                                                 <AuthButton
-                                                roles={["cookie", "chocolate", "ice-cream"]}
+                                                    roles={["cookie", "chocolate", "ice-cream"]}
                                                     className="btn-primary"
                                                     onClick={e => {
                                                         e.preventDefault();