修复帖子点赞和收藏功能

Change-Id: If66f9065607d97fb9527f0905b3465e6cd5b5995
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;