修改促销、优化页面布局

Change-Id: Iae813b5b6557efa7059fe6d94bc32e96c984e4ea
diff --git a/src/components/AuthButton.jsx b/src/components/AuthButton.jsx
index b5cc431..246555a 100644
--- a/src/components/AuthButton.jsx
+++ b/src/components/AuthButton.jsx
@@ -4,11 +4,13 @@
 const AuthButton = ({children, roles,onClick, ...rest }) => {
     const {user} = useContext(UserContext);
     const {levelRole} = user;
+    
     let clickFunc = onClick
     if(!roles || roles.length === 0 || roles.includes(levelRole)){
       clickFunc = onClick;
     }else{
-        clickFunc = () => {
+        clickFunc = (e) => {
+            e.preventDefault();
             toast.error("权限不足");
         }
     }
diff --git a/src/components/Header.css b/src/components/Header.css
index 66fe1a0..a19f9e9 100644
--- a/src/components/Header.css
+++ b/src/components/Header.css
@@ -4,7 +4,7 @@
   justify-content: space-between;
   align-items: center;
   padding: 10px 20px;
-  background-color: #6b4f3b; /* 深棕色背景 */
+  background-color: #6c3e28; /* 深棕色背景 */
   box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
 }
 
diff --git a/src/components/Header.jsx b/src/components/Header.jsx
index e0a8495..fd2a381 100644
--- a/src/components/Header.jsx
+++ b/src/components/Header.jsx
@@ -1,12 +1,13 @@
-import React, { useState, useEffect } from 'react';
+import React, { useEffect } from 'react';
 import './Header.css';
 import logo from '../assets/logo.png';
 import { useUser } from '../context/UserContext';
-import { BookOpen } from '@icon-park/react';  // 导入图标组件
+import { BookOpen } from '@icon-park/react';
+import { useLocation } from 'wouter';
 
 const Header = () => {
-  const [currentPath, setCurrentPath] = useState(window.location.pathname);
   const { user } = useUser();
+  const [location, setLocation] = useLocation();
 
   const navLinks = [
     { to: '/friend-moments', label: '好友动态' },
@@ -16,22 +17,8 @@
     { to: '/publish-seed', label: '发布种子' },
   ];
 
-  useEffect(() => {
-    const handleLocationChange = () => {
-      setCurrentPath(window.location.pathname);
-    };
-    window.addEventListener('popstate', handleLocationChange);
-    return () => {
-      window.removeEventListener('popstate', handleLocationChange);
-    };
-  }, []);
-
-  const isActive = (path) => currentPath.startsWith(path);
-
-  const handleLinkClick = (to) => {
-    window.history.pushState({}, '', to);
-    setCurrentPath(to);
-  };
+  // 头像变化时刷新组件(这段其实 React 会自动做,但你手动 history 管理就错过了)
+  useEffect(() => {}, [user?.avatarUrl]);
 
   return (
     <div className="main-page">
@@ -41,16 +28,14 @@
           <span className="site-name">Echo</span>
         </div>
         <div className="user-and-message" style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
-          {/* 新手指南图标,放在头像左边 */}
-        <button
-          className="guide-button"
-          onClick={() => handleLinkClick('/new-user-guide')}
-          title="新手指南"
-        >
-          <BookOpen theme="outline" size="20" fill="#fff" />
-          <span style={{ marginLeft: '6px' }}>新手指南</span>
-        </button>
-
+          <button
+            className="guide-button"
+            onClick={() => setLocation('/new-user-guide')}
+            title="新手指南"
+          >
+            <BookOpen theme="outline" size="20" fill="#fff" />
+            <span style={{ marginLeft: '6px' }}>新手指南</span>
+          </button>
 
           <a href="/user/profile">
             <img
@@ -59,13 +44,14 @@
               className="user-avatar"
             />
           </a>
-          <span
+
+          {/* <span
             className="message-center"
-            onClick={() => handleLinkClick('/messages')}
+            onClick={() => setLocation('/messages')}
             style={{ cursor: 'pointer' }}
           >
             消息
-          </span>
+          </span> */}
         </div>
       </header>
 
@@ -76,9 +62,9 @@
             href={to}
             onClick={(e) => {
               e.preventDefault();
-              handleLinkClick(to);
+              setLocation(to);
             }}
-            className={`nav-item ${isActive(to) ? 'active' : ''}`}
+            className={`nav-item ${location.startsWith(to) ? 'active' : ''}`}
           >
             {label}
           </a>
diff --git a/src/context/UserContext.js b/src/context/UserContext.js
index c8c65e8..493eede 100644
--- a/src/context/UserContext.js
+++ b/src/context/UserContext.js
@@ -1,4 +1,70 @@
 
+// import React, { createContext, useContext, useState, useEffect } from 'react';
+
+// const avatarBaseUrl = process.env.REACT_APP_AVATAR_BASE_URL || '';
+
+// export const UserContext = createContext();
+
+// export const UserProvider = ({ children }) => {
+//   const [user, setUser] = useState(null);
+//   const [loading, setLoading] = useState(true);
+
+//   const formatUser = (raw) => {
+//     if (!raw) return null;
+//     return {
+//       userId: raw.userId || raw.id || null,
+//       username: raw.username || '匿名用户',
+//       avatarUrl: raw.avatarUrl ? `${avatarBaseUrl}${raw.avatarUrl}` : null,
+//       ...raw,
+//     };
+//   };
+
+//   useEffect(() => {
+//     const storedUser = localStorage.getItem('user');
+//     if (storedUser) {
+//       try {
+//         const parsed = JSON.parse(storedUser);
+//         setUser(formatUser(parsed));
+//       } catch (err) {
+//         console.error('本地用户信息解析失败:', err);
+//         localStorage.removeItem('user');
+//         setUser(null);
+//       }
+//     } else {
+//       // 可以默认不自动登录,退出就是空
+//       setUser(null);
+//     }
+//     setLoading(false);
+//   }, []);
+
+//   const saveUser = (userData) => {
+//     if (userData && (userData.userId || userData.id)) {
+//       localStorage.setItem('user', JSON.stringify(userData));
+//       setUser(formatUser(userData));
+//     } else {
+//       console.error('无效的用户数据:', userData);
+//     }
+//   };
+
+//   const logout = () => {
+//     localStorage.removeItem('user');
+//     setUser(null);
+//   };
+
+//   return (
+//     <UserContext.Provider value={{ user, saveUser, logout, loading }}>
+//       {children}
+//     </UserContext.Provider>
+//   );
+// };
+
+// export const useUser = () => {
+//   const context = useContext(UserContext);
+//   if (!context) {
+//     throw new Error('useUser 必须在 UserProvider 内使用');
+//   }
+//   return context;
+// };
 import React, { createContext, useContext, useState, useEffect } from 'react';
 
 const avatarBaseUrl = process.env.REACT_APP_AVATAR_BASE_URL || '';
@@ -14,7 +80,11 @@
     return {
       userId: raw.userId || raw.id || null,
       username: raw.username || '匿名用户',
-      avatarUrl: raw.avatarUrl ? `${avatarBaseUrl}${raw.avatarUrl}` : null,
+      avatarUrl: raw.avatarUrl
+        ? raw.avatarUrl.startsWith('http')
+          ? raw.avatarUrl
+          : `${avatarBaseUrl}${raw.avatarUrl}`
+        : null,
       ...raw,
     };
   };
@@ -31,7 +101,6 @@
         setUser(null);
       }
     } else {
-      // 可以默认不自动登录,退出就是空
       setUser(null);
     }
     setLoading(false);
@@ -39,8 +108,9 @@
 
   const saveUser = (userData) => {
     if (userData && (userData.userId || userData.id)) {
-      localStorage.setItem('user', JSON.stringify(userData));
-      setUser(formatUser(userData));
+      const formatted = formatUser(userData);
+      localStorage.setItem('user', JSON.stringify(formatted));
+      setUser(formatted);
     } else {
       console.error('无效的用户数据:', userData);
     }
diff --git a/src/pages/Forum/posts-detail/PostDetailPage.jsx b/src/pages/Forum/posts-detail/PostDetailPage.jsx
index 2e4874a..bf0f062 100644
--- a/src/pages/Forum/posts-detail/PostDetailPage.jsx
+++ b/src/pages/Forum/posts-detail/PostDetailPage.jsx
@@ -5,6 +5,7 @@
 import './PostDetailPage.css';
 import { UserContext } from '../../../context/UserContext'; // 用户上下文
 import Header from '../../../components/Header';
+import AuthButton from '../../../components/AuthButton';
 
 const formatImageUrl = (url) => {
   if (!url) return '';
@@ -259,7 +260,10 @@
                       onChange={(e) => setNewComment(e.target.value)}
                     />
                     <div className="comment-options">
-                      <button onClick={handleAddComment}>发布回复</button>
+                      <AuthButton roles={['cookie', 'chocolate', 'ice-cream']} onClick={handleAddComment}>
+                        发布回复
+                      </AuthButton>
+
                       <button
                         onClick={() => {
                           setReplyToCommentId(null);
@@ -284,7 +288,10 @@
                   onChange={(e) => setNewComment(e.target.value)}
                 />
                 <div className="comment-options">
-                  <button onClick={handleAddComment}>发布评论</button>
+                  <AuthButton roles={['cookie', 'chocolate', 'ice-cream']} onClick={handleAddComment}>
+                    发布评论
+                  </AuthButton>
+
                 </div>
               </div>
             )}
diff --git a/src/pages/Forum/posts-main/ForumPage.css b/src/pages/Forum/posts-main/ForumPage.css
index 5fd64a2..4eb280f 100644
--- a/src/pages/Forum/posts-main/ForumPage.css
+++ b/src/pages/Forum/posts-main/ForumPage.css
@@ -1,8 +1,8 @@
 .forum-page {
-    color: #fff;
+    color: #453228;
     /* background-color: #5F4437; */
     /* background: linear-gradient(180deg, #5F4437, #9c737b); */
-    background: #333;
+    background: #f8f3ef;
     /* background-color: #5F4437; */
     min-height: 100vh;
     font-family: Arial, sans-serif;
@@ -37,20 +37,13 @@
     align-items: center;
   }
   
-  .avatar {
-    width: 36px;
-    height: 36px;
-    border-radius: 50%;
-    margin-right: 10px;
-  }
-  
   .nickname {
     font-weight: bold;
   }
   
-  .cover-image {
-    max-height: 80px;
-    max-width: 120px;
+  .cover {
+    max-height: 320px;
+    max-width: 320px;
     object-fit: cover;
     border-radius: 6px;
   }
diff --git a/src/pages/Forum/posts-main/components/CreatePostButton.css b/src/pages/Forum/posts-main/components/CreatePostButton.css
index 225ddde..c5cc906 100644
--- a/src/pages/Forum/posts-main/components/CreatePostButton.css
+++ b/src/pages/Forum/posts-main/components/CreatePostButton.css
@@ -1,13 +1,18 @@
 .create-post {
   display: flex;
   justify-content: center;
-  margin: 20px 0;
+  margin-top: 3%;
+  margin-bottom: -1%;
 }
 
 .create-btn {
-  background-color: #BA929A;
-  color: white;
-  padding: 10px 20px;
+  /* background-color: #BA929A;
+  color: white; */
+  /* background-color: #e9ded2; */
+  /* 使用浅色背景,符合整体风格 */
+  background: none;
+  color: #5F4437;
+  padding: 7px 15px;
   border-radius: 8px;
   border: none;
   cursor: pointer;
@@ -18,7 +23,24 @@
 }
 
 .create-btn:hover {
-  background-color: #a17b83;
+  background-color: #e9ded2;
+}
+
+.view-btn {
+  background: none;
+  color: #0f5e51;
+  padding: 7px 15px;
+  border-radius: 8px;
+  border: none;
+  cursor: pointer;
+  font-size: 16px;
+  display: flex;
+  align-items: center;
+  transition: background-color 0.3s ease;
+}
+
+.view-btn:hover {
+  background-color: #e9ded2;
 }
 
 /* Modal 样式 */
diff --git a/src/pages/Forum/posts-main/components/PostList.css b/src/pages/Forum/posts-main/components/PostList.css
index ee4d951..f6d6c2a 100644
--- a/src/pages/Forum/posts-main/components/PostList.css
+++ b/src/pages/Forum/posts-main/components/PostList.css
@@ -5,13 +5,68 @@
     padding: 30px;
   }
   
-.post-actions {
-  justify-content: flex-end; /*靠右对齐*/
+.dianzan-shoucang {
+   /*靠左对齐*/
+   display: flex;
+   justify-content: flex-start;
+   align-items: center;
+   margin-left: -30px;
 }
-  .post-card {
-    background-color: #e9ded2;
-    border: 1px solid #000000;
-    padding: 16px;
-    border-radius: 8px;
-  }
-  
\ No newline at end of file
+.post-card {
+  background-color: #e9ded2;
+  padding: 16px;
+  border-radius: 8px;
+  /* 移除固定高度 */
+  /* height: 230px; */
+  /* 添加阴影效果增强视觉层次感 */
+  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+  /* 添加过渡效果使交互更流畅 */
+  transition: transform 0.2s ease;
+}
+
+/* 鼠标悬停效果 */
+.post-card:hover {
+  transform: translateY(-2px);
+}
+  
+/* 新增:内容包装器,使用flex布局 */
+.post-content-wrapper {
+  display: flex;
+  gap: 1rem;
+  margin-top: 1rem;
+}
+
+/* 新增:左侧内容区域 */
+.post-content-left {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+}
+
+/* 新增:右侧内容区域 */
+.post-content-right {
+  flex: 0 0 30%; 
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+/* 调整封面图片样式 */
+.cover {
+  /* max-width: 100%;
+  max-height: 200px; */
+  width: 50%;
+  height: 100%;
+  object-fit: cover;
+  border-radius: 8px;
+}
+
+.custom-link {
+  color: #2196F3; /* 浅蓝色 */
+  text-decoration: none; /* 去除下划线 */
+}
+
+.custom-link:hover {
+  text-decoration: underline; /* 鼠标悬停时显示下划线 */
+}
diff --git a/src/pages/Forum/posts-main/components/PostList.jsx b/src/pages/Forum/posts-main/components/PostList.jsx
index d5ff736..cf0a424 100644
--- a/src/pages/Forum/posts-main/components/PostList.jsx
+++ b/src/pages/Forum/posts-main/components/PostList.jsx
@@ -159,45 +159,55 @@
 
               return (
                 <div key={post.postNo} className="post-card" style={{ backgroundColor: '#e9ded2' }}>
+                  {/* 用户信息 */}
                   <div className="user-info">
                     <Link href={`/information/${post.user_id}`}>
                       <img
-                        className="avatar"
+                        style={{ width: '80px', height: '80px', borderRadius: '50%', cursor: 'pointer', border: '4px solid #d2b48c' }}
                         src={post.avatarUrl}
                         alt="头像"
-                        style={{ cursor: 'pointer' }}
                       />
                     </Link>
-                    <span className="nickname" style={{ color: '#755e50' }}>{post.username}</span>
+                    <span className="nickname" style={{ color: '#755e50', marginLeft: '10px', fontSize: '20px' }}>{post.username}</span>
                   </div>
 
-                  {coverImage && <img className="cover-image" src={coverImage} alt="封面" />}
-
-                  <h3 style={{ color: '#000000' }}>{post.title || '无标题'}</h3>
-                  <div className="post-meta">
-                    <span>发布时间:{timeText}</span>
-                    <div className="post-actions">
-                      <button className="icon-btn" onClick={() => toggleLike(post.postNo, post.liked,user.userId
-)}>
-                        <GoodTwo theme="outline" size="24" fill={post.liked ? '#f00' : '#fff'} />
-                        <span>{post.likeCount}</span>
-                      </button>
-                      <button className="icon-btn" onClick={() => toggleCollect(post.postNo, post.collected, user.userId
-)}>
-                        <Star theme="outline" size="24" fill={post.collected ? '#ffd700' : '#fff'} />
-                        <span>{post.collectCount}</span>
-                      </button>
-
-                      {canDelete && (
-                        <button className="icon-btn" onClick={() => handleDeletePost(post.postNo, user.userId
-)}>
-                          <Delete theme="outline" size="24" fill="#333" />
+                  {/* 内容区 - 使用flex布局 */}
+                  <div className="post-content-wrapper">
+                    {/* 左侧内容:标题和元信息 */}
+                    <div className="post-content-left">
+                      <h3 style={{ color: '#000000' }}>{post.title || '无标题'}</h3>
+                      <div className="post-meta">
+                        <span>发布时间:{timeText}</span>
+                      </div>
+                      
+                      {/* 点赞和收藏按钮 - 移至内容下方 */}
+                      <div className="dianzan-shoucang">
+                        <button className="icon-btn" onClick={() => toggleLike(post.postNo, post.liked, user.userId)}>
+                          <GoodTwo theme="outline" size="24" fill={post.liked ? '#f00' : '#fff'} />
+                          <span>{post.likeCount}</span>
                         </button>
-                      )}
+                        <button className="icon-btn" onClick={() => toggleCollect(post.postNo, post.collected, user.userId)}>
+                          <Star theme="outline" size="24" fill={post.collected ? '#ffd700' : '#fff'} />
+                          <span>{post.collectCount}</span>
+                        </button>
+
+                        {canDelete && (
+                          <button className="icon-btn" onClick={() => handleDeletePost(post.postNo, post.user_id)}>
+                            <Delete theme="outline" size="24" fill="#333" />
+                          </button>
+                        )}
+                      </div>
+                      
+                      {/* 查看详情按钮 */}
+                      <div>
+                        <Link href={`/forum/post/${post.postNo}`} className="custom-link">查看详情</Link>
+                      </div>
                     </div>
-                  </div>
-                  <div className="detail-button-wrapper">
-                    <Link href={`/forum/post/${post.postNo}`} className="detail-button">查看详情</Link>
+
+                    {/* 右侧内容:封面图片 */}
+                    <div className="post-content-right">
+                      {coverImage && <img className="cover" src={coverImage} alt="封面" />}
+                    </div>
                   </div>
                 </div>
               );
@@ -213,5 +223,4 @@
   );
 };
 
-export default PostList;
-
+export default PostList;  
diff --git a/src/pages/Forum/promotion-part/CategoryPromotionDialog.jsx b/src/pages/Forum/promotion-part/CategoryPromotionDialog.jsx
new file mode 100644
index 0000000..101b653
--- /dev/null
+++ b/src/pages/Forum/promotion-part/CategoryPromotionDialog.jsx
@@ -0,0 +1,79 @@
+import React from 'react';
+
+const CategoryPromotionDialog = ({
+  showCategoryDialog,
+  categoryFormData,
+  handleCategoryInputChange,
+  closeCategoryDialog,
+  handleCreateCategoryPromotion
+}) => {
+  return (
+    showCategoryDialog && (
+      <div className="dialog-overlay">
+        <div className="dialog">
+          <h3>创建特定分类促销</h3>
+          <div className="form-item">
+            <label>促销名称:</label>
+            <input
+              type="text"
+              name="name"
+              value={categoryFormData.name}
+              onChange={handleCategoryInputChange}
+              placeholder="请输入促销名称"
+            />
+          </div>
+          <div className="form-item">
+            <label>开始时间:</label>
+            <input
+              type="datetime-local"
+              name="startTime"
+              value={categoryFormData.startTime}
+              onChange={handleCategoryInputChange}
+            />
+          </div>
+          <div className="form-item">
+            <label>结束时间:</label>
+            <input
+              type="datetime-local"
+              name="endTime"
+              value={categoryFormData.endTime}
+              onChange={handleCategoryInputChange}
+            />
+          </div>
+          <div className="form-item">
+            <label>折扣百分比:</label>
+            <input
+              type="number"
+              name="discountPercentage"
+              value={categoryFormData.discountPercentage}
+              onChange={handleCategoryInputChange}
+              placeholder="正数表示上传加成,负数表示下载折扣"
+              step="0.1"
+            />
+          </div>
+          <div className="form-item">
+            <label>促销类别:</label>
+            <select
+              name="category"
+              value={categoryFormData.category}
+              onChange={handleCategoryInputChange}
+            >
+              <option value="movie">电影</option>
+              <option value="tv">剧集</option>
+              <option value="music">音乐</option>
+              <option value="game">游戏</option>
+              <option value="software">软件</option>
+              <option value="book">书籍</option>
+            </select>
+          </div>
+          <div className="dialog-buttons">
+            <button onClick={handleCreateCategoryPromotion}>确定</button>
+            <button onClick={closeCategoryDialog}>取消</button>
+          </div>
+        </div>
+      </div>
+    )
+  );
+};
+
+export default CategoryPromotionDialog;    
\ No newline at end of file
diff --git a/src/pages/Forum/promotion-part/ColdTorrentsDialog.jsx b/src/pages/Forum/promotion-part/ColdTorrentsDialog.jsx
new file mode 100644
index 0000000..79d2b4b
--- /dev/null
+++ b/src/pages/Forum/promotion-part/ColdTorrentsDialog.jsx
@@ -0,0 +1,69 @@
+import React from 'react';
+
+const ColdTorrentsDialog = ({
+  showColdDialog,
+  coldTorrents,
+  closeColdDialog,
+  fetchTorrentDetail
+}) => {
+  return (
+    showColdDialog && (
+      <div className="cold-dialog-overlay">
+        <div className="cold-dialog">
+          <h3 className="cold-dialog-title">冷门资源列表</h3>
+          <button 
+            className="close-btn" 
+            onClick={closeColdDialog}
+          >
+            &times;
+          </button>
+
+          {coldTorrents.length === 0 ? (
+            <div className="empty-state">暂无冷门资源</div>
+          ) : (
+            <div className="cold-table-container">
+              <table className="cold-torrent-table">
+                <thead>
+                  <tr>
+                    <th>序号</th>
+                    <th>资源名称</th>
+                    <th>资源ID</th>
+                    <th>分类</th>
+                    <th>描述</th>
+                    <th>下载用户数</th>
+                    <th>浏览次数</th>
+                    <th>创建时间</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  {coldTorrents.map((torrent, index) => (
+                    <tr key={torrent.id}>
+                      <td>{index + 1}</td>
+                      <td>
+                        <button
+                          className="torrent-link"
+                          onClick={() => fetchTorrentDetail(torrent.id)}
+                          aria-label={`查看种子${torrent.title || torrent.id}的详情`}
+                        >
+                          {torrent.title}
+                        </button>
+                      </td>
+                      <td>{torrent.id}</td>
+                      <td>{torrent.category || '未分类'}</td>
+                      <td>{torrent.description || '无描述'}</td>
+                      <td>{torrent.leechers || 0}</td>
+                      <td>{torrent.views || 0}</td>
+                      <td>{new Date(torrent.createdTime).toLocaleDateString()}</td>
+                    </tr>
+                  ))}
+                </tbody>
+              </table>
+            </div>
+          )}
+        </div>
+      </div>
+    )
+  );
+};
+
+export default ColdTorrentsDialog;    
\ No newline at end of file
diff --git a/src/pages/Forum/promotion-part/CreatePromotionDialog.jsx b/src/pages/Forum/promotion-part/CreatePromotionDialog.jsx
new file mode 100644
index 0000000..6dcf236
--- /dev/null
+++ b/src/pages/Forum/promotion-part/CreatePromotionDialog.jsx
@@ -0,0 +1,115 @@
+import React from 'react';
+
+const CreatePromotionDialog = ({
+  showCreateDialog,
+  formData,
+  handleInputChange,
+  closeCreateDialog,
+  handleCreatePromotion,
+  fetchPromoColdTorrents,
+  showPromoColdTable,
+  coldTorrents,
+  handlePromoTorrentSelection
+}) => {
+  return (
+    showCreateDialog && (
+      <div className="dialog-overlay">
+        <div className="dialog">
+          <h3>创建冷门资源促销</h3>
+          <div className="form-item">
+            <label>促销名称:</label>
+            <input
+              type="text"
+              name="name"
+              value={formData.name}
+              onChange={handleInputChange}
+              placeholder="请输入促销名称"
+            />
+          </div>
+          <div className="form-item">
+            <label>开始时间:</label>
+            <input
+              type="datetime-local"
+              name="startTime"
+              value={formData.startTime}
+              onChange={handleInputChange}
+            />
+          </div>
+          <div className="form-item">
+            <label>结束时间:</label>
+            <input
+              type="datetime-local"
+              name="endTime"
+              value={formData.endTime}
+              onChange={handleInputChange}
+            />
+          </div>
+          <div className="form-item">
+            <label>折扣百分比:</label>
+            <input
+              type="number"
+              name="discountPercentage"
+              value={formData.discountPercentage}
+              onChange={handleInputChange}
+              placeholder="正数表示上传加成,负数表示下载折扣"
+              step="0.1"
+            />
+          </div>
+          <div className="form-item">
+            <label>适用种子:</label>
+            <button 
+              className="cold-btn small" 
+              onClick={fetchPromoColdTorrents}
+            >
+              选择冷门资源 <span>(点击加载列表)</span>
+            </button>
+            
+            {showPromoColdTable && (
+              <div className="torrent-table-container">
+                <table className="torrent-selection-table">
+                  <thead>
+                    <tr>
+                      <th>选择</th>
+                      <th>序号</th>
+                      <th>资源名称</th>
+                      <th>资源ID</th>
+                      <th>分类</th>
+                      <th>下载用户数</th>
+                      <th>浏览次数</th>
+                    </tr>
+                  </thead>
+                  <tbody>
+                    {coldTorrents.map((torrent, index) => (
+                      <tr key={torrent.id}>
+                        <td>
+                          <input
+                            type="checkbox"
+                            checked={formData.applicableTorrentIds.includes(torrent.id)}
+                            onChange={(e) => handlePromoTorrentSelection(torrent.id, e.target.checked)}
+                          />
+                        </td>
+                        <td>{index + 1}</td>
+                        <td>{torrent.title}</td>
+                        <td>{torrent.id}</td>
+                        <td>{torrent.category || '未分类'}</td>
+                        <td>{torrent.leechers || 0}</td>
+                        <td>{torrent.views || 0}</td>
+                      </tr>
+                    ))}
+                  </tbody>
+                </table>
+              </div>
+            )}
+          </div>
+
+          <div className="dialog-buttons">
+            <button onClick={handleCreatePromotion}>确定</button>
+            <button onClick={closeCreateDialog}>取消</button>
+          </div>
+        </div>
+      </div>
+    )
+  );
+};
+
+export default CreatePromotionDialog;    
\ No newline at end of file
diff --git a/src/pages/Forum/promotion-part/Promotion.css b/src/pages/Forum/promotion-part/Promotion.css
index 46e7a0d..656114a 100644
--- a/src/pages/Forum/promotion-part/Promotion.css
+++ b/src/pages/Forum/promotion-part/Promotion.css
@@ -1,83 +1,3 @@
-.promotion-container {
-  padding: 20px;
-  margin: 20px 0;
-  border-radius: 8px;
-}
-
-/* 并排两列 */
-.carousel-container {
-  display: flex;
-  gap: 20px;
-}
-
-.carousel-section {
-  flex: 1;
-}
-
-.carousel-section h2 {
-  font-size: 20px;
-  margin-bottom: 15px;
-}
-
-/* 轮播框架 */
-.carousel {
-  position: relative;
-  /* background: #a54747; */
-  /* background: linear-gradient(135deg, #4A3B34, #a54747); */
-  /* background: linear-gradient(135deg, #e38f77, #aa3e3e); */
-  /* 背景渐变 */
-  background: linear-gradient(135deg, #e1cab2, #b68791);
-  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
-  border-radius: 6px;
-  padding: 15px;
-  color: #fff;
-  min-height: 200px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-/* 左右箭头 */
-.carousel .arrow {
-  background: rgba(0,0,0,0.2);
-  border: none;
-  color: #fff;
-  font-size: 24px;
-  width: 36px;
-  height: 36px;
-  border-radius: 50%;
-  cursor: pointer;
-  position: absolute;
-  top: 50%;
-  transform: translateY(-50%);
-}
-
-.carousel .arrow.left {
-  left: 10px;
-}
-
-.carousel .arrow.right {
-  right: 10px;
-}
-
-.carousel .arrow:hover {
-  background: rgba(0,0,0,0.4);
-}
-
-/* 每帧内容 */
-.carousel .slide {
-  width: calc(100% - 80px);
-  /* 留出箭头空间 */
-  text-align: left;
-}
-
-/* 冷门资源专用 slide */
-.cold-slide {
-  display: flex;
-  gap: 10px;
-  align-items: center;
-}
-
 /* 资源海报 */
 .resource-poster {
   width: 80px;
@@ -125,7 +45,7 @@
   background: #fff;
   padding: 20px;
   border-radius: 6px;
-  width: 400px;
+  width: 80%;
   max-width: 90%;
   box-shadow: 0 0 10px rgba(0,0,0,0.25);
 }
@@ -154,3 +74,266 @@
   cursor: pointer;
 }
 
+
+/* 冷门资源模态框样式 */
+.cold-dialog-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(255, 228, 230, 0.3); /* 清透粉半透明背景 */
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1000;
+}
+
+.cold-dialog {
+  background-color: #F8F8F0; /* 米白色背景 */
+  padding: 20px;
+  border-radius: 10px;
+  box-shadow: 0 4px 12px rgba(255, 192, 203, 0.3); /* 粉调阴影 */
+  max-width: 800px;
+  width: 100%;
+}
+
+.cold-dialog-title {
+  color: #FF6B81; /* 亮粉标题 */
+  text-align: center;
+  margin-bottom: 15px;
+}
+
+.close-btn {
+  position: absolute;
+  top: 10px;
+  right: 15px;
+  font-size: 20px;
+  background: none;
+  border: none;
+  cursor: pointer;
+  color: #FF4E50; /* 深粉关闭按钮 */
+}
+
+.cold-table-container {
+  overflow-x: auto; /* 长表格横向滚动 */
+}
+
+.cold-torrent-table {
+  width: 100%;
+  border-collapse: collapse;
+  margin-top: 15px;
+  background-color: white; /* 表格白色背景 */
+}
+
+.cold-torrent-table th,
+.cold-torrent-table td {
+  padding: 12px 15px;
+  text-align: left;
+  border-bottom: 1px solid #FFE4E6; /* 清透粉分隔线 */
+}
+
+.cold-torrent-table th {
+  background-color: #FFF0F5; /* 淡粉表头背景 */
+  color: #FF69B4; /* 粉紫表头文字 */
+  font-weight: 500;
+}
+
+.cold-torrent-table tr:hover {
+  background-color: #FFF5EB; /* 米白悬停效果 */
+}
+
+.empty-state {
+  text-align: center;
+  padding: 20px;
+  color: #666;
+}
+
+/* 适配小屏幕 */
+@media (max-width: 600px) {
+  .cold-dialog {
+    margin: 20px;
+    max-width: calc(100% - 40px);
+  }
+}
+
+.cold-btn.small {
+  font-size: 0.9em;
+  padding: 5px 10px;
+  margin-top: 5px;
+}
+
+.torrent-table-container {
+  margin-top: 10px;
+  max-height: 300px;
+  overflow-y: auto;
+}
+
+.torrent-selection-table {
+  width: 100%;
+  border-collapse: collapse;
+}
+
+.torrent-selection-table th,
+.torrent-selection-table td {
+  padding: 8px 12px;
+  border: 1px solid #ddd;
+  text-align: left;
+}
+
+.torrent-selection-table th {
+  background-color: #f5f5f5;
+}
+
+.detail-dialog-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 100;
+}
+
+.detail-dialog {
+  background-color: white;
+  padding: 20px;
+  border-radius: 8px;
+  width: 90%;
+  max-width: 600px;
+  max-height: 80vh;
+  overflow-y: auto;
+}
+
+.detail-content {
+  margin-top: 20px;
+}
+
+.detail-item {
+  margin-bottom: 15px;
+  display: flex;
+}
+
+.detail-label {
+  font-weight: bold;
+  min-width: 120px;
+}
+
+.detail-value {
+  flex: 1;
+}
+
+.torrent-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.torrent-link {
+  background: none;
+  border: none;
+  color: #0066cc;
+  text-decoration: underline;
+  cursor: pointer;
+  padding: 0;
+  font-size: inherit;
+}
+
+.torrent-link:hover,
+.torrent-link:focus {
+  text-decoration: none;
+  outline: none;
+  color: #004499;
+}
+
+.torrent-detail-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 200; /* 确保在促销详情对话框之上 */
+}
+
+.torrent-detail-dialog {
+  background-color: white;
+  padding: 20px;
+  border-radius: 8px;
+  width: 90%;
+  max-width: 700px;
+  max-height: 85vh;
+  overflow-y: auto;
+}
+
+.torrent-detail-content {
+  margin-top: 20px;
+}
+
+.torrent-detail-item {
+  margin-bottom: 15px;
+  display: flex;
+}
+
+.torrent-detail-label {
+  font-weight: bold;
+  min-width: 120px;
+}
+
+.torrent-detail-value {
+  flex: 1;
+}
+
+.description {
+  white-space: pre-wrap;
+}
+
+.torrent-cover-container {
+  display: flex;
+  justify-content: center;
+  margin-bottom: 20px;
+}
+
+.torrent-cover {
+  max-width: 100%;
+  max-height: 300px;
+  object-fit: contain;
+  border-radius: 4px;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
+}
+
+.status-badge {
+  padding: 2px 8px;
+  border-radius: 4px;
+  font-size: 0.9em;
+  color: white;
+}
+
+.status-badge.hot {
+  background-color: #e53935;
+}
+
+.status-badge.cold {
+  background-color: #1e88e5;
+}
+
+.status-badge.normal {
+  background-color: #757575;
+}
+
+.download-link {
+  color: #0066cc;
+  text-decoration: none;
+  display: inline-flex;
+  align-items: center;
+}
+
+.download-link:hover {
+  text-decoration: underline;
+}
\ No newline at end of file
diff --git a/src/pages/Forum/promotion-part/Promotion.jsx b/src/pages/Forum/promotion-part/Promotion.jsx
index 953a37f..37730f3 100644
--- a/src/pages/Forum/promotion-part/Promotion.jsx
+++ b/src/pages/Forum/promotion-part/Promotion.jsx
@@ -1,832 +1,13 @@
-// import React, { useEffect, useState, useRef } from 'react';
-// import './Promotion.css';
-// import { useUser } from '../../../context/UserContext';
-
-// const Promotion = () => {
-//   const { user } = useUser();
-//   const [promotions, setPromotions] = useState([]);
-//   const [torrents, setTorrents] = useState([]);
-//   const [loading, setLoading] = useState(true);
-//   const [promoIndex, setPromoIndex] = useState(0);
-//   const promoTimerRef = useRef(null);
-
-//   // 新增:控制创建对话框显示
-//   const [showCreateDialog, setShowCreateDialog] = useState(false);
-
-//   // 创建促销活动表单状态
-//   const [formData, setFormData] = useState({
-//     name: '',
-//     startTime: '',
-//     endTime: '',
-//     discountPercentage: '',
-//     uploadCoeff: '',
-//     downloadCoeff: '',
-//     description: ''
-//   });
-
-//   useEffect(() => {
-//     fetchData();
-//     fetchTorrentList();
-//   }, []);
-
-//   useEffect(() => {
-//     if (promotions.length === 0) return;
-//     clearInterval(promoTimerRef.current);
-//     promoTimerRef.current = setInterval(() => {
-//       setPromoIndex(prev => (prev + 1) % promotions.length);
-//     }, 5000);
-//     return () => clearInterval(promoTimerRef.current);
-//   }, [promotions]);
-
-//   const fetchData = async () => {
-//     try {
-//       const response = await fetch('/seeds/promotions');
-//       const json = await response.json();
-//       const promoData = Array.isArray(json?.data) ? json.data : [];
-//       setPromotions(promoData);
-//     } catch (error) {
-//       console.error('获取促销活动失败:', error);
-//     } finally {
-//       setLoading(false);
-//     }
-//   };
-
-//   const fetchTorrentList = async () => {
-//     try {
-//       const response = await fetch('/seeds/list');
-//       const json = await response.json();
-//       const torrentList = Array.isArray(json?.data) ? json.data : [];
-//       setTorrents(torrentList);
-//     } catch (error) {
-//       console.error('获取种子列表失败:', error);
-//     }
-//   };
-
-//   // 打开创建促销活动弹窗
-//   const openCreateDialog = () => {
-//     // 重置表单数据
-//     setFormData({
-//       name: '',
-//       startTime: '',
-//       endTime: '',
-//       discountPercentage: '',
-//       uploadCoeff: '',
-//       downloadCoeff: '',
-//       description: ''
-//     });
-//     setShowCreateDialog(true);
-//   };
-
-//   // 关闭弹窗
-//   const closeCreateDialog = () => {
-//     setShowCreateDialog(false);
-//   };
-
-//   // 处理表单输入变化
-//   const handleInputChange = (e) => {
-//     const { name, value } = e.target;
-//     setFormData(prev => ({
-//       ...prev,
-//       [name]: value
-//     }));
-//   };
-
-//   // 提交创建促销活动
-//   const handleCreatePromotion = async () => {
-//     if (torrents.length === 0) {
-//       alert('没有可用的种子,请先上传种子');
-//       return;
-//     }
-//     if (!formData.name.trim()) {
-//       alert('促销名称不能为空');
-//       return;
-//     }
-//     if (!formData.startTime || !formData.endTime) {
-//       alert('促销开始时间和结束时间不能为空');
-//       return;
-//     }
-//     if (new Date(formData.startTime) >= new Date(formData.endTime)) {
-//       alert('促销结束时间必须晚于开始时间');
-//       return;
-//     }
-//     if (!formData.discountPercentage || isNaN(formData.discountPercentage)) {
-//       alert('折扣百分比必须是数字');
-//       return;
-//     }
-
-//     const applicableTorrentIds = torrents.map(t => t.id);
-
-//     const newPromo = {
-//       name: formData.name,
-//       startTime: new Date(formData.startTime).toISOString(),
-//       endTime: new Date(formData.endTime).toISOString(),
-//       discountPercentage: Number(formData.discountPercentage),
-//       uploadCoeff: formData.uploadCoeff ? Number(formData.uploadCoeff) : undefined,
-//       downloadCoeff: formData.downloadCoeff ? Number(formData.downloadCoeff) : undefined,
-//       applicableTorrentIds: JSON.stringify(applicableTorrentIds), // ✅ 关键修改
-//       description: formData.description
-//     };
-
-
-//     try {
-//       const res = await fetch('/seeds/promotions', {
-//         method: 'POST',
-//         headers: { 'Content-Type': 'application/json' },
-//         body: JSON.stringify(newPromo)
-//       });
-//       const json = await res.json();
-//       if (json.code === 200) {
-//         alert('促销活动创建成功');
-//         fetchData();
-//         setShowCreateDialog(false);
-//       } else {
-//         alert('创建失败: ' + (json.msg || '未知错误'));
-//       }
-//     } catch (err) {
-//       console.error('创建促销失败:', err);
-//       alert('创建促销失败');
-//     }
-//   };
-
-//   const handleDeletePromotion = async (promotionId) => {
-//     if (!window.confirm('确认删除该促销活动吗?')) return;
-
-//     try {
-//       const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
-//       const json = await res.json();
-//       if (json.success) {
-//         alert('删除成功');
-//         fetchData();
-//       } else {
-//         alert('删除失败: ' + json.message);
-//       }
-//     } catch (err) {
-//       console.error('删除失败:', err);
-//     }
-//   };
-
-//   const isAdmin = user?.role === 'admin';
-//   const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
-//     const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
-//   const currentPromo = promotions[promoIndex];
-
-//   if (loading) {
-//     return <div className="promotion-container">加载中...</div>;
-//   }
-
-//   return (
-//     <div className="promotion-container carousel-container">
-//       <section className="carousel-section">
-//         <h2>当前促销活动</h2>
-
-//         {isAdmin && (
-//           <button className="create-btn" onClick={openCreateDialog}>
-//             创建促销活动
-//           </button>
-//         )}
-
-//         {promotions.length === 0 || !currentPromo ? (
-//           <div className="empty-state">暂无促销活动</div>
-//         ) : (
-//           <div
-//             className="carousel"
-//             onMouseEnter={() => clearInterval(promoTimerRef.current)}
-//             onMouseLeave={() => {
-//               promoTimerRef.current = setInterval(() => {
-//                 setPromoIndex(prev => (prev + 1) % promotions.length);
-//               }, 3000);
-//             }}
-//           >
-//             <button className="arrow left" onClick={prevPromo}>&lt;</button>
-//             <div className="slide">
-//               <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
-//               <div><strong>促销时间:</strong>
-//                 {currentPromo?.pStartTime && currentPromo?.pEndTime
-//                   ? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
-//                   : '未知'}
-//               </div>
-//               <div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
-//               <div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
-//               {currentPromo?.description && (
-//                 <div><strong>描述:</strong>{currentPromo.description}</div>
-//               )}
-//               {isAdmin && (
-//                 <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
-//                   删除该活动
-//                 </button>
-//               )}
-//             </div>
-//             <button className="arrow right" onClick={nextPromo}>&gt;</button>
-//           </div>
-//         )}
-//       </section>
-
-//       {/* 创建促销活动弹窗 */}
-//       {showCreateDialog && (
-//         <div className="dialog-overlay">
-//           <div className="dialog">
-//             <h3>创建促销活动</h3>
-//             <div className="form-item">
-//               <label>促销名称:</label>
-//               <input
-//                 type="text"
-//                 name="name"
-//                 value={formData.name}
-//                 onChange={handleInputChange}
-//                 placeholder="请输入促销名称"
-//               />
-//             </div>
-//             <div className="form-item">
-//               <label>开始时间:</label>
-//               <input
-//                 type="datetime-local"
-//                 name="startTime"
-//                 value={formData.startTime}
-//                 onChange={handleInputChange}
-//               />
-//             </div>
-//             <div className="form-item">
-//               <label>结束时间:</label>
-//               <input
-//                 type="datetime-local"
-//                 name="endTime"
-//                 value={formData.endTime}
-//                 onChange={handleInputChange}
-//               />
-//             </div>
-//             <div className="form-item">
-//               <label>折扣百分比(数字):</label>
-//               <input
-//                 type="number"
-//                 name="discountPercentage"
-//                 value={formData.discountPercentage}
-//                 onChange={handleInputChange}
-//                 placeholder="例如:20 表示 20% 折扣"
-//                 min="0"
-//                 max="100"
-//               />
-//             </div>
-//             <div className="form-item">
-//               <label>上传奖励系数(可选):</label>
-//               <input
-//                 type="number"
-//                 name="uploadCoeff"
-//                 value={formData.uploadCoeff}
-//                 onChange={handleInputChange}
-//                 placeholder="例如:1.5"
-//                 step="0.1"
-//               />
-//             </div>
-//             <div className="form-item">
-//               <label>下载折扣系数(可选):</label>
-//               <input
-//                 type="number"
-//                 name="downloadCoeff"
-//                 value={formData.downloadCoeff}
-//                 onChange={handleInputChange}
-//                 placeholder="例如:0.8"
-//                 step="0.1"
-//               />
-//             </div>
-//             <div className="form-item">
-//               <label>描述(可选):</label>
-//               <textarea
-//                 name="description"
-//                 value={formData.description}
-//                 onChange={handleInputChange}
-//                 placeholder="促销活动描述"
-//                 rows={3}
-//               />
-//             </div>
-//             <div className="dialog-buttons">
-//               <button onClick={handleCreatePromotion}>确定</button>
-//               <button onClick={closeCreateDialog}>取消</button>
-//             </div>
-//           </div>
-//         </div>
-//       )}
-//     </div>
-//   );
-// };
-
-// export default Promotion;
-
-
-// // import React, { useEffect, useState, useRef } from 'react';
-// // import './Promotion.css';
-// // import { useUser } from '../../../context/UserContext';
-
-// // const Promotion = () => {
-// //   const { user } = useUser();
-// //   const [promotions, setPromotions] = useState([]);
-// //   const [torrents, setTorrents] = useState([]);
-// //   const [loading, setLoading] = useState(true);
-// //   const [promoIndex, setPromoIndex] = useState(0);
-// //   const promoTimerRef = useRef(null);
-
-// //   // 新增:控制模态框显示与表单状态
-// //   const [showCreateModal, setShowCreateModal] = useState(false);
-// //   const [formData, setFormData] = useState({
-// //     name: '',
-// //     description: '',
-// //     discountPercentage: 0,
-// //     startTime: '',
-// //     endTime: '',
-// //     applicableTorrentIds: [],
-// //   });
-
-// //   useEffect(() => {
-// //     fetchData();
-// //     fetchTorrentList();
-// //   }, []);
-
-// //   useEffect(() => {
-// //     if (promotions.length === 0) return;
-// //     clearInterval(promoTimerRef.current);
-// //     promoTimerRef.current = setInterval(() => {
-// //       setPromoIndex(prev => (prev + 1) % promotions.length);
-// //     }, 5000);
-// //     return () => clearInterval(promoTimerRef.current);
-// //   }, [promotions]);
-
-// //   const fetchData = async () => {
-// //     try {
-// //       const response = await fetch('/seeds/promotions');
-// //       const json = await response.json();
-// //       const promoData = Array.isArray(json?.data) ? json.data : [];
-// //       setPromotions(promoData);
-// //     } catch (error) {
-// //       console.error('获取促销活动失败:', error);
-// //     } finally {
-// //       setLoading(false);
-// //     }
-// //   };
-
-// //   const fetchTorrentList = async () => {
-// //     try {
-// //       const response = await fetch('/seeds/list');
-// //       const json = await response.json();
-// //       const torrentList = Array.isArray(json?.data) ? json.data : [];
-// //       setTorrents(torrentList);
-// //     } catch (error) {
-// //       console.error('获取种子列表失败:', error);
-// //     }
-// //   };
-
-// //   // 打开模态框时,重置表单数据,默认设置时间并填入所有种子ID
-// //   const openCreateModal = () => {
-// //     if (torrents.length === 0) {
-// //       alert('没有可用的种子,请先上传种子');
-// //       return;
-// //     }
-// //     setFormData({
-// //       name: '',
-// //       description: '',
-// //       discountPercentage: 20,
-// //       startTime: new Date().toISOString().slice(0, 16), // 用于datetime-local输入框,格式 YYYY-MM-DDTHH:mm
-// //       endTime: new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 16),
-// //       applicableTorrentIds: torrents.map(t => t.id),
-// //     });
-// //     setShowCreateModal(true);
-// //   };
-
-// //   // 表单输入处理
-// //   const handleInputChange = (e) => {
-// //     const { name, value } = e.target;
-// //     setFormData(prev => ({
-// //       ...prev,
-// //       [name]: name === 'discountPercentage' ? Number(value) : value,
-// //     }));
-// //   };
-
-// //   // 点击确定提交创建
-// //   const handleCreateConfirm = async () => {
-// //     if (!formData.name) {
-// //       alert('促销名称不能为空');
-// //       return;
-// //     }
-// //     if (!formData.startTime || !formData.endTime) {
-// //       alert('请选择开始时间和结束时间');
-// //       return;
-// //     }
-// //     if (formData.discountPercentage <= 0 || formData.discountPercentage >= 100) {
-// //       alert('折扣百分比应在1-99之间');
-// //       return;
-// //     }
-// //     if (!formData.applicableTorrentIds.length) {
-// //       alert('请选择适用的种子');
-// //       return;
-// //     }
-
-// //     // 准备发送数据,适配后端字段名
-// //     const newPromo = {
-// //       name: formData.name,
-// //       description: formData.description,
-// //       discountPercentage: formData.discountPercentage,
-// //       startTime: new Date(formData.startTime).toISOString(),
-// //       endTime: new Date(formData.endTime).toISOString(),
-// //       applicableTorrentIds: formData.applicableTorrentIds,
-// //     };
-
-// //     try {
-// //       const res = await fetch('/seeds/promotions', {
-// //         method: 'POST',
-// //         headers: { 'Content-Type': 'application/json' },
-// //         body: JSON.stringify(newPromo),
-// //       });
-// //       const json = await res.json();
-// //       if (json.code === 200) {
-// //         alert('促销活动创建成功');
-// //         setShowCreateModal(false);
-// //         fetchData();
-// //       } else {
-// //         alert('创建失败: ' + (json.msg || '未知错误'));
-// //       }
-// //     } catch (err) {
-// //       console.error('创建促销失败:', err);
-// //       alert('创建促销失败');
-// //     }
-// //   };
-
-// //   const handleCancel = () => {
-// //     setShowCreateModal(false);
-// //   };
-
-// //   const handleDeletePromotion = async (promotionId) => {
-// //     if (!window.confirm('确认删除该促销活动吗?')) return;
-
-// //     try {
-// //       const res = await fetch(`/seeds/promotions/${promotionId}`, { method: 'DELETE' });
-// //       const json = await res.json();
-// //       if (json.success) {
-// //         alert('删除成功');
-// //         fetchData();
-// //       } else {
-// //         alert('删除失败: ' + json.message);
-// //       }
-// //     } catch (err) {
-// //       console.error('删除失败:', err);
-// //     }
-// //   };
-
-// //   const isAdmin = user?.role === 'admin';
-// //   const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
-// //   const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
-// //   const currentPromo = promotions[promoIndex];
-
-// //   if (loading) {
-// //     return <div className="promotion-container">加载中...</div>;
-// //   }
-
-// //   return (
-// //     <div className="promotion-container carousel-container">
-// //       <section className="carousel-section">
-// //         <h2>当前促销活动</h2>
-
-// //         {isAdmin && (
-// //           <button className="create-btn" onClick={openCreateModal}>
-// //             创建促销活动
-// //           </button>
-// //         )}
-
-// //         {promotions.length === 0 || !currentPromo ? (
-// //           <div className="empty-state">暂无促销活动</div>
-// //         ) : (
-// //           <div
-// //             className="carousel"
-// //             onMouseEnter={() => clearInterval(promoTimerRef.current)}
-// //             onMouseLeave={() => {
-// //               promoTimerRef.current = setInterval(() => {
-// //                 setPromoIndex(prev => (prev + 1) % promotions.length);
-// //               }, 3000);
-// //             }}
-// //           >
-// //             <button className="arrow left" onClick={prevPromo}>&lt;</button>
-// //             <div className="slide">
-// //               <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
-// //               <div><strong>促销时间:</strong>
-// //                 {currentPromo?.startTime && currentPromo?.endTime
-// //                   ? `${new Date(currentPromo.startTime).toLocaleString()} ~ ${new Date(currentPromo.endTime).toLocaleString()}`
-// //                   : '未知'}
-// //               </div>
-// //               <div><strong>折扣百分比:</strong>{currentPromo?.discountPercentage ?? '无'}</div>
-// //               {currentPromo?.description && (
-// //                 <div><strong>描述:</strong>{currentPromo.description}</div>
-// //               )}
-// //               {isAdmin && (
-// //                 <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
-// //                   删除该活动
-// //                 </button>
-// //               )}
-// //             </div>
-// //             <button className="arrow right" onClick={nextPromo}>&gt;</button>
-// //           </div>
-// //         )}
-// //       </section>
-
-// //       {/* 创建促销模态框 */}
-// //       {showCreateModal && (
-// //         <div className="modal-overlay">
-// //           <div className="modal-content">
-// //             <h3>创建促销活动</h3>
-// //             <label>
-// //               促销名称:
-// //               <input
-// //                 type="text"
-// //                 name="name"
-// //                 value={formData.name}
-// //                 onChange={handleInputChange}
-// //               />
-// //             </label>
-// //             <label>
-// //               描述:
-// //               <textarea
-// //                 name="description"
-// //                 value={formData.description}
-// //                 onChange={handleInputChange}
-// //                 rows={3}
-// //               />
-// //             </label>
-// //             <label>
-// //               折扣百分比:
-// //               <input
-// //                 type="number"
-// //                 name="discountPercentage"
-// //                 value={formData.discountPercentage}
-// //                 min={1}
-// //                 max={99}
-// //                 onChange={handleInputChange}
-// //               />
-// //             </label>
-// //             <label>
-// //               开始时间:
-// //               <input
-// //                 type="datetime-local"
-// //                 name="startTime"
-// //                 value={formData.startTime}
-// //                 onChange={handleInputChange}
-// //               />
-// //             </label>
-// //             <label>
-// //               结束时间:
-// //               <input
-// //                 type="datetime-local"
-// //                 name="endTime"
-// //                 value={formData.endTime}
-// //                 onChange={handleInputChange}
-// //               />
-// //             </label>
-// //             <label>
-// //               适用种子ID(逗号分隔,可留空默认所有):
-// //               <input
-// //                 type="text"
-// //                 name="applicableTorrentIds"
-// //                 value={formData.applicableTorrentIds.join(',')}
-// //                 onChange={(e) => {
-// //                   const ids = e.target.value
-// //                     .split(',')
-// //                     .map(id => id.trim())
-// //                     .filter(id => id !== '')
-// //                     .map(id => Number(id))
-// //                     .filter(id => !isNaN(id));
-// //                   setFormData(prev => ({ ...prev, applicableTorrentIds: ids }));
-// //                 }}
-// //               />
-// //             </label>
-
-// //             <div className="modal-buttons">
-// //               <button onClick={handleCreateConfirm}>确定</button>
-// //               <button onClick={handleCancel}>取消</button>
-// //             </div>
-// //           </div>
-// //         </div>
-// //       )}
-
-// //       {/* 模态框简单样式 */}
-// //       <style>{`
-// //         .modal-overlay {
-// //           position: fixed;
-// //           top: 0; left: 0; right: 0; bottom: 0;
-// //           background: rgba(0,0,0,0.4);
-// //           display: flex;
-// //           justify-content: center;
-// //           align-items: center;
-// //           z-index: 999;
-// //         }
-// //         .modal-content {
-// //           background: white;
-// //           padding: 20px;
-// //           border-radius: 6px;
-// //           width: 320px;
-// //           max-width: 90%;
-// //         }
-// //         .modal-content label {
-// //           display: block;
-// //           margin-bottom: 10px;
-// //           font-size: 14px;
-// //         }
-// //         .modal-content input[type="text"],
-// //         .modal-content input[type="number"],
-// //         .modal-content input[type="datetime-local"],
-// //         .modal-content textarea {
-// //           width: 100%;
-// //           box-sizing: border-box;
-// //           padding: 5px;
-// //           font-size: 14px;
-// //           margin-top: 4px;
-// //         }
-// //         .modal-buttons {
-// //           margin-top: 15px;
-// //           text-align: right;
-// //         }
-// //         .modal-buttons button {
-// //           margin-left: 10px;
-// //           padding: 6px 12px;
-// //           font-size: 14px;
-// //         }
-// //       `}</style>
-// //     </div>
-// //   );
-// // };
-
-// // export default Promotion;
-
-
-// // import React, { useEffect, useState, useRef } from 'react';
-// // import './Promotion.css';
-// // import { useUser } from '../../../context/UserContext';
-
-// // const Promotion = () => {
-// //   const { user } = useUser();
-// //   const [promotions, setPromotions] = useState([]);
-// //   const [torrents, setTorrents] = useState([]); // 新增,存放种子列表
-// //   const [loading, setLoading] = useState(true);
-// //   const [promoIndex, setPromoIndex] = useState(0);
-// //   const promoTimerRef = useRef(null);
-
-// //   useEffect(() => {
-// //     fetchData();
-// //     fetchTorrentList();  // 新增,获取种子列表
-// //   }, []);
-
-// //   useEffect(() => {
-// //     if (promotions.length === 0) return;
-// //     clearInterval(promoTimerRef.current);
-// //     promoTimerRef.current = setInterval(() => {
-// //       setPromoIndex(prev => (prev + 1) % promotions.length);
-// //     }, 5000);
-// //     return () => clearInterval(promoTimerRef.current);
-// //   }, [promotions]);
-
-// //   // 获取促销数据
-// //   const fetchData = async () => {
-// //     try {
-// //       const response = await fetch('/seeds/promotions');
-// //       const json = await response.json();
-// //       const promoData = Array.isArray(json?.data) ? json.data : [];
-// //       setPromotions(promoData);
-// //     } catch (error) {
-// //       console.error('获取促销活动失败:', error);
-// //     } finally {
-// //       setLoading(false);
-// //     }
-// //   };
-
-// //   // 获取种子列表,赋值给torrents
-// //   const fetchTorrentList = async () => {
-// //     try {
-// //       const response = await fetch('/seeds/list');
-// //       const json = await response.json();
-// //       const torrentList = Array.isArray(json?.data) ? json.data : [];
-// //       setTorrents(torrentList);
-// //     } catch (error) {
-// //       console.error('获取种子列表失败:', error);
-// //     }
-// //   };
-
-// //   // 创建促销时,自动使用当前种子的id列表,而不是写死
-// //   const handleCreatePromotion = async () => {
-// //     if (torrents.length === 0) {
-// //       alert('没有可用的种子,请先上传种子');
-// //       return;
-// //     }
-
-// //     const applicableTorrentIds = torrents.map(t => t.id); // 获取所有种子id数组
-
-// //     const newPromo = {
-// //       name: '测试促销活动',
-// //       startTime: new Date().toISOString(),
-// //       endTime: new Date(Date.now() + 7 * 86400000).toISOString(),
-// //       discountPercentage: 20,
-// //       applicableTorrentIds: applicableTorrentIds, // 动态传入种子ID数组
-// //       description: '这是一个测试促销活动'
-// //     };
-
-// //     try {
-// //       const res = await fetch('/seeds/promotions', {
-// //         method: 'POST',
-// //         headers: {
-// //           'Content-Type': 'application/json'
-// //         },
-// //         body: JSON.stringify(newPromo)
-// //       });
-// //       const json = await res.json();
-// //       if (json.code === 200) {
-// //         alert('促销活动创建成功');
-// //         fetchData();
-// //       } else {
-// //         alert('创建失败: ' + (json.msg || '未知错误'));
-// //       }
-// //     } catch (err) {
-// //       console.error('创建促销失败:', err);
-// //       alert('创建促销失败');
-// //     }
-// //   };
-
-// //   const handleDeletePromotion = async (promotionId) => {
-// //     if (!window.confirm('确认删除该促销活动吗?')) return;
-
-// //     try {
-// //       const res = await fetch(`/seeds/promotions/${promotionId}`, {
-// //         method: 'DELETE'
-// //       });
-// //       const json = await res.json();
-// //       if (json.success) {
-// //         alert('删除成功');
-// //         fetchData();
-// //       } else {
-// //         alert('删除失败: ' + json.message);
-// //       }
-// //     } catch (err) {
-// //       console.error('删除失败:', err);
-// //     }
-// //   };
-
-// //   const isAdmin = user?.role === 'admin';
-// //   const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
-// //   const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
-// //   const currentPromo = promotions[promoIndex];
-
-// //   if (loading) {
-// //     return <div className="promotion-container">加载中...</div>;
-// //   }
-
-// //   return (
-// //     <div className="promotion-container carousel-container">
-// //       <section className="carousel-section">
-// //         <h2>当前促销活动</h2>
-
-// //         {isAdmin && (
-// //           <button className="create-btn" onClick={handleCreatePromotion}>
-// //             创建促销活动
-// //           </button>
-// //         )}
-
-// //         {promotions.length === 0 || !currentPromo ? (
-// //           <div className="empty-state">暂无促销活动</div>
-// //         ) : (
-// //           <div
-// //             className="carousel"
-// //             onMouseEnter={() => clearInterval(promoTimerRef.current)}
-// //             onMouseLeave={() => {
-// //               promoTimerRef.current = setInterval(() => {
-// //                 setPromoIndex(prev => (prev + 1) % promotions.length);
-// //               }, 3000);
-// //             }}
-// //           >
-// //             <button className="arrow left" onClick={prevPromo}>&lt;</button>
-// //             <div className="slide">
-// //               <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
-// //               <div><strong>促销时间:</strong>
-// //                 {currentPromo?.pStartTime && currentPromo?.pEndTime
-// //                   ? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
-// //                   : '未知'}
-// //               </div>
-// //               <div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
-// //               <div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
-// //               {currentPromo?.description && (
-// //                 <div><strong>描述:</strong>{currentPromo.description}</div>
-// //               )}
-// //               {isAdmin && (
-// //                 <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
-// //                   删除该活动
-// //                 </button>
-// //               )}
-// //             </div>
-// //             <button className="arrow right" onClick={nextPromo}>&gt;</button>
-// //           </div>
-// //         )}
-// //       </section>
-// //     </div>
-// //   );
-// // };
-
-// // export default Promotion;
-
-
 import React, { useEffect, useState, useRef } from 'react';
 import './Promotion.css';
 import { useUser } from '../../../context/UserContext';
+import axios from 'axios';
+import PromotionCarousel from './PromotionCarousel';
+import PromotionDetailDialog from './PromotionDetailDialog';
+import TorrentDetailDialog from './TorrentDetailDialog';
+import CreatePromotionDialog from './CreatePromotionDialog';
+import CategoryPromotionDialog from './CategoryPromotionDialog';
+import ColdTorrentsDialog from './ColdTorrentsDialog';
 
 const Promotion = () => {
   const { user } = useUser();
@@ -835,20 +16,36 @@
   const [loading, setLoading] = useState(true);
   const [promoIndex, setPromoIndex] = useState(0);
   const promoTimerRef = useRef(null);
-
-  // 新增:控制创建对话框显示
   const [showCreateDialog, setShowCreateDialog] = useState(false);
-
-  // 创建促销活动表单状态
+  const [showCategoryDialog, setShowCategoryDialog] = useState(false);
   const [formData, setFormData] = useState({
     name: '',
     startTime: '',
     endTime: '',
     discountPercentage: '',
-    uploadCoeff: '',
-    downloadCoeff: '',
-    description: ''
+    applicableTorrentIds: []
   });
+  const [categoryFormData, setCategoryFormData] = useState({
+    name: '',
+    startTime: '',
+    endTime: '',
+    discountPercentage: '',
+    category: 'movie'
+  });
+
+  // 冷门资源列表状态
+  const [coldTorrents, setColdTorrents] = useState([]);
+  const [showColdDialog, setShowColdDialog] = useState(false);
+  // 新增状态:控制促销对话框中冷门资源表格的显示
+  const [showPromoColdTable, setShowPromoColdTable] = useState(false);
+
+  // 新增状态:促销详情数据和详情对话框显示控制
+  const [promotionDetail, setPromotionDetail] = useState(null);
+  const [showDetailDialog, setShowDetailDialog] = useState(false);
+
+  // 新增状态:种子详情数据和种子详情对话框显示控制
+  const [torrentDetail, setTorrentDetail] = useState(null);
+  const [showTorrentDialog, setShowTorrentDialog] = useState(false);
 
   useEffect(() => {
     fetchData();
@@ -868,8 +65,11 @@
     try {
       const response = await fetch('/seeds/promotions');
       const json = await response.json();
-      const promoData = Array.isArray(json?.data) ? json.data : [];
-      setPromotions(promoData);
+      if (json.code === 0 || json.code === 200) {
+        setPromotions(json.data || []);
+      } else {
+        console.error('获取促销活动失败:', json.msg);
+      }
     } catch (error) {
       console.error('获取促销活动失败:', error);
     } finally {
@@ -877,38 +77,191 @@
     }
   };
 
+  const formatImageUrl = (url) => {
+    if (!url) return '';
+    const filename = url.split('/').pop();
+    return `http://localhost:5011/uploads/torrents/${filename}`;
+  };
+
+  // 修正后的获取种子详情函数
+  const fetchTorrentDetail = async (torrentId) => {
+  try {
+    // 修正参数名称为torrentId
+    const res = await axios.post(`/seeds/info/${torrentId}`);
+    if (res.data.code === 0) {
+      const seedData = res.data.data;
+      
+      // 处理封面图片
+      let cover = seedData.imageUrl;
+      if (!cover && seedData.imgUrl) {
+        const imgs = seedData.imgUrl
+          .split(',')
+          .map((i) => i.trim())
+          .filter(Boolean);
+        cover = imgs.length > 0 ? formatImageUrl(imgs[0]) : null;
+      }
+      
+      setTorrentDetail({...seedData, coverImage: cover});
+      setShowTorrentDialog(true);
+    } else {
+      alert(`获取种子详情失败: ${res.data.msg || '未知错误'}`);
+    }
+  } catch (err) {
+    console.error('获取种子详情失败:', err);
+    alert('获取种子详情失败');
+  }
+};
+
+
+const fetchPromotionDetail = async (promotionId) => {
+  try {
+    const response = await fetch(`/seeds/promotions/${promotionId}`);
+    const json = await response.json();
+    if (json.code === 0 || json.code === 200) {
+      // 正确解析applicableTorrentIds
+      const data = {
+        ...json.data,
+        applicableTorrentIds: parseTorrentIds(json.data.applicableTorrentIds)
+      };
+      setPromotionDetail(data);
+      setShowDetailDialog(true);
+    } else {
+      alert(`获取促销详情失败: ${json.msg || '未知错误'}`);
+    }
+  } catch (error) {
+    console.error('获取促销详情失败:', error);
+    alert('获取促销详情失败');
+  }
+};
+
+// 解析种子ID字符串为数组
+const parseTorrentIds = (idString) => {
+  try {
+    // 处理类似 "[69, 49, 6]" 的字符串
+    return JSON.parse(idString);
+  } catch (e) {
+    console.error('解析种子ID失败:', e);
+    return [];
+  }
+};
+
+  // 关闭详情对话框
+  const closeDetailDialog = () => {
+    setShowDetailDialog(false);
+    setPromotionDetail(null);
+  };
+
+  // 关闭种子详情对话框
+  const closeTorrentDialog = () => {
+    setShowTorrentDialog(false);
+    setTorrentDetail(null);
+  };
+
   const fetchTorrentList = async () => {
     try {
       const response = await fetch('/seeds/list');
       const json = await response.json();
-      const torrentList = Array.isArray(json?.data) ? json.data : [];
-      setTorrents(torrentList);
+      if (json.code === 0 || json.code === 200) {
+        // 为每个种子添加selected状态
+        const torrentsWithSelection = (json.data || []).map(torrent => ({
+          ...torrent,
+          selected: false
+        }));
+        setTorrents(torrentsWithSelection);
+      } else {
+        console.error('获取种子列表失败:', json.msg);
+      }
     } catch (error) {
       console.error('获取种子列表失败:', error);
     }
   };
 
-  // 打开创建促销活动弹窗
+  const fetchColdTorrents = async () => {
+    try {
+      const response = await fetch('/seeds/cold');
+      const json = await response.json();
+      if (json.code === 0 || json.code === 200) {
+        setColdTorrents(json.data || []); // 存储冷门资源数据
+        setShowColdDialog(true); // 打开模态框
+      } else {
+        alert(`获取冷门资源失败: ${json.msg || '未知错误'}`);
+      }
+    } catch (error) {
+      console.error('获取冷门资源失败:', error);
+      alert('获取冷门资源失败');
+    }
+  };
+
+  // 从服务器获取冷门资源并显示在促销对话框中
+  const fetchPromoColdTorrents = async () => {
+    try {
+      const response = await fetch('/seeds/cold');
+      const json = await response.json();
+      if (json.code === 0 || json.code === 200) {
+        setColdTorrents(json.data || []);
+        setShowPromoColdTable(true);
+      } else {
+        alert(`获取冷门资源失败: ${json.msg || '未知错误'}`);
+      }
+    } catch (error) {
+      console.error('获取冷门资源失败:', error);
+      alert('获取冷门资源失败');
+    }
+  };
+
+  // 处理促销对话框中种子的选择
+  const handlePromoTorrentSelection = (torrentId, isChecked) => {
+    setFormData(prev => {
+      const ids = [...prev.applicableTorrentIds];
+      if (isChecked) {
+        ids.push(torrentId);
+      } else {
+        const index = ids.indexOf(torrentId);
+        if (index !== -1) ids.splice(index, 1);
+      }
+      return {
+        ...prev,
+        applicableTorrentIds: ids
+      };
+    });
+  };
+
+  // 关闭冷门资源模态框
+  const closeColdDialog = () => {
+    setShowColdDialog(false);
+    setColdTorrents([]);
+  };
+
   const openCreateDialog = () => {
-    // 重置表单数据
     setFormData({
       name: '',
       startTime: '',
       endTime: '',
       discountPercentage: '',
-      uploadCoeff: '',
-      downloadCoeff: '',
-      description: ''
+      applicableTorrentIds: []
     });
     setShowCreateDialog(true);
   };
 
-  // 关闭弹窗
   const closeCreateDialog = () => {
     setShowCreateDialog(false);
   };
 
-  // 处理表单输入变化
+  const openCategoryDialog = () => {
+    setCategoryFormData({
+      name: '',
+      startTime: '',
+      endTime: '',
+      discountPercentage: '',
+      category: 'movie'
+    });
+    setShowCategoryDialog(true);
+  };
+
+  const closeCategoryDialog = () => {
+    setShowCategoryDialog(false);
+  };
+
   const handleInputChange = (e) => {
     const { name, value } = e.target;
     setFormData(prev => ({
@@ -917,12 +270,46 @@
     }));
   };
 
-  // 提交创建促销活动
+  const handleCategoryInputChange = (e) => {
+    const { name, value } = e.target;
+    setCategoryFormData(prev => ({
+      ...prev,
+      [name]: value
+    }));
+  };
+
+  const formatSize = (bytes) => {
+    if (bytes === 0) return '0 B';
+    
+    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(1024));
+    
+    return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  const handleTorrentSelection = (torrentId, isChecked) => {
+    setTorrents(prev => prev.map(torrent => 
+      torrent.id === torrentId 
+        ? {...torrent, selected: isChecked} 
+        : torrent
+    ));
+    
+    setFormData(prev => {
+      const ids = [...prev.applicableTorrentIds];
+      if (isChecked) {
+        ids.push(torrentId);
+      } else {
+        const index = ids.indexOf(torrentId);
+        if (index !== -1) ids.splice(index, 1);
+      }
+      return {
+        ...prev,
+        applicableTorrentIds: ids
+      };
+    });
+  };
+
   const handleCreatePromotion = async () => {
-    if (torrents.length === 0) {
-      alert('没有可用的种子,请先上传种子');
-      return;
-    }
     if (!formData.name.trim()) {
       alert('促销名称不能为空');
       return;
@@ -939,21 +326,19 @@
       alert('折扣百分比必须是数字');
       return;
     }
-
-    const applicableTorrentIds = torrents.map(t => t.id);
+    if (formData.applicableTorrentIds.length === 0) {
+      alert('请至少选择一个适用的种子');
+      return;
+    }
 
     const newPromo = {
       name: formData.name,
       startTime: new Date(formData.startTime).toISOString(),
       endTime: new Date(formData.endTime).toISOString(),
       discountPercentage: Number(formData.discountPercentage),
-      uploadCoeff: formData.uploadCoeff ? Number(formData.uploadCoeff) : undefined,
-      downloadCoeff: formData.downloadCoeff ? Number(formData.downloadCoeff) : undefined,
-      applicableTorrentIds: applicableTorrentIds,
-      description: formData.description
+      applicableTorrentIds: formData.applicableTorrentIds // 使用formData中的种子ID
     };
 
-
     try {
       const res = await fetch('/seeds/promotions', {
         method: 'POST',
@@ -961,12 +346,12 @@
         body: JSON.stringify(newPromo)
       });
       const json = await res.json();
-      if (json.code === 200 || json.code === 0) {
+      if (json.code === 0 || json.code === 200) {
         alert('促销活动创建成功');
         fetchData();
         setShowCreateDialog(false);
       } else {
-        alert('创建失败: ' + (json.msg || '未知错误'));
+        alert(`创建失败: ${json.msg || '未知错误'}`);
       }
     } catch (err) {
       console.error('创建促销失败:', err);
@@ -974,6 +359,51 @@
     }
   };
 
+  const handleCreateCategoryPromotion = async () => {
+    if (!categoryFormData.name.trim()) {
+      alert('促销名称不能为空');
+      return;
+    }
+    if (!categoryFormData.startTime || !categoryFormData.endTime) {
+      alert('促销开始时间和结束时间不能为空');
+      return;
+    }
+    if (new Date(categoryFormData.startTime) >= new Date(categoryFormData.endTime)) {
+      alert('促销结束时间必须晚于开始时间');
+      return;
+    }
+    if (!categoryFormData.discountPercentage || isNaN(categoryFormData.discountPercentage)) {
+      alert('折扣百分比必须是数字');
+      return;
+    }
+
+    const newPromo = {
+      name: categoryFormData.name,
+      startTime: new Date(categoryFormData.startTime).toISOString(),
+      endTime: new Date(categoryFormData.endTime).toISOString(),
+      discountPercentage: Number(categoryFormData.discountPercentage)
+    };
+
+    try {
+      const res = await fetch(`/seeds/promotions/category?category=${categoryFormData.category}`, {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify(newPromo)
+      });
+      const json = await res.json();
+      if (json.code === 0 || json.code === 200) {
+        alert('分类促销活动创建成功');
+        fetchData();
+        setShowCategoryDialog(false);
+      } else {
+        alert(`创建失败: ${json.msg || '未知错误'}`);
+      }
+    } catch (err) {
+      console.error('创建分类促销失败:', err);
+      alert('创建分类促销失败');
+    }
+  };
+
   const handleDeletePromotion = async (promotionId) => {
     if (!window.confirm('确认删除该促销活动吗?')) return;
 
@@ -984,7 +414,7 @@
         alert('删除成功');
         fetchData();
       } else {
-        alert('删除失败: ' + (json.msg || '未知错误'));
+        alert(`删除失败: ${json.msg || '未知错误'}`);
       }
     } catch (err) {
       console.error('删除失败:', err);
@@ -993,146 +423,93 @@
 
   const isAdmin = user?.role === 'admin';
   const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
-    const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
+  const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
   const currentPromo = promotions[promoIndex];
 
+  const formatDateTime = (dateTime) => {
+    if (!dateTime) return '未知';
+    return new Date(dateTime).toLocaleString();
+  };
+
+  const getUploadBonusDisplay = (promo) => {
+    if (!promo || !promo.discountPercentage) return '无';
+    const bonus = promo.discountPercentage;
+    return bonus > 0 ? `+${bonus}%` : `-${Math.abs(bonus)}%`;
+  };
+
+  const getDownloadDiscountDisplay = (promo) => {
+    if (!promo || !promo.downloadDiscount) return '无';
+    const discount = (1 - promo.downloadDiscount) * 100;
+    return discount > 0 ? `-${discount.toFixed(1)}%` : '无';
+  };
+
   if (loading) {
     return <div className="promotion-container">加载中...</div>;
-  }
+  };
 
   return (
     <div className="promotion-container carousel-container">
-      <section className="carousel-section">
-        <h2>当前促销活动</h2>
+      <PromotionCarousel
+        promotions={promotions}
+        currentPromo={currentPromo}
+        prevPromo={prevPromo}
+        nextPromo={nextPromo}
+        isAdmin={isAdmin}
+        openCreateDialog={openCreateDialog}
+        openCategoryDialog={openCategoryDialog}
+        fetchColdTorrents={fetchColdTorrents}
+        handleDeletePromotion={handleDeletePromotion}
+        fetchPromotionDetail={fetchPromotionDetail}
+      />
 
-        {isAdmin && (
-          <button className="create-btn" onClick={openCreateDialog}>
-            创建促销活动
-          </button>
-        )}
+      {/* 新增:冷门资源模态框 */}
+      <ColdTorrentsDialog
+        showColdDialog={showColdDialog}
+        coldTorrents={coldTorrents}
+        closeColdDialog={closeColdDialog}
+        fetchTorrentDetail={fetchTorrentDetail}
+      />
 
-        {promotions.length === 0 || !currentPromo ? (
-          <div className="empty-state">暂无促销活动</div>
-        ) : (
-          <div
-            className="carousel"
-            onMouseEnter={() => clearInterval(promoTimerRef.current)}
-            onMouseLeave={() => {
-              promoTimerRef.current = setInterval(() => {
-                setPromoIndex(prev => (prev + 1) % promotions.length);
-              }, 3000);
-            }}
-          >
-            <button className="arrow left" onClick={prevPromo}>&lt;</button>
-            <div className="slide">
-              <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
-              <div><strong>促销时间:</strong>
-                {currentPromo?.pStartTime && currentPromo?.pEndTime
-                  ? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
-                  : '未知'}
-              </div>
-              <div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
-              <div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
-              {currentPromo?.description && (
-                <div><strong>描述:</strong>{currentPromo.description}</div>
-              )}
-              {isAdmin && (
-                <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
-                  删除该活动
-                </button>
-              )}
-            </div>
-            <button className="arrow right" onClick={nextPromo}>&gt;</button>
-          </div>
-        )}
-      </section>
+      {/* 促销详情对话框 */}
+      <PromotionDetailDialog
+        showDetailDialog={showDetailDialog}
+        promotionDetail={promotionDetail}
+        closeDetailDialog={closeDetailDialog}
+        torrents={torrents}
+        fetchTorrentDetail={fetchTorrentDetail}
+      />
 
-      {/* 创建促销活动弹窗 */}
-      {showCreateDialog && (
-        <div className="dialog-overlay">
-          <div className="dialog">
-            <h3>创建促销活动</h3>
-            <div className="form-item">
-              <label>促销名称:</label>
-              <input
-                type="text"
-                name="name"
-                value={formData.name}
-                onChange={handleInputChange}
-                placeholder="请输入促销名称"
-              />
-            </div>
-            <div className="form-item">
-              <label>开始时间:</label>
-              <input
-                type="datetime-local"
-                name="startTime"
-                value={formData.startTime}
-                onChange={handleInputChange}
-              />
-            </div>
-            <div className="form-item">
-              <label>结束时间:</label>
-              <input
-                type="datetime-local"
-                name="endTime"
-                value={formData.endTime}
-                onChange={handleInputChange}
-              />
-            </div>
-            <div className="form-item">
-              <label>折扣百分比(数字):</label>
-              <input
-                type="number"
-                name="discountPercentage"
-                value={formData.discountPercentage}
-                onChange={handleInputChange}
-                placeholder="例如:20 表示 20% 折扣"
-                min="0"
-                max="100"
-              />
-            </div>
-            <div className="form-item">
-              <label>上传奖励系数(可选):</label>
-              <input
-                type="number"
-                name="uploadCoeff"
-                value={formData.uploadCoeff}
-                onChange={handleInputChange}
-                placeholder="例如:1.5"
-                step="0.1"
-              />
-            </div>
-            <div className="form-item">
-              <label>下载折扣系数(可选):</label>
-              <input
-                type="number"
-                name="downloadCoeff"
-                value={formData.downloadCoeff}
-                onChange={handleInputChange}
-                placeholder="例如:0.8"
-                step="0.1"
-              />
-            </div>
-            <div className="form-item">
-              <label>描述(可选):</label>
-              <textarea
-                name="description"
-                value={formData.description}
-                onChange={handleInputChange}
-                placeholder="促销活动描述"
-                rows={3}
-              />
-            </div>
-            <div className="dialog-buttons">
-              <button onClick={handleCreatePromotion}>确定</button>
-              <button onClick={closeCreateDialog}>取消</button>
-            </div>
-          </div>
-        </div>
-      )}
+      {/* 种子详情对话框 */}
+      <TorrentDetailDialog
+        showTorrentDialog={showTorrentDialog}
+        torrentDetail={torrentDetail}
+        closeTorrentDialog={closeTorrentDialog}
+      />
+
+      {/* 创建冷门资源促销弹窗 */}
+      <CreatePromotionDialog
+        showCreateDialog={showCreateDialog}
+        formData={formData}
+        handleInputChange={handleInputChange}
+        closeCreateDialog={closeCreateDialog}
+        handleCreatePromotion={handleCreatePromotion}
+        fetchPromoColdTorrents={fetchPromoColdTorrents}
+        showPromoColdTable={showPromoColdTable}
+        coldTorrents={coldTorrents}
+        handlePromoTorrentSelection={handlePromoTorrentSelection}
+      />
+
+      {/* 创建特定分类促销弹窗 */}
+      <CategoryPromotionDialog
+        showCategoryDialog={showCategoryDialog}
+        categoryFormData={categoryFormData}
+        handleCategoryInputChange={handleCategoryInputChange}
+        closeCategoryDialog={closeCategoryDialog}
+        handleCreateCategoryPromotion={handleCreateCategoryPromotion}
+      />
     </div>
   );
 };
 
-export default Promotion;
+export default Promotion;    
+
diff --git a/src/pages/Forum/promotion-part/PromotionCarousel.css b/src/pages/Forum/promotion-part/PromotionCarousel.css
new file mode 100644
index 0000000..330c886
--- /dev/null
+++ b/src/pages/Forum/promotion-part/PromotionCarousel.css
@@ -0,0 +1,150 @@
+/* 优化后的轮播样式 */
+.carousel-container {
+  display: flex;
+  margin-top: 20px;
+  margin-left: 2%;
+  margin-right: 2%;
+}
+
+.carousel-section {
+  flex: 1;
+}
+
+.carousel-section h2 {
+  font-size: 20px;
+  margin-bottom: 15px;
+}
+
+.carousel {
+  position: relative;
+  background: linear-gradient(135deg, #e1cab2, #b68791);
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
+  border-radius: 12px;
+  padding: 24px 48px;
+  color: #fff;
+  min-height: 220px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  overflow: hidden;
+}
+
+.promotion-name {
+  font-size: 24px;
+  font-weight: bold;
+  margin-top: 12px;
+  margin-bottom: 14px;
+  color: #135c69;
+  text-align: center;
+}
+
+.carousel .arrow {
+  background: rgba(0, 0, 0, 0.3);
+  border: none;
+  color: #fff;
+  font-size: 24px;
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  cursor: pointer;
+  position: absolute;
+  top: 50%;
+  transform: translateY(-50%);
+  transition: background 0.3s;
+  z-index: 10;
+}
+
+.carousel .arrow.left {
+  left: 16px;
+}
+
+.carousel .arrow.right {
+  right: 16px;
+}
+
+.carousel .arrow:hover {
+  background: rgba(0, 0, 0, 0.5);
+}
+
+.carousel .slide {
+  width: 100%;
+  max-width: 720px;
+  text-align: left;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  line-height: 1.6;
+}
+
+.carousel .slide strong {
+  font-weight: 600;
+}
+
+.carousel .action-buttons {
+  display: flex;
+  gap: 12px;
+  margin-top: 12px;
+}
+
+.carousel .action-buttons button {
+  padding: 6px 12px;
+  font-size: 14px;
+  border: none;
+  border-radius: 6px;
+  cursor: pointer;
+  transition: background-color 0.3s;
+}
+
+.carousel .delete-btn {
+  background-color: #d9534f;
+  color: white;
+}
+
+.carousel .delete-btn:hover {
+  background-color: #c9302c;
+}
+
+.carousel .view-btn {
+  background-color: #5bc0de;
+  color: white;
+}
+
+.carousel .view-btn:hover {
+  background-color: #31b0d5;
+}
+
+/* 轮播指示器容器 */
+.carousel-indicators {
+  margin-top: 5%;
+  position: absolute; 
+  bottom: 16px;       /* 距离轮播底部的间距,可调整 */
+  left: 50%;         
+  transform: translateX(-50%); /* 水平居中 */
+  display: flex;     
+  align-items: center;
+  gap: 8px;          /* 圆点间距 */
+  z-index: 10;       /* 确保在内容上层 */
+}
+
+/* 单个圆点 */
+.carousel-indicators .indicator {
+  width: 12px;       
+  height: 12px;      
+  border-radius: 50%; /* 圆形 */
+  background-color: rgba(255, 255, 255, 0.4); /* 未选中状态颜色 */
+  cursor: pointer;   
+  transition: background-color 0.3s ease; /* 渐变过渡 */
+}
+
+/* 选中状态的圆点 */
+.carousel-indicators .indicator.active {
+  background-color: #fff; /* 选中时的高亮颜色 */
+}
+
+
+/* 冷门资源专用 slide */
+.cold-slide {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+}
diff --git a/src/pages/Forum/promotion-part/PromotionCarousel.jsx b/src/pages/Forum/promotion-part/PromotionCarousel.jsx
new file mode 100644
index 0000000..6408c54
--- /dev/null
+++ b/src/pages/Forum/promotion-part/PromotionCarousel.jsx
@@ -0,0 +1,143 @@
+import React, { useState } from 'react';
+import './PromotionCarousel.css'; 
+
+const PromotionCarousel = ({
+  promotions,
+  isAdmin,
+  openCreateDialog,
+  openCategoryDialog,
+  fetchColdTorrents,
+  handleDeletePromotion,
+  fetchPromotionDetail
+}) => {
+  // 1. 新增状态:跟踪当前轮播项的索引
+  const [currentIndex, setCurrentIndex] = useState(0);
+
+  // 2. 上一个/下一个轮播的逻辑
+  const prevPromo = () => {
+    if (promotions.length === 0) return;
+    setCurrentIndex(prev => 
+      prev === 0 ? promotions.length - 1 : prev - 1
+    );
+  };
+
+  const nextPromo = () => {
+    if (promotions.length === 0) return;
+    setCurrentIndex(prev => 
+      prev === promotions.length - 1 ? 0 : prev + 1
+    );
+  };
+
+  // 3. 当前显示的促销项(从数组中取)
+  const currentPromo = promotions[currentIndex];
+
+  // 原有工具函数保持不变
+  const formatDateTime = (dateTime) => {
+    if (!dateTime) return '未知';
+    // dateTime [2025,1,3,12,10]
+    return new Date(...dateTime).toLocaleString();
+
+  };
+
+  // 修改为一个统一的处理函数,避免混淆
+const getUploadBonusDisplay = (promo) => {
+  if (!promo || typeof promo.discountPercentage !== 'number') return '无';
+  const bonus = promo.discountPercentage;
+  return bonus > 0 ? `${(bonus * 100).toFixed(0)}%` : '无';
+};
+
+const getDownloadDiscountDisplay = (promo) => {
+  if (!promo || typeof promo.discountPercentage !== 'number') return '无';
+  const discount = promo.discountPercentage;
+  return discount < 0 ? `${Math.abs(discount * 100).toFixed(0)}%` : '无';
+};
+
+
+  if (!Array.isArray(promotions) || promotions.length === 0 || !promotions[currentIndex]) {
+  return (
+    <section className="carousel-section">
+      <h2 style={{ marginLeft: '1.6rem' }}>当前促销活动</h2>
+      {isAdmin && (
+        <div style={{ display: 'flex', gap: '0px', marginBottom: '10px' }}>
+          <button className="create-btn" onClick={openCreateDialog}>
+            +创建冷门资源促销
+          </button>
+          <button className="create-btn" onClick={openCategoryDialog}>
+            +创建特定分类促销
+          </button>
+        </div>
+      )}
+      <div className="empty-state">暂无促销活动</div>
+    </section>
+  );
+}
+
+
+  return (
+    <section className="carousel-section">
+      <h2 style={{ marginLeft: '1.6rem' }}>当前促销活动</h2>
+
+      {isAdmin && (
+        <div style={{ display: 'flex', gap: '0px', marginBottom: '10px' }}>
+          <button className="create-btn" onClick={openCreateDialog}>
+            +创建冷门资源促销
+          </button>
+          <button className="create-btn" onClick={openCategoryDialog}>
+            +创建特定分类促销
+          </button>
+        </div>
+      )}
+
+      <div
+        className="carousel"
+        onMouseEnter={() => {}}
+        onMouseLeave={() => {}}
+      >
+
+        <button className="arrow left" onClick={prevPromo}>&lt;</button>
+        <div className="slide">
+          <div className='promotion-name'><strong>{currentPromo?.name ?? '未知'}</strong></div>
+          <div style={{ color: '#135c69' }}><strong>促销时间:</strong>
+            {currentPromo?.startTime && currentPromo?.endTime
+              ? `${formatDateTime(currentPromo.startTime)} ~ ${formatDateTime(currentPromo.endTime)}`
+              : '未知'}
+          </div>
+          <div style={{ color: '#135c69' }}><strong>上传奖励:</strong>{getUploadBonusDisplay(currentPromo)}</div>
+          <div style={{ color: '#135c69' }}><strong>下载折扣:</strong>{getDownloadDiscountDisplay(currentPromo)}</div>
+          {currentPromo?.description && (
+            <div><strong>描述:</strong>{currentPromo.description}</div>
+          )}            
+
+          <div className="action-buttons" style={{ display: 'flex', gap: '10px' }}>
+            {isAdmin && (
+              <button className="delete-btn" onClick={() => handleDeletePromotion(currentPromo.id)}>
+                删除活动
+              </button>
+            )}
+            <button
+              className="view-btn"
+              onClick={() => fetchPromotionDetail(currentPromo.id)}
+              aria-label={`查看${currentPromo.name}的详情`}
+            >
+              查看详情
+            </button>
+          </div>
+        </div>
+        <button className="arrow right" onClick={nextPromo}>&gt;</button>
+
+        {/* 4. 新增:底部指示器 */}
+        <div className="carousel-indicators">
+          {promotions.map((_, index) => (
+            <div
+              key={index}
+              className={`indicator ${currentIndex === index ? 'active' : ''}`}
+              onClick={() => setCurrentIndex(index)} // 点击切换轮播项
+            />
+          ))}
+        </div>
+      </div>
+    </section>
+  );
+};
+
+export default PromotionCarousel;
\ No newline at end of file
diff --git a/src/pages/Forum/promotion-part/PromotionDetailDialog.jsx b/src/pages/Forum/promotion-part/PromotionDetailDialog.jsx
new file mode 100644
index 0000000..5310c79
--- /dev/null
+++ b/src/pages/Forum/promotion-part/PromotionDetailDialog.jsx
@@ -0,0 +1,166 @@
+import { type } from '@testing-library/user-event/dist/type';
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+
+const PromotionDetailDialog = ({
+  showDetailDialog,
+  promotionDetail,
+  closeDetailDialog,
+  torrents,
+  fetchTorrentDetail
+}) => {
+  const navigate = useNavigate();
+
+  // 处理API返回的日期数组格式
+  const parseApiDate = (dateArray) => {
+    if (!Array.isArray(dateArray) || dateArray.length < 3) return null;
+    
+    // 注意:JavaScript的Date月份是从0开始的,所以需要减1
+    return new Date(
+      dateArray[0],        // 年
+      dateArray[1] - 1,    // 月 (减1)
+      dateArray[2],        // 日
+      dateArray[3] || 0,   // 时 (默认0)
+      dateArray[4] || 0,   // 分 (默认0)
+      dateArray[5] || 0    // 秒 (默认0)
+    );
+  };
+
+  const formatDateTime = (dateArray) => {
+    if (!dateArray) return '未知';
+    
+    try {
+      const date = parseApiDate(dateArray);
+      return date ? date.toLocaleString() : '格式错误';
+    } catch (e) {
+      return '格式错误';
+    }
+  };
+
+  const getUploadBonusDisplay = (promo) => {
+    if (!promo || !promo.discountPercentage) return '无';
+    const bonus = promo.discountPercentage;
+    return bonus > 0 ? `+${bonus}%` : `-${Math.abs(bonus)}%`;
+  };
+
+  const getDownloadDiscountDisplay = (promo) => {
+    if (!promo || !promo.downloadDiscount) return '无';
+    const discount = (1 - promo.downloadDiscount) * 100;
+    return discount > 0 ? `-${discount.toFixed(1)}%` : '无';
+  };
+
+  const redirectToTorrentDetail = (torrentId) => {
+    if (fetchTorrentDetail) {
+      navigate(`/seed/${torrentId}`);
+    }
+  };
+
+  return (
+    showDetailDialog && promotionDetail && (
+      <div className="detail-dialog-overlay">
+        <div className="detail-dialog">
+          <h3 className="detail-dialog-title">{promotionDetail.name}</h3>
+          <button 
+            className="close-btn" 
+            onClick={closeDetailDialog}
+          >
+            &times;
+          </button>
+          
+          <div className="detail-content">
+            {/* <div className="detail-item"> */}
+              {/* <span className="detail-label">促销ID:</span> */}
+              {/* <span className="detail-value">{promotionDetail.id}</span>
+            </div> */}
+            {/* <div className="detail-item">
+              <span className="detail-label">促销名称:</span>
+              <span className="detail-value">{promotionDetail.name}</span>
+            </div> */}
+            <div className="detail-item">
+              <span className="detail-label">开始时间:</span>
+              <span className="detail-value">{formatDateTime(promotionDetail.startTime)}</span>
+            </div>
+            <div className="detail-item">
+              <span className="detail-label">结束时间:</span>
+              <span className="detail-value">{formatDateTime(promotionDetail.endTime)}</span>
+            </div>
+            <div className="detail-item">
+              <span className="detail-label">上传奖励:</span>
+              <span className="detail-value">{getUploadBonusDisplay(promotionDetail)}</span>
+            </div>
+            <div className="detail-item">
+              <span className="detail-label">下载折扣:</span>
+              <span className="detail-value">{getDownloadDiscountDisplay(promotionDetail)}</span>
+            </div>
+            {/* <div className="detail-item">
+              <span className="detail-label">创建时间:</span>
+              <span className="detail-value">{formatDateTime(promotionDetail.createTime)}</span>
+            </div> */}
+            {/* <div className="detail-item">
+              <span className="detail-label">创建者:</span>
+              <span className="detail-value">{promotionDetail.creator || '未知'}</span>
+            </div> */}
+            
+            {promotionDetail.description && (
+              <div className="detail-item">
+                <span className="detail-label">描述:</span>
+                <span className="detail-value">{promotionDetail.description}</span>
+              </div>
+            )}
+            
+            {/* 适用种子列表 */}
+            <div className="detail-item">
+              <span className="detail-label">适用种子:</span>
+              <div className="detail-value">
+                {promotionDetail.applicableTorrentIds ? (
+                  <div className="torrent-list">
+                    {/* 解析字符串形式的数组 */}
+                    {parseTorrentIds(promotionDetail.applicableTorrentIds).map(torrentId => {
+                      const matchedTorrent = torrents.find(t => t.id === torrentId) || {};
+
+                      return (
+                        <button
+                          key={torrentId}
+                          className="torrent-link"
+                          onClick={() => redirectToTorrentDetail(torrentId)}
+                          aria-label={`查看种子${matchedTorrent.name || torrentId}的详情`}
+                        >
+                          {matchedTorrent.name || `种子${torrentId}`}
+                          {/* {matchedTorrent.seeders > 10 && <span className="status-indicator hot">热门</span>}
+                          {matchedTorrent.seeders === 0 && <span className="status-indicator cold">冷门</span>} */}
+                        </button>
+                      );
+                    })}
+                  </div>
+                ) : (
+                  <span className="empty-list">暂无适用种子</span>
+                )}
+              </div>
+            </div>
+          </div>
+          
+          <div className="dialog-buttons">
+            <button onClick={closeDetailDialog}>关闭</button>
+          </div>
+        </div>
+      </div>
+    )
+  );
+};
+
+// 解析种子ID字符串为数组
+const parseTorrentIds = (idString) => {
+  if (typeof idString === 'number') {
+    return [idString];
+  }
+
+  if (Array.isArray(idString)) {
+    return idString;
+  }
+
+  let items = typeof idString === 'string' && !idString.startsWith('[') ? idString.split(',') : JSON.parse(idString || '[]');
+
+  return items;
+};
+
+export default PromotionDetailDialog;
\ No newline at end of file
diff --git a/src/pages/Forum/promotion-part/TorrentDetailDialog.jsx b/src/pages/Forum/promotion-part/TorrentDetailDialog.jsx
new file mode 100644
index 0000000..f038b90
--- /dev/null
+++ b/src/pages/Forum/promotion-part/TorrentDetailDialog.jsx
@@ -0,0 +1,130 @@
+import React from 'react';
+
+const TorrentDetailDialog = ({
+  showTorrentDialog,
+  torrentDetail,
+  closeTorrentDialog
+}) => {
+  const formatSize = (bytes) => {
+    if (bytes === 0) return '0 B';
+    
+    const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(1024));
+    
+    return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  const formatDateTime = (dateTime) => {
+    if (!dateTime) return '未知';
+    return new Date(dateTime).toLocaleString();
+  };
+
+  return (
+    showTorrentDialog && torrentDetail && (
+      <div className="torrent-detail-overlay">
+        <div className="torrent-detail-dialog">
+          <h3 className="torrent-detail-title">种子详情 - {torrentDetail.title}</h3>
+          <button 
+            className="close-btn" 
+            onClick={closeTorrentDialog}
+          >
+            &times;
+          </button>
+          
+          {/* 封面图片 */}
+          {torrentDetail.coverImage && (
+            <div className="torrent-cover-container">
+              <img 
+                src={torrentDetail.coverImage} 
+                alt={`${torrentDetail.name}封面`} 
+                className="torrent-cover"
+              />
+            </div>
+          )}
+          
+          <div className="torrent-detail-content">
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">种子ID:</span>
+              <span className="torrent-detail-value">{torrentDetail.id}</span>
+            </div>
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">种子名称:</span>
+              <span className="torrent-detail-value">{torrentDetail.title}</span>
+            </div>
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">分类:</span>
+              <span className="torrent-detail-value">{torrentDetail.category || '未分类'}</span>
+            </div>
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">大小:</span>
+              <span className="torrent-detail-value">{formatSize(torrentDetail.size)}</span>
+            </div>
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">上传者:</span>
+              <span className="torrent-detail-value">{torrentDetail.username || '匿名'}</span>
+            </div>
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">上传时间:</span>
+              <span className="torrent-detail-value">{formatDateTime(torrentDetail.createTime)}</span>
+            </div>
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">做种人数:</span>
+              <span className="torrent-detail-value">{torrentDetail.seeders || 0}</span>
+            </div>
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">下载人数:</span>
+              <span className="torrent-detail-value">{torrentDetail.leechers || 0}</span>
+            </div>
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">完成次数:</span>
+              <span className="torrent-detail-value">{torrentDetail.completed || 0}</span>
+            </div>
+            
+            {/* 种子状态 */}
+            <div className="torrent-detail-item">
+              <span className="torrent-detail-label">状态:</span>
+              <span className="torrent-detail-value">
+                {torrentDetail.seeders > 10 ? (
+                  <span className="status-badge hot">热门</span>
+                ) : torrentDetail.seeders === 0 ? (
+                  <span className="status-badge cold">冷门</span>
+                ) : (
+                  <span className="status-badge normal">普通</span>
+                )}
+              </span>
+            </div>
+            
+            {/* 种子描述 */}
+            {torrentDetail.description && (
+              <div className="torrent-detail-item">
+                <span className="torrent-detail-label">描述:</span>
+                <div className="torrent-detail-value description">{torrentDetail.description}</div>
+              </div>
+            )}
+            
+            {/* 下载链接 */}
+            {torrentDetail.downloadUrl && (
+              <div className="torrent-detail-item">
+                <span className="torrent-detail-label">下载:</span>
+                <a 
+                  href={torrentDetail.downloadUrl} 
+                  target="_blank" 
+                  rel="noopener noreferrer"
+                  className="download-link"
+                >
+                  <i className="fa fa-download"></i> 下载种子
+                </a>
+              </div>
+            )}
+          </div>
+          
+          <div className="dialog-buttons">
+            <button onClick={closeTorrentDialog}>关闭</button>
+          </div>
+        </div>
+      </div>
+    )
+  );
+};
+
+export default TorrentDetailDialog;    
\ No newline at end of file
diff --git a/src/pages/FriendMoments/FriendMoments.css b/src/pages/FriendMoments/FriendMoments.css
index edab68f..d383c27 100644
--- a/src/pages/FriendMoments/FriendMoments.css
+++ b/src/pages/FriendMoments/FriendMoments.css
@@ -1,12 +1,3 @@
-.user-avatar {
-  width: 40px;
-  height: 40px;
-  border-radius: 50%;
-  object-fit: cover;
-  border: 1.5px solid #ddd;
-  box-shadow: 0 1px 4px rgba(0,0,0,0.1);
-}
-
 .friend-moments-container {
   margin: 0 auto;
   background: #f8f3ef;
@@ -90,9 +81,13 @@
 .delete-btn {
   background: none;
   border: none;
-  color: #f44;
+  color: rgb(139, 31, 31);
   cursor: pointer;
-  font-size: 12px;
+  /* font-size: 12px; */
+}
+
+.delete-btn:hover {
+  background: #e9ded2;
 }
 
 .modal-overlay {
@@ -188,17 +183,6 @@
   margin-bottom: 10px;
 }
 
-.feed-title {
-  font-size: 1.2em;
-  font-weight: bold;
-  margin-bottom: 8px;
-}
-
-.feed-content {
-  margin-bottom: 12px;
-  line-height: 1.5;
-}
-
 .feed-images {
   display: grid;
   grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
@@ -235,13 +219,6 @@
   color: #555;
 }
 
-.delete-btn {
-  background: none;
-  border: none;
-  color: #f44336;
-  cursor: pointer;
-}
-
 .comment-box {
   margin-top: 12px;
 }
@@ -284,6 +261,8 @@
 }
 
 .comment-user {
+  margin-bottom: 0.5%;
+  font-size: 1.2em;
   font-weight: bold;
   color: #333;
 }
@@ -310,6 +289,7 @@
   font-size: 0.9em;
   cursor: pointer;
   padding: 0;
+  margin-left: 0px;
 }
 
 .nested-replies {
diff --git a/src/pages/FriendMoments/FriendMoments.jsx b/src/pages/FriendMoments/FriendMoments.jsx
index ab1aef2..0d92303 100644
--- a/src/pages/FriendMoments/FriendMoments.jsx
+++ b/src/pages/FriendMoments/FriendMoments.jsx
@@ -1,1341 +1,3 @@
-// // FriendMoments.js
-// import React, { useContext, useState, useEffect } from 'react'; 
-// import axios from 'axios';
-// import './FriendMoments.css';
-// import Header from '../../components/Header';
-// import { Edit, GoodTwo, Comment } from '@icon-park/react';
-// import { UserContext } from '../../context/UserContext'; // 引入用户上下文
-
-// // 修改后的封面图 URL 拼接函数
-// const formatImageUrl = (url) => {
-//   if (!url) return '';
-//   const filename = url.split('/').pop(); // 提取文件名部分
-//   return `http://localhost:5011/uploads/dynamic/${filename}`;
-// };
-
-// const FriendMoments = () => {
-//   const [feeds, setFeeds] = useState([]);
-//   const [filteredFeeds, setFilteredFeeds] = useState([]);
-//   const [query, setQuery] = useState('');
-//   const [loading, setLoading] = useState(true);
-//   const [error, setError] = useState(null);
-
-//   // 从上下文中获取用户信息
-//   const { user } = useContext(UserContext);
-//   const userId = user?.userId || null; // 从用户上下文中获取userId
-//   const username = user?.username || '未知用户'; // 获取用户名
-
-//   // Modal state & form fields
-//   const [showModal, setShowModal] = useState(false);
-//   const [title, setTitle] = useState('');
-//   const [content, setContent] = useState('');
-//   const [selectedImages, setSelectedImages] = useState([]);
-//   const [previewUrls, setPreviewUrls] = useState([]);
-
-//   // 检查用户是否已登录
-//   const isLoggedIn = !!userId;
-
-//   // 拉取好友动态列表
-//   const fetchFeeds = async () => {
-//     if (!isLoggedIn) {
-//       setLoading(false);
-//       setError('请先登录');
-//       return;
-//     }
-
-//     setLoading(true);
-//     setError(null);
-//     try {
-//       // 注意这里修改了API路径,使用getAllDynamics接口
-//       const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
-      
-//       // 检查API返回的数据结构
-//       console.log('API响应数据:', res.data);
-      
-//       // 从响应中提取dynamic数组
-//       const dynamicList = res.data.dynamic || [];
-      
-//       // 将API返回的数据结构转换为前端期望的格式
-//       const formattedFeeds = dynamicList.map(item => ({
-//         postNo: item.dynamic_id, // 使用API返回的dynamic_id作为帖子ID
-//         title: item.title,
-//         postContent: item.content,
-//         imageUrl: item.images, // 使用API返回的images字段
-//         postTime: item.time, // 使用API返回的time字段
-//         postLikeNum: item.likes?.length || 0, // 点赞数
-//         liked: item.likes?.some(like => like.user_id === userId), // 当前用户是否已点赞
-//         user_id: item.user_id, // 发布者ID
-//         username: item.username, // 发布者昵称
-//         avatar_url: item.avatar_url, // 发布者头像
-//         comments: item.comments || [] // 评论列表
-//       }));
-      
-//       setFeeds(formattedFeeds);
-//       setFilteredFeeds(formattedFeeds);
-//     } catch (err) {
-//       console.error('获取动态列表失败:', err);
-//       setError('获取动态列表失败,请稍后重试');
-//     } finally {
-//       setLoading(false);
-//     }
-//   };
-
-//   useEffect(() => {
-//     fetchFeeds();
-//   }, [userId]);
-
-//   // 搜索处理
-//   const handleSearch = () => {
-//     const q = query.trim().toLowerCase();
-//     if (!q) {
-//       setFilteredFeeds(feeds);
-//       return;
-//     }
-//     setFilteredFeeds(
-//       feeds.filter(f => 
-//         (f.title || '').toLowerCase().includes(q) || 
-//         (f.postContent || '').toLowerCase().includes(q)
-//       )
-//     );
-//   };
-
-//   const handleReset = () => {
-//     setQuery('');
-//     setFilteredFeeds(feeds);
-//   };
-
-//   // 对话框内:处理图片选择
-//   const handleImageChange = (e) => {
-//     const files = Array.from(e.target.files);
-//     if (!files.length) return;
-    
-//     const previewUrls = files.map(file => URL.createObjectURL(file));
-    
-//     setSelectedImages(files);
-//     setPreviewUrls(previewUrls);
-//   };
-
-//   // 对话框内:提交新动态
-//   const handleSubmit = async () => {
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     if (!content.trim()) {
-//       alert('内容不能为空');
-//       return;
-//     }
-
-//     try {
-//       // 使用formData格式提交
-//       const formData = new FormData();
-//       formData.append('title', title.trim() || '');
-//       formData.append('content', content.trim());
-      
-//       // 添加图片文件
-//       selectedImages.forEach((file, index) => {
-//         formData.append('image_url', file);
-//       });
-
-//       // 调用创建动态API
-//       await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
-//         headers: {
-//           'Content-Type': 'multipart/form-data'
-//         }
-//       });
-
-//       // 重置表单
-//       setTitle('');
-//       setContent('');
-//       setSelectedImages([]);
-//       setPreviewUrls([]);
-//       setShowModal(false);
-//       fetchFeeds();
-//       alert('发布成功');
-//     } catch (err) {
-//       console.error('发布失败', err);
-//       alert('发布失败,请稍后重试');
-//     }
-//   };
-
-//   // 删除动态 - 注意:API文档中未提供删除接口,这里保留原代码
-//   const handleDelete = async (dynamicId) => {
-  
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     if (!window.confirm('确定要删除这条动态吗?')) return;
-//     try {
-//       // 注意:API文档中未提供删除接口,这里使用原代码中的路径
-//       await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
-//       fetchFeeds();
-//       alert('删除成功');
-//     } catch (err) {
-//       console.error('删除失败', err);
-//       alert('删除失败,请稍后重试');
-//     }
-//   };
-
-//   // 点赞动态
-//   const handleLike = async (dynamicId, islike) => {
-//     if (islike) {
-//       handleUnlike(dynamicId);
-//       return
-//     }
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     // 验证dynamicId是否有效
-//     if (!dynamicId) {
-//       console.error('无效的dynamicId:', dynamicId);
-//       alert('点赞失败:动态ID无效');
-//       return;
-//     }
-
-//     console.log('当前用户ID:', userId);
-//     console.log('即将点赞的动态ID:', dynamicId);
-    
-//     try {
-//       // 确保参数是整数类型
-//       const requestData = {
-//         userId: parseInt(userId),
-//         dynamicId: parseInt(dynamicId)
-//       };
-      
-//       // 验证参数是否为有效数字
-//       if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
-//         console.error('无效的参数:', requestData);
-//         alert('点赞失败:参数格式错误');
-//         return;
-//       }
-      
-//       console.log('点赞请求数据:', requestData);
-      
-//       const res = await axios.post(`/echo/dynamic/like`, requestData, {
-//         headers: {
-//           'Content-Type': 'application/json' // 明确指定JSON格式
-//         }
-//       });
-      
-//       console.log('点赞API响应:', res.data);
-      
-//       if (res.status === 200) {
-//         // 更新本地状态
-//         setFeeds(prevFeeds => {
-//           return prevFeeds.map(feed => {
-//             if (feed.postNo === dynamicId) {
-//               return {
-//                 ...feed,
-//                 postLikeNum: (feed.postLikeNum || 0) + 1,
-//                 liked: true
-//               };
-//             }
-//             return feed;
-//           });
-//         });
-//       } else {
-//         alert(res.data.message || '点赞失败');
-//       }
-//     } catch (err) {
-//       console.error('点赞失败', err);
-      
-//       // 检查错误响应,获取更详细的错误信息
-//       if (err.response) {
-//         console.error('错误响应数据:', err.response.data);
-//         console.error('错误响应状态:', err.response.status);
-//         console.error('错误响应头:', err.response.headers);
-//       }
-      
-//       alert('点赞失败,请稍后重试');
-//     }
-//   };
-
-//   // 取消点赞
-//   const handleUnlike = async (dynamicId) => {
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     // 验证dynamicId是否有效
-//     if (!dynamicId) {
-//       console.error('无效的dynamicId:', dynamicId);
-//       alert('取消点赞失败:动态ID无效');
-//       return;
-//     }
-
-//     // 检查是否已经取消点赞,防止重复请求
-//     const currentFeed = feeds.find(feed => feed.postNo === dynamicId);
-//     if (currentFeed && !currentFeed.liked) {
-//       console.warn('尝试重复取消点赞,已忽略');
-//       return;
-//     }
-
-//     try {
-//       // 确保参数是整数类型
-//       const requestData = {
-//         userId: parseInt(userId),
-//         dynamicId: parseInt(dynamicId)
-//       };
-      
-//       // 验证参数是否为有效数字
-//       if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
-//         console.error('无效的参数:', requestData);
-//         alert('取消点赞失败:参数格式错误');
-//         return;
-//       }
-      
-//       console.log('取消点赞请求数据:', requestData);
-      
-//       const res = await axios.delete(`/echo/dynamic/unlike`, {
-//         headers: {
-//           'Content-Type': 'application/json' // 明确指定JSON格式
-//         },
-//         data: requestData // 将参数放在data属性中
-//       });
-      
-//       console.log('取消点赞API响应:', res.data);
-      
-//       if (res.status === 200) {
-//         // 更新本地状态
-//         setFeeds(prevFeeds => {
-//           return prevFeeds.map(feed => {
-//             if (feed.postNo === dynamicId) {
-//               return {
-//                 ...feed,
-//                 postLikeNum: Math.max(0, (feed.postLikeNum || 0) - 1),
-//                 liked: false
-//               };
-//             }
-//             return feed;
-//           });
-//         });
-//       } else {
-//         alert(res.data.message || '取消点赞失败');
-//       }
-//     } catch (err) {
-//       console.error('取消点赞失败', err);
-      
-//       // 检查错误响应,获取更详细的错误信息
-//       if (err.response) {
-//         console.error('错误响应数据:', err.response.data);
-//         console.error('错误响应状态:', err.response.status);
-//         console.error('错误响应头:', err.response.headers);
-//       }
-      
-//       alert('取消点赞失败,请稍后重试');
-//     }
-//   };
-
-//   // 评论好友动态
-//   const handleComment = async (dynamicId, parentCommentId = null, replyToUsername = '') => {
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     const commentInputId = `comment-input-${dynamicId}-${parentCommentId}`;
-//     const commentInput = document.getElementById(commentInputId);
-    
-//     if (!commentInput || !commentInput.value.trim()) {
-//       alert('评论内容不能为空');
-//       return;
-//     }
-
-//     const commentContent = commentInput.value.trim();
-
-//     try {
-//       // 准备请求数据
-//       const requestData = {
-//         content: commentContent
-//       };
-      
-//       // 如果是回复,添加parent_comment_id
-//       if (parentCommentId) {
-//         requestData.parent_comment_id = parentCommentId;
-//       }
-      
-//       const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, requestData);
-
-//       if (res.status === 200 || res.status === 201) {
-//         // 创建新评论对象
-//         const newComment = {
-//           // 使用API返回的评论ID,如果没有则生成临时ID
-//           id: res.data.comment_id || `temp-${Date.now()}`,
-//           user_id: userId,
-//           username: username,
-//           content: commentContent,
-//           time: new Date().toISOString(),
-//           // 如果是回复,添加reply_to_username
-//           ...(replyToUsername && { reply_to_username: replyToUsername })
-//         };
-
-//         // 更新本地状态
-//         setFeeds(prevFeeds => {
-//           return prevFeeds.map(feed => {
-//             if (feed.postNo === dynamicId) {
-//               if (parentCommentId) {
-//                 // 这是一个回复,找到父评论并添加到其replies数组
-//                 return {
-//                   ...feed,
-//                   comments: feed.comments.map(comment => {
-//                     if (comment.id === parentCommentId || comment.postNo === parentCommentId) {
-//                       // 确保replies数组存在
-//                       if (!comment.replies) {
-//                         return {
-//                           ...comment,
-//                           replies: [newComment]
-//                         };
-//                       }
-//                       return {
-//                         ...comment,
-//                         replies: [...comment.replies, newComment]
-//                       };
-//                     }
-//                     return comment;
-//                   })
-//                 };
-//               } else {
-//                 // 这是一个新评论,添加到评论列表
-//                 return {
-//                   ...feed,
-//                   comments: [...feed.comments, newComment]
-//                 };
-//               }
-//             }
-//             return feed;
-//           });
-//         });
-
-//         // 清空输入框并隐藏回复框
-//         if (commentInput) {
-//           commentInput.value = '';
-//         }
-//         toggleReplyBox(dynamicId, parentCommentId);
-//       } else {
-//         alert(res.data.error || '评论失败');
-//       }
-//     } catch (err) {
-//       console.error('评论失败', err);
-//       alert('评论失败,请稍后重试');
-//     }
-//   };
-
-//   // 切换回复框显示状态
-//   const toggleReplyBox = (dynamicId, parentCommentId = null) => {
-//     const replyBoxId = `reply-box-${dynamicId}-${parentCommentId}`;
-//     const replyBox = document.getElementById(replyBoxId);
-    
-//     if (replyBox) {
-//       replyBox.style.display = replyBox.style.display === 'none' ? 'block' : 'none';
-      
-//       // 如果显示,聚焦到输入框
-//       if (replyBox.style.display === 'block') {
-//         const commentInput = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
-//         if (commentInput) commentInput.focus();
-//       }
-//     }
-//   };
-
-//   return (
-//     <div className="friend-moments-container">
-//       <Header />
-//       <div className="fm-header">
-//         <button className="create-btn" onClick={() => setShowModal(true)}>
-//           <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
-//           创建动态
-//         </button>
-//       </div>
-
-//       <div className="feed-list">
-//         {loading ? (
-//           <div className="loading-message">加载中...</div>
-//         ) : error ? (
-//           <div className="error-message">{error}</div>
-//         ) : !isLoggedIn ? (
-//           <div className="login-prompt">
-//             <p>请先登录查看好友动态</p>
-//           </div>
-//         ) : filteredFeeds.length === 0 ? (
-//           <div className="empty-message">暂无动态</div>
-//         ) : (
-//           filteredFeeds.map(feed => (
-//             <div className="feed-item" key={feed.postNo || `feed-${Math.random()}`}>
-//               {/* 显示发布者信息 */}
-//               <div className="feed-author">
-//                 <img
-//                   className="user-avatar"
-//                   src={feed.avatar_url || 'https://example.com/default-avatar.jpg'}
-//                   alt={feed.username || '用户头像'}
-//                 />
-//                 <div>
-//                   <h4>{feed.username || '未知用户'}</h4>
-//                   <span className="feed-date">{new Date(feed.postTime || Date.now()).toLocaleString()}</span>
-//                 </div>
-//               </div>
-
-//               {feed.title && <h4 className="feed-title">{feed.title}</h4>}
-//               <p className="feed-content">{feed.postContent || '无内容'}</p>
-
-//               {feed.imageUrl && (
-//                 <div className="feed-images">
-//                   {typeof feed.imageUrl === 'string' ? (
-//                     <img src={formatImageUrl(feed.imageUrl)} alt="动态图片" />
-//                   ) : (
-//                     feed.imageUrl.map((url, i) => (
-//                       <img key={i} src={formatImageUrl(url)} alt={`动态图${i}`} />
-//                     ))
-//                   )}
-//                 </div>
-//               )}
-
-//               <div className="feed-footer">
-//                 <div className="like-container">
-//                   <button className="icon-btn" onClick={() => handleLike(feed.postNo, feed.liked, feed.user_id)}>
-//                     <GoodTwo theme="outline" size="24" fill={feed.liked ? '#f00' : '#fff'} />
-//                     <span>{feed.postLikeNum || 0}</span>
-//                   </button>
-
-//                   <button
-//                     className="icon-btn"
-//                     onClick={() => toggleReplyBox(feed.postNo)}
-//                   >
-//                     <Comment theme="outline" size="24" fill="#333" />
-//                     <span>评论</span>
-//                   </button>
-//                 </div>
-                
-//                 {feed.user_id === userId && (
-//                   <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
-//                     删除
-//                   </button>
-//                 )}
-//               </div>
-
-//               {/* 动态的评论输入框 */}
-//               <div id={`reply-box-${feed.postNo}-null`} className="comment-box" style={{display: 'none'}}>
-//                 <textarea
-//                   id={`comment-input-${feed.postNo}-null`}
-//                   className="comment-input"
-//                   placeholder="请输入评论内容..."
-//                 />
-//                 <button
-//                   className="submit-comment-btn"
-//                   onClick={() => handleComment(feed.postNo)}
-//                 >
-//                   发布评论
-//                 </button>
-//               </div>
-
-//               {/* 评论列表 */}
-//               {Array.isArray(feed.comments) && feed.comments.length > 0 && (
-//                 <div className="comments-container">
-//                   <h5>评论 ({feed.comments.length})</h5>
-//                   <div className="comments-list">
-//                     {feed.comments.map((comment, index) => (
-//                       <div className="comment-item" key={comment.id || index}>
-//                         <div className="comment-header">
-//                           <span className="comment-user">{comment.username || '用户'}</span>
-//                           <span className="comment-time">
-//                             {new Date(comment.time || Date.now()).toLocaleString()}
-//                           </span>
-//                         </div>
-//                         <p className="comment-content">
-//                           {/* 显示回复格式 */}
-//                           {comment.reply_to_username ? 
-//                             <span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> : 
-//                             <span>{comment.username}:</span>
-//                           }
-//                           {comment.content}
-//                         </p>
-//                         <button 
-//                           className="reply-btn" 
-//                           onClick={() => toggleReplyBox(feed.postNo, comment.id || index, comment.username)}
-//                         >
-//                           回复
-//                         </button>
-                        
-//                         {/* 该评论的回复框 */}
-//                         <div id={`reply-box-${feed.postNo}-${comment.id || index}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
-//                           <textarea
-//                             id={`comment-input-${feed.postNo}-${comment.id || index}`}
-//                             className="comment-input"
-//                             placeholder={`回复 ${comment.username}...`}
-//                           />
-//                           <button
-//                             className="submit-comment-btn"
-//                             onClick={() => handleComment(feed.postNo, comment.id || index, comment.username)}
-//                           >
-//                             发布回复
-//                           </button>
-//                         </div>
-                        
-//                         {/* 嵌套回复 */}
-//                         {Array.isArray(comment.replies) && comment.replies.length > 0 && (
-//                           <div className="nested-replies">
-//                             {comment.replies.map((reply, replyIndex) => (
-//                               <div className="reply-item" key={reply.id || `${comment.id || index}-${replyIndex}`}>
-//                                 <p className="reply-content">
-//                                   {reply.reply_to_username ? 
-//                                     <span className="reply-prefix">{reply.username} 回复 {reply.reply_to_username}:</span> : 
-//                                     <span>{reply.username}:</span>
-//                                   }
-//                                   {reply.content}
-//                                 </p>
-//                                 <button 
-//                                   className="reply-btn" 
-//                                   onClick={() => toggleReplyBox(feed.postNo, reply.id || `${comment.id || index}-${replyIndex}`, reply.username)}
-//                                 >
-//                                   回复
-//                                 </button>
-                                
-//                                 {/* 该回复的回复框 */}
-//                                 <div id={`reply-box-${feed.postNo}-${reply.id || `${comment.id || index}-${replyIndex}`}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
-//                                   <textarea
-//                                     id={`comment-input-${feed.postNo}-${reply.id || `${comment.id || index}-${replyIndex}`}`}
-//                                     className="comment-input"
-//                                     placeholder={`回复 ${reply.username}...`}
-//                                   />
-//                                   <button
-//                                     className="submit-comment-btn"
-//                                     onClick={() => handleComment(feed.postNo, reply.id || `${comment.id || index}-${replyIndex}`, reply.username)}
-//                                   >
-//                                     发布回复
-//                                   </button>
-//                                 </div>
-//                               </div>
-//                             ))}
-//                           </div>
-//                         )}
-//                       </div>
-//                     ))}
-//                   </div>
-//                 </div>
-//               )}
-//             </div>
-//           ))
-//         )}
-//       </div>
-
-//       {/* Modal 对话框 */}
-//       {showModal && (
-//         <div className="modal-overlay" onClick={() => setShowModal(false)}>
-//           <div className="modal-dialog" onClick={e => e.stopPropagation()}>
-//             <h3>发布新动态</h3>
-//             <input
-//               type="text"
-//               placeholder="标题"
-//               value={title}
-//               onChange={e => setTitle(e.target.value)}
-//             />
-//             <textarea
-//               placeholder="写下你的内容..."
-//               value={content}
-//               onChange={e => setContent(e.target.value)}
-//             />
-//             <label className="file-label">
-//               选择图片
-//               <input
-//                 type="file"
-//                 accept="image/*"
-//                 multiple
-//                 onChange={handleImageChange}
-//                 style={{ display: 'none' }}
-//               />
-//             </label>
-//             <div className="cf-preview">
-//               {previewUrls.map((url, i) => (
-//                 <img key={i} src={url} alt={`预览${i}`} />
-//               ))}
-//             </div>
-//             <div className="modal-actions">
-//               <button className="btn cancel" onClick={() => setShowModal(false)}>
-//                 取消
-//               </button>
-//               <button className="btn submit" onClick={handleSubmit}>
-//                 发布
-//               </button>
-//             </div>
-//           </div>
-//         </div>
-//       )}
-//     </div>
-//   );
-// };
-
-// export default FriendMoments;
-// // FriendMoments.js
-// import React, { useContext, useState, useEffect } from 'react'; 
-// import axios from 'axios';
-// import './FriendMoments.css';
-// import Header from '../../components/Header';
-// import { Edit, GoodTwo, Comment } from '@icon-park/react';
-// import { UserContext } from '../../context/UserContext'; // 引入用户上下文
-
-// // 修改后的封面图 URL 拼接函数
-// const formatImageUrl = (url) => {
-//   if (!url) return '';
-//   const filename = url.split('/').pop(); // 提取文件名部分
-//   return `http://localhost:5011/uploads/dynamic/${filename}`;
-// };
-
-// const FriendMoments = () => {
-//   const [feeds, setFeeds] = useState([]);
-//   const [filteredFeeds, setFilteredFeeds] = useState([]);
-//   const [query, setQuery] = useState('');
-//   const [loading, setLoading] = useState(true);
-//   const [error, setError] = useState(null);
-
-//   // 从上下文中获取用户信息
-//   const { user } = useContext(UserContext);
-//   const userId = user?.userId || null; // 从用户上下文中获取userId
-//   const username = user?.username || '未知用户'; // 获取用户名
-
-//   // Modal state & form fields
-//   const [showModal, setShowModal] = useState(false);
-//   const [title, setTitle] = useState('');
-//   const [content, setContent] = useState('');
-//   const [selectedImages, setSelectedImages] = useState([]);
-//   const [previewUrls, setPreviewUrls] = useState([]);
-
-//   // 检查用户是否已登录
-//   const isLoggedIn = !!userId;
-
-//   // 拉取好友动态列表
-//   const fetchFeeds = async () => {
-//     if (!isLoggedIn) {
-//       setLoading(false);
-//       setError('请先登录');
-//       return;
-//     }
-
-//     setLoading(true);
-//     setError(null);
-//     try {
-//       // 注意这里修改了API路径,使用getAllDynamics接口
-//       const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
-      
-//       // 检查API返回的数据结构
-//       console.log('API响应数据:', res.data);
-      
-//       // 从响应中提取dynamic数组
-//       const dynamicList = res.data.dynamic || [];
-      
-//       // 将API返回的数据结构转换为前端期望的格式
-//       const formattedFeeds = dynamicList.map(item => ({
-//         postNo: item.dynamic_id, // 使用API返回的dynamic_id作为帖子ID
-//         title: item.title,
-//         postContent: item.content,
-//         imageUrl: item.images, // 使用API返回的images字段
-//         postTime: item.time, // 使用API返回的time字段
-//         postLikeNum: item.likes?.length || 0, // 点赞数
-//         liked: item.likes?.some(like => like.user_id === userId), // 当前用户是否已点赞
-//         user_id: item.user_id, // 发布者ID
-//         username: item.username, // 发布者昵称
-//         avatar_url: item.avatar_url, // 发布者头像
-//         comments: item.comments || [] // 评论列表
-//       }));
-      
-//       setFeeds(formattedFeeds);
-//       setFilteredFeeds(formattedFeeds);
-//     } catch (err) {
-//       console.error('获取动态列表失败:', err);
-//       setError('获取动态列表失败,请稍后重试');
-//     } finally {
-//       setLoading(false);
-//     }
-//   };
-
-//   useEffect(() => {
-//     fetchFeeds();
-//   }, [userId]);
-
-//   // 搜索处理
-//   const handleSearch = () => {
-//     const q = query.trim().toLowerCase();
-//     if (!q) {
-//       setFilteredFeeds(feeds);
-//       return;
-//     }
-//     setFilteredFeeds(
-//       feeds.filter(f => 
-//         (f.title || '').toLowerCase().includes(q) || 
-//         (f.postContent || '').toLowerCase().includes(q)
-//       )
-//     );
-//   };
-
-//   const handleReset = () => {
-//     setQuery('');
-//     setFilteredFeeds(feeds);
-//   };
-
-//   // 对话框内:处理图片选择
-//   const handleImageChange = (e) => {
-//     const files = Array.from(e.target.files);
-//     if (!files.length) return;
-    
-//     const previewUrls = files.map(file => URL.createObjectURL(file));
-    
-//     setSelectedImages(files);
-//     setPreviewUrls(previewUrls);
-//   };
-
-//   // 对话框内:提交新动态
-//   const handleSubmit = async () => {
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     if (!content.trim()) {
-//       alert('内容不能为空');
-//       return;
-//     }
-
-//     try {
-//       // 使用formData格式提交
-//       const formData = new FormData();
-//       formData.append('title', title.trim() || '');
-//       formData.append('content', content.trim());
-      
-//       // 添加图片文件
-//       selectedImages.forEach((file, index) => {
-//         formData.append('image_url', file);
-//       });
-
-//       // 调用创建动态API
-//       await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
-//         headers: {
-//           'Content-Type': 'multipart/form-data'
-//         }
-//       });
-
-//       // 重置表单
-//       setTitle('');
-//       setContent('');
-//       setSelectedImages([]);
-//       setPreviewUrls([]);
-//       setShowModal(false);
-//       fetchFeeds();
-//       alert('发布成功');
-//     } catch (err) {
-//       console.error('发布失败', err);
-//       alert('发布失败,请稍后重试');
-//     }
-//   };
-
-//   // 删除动态 - 注意:API文档中未提供删除接口,这里保留原代码
-//   const handleDelete = async (dynamicId) => {
-  
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     if (!window.confirm('确定要删除这条动态吗?')) return;
-//     try {
-//       // 注意:API文档中未提供删除接口,这里使用原代码中的路径
-//       await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
-//       fetchFeeds();
-//       alert('删除成功');
-//     } catch (err) {
-//       console.error('删除失败', err);
-//       alert('删除失败,请稍后重试');
-//     }
-//   };
-
-//   // 点赞动态
-//   const handleLike = async (dynamicId, islike) => {
-//     if (islike) {
-//       handleUnlike(dynamicId);
-//       return
-//     }
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     // 验证dynamicId是否有效
-//     if (!dynamicId) {
-//       console.error('无效的dynamicId:', dynamicId);
-//       alert('点赞失败:动态ID无效');
-//       return;
-//     }
-
-//     console.log('当前用户ID:', userId);
-//     console.log('即将点赞的动态ID:', dynamicId);
-    
-//     try {
-//       // 确保参数是整数类型
-//       const requestData = {
-//         userId: parseInt(userId),
-//         dynamicId: parseInt(dynamicId)
-//       };
-      
-//       // 验证参数是否为有效数字
-//       if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
-//         console.error('无效的参数:', requestData);
-//         alert('点赞失败:参数格式错误');
-//         return;
-//       }
-      
-//       console.log('点赞请求数据:', requestData);
-      
-//       const res = await axios.post(`/echo/dynamic/like`, requestData, {
-//         headers: {
-//           'Content-Type': 'application/json' // 明确指定JSON格式
-//         }
-//       });
-      
-//       console.log('点赞API响应:', res.data);
-      
-//       if (res.status === 200) {
-//         // 更新本地状态
-//         feeds.forEach(feed => {
-//           if (feed.postNo === dynamicId) {
-//             feed.postLikeNum = (feed.postLikeNum || 0) + 1;
-//             feed.liked = true;
-//           }
-//         });
-//         setFeeds([...feeds]); // 更新状态以触发重新渲染
-//       } else {
-//         alert(res.data.message || '点赞失败');
-//       }
-//     } catch (err) {
-//       console.error('点赞失败', err);
-      
-//       // 检查错误响应,获取更详细的错误信息
-//       if (err.response) {
-//         console.error('错误响应数据:', err.response.data);
-//         console.error('错误响应状态:', err.response.status);
-//         console.error('错误响应头:', err.response.headers);
-//       }
-      
-//       alert('点赞失败,请稍后重试');
-//     }
-//   };
-
-//   // 取消点赞
-//   const handleUnlike = async (dynamicId) => {
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     // 验证dynamicId是否有效
-//     if (!dynamicId) {
-//       console.error('无效的dynamicId:', dynamicId);
-//       alert('取消点赞失败:动态ID无效');
-//       return;
-//     }
-
-//     // 检查是否已经取消点赞,防止重复请求
-//     const currentFeed = feeds.find(feed => feed.postNo === dynamicId);
-//     if (currentFeed && !currentFeed.liked) {
-//       console.warn('尝试重复取消点赞,已忽略');
-//       return;
-//     }
-
-//     try {
-//       // 确保参数是整数类型
-//       const requestData = {
-//         userId: parseInt(userId),
-//         dynamicId: parseInt(dynamicId)
-//       };
-      
-//       // 验证参数是否为有效数字
-//       if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
-//         console.error('无效的参数:', requestData);
-//         alert('取消点赞失败:参数格式错误');
-//         return;
-//       }
-      
-//       console.log('取消点赞请求数据:', requestData);
-      
-//       const res = await axios.delete(`/echo/dynamic/unlike`, {
-//         headers: {
-//           'Content-Type': 'application/json' // 明确指定JSON格式
-//         },
-//         data: requestData // 将参数放在data属性中
-//       });
-      
-//       console.log('取消点赞API响应:', res.data);
-      
-//       if (res.status === 200) {
-//         // 更新本地状态
-//         feeds.forEach(feed => {
-//           if (feed.postNo === dynamicId) {
-//             feed.postLikeNum = Math.max(0, (feed.postLikeNum || 0) - 1);
-//             feed.liked = false;
-//           }
-//         });
-//         setFeeds([...feeds]); // 更新状态以触发重新渲染
-//       } else {
-//         alert(res.data.message || '取消点赞失败');
-//       }
-//     } catch (err) {
-//       console.error('取消点赞失败', err);
-      
-//       // 检查错误响应,获取更详细的错误信息
-//       if (err.response) {
-//         console.error('错误响应数据:', err.response.data);
-//         console.error('错误响应状态:', err.response.status);
-//         console.error('错误响应头:', err.response.headers);
-//       }
-      
-//       alert('取消点赞失败,请稍后重试');
-//     }
-//   };
-
-//   // 评论好友动态
-//   const handleComment = async (dynamicId, parentCommentId = null, replyToUsername = '') => {
-//     if (!isLoggedIn) {
-//       alert('请先登录');
-//       return;
-//     }
-
-//     const commentInputRef = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
-//     if (!commentInputRef || !commentInputRef.value.trim()) {
-//       alert('评论内容不能为空');
-//       return;
-//     }
-
-//     const commentContent = commentInputRef.value.trim();
-
-//     try {
-//       // 准备请求数据
-//       const requestData = {
-//         content: commentContent
-//       };
-      
-//       // 如果是回复,添加parent_comment_id
-//       if (parentCommentId) {
-//         requestData.parent_comment_id = parentCommentId;
-//       }
-      
-//       const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, requestData);
-
-//       if (res.status === 200 || res.status === 201) {
-//         // 成功获取评论数据
-//         const newComment = {
-//           user_id: userId,
-//           username: username,
-//           content: commentContent,
-//           time: new Date().toISOString(), // 使用当前时间作为评论时间
-//           // 如果是回复,添加parent_comment_id和reply_to_username
-//           ...(parentCommentId && { parent_comment_id: parentCommentId }),
-//           ...(replyToUsername && { reply_to_username: replyToUsername })
-//         };
-
-//         // 更新本地状态,添加新评论
-//         setFeeds(prevFeeds => {
-//           return prevFeeds.map(feed => {
-//             if (feed.postNo === dynamicId) {
-//               // 确保comments是数组,并且正确合并新评论
-//               const currentComments = Array.isArray(feed.comments) ? feed.comments : [];
-              
-//               if (parentCommentId) {
-//                 // 查找父评论并添加回复
-//                 return {
-//                   ...feed,
-//                   comments: currentComments.map(comment => {
-//                     if (comment.id === parentCommentId || comment.postNo === parentCommentId) {
-//                       // 如果父评论已有replies数组,添加到其中
-//                       if (Array.isArray(comment.replies)) {
-//                         return {
-//                           ...comment,
-//                           replies: [...comment.replies, newComment]
-//                         };
-//                       } else {
-//                         // 否则创建新的replies数组
-//                         return {
-//                           ...comment,
-//                           replies: [newComment]
-//                         };
-//                       }
-//                     }
-//                     return comment;
-//                   })
-//                 };
-//               } else {
-//                 // 普通评论,添加到评论列表
-//                 return {
-//                   ...feed,
-//                   comments: [...currentComments, newComment]
-//                 };
-//               }
-//             }
-//             return feed;
-//           });
-//         });
-
-//         // 清空输入框
-//         if (commentInputRef) {
-//           commentInputRef.value = '';
-//         }
-        
-//         // 隐藏回复框
-//         toggleReplyBox(dynamicId, parentCommentId);
-//       } else {
-//         alert(res.data.error || '评论失败');
-//       }
-//     } catch (err) {
-//       console.error('评论失败', err);
-//       alert('评论失败,请稍后重试');
-//     }
-//   };
-
-//   // 切换回复框显示状态
-//   const toggleReplyBox = (dynamicId, parentCommentId = null) => {
-//     const replyBoxId = `reply-box-${dynamicId}-${parentCommentId}`;
-//     const replyBox = document.getElementById(replyBoxId);
-    
-//     if (replyBox) {
-//       replyBox.style.display = replyBox.style.display === 'none' ? 'block' : 'none';
-      
-//       // 如果显示,聚焦到输入框
-//       if (replyBox.style.display === 'block') {
-//         const commentInput = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
-//         if (commentInput) commentInput.focus();
-//       }
-//     }
-//   };
-
-//   return (
-//     <div className="friend-moments-container">
-//       <Header />
-//       <div className="fm-header">
-//         <button className="create-btn" onClick={() => setShowModal(true)}>
-//           <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
-//           创建动态
-//         </button>
-//       </div>
-
-//       <div className="feed-list">
-//         {loading ? (
-//           <div className="loading-message">加载中...</div>
-//         ) : error ? (
-//           <div className="error-message">{error}</div>
-//         ) : !isLoggedIn ? (
-//           <div className="login-prompt">
-//             <p>请先登录查看好友动态</p>
-//           </div>
-//         ) : filteredFeeds.length === 0 ? (
-//           <div className="empty-message">暂无动态</div>
-//         ) : (
-//           filteredFeeds.map(feed => (
-//             <div className="feed-item" key={feed.postNo || `feed-${Math.random()}`}>
-//               {/* 显示发布者信息 */}
-//               <div className="feed-author">
-//                 <img
-//                   className="user-avatar"
-//                   src={feed.avatar_url || 'https://example.com/default-avatar.jpg'}
-//                   alt={feed.username || '用户头像'}
-//                 />
-//                 <div>
-//                   <h4>{feed.username || '未知用户'}</h4>
-//                   <span className="feed-date">{new Date(feed.postTime || Date.now()).toLocaleString()}</span>
-//                 </div>
-//               </div>
-
-//               {feed.title && <h4 className="feed-title">{feed.title}</h4>}
-//               <p className="feed-content">{feed.postContent || '无内容'}</p>
-
-//               {feed.imageUrl && (
-//                 <div className="feed-images">
-//                   {typeof feed.imageUrl === 'string' ? (
-//                     <img src={formatImageUrl(feed.imageUrl)} alt="动态图片" />
-//                   ) : (
-//                     feed.imageUrl.map((url, i) => (
-//                       <img key={i} src={formatImageUrl(url)} alt={`动态图${i}`} />
-//                     ))
-//                   )}
-//                 </div>
-//               )}
-
-//               <div className="feed-footer">
-//                 <div className="like-container">
-//                   <button className="icon-btn" onClick={() => handleLike(feed.postNo, feed.liked, feed.user_id)}>
-//                     <GoodTwo theme="outline" size="24" fill={feed.liked ? '#f00' : '#fff'} />
-//                     <span>{feed.postLikeNum || 0}</span>
-//                   </button>
-
-//                   <button
-//                     className="icon-btn"
-//                     onClick={() => toggleReplyBox(feed.postNo)}
-//                   >
-//                     <Comment theme="outline" size="24" fill="#333" />
-//                     <span>评论</span>
-//                   </button>
-//                 </div>
-                
-//                 {feed.user_id === userId && (
-//                   <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
-//                     删除
-//                   </button>
-//                 )}
-//               </div>
-
-//               {/* 动态的评论输入框 */}
-//               <div id={`reply-box-${feed.postNo}-null`} className="comment-box" style={{display: 'none'}}>
-//                 <textarea
-//                   id={`comment-input-${feed.postNo}-null`}
-//                   className="comment-input"
-//                   placeholder="请输入评论内容..."
-//                 />
-//                 <button
-//                   className="submit-comment-btn"
-//                   onClick={() => handleComment(feed.postNo)}
-//                 >
-//                   发布评论
-//                 </button>
-//               </div>
-
-//               {/* 评论列表 */}
-//               {Array.isArray(feed.comments) && feed.comments.length > 0 && (
-//                 <div className="comments-container">
-//                   <h5>评论 ({feed.comments.length})</h5>
-//                   <div className="comments-list">
-//                     {feed.comments.map((comment, index) => (
-//                       <div className="comment-item" key={index}>
-//                         <div className="comment-header">
-//                           <span className="comment-user">{comment.username || '用户'}</span>
-//                           <span className="comment-time">
-//                             {new Date(comment.time || Date.now()).toLocaleString()}
-//                           </span>
-//                         </div>
-//                         <p className="comment-content">
-//                           {/* 显示回复格式 */}
-//                           {comment.reply_to_username ? 
-//                             <span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> : 
-//                             <span>{comment.username}:</span>
-//                           }
-//                           {comment.content}
-//                         </p>
-//                         <button 
-//                           className="reply-btn" 
-//                           onClick={() => toggleReplyBox(feed.postNo, comment.id || index)}
-//                         >
-//                           回复
-//                         </button>
-                        
-//                         {/* 该评论的回复框 */}
-//                         <div id={`reply-box-${feed.postNo}-${comment.id || index}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
-//                           <textarea
-//                             id={`comment-input-${feed.postNo}-${comment.id || index}`}
-//                             className="comment-input"
-//                             placeholder={`回复 ${comment.username}...`}
-//                           />
-//                           <button
-//                             className="submit-comment-btn"
-//                             onClick={() => handleComment(feed.postNo, comment.id || index, comment.username)}
-//                           >
-//                             发布回复
-//                           </button>
-//                         </div>
-                        
-//                         {/* 嵌套回复 */}
-//                         {Array.isArray(comment.replies) && comment.replies.length > 0 && (
-//                           <div className="nested-replies">
-//                             {comment.replies.map((reply, replyIndex) => (
-//                               <div className="reply-item" key={replyIndex}>
-//                                 <p className="reply-content">
-//                                   {reply.reply_to_username ? 
-//                                     <span className="reply-prefix">{reply.username} 回复 {reply.reply_to_username}:</span> : 
-//                                     <span>{reply.username}:</span>
-//                                   }
-//                                   {reply.content}
-//                                 </p>
-//                                 <button 
-//                                   className="reply-btn" 
-//                                   onClick={() => toggleReplyBox(feed.postNo, reply.id || `${index}-${replyIndex}`, reply.username)}
-//                                 >
-//                                   回复
-//                                 </button>
-                                
-//                                 {/* 该回复的回复框 */}
-//                                 <div id={`reply-box-${feed.postNo}-${reply.id || `${index}-${replyIndex}`}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
-//                                   <textarea
-//                                     id={`comment-input-${feed.postNo}-${reply.id || `${index}-${replyIndex}`}`}
-//                                     className="comment-input"
-//                                     placeholder={`回复 ${reply.username}...`}
-//                                   />
-//                                   <button
-//                                     className="submit-comment-btn"
-//                                     onClick={() => handleComment(feed.postNo, reply.id || `${index}-${replyIndex}`, reply.username)}
-//                                   >
-//                                     发布回复
-//                                   </button>
-//                                 </div>
-//                               </div>
-//                             ))}
-//                           </div>
-//                         )}
-//                       </div>
-//                     ))}
-//                   </div>
-//                 </div>
-//               )}
-//             </div>
-//           ))
-//         )}
-//       </div>
-
-//       {/* Modal 对话框 */}
-//       {showModal && (
-//         <div className="modal-overlay" onClick={() => setShowModal(false)}>
-//           <div className="modal-dialog" onClick={e => e.stopPropagation()}>
-//             <h3>发布新动态</h3>
-//             <input
-//               type="text"
-//               placeholder="标题"
-//               value={title}
-//               onChange={e => setTitle(e.target.value)}
-//             />
-//             <textarea
-//               placeholder="写下你的内容..."
-//               value={content}
-//               onChange={e => setContent(e.target.value)}
-//             />
-//             <label className="file-label">
-//               选择图片
-//               <input
-//                 type="file"
-//                 accept="image/*"
-//                 multiple
-//                 onChange={handleImageChange}
-//                 style={{ display: 'none' }}
-//               />
-//             </label>
-//             <div className="cf-preview">
-//               {previewUrls.map((url, i) => (
-//                 <img key={i} src={url} alt={`预览${i}`} />
-//               ))}
-//             </div>
-//             <div className="modal-actions">
-//               <button className="btn cancel" onClick={() => setShowModal(false)}>
-//                 取消
-//               </button>
-//               <button className="btn submit" onClick={handleSubmit}>
-//                 发布
-//               </button>
-//             </div>
-//           </div>
-//         </div>
-//       )}
-//     </div>
-//   );
-// };
-
-// export default FriendMoments; 
-
-
 // FriendMoments.js
 import React, { useContext, useState, useEffect } from 'react'; 
 import axios from 'axios';
@@ -1790,18 +452,18 @@
               {/* 显示发布者信息 */}
               <div className="feed-author">
                 <img
-                  className="user-avatar"
+                  style={{ width: '70px', height: '70px', borderRadius: '50%' }}
                   src={feed.avatar_url || 'https://example.com/default-avatar.jpg'}
                   alt={feed.username || '用户头像'}
                 />
                 <div>
-                  <h4>{feed.username || '未知用户'}</h4>
+                  <div style={{ fontWeight: 'bold', fontSize: '20px', marginBottom: '5px' }}>{feed.username || '未知用户'}</div>
                   <span className="feed-date">{new Date(feed.postTime || Date.now()).toLocaleString()}</span>
                 </div>
               </div>
 
-              {feed.title && <h4 className="feed-title">{feed.title}</h4>}
-              <p className="feed-content">{feed.postContent || '无内容'}</p>
+              {feed.title && <h4 style={{ fontWeight: 'bold', fontSize: '18px', margin: '15px 0' }}>{feed.title}</h4>}
+              <div style={{ margin: '20px 0' }}>{feed.postContent || '无内容'}</div>
 
               {feed.imageUrl && (
                 <div className="feed-images">
@@ -1818,7 +480,7 @@
               <div className="feed-footer">
                 <div className="like-container">
                   <button className="icon-btn" onClick={() => handleLike(feed.postNo, feed.liked, feed.user_id)}>
-                    <GoodTwo theme="outline" size="24" fill={feed.liked ? '#f00' : '#fff'} />
+                    <GoodTwo theme="outline" size="24" fill={feed.liked ? '#ffa600dd' : '#000000'} />
                     <span>{feed.postLikeNum || 0}</span>
                   </button>
 
@@ -1828,8 +490,8 @@
                       toggleReplyBox(feed.postNo);
                     }}
                   >
-                    <Comment theme="outline" size="24" fill="#333" />
-                    <span>评论</span>
+                    <Comment theme="outline" size="24" fill="#333" />评论
+                    {/* <span style={{ fontSize: '14px', color: '#333' }}>评论</span> */}
                   </button>
                 </div>
                 
@@ -1861,7 +523,7 @@
               {/* 评论列表 */}
               {Array.isArray(feed.comments) && feed.comments.length > 0 && (
                 <div className="comments-container">
-                  <h5>评论 ({feed.comments.length})</h5>
+                  <h5 style={{ fontWeight: 'bold', fontSize: '18px', marginTop: '10px', marginBottom: '20px' }}>评论 ({feed.comments.length})</h5>
                   <div className="comments-list">
                     {feed.comments.map((comment, index) => (
                       <div className="comment-item" key={index}>
@@ -1873,10 +535,10 @@
                         </div>
                         <p className="comment-content">
                           {/* 显示回复格式 */}
-                          {comment.reply_to_username ? 
+                          {/* {comment.reply_to_username ? 
                             <span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> : 
                             <span>{comment.username}:</span>
-                          }
+                          } */}
                           {comment.content}
                         </p>
                         <button 
diff --git a/src/pages/InterestGroup/GroupItem.jsx b/src/pages/InterestGroup/GroupItem.jsx
index 8e6068b..1718111 100644
--- a/src/pages/InterestGroup/GroupItem.jsx
+++ b/src/pages/InterestGroup/GroupItem.jsx
@@ -3,6 +3,7 @@
 import { useUser } from '../../context/UserContext';
 import { useLocation } from 'wouter';
 import './GroupDetail.css';
+import AuthButton from '../../components/AuthButton';
 
 const GroupItem = ({ group }) => {
   const [, setLocation] = useLocation();
@@ -97,7 +98,8 @@
           <p style={{ color: '#BA929A' }}>{group.memberCount || 0}人加入了小组</p>
 
           {userId && (
-            <button
+            <AuthButton
+              roles={["chocolate", "ice-cream"]}
               style={{ color: '#2167c9', background: 'none', border: 'none', padding: 0, cursor: 'pointer', fontSize: '16px' }}
               onClick={(e) => {
                 e.stopPropagation();
@@ -106,7 +108,7 @@
               disabled={loading}
             >
               {loading ? '处理中...' : isMember ? '退出小组' : '+加入小组'}
-            </button>
+            </AuthButton>
           )}
           {!userId && <button disabled>请登录</button>}
 
diff --git a/src/pages/InterestGroup/GroupPosts.jsx b/src/pages/InterestGroup/GroupPosts.jsx
index 7bd16ba..d7893c7 100644
--- a/src/pages/InterestGroup/GroupPosts.jsx
+++ b/src/pages/InterestGroup/GroupPosts.jsx
@@ -2,6 +2,7 @@
 import CommentForm from './CommentForm';
 import { GoodTwo, Comment } from '@icon-park/react';
 import './GroupDetail.css';
+import AuthButton from '../../components/AuthButton';
 
 const GroupPosts = ({ 
   posts, 
@@ -21,12 +22,13 @@
       
       <div className="post-list-header">
         {userId && isMember && (
-          <button 
+          <AuthButton
+          roles={[ "chocolate", "ice-cream"]}
             className="create-post-btn" 
             onClick={onShowCreatePost}
           >
             + 发布帖子
-          </button>
+          </AuthButton>
         )}
         {(!userId || !isMember) && <p className="login-hint">{loginHint}</p>}
       </div>
diff --git a/src/pages/PromotionsPage/PromotionsPage.css b/src/pages/PromotionsPage/PromotionsPage.css
deleted file mode 100644
index bc5bf8c..0000000
--- a/src/pages/PromotionsPage/PromotionsPage.css
+++ /dev/null
@@ -1,206 +0,0 @@
-/* .promotions-page {
-    padding: 20px;
-    font-family: Arial, sans-serif;
-}
-
-.promotions-container {
-    max-width: 1200px;
-    margin: 0 auto;
-    background-color: #fff;
-    border-radius: 8px;
-    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-    padding: 20px;
-}
-
-h1, h2, h3 {
-    color: #333;
-}
-
-.admin-actions {
-    margin-bottom: 20px;
-}
-
-.create-button, .submit-button, .delete-button {
-    background-color: #4CAF50;
-    color: white;
-    border: none;
-    padding: 10px 15px;
-    border-radius: 4px;
-    cursor: pointer;
-    font-size: 14px;
-    transition: background-color 0.3s;
-}
-
-.create-button:hover, .submit-button:hover {
-    background-color: #45a049;
-}
-
-.delete-button {
-    background-color: #f44336;
-    margin-top: 10px;
-}
-
-.delete-button:hover {
-    background-color: #d32f2f;
-}
-
-.create-promotion-form {
-    background-color: #f9f9f9;
-    padding: 20px;
-    border-radius: 8px;
-    margin-bottom: 20px;
-}
-
-.form-group {
-    margin-bottom: 15px;
-}
-
-.form-row {
-    display: flex;
-    gap: 20px;
-}
-
-.form-row .form-group {
-    flex: 1;
-}
-
-label {
-    display: block;
-    margin-bottom: 5px;
-    font-weight: bold;
-}
-
-input, select {
-    width: 100%;
-    padding: 8px;
-    border: 1px solid #ddd;
-    border-radius: 4px;
-    box-sizing: border-box;
-}
-
-.error-message {
-    color: #f44336;
-    margin-bottom: 15px;
-    padding: 10px;
-    background-color: #ffebee;
-    border-radius: 4px;
-}
-
-.promotions-grid {
-    display: grid;
-    grid-template-columns: 1fr 1fr;
-    gap: 20px;
-}
-
-.promotions-list {
-    border-right: 1px solid #eee;
-    padding-right: 20px;
-}
-
-.promotion-items {
-    max-height: 600px;
-    overflow-y: auto;
-}
-
-.promotion-item {
-    background-color: #f9f9f9;
-    padding: 15px;
-    border-radius: 8px;
-    margin-bottom: 15px;
-    cursor: pointer;
-    transition: background-color 0.3s;
-}
-
-.promotion-item:hover {
-    background-color: #f0f0f0;
-}
-
-.promotion-item.active {
-    background-color: #e3f2fd;
-    border-left: 4px solid #2196F3;
-}
-
-.promotion-header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 10px;
-}
-
-.promotion-type {
-    background-color: #2196F3;
-    color: white;
-    padding: 3px 8px;
-    border-radius: 12px;
-    font-size: 12px;
-}
-
-.promotion-dates {
-    color: #666;
-    font-size: 14px;
-    margin-bottom: 10px;
-}
-
-.promotion-coeffs {
-    display: flex;
-    gap: 15px;
-    font-weight: bold;
-}
-
-.promotion-coeffs span {
-    background-color: #e3f2fd;
-    padding: 3px 8px;
-    border-radius: 4px;
-}
-
-.promotion-details {
-    padding: 0 20px;
-}
-
-.detail-item {
-    margin-bottom: 15px;
-}
-
-.detail-item label {
-    font-weight: bold;
-    color: #555;
-}
-
-.detail-item span {
-    display: block;
-    margin-top: 5px;
-    padding: 8px;
-    background-color: #f5f5f5;
-    border-radius: 4px;
-}
-
-.no-promotions, .no-selection, .loading {
-    text-align: center;
-    padding: 40px;
-    color: #888;
-}
-
-.pagination {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    gap: 15px;
-    margin-top: 20px;
-}
-
-.pagination button {
-    padding: 5px 10px;
-    background-color: #f0f0f0;
-    border: 1px solid #ddd;
-    border-radius: 4px;
-    cursor: pointer;
-}
-
-.pagination button:disabled {
-    opacity: 0.5;
-    cursor: not-allowed;
-}
-
-.pagination span {
-    font-size: 14px;
-} */
\ No newline at end of file
diff --git a/src/pages/PromotionsPage/PromotionsPage.jsx b/src/pages/PromotionsPage/PromotionsPage.jsx
deleted file mode 100644
index ff01ef3..0000000
--- a/src/pages/PromotionsPage/PromotionsPage.jsx
+++ /dev/null
@@ -1,435 +0,0 @@
-// import React, { useState, useEffect } from 'react';
-// import './PromotionsPage.css';
-
-
-// function PromotionsPage() {
-//   const [promotions, setPromotions] = useState([]);
-//   const [currentPromotion, setCurrentPromotion] = useState(null);
-//   const [isAdmin, setIsAdmin] = useState(false);
-//   const [isLoading, setIsLoading] = useState(false);
-//   const [error, setError] = useState(null);
-//   const [formData, setFormData] = useState({
-//     name: '',
-//     uploadCoeff: 1,
-//     downloadCoeff: 1,
-//     timeRange: 0,
-//     criteria: 1,
-//     pStartTime: '',
-//     pEndTime: ''
-//   });
-//   const [isCreating, setIsCreating] = useState(false);
-//   const [currentPage, setCurrentPage] = useState(1);
-//   const [perPage] = useState(10);
-//   const [totalPromotions, setTotalPromotions] = useState(0);
-
-//   const getAuthHeaders = () => {
-//     const token = localStorage.getItem('token');
-//     return {
-//       'Authorization': token ? `Bearer ${token}` : '',
-//       'Content-Type': 'application/json'
-//     };
-//   };
-
-//   const fetchPromotions = async (page = 1) => {
-//     setIsLoading(true);
-//     try {
-//       const response = await fetch(`/promotions/list?page=${page}&per_page=${perPage}`, {
-//         headers: getAuthHeaders()
-//       });
-
-//       if (!response.ok) {
-//         throw new Error('获取促销活动失败');
-//       }
-
-//       const data = await response.json();
-//       if (data.code === 0 && data.result) {
-//         setPromotions(data.rows || []);
-//         setTotalPromotions(data.total || 0);
-//       } else {
-//         throw new Error(data.msg || '获取促销活动失败');
-//       }
-//     } catch (err) {
-//       console.error('获取促销活动错误:', err);
-//       setError(err.message);
-//     } finally {
-//       setIsLoading(false);
-//     }
-//   };
-
-//   const fetchPromotionDetails = async (promoId) => {
-//     setIsLoading(true);
-//     try {
-//       const response = await fetch(`/promotions/${promoId}`, {
-//         headers: getAuthHeaders()
-//       });
-
-//       if (!response.ok) {
-//         throw new Error('获取促销详情失败');
-//       }
-
-//       const data = await response.json();
-//       if (data.code === 0 && data.result) {
-//         setCurrentPromotion(data.rows);
-//       } else {
-//         throw new Error(data.msg || '获取促销详情失败');
-//       }
-//     } catch (err) {
-//       console.error('获取促销详情错误:', err);
-//       setError(err.message);
-//     } finally {
-//       setIsLoading(false);
-//     }
-//   };
-
-//   const createPromotion = async () => {
-//     if (!formData.name || !formData.pStartTime || !formData.pEndTime) {
-//       alert('请填写完整活动信息');
-//       return;
-//     }
-
-//     if (new Date(formData.pStartTime) >= new Date(formData.pEndTime)) {
-//       alert('活动时间设置不正确,请重新设定');
-//       return;
-//     }
-
-//     setIsLoading(true);
-//     try {
-//       const response = await fetch('/promotions/add', {
-//         method: 'POST',
-//         headers: getAuthHeaders(),
-//         body: JSON.stringify(formData)
-//       });
-
-//       if (!response.ok) {
-//         throw new Error('创建促销活动失败');
-//       }
-
-//       const data = await response.json();
-//       if (data.code === 0 && data.result) {
-//         alert(`活动创建成功!活动ID: ${data.msg}`);
-//         setIsCreating(false);
-//         setFormData({
-//           name: '',
-//           uploadCoeff: 1,
-//           downloadCoeff: 1,
-//           timeRange: 0,
-//           criteria: 1,
-//           pStartTime: '',
-//           pEndTime: ''
-//         });
-//         fetchPromotions();
-//       } else {
-//         throw new Error(data.msg || '创建促销活动失败');
-//       }
-//     } catch (err) {
-//       console.error('创建促销活动错误:', err);
-//       alert(err.message);
-//     } finally {
-//       setIsLoading(false);
-//     }
-//   };
-
-//   const deletePromotion = async (promoId) => {
-//     if (!window.confirm('确定要删除这个促销活动吗?')) {
-//       return;
-//     }
-
-//     setIsLoading(true);
-//     try {
-//       const response = await fetch(`/promotions/delete/${promoId}`, {
-//         method: 'DELETE',
-//         headers: getAuthHeaders()
-//       });
-
-//       if (!response.ok) {
-//         throw new Error('删除促销活动失败');
-//       }
-
-//       const data = await response.json();
-//       if (data.code === 0 && data.result) {
-//         alert('促销活动删除成功');
-//         fetchPromotions();
-//         if (currentPromotion && currentPromotion.promoId === promoId) {
-//           setCurrentPromotion(null);
-//         }
-//       } else {
-//         throw new Error(data.msg || '删除促销活动失败');
-//       }
-//     } catch (err) {
-//       console.error('删除促销活动错误:', err);
-//       alert(err.message);
-//     } finally {
-//       setIsLoading(false);
-//     }
-//   };
-
-//   const checkAdminStatus = () => {
-//     const role = localStorage.getItem('role');
-//     setIsAdmin(role === 'admin');
-//   };
-
-//   useEffect(() => {
-//     checkAdminStatus();
-//     fetchPromotions();
-//   }, []);
-
-//   const handleInputChange = (e) => {
-//     const { name, value } = e.target;
-//     setFormData(prev => ({
-//       ...prev,
-//       [name]: name === 'uploadCoeff' || name === 'downloadCoeff' || name === 'timeRange' || name === 'criteria'
-//           ? parseFloat(value)
-//           : value
-//     }));
-//   };
-
-//   const handlePageChange = (newPage) => {
-//     setCurrentPage(newPage);
-//     fetchPromotions(newPage);
-//   };
-
-//   const getPromotionType = (promo) => {
-//     if (promo.downloadCoeff === 0 && promo.uploadCoeff > 1) {
-//       return '免费';
-//     } else if (promo.downloadCoeff < 1 && promo.uploadCoeff > 1) {
-//       return '折扣+上传奖励';
-//     } else if (promo.downloadCoeff < 1) {
-//       return '折扣';
-//     } else if (promo.uploadCoeff > 1) {
-//       return '上传奖励';
-//     }
-//     return '普通';
-//   };
-
-//   return (
-//       <div className="promotions-page">
-//         <div className="promotions-container">
-//           <h1>促销活动</h1>
-
-//           {isAdmin && (
-//               <div className="admin-actions">
-//                 <button
-//                     className="create-button"
-//                     onClick={() => setIsCreating(!isCreating)}
-//                 >
-//                   {isCreating ? '取消创建' : '创建新活动'}
-//                 </button>
-//               </div>
-//           )}
-
-//           {isCreating && isAdmin && (
-//               <div className="create-promotion-form">
-//                 <h2>创建新促销活动</h2>
-//                 <div className="form-group">
-//                   <label>活动名称</label>
-//                   <input
-//                       type="text"
-//                       name="name"
-//                       value={formData.name}
-//                       onChange={handleInputChange}
-//                       placeholder="例如: 春节特惠"
-//                   />
-//                 </div>
-
-//                 <div className="form-row">
-//                   <div className="form-group">
-//                     <label>上传量系数</label>
-//                     <input
-//                         type="number"
-//                         name="uploadCoeff"
-//                         min="0"
-//                         step="0.1"
-//                         value={formData.uploadCoeff}
-//                         onChange={handleInputChange}
-//                     />
-//                   </div>
-
-//                   <div className="form-group">
-//                     <label>下载量系数</label>
-//                     <input
-//                         type="number"
-//                         name="downloadCoeff"
-//                         min="0"
-//                         step="0.1"
-//                         value={formData.downloadCoeff}
-//                         onChange={handleInputChange}
-//                     />
-//                   </div>
-//                 </div>
-
-//                 <div className="form-row">
-//                   <div className="form-group">
-//                     <label>资源时间范围</label>
-//                     <select
-//                         name="timeRange"
-//                         value={formData.timeRange}
-//                         onChange={handleInputChange}
-//                     >
-//                       <option value="0">全站资源</option>
-//                       <option value="1">当天上传</option>
-//                       <option value="2">最近两天</option>
-//                       <option value="7">最近一周</option>
-//                       <option value="30">最近一个月</option>
-//                     </select>
-//                   </div>
-
-//                   <div className="form-group">
-//                     <label>最低用户等级</label>
-//                     <input
-//                         type="number"
-//                         name="criteria"
-//                         min="1"
-//                         value={formData.criteria}
-//                         onChange={handleInputChange}
-//                     />
-//                   </div>
-//                 </div>
-
-//                 <div className="form-row">
-//                   <div className="form-group">
-//                     <label>开始时间</label>
-//                     <input
-//                         type="datetime-local"
-//                         name="pStartTime"
-//                         value={formData.pStartTime}
-//                         onChange={handleInputChange}
-//                     />
-//                   </div>
-
-//                   <div className="form-group">
-//                     <label>结束时间</label>
-//                     <input
-//                         type="datetime-local"
-//                         name="pEndTime"
-//                         value={formData.pEndTime}
-//                         onChange={handleInputChange}
-//                     />
-//                   </div>
-//                 </div>
-
-//                 <button
-//                     className="submit-button"
-//                     onClick={createPromotion}
-//                     disabled={isLoading}
-//                 >
-//                   {isLoading ? '创建中...' : '提交创建'}
-//                 </button>
-//               </div>
-//           )}
-
-//           {error && <div className="error-message">{error}</div>}
-
-//           <div className="promotions-grid">
-//             {/* 促销活动列表 */}
-//             <div className="promotions-list">
-//               <h2>当前促销活动</h2>
-//               {isLoading && promotions.length === 0 ? (
-//                   <div className="loading">加载中...</div>
-//               ) : promotions.length === 0 ? (
-//                   <div className="no-promotions">暂无促销活动</div>
-//               ) : (
-//                   <div className="promotion-items">
-//                     {promotions.map(promo => (
-//                         <div
-//                             key={promo.promoId}
-//                             className={`promotion-item ${currentPromotion && currentPromotion.promoId === promo.promoId ? 'active' : ''}`}
-//                             onClick={() => fetchPromotionDetails(promo.promoId)}
-//                         >
-//                           <div className="promotion-header">
-//                             <h3>{promo.name}</h3>
-//                             <span className="promotion-type">{getPromotionType(promo)}</span>
-//                           </div>
-//                           <div className="promotion-dates">
-//                             {new Date(promo.pStartTime).toLocaleString()} - {new Date(promo.pEndTime).toLocaleString()}
-//                           </div>
-//                           <div className="promotion-coeffs">
-//                             <span>上传: {promo.uploadCoeff}x</span>
-//                             <span>下载: {promo.downloadCoeff}x</span>
-//                           </div>
-//                           {isAdmin && (
-//                               <button
-//                                   className="delete-button"
-//                                   onClick={(e) => {
-//                                     e.stopPropagation();
-//                                     deletePromotion(promo.promoId);
-//                                   }}
-//                                   disabled={isLoading}
-//                               >
-//                                 删除
-//                               </button>
-//                           )}
-//                         </div>
-//                     ))}
-//                   </div>
-//               )}
-
-//               {totalPromotions > perPage && (
-//                   <div className="pagination">
-//                     <button
-//                         disabled={currentPage === 1}
-//                         onClick={() => handlePageChange(currentPage - 1)}
-//                     >
-//                       上一页
-//                     </button>
-//                     <span>第 {currentPage} 页</span>
-//                     <button
-//                         disabled={currentPage * perPage >= totalPromotions}
-//                         onClick={() => handlePageChange(currentPage + 1)}
-//                     >
-//                       下一页
-//                     </button>
-//                   </div>
-//               )}
-//             </div>
-
-//             {/* 促销活动详情 */}
-//             <div className="promotion-details">
-//               {currentPromotion ? (
-//                   <>
-//                     <h2>{currentPromotion.name}</h2>
-//                     <div className="detail-item">
-//                       <label>活动ID:</label>
-//                       <span>{currentPromotion.promoId}</span>
-//                     </div>
-//                     <div className="detail-item">
-//                       <label>活动时间:</label>
-//                       <span>
-//                     {new Date(currentPromotion.pStartTime).toLocaleString()} - {new Date(currentPromotion.pEndTime).toLocaleString()}
-//                   </span>
-//                     </div>
-//                     <div className="detail-item">
-//                       <label>促销类型:</label>
-//                       <span>{getPromotionType(currentPromotion)}</span>
-//                     </div>
-//                     <div className="detail-item">
-//                       <label>上传量系数:</label>
-//                       <span>{currentPromotion.uploadCoeff}x</span>
-//                     </div>
-//                     <div className="detail-item">
-//                       <label>下载量系数:</label>
-//                       <span>{currentPromotion.downloadCoeff}x</span>
-//                     </div>
-//                     <div className="detail-item">
-//                       <label>适用资源:</label>
-//                       <span>
-//                     {currentPromotion.timeRange === 0
-//                         ? '全站资源'
-//                         : `最近${currentPromotion.timeRange}天内上传的资源`}
-//                   </span>
-//                     </div>
-//                     <div className="detail-item">
-//                       <label>参与条件:</label>
-//                       <span>用户等级 ≥ {currentPromotion.criteria}</span>
-//                     </div>
-//                   </>
-//               ) : (
-//                   <div className="no-selection">请从左侧选择一个促销活动查看详情</div>
-//               )}
-//             </div>
-//           </div>
-//         </div>
-//       </div>
-//   );
-// }
-
-// export default PromotionsPage;
\ No newline at end of file
diff --git a/src/pages/PublishSeed/PublishSeed.jsx b/src/pages/PublishSeed/PublishSeed.jsx
index 27717ca..6528b0d 100644
--- a/src/pages/PublishSeed/PublishSeed.jsx
+++ b/src/pages/PublishSeed/PublishSeed.jsx
@@ -5,6 +5,7 @@
 import './PublishSeed.css';
 import { useUser } from '../../context/UserContext';
 import { uploadFile } from '../../api/file';
+import AuthButton from '../../components/AuthButton';
 
 const PublishSeed = () => {
   const [title, setTitle] = useState('');
@@ -99,7 +100,7 @@
       });
       console.log('[DEBUG] 请求成功,响应:', response.data);
 
-      if (response.data.status === 'success') {
+      if (response.data.code === 0) {
         setMessage('种子上传成功');
       } else {
         setMessage(response.data.message || '上传失败,请稍后再试');
@@ -238,13 +239,14 @@
           </div>
 
           <div className="ps-upload-button">
-            <button
+            <AuthButton
+              roles={["cookie", "chocolate", "ice-cream"]}
               type="submit"
               disabled={isLoading}
               onClick={() => console.log('[DEBUG] 上传按钮 onClick 触发')}
             >
               {isLoading ? '正在上传...' : '上传种子'}
-            </button>
+            </AuthButton>
           </div>
         </form>
       </div>
diff --git a/src/pages/SeedList/Recommend/PlaylistDetailPage.css b/src/pages/SeedList/Recommend/PlaylistDetailPage.css
index 78e7068..f9c09e6 100644
--- a/src/pages/SeedList/Recommend/PlaylistDetailPage.css
+++ b/src/pages/SeedList/Recommend/PlaylistDetailPage.css
@@ -12,7 +12,7 @@
   font-weight: 700;
 }
 
-.cover-image {
+.cover-img {
   width: 100%;
   max-height: 400px;
   object-fit: cover;
diff --git a/src/pages/SeedList/Recommend/PlaylistDetailPage.jsx b/src/pages/SeedList/Recommend/PlaylistDetailPage.jsx
index 07558d6..54380e1 100644
--- a/src/pages/SeedList/Recommend/PlaylistDetailPage.jsx
+++ b/src/pages/SeedList/Recommend/PlaylistDetailPage.jsx
@@ -72,7 +72,7 @@
       src={detail.coverUrl || '/default-cover.jpg'}
       alt={detail.title}
       onError={e => { e.target.src = '/default-cover.jpg'; }}
-      className="cover-image"
+      className="cover-img"
     />
     <p>{detail.description}</p>
 
diff --git a/src/pages/SeedList/Recommend/Recommend.jsx b/src/pages/SeedList/Recommend/Recommend.jsx
index f58c73d..2229bb1 100644
--- a/src/pages/SeedList/Recommend/Recommend.jsx
+++ b/src/pages/SeedList/Recommend/Recommend.jsx
@@ -7,6 +7,7 @@
 import CreatePlaylistModal from './CreatePlaylistModal';
 import { confirmAlert } from 'react-confirm-alert';
 import 'react-confirm-alert/src/react-confirm-alert.css';
+import AuthButton from '../../../components/AuthButton';
 
 const Recommend = () => {
   const { user } = useUser();
@@ -160,15 +161,18 @@
             />
             <div className="paid-title">{list.title}</div>
 
-            {user && user.role === 'admin' ? (
-              <div className="admin-actions">
-                <button onClick={() => handleDelete(list.id)}>删除</button>
-              </div>
-            ) : list.isPaid ? (
-              <button onClick={() => navigate(`/playlist/${list.id}`)}>详情</button>
-            ) : (
-              <button onClick={() => handlePurchase(list.id)}>购买</button>
-            )}
+          {user && user.role === 'admin' ? (
+            <div className="admin-actions">
+              <button onClick={() => handleDelete(list.id)}>删除</button>
+            </div>
+          ) : list.isPaid ? (
+            <button onClick={() => navigate(`/playlist/${list.id}`)}>详情</button>
+          ) : (
+            <AuthButton roles={['chocolate', 'ice-cream']} onClick={() => handlePurchase(list.id)}>
+              购买
+            </AuthButton>
+          )}
+
           </div>
         ))}
       </div>
diff --git a/src/pages/SeedList/SeedDetail/SeedDetail.jsx b/src/pages/SeedList/SeedDetail/SeedDetail.jsx
index 4ab9274..705368a 100644
--- a/src/pages/SeedList/SeedDetail/SeedDetail.jsx
+++ b/src/pages/SeedList/SeedDetail/SeedDetail.jsx
@@ -5,6 +5,7 @@
 import './SeedDetail.css';
 import { useUser } from '../../../context/UserContext';
 import SeedRating from './SeedRating';
+import AuthButton from '../../../components/AuthButton';
 
 const SeedDetail = () => {
   const params = useParams();
@@ -213,12 +214,16 @@
         </div>
 
         <div className="action-buttons">
-          <button className="btn" onClick={() => handleDownload(seed.id)}>下载</button>
-          <button className="btn-outline" onClick={handleCollect}>收藏</button>
-          {/* <button className="btn" onClick={handleCollect}>收藏</button> */}
+          <AuthButton roles={["cookie", "chocolate", "ice-cream"]} onClick={() => handleDownload(seed.id)}>
+            下载
+          </AuthButton>
+          <AuthButton roles={["cookie", "chocolate", "ice-cream"]} onClick={handleCollect}>
+            收藏
+          </AuthButton>
           <SeedRating seedId={seed.id} />
         </div>
 
+
         <hr className="divider" />
         <h3>评论区</h3>
         <div className="comments-section">
diff --git a/src/pages/SeedList/SeedDetail/SeedRating.css b/src/pages/SeedList/SeedDetail/SeedRating.css
index e40c055..f62131c 100644
--- a/src/pages/SeedList/SeedDetail/SeedRating.css
+++ b/src/pages/SeedList/SeedDetail/SeedRating.css
@@ -20,4 +20,8 @@
   margin-left: 10px;
   font-size: 14px;
   color: rgba(222, 91, 111, 0.982);
+} 
+.star.hover {
+  color: rgba(240, 184, 62, 0.916); /* 亮黄色 */
 }
+
diff --git a/src/pages/SeedList/SeedDetail/SeedRating.jsx b/src/pages/SeedList/SeedDetail/SeedRating.jsx
index 1841443..8e2d3f0 100644
--- a/src/pages/SeedList/SeedDetail/SeedRating.jsx
+++ b/src/pages/SeedList/SeedDetail/SeedRating.jsx
@@ -63,6 +63,7 @@
 import axios from 'axios';
 import './SeedRating.css';
 import { useUser } from '../../../context/UserContext';
+import AuthButton from '../../../components/AuthButton';
 
 const SeedRating = ({ seedId }) => {
   const { user } = useUser();
@@ -105,17 +106,28 @@
 
   return (
     <div className="seed-rating">
-      <span>评分:</span>
+      <span style={{color: '#333'}}>评分:</span>
       {[1, 2, 3, 4, 5].map((star) => (
-        <span
-          key={star}
-          className={`star ${star <= (hoverScore || score) ? 'active' : ''}`}
-          onMouseEnter={() => !submitted && setHoverScore(star)}
-          onMouseLeave={() => !submitted && setHoverScore(0)}
-          onClick={() => handleRating(star)}
-        >
-          ★
-        </span>
+      <AuthButton
+        key={star}
+        roles={["cookie", "chocolate", "ice-cream"]}
+        style={{
+          backgroundColor: 'inherit',
+          margin: 0,
+          // color: '#ccc',
+          padding: 0,
+          outline: 'none',
+          border: 'none',
+          cursor: 'pointer'
+        }}
+        className={`star ${(star <= (hoverScore || score) ? 'active' : '')} ${hoverScore >= star ? 'hover' : ''}`}
+        onMouseEnter={() => !submitted && setHoverScore(star)}
+        onMouseLeave={() => !submitted && setHoverScore(0)}
+        onClick={() => handleRating(star)}
+      >
+        ★
+      </AuthButton>
+
       ))}
       {submitted && <span className="thank-you">感谢您的评分!</span>}
     </div>
diff --git a/src/pages/SeedList/SeedList.jsx b/src/pages/SeedList/SeedList.jsx
index 263038b..45b9f8c 100644
--- a/src/pages/SeedList/SeedList.jsx
+++ b/src/pages/SeedList/SeedList.jsx
@@ -169,8 +169,8 @@
 
             <div className="tag-filters">
                 {TAGS.map(tag => (
-                    <AuthButton
-                        roles={["test"]}
+                     <button
+                        // roles={["test"]}
                         key={tag}
                         className={`tag-button ${activeTab === tag ? 'active-tag' : ''}`}
                         onClick={() => {
@@ -180,7 +180,7 @@
                         }}
                     >
                         {tag}
-                    </AuthButton>
+                    </button>
                 ))}
             </div>
 
@@ -257,9 +257,10 @@
                                             </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-downloads">{seed.downloads ?? 0} 次下载</div>
+                                            <div className="seed-item-downloads">{seed.leechers ?? 0} 次下载</div>
                                             <div className="seed-item-actions" onClick={e => e.stopPropagation()}>
-                                                <button
+                                                <AuthButton
+                                                roles={["cookie", "chocolate", "ice-cream"]}
                                                     className="btn-primary"
                                                     onClick={e => {
                                                         e.preventDefault();
@@ -285,8 +286,9 @@
                                                     }}
                                                 >
                                                     下载
-                                                </button>
-                                                <button
+                                                </AuthButton>
+                                                <AuthButton
+                                                    roles={["cookie", "chocolate", "ice-cream"]}
                                                     className="btn-outline"
                                                     onClick={async (e) => {
                                                         e.preventDefault();
@@ -314,7 +316,7 @@
                                                     }}
                                                 >
                                                     收藏
-                                                </button>
+                                                </AuthButton>
                                             </div>
                                         </div>
                                     </Link>
diff --git a/src/pages/UserCenter/UserLevelExperience.jsx b/src/pages/UserCenter/UserLevelExperience.jsx
index 60dcd55..81135c1 100644
--- a/src/pages/UserCenter/UserLevelExperience.jsx
+++ b/src/pages/UserCenter/UserLevelExperience.jsx
@@ -7,6 +7,9 @@
 //   const [isLoading, setIsLoading] = useState(false);
 //   const [upgradeResult, setUpgradeResult] = useState(null);
 //   const [hasCheckedIn, setHasCheckedIn] = useState(false);
+//   const [isUpgrading, setIsUpgrading] = useState(false);
+//   const [lastUpgradeTime, setLastUpgradeTime] = useState(null);
+//   const [justUpgraded, setJustUpgraded] = useState(false); // 新增
 
 //   useEffect(() => {
 //     if (!userId) return;
@@ -14,14 +17,16 @@
 //   }, [userId]);
 
 //   useEffect(() => {
-//     // 自动触发升级判断
 //     if (
 //       experienceInfo &&
-//       experienceInfo.current_experience >= experienceInfo.next_level_experience
+//       experienceInfo.current_experience >= experienceInfo.next_level_experience &&
+//       !isUpgrading &&
+//       !justUpgraded &&
+//       (!lastUpgradeTime || Date.now() - lastUpgradeTime > 2000)
 //     ) {
 //       checkUpgrade();
 //     }
-//   }, [experienceInfo]);
+//   }, [experienceInfo, isUpgrading, lastUpgradeTime, justUpgraded]);
 
 //   const fetchAllLevelData = async () => {
 //     try {
@@ -81,8 +86,11 @@
 //   };
 
 //   const checkUpgrade = async () => {
+//     if (isUpgrading) return;
+
 //     try {
 //       setIsLoading(true);
+//       setIsUpgrading(true);
 //       setError(null);
 
 //       const { data } = await axios.get('/echo/level/upgrade-check', {
@@ -90,46 +98,66 @@
 //       });
 
 //       if (data.can_upgrade) {
-//         await performUpgrade(); // 自动触发
+//         if (window.confirm('您已满足升级条件,是否要升级?')) {
+//           await performUpgrade();
+//         }
+//       } else {
+//         if (data.is_max_level) {
+//           alert('您已达到最高等级!');
+//         } else {
+//           alert(`还不能升级,还需要${data.next_level_experience - data.current_experience}点经验值`);
+//         }
 //       }
 //     } catch (err) {
 //       console.error('检查升级失败:', err);
 //       setError(err.response?.data?.message || '检查升级失败');
 //     } finally {
 //       setIsLoading(false);
+//       setIsUpgrading(false);
 //     }
 //   };
 
+//   const performUpgrade = async () => {
+//     try {
+//       setIsUpgrading(true);
+//       setIsLoading(true);
+//       setError(null);
 
-// const performUpgrade = async () => {
-//   try {
-//     setIsLoading(true);
-//     setError(null);
+//       const { data } = await axios.post('/echo/level/upgrades', {
+//         user_id: userId,
+//         can_upgrade: true,
+//       });
 
-//     const { data } = await axios.post('/echo/level/upgrades', {
-//       user_id: userId,
-//       can_upgrade: true,
-//     });
+//       console.log('升级响应数据:', data);
 
-//     console.log('升级响应数据:', data); // 保留调试日志
+//       if (data.status === 'success') {
+//         setExperienceInfo((prev) => ({
+//           ...prev,
+//           current_level: data.new_level,
+//           current_experience: data.current_experience || 0,
+//           next_level_experience: data.next_level_experience || prev.next_level_experience * 2,
+//         }));
 
-//     setExperienceInfo((prev) => ({
-//       ...prev,
-//       current_level: data.new_level, // 修复:使用正确的字段名
-//       current_experience: 0,
-//       next_level_experience: prev.next_level_experience * 2,
-//     }));
+//         setUpgradeResult(data);
+//         setLastUpgradeTime(Date.now());
+//         setJustUpgraded(true); // 标记为刚升级过
+//         setTimeout(() => setJustUpgraded(false), 3000); // 3 秒冷却期
+//         alert(`恭喜!您已升级到等级 ${data.new_level}!`);
 
-//     setUpgradeResult(data);
-//     alert(`恭喜!您已升级到等级 ${data.new_level}!`); // 修复:使用正确的字段名
-//   } catch (err) {
-//     console.error('升级失败:', err);
-//     setError(err.response?.data?.message || '升级失败');
-//   } finally {
-//     setIsLoading(false);
-//   }
-// };
-
+//         // 再次拉取最新经验数据,避免经验值仍然满足升级条件
+//         await fetchAllLevelData();
+//       } else {
+//         throw new Error(data.message || '升级失败');
+//       }
+//     } catch (err) {
+//       console.error('升级失败:', err);
+//       setError(err.message || '升级失败');
+//       alert(err.message || '升级失败,请稍后再试');
+//     } finally {
+//       setIsLoading(false);
+//       setIsUpgrading(false);
+//     }
+//   };
 
 //   if (error) return <p className="error">{error}</p>;
 //   if (isLoading) return <p>加载中...</p>;
@@ -141,11 +169,11 @@
 //     (current_experience / (next_level_experience || 1)) * 100
 //   ).toFixed(2);
 
-//   const expToNextLevel = Math.max(0, next_level_experience - current_experience); // 防止负数
+//   const expToNextLevel = Math.max(0, next_level_experience - current_experience);
 
 //   return (
 //     <div className="level-experience-section">
-//       {/* <h3>等级与经验</h3> */}
+//       <h3>等级与经验</h3>
 //       <p><strong>当前等级:</strong>{current_level || '未知'}</p>
 //       <p><strong>当前经验:</strong>{current_experience}</p>
 //       <p><strong>距离下一等级还需:</strong>{expToNextLevel} 经验值</p>
@@ -155,14 +183,17 @@
 //       </div>
 //       <p className="exp-progress-text">{progressPercent}%</p>
 
-
 //       {upgradeResult && (
 //         <div className="upgrade-success">
-//             {/* 使用与状态一致的字段名 */}
-//             <p>恭喜!您已成功升级到等级 {upgradeResult.new_level}!</p>
+//           <p>恭喜!您已成功升级到等级 {upgradeResult.new_level}!</p>
 //         </div>
-//         )}
-      
+//       )}
+
+//       {error && (
+//         <div className="upgrade-error">
+//           <p>{error}</p>
+//         </div>
+//       )}
 
 //       <div className="level-actions">
 //         <button onClick={() => updateExperience('check-in', 15)} disabled={hasCheckedIn}>
@@ -170,7 +201,9 @@
 //         </button>
 //         <button onClick={() => updateExperience('task', 30)}>完成任务 (+30经验)</button>
 //         <button onClick={() => updateExperience('upload', 50)}>上传种子 (+50经验)</button>
-//         {/* <button onClick={checkUpgrade}>检查升级</button> */}
+//         <button onClick={checkUpgrade} disabled={isUpgrading}>
+//           {isUpgrading ? '升级中...' : '检查升级'}
+//         </button>
 //       </div>
 //     </div>
 //   );
@@ -178,198 +211,3 @@
 
 // export default UserLevelExperience;
 
-import React, { useState, useEffect } from 'react';
-import axios from 'axios';
-
-const UserLevelExperience = ({ userId }) => {
-  const [experienceInfo, setExperienceInfo] = useState(null);
-  const [error, setError] = useState(null);
-  const [isLoading, setIsLoading] = useState(false);
-  const [upgradeResult, setUpgradeResult] = useState(null);
-  const [hasCheckedIn, setHasCheckedIn] = useState(false);
-
-  useEffect(() => {
-    if (!userId) return;
-    fetchAllLevelData();
-  }, [userId]);
-
-  useEffect(() => {
-    // 自动触发升级判断
-    if (
-      experienceInfo &&
-      experienceInfo.current_experience >= experienceInfo.next_level_experience
-    ) {
-      checkUpgrade();
-    }
-  }, [experienceInfo]);
-
-  const fetchAllLevelData = async () => {
-    try {
-      setIsLoading(true);
-      setError(null);
-
-      const { data } = await axios.get('/echo/level/getExperience', {
-        params: { user_id: userId },
-      });
-
-      const normalizedData = {
-        ...data,
-        current_level: data.current_level || data.level,
-      };
-
-      setExperienceInfo(normalizedData);
-
-      const today = new Date().toDateString();
-      const lastCheckIn = localStorage.getItem('lastCheckIn');
-      setHasCheckedIn(lastCheckIn === today);
-    } catch (err) {
-      console.error('经验信息获取失败:', err);
-      setError('获取经验信息失败');
-    } finally {
-      setIsLoading(false);
-    }
-  };
-
-  const updateExperience = async (source, amount = 10) => {
-    try {
-      setIsLoading(true);
-      setError(null);
-
-      const { data } = await axios.post('/echo/level/updateExperience', {
-        user_id: userId,
-        experience: amount,
-        source: source,
-      });
-
-      setExperienceInfo((prev) => ({
-        ...prev,
-        current_experience: data.current_experience,
-      }));
-
-      alert(`获得${amount}点经验值!来源:${source}`);
-
-      if (source === 'check-in') {
-        localStorage.setItem('lastCheckIn', new Date().toDateString());
-        setHasCheckedIn(true);
-      }
-    } catch (err) {
-      console.error('更新经验失败:', err);
-      setError(err.response?.data?.message || '更新经验失败');
-    } finally {
-      setIsLoading(false);
-    }
-  };
-
-  const checkUpgrade = async () => {
-    try {
-      setIsLoading(true);
-      setError(null);
-
-      const { data } = await axios.get('/echo/level/upgrade-check', {
-        params: { user_id: userId },
-      });
-
-      if (data.can_upgrade) {
-        if (window.confirm('您已满足升级条件,是否要升级?')) {
-          await performUpgrade();
-        }
-      } else {
-        // 区分是经验不足还是已达最高等级
-        if (data.is_max_level) {
-          alert('您已达到最高等级!');
-        } else {
-          alert(`还不能升级,还需要${data.next_level_experience - data.current_experience}点经验值`);
-        }
-      }
-    } catch (err) {
-      console.error('检查升级失败:', err);
-      setError(err.response?.data?.message || '检查升级失败');
-    } finally {
-      setIsLoading(false);
-    }
-  };
-
-  const performUpgrade = async () => {
-    try {
-      setIsLoading(true);
-      setError(null);
-
-      const { data } = await axios.post('/echo/level/upgrades', {
-        user_id: userId,
-        can_upgrade: true,
-      });
-
-      console.log('升级响应数据:', data);
-
-      // 正确处理升级结果
-      if (data.status === 'success') {
-        setExperienceInfo((prev) => ({
-          ...prev,
-          current_level: data.new_level,
-          current_experience: 0,
-          next_level_experience: prev.next_level_experience * 2,
-        }));
-
-        setUpgradeResult(data);
-        alert(`恭喜!您已升级到等级 ${data.new_level}!`);
-      } else {
-        throw new Error(data.message || '升级失败');
-      }
-    } catch (err) {
-      console.error('升级失败:', err);
-      setError(err.message || '升级失败');
-      alert(err.message || '升级失败,请稍后再试');
-    } finally {
-      setIsLoading(false);
-    }
-  };
-
-  if (error) return <p className="error">{error}</p>;
-  if (isLoading) return <p>加载中...</p>;
-  if (!experienceInfo) return <p>加载经验信息中...</p>;
-
-  const { current_experience, next_level_experience, current_level } = experienceInfo;
-  const progressPercent = Math.min(
-    100,
-    (current_experience / (next_level_experience || 1)) * 100
-  ).toFixed(2);
-
-  const expToNextLevel = Math.max(0, next_level_experience - current_experience);
-
-  return (
-    <div className="level-experience-section">
-      <h3>等级与经验</h3>
-      <p><strong>当前等级:</strong>{current_level || '未知'}</p>
-      <p><strong>当前经验:</strong>{current_experience}</p>
-      <p><strong>距离下一等级还需:</strong>{expToNextLevel} 经验值</p>
-
-      <div className="exp-bar-wrapper">
-        <div className="exp-bar" style={{ width: `${progressPercent}%` }} />
-      </div>
-      <p className="exp-progress-text">{progressPercent}%</p>
-
-      {upgradeResult && (
-        <div className="upgrade-success">
-          <p>恭喜!您已成功升级到等级 {upgradeResult.new_level}!</p>
-        </div>
-      )}
-
-      {error && (
-        <div className="upgrade-error">
-          <p>{error}</p>
-        </div>
-      )}
-
-      <div className="level-actions">
-        <button onClick={() => updateExperience('check-in', 15)} disabled={hasCheckedIn}>
-          {hasCheckedIn ? '今日已签到' : '每日签到 (+15经验)'}
-        </button>
-        <button onClick={() => updateExperience('task', 30)}>完成任务 (+30经验)</button>
-        <button onClick={() => updateExperience('upload', 50)}>上传种子 (+50经验)</button>
-        <button onClick={checkUpgrade}>检查升级</button>
-      </div>
-    </div>
-  );
-};
-
-export default UserLevelExperience;  
diff --git a/src/pages/UserCenter/UserNav.jsx b/src/pages/UserCenter/UserNav.jsx
index 63b83ca..7e09e2c 100644
--- a/src/pages/UserCenter/UserNav.jsx
+++ b/src/pages/UserCenter/UserNav.jsx
@@ -10,7 +10,7 @@
     { to: '/user/profile', label: '个人资料' },
     { to: '/user/dynamics', label: '我的动态' },
     { to: '/user/friends', label: '我的好友' },
-    { to: '/user/groups', label: '我的群组' },
+    // { to: '/user/groups', label: '我的群组' },
     { to: '/user/collections', label: '我的收藏' },
     // { to: '/user/newbie-tasks', label: '用户考核' },
     { to: '/user/invite', label: '邀请新用户' },
diff --git a/src/pages/UserCenter/UserProfile.jsx b/src/pages/UserCenter/UserProfile.jsx
index bcfbf0b..79d8313 100644
--- a/src/pages/UserCenter/UserProfile.jsx
+++ b/src/pages/UserCenter/UserProfile.jsx
@@ -1,7 +1,8 @@
 import React from 'react';
 import UserProfileBase from './UserProfileBase';
-import UserLevelExperience from './UserLevelExperience';
+// import UserLevelExperience from './UserLevelExperience';
 import './UserProfile.css';
+import UserStatusChecker from './UserStatusChecker';
 
 const UserProfile = () => {
   const [userId, setUserId] = React.useState(null);
@@ -13,7 +14,8 @@
   return (
     <div>
       <UserProfileBase onLoadExperienceInfo={loadExperienceInfo} />
-      {userId && <UserLevelExperience userId={userId} />}
+      {/* {userId && <UserLevelExperience userId={userId} />} */}
+      {/* <UserStatusChecker /> */}
     </div>
   );
 };
diff --git a/src/pages/UserCenter/UserProfileBase.jsx b/src/pages/UserCenter/UserProfileBase.jsx
index 791baca..c90cb63 100644
--- a/src/pages/UserCenter/UserProfileBase.jsx
+++ b/src/pages/UserCenter/UserProfileBase.jsx
@@ -9,7 +9,7 @@
 const DEFAULT_AVATAR_URL = `${process.env.PUBLIC_URL}/default-avatar.png`;
 
 const UserProfileBase = ({ onLoadExperienceInfo }) => {
-  const { user, loading, logout } = useUser();
+  const { user, loading, logout ,saveUser} = useUser();
   const [userProfile, setUserProfile] = useState(null);
   const [error, setError] = useState(null);
 
@@ -66,34 +66,44 @@
     fetchUserProfile();
   }, [user, loading, onLoadExperienceInfo]);
 
-  const handleAvatarUpload = async (e) => {
-    const file = e.target.files[0];
-    if (!file) return;
+const handleAvatarUpload = async (e) => {
+  const file = e.target.files[0];
+  if (!file) return;
 
-    const formData = new FormData();
-    formData.append('file', file);
+  const formData = new FormData();
+  formData.append('file', file);
 
-    try {
-      const { data } = await axios.post(
-        `/echo/user/${user.userId}/uploadAvatar`,
-        formData,
-        { headers: { 'Content-Type': 'multipart/form-data' } }
-      );
+  try {
+    const { data } = await axios.post(
+      `/echo/user/${user.userId}/uploadAvatar`,
+      formData,
+      { headers: { 'Content-Type': 'multipart/form-data' } }
+    );
 
-      if (data?.avatarUrl) {
-        setUserProfile((prev) => ({
-          ...prev,
-          avatarUrl: `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}`,
-        }));
-        toast.success('头像上传成功');
-      } else {
-        toast.success('头像上传成功,但未返回新头像地址');
-      }
-    } catch (err) {
-      console.error('上传失败:', err);
-      toast.error('头像上传失败,请重试');
+    if (data?.avatarUrl) {
+      // 加时间戳避免缓存
+      const newAvatarUrl = `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}?t=${Date.now()}`;
+
+      setUserProfile((prev) => ({
+        ...prev,
+        avatarUrl: newAvatarUrl,
+      }));
+
+      saveUser({
+        ...user,
+        avatarUrl: newAvatarUrl,
+      });
+
+      toast.success('头像上传成功');
+    } else {
+      toast.success('头像上传成功,但未返回新头像地址');
     }
-  };
+  } catch (err) {
+    console.error('上传失败:', err);
+    toast.error('头像上传失败,请重试');
+  }
+};
+
 
   const handleLogout = () => {
     logout();
diff --git a/src/pages/UserCenter/UserStatusChecker.jsx b/src/pages/UserCenter/UserStatusChecker.jsx
new file mode 100644
index 0000000..7b8b303
--- /dev/null
+++ b/src/pages/UserCenter/UserStatusChecker.jsx
@@ -0,0 +1,58 @@
+import React, { useEffect, useState, useContext } from 'react';
+import axios from 'axios';
+import { UserContext } from '../../context/UserContext';
+
+const UserStatusChecker = () => {
+  const { user } = useContext(UserContext); // 假设你在上下文中已经有 user 信息
+  const [statusMessage, setStatusMessage] = useState('');
+  const [statusType, setStatusType] = useState('normal'); // normal / warning / danger
+
+  useEffect(() => {
+    if (user?.id) {
+      checkUserShareRate(user.id);
+    }
+  }, [user]);
+
+  const checkUserShareRate = async (userId) => {
+    try {
+      const response = await axios.get(`/users/${userId}/share-rate`);
+      const message = response.data;
+
+      setStatusMessage(message);
+
+      if (message.includes('账号已被注销')) {
+        setStatusType('danger');
+      } else if (message.includes('警告')) {
+        setStatusType('warning');
+      } else {
+        setStatusType('normal');
+      }
+
+    } catch (error) {
+      console.error('获取用户状态失败:', error);
+      setStatusMessage('无法获取用户状态');
+      setStatusType('danger');
+    }
+  };
+
+  const getStatusStyle = () => {
+    switch (statusType) {
+      case 'warning':
+        return { backgroundColor: '#fff3cd', color: '#856404', padding: '10px', borderRadius: '8px' };
+      case 'danger':
+        return { backgroundColor: '#f8d7da', color: '#721c24', padding: '10px', borderRadius: '8px' };
+      default:
+        return { backgroundColor: '#d4edda', color: '#155724', padding: '10px', borderRadius: '8px' };
+    }
+  };
+
+  return (
+    <div style={{ marginTop: '20px' }}>
+      <div style={getStatusStyle()}>
+        <strong>账号状态提示:</strong> {statusMessage}
+      </div>
+    </div>
+  );
+};
+
+export default UserStatusChecker;