fix-img

Change-Id: Ida77fc6aed06b28e41e2abcb6ae09d5f63d016f2
diff --git a/src/pages/Forum/posts-main/components/CreatePostButton.jsx b/src/pages/Forum/posts-main/components/CreatePostButton.jsx
index 0f23e82..e324056 100644
--- a/src/pages/Forum/posts-main/components/CreatePostButton.jsx
+++ b/src/pages/Forum/posts-main/components/CreatePostButton.jsx
@@ -2,20 +2,18 @@
 import axios from 'axios';
 import { Edit } from '@icon-park/react';
 import './CreatePostButton.css';
-
-const user = JSON.parse(localStorage.getItem('user')); // user = { user_id: 123, ... }
-const userId = user?.user_id;
-
+import { useUser } from '../../../../context/UserContext';
 
 const CreatePostButton = () => {
-  const [showModal, setShowModal] = useState(false);
+  const { user } = useUser();
+  const userId = user?.userId;  // 这里改为 userId,跟 UserContext 统一
 
+  const [showModal, setShowModal] = useState(false);
   const [title, setTitle] = useState('');
   const [content, setContent] = useState('');
   const [previewUrls, setPreviewUrls] = useState([]);
   const [files, setFiles] = useState([]);
 
-  // 选择图片并预览
   const handleImageChange = (e) => {
     const selectedFiles = Array.from(e.target.files);
     if (!selectedFiles.length) return;
@@ -24,6 +22,10 @@
   };
 
   const handleSubmit = async () => {
+    if (!userId) {
+      alert('用户未登录或用户ID未获取到,无法发帖');
+      return;
+    }
     if (!title.trim() || !content.trim()) {
       alert('标题和内容均为必填项');
       return;
@@ -34,7 +36,7 @@
     formData.append('postContent', content.trim());
 
     files.forEach(file => {
-      formData.append('imageUrl', file); // 多文件使用同一个字段名
+      formData.append('imageUrl', file);
     });
 
     try {
@@ -46,7 +48,6 @@
         }
       );
 
-      // 清空表单
       setTitle('');
       setContent('');
       setFiles([]);
@@ -119,4 +120,3 @@
 };
 
 export default CreatePostButton;
-
diff --git a/src/pages/Forum/posts-main/components/PostList.jsx b/src/pages/Forum/posts-main/components/PostList.jsx
index 9e088ea..c1d9b7b 100644
--- a/src/pages/Forum/posts-main/components/PostList.jsx
+++ b/src/pages/Forum/posts-main/components/PostList.jsx
@@ -3,8 +3,16 @@
 import { Link } from 'wouter';
 import { GoodTwo, Star, Delete } from '@icon-park/react';
 import { likePost } from '../../posts-detail/api';
+import { formatAvatarUrl } from '../../../../components/utils/avatar';
 import './PostList.css';
 
+// 修改后的封面图 URL 拼接函数
+const formatImageUrl = (url) => {
+  if (!url) return '';
+  const filename = url.split('/').pop(); // 提取文件名部分
+  return `http://localhost:8080/uploads/post/${filename}`;
+};
+
 const PostList = ({ search }) => {
   const [posts, setPosts] = useState([]);
   const [page, setPage] = useState(1);
@@ -21,49 +29,26 @@
       setErrorMsg('');
       try {
         const res = await axios.get(`/echo/forum/posts/getAllPosts`, {
-          params: {
-            page,
-            pageSize: size,
-            sortBy: 'createdAt',
-            order: 'desc'
-          }
+          params: { page, pageSize: size, sortBy: 'createdAt', order: 'desc' }
         });
 
-        // 检查响应结构是否符合预期
-        if (!res.data || !Array.isArray(res.data.posts)) {
-          throw new Error('API返回格式不正确');
-        }
+        if (!res.data || !Array.isArray(res.data.posts)) throw new Error('API返回格式不正确');
 
-        const postsData = res.data.posts || [];
+        const postsData = res.data.posts;
 
-        const userIds = [...new Set(postsData.map(post => post.user_id))];
+        const filteredPosts = postsData.filter(post =>
+          post.title?.toLowerCase().includes(search.toLowerCase())
+        );
 
-        const profiles = await Promise.all(userIds.map(async id => {
-          try {
-            const r = await axios.get(`/echo/user/profile`, {
-              params: { user_id: id }
-            });
-            return { id, profile: r.data };
-          } catch (e) {
-            return { id, profile: { nickname: '未知用户', avatar_url: 'default-avatar.png' } };
-          }
+        const postsWithProfiles = filteredPosts.map(post => ({
+          ...post,
+          username: post.username || '未知用户',
+          avatarUrl: formatAvatarUrl(post.avatarUrl || ''),
+          liked: false,
+          collected: false,
+          commentCount: 0
         }));
 
-        const userMap = {};
-        profiles.forEach(({ id, profile }) => {
-          userMap[id] = profile;
-        });
-
-        const postsWithProfiles = postsData
-          .filter(post => post.title.toLowerCase().includes(search.toLowerCase()))
-          .map(post => ({
-            ...post,
-            userProfile: userMap[post.user_id] || { nickname: '未知用户', avatar_url: 'default-avatar.png' },
-            liked: false,
-            collected: false,
-            commentCount: 0
-          }));
-
         setPosts(postsWithProfiles);
         setTotal(res.data.total || 0);
       } catch (err) {
@@ -78,77 +63,65 @@
   }, [page, search]);
 
   const toggleLike = async (postNo, liked, userId) => {
-  try {
-    if (liked) {
-      // 修改为 POST 请求,并带上 user_id 参数
-      await axios.post(`/echo/forum/posts/${postNo}/unlike`, {
-        user_id: userId
-      });
-    } else {
-      await likePost(postNo, userId); // 你已有的点赞逻辑
+    try {
+      if (liked) {
+        await axios.post(`/echo/forum/posts/${postNo}/unlike`, { user_id: userId });
+      } else {
+        await likePost(postNo, userId);
+      }
+
+      setPosts(posts =>
+        posts.map(post =>
+          post.postNo === postNo
+            ? {
+                ...post,
+                liked: !liked,
+                likeCount: liked ? post.likeCount - 1 : post.likeCount + 1
+              }
+            : post
+        )
+      );
+    } catch (err) {
+      console.error('点赞失败:', err);
+      alert('点赞操作失败,请稍后重试');
     }
+  };
 
-    setPosts(posts =>
-      posts.map(post =>
-        post.postNo === postNo
-          ? { ...post, liked: !liked, likeCount: liked ? post.likeCount - 1 : post.likeCount + 1 }
-          : post
-      )
-    );
-  } catch (err) {
-    console.error('点赞失败:', err);
-    alert('点赞操作失败,请稍后重试');
-  }
-};
-
-
-  // 收藏帖子
   const toggleCollect = async (postNo, collected, userId) => {
-  try {
-    if (collected) {
-      // 取消收藏:DELETE 请求 + JSON 请求体
-      await axios.delete(`/echo/forum/posts/${postNo}/uncollect`, {
-        data: { user_id: userId } // 注意:DELETE 请求的请求体需放在 data 字段中
-      });
-    } else {
-      // 收藏:POST 请求 + JSON 请求体
-      await axios.post(`/echo/forum/posts/${postNo}/collect`, {
-        user_id: userId
-      });
+    try {
+      if (collected) {
+        await axios.delete(`/echo/forum/posts/${postNo}/uncollect`, {
+          data: { user_id: userId }
+        });
+      } else {
+        await axios.post(`/echo/forum/posts/${postNo}/collect`, {
+          user_id: userId
+        });
+      }
+
+      setPosts(posts =>
+        posts.map(post =>
+          post.postNo === postNo
+            ? {
+                ...post,
+                collected: !collected,
+                collectCount: collected ? post.collectCount - 1 : post.collectCount + 1
+              }
+            : post
+        )
+      );
+    } catch (err) {
+      console.error('收藏操作失败:', err);
+      alert('收藏操作失败,请稍后重试');
     }
+  };
 
-    setPosts(posts =>
-      posts.map(post =>
-        post.postNo === postNo
-          ? {
-              ...post,
-              collected: !collected,
-              collectCount: collected ? post.collectCount - 1 : post.collectCount + 1
-            }
-          : post
-      )
-    );
-  } catch (err) {
-    console.error('收藏操作失败:', err.response?.data || err.message);
-    alert('收藏操作失败,请稍后重试');
-  }
-};
-
-
-
-  // 删除帖子
   const handleDeletePost = async (postNo) => {
     if (window.confirm('确定要删除这篇帖子吗?')) {
       try {
         await axios.delete(`/echo/forum/posts/${postNo}/deletePost`);
-        
-        // 从列表中移除已删除的帖子
         setPosts(posts => posts.filter(post => post.postNo !== postNo));
-        
-        // 如果删除后当前页没有帖子了,尝试加载上一页
-        if (posts.length === 1 && page > 1) {
-          setPage(page - 1);
-        }
+        if (posts.length === 1 && page > 1) setPage(page - 1);
       } catch (err) {
         console.error('删除帖子失败:', err);
         alert('删除帖子失败,请稍后再试');
@@ -161,43 +134,52 @@
       {loading ? <p>加载中...</p> :
         errorMsg ? <p className="error-text">{errorMsg}</p> :
           posts.length === 0 ? <p>暂无帖子。</p> :
-            posts.map(post => (
-              <div
-                key={post.postNo}
-                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.imgUrl && (
-                  <img className="cover-image" src={post.imgUrl} 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={() => toggleLike(post.postNo, post.liked, post.user_id)}>
-                      <GoodTwo theme="outline" size="24" fill={post.liked ? '#f00' : '#fff'} />
-                      <span>{post.likeCount}</span>
-                    </button>
+            posts.map(post => {
+              const createdAtDate = new Date(post.createdAt);
+              const timeText = isNaN(createdAtDate.getTime()) ? '时间未设置' : createdAtDate.toLocaleString();
 
-                    <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>
-                    
-                    <button className="icon-btn" onClick={() => handleDeletePost(post.postNo)}>
-                      <Delete theme="outline" size="24" fill="#333" />
-                    </button>
+              let coverImage = null;
+              if (post.imgUrl) {
+                const imgs = post.imgUrl.split(',').map(i => i.trim()).filter(Boolean);
+                coverImage = imgs.length > 0 ? formatImageUrl(imgs[0]) : null;
+              }
+
+              return (
+                <div key={post.postNo} className="post-card" style={{ backgroundColor: '#e9ded2' }}>
+                  <div className="user-info">
+                    <img
+                      className="avatar"
+                      src={post.avatarUrl}
+                      alt="头像"
+                    />
+                    <span className="nickname" style={{ color: '#755e50' }}>{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, 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.postNo, post.collected, post.user_id)}>
+                        <Star theme="outline" size="24" fill={post.collected ? '#ffd700' : '#fff'} />
+                        <span>{post.collectCount}</span>
+                      </button>
+                      <button className="icon-btn" onClick={() => handleDeletePost(post.postNo)}>
+                        <Delete theme="outline" size="24" fill="#333" />
+                      </button>
+                    </div>
+                  </div>
+                  <div className="detail-button-wrapper">
+                    <Link href={`/forum/post/${post.postNo}`} className="detail-button">查看详情</Link>
                   </div>
                 </div>
-                <div className="detail-button-wrapper">
-                  <Link href={`/forum/post/${post.postNo}`} className="detail-button">查看详情</Link>
-                </div>
-              </div>
-            ))
+              );
+            })
       }
 
       <div className="pagination">
@@ -209,4 +191,4 @@
   );
 };
 
-export default PostList;
\ No newline at end of file
+export default PostList;