fix-img

Change-Id: Ida77fc6aed06b28e41e2abcb6ae09d5f63d016f2
diff --git a/src/pages/Forum/posts-detail/PostDetailPage.jsx b/src/pages/Forum/posts-detail/PostDetailPage.jsx
index 159bdfa..f703fd6 100644
--- a/src/pages/Forum/posts-detail/PostDetailPage.jsx
+++ b/src/pages/Forum/posts-detail/PostDetailPage.jsx
@@ -1,200 +1,171 @@
-import React, { useContext, useEffect, useState } from 'react';
+import React, { useContext, useEffect, useState } from 'react'; 
 import { useParams } from 'wouter';
 import { GoodTwo, Star } from '@icon-park/react';
-import { getPostDetail, getPostComments, likePost, unlikePost, addCommentToPost, collectPost, uncollectPost } from './api'; // 引入你的 API 函数
+import { getPostDetail, getPostComments, likePost, unlikePost, addCommentToPost, collectPost } from './api'; // 你的 API 函数
 import './PostDetailPage.css';
-import { UserContext, useUser } from '../../../context/UserContext'; // 注意路径
+import { UserContext } from '../../../context/UserContext'; // 用户上下文
 import Header from '../../../components/Header';
 
+const formatImageUrl = (url) => {
+  if (!url) return '';
+
+  if (url.startsWith('http')) return url;
+
+  // 如果是 /images/... ,替换成 /uploads/post/...
+  if (url.startsWith('/images/')) {
+    // 这里把 /images/ 替换成 /uploads/post/
+    return `http://localhost:8080/uploads/post/${url.slice('/images/'.length)}`;
+  }
+
+  // 其它情况默认直接拼接,不加斜杠
+  return `http://localhost:8080${url.startsWith('/') ? '' : '/'}${url}`;
+};
+
+
+// 头像地址格式化,处理 avatarUrl 字段
+export function formatAvatarUrlNoDefault(avatarUrl) {
+  if (!avatarUrl) return '';
+  if (avatarUrl.startsWith('http')) return avatarUrl;
+  return `http://localhost:8080${avatarUrl}`;
+}
+
 const PostDetailPage = () => {
-  const { postId } = useParams(); // 获取帖子ID
+  const { postId } = useParams();
+  const { user } = useContext(UserContext);
+
   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 [newComment, setNewComment] = useState('');
+  const [isLiked, setIsLiked] = useState(false);
+  const [isCollected, setIsCollected] = useState(false);
+  const [replyToCommentId, setReplyToCommentId] = useState(null);
   const [replyToUsername, setReplyToUsername] = useState(null);
 
-  // 获取当前用户ID(假设从上下文中获取)
-  const { user } = useContext(UserContext);
-  // const { user } = useUser(); // 你需要从用户上下文获取用户 ID
-
   useEffect(() => {
-    const fetchPostDetail = async () => {
+    const fetchData = async () => {
       setLoading(true);
       setErrorMsg('');
       try {
-        // 获取帖子详情
         const postData = await getPostDetail(postId);
         setPostDetail(postData);
-
-        // 获取帖子评论
         const commentsData = await getPostComments(postId);
         setComments(commentsData);
 
-        // 设置是否已经点赞
-        if (postData.likedByUser) {
-          setIsLiked(true);
-        } else {
-          setIsLiked(false);
-        }
-
-        // 设置是否已经收藏
-        if (postData.collectedByUser) {
-          setIsCollected(true);
-        } else {
-          setIsCollected(false);
-        }
+        setIsLiked(!!postData.likedByUser);
+        setIsCollected(!!postData.collectedByUser);
       } catch (err) {
-        console.error('加载失败:', err);
+        console.error(err);
         setErrorMsg('加载失败,请稍后重试');
       } finally {
         setLoading(false);
       }
     };
-
-    fetchPostDetail();
+    fetchData();
   }, [postId]);
 
-  // 点赞功能
+  // 点赞
   const toggleLike = async () => {
-    if (!user) {
-      alert('请先登录');
-      return;
-    }
-
+    if (!user) return alert('请先登录');
     try {
       if (isLiked) {
-        // 取消点赞
         await unlikePost(postId, user.userId);
         setIsLiked(false);
-        setPostDetail((prev) => ({
+        setPostDetail(prev => ({
           ...prev,
           postLikeNum: prev.postLikeNum - 1,
         }));
       } else {
-        // 点赞
         await likePost(postId, user.userId);
         setIsLiked(true);
-        setPostDetail((prev) => ({
+        setPostDetail(prev => ({
           ...prev,
           postLikeNum: prev.postLikeNum + 1,
         }));
       }
-    } catch (err) {
-      console.error('点赞失败:', err);
+    } catch {
       alert('点赞失败,请稍后再试');
     }
   };
 
-// 收藏功能
-const toggleCollect = async () => {
-    if (!user) {
-        alert('请先登录');
-        return;
+  // 收藏
+  const toggleCollect = async () => {
+    if (!user) return alert('请先登录');
+    try {
+      if (isCollected) {
+        await collectPost(postId, user.userId, 'cancel');
+        setIsCollected(false);
+        setPostDetail(prev => ({
+          ...prev,
+          postCollectNum: prev.postCollectNum - 1,
+        }));
+      } else {
+        await collectPost(postId, user.userId, 'collect');
+        setIsCollected(true);
+        setPostDetail(prev => ({
+          ...prev,
+          postCollectNum: prev.postCollectNum + 1,
+        }));
+      }
+    } catch {
+      alert('收藏失败,请稍后再试');
     }
+  };
+
+  // 添加评论
+  const handleAddComment = async () => {
+    if (!user || !user.userId) return alert('请先登录后再评论');
+    if (!newComment.trim()) return alert('评论内容不能为空');
 
     try {
-        if (isCollected) {
-            // 取消收藏 - 使用原有的collectPost函数,传递action: "cancel"
-            await collectPost(postId, user.userId, "cancel");
-            setIsCollected(false);
-            setPostDetail((prev) => ({
-                ...prev,
-                postCollectNum: prev.postCollectNum - 1,
-            }));
-        } else {
-            // 收藏
-            await collectPost(postId, user.userId, "collect");
-            setIsCollected(true);
-            setPostDetail((prev) => ({
-                ...prev,
-                postCollectNum: prev.postCollectNum + 1,
-            }));
-        }
-    } catch (err) {
-        console.error('收藏操作失败:', err);
-        alert('收藏操作失败,请稍后再试');
+      const commentPayload = {
+        content: newComment,
+        userId: user.userId,
+        isAnonymous: false,
+        com_comment_id: replyToCommentId || null,
+      };
+      const commentData = await addCommentToPost(postId, commentPayload);
+
+      const newCommentItem = {
+        commentId: commentData?.commentId || Date.now(),
+        post_id: postId,
+        userId: user.userId,
+        username: user.username || '匿名',
+        content: newComment,
+        commentTime: new Date().toISOString(),
+        comCommentId: replyToCommentId,
+        userAvatar: user.avatar_url || '',
+      };
+
+      setComments(prev => [newCommentItem, ...prev]);
+      setNewComment('');
+      setReplyToCommentId(null);
+      setReplyToUsername(null);
+    } catch (error) {
+      alert(error.response?.data?.message || '评论失败,请稍后再试');
     }
-};
+  };
 
-// 添加评论
-const handleAddComment = async () => {
-  // 直接使用组件顶层获取的 user
-  if (!user || !user.userId) {
-    alert('请先登录后再评论');
-    return;
-  }
-
-  if (!newComment.trim()) {
-    alert('评论内容不能为空');
-    return;
-  }
-
-  try {
-    // 构建评论数据
-    const commentPayload = {
-      content: newComment,
-      userId: user.userId, // 使用已获取的用户ID
-      isAnonymous: false,
-      com_comment_id: replyToCommentId || null,
-    };
-
-    // 发送评论请求
-    const commentData = await addCommentToPost(postId, commentPayload);
-
-    // 更新评论列表
-    const newCommentItem = {
-      commentId: commentData?.commentId || Date.now(),
-      post_id: postId,
-      userId: user.userId,
-      content: newComment,
-      commentTime: new Date().toISOString(),
-      comCommentId: replyToCommentId,
-    };
-
-    setComments((prevComments) => [newCommentItem, ...prevComments]);
-
-    // 重置表单
-    setNewComment('');
-    setReplyToCommentId(null);
-
-    // alert('评论成功!');
-  } catch (error) {
-    console.error('评论失败:', error);
-    
-    const errorMessage = 
-      error.response?.data?.message || 
-      error.message || 
-      '评论失败,请稍后再试';
-      
-    alert(errorMessage);
-  }
-};
-
-
-
-  // 回复评论
+  // 回复按钮点击
   const handleReply = (commentId) => {
-  setReplyToCommentId(commentId);
-  const comment = comments.find(c => c.commentId === commentId);
-  if (comment) {
-    // 这里用用户名或者用户ID
-    setReplyToUsername(comment.username || comment.userId);
-  } else {
-    setReplyToUsername(null);
-  }
-};
+    setReplyToCommentId(commentId);
+    const comment = comments.find(c => c.commentId === commentId);
+    setReplyToUsername(comment?.username || comment?.userId || '未知用户');
+  };
 
-const findUsernameByCommentId = (id) => {
-  const comment = comments.find(c => c.commentId === id);
-  return comment ? (comment.username || comment.userId) : '未知用户';
-};
+  // 查找回复的用户名
+  const findUsernameByCommentId = (id) => {
+    const comment = comments.find(c => c.commentId === id);
+    return comment ? (comment.username || comment.userId || '未知用户') : '未知用户';
+  };
 
+  // 帖子图片处理,imgUrl 是单字符串,包装成数组
+  const getPostImages = () => {
+    if (!postDetail) return [];
+    if (postDetail.imgUrl) return [formatImageUrl(postDetail.imgUrl)];
+    return [];
+  };
 
   return (
     <div className="post-detail-page">
@@ -207,122 +178,116 @@
         <div className="post-detail">
           <h1>{postDetail.title}</h1>
           <div className="post-meta">
-            <span className="post-user">用户ID: {postDetail.user_id}</span>
+            <div className="post-user-info">
+              {postDetail.avatarUrl ? (
+                <img
+                  className="avatar"
+                  src={formatAvatarUrlNoDefault(postDetail.avatarUrl)}
+                  alt={postDetail.username || '用户头像'}
+                />
+              ) : null}
+              <span className="post-username">{postDetail.username || '匿名用户'}</span>
+            </div>
             <span className="post-time">
-            发布时间:{new Date(postDetail.postTime).toLocaleString()}
+              发布时间:{new Date(postDetail.postTime).toLocaleString()}
             </span>
           </div>
+
           <div className="post-content">
             <p>{postDetail.postContent}</p>
-            {Array.isArray(postDetail.imgUrl) ? (
-              <div className="post-images">
-                {postDetail.imgUrl.map((url, idx) => (
-                  <img key={idx} src={url} alt={`图片${idx}`} />
-                ))}
-              </div>
-            ) : (
-              postDetail.imgUrl && (
-                <img className="post-image" src={postDetail.imgUrl} alt="帖子图片" />
-              )
-            )}
-
+            <div className="post-images">
+              {getPostImages().map((url, idx) => (
+                <img key={idx} src={url} alt={`图片${idx + 1}`} />
+              ))}
+            </div>
           </div>
 
-          {/* 点赞和收藏 */}
           <div className="post-actions">
-            <button
-              className="icon-btn"
-              onClick={toggleLike} // 点赞操作
-            >
-              <GoodTwo
-                theme="outline"
-                size="20"
-                fill={isLiked ? '#f00' : '#ccc'} // 如果已点赞,显示红色
-              />
+            <button className="icon-btn" onClick={toggleLike} title="点赞">
+              <GoodTwo theme="outline" size="20" fill={isLiked ? '#f00' : '#ccc'} />
               <span>{postDetail.postLikeNum}</span>
             </button>
-            <button
-              className="icon-btn"
-              onClick={toggleCollect} // 收藏操作
-            >
-              <Star
-                theme="outline"
-                size="20"
-                fill={isCollected ? '#ffd700' : '#ccc'} // 如果已收藏,显示金色
-              />
+            <button className="icon-btn" onClick={toggleCollect} title="收藏">
+              <Star theme="outline" size="20" fill={isCollected ? '#ffd700' : '#ccc'} />
               <span>{postDetail.postCollectNum}</span>
             </button>
           </div>
-          
+
           <hr className="divider" />
-          {/* 评论部分 */}
+
           <h3>评论区</h3>
-          <div className="comments-section">      
-            {comments.length ? (
-              comments.map((comment) => (
-                <div key={comment.commentId} className="comment">
-                  <div className="comment-header">
-                    <span className="comment-user">用户 ID: {comment.userId}</span>
-                    <button className="reply-btn" onClick={() => handleReply(comment.commentId)}>回复</button>
-                  </div>
-
-                  <p className="comment-content">
-                    {comment.comCommentId ? (
-                      <>
-                        <span className="reply-to">回复 {findUsernameByCommentId(comment.comCommentId)}:</span>
-                        {comment.content}
-                      </>
-                    ) : (
-                      comment.content
-                    )}
-                  </p>
-
-                  <div className="comment-time">
-                    {new Date(comment.commentTime).toLocaleString()}
-                  </div>
-
-                  {/* 回复框 */}
-                  {replyToCommentId === comment.commentId && (
-                    <div className="reply-form">
-                      <div className="replying-to">
-                        回复 <strong>{replyToUsername}</strong>:
-                      </div>
-                      <textarea
-                        placeholder="输入你的回复..."
-                        value={newComment}
-                        onChange={(e) => setNewComment(e.target.value)}
+          <div className="comments-section">
+            {comments.length ? comments.map(comment => (
+              <div key={comment.commentId} className="comment">
+                <div className="comment-header">
+                  <div className="comment-user-info">
+                    {comment.userAvatar ? (
+                      <img
+                        className="avatar-small"
+                        src={formatAvatarUrlNoDefault(comment.userAvatar)}
+                        alt={comment.username || '用户头像'}
                       />
-                      <div className="comment-options">
-                        <button onClick={handleAddComment}>发布回复</button>
-                      </div>
-                    </div>
-                  )}
+                    ) : null}
+                    <span className="comment-username">{comment.username || '匿名用户'}</span>
+                  </div>
+                  <button className="reply-btn" onClick={() => handleReply(comment.commentId)}>回复</button>
                 </div>
-              ))
-            ) : (
-              <p>暂无评论</p>
-            )}
 
+                <p className="comment-content">
+                  {comment.comCommentId ? (
+                    <>
+                      <span className="reply-to">回复 {findUsernameByCommentId(comment.comCommentId)}:</span>
+                      {comment.content}
+                    </>
+                  ) : (
+                    comment.content
+                  )}
+                </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 className="comment-time">
+                  {new Date(comment.commentTime).toLocaleString()}
+                </div>
+
+                {replyToCommentId === comment.commentId && (
+                  <div className="reply-form">
+                    <div className="replying-to">
+                      回复 <strong>{replyToUsername}</strong>:
+                    </div>
+                    <textarea
+                      placeholder="输入你的回复..."
+                      value={newComment}
+                      onChange={(e) => setNewComment(e.target.value)}
+                    />
+                    <div className="comment-options">
+                      <button onClick={handleAddComment}>发布回复</button>
+                      <button
+                        onClick={() => {
+                          setReplyToCommentId(null);
+                          setReplyToUsername(null);
+                          setNewComment('');
+                        }}
+                        style={{ marginLeft: '8px' }}
+                      >
+                        取消
+                      </button>
+                    </div>
+                  </div>
+                )}
               </div>
-            </div>
+            )) : <p>暂无评论</p>}
+
+            {!replyToCommentId && (
+              <div className="add-comment-form">
+                <textarea
+                  placeholder="输入你的评论..."
+                  value={newComment}
+                  onChange={(e) => setNewComment(e.target.value)}
+                />
+                <div className="comment-options">
+                  <button onClick={handleAddComment}>发布评论</button>
+                </div>
+              </div>
+            )}
           </div>
         </div>
       ) : (
@@ -332,4 +297,4 @@
   );
 };
 
-export default PostDetailPage;
\ No newline at end of file
+export default PostDetailPage;