修改论坛、促销、登录,增加测试

Change-Id: I71883fc1da46a94db47f90a4cd61474c274a5b2c
diff --git a/src/pages/Forum/posts-main/ForumPage.css b/src/pages/Forum/posts-main/ForumPage.css
index 8a7ae4c..5fd64a2 100644
--- a/src/pages/Forum/posts-main/ForumPage.css
+++ b/src/pages/Forum/posts-main/ForumPage.css
@@ -2,7 +2,7 @@
     color: #fff;
     /* background-color: #5F4437; */
     /* background: linear-gradient(180deg, #5F4437, #9c737b); */
-    background: linear-gradient(180deg, #5F4437, #823c3c);
+    background: #333;
     /* background-color: #5F4437; */
     min-height: 100vh;
     font-family: Arial, sans-serif;
diff --git a/src/pages/Forum/posts-main/components/CreatePostButton.jsx b/src/pages/Forum/posts-main/components/CreatePostButton.jsx
index 0390ee7..4f7d7b1 100644
--- a/src/pages/Forum/posts-main/components/CreatePostButton.jsx
+++ b/src/pages/Forum/posts-main/components/CreatePostButton.jsx
@@ -4,7 +4,7 @@
 import './CreatePostButton.css';
 
 const API_BASE = process.env.REACT_APP_API_BASE;
-const USER_ID = 456;
+const user_id = 456;
 
 const CreatePostButton = () => {
   const [showModal, setShowModal] = useState(false);
@@ -49,7 +49,7 @@
 
     try {
       await axios.post(
-        `${API_BASE}/echo/forum/posts/${USER_ID}/createPost`,
+        `${API_BASE}/echo/forum/posts/${user_id}/createPost`,
         {
           title: title.trim(),
           post_content: content.trim(),
diff --git a/src/pages/Forum/posts-main/components/PostList.jsx b/src/pages/Forum/posts-main/components/PostList.jsx
index 3eba6f8..707ff15 100644
--- a/src/pages/Forum/posts-main/components/PostList.jsx
+++ b/src/pages/Forum/posts-main/components/PostList.jsx
@@ -1,175 +1,8 @@
-// import React, { useEffect, useState } from 'react';
-// import axios from 'axios';
-// import { Link } from 'wouter';
-// import { GoodTwo, Comment, Star } from '@icon-park/react';
-// import { likePost, unlikePost, collectPost } from '../../posts-detail/api'; 
-// import './PostList.css';
-
-// const API_BASE = process.env.REACT_APP_API_BASE;
-
-// const PostList = ({ search }) => {
-//   const [posts, setPosts] = useState([]);
-//   const [page, setPage] = useState(1);
-//   const [total, setTotal] = useState(0);
-//   const [loading, setLoading] = useState(true);
-//   const [errorMsg, setErrorMsg] = useState('');
-
-//   const size = 10;  // 每页条数
-//   const totalPages = Math.ceil(total / size);
-
-//   useEffect(() => {
-//     const fetchPosts = async () => {
-//       setLoading(true);
-//       setErrorMsg('');
-//       try {
-//         const res = await axios.get(`${API_BASE}/echo/forum/posts`, {
-//           params: { 
-//             page: page,
-//             pageSize: size,
-//             sortBy: 'createdAt',  // 按时间排序
-//             order: 'desc'         // 按降序排序
-//           }
-//         });
-
-//         const postsData = res.data.posts || [];
-//         const userIds = [...new Set(postsData.map(p => p.user_id))];
-
-//         // 获取用户信息
-//         const profiles = await Promise.all(userIds.map(async id => {
-//           try {
-//             const r = await axios.get(`${API_BASE}/echo/user/profile`, {
-//               params: { user_id: id }
-//             });
-//             return { id, profile: r.data };
-//           } catch {
-//             return { id, profile: { nickname: '未知用户', avatar_url: 'default-avatar.png' } };
-//           }
-//         }));
-
-//         const userMap = {};
-//         profiles.forEach(({ id, profile }) => { userMap[id] = profile; });
-
-//         // 更新帖子数据
-//         const postsWithProfiles = postsData
-//           .filter(post => post.title.includes(search))
-//           .map(post => ({
-//             ...post,
-//             userProfile: userMap[post.user_id] || {}
-//           }));
-
-//         setPosts(postsWithProfiles);
-//         setTotal(res.data.total || 0);
-//       } catch (err) {
-//         console.error('加载失败:', err);
-//         setErrorMsg('加载失败,请稍后重试');
-//       } finally {
-//         setLoading(false);
-//       }
-//     };
-
-//     fetchPosts();
-//   }, [page, search]);
-
-//   // 点赞/取消点赞操作
-//   const toggleLike = async (postId, liked, userId) => {
-//     try {
-//       if (liked) {
-//         await unlikePost(postId);  // 取消点赞
-//       } else {
-//         await likePost(postId, userId);  // 点赞
-//       }
-
-//       setPosts(posts =>
-//         posts.map(post =>
-//           post.id === postId
-//             ? { ...post, liked: !liked, likeCount: liked ? post.likeCount - 1 : post.likeCount + 1 }
-//             : post
-//         )
-//       );
-//     } catch (err) {
-//       console.error('点赞失败:', err);
-//     }
-//   };
-
-//   // 收藏/取消收藏操作
-//   const toggleCollect = async (postId, collected, userId) => {
-//     try {
-//       const action = collected ? 'cancel' : 'collect';
-//       await collectPost(postId, userId, action);
-
-//       setPosts(posts =>
-//         posts.map(post =>
-//           post.id === postId
-//             ? { ...post, collected: !collected, collectCount: collected ? post.collectCount - 1 : post.collectCount + 1 }
-//             : post
-//         )
-//       );
-//     } catch (err) {
-//       console.error('收藏失败:', err);
-//     }
-//   };
-
-//   return (
-//     <div className="post-list">
-//       {loading ? <p>加载中...</p> :
-//         errorMsg ? <p className="error-text">{errorMsg}</p> :
-//           posts.length === 0 ? <p>暂无帖子。</p> :
-//             posts.map(post => (
-//               <Link
-//                 key={post.id}
-//                 href={`/forum/post/${post.id}`}
-//                 className="post-card"
-//                 style={{ backgroundColor: '#e9ded2' }}
-//               >
-//                 <div className="user-info">
-//                   <img className="avatar" src={post.userProfile.avatar_url} alt="头像" />
-//                   <span className="nickname" style={{ color: '#755e50' }}>{post.userProfile.nickname}</span>
-//                 </div>
-//                 {post.cover_image_url && (
-//                   <img className="cover-image" src={post.cover_image_url} alt="封面" />
-//                 )}
-//                 <h3 style={{ color: '#000000' }}>{post.title}</h3>
-//                 <div className="post-meta">
-//                   <span>发布时间:{new Date(post.createdAt).toLocaleString()}</span>
-//                   <div className="post-actions">
-//                     {/* 点赞按钮 */}
-//                     <button className="icon-btn" onClick={(e) => { e.stopPropagation(); toggleLike(post.id, post.liked, post.user_id); }}>
-//                       <GoodTwo theme="outline" size="24" fill={post.liked ? '#f00' : '#fff'} />
-//                       <span>{post.likeCount}</span>
-//                     </button>
-  
-//                     {/* 收藏按钮 */}
-//                     <button className="icon-btn" onClick={(e) => { e.stopPropagation(); toggleCollect(post.id, post.collected, post.user_id); }}>
-//                       <Star theme="outline" size="24" fill={post.collected ? '#ffd700' : '#fff'} />
-//                       <span>{post.collectCount}</span>
-//                     </button>
-  
-//                     <Link href={`/forum/post/${post.id}`} className="icon-btn" onClick={(e) => e.stopPropagation()}>
-//                       <Comment theme="outline" size="24" fill="#fff" />
-//                       <span>{post.commentCount}</span>
-//                     </Link>
-//                   </div>
-//                 </div>
-//               </Link>
-//             ))
-//       }
-  
-//       <div className="pagination">
-//         <button disabled={page === 1} onClick={() => setPage(page - 1)}>上一页</button>
-//         <span>第 {page} 页 / 共 {totalPages} 页</span>
-//         <button disabled={page === totalPages} onClick={() => setPage(page + 1)}>下一页</button>
-//       </div>
-//     </div>
-//   );
-// };
-
-// export default PostList;
-
 import React, { useEffect, useState } from 'react';
 import axios from 'axios';
 import { Link } from 'wouter';
-import { GoodTwo, Comment, Star } from '@icon-park/react';
-import { likePost, unlikePost, collectPost } from '../../posts-detail/api';
+import { GoodTwo, Comment, Star, Delete } from '@icon-park/react';
+import { likePost, unlikePost } from '../../posts-detail/api';
 import './PostList.css';
 
 const API_BASE = process.env.REACT_APP_API_BASE;
@@ -200,10 +33,8 @@
 
         const postsData = res.data.posts || [];
 
-        // 收集所有 user_id
         const userIds = [...new Set(postsData.map(post => post.user_id))];
 
-        // 批量请求用户资料
         const profiles = await Promise.all(userIds.map(async id => {
           try {
             const r = await axios.get(`${API_BASE}/echo/user/profile`, {
@@ -215,13 +46,11 @@
           }
         }));
 
-        // 创建 user_id -> profile 映射
         const userMap = {};
         profiles.forEach(({ id, profile }) => {
           userMap[id] = profile;
         });
 
-        // 过滤并补充 profile
         const postsWithProfiles = postsData
           .filter(post => post.title.toLowerCase().includes(search.toLowerCase()))
           .map(post => ({
@@ -265,10 +94,20 @@
     }
   };
 
+  // 收藏帖子
   const toggleCollect = async (postId, collected, userId) => {
     try {
-      const action = collected ? 'cancel' : 'collect';
-      await collectPost(postId, userId, action);
+      if (collected) {
+        // 取消收藏
+        await axios.get(`${API_BASE}/echo/forum/posts/${postId}/uncollect`, {
+          data: { user_id: userId }
+        });
+      } else {
+        // 收藏帖子
+        await axios.post(`${API_BASE}/echo/forum/posts/${postId}/collect`, {
+          user_id: userId
+        });
+      }
 
       setPosts(posts =>
         posts.map(post =>
@@ -278,7 +117,27 @@
         )
       );
     } catch (err) {
-      console.error('收藏失败:', err);
+      console.error('收藏操作失败:', err);
+    }
+  };
+
+  // 删除帖子
+  const handleDeletePost = async (postId) => {
+    if (window.confirm('确定要删除这篇帖子吗?')) {
+      try {
+        await axios.delete(`${API_BASE}/echo/forum/posts/${postId}/deletePost`);
+        
+        // 从列表中移除已删除的帖子
+        setPosts(posts => posts.filter(post => post.postNo !== postId));
+        
+        // 如果删除后当前页没有帖子了,尝试加载上一页
+        if (posts.length === 1 && page > 1) {
+          setPage(page - 1);
+        }
+      } catch (err) {
+        console.error('删除帖子失败:', err);
+        alert('删除帖子失败,请稍后再试');
+      }
     }
   };
 
@@ -288,9 +147,8 @@
         errorMsg ? <p className="error-text">{errorMsg}</p> :
           posts.length === 0 ? <p>暂无帖子。</p> :
             posts.map(post => (
-              <Link
+              <div
                 key={post.postNo}
-                href={`/forum/post/${post.postNo}`}
                 className="post-card"
                 style={{ backgroundColor: '#e9ded2' }}
               >
@@ -305,23 +163,30 @@
                 <div className="post-meta">
                   <span>发布时间:{new Date(post.createdAt).toLocaleString()}</span>
                   <div className="post-actions">
-                    <button className="icon-btn" onClick={(e) => { e.stopPropagation(); toggleLike(post.postNo, post.liked, post.user_id); }}>
+                    <button className="icon-btn" onClick={() => toggleLike(post.postNo, post.liked, post.user_id)}>
                       <GoodTwo theme="outline" size="24" fill={post.liked ? '#f00' : '#fff'} />
                       <span>{post.likeCount}</span>
                     </button>
 
-                    <button className="icon-btn" onClick={(e) => { e.stopPropagation(); toggleCollect(post.postNo, post.collected, post.user_id); }}>
+                    <button className="icon-btn" onClick={() => toggleCollect(post.postNo, post.collected, post.user_id)}>
                       <Star theme="outline" size="24" fill={post.collected ? '#ffd700' : '#fff'} />
                       <span>{post.collectCount}</span>
                     </button>
 
-                    <Link href={`/forum/post/${post.postNo}`} className="icon-btn" onClick={(e) => e.stopPropagation()}>
+                    <div className="icon-btn">
                       <Comment theme="outline" size="24" fill="#fff" />
                       <span>{post.commentCount}</span>
-                    </Link>
+                    </div>
+                    
+                    <button className="icon-btn" onClick={() => handleDeletePost(post.postNo)}>
+                      <Delete theme="outline" size="24" fill="#333" />
+                    </button>
                   </div>
                 </div>
-              </Link>
+                <div className="detail-button-wrapper">
+                  <Link href={`/forum/post/${post.postNo}`} className="detail-button">查看详情</Link>
+                </div>
+              </div>
             ))
       }
 
@@ -334,4 +199,4 @@
   );
 };
 
-export default PostList;
+export default PostList;
\ No newline at end of file