修改好友动态、兴趣小组

Change-Id: I8dc8f304f9ac9c968e316bc997b2aeb58b26fe48
diff --git a/src/pages/FriendMoments/FriendMoments.css b/src/pages/FriendMoments/FriendMoments.css
index 1059f10..087abcb 100644
--- a/src/pages/FriendMoments/FriendMoments.css
+++ b/src/pages/FriendMoments/FriendMoments.css
@@ -11,7 +11,11 @@
   padding: 2%;
 }
 
-
+.like-container{
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
 .f-search-bar {
   display: flex;
   align-items: center;
diff --git a/src/pages/FriendMoments/FriendMoments.jsx b/src/pages/FriendMoments/FriendMoments.jsx
index fd017b2..526c06d 100644
--- a/src/pages/FriendMoments/FriendMoments.jsx
+++ b/src/pages/FriendMoments/FriendMoments.jsx
@@ -1,32 +1,76 @@
-import React, { useState, useEffect } from 'react';
+import React, { useContext, useState, useEffect } from 'react'; 
 import axios from 'axios';
 import './FriendMoments.css';
 import Header from '../../components/Header';
-import { Edit } from '@icon-park/react';
+import { Edit, GoodTwo, Comment } from '@icon-park/react';
+import { UserContext } from '../../context/UserContext'; // 引入用户上下文
 
 const FriendMoments = () => {
   const [feeds, setFeeds] = useState([]);
   const [filteredFeeds, setFilteredFeeds] = useState([]);
   const [query, setQuery] = useState('');
-  const [userId, setUserId] = useState(456); // 从状态管理或登录信息获取
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(null);
+  const [commentBoxVisibleId, setCommentBoxVisibleId] = useState(null); // 当前显示评论框的动态ID
+  const [commentInput, setCommentInput] = useState(''); // 当前输入的评论内容
+
+  // 从上下文中获取用户信息
+  const { user } = useContext(UserContext);
+  const userId = user?.userId || null; // 从用户上下文中获取userId
+  const username = user?.username || '未知用户'; // 获取用户名
 
   // Modal state & form fields
   const [showModal, setShowModal] = useState(false);
   const [title, setTitle] = useState('');
   const [content, setContent] = useState('');
   const [selectedImages, setSelectedImages] = useState([]);
-  const [previewUrls, setPreviewUrls] = useState([]); // 新增:图片预览URLs
+  const [previewUrls, setPreviewUrls] = useState([]);
+
+  // 检查用户是否已登录
+  const isLoggedIn = !!userId;
 
   // 拉取好友动态列表
   const fetchFeeds = async () => {
+    if (!isLoggedIn) {
+      setLoading(false);
+      setError('请先登录');
+      return;
+    }
+
+    setLoading(true);
+    setError(null);
     try {
-      // 修改为新的API路径
+      // 注意这里修改了API路径,使用getAllDynamics接口
       const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
-      setFeeds(res.data.posts || []);
-      setFilteredFeeds(res.data.posts || []);
+      
+      // 检查API返回的数据结构
+      console.log('API响应数据:', res.data);
+      
+      // 从响应中提取dynamic数组
+      const dynamicList = res.data.dynamic || [];
+      
+      // 将API返回的数据结构转换为前端期望的格式
+      const formattedFeeds = dynamicList.map(item => ({
+        postNo: item.dynamic_id, // 使用API返回的dynamic_id作为帖子ID
+        title: item.title,
+        postContent: item.content,
+        imageUrl: item.images, // 使用API返回的images字段
+        postTime: item.time, // 使用API返回的time字段
+        postLikeNum: item.likes?.length || 0, // 点赞数
+        liked: item.likes?.some(like => like.user_id === userId), // 当前用户是否已点赞
+        user_id: item.user_id, // 发布者ID
+        username: item.username, // 发布者昵称
+        avatar_url: item.avatar_url, // 发布者头像
+        comments: item.comments || [] // 评论列表
+      }));
+      
+      setFeeds(formattedFeeds);
+      setFilteredFeeds(formattedFeeds);
     } catch (err) {
       console.error('获取动态列表失败:', err);
-      alert('获取动态列表失败,请稍后重试');
+      setError('获取动态列表失败,请稍后重试');
+    } finally {
+      setLoading(false);
     }
   };
 
@@ -59,23 +103,27 @@
     const files = Array.from(e.target.files);
     if (!files.length) return;
     
-    // 生成预览URLs
     const previewUrls = files.map(file => URL.createObjectURL(file));
     
     setSelectedImages(files);
-    setPreviewUrls(previewUrls); // 更新预览URLs
+    setPreviewUrls(previewUrls);
   };
 
   // 对话框内:提交新动态
   const handleSubmit = async () => {
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
+    }
+
     if (!content.trim()) {
       alert('内容不能为空');
       return;
     }
 
     try {
+      // 使用formData格式提交
       const formData = new FormData();
-      formData.append('user_id', userId);
       formData.append('title', title.trim() || '');
       formData.append('content', content.trim());
       
@@ -84,7 +132,7 @@
         formData.append('image_url', file);
       });
 
-      // 修改为新的API路径
+      // 调用创建动态API
       await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
         headers: {
           'Content-Type': 'multipart/form-data'
@@ -95,7 +143,7 @@
       setTitle('');
       setContent('');
       setSelectedImages([]);
-      setPreviewUrls([]); // 重置预览URLs
+      setPreviewUrls([]);
       setShowModal(false);
       fetchFeeds();
       alert('发布成功');
@@ -105,11 +153,17 @@
     }
   };
 
-  // 删除动态
+  // 删除动态 - 注意:API文档中未提供删除接口,这里保留原代码
   const handleDelete = async (dynamicId) => {
+  
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
+    }
+
     if (!window.confirm('确定要删除这条动态吗?')) return;
     try {
-      // 修改为新的API路径
+      // 注意:API文档中未提供删除接口,这里使用原代码中的路径
       await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
       fetchFeeds();
       alert('删除成功');
@@ -120,64 +174,224 @@
   };
 
   // 点赞动态
-  const handleLike = async (dynamicId) => {
+  const handleLike = async (dynamicId,islike) => {
+    if (islike) {
+      handleUnlike(dynamicId);
+      return
+    }
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
+    }
+
+    // 验证dynamicId是否有效
+    if (!dynamicId) {
+      console.error('无效的dynamicId:', dynamicId);
+      alert('点赞失败:动态ID无效');
+      return;
+    }
+
+    // 检查是否已经点赞,防止重复请求
+    // const currentFeed = feeds.find(feed => feed.postNo === dynamicId);
+    // if (currentFeed && currentFeed.liked) {
+    //   console.warn('尝试重复点赞,已忽略');
+    //   return;
+    // }
+
+    console.log('当前用户ID:', userId);
+    console.log('即将点赞的动态ID:', dynamicId);
+    
     try {
-      // 调用新的点赞API
-      const res = await axios.post(`/echo/dynamic/like`, {
-        userId,
-        dynamicId
+      // 确保参数是整数类型
+      const requestData = {
+        userId: parseInt(userId),
+        dynamicId: parseInt(dynamicId)
+      };
+      
+      // 验证参数是否为有效数字
+      if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
+        console.error('无效的参数:', requestData);
+        alert('点赞失败:参数格式错误');
+        return;
+      }
+      
+      console.log('点赞请求数据:', requestData);
+      
+      const res = await axios.post(`/echo/dynamic/like`, requestData, {
+        headers: {
+          'Content-Type': 'application/json' // 明确指定JSON格式
+        }
       });
       
+      console.log('点赞API响应:', res.data);
+      
       if (res.status === 200) {
         // 更新本地状态
-        setFeeds(feeds.map(feed => {
+        feeds.forEach(feed => {
           if (feed.postNo === dynamicId) {
-            return {
-              ...feed,
-              postLikeNum: (feed.postLikeNum || 0) + 1,
-              liked: true
-            };
+            feed.postLikeNum = (feed.postLikeNum || 0) + 1;
+            feed.liked = true;
           }
-          return feed;
-        }));
+        });
+        setFeeds([...feeds]); // 更新状态以触发重新渲染
       } else {
         alert(res.data.message || '点赞失败');
       }
     } catch (err) {
       console.error('点赞失败', err);
+      
+      // 检查错误响应,获取更详细的错误信息
+      if (err.response) {
+        console.error('错误响应数据:', err.response.data);
+        console.error('错误响应状态:', err.response.status);
+        console.error('错误响应头:', err.response.headers);
+      }
+      
       alert('点赞失败,请稍后重试');
     }
   };
 
   // 取消点赞
   const handleUnlike = async (dynamicId) => {
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
+    }
+
+    // 验证dynamicId是否有效
+    if (!dynamicId) {
+      console.error('无效的dynamicId:', dynamicId);
+      alert('取消点赞失败:动态ID无效');
+      return;
+    }
+
+    // 检查是否已经取消点赞,防止重复请求
+    const currentFeed = feeds.find(feed => feed.postNo === dynamicId);
+    if (currentFeed && !currentFeed.liked) {
+      console.warn('尝试重复取消点赞,已忽略');
+      return;
+    }
+
     try {
-      // 调用新的取消点赞API
+      // 确保参数是整数类型
+      const requestData = {
+        userId: parseInt(userId),
+        dynamicId: parseInt(dynamicId)
+      };
+      
+      // 验证参数是否为有效数字
+      if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
+        console.error('无效的参数:', requestData);
+        alert('取消点赞失败:参数格式错误');
+        return;
+      }
+      
+      console.log('取消点赞请求数据:', requestData);
+      
       const res = await axios.delete(`/echo/dynamic/unlike`, {
-        data: { userId, dynamicId }
+        headers: {
+          'Content-Type': 'application/json' // 明确指定JSON格式
+        },
+        data: requestData // 将参数放在data属性中
       });
       
+      console.log('取消点赞API响应:', res.data);
+      
       if (res.status === 200) {
         // 更新本地状态
-        setFeeds(feeds.map(feed => {
+        feeds.forEach(feed => {
           if (feed.postNo === dynamicId) {
-            return {
-              ...feed,
-              postLikeNum: Math.max(0, (feed.postLikeNum || 0) - 1),
-              liked: false
-            };
+            feed.postLikeNum = Math.max(0, (feed.postLikeNum || 0) - 1);
+            feed.liked = false;
           }
-          return feed;
-        }));
+        });
+        setFeeds([...feeds]); // 更新状态以触发重新渲染
       } else {
         alert(res.data.message || '取消点赞失败');
       }
     } catch (err) {
       console.error('取消点赞失败', err);
+      
+      // 检查错误响应,获取更详细的错误信息
+      if (err.response) {
+        console.error('错误响应数据:', err.response.data);
+        console.error('错误响应状态:', err.response.status);
+        console.error('错误响应头:', err.response.headers);
+      }
+      
       alert('取消点赞失败,请稍后重试');
     }
   };
 
+  // 评论好友动态
+  // 评论好友动态
+const handleComment = async (dynamicId) => {
+  if (!isLoggedIn) {
+    alert('请先登录');
+    return;
+  }
+
+  if (!commentInput.trim()) {
+    alert('评论内容不能为空');
+    return;
+  }
+
+  try {
+    const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, {
+      content: commentInput.trim()
+    });
+
+    if (res.status === 200 || res.status === 201) {
+      // 成功获取评论数据
+      const newComment = {
+        user_id: userId,
+        username: username,
+        content: commentInput.trim(),
+        time: new Date().toISOString() // 使用当前时间作为评论时间
+      };
+
+      // 更新本地状态,添加新评论
+      setFeeds(prevFeeds => {
+        return prevFeeds.map(feed => {
+          if (feed.postNo === dynamicId) {
+            // 确保comments是数组,并且正确合并新评论
+            const currentComments = Array.isArray(feed.comments) ? feed.comments : [];
+            return {
+              ...feed,
+              comments: [...currentComments, newComment]
+            };
+          }
+          return feed;
+        });
+      });
+
+      // 更新过滤后的动态列表
+      setFilteredFeeds(prevFeeds => {
+        return prevFeeds.map(feed => {
+          if (feed.postNo === dynamicId) {
+            // 确保comments是数组,并且正确合并新评论
+            const currentComments = Array.isArray(feed.comments) ? feed.comments : [];
+            return {
+              ...feed,
+              comments: [...currentComments, newComment]
+            };
+          }
+          return feed;
+        });
+      });
+
+      // alert('评论成功');
+      setCommentInput('');
+      setCommentBoxVisibleId(null); // 关闭评论框
+    } else {
+      alert(res.data.error || '评论失败');
+    }
+  } catch (err) {
+    console.error('评论失败', err);
+    alert('评论失败,请稍后重试');
+  }
+};
+
   return (
     <div className="friend-moments-container">
       <Header />
@@ -186,7 +400,7 @@
           <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
           创建动态
         </button>
-        <div className="f-search-bar">
+        {/* <div className="f-search-bar">
           <input
             className="search-input"
             type="text"
@@ -196,46 +410,115 @@
           />
           <button className="search-btn" onClick={handleSearch}>搜索</button>
           <button className="search-btn" onClick={handleReset}>重置</button>
-        </div>
+        </div> */}
       </div>
 
       <div className="feed-list">
-        {filteredFeeds.map(feed => (
-          <div className="feed-item" key={feed.postNo}>
-            {feed.title && <h4>{feed.title}</h4>}
-            <p>{feed.postContent}</p>
-
-            {feed.imageUrl && feed.imageUrl.split(',').length > 0 && (
-              <div className="feed-images">
-                {feed.imageUrl.split(',').map((url, i) => (
-                  <img key={i} src={url} alt={`动态图${i}`} />
-                ))}
-              </div>
-            )}
-
-            <div className="feed-footer">
-              <span className="feed-date">
-                {new Date(feed.postTime).toLocaleString()}
-              </span>
-              <div className="like-container">
-                {feed.liked ? (
-                  <button className="unlike-btn" onClick={() => handleUnlike(feed.postNo)}>
-                    已点赞 ({feed.postLikeNum || 0})
-                  </button>
-                ) : (
-                  <button className="like-btn" onClick={() => handleLike(feed.postNo)}>
-                    点赞 ({feed.postLikeNum || 0})
-                  </button>
-                )}
-              </div>
-              {feed.user_id === userId && (
-                <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
-                  删除
-                </button>
-              )}
-            </div>
+        {loading ? (
+          <div className="loading-message">加载中...</div>
+        ) : error ? (
+          <div className="error-message">{error}</div>
+        ) : !isLoggedIn ? (
+          <div className="login-prompt">
+            <p>请先登录查看好友动态</p>
           </div>
-        ))}
+        ) : filteredFeeds.length === 0 ? (
+          <div className="empty-message">暂无动态</div>
+        ) : (
+          filteredFeeds.map(feed => (
+            <div className="feed-item" key={feed.postNo || `feed-${Math.random()}`}>
+              {/* 显示发布者信息 */}
+              <div className="feed-author">
+                <img src={feed.avatar_url || 'https://example.com/default-avatar.jpg'} alt={feed.username || '用户头像'} />
+                <div>
+                  <h4>{feed.username || '未知用户'}</h4>
+                  <span className="feed-date">{new Date(feed.postTime || Date.now()).toLocaleString()}</span>
+                </div>
+              </div>
+
+              {feed.title && <h4 className="feed-title">{feed.title}</h4>}
+              <p className="feed-content">{feed.postContent || '无内容'}</p>
+
+              {feed.imageUrl && (
+                <div className="feed-images">
+                  {/* 处理可能是单张图片或多张图片的情况 */}
+                  {typeof feed.imageUrl === 'string' ? (
+                    <img src={feed.imageUrl} alt="动态图片" />
+                  ) : (
+                    feed.imageUrl.map((url, i) => (
+                      <img key={i} src={url} alt={`动态图${i}`} />
+                    ))
+                  )}
+                </div>
+              )}
+
+              <div className="feed-footer">
+                <div className="like-container">
+                    <button className="icon-btn" onClick={() => handleLike(feed.postNo, feed.liked, feed.user_id)}>
+                      <GoodTwo theme="outline" size="24" fill={feed.liked ? '#f00' : '#fff'} />
+                      <span>{feed.postLikeNum || 0}</span>
+                    
+                    </button>
+
+                  <button
+                    className="icon-btn"
+                    onClick={() => {
+                      setCommentBoxVisibleId(feed.postNo);
+                      setCommentInput('');
+                    }}
+                  >
+                    <Comment theme="outline" size="24" fill="#333" />
+                    <span>评论</span>
+                  </button>
+
+    {commentBoxVisibleId === feed.postNo && (
+      <div className="comment-box">
+        <textarea
+          className="comment-input"
+          placeholder="请输入评论内容..."
+          value={commentInput}
+          onChange={(e) => setCommentInput(e.target.value)}
+        />
+        <button
+          className="submit-comment-btn"
+          onClick={() => handleComment(feed.postNo)}
+        >
+          发布评论
+        </button>
+      </div>
+    )}
+  </div>
+  {feed.user_id === userId && (
+    <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
+      删除
+    </button>
+  )}
+</div>
+
+              {/* 评论列表 */}
+              {Array.isArray(feed.comments) && feed.comments.length > 0 && (
+                <div className="comments-container">
+                  <h5>评论 ({feed.comments.length})</h5>
+                  <div className="comments-list">
+                    {feed.comments.map((comment, index) => (
+                      <div className="comment-item" key={index}>
+                        <div className="comment-header">
+                          <span className="comment-user">{comment.username || '用户'}</span>
+                          {/* <span className="comment-user-id">ID: {comment.user_id}</span> */}
+                          <span className="comment-time">
+                            {new Date(comment.time || Date.now()).toLocaleString()}
+                          </span>
+                        </div>
+                        <p className="comment-content">{comment.content}</p>
+                      </div>
+                    ))}
+                  </div>
+                </div>
+              )}
+
+            </div>
+          ))
+        )}
       </div>
 
       {/* Modal 对话框 */}
@@ -265,7 +548,7 @@
               />
             </label>
             <div className="cf-preview">
-              {previewUrls.map((url, i) => ( // 使用定义的previewUrls
+              {previewUrls.map((url, i) => (
                 <img key={i} src={url} alt={`预览${i}`} />
               ))}
             </div>
@@ -284,4 +567,4 @@
   );
 };
 
-export default FriendMoments;
\ No newline at end of file
+export default FriendMoments;  
\ No newline at end of file