修复帖子点赞和收藏功能

Change-Id: If66f9065607d97fb9527f0905b3465e6cd5b5995
diff --git a/src/App.js b/src/App.js
index 165caef..29f392f 100644
--- a/src/App.js
+++ b/src/App.js
@@ -22,7 +22,7 @@
         <Route path="/friend-moments" component={FriendMoments} />
         <Route path="/forum" component={ForumPage} />
         <Route path="/forum/post/:postId" component={PostDetailPage} />
-        <Route path="/forum/create-post" element={CreatePostPage} />
+        <Route path="/forum/create-post" component={CreatePostPage} />
         <Route path="/seed-list" component={SeedList} />
         <Route path="/publish-seed" component={PublishSeed} />
         <Route path="/seed/:seed_id" component={SeedDetail} /> {/* 新增路由 */}
diff --git a/src/context/UserContext.js b/src/context/UserContext.js
index 64c1b9a..a2be382 100644
--- a/src/context/UserContext.js
+++ b/src/context/UserContext.js
@@ -6,22 +6,24 @@
   const [user, setUser] = useState(null);
   const [loading, setLoading] = useState(true);
 
-  // 加载本地存储的用户信息
   useEffect(() => {
     const storedUser = localStorage.getItem('user');
     if (storedUser) {
       setUser(JSON.parse(storedUser));
+    } else {
+      // 设置默认用户(id: 1)
+      const defaultUser = { id: 1, name: '测试用户' };
+      localStorage.setItem('user', JSON.stringify(defaultUser));
+      setUser(defaultUser);
     }
     setLoading(false);
   }, []);
 
-  // 保存用户信息到本地存储
   const saveUser = (userData) => {
     localStorage.setItem('user', JSON.stringify(userData));
     setUser(userData);
   };
 
-  // 退出登录
   const logout = () => {
     localStorage.removeItem('user');
     setUser(null);
@@ -34,4 +36,4 @@
   );
 };
 
-export const useUser = () => useContext(UserContext);
\ No newline at end of file
+export const useUser = () => useContext(UserContext);
diff --git a/src/pages/Forum/posts-create/CreatePost.jsx b/src/pages/Forum/posts-create/CreatePost.jsx
index a03a836..e38c29a 100644
--- a/src/pages/Forum/posts-create/CreatePost.jsx
+++ b/src/pages/Forum/posts-create/CreatePost.jsx
@@ -1,91 +1,172 @@
-// src/pages/Forum/CreatePost.jsx
+// // src/pages/Forum/CreatePost.jsx
+// import React, { useState } from 'react';
+// import axios from 'axios';
+
+// const API_BASE = process.env.REACT_APP_API_BASE;
+
+// const CreatePost = ({ userId }) => {
+//   const [title, setTitle] = useState('');
+//   const [content, setContent] = useState('');
+//   const [imgUrl, setImageUrl] = useState('');
+//   const [isAnonymous, setIsAnonymous] = useState(false);
+
+//   const handleSubmit = async (e) => {
+//     e.preventDefault();
+
+//     try {
+//       const postData = {
+//         title,
+//         postContent: content,
+//         postType: isAnonymous,
+//       };
+
+//       if (imgUrl.trim()) {
+//         postData.imgUrl = imgUrl;
+//       }
+
+//       const response = await axios.post(
+//         `${API_BASE}/echo/forum/posts/${userId}/createPost`,
+//         postData
+//       );
+      
+
+//       if (response.status === 201) {
+//         alert('帖子创建成功!');
+//         setTitle('');
+//         setContent('');
+//         setImageUrl('');
+//         setIsAnonymous(false);
+//       }
+//     } catch (error) {
+//       console.error('帖子创建失败:', error.response?.data || error.message);
+//       alert('创建失败,请重试');
+//     }    
+//   };
+
+//   return (
+//     <div className="create-post">
+//       <h2>创建新帖子</h2>
+//       <form onSubmit={handleSubmit}>
+//         <div>
+//           <label>标题:</label>
+//           <input
+//             type="text"
+//             value={title}
+//             onChange={(e) => setTitle(e.target.value)}
+//             required
+//           />
+//         </div>
+//         <div>
+//           <label>内容:</label>
+//           <textarea
+//             value={content}
+//             onChange={(e) => setContent(e.target.value)}
+//             required
+//           />
+//         </div>
+//         <div>
+//           <label>图片 URL(可选):</label>
+//           <input
+//             type="text"
+//             value={imgUrl}
+//             onChange={(e) => setImageUrl(e.target.value)}
+//           />
+//         </div>
+//         <div>
+//           <label>
+//             <input
+//               type="checkbox"
+//               checked={isAnonymous}
+//               onChange={(e) => setIsAnonymous(e.target.checked)}
+//             />
+//             匿名发布
+//           </label>
+//         </div>
+//         <button type="submit">发布</button>
+//       </form>
+//     </div>
+//   );
+// };
+
+// export default CreatePost;
+
 import React, { useState } from 'react';
 import axios from 'axios';
+import './CreatePost.css'; // 如果你打算加样式
 
 const API_BASE = process.env.REACT_APP_API_BASE;
 
 const CreatePost = ({ userId }) => {
   const [title, setTitle] = useState('');
   const [content, setContent] = useState('');
-  const [imgUrl, setImageUrl] = useState('');
-  const [isAnonymous, setIsAnonymous] = useState(false);
+  const [imageUrl, setImageUrl] = useState('');
+  const [message, setMessage] = useState('');
+  const [error, setError] = useState('');
 
   const handleSubmit = async (e) => {
     e.preventDefault();
+    setMessage('');
+    setError('');
+
+    if (!title.trim() || !content.trim()) {
+      setError('标题和内容不能为空');
+      return;
+    }
 
     try {
-      const postData = {
+      const res = await axios.post(`${API_BASE}/echo/forum/posts/${userId}/createPost`, {
         title,
-        postContent: content,
-        postType: isAnonymous,
-      };
+        post_content: content,
+        image_url: imageUrl
+      });
 
-      if (imgUrl.trim()) {
-        postData.imgUrl = imgUrl;
-      }
-
-      const response = await axios.post(
-        `${API_BASE}/echo/forum/posts/${userId}/createPost`,
-        postData
-      );
-      
-
-      if (response.status === 201) {
-        alert('帖子创建成功!');
-        setTitle('');
-        setContent('');
-        setImageUrl('');
-        setIsAnonymous(false);
-      }
-    } catch (error) {
-      console.error('帖子创建失败:', error.response?.data || error.message);
-      alert('创建失败,请重试');
-    }    
+      setMessage(`发帖成功,帖子ID:${res.data.post_id}`);
+      setTitle('');
+      setContent('');
+      setImageUrl('');
+    } catch (err) {
+      console.error(err);
+      setError(err.response?.data?.error || '发帖失败,请稍后重试');
+    }
   };
 
   return (
-    <div className="create-post">
-      <h2>创建新帖子</h2>
-      <form onSubmit={handleSubmit}>
-        <div>
+    <div className="create-post-container">
+      <h2>发表新帖子</h2>
+      <form onSubmit={handleSubmit} className="create-post-form">
+        <div className="form-group">
           <label>标题:</label>
           <input
             type="text"
             value={title}
             onChange={(e) => setTitle(e.target.value)}
-            required
+            placeholder="输入帖子标题"
           />
         </div>
-        <div>
+        <div className="form-group">
           <label>内容:</label>
           <textarea
             value={content}
             onChange={(e) => setContent(e.target.value)}
-            required
+            placeholder="输入帖子内容"
           />
         </div>
-        <div>
-          <label>图片 URL(可选):</label>
+        <div className="form-group">
+          <label>图片链接(可选):</label>
           <input
             type="text"
-            value={imgUrl}
+            value={imageUrl}
             onChange={(e) => setImageUrl(e.target.value)}
+            placeholder="例如:https://example.com/img.jpg"
           />
         </div>
-        <div>
-          <label>
-            <input
-              type="checkbox"
-              checked={isAnonymous}
-              onChange={(e) => setIsAnonymous(e.target.checked)}
-            />
-            匿名发布
-          </label>
-        </div>
         <button type="submit">发布</button>
       </form>
+
+      {message && <p className="success-text">{message}</p>}
+      {error && <p className="error-text">{error}</p>}
     </div>
   );
 };
 
-export default CreatePost;
\ No newline at end of file
+export default CreatePost;
diff --git a/src/pages/Forum/posts-create/CreatePostPage.jsx b/src/pages/Forum/posts-create/CreatePostPage.jsx
index ea2505c..28f1a20 100644
--- a/src/pages/Forum/posts-create/CreatePostPage.jsx
+++ b/src/pages/Forum/posts-create/CreatePostPage.jsx
@@ -1,11 +1,22 @@
-// src/pages/Forum/posts-create/CreatePostPage.jsx
 import React from 'react';
-import { useUserStore } from '../../store/user';
 import CreatePost from './CreatePost';
+import { useUser } from '../../../context/UserContext'; // 注意路径
+
 
 const CreatePostPage = () => {
-  const { user } = useUserStore(); // 拿到 user
-  return <CreatePost userId={user?.id} />;
+  const store = useUser?.();
+  const user = store?.user;
+
+  // 可以加个判断
+  if (!user) {
+    return <p>请先登录后再发帖。</p>;
+  }
+
+  return (
+    <div className="create-post-page">
+      <CreatePost userId={user.user_id} />
+    </div>
+  );
 };
 
 export default CreatePostPage;
diff --git a/src/pages/Forum/posts-detail/PostDetailPage.jsx b/src/pages/Forum/posts-detail/PostDetailPage.jsx
index c0f218f..5186339 100644
--- a/src/pages/Forum/posts-detail/PostDetailPage.jsx
+++ b/src/pages/Forum/posts-detail/PostDetailPage.jsx
@@ -1,310 +1,273 @@
-import React, { useState, useEffect } from 'react';
-import { useRoute } from 'wouter';
-import {
-    getPostDetail,
-    getPostComments,
-    likePost,
-    unlikePost,
-    addCommentToPost,
-    replyToComment,
-    likeComment,
-    unlikeComment,
-    getUserInfo
-} from './api';
+import React, { useEffect, useState } from 'react';
+import { useParams } from 'wouter';
+import { GoodTwo, Star } from '@icon-park/react';
+import { getPostDetail, getPostComments, likePost, unlikePost, addCommentToPost, collectPost } from './api'; // 引入你的 API 函数
 import './PostDetailPage.css';
-import axios from 'axios';
-
-const API_BASE = process.env.REACT_APP_API_BASE;
-
-const PostHeader = ({ post }) => {
-    const anonymousAvatar = '/assets/img/anonymous.jpg';
-    return (
-        <div className="post-header">
-            <div className="author-info">
-                <img className="avatar" src={post.isAnonymous? anonymousAvatar : post.userProfile.avatar_url} alt="头像" />
-                <span className="author-name">{post.isAnonymous? '某同学' : post.userProfile.nickname}</span>
-            </div>
-            <h1 className="post-title">{post.title}</h1>
-        </div>
-    );
-};
-
-const PostContent = ({ content }) => {
-    return (
-        <div className="post-content" dangerouslySetInnerHTML={{ __html: content }} />
-    );
-};
-
-const PostActions = ({ post, onLike, onFavorite }) => {
-    return (
-        <div className="post-actions">
-            <div className="action-item" onClick={onLike}>
-                <i className={post.liked? 'liked' : 'unliked'} />
-                <span>{post.likeCount || 0}</span>
-            </div>
-            <div className="action-item" onClick={onFavorite}>
-                <i className={post.favorited? 'favorited' : 'unfavorited'} />
-                <span>{post.favorites || 0}</span>
-            </div>
-        </div>
-    );
-};
-
-const CommentInput = ({ onSubmitComment, isFlag }) => {
-    const [content, setContent] = useState('');
-
-    useEffect(() => {
-        if (isFlag) {
-            setContent('');
-        }
-    }, [isFlag]);
-
-    const handleSubmit = () => {
-        if (content) {
-            onSubmitComment(content);
-        }
-    };
-
-    return (
-        <div className="comment-input">
-            <textarea
-                value={content}
-                onChange={(e) => setContent(e.target.value)}
-                placeholder="写下你的评论..."
-                className="comment-textarea"
-            />
-            <div className="button-container">
-                <button
-                    type="button"
-                    onClick={handleSubmit}
-                    disabled={!content}
-                    className="submit-button"
-                >
-                    发布评论
-                </button>
-            </div>
-        </div>
-    );
-};
-
-const CommentItem = ({ comment, onLikeComment, onReplyComment }) => {
-    const [showReplyInput, setShowReplyInput] = useState(false);
-    const [replyContent, setReplyContent] = useState('');
-
-    const queryUserInfo = async (id) => {
-        if (!id) {
-            return;
-        }
-        try {
-            const userData = await getUserInfo(id);
-            console.log(userData);
-            // 这里可以添加跳转逻辑等,比如根据用户ID跳转到对应个人信息页面
-        } catch (error) {
-            console.error('获取用户信息失败:', error);
-        }
-    };
-
-    const handleLike = () => {
-        onLikeComment(comment);
-    };
-
-    const handleReply = () => {
-        setShowReplyInput(!showReplyInput);
-    };
-
-    const handleSubmitReply = () => {
-        if (replyContent) {
-            onReplyComment(comment, replyContent);
-            setReplyContent('');
-            setShowReplyInput(false);
-        }
-    };
-
-    return (
-        <div className="comment-item">
-            <img className="avatar" src={comment.author.avatar_url} alt="头像" onClick={() => queryUserInfo(comment.author.userId)} />
-            <div className="comment-content">
-                <div className="comment-author">{comment.author.nickname}</div>
-                <div className="comment-text">{comment.content}</div>
-                <div className="comment-actions">
-                    <div className="action-item" onClick={handleLike}>
-                        <i className={comment.liked? 'liked' : 'unliked'} />
-                        <span>{comment.likeCount || 0}</span>
-                    </div>
-                    <button type="button" onClick={handleReply}>回复</button>
-                </div>
-                {showReplyInput && (
-                    <div className="reply-input">
-                        <textarea
-                            value={replyContent}
-                            onChange={(e) => setReplyContent(e.target.value)}
-                            placeholder="写下你的回复..."
-                            className="reply-textarea"
-                        />
-                        <button
-                            type="button"
-                            onClick={handleSubmitReply}
-                            disabled={!replyContent}
-                            className="submit-button"
-                        >
-                            发布回复
-                        </button>
-                    </div>
-                )}
-                {comment.replies && comment.replies.length > 0 && (
-                    <div className="reply-list">
-                        {comment.replies.map(reply => (
-                            <CommentItem
-                                key={reply.id}
-                                comment={reply}
-                                onLikeComment={onLikeComment}
-                                onReplyComment={onReplyComment}
-                            />
-                        ))}
-                    </div>
-                )}
-            </div>
-        </div>
-    );
-};
-
-const CommentsList = ({ comments, onLikeComment, onReplyComment }) => {
-    return (
-        <div className="comments-list">
-            <h2>评论</h2>
-            {comments.map(comment => (
-                <CommentItem
-                    key={comment.id}
-                    comment={comment}
-                    onLikeComment={onLikeComment}
-                    onReplyComment={onReplyComment}
-                />
-            ))}
-        </div>
-    );
-};
+import { useUser } from '../../../context/UserContext'; // 注意路径
 
 const PostDetailPage = () => {
-    const [post, setPost] = useState(null);
-    const [loading, setLoading] = useState(true);
-    const [errorMsg, setErrorMsg] = useState('');
-    const [comments, setComments] = useState([]);
-    const [isFlag, setIsFlag] = useState(false);
+  const { postId } = useParams(); // 获取帖子ID
+  const [postDetail, setPostDetail] = useState(null);
+  const [comments, setComments] = useState([]);
+  const [loading, setLoading] = useState(true);
+  const [errorMsg, setErrorMsg] = useState('');
+  const [newComment, setNewComment] = useState(''); // 新评论内容
+  const [isAnonymous, setIsAnonymous] = useState(false); // 是否匿名
+  const [isLiked, setIsLiked] = useState(false); // 是否已点赞
+  const [isCollected, setIsCollected] = useState(false); // 是否已收藏
+  const [replyToCommentId, setReplyToCommentId] = useState(null); // 回复的评论ID
 
-    const { params } = useRoute('/forum/post/:postId');
-    const postId = params?.postId;
+  // 获取当前用户ID(假设从上下文中获取)
+  const { user } = useUser(); // 你需要从用户上下文获取用户 ID
 
-    useEffect(() => {
-        const fetchPostDetail = async () => {
-            setLoading(true);
-            setErrorMsg('');
-            try {
-                const postDetail = await getPostDetail(postId);
-                const postComments = await getPostComments(postId);
-                setPost(postDetail);
-                setComments(postComments);
-            } catch (error) {
-                console.error('获取帖子详情失败:', error);
-                setErrorMsg('加载失败,请稍后重试');
-            } finally {
-                setLoading(false);
-            }
-        };
+  useEffect(() => {
+    const fetchPostDetail = async () => {
+      setLoading(true);
+      setErrorMsg('');
+      try {
+        // 获取帖子详情
+        const postData = await getPostDetail(postId);
+        setPostDetail(postData);
 
-        if (postId) {
-            fetchPostDetail();
-        }
-    }, [postId]);
+        // 获取帖子评论
+        const commentsData = await getPostComments(postId);
+        setComments(commentsData);
 
-    const handleLike = async () => {
-        if (!post.liked) {
-            try {
-                await likePost(postId);
-                const newPost = { ...post, liked: true, likeCount: post.likeCount + 1 };
-                setPost(newPost);
-            } catch (err) {
-                console.error('点赞失败:', err);
-            }
+        // 设置是否已经点赞
+        if (postData.likedByUser) {
+          setIsLiked(true);
         } else {
-            try {
-                await unlikePost(postId);
-                const newPost = { ...post, liked: false, likeCount: post.likeCount - 1 };
-                setPost(newPost);
-            } catch (err) {
-                console.error('取消点赞失败:', err);
-            }
+          setIsLiked(false);
         }
-    };
 
-    const handleFavorite = () => {
-        const newPost = { ...post, favorited: !post.favorited, favorites: post.favorited? post.favorites - 1 : post.favorites + 1 };
-        setPost(newPost);
-        if (newPost.favorited) {
-            axios.post(`${API_BASE}/echo/forum/posts/${postId}/favorite`).catch(err => {
-                console.error('收藏失败:', err);
-            });
+        // 设置是否已经收藏
+        if (postData.collectedByUser) {
+          setIsCollected(true);
         } else {
-            axios.delete(`${API_BASE}/echo/forum/posts/${postId}/unfavorite`).catch(err => {
-                console.error('取消收藏失败:', err);
-            });
+          setIsCollected(false);
         }
+      } catch (err) {
+        console.error('加载失败:', err);
+        setErrorMsg('加载失败,请稍后重试');
+      } finally {
+        setLoading(false);
+      }
     };
 
-    const likeCommentAction = async (comment) => {
-        if (!comment.liked) {
-            try {
-                await likeComment(comment.id);
-                const newComment = { ...comment, liked: true, likeCount: comment.likeCount + 1 };
-                setComments(comments.map(c => c.id === comment.id? newComment : c));
-            } catch (err) {
-                console.error('点赞评论失败:', err);
-            }
-        } else {
-            try {
-                await unlikeComment(comment.id);
-                const newComment = { ...comment, liked: false, likeCount: comment.likeCount - 1 };
-                setComments(comments.map(c => c.id === comment.id? newComment : c));
-            } catch (err) {
-                console.error('取消点赞评论失败:', err);
-            }
-        }
-    };
+    fetchPostDetail();
+  }, [postId]);
 
-    const replyCommentAction = async (comment, replyContent) => {
-        try {
-            await replyToComment(comment.id, replyContent);
-            setIsFlag(true);
-            const commentResponse = await getPostComments(postId);
-            setComments(commentResponse.data);
-        } catch (error) {
-            console.error('回复评论失败:', error);
-        }
-    };
+  // 点赞功能
+  const toggleLike = async () => {
+    if (!user) {
+      alert('请先登录');
+      return;
+    }
 
-    const addCommentAction = async (content) => {
-        try {
-            await addCommentToPost(postId, content);
-            setIsFlag(true);
-            const commentResponse = await getPostComments(postId);
-            setComments(commentResponse.data);
-        } catch (error) {
-            console.error('添加评论失败:', error);
-        }
-    };
+    try {
+      if (isLiked) {
+        // 取消点赞
+        await unlikePost(postId, user.id);
+        setIsLiked(false);
+        setPostDetail((prev) => ({
+          ...prev,
+          postLikeNum: prev.postLikeNum - 1,
+        }));
+      } else {
+        // 点赞
+        await likePost(postId, user.id);
+        setIsLiked(true);
+        setPostDetail((prev) => ({
+          ...prev,
+          postLikeNum: prev.postLikeNum + 1,
+        }));
+      }
+    } catch (err) {
+      console.error('点赞失败:', err);
+      alert('点赞失败,请稍后再试');
+    }
+  };
 
-    if (loading) return <p>加载中...</p>;
-    if (errorMsg) return <p className="error-text">{errorMsg}</p>;
-    if (!post) return <p>没有找到该帖子。</p>;
+  // 收藏功能
+  const toggleCollect = async () => {
+    if (!user) {
+      alert('请先登录');
+      return;
+    }
 
-    return (
-        <div className="post-detail-page">
-            <PostHeader post={post} />
-            <PostContent content={post.content} />
-            <PostActions post={post} onLike={handleLike} onFavorite={handleFavorite} />
-            <CommentInput onSubmitComment={addCommentAction} isFlag={isFlag} />
-            <CommentsList comments={comments} onLikeComment={likeCommentAction} onReplyComment={replyCommentAction} />
+    try {
+      const action = isCollected ? 'cancel' : 'collect';
+      // 调用收藏 API
+      await collectPost(postId, user.id, action);
+      setIsCollected(!isCollected);
+      setPostDetail((prev) => ({
+        ...prev,
+        postCollectNum: isCollected ? prev.postCollectNum - 1 : prev.postCollectNum + 1,
+      }));
+    } catch (err) {
+      console.error('收藏失败:', err);
+      alert('收藏失败,请稍后再试');
+    }
+  };
+
+  // 添加评论
+  const handleAddComment = async () => {
+    if (!newComment.trim()) {
+      alert('评论内容不能为空');
+      return;
+    }
+
+    try {
+      // 调用 API 添加评论,若为回复评论则传递父评论ID(com_comment_id)
+      const commentData = await addCommentToPost(postId, user.id, newComment, isAnonymous, replyToCommentId);
+      // 更新评论列表
+      setComments((prev) => [
+        ...prev,
+        {
+          commentId: commentData.commentId,
+          post_id: postId,
+          userId: user.id,
+          content: newComment,
+          isAnonymous,
+          commentTime: new Date().toISOString(),
+          comCommentId: replyToCommentId, // 回复评论时传递父评论ID
+        },
+      ]);
+      // 清空评论框和回复状态
+      setNewComment('');
+      setReplyToCommentId(null);
+    } catch (err) {
+      console.error('评论添加失败:', err);
+      alert('评论失败,请稍后再试');
+    }
+  };
+
+  // 回复评论
+  const handleReply = (commentId) => {
+    setReplyToCommentId(commentId); // 设置父评论ID为当前评论的ID
+  };
+
+  return (
+    <div className="post-detail-page">
+      {loading ? (
+        <p>加载中...</p>
+      ) : errorMsg ? (
+        <p className="error-text">{errorMsg}</p>
+      ) : postDetail ? (
+        <div className="post-detail">
+          <h1>{postDetail.title}</h1>
+          <div className="post-meta">
+            <span className="post-time">
+              {new Date(postDetail.postTime).toLocaleString()}
+            </span>
+            <span className="post-user">用户 ID: {postDetail.user_id}</span>
+          </div>
+          <div className="post-content">
+            <p>{postDetail.postContent}</p>
+            {postDetail.imgUrl && (
+              <img
+                className="post-image"
+                src={postDetail.imgUrl}
+                alt="帖子图片"
+              />
+            )}
+          </div>
+
+          {/* 点赞和收藏 */}
+          <div className="post-actions">
+            <button
+              className="icon-btn"
+              onClick={toggleLike} // 点赞操作
+            >
+              <GoodTwo
+                theme="outline"
+                size="24"
+                fill={isLiked ? '#f00' : '#ccc'} // 如果已点赞,显示红色
+              />
+              <span>{postDetail.postLikeNum}</span>
+            </button>
+            <button
+              className="icon-btn"
+              onClick={toggleCollect} // 收藏操作
+            >
+              <Star
+                theme="outline"
+                size="24"
+                fill={isCollected ? '#ffd700' : '#ccc'} // 如果已收藏,显示金色
+              />
+              <span>{postDetail.postCollectNum}</span>
+            </button>
+          </div>
+
+          {/* 评论部分 */}
+          <div className="comments-section">
+            <h3>评论区</h3>
+            {comments.length ? (
+              comments.map((comment) => (
+                <div key={comment.commentId} className="comment">
+                  <p>{comment.content}</p>
+                  <div className="comment-meta">
+                    <span className="comment-time">
+                      {new Date(comment.commentTime).toLocaleString()}
+                    </span>
+                    <span className="comment-user">用户 ID: {comment.userId}</span>
+                  </div>
+                  {/* 回复按钮 */}
+                  <button onClick={() => handleReply(comment.commentId)}>回复</button>
+
+                  {/* 回复框,只有在当前评论是正在回复的评论时显示 */}
+                  {replyToCommentId === comment.commentId && (
+                    <div className="reply-form">
+                      <textarea
+                        placeholder="输入你的回复..."
+                        value={newComment}
+                        onChange={(e) => setNewComment(e.target.value)}
+                      />
+                      <div className="comment-options">
+                        <label>
+                          <input
+                            type="checkbox"
+                            checked={isAnonymous}
+                            onChange={() => setIsAnonymous(!isAnonymous)}
+                          />
+                          匿名评论
+                        </label>
+                        <button onClick={handleAddComment}>发布回复</button>
+                      </div>
+                    </div>
+                  )}
+                </div>
+              ))
+            ) : (
+              <p>暂无评论</p>
+            )}
+
+            {/* 添加评论表单 */}
+            <div className="add-comment-form">
+              <textarea
+                placeholder="输入你的评论..."
+                value={newComment}
+                onChange={(e) => setNewComment(e.target.value)}
+              />
+              <div className="comment-options">
+                <label>
+                  <input
+                    type="checkbox"
+                    checked={isAnonymous}
+                    onChange={() => setIsAnonymous(!isAnonymous)}
+                  />
+                  匿名评论
+                </label>
+                <button onClick={handleAddComment}>发布评论</button>
+              </div>
+            </div>
+          </div>
         </div>
-    );
+      ) : (
+        <p>帖子不存在</p>
+      )}
+    </div>
+  );
 };
 
-export default PostDetailPage;
\ No newline at end of file
+export default PostDetailPage;
diff --git a/src/pages/Forum/posts-detail/api.js b/src/pages/Forum/posts-detail/api.js
index 924cba9..d05f148 100644
--- a/src/pages/Forum/posts-detail/api.js
+++ b/src/pages/Forum/posts-detail/api.js
@@ -15,9 +15,15 @@
 };
 
 // 点赞帖子
-export const likePost = async (postId) => {
-    const response = await axios.post(`${API_BASE}/echo/forum/posts/${postId}/like`);
-    return response.data;
+export const likePost = async (postId, userId) => {
+    try {
+        const response = await axios.post(`${API_BASE}/echo/forum/posts/${postId}/like`, {
+            user_id: userId,  // 用户 ID
+        });
+        return response.data;
+    } catch (error) {
+        return handleApiError(error);
+    }
 };
 
 // 取消点赞帖子
@@ -27,15 +33,18 @@
 };
 
 // 添加评论
-export const addCommentToPost = async (postId, content) => {
-    const response = await axios.post(`${API_BASE}/echo/forum/posts/${postId}/comments`, { content });
-    return response.data;
-};
-
-// 回复评论
-export const replyToComment = async (commentId, replyContent) => {
-    const response = await axios.post(`${API_BASE}/echo/forum/comments/${commentId}/reply`, { content: replyContent });
-    return response.data;
+export const addCommentToPost = async (postId, userId, content, isAnonymous, comCommentId = null) => {
+    try {
+        const response = await axios.post(`${API_BASE}/echo/forum/posts/${postId}/comments`, {
+            content,
+            user_id: userId,
+            is_anonymous: isAnonymous,
+            com_comment_id: comCommentId, // 如果是回复评论,传递 com_comment_id
+        });
+        return response.data;
+    } catch (error) {
+        return handleApiError(error);
+    }
 };
 
 // 点赞评论
@@ -50,8 +59,41 @@
     return response.data;
 };
 
+// 收藏帖子
+export const collectPost = async (postId, userId, action) => {
+    try {
+        const response = await axios.post(`${API_BASE}/echo/forum/posts/${postId}/collect`, {
+            user_id: userId,
+            action: action,  // "collect" 或 "cancel"
+        });
+        return response.data;
+    } catch (error) {
+        return handleApiError(error);
+    }
+};
+
 // 获取用户信息
 export const getUserInfo = async (userId) => {
     const response = await axios.get(`${API_BASE}/user/${userId}/info`);
     return response.data;
-};
\ No newline at end of file
+};
+
+// 错误处理
+const handleApiError = (error) => {
+    if (error.response) {
+        return {
+            success: false,
+            message: error.response.data.error || '请求失败',
+        };
+    } else if (error.request) {
+        return {
+            success: false,
+            message: '请求未得到响应,请稍后重试',
+        };
+    } else {
+        return {
+            success: false,
+            message: error.message || '发生了未知错误',
+        };
+    }
+};
diff --git a/src/pages/Forum/posts-main/ForumPage.jsx b/src/pages/Forum/posts-main/ForumPage.jsx
index 5c7d622..1452782 100644
--- a/src/pages/Forum/posts-main/ForumPage.jsx
+++ b/src/pages/Forum/posts-main/ForumPage.jsx
@@ -1,151 +1,3 @@
-// import React, { useState, useEffect } from 'react';
-// import { Link } from 'wouter';
-// import axios from 'axios';
-// import { GoodTwo, Comment } from '@icon-park/react';
-// import Header from '../../components/Header'; 
-// import './ForumPage.css';
-
-// const API_BASE = process.env.REACT_APP_API_BASE;
-
-// const ForumPage = () => {
-//   const [posts, setPosts] = useState([]);
-//   const [total, setTotal] = useState(0);
-//   const [page, setPage] = useState(1);
-//   const [size, setSize] = useState(10);
-//   const [loading, setLoading] = useState(true);
-//   const [errorMsg, setErrorMsg] = useState('');
-
-//   const totalPages = Math.ceil(total / size);
-
-//   useEffect(() => {
-//     const fetchPosts = async () => {
-//       setLoading(true);
-//       setErrorMsg('');
-//       try {
-//         const response = await axios.get(`${API_BASE}/echo/forum/posts/getAllPost`, {
-//           params: { page, size }
-//         });
-//         const postsData = response.data.posts || [];
-
-//         const userIds = [...new Set(postsData.map(post => post.user_id))];
-//         const userProfiles = await Promise.all(
-//           userIds.map(async id => {
-//             try {
-//               const res = await axios.get(`${API_BASE}/echo/user/profile`, {
-//                 params: { user_id: id }
-//               });
-//               return { id, profile: res.data };
-//             } catch {
-//               return { id, profile: { nickname: '未知用户', avatar_url: 'default-avatar.png' } };
-//             }
-//           })
-//         );
-
-//         const userMap = {};
-//         userProfiles.forEach(({ id, profile }) => {
-//           userMap[id] = profile;
-//         });
-
-//         const postsWithProfiles = postsData.map(post => ({
-//           ...post,
-//           userProfile: userMap[post.user_id] || { nickname: '未知用户', avatar_url: 'default-avatar.png' }
-//         }));
-
-//         setPosts(postsWithProfiles);
-//         setTotal(response.data.total || 0);
-//       } catch (error) {
-//         console.error('获取帖子失败:', error);
-//         setErrorMsg('加载失败,请稍后重试');
-//       } finally {
-//         setLoading(false);
-//       }
-//     };
-//     fetchPosts();
-//   }, [page, size]);
-
-//   const toggleLike = async (postId, liked) => {
-//     try {
-//       if (liked) {
-//         await axios.delete(`${API_BASE}/echo/forum/posts/${postId}/unlike`);
-//       } else {
-//         await axios.post(`${API_BASE}/echo/forum/posts/${postId}/like`);
-//       }
-
-//       setPosts(prevPosts =>
-//         prevPosts.map(post =>
-//           post.id === postId
-//             ? {
-//                 ...post,
-//                 liked: !liked,
-//                 likeCount: liked ? post.likeCount - 1 : post.likeCount + 1
-//               }
-//             : post
-//         )
-//       );
-//     } catch (error) {
-//       console.error('点赞操作失败:', error);
-//     }
-//   };
-
-//   return (
-//     <div className="forum-page">
-//       <Header /> {/* 使用 Header 组件 */}
-//       <div className="forum-content">
-//         <h2>论坛帖子列表</h2>
-
-//         {loading ? (
-//           <p>加载中...</p>
-//         ) : errorMsg ? (
-//           <p className="error-text">{errorMsg}</p>
-//         ) : posts.length === 0 ? (
-//           <p>暂无帖子。</p>
-//         ) : (
-//           <div className="post-list">
-//             {posts.map(post => (
-//               <div key={post.id} className="post-card">
-//                 <div className="post-card-top">
-//                   <div className="user-info">
-//                     <img className="avatar" src={post.userProfile.avatar_url} alt="头像" />
-//                     <span className="nickname">{post.userProfile.nickname}</span>
-//                   </div>
-//                   {post.cover_image_url && (
-//                     <img className="cover-image" src={post.cover_image_url} alt="封面" />
-//                   )}
-//                 </div>
-//                 <h3>{post.title}</h3>
-//                 <p className="post-meta">
-//                   发布时间:{new Date(post.created_at).toLocaleString()}
-//                 </p>
-//                 <div className="post-actions">
-//                   <button
-//                     className="icon-btn"
-//                     onClick={() => toggleLike(post.id, post.liked)}
-//                   >
-//                     <GoodTwo theme="outline" size="24" fill={post.liked ? '#f00' : '#fff'} />
-//                     <span>{post.likeCount || 0}</span>
-//                   </button>
-//                   <Link href={`/forum/post/${post.id}`} className="icon-btn">
-//                     <Comment theme="outline" size="24" fill="#fff" />
-//                     <span>{post.commentCount || 0}</span>
-//                   </Link>
-//                 </div>
-//                 <Link href={`/forum/post/${post.id}`} className="btn-secondary">查看详情</Link>
-//               </div>
-//             ))}
-//           </div>
-//         )}
-
-//         <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>
-//     </div>
-//   );
-// };
-
-// export default ForumPage;
 
 import React, { useState } from 'react';
 import Header from '../../../components/Header';
diff --git a/src/pages/Forum/posts-main/components/PostList.jsx b/src/pages/Forum/posts-main/components/PostList.jsx
index fa33dd5..7ad0a86 100644
--- a/src/pages/Forum/posts-main/components/PostList.jsx
+++ b/src/pages/Forum/posts-main/components/PostList.jsx
@@ -1,7 +1,8 @@
 import React, { useEffect, useState } from 'react';
 import axios from 'axios';
 import { Link } from 'wouter';
-import { GoodTwo, Comment } from '@icon-park/react';
+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;
@@ -13,7 +14,7 @@
   const [loading, setLoading] = useState(true);
   const [errorMsg, setErrorMsg] = useState('');
 
-  const size = 10;
+  const size = 10;  // 每页条数
   const totalPages = Math.ceil(total / size);
 
   useEffect(() => {
@@ -21,13 +22,19 @@
       setLoading(true);
       setErrorMsg('');
       try {
-        const res = await axios.get(`${API_BASE}/echo/forum/posts/getAllPost`, {
-          params: { page, size }
+        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`, {
@@ -42,6 +49,7 @@
         const userMap = {};
         profiles.forEach(({ id, profile }) => { userMap[id] = profile; });
 
+        // 更新帖子数据
         const postsWithProfiles = postsData
           .filter(post => post.title.includes(search))
           .map(post => ({
@@ -62,10 +70,14 @@
     fetchPosts();
   }, [page, search]);
 
-  const toggleLike = async (postId, liked) => {
+  // 点赞/取消点赞操作
+  const toggleLike = async (postId, liked, userId) => {
     try {
-      if (liked) await axios.delete(`${API_BASE}/echo/forum/posts/${postId}/unlike`);
-      else await axios.post(`${API_BASE}/echo/forum/posts/${postId}/like`);
+      if (liked) {
+        await unlikePost(postId);  // 取消点赞
+      } else {
+        await likePost(postId, userId);  // 点赞
+      }
 
       setPosts(posts =>
         posts.map(post =>
@@ -79,6 +91,24 @@
     }
   };
 
+  // 收藏/取消收藏操作
+  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> :
@@ -97,13 +127,21 @@
                 </div>
                 <h3>{post.title}</h3>
                 <p className="post-meta">
-                  发布时间:{new Date(post.created_at).toLocaleString()}
+                  发布时间:{new Date(post.createdAt).toLocaleString()}
                 </p>
                 <div className="post-actions">
-                  <button className="icon-btn" onClick={() => toggleLike(post.id, post.liked)}>
+                  {/* 点赞按钮 */}
+                  <button className="icon-btn" onClick={() => 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={() => 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">
                     <Comment theme="outline" size="24" fill="#fff" />
                     <span>{post.commentCount}</span>