修复查看帖子、评论、回复评论、点赞、收藏,添加用户等级

Change-Id: Ida9590d7ccee08dcd787a36c7e5cb39a3e26cd0d
diff --git a/src/pages/Forum/posts-main/ForumPage.jsx b/src/pages/Forum/posts-main/ForumPage.jsx
index f3866ff..e714415 100644
--- a/src/pages/Forum/posts-main/ForumPage.jsx
+++ b/src/pages/Forum/posts-main/ForumPage.jsx
@@ -1,7 +1,7 @@
 
 import React, { useState } from 'react';
 import Header from '../../../components/Header';
-import SearchBar from './components/SearchBar';
+// import SearchBar from './components/SearchBar';
 import CreatePostButton from './components/CreatePostButton';
 import PostList from './components/PostList';
 import './ForumPage.css';
@@ -20,7 +20,7 @@
       <Promotion />
       <div className="toolbar">
         <CreatePostButton />
-        <SearchBar onSearch={handleSearch} />     
+        {/* <SearchBar onSearch={handleSearch} />      */}
       </div>
       <PostList search={searchQuery} />
     </div>
diff --git a/src/pages/Forum/posts-main/components/CreatePostButton.jsx b/src/pages/Forum/posts-main/components/CreatePostButton.jsx
index 4f7d7b1..0f23e82 100644
--- a/src/pages/Forum/posts-main/components/CreatePostButton.jsx
+++ b/src/pages/Forum/posts-main/components/CreatePostButton.jsx
@@ -3,67 +3,56 @@
 import { Edit } from '@icon-park/react';
 import './CreatePostButton.css';
 
-const API_BASE = process.env.REACT_APP_API_BASE;
-const user_id = 456;
+const user = JSON.parse(localStorage.getItem('user')); // user = { user_id: 123, ... }
+const userId = user?.user_id;
+
 
 const CreatePostButton = () => {
   const [showModal, setShowModal] = useState(false);
 
-  // 表单字段
   const [title, setTitle] = useState('');
   const [content, setContent] = useState('');
   const [previewUrls, setPreviewUrls] = useState([]);
-  const [imageUrls, setImageUrls] = useState([]);
+  const [files, setFiles] = useState([]);
 
-  // 处理文件选中:预览 & 上传
-  const handleImageChange = async (e) => {
-    const files = Array.from(e.target.files);
-    if (!files.length) return;
-    // 本地预览
-    setPreviewUrls(files.map(f => URL.createObjectURL(f)));
-
-    // 并发上传,假设 /upload 接口返回 { url: '...' }
-    try {
-      const uploaded = await Promise.all(
-        files.map(file => {
-          const fd = new FormData();
-          fd.append('file', file);
-          return axios.post(`${API_BASE}/upload`, fd, {
-            headers: { 'Content-Type': 'multipart/form-data' }
-          }).then(res => res.data.url);
-        })
-      );
-      setImageUrls(uploaded);
-    } catch (err) {
-      console.error('图片上传失败:', err);
-      alert('封面图上传失败,请重试');
-    }
+  // 选择图片并预览
+  const handleImageChange = (e) => {
+    const selectedFiles = Array.from(e.target.files);
+    if (!selectedFiles.length) return;
+    setFiles(selectedFiles);
+    setPreviewUrls(selectedFiles.map(f => URL.createObjectURL(f)));
   };
 
-  // 提交发帖
   const handleSubmit = async () => {
     if (!title.trim() || !content.trim()) {
       alert('标题和内容均为必填项');
       return;
     }
 
+    const formData = new FormData();
+    formData.append('title', title.trim());
+    formData.append('postContent', content.trim());
+
+    files.forEach(file => {
+      formData.append('imageUrl', file); // 多文件使用同一个字段名
+    });
+
     try {
       await axios.post(
-        `${API_BASE}/echo/forum/posts/${user_id}/createPost`,
+        `/echo/forum/posts/${userId}/createPost`,
+        formData,
         {
-          title: title.trim(),
-          post_content: content.trim(),
-          image_url: imageUrls
+          headers: { 'Content-Type': 'multipart/form-data' }
         }
       );
-      // 重置状态并关闭
+
+      // 清空表单
       setTitle('');
       setContent('');
+      setFiles([]);
       setPreviewUrls([]);
-      setImageUrls([]);
       setShowModal(false);
       alert('发帖成功');
-      // 如需刷新帖子列表,可在这里触发外部回调
     } catch (err) {
       console.error('发帖失败:', err.response?.data || err);
       alert(err.response?.data?.error || '发帖失败,请稍后重试');
@@ -110,7 +99,7 @@
 
             <div className="cp-preview">
               {previewUrls.map((url, i) => (
-                <img key={i} src={url} alt={`封面预览 ${i}`} />
+                <img key={i} src={url} alt={`预览 ${i}`} />
               ))}
             </div>
 
@@ -130,3 +119,4 @@
 };
 
 export default CreatePostButton;
+
diff --git a/src/pages/Forum/posts-main/components/PostList.jsx b/src/pages/Forum/posts-main/components/PostList.jsx
index 707ff15..9e088ea 100644
--- a/src/pages/Forum/posts-main/components/PostList.jsx
+++ b/src/pages/Forum/posts-main/components/PostList.jsx
@@ -1,12 +1,10 @@
 import React, { useEffect, useState } from 'react';
 import axios from 'axios';
 import { Link } from 'wouter';
-import { GoodTwo, Comment, Star, Delete } from '@icon-park/react';
-import { likePost, unlikePost } from '../../posts-detail/api';
+import { GoodTwo, Star, Delete } from '@icon-park/react';
+import { likePost } 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);
@@ -22,7 +20,7 @@
       setLoading(true);
       setErrorMsg('');
       try {
-        const res = await axios.get(`${API_BASE}/echo/forum/posts/getAllPosts`, {
+        const res = await axios.get(`/echo/forum/posts/getAllPosts`, {
           params: {
             page,
             pageSize: size,
@@ -31,13 +29,18 @@
           }
         });
 
+        // 检查响应结构是否符合预期
+        if (!res.data || !Array.isArray(res.data.posts)) {
+          throw new Error('API返回格式不正确');
+        }
+
         const postsData = res.data.posts || [];
 
         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`, {
+            const r = await axios.get(`/echo/user/profile`, {
               params: { user_id: id }
             });
             return { id, profile: r.data };
@@ -74,61 +77,73 @@
     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.postNo === postId
-            ? { ...post, liked: !liked, likeCount: liked ? post.likeCount - 1 : post.likeCount + 1 }
-            : post
-        )
-      );
-    } catch (err) {
-      console.error('点赞失败:', err);
+  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); // 你已有的点赞逻辑
     }
-  };
+
+    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 (postId, collected, userId) => {
-    try {
-      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 =>
-          post.postNo === postId
-            ? { ...post, collected: !collected, collectCount: collected ? post.collectCount - 1 : post.collectCount + 1 }
-            : post
-        )
-      );
-    } catch (err) {
-      console.error('收藏操作失败:', err);
+  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
+      });
     }
-  };
+
+    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 (postId) => {
+  const handleDeletePost = async (postNo) => {
     if (window.confirm('确定要删除这篇帖子吗?')) {
       try {
-        await axios.delete(`${API_BASE}/echo/forum/posts/${postId}/deletePost`);
+        await axios.delete(`/echo/forum/posts/${postNo}/deletePost`);
         
         // 从列表中移除已删除的帖子
-        setPosts(posts => posts.filter(post => post.postNo !== postId));
+        setPosts(posts => posts.filter(post => post.postNo !== postNo));
         
         // 如果删除后当前页没有帖子了,尝试加载上一页
         if (posts.length === 1 && page > 1) {
@@ -172,11 +187,6 @@
                       <Star theme="outline" size="24" fill={post.collected ? '#ffd700' : '#fff'} />
                       <span>{post.collectCount}</span>
                     </button>
-
-                    <div className="icon-btn">
-                      <Comment theme="outline" size="24" fill="#fff" />
-                      <span>{post.commentCount}</span>
-                    </div>
                     
                     <button className="icon-btn" onClick={() => handleDeletePost(post.postNo)}>
                       <Delete theme="outline" size="24" fill="#333" />