兴趣小组、好友动态

Change-Id: I7aa713600dea31eb2cd5b32ecc4e257b2bbd8be1
diff --git a/src/pages/FriendMoments/FriendMoments.css b/src/pages/FriendMoments/FriendMoments.css
index 4f0a801..cca399f 100644
--- a/src/pages/FriendMoments/FriendMoments.css
+++ b/src/pages/FriendMoments/FriendMoments.css
@@ -180,3 +180,241 @@
   color: #fff;
 } 
 
+
+.feed-author {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 10px;
+}
+
+.feed-title {
+  font-size: 1.2em;
+  font-weight: bold;
+  margin-bottom: 8px;
+}
+
+.feed-content {
+  margin-bottom: 12px;
+  line-height: 1.5;
+}
+
+.feed-images {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
+  gap: 8px;
+  margin-bottom: 12px;
+}
+
+.feed-images img {
+  width: 100%;
+  height: 120px;
+  object-fit: cover;
+  border-radius: 4px;
+}
+
+.feed-footer {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-top: 12px;
+}
+
+.like-container {
+  display: flex;
+  gap: 15px;
+}
+
+.icon-btn {
+  background: none;
+  border: none;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  color: #555;
+}
+
+.delete-btn {
+  background: none;
+  border: none;
+  color: #f44336;
+  cursor: pointer;
+}
+
+.comment-box {
+  margin-top: 12px;
+}
+
+.comment-input {
+  width: 100%;
+  padding: 8px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  margin-bottom: 8px;
+  resize: vertical;
+}
+
+.submit-comment-btn {
+  background-color: #ce6178;
+  color: white;
+  border: none;
+  padding: 6px 12px;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.comments-container {
+  margin-top: 16px;
+  padding-top: 16px;
+  border-top: 1px solid #ba8989;
+}
+
+.comments-list {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.comment-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 4px;
+}
+
+.comment-user {
+  font-weight: bold;
+  color: #333;
+}
+
+.comment-time {
+  font-size: 0.8em;
+  color: #888;
+}
+
+.comment-content {
+  margin-bottom: 6px;
+  line-height: 1.4;
+}
+
+.reply-prefix {
+  color: #666;
+  font-weight: bold;
+}
+
+.reply-btn {
+  background: none;
+  border: none;
+  color: #2196F3;
+  font-size: 0.9em;
+  cursor: pointer;
+  padding: 0;
+}
+
+.nested-replies {
+  margin-top: 8px;
+  padding-left: 16px;
+  border-left: 2px solid #eee;
+}
+
+.reply-item {
+  margin-bottom: 8px;
+}
+
+.reply-content {
+  margin-bottom: 4px;
+  line-height: 1.4;
+}
+
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0,0,0,0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.modal-dialog {
+  background-color: white;
+  border-radius: 8px;
+  padding: 20px;
+  width: 90%;
+  max-width: 500px;
+}
+
+.modal-dialog h3 {
+  margin-top: 0;
+  margin-bottom: 16px;
+}
+
+.modal-dialog input,
+.modal-dialog textarea {
+  width: 100%;
+  padding: 8px;
+  margin-bottom: 12px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+}
+
+.file-label {
+  display: inline-block;
+  background-color: #f0f0f0;
+  color: #333;
+  padding: 8px 12px;
+  border-radius: 4px;
+  cursor: pointer;
+  margin-bottom: 12px;
+}
+
+.cf-preview {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  margin-bottom: 12px;
+}
+
+.cf-preview img {
+  width: 80px;
+  height: 80px;
+  object-fit: cover;
+  border-radius: 4px;
+}
+
+.modal-actions {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+
+.btn {
+  padding: 8px 16px;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.cancel {
+  background-color: #f0f0f0;
+  color: #333;
+  border: 1px solid #ddd;
+}
+
+.submit {
+  background-color: #4CAF50;
+  color: white;
+  border: none;
+}
+
+.loading-message,
+.error-message,
+.login-prompt,
+.empty-message {
+  text-align: center;
+  padding: 20px;
+  color: #555;
+}
+
diff --git a/src/pages/FriendMoments/FriendMoments.jsx b/src/pages/FriendMoments/FriendMoments.jsx
index c642772..ab1aef2 100644
--- a/src/pages/FriendMoments/FriendMoments.jsx
+++ b/src/pages/FriendMoments/FriendMoments.jsx
@@ -1,3 +1,1342 @@
+// // FriendMoments.js
+// import React, { useContext, useState, useEffect } from 'react'; 
+// import axios from 'axios';
+// import './FriendMoments.css';
+// import Header from '../../components/Header';
+// import { Edit, GoodTwo, Comment } from '@icon-park/react';
+// import { UserContext } from '../../context/UserContext'; // 引入用户上下文
+
+// // 修改后的封面图 URL 拼接函数
+// const formatImageUrl = (url) => {
+//   if (!url) return '';
+//   const filename = url.split('/').pop(); // 提取文件名部分
+//   return `http://localhost:5011/uploads/dynamic/${filename}`;
+// };
+
+// const FriendMoments = () => {
+//   const [feeds, setFeeds] = useState([]);
+//   const [filteredFeeds, setFilteredFeeds] = useState([]);
+//   const [query, setQuery] = useState('');
+//   const [loading, setLoading] = useState(true);
+//   const [error, setError] = useState(null);
+
+//   // 从上下文中获取用户信息
+//   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([]);
+
+//   // 检查用户是否已登录
+//   const isLoggedIn = !!userId;
+
+//   // 拉取好友动态列表
+//   const fetchFeeds = async () => {
+//     if (!isLoggedIn) {
+//       setLoading(false);
+//       setError('请先登录');
+//       return;
+//     }
+
+//     setLoading(true);
+//     setError(null);
+//     try {
+//       // 注意这里修改了API路径,使用getAllDynamics接口
+//       const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
+      
+//       // 检查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);
+//       setError('获取动态列表失败,请稍后重试');
+//     } finally {
+//       setLoading(false);
+//     }
+//   };
+
+//   useEffect(() => {
+//     fetchFeeds();
+//   }, [userId]);
+
+//   // 搜索处理
+//   const handleSearch = () => {
+//     const q = query.trim().toLowerCase();
+//     if (!q) {
+//       setFilteredFeeds(feeds);
+//       return;
+//     }
+//     setFilteredFeeds(
+//       feeds.filter(f => 
+//         (f.title || '').toLowerCase().includes(q) || 
+//         (f.postContent || '').toLowerCase().includes(q)
+//       )
+//     );
+//   };
+
+//   const handleReset = () => {
+//     setQuery('');
+//     setFilteredFeeds(feeds);
+//   };
+
+//   // 对话框内:处理图片选择
+//   const handleImageChange = (e) => {
+//     const files = Array.from(e.target.files);
+//     if (!files.length) return;
+    
+//     const previewUrls = files.map(file => URL.createObjectURL(file));
+    
+//     setSelectedImages(files);
+//     setPreviewUrls(previewUrls);
+//   };
+
+//   // 对话框内:提交新动态
+//   const handleSubmit = async () => {
+//     if (!isLoggedIn) {
+//       alert('请先登录');
+//       return;
+//     }
+
+//     if (!content.trim()) {
+//       alert('内容不能为空');
+//       return;
+//     }
+
+//     try {
+//       // 使用formData格式提交
+//       const formData = new FormData();
+//       formData.append('title', title.trim() || '');
+//       formData.append('content', content.trim());
+      
+//       // 添加图片文件
+//       selectedImages.forEach((file, index) => {
+//         formData.append('image_url', file);
+//       });
+
+//       // 调用创建动态API
+//       await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
+//         headers: {
+//           'Content-Type': 'multipart/form-data'
+//         }
+//       });
+
+//       // 重置表单
+//       setTitle('');
+//       setContent('');
+//       setSelectedImages([]);
+//       setPreviewUrls([]);
+//       setShowModal(false);
+//       fetchFeeds();
+//       alert('发布成功');
+//     } catch (err) {
+//       console.error('发布失败', err);
+//       alert('发布失败,请稍后重试');
+//     }
+//   };
+
+//   // 删除动态 - 注意:API文档中未提供删除接口,这里保留原代码
+//   const handleDelete = async (dynamicId) => {
+  
+//     if (!isLoggedIn) {
+//       alert('请先登录');
+//       return;
+//     }
+
+//     if (!window.confirm('确定要删除这条动态吗?')) return;
+//     try {
+//       // 注意:API文档中未提供删除接口,这里使用原代码中的路径
+//       await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
+//       fetchFeeds();
+//       alert('删除成功');
+//     } catch (err) {
+//       console.error('删除失败', err);
+//       alert('删除失败,请稍后重试');
+//     }
+//   };
+
+//   // 点赞动态
+//   const handleLike = async (dynamicId, islike) => {
+//     if (islike) {
+//       handleUnlike(dynamicId);
+//       return
+//     }
+//     if (!isLoggedIn) {
+//       alert('请先登录');
+//       return;
+//     }
+
+//     // 验证dynamicId是否有效
+//     if (!dynamicId) {
+//       console.error('无效的dynamicId:', dynamicId);
+//       alert('点赞失败:动态ID无效');
+//       return;
+//     }
+
+//     console.log('当前用户ID:', userId);
+//     console.log('即将点赞的动态ID:', dynamicId);
+    
+//     try {
+//       // 确保参数是整数类型
+//       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(prevFeeds => {
+//           return prevFeeds.map(feed => {
+//             if (feed.postNo === dynamicId) {
+//               return {
+//                 ...feed,
+//                 postLikeNum: (feed.postLikeNum || 0) + 1,
+//                 liked: true
+//               };
+//             }
+//             return feed;
+//           });
+//         });
+//       } 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 {
+//       // 确保参数是整数类型
+//       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`, {
+//         headers: {
+//           'Content-Type': 'application/json' // 明确指定JSON格式
+//         },
+//         data: requestData // 将参数放在data属性中
+//       });
+      
+//       console.log('取消点赞API响应:', res.data);
+      
+//       if (res.status === 200) {
+//         // 更新本地状态
+//         setFeeds(prevFeeds => {
+//           return prevFeeds.map(feed => {
+//             if (feed.postNo === dynamicId) {
+//               return {
+//                 ...feed,
+//                 postLikeNum: Math.max(0, (feed.postLikeNum || 0) - 1),
+//                 liked: false
+//               };
+//             }
+//             return feed;
+//           });
+//         });
+//       } 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, parentCommentId = null, replyToUsername = '') => {
+//     if (!isLoggedIn) {
+//       alert('请先登录');
+//       return;
+//     }
+
+//     const commentInputId = `comment-input-${dynamicId}-${parentCommentId}`;
+//     const commentInput = document.getElementById(commentInputId);
+    
+//     if (!commentInput || !commentInput.value.trim()) {
+//       alert('评论内容不能为空');
+//       return;
+//     }
+
+//     const commentContent = commentInput.value.trim();
+
+//     try {
+//       // 准备请求数据
+//       const requestData = {
+//         content: commentContent
+//       };
+      
+//       // 如果是回复,添加parent_comment_id
+//       if (parentCommentId) {
+//         requestData.parent_comment_id = parentCommentId;
+//       }
+      
+//       const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, requestData);
+
+//       if (res.status === 200 || res.status === 201) {
+//         // 创建新评论对象
+//         const newComment = {
+//           // 使用API返回的评论ID,如果没有则生成临时ID
+//           id: res.data.comment_id || `temp-${Date.now()}`,
+//           user_id: userId,
+//           username: username,
+//           content: commentContent,
+//           time: new Date().toISOString(),
+//           // 如果是回复,添加reply_to_username
+//           ...(replyToUsername && { reply_to_username: replyToUsername })
+//         };
+
+//         // 更新本地状态
+//         setFeeds(prevFeeds => {
+//           return prevFeeds.map(feed => {
+//             if (feed.postNo === dynamicId) {
+//               if (parentCommentId) {
+//                 // 这是一个回复,找到父评论并添加到其replies数组
+//                 return {
+//                   ...feed,
+//                   comments: feed.comments.map(comment => {
+//                     if (comment.id === parentCommentId || comment.postNo === parentCommentId) {
+//                       // 确保replies数组存在
+//                       if (!comment.replies) {
+//                         return {
+//                           ...comment,
+//                           replies: [newComment]
+//                         };
+//                       }
+//                       return {
+//                         ...comment,
+//                         replies: [...comment.replies, newComment]
+//                       };
+//                     }
+//                     return comment;
+//                   })
+//                 };
+//               } else {
+//                 // 这是一个新评论,添加到评论列表
+//                 return {
+//                   ...feed,
+//                   comments: [...feed.comments, newComment]
+//                 };
+//               }
+//             }
+//             return feed;
+//           });
+//         });
+
+//         // 清空输入框并隐藏回复框
+//         if (commentInput) {
+//           commentInput.value = '';
+//         }
+//         toggleReplyBox(dynamicId, parentCommentId);
+//       } else {
+//         alert(res.data.error || '评论失败');
+//       }
+//     } catch (err) {
+//       console.error('评论失败', err);
+//       alert('评论失败,请稍后重试');
+//     }
+//   };
+
+//   // 切换回复框显示状态
+//   const toggleReplyBox = (dynamicId, parentCommentId = null) => {
+//     const replyBoxId = `reply-box-${dynamicId}-${parentCommentId}`;
+//     const replyBox = document.getElementById(replyBoxId);
+    
+//     if (replyBox) {
+//       replyBox.style.display = replyBox.style.display === 'none' ? 'block' : 'none';
+      
+//       // 如果显示,聚焦到输入框
+//       if (replyBox.style.display === 'block') {
+//         const commentInput = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
+//         if (commentInput) commentInput.focus();
+//       }
+//     }
+//   };
+
+//   return (
+//     <div className="friend-moments-container">
+//       <Header />
+//       <div className="fm-header">
+//         <button className="create-btn" onClick={() => setShowModal(true)}>
+//           <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
+//           创建动态
+//         </button>
+//       </div>
+
+//       <div className="feed-list">
+//         {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
+//                   className="user-avatar"
+//                   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={formatImageUrl(feed.imageUrl)} alt="动态图片" />
+//                   ) : (
+//                     feed.imageUrl.map((url, i) => (
+//                       <img key={i} src={formatImageUrl(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={() => toggleReplyBox(feed.postNo)}
+//                   >
+//                     <Comment theme="outline" size="24" fill="#333" />
+//                     <span>评论</span>
+//                   </button>
+//                 </div>
+                
+//                 {feed.user_id === userId && (
+//                   <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
+//                     删除
+//                   </button>
+//                 )}
+//               </div>
+
+//               {/* 动态的评论输入框 */}
+//               <div id={`reply-box-${feed.postNo}-null`} className="comment-box" style={{display: 'none'}}>
+//                 <textarea
+//                   id={`comment-input-${feed.postNo}-null`}
+//                   className="comment-input"
+//                   placeholder="请输入评论内容..."
+//                 />
+//                 <button
+//                   className="submit-comment-btn"
+//                   onClick={() => handleComment(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={comment.id || index}>
+//                         <div className="comment-header">
+//                           <span className="comment-user">{comment.username || '用户'}</span>
+//                           <span className="comment-time">
+//                             {new Date(comment.time || Date.now()).toLocaleString()}
+//                           </span>
+//                         </div>
+//                         <p className="comment-content">
+//                           {/* 显示回复格式 */}
+//                           {comment.reply_to_username ? 
+//                             <span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> : 
+//                             <span>{comment.username}:</span>
+//                           }
+//                           {comment.content}
+//                         </p>
+//                         <button 
+//                           className="reply-btn" 
+//                           onClick={() => toggleReplyBox(feed.postNo, comment.id || index, comment.username)}
+//                         >
+//                           回复
+//                         </button>
+                        
+//                         {/* 该评论的回复框 */}
+//                         <div id={`reply-box-${feed.postNo}-${comment.id || index}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
+//                           <textarea
+//                             id={`comment-input-${feed.postNo}-${comment.id || index}`}
+//                             className="comment-input"
+//                             placeholder={`回复 ${comment.username}...`}
+//                           />
+//                           <button
+//                             className="submit-comment-btn"
+//                             onClick={() => handleComment(feed.postNo, comment.id || index, comment.username)}
+//                           >
+//                             发布回复
+//                           </button>
+//                         </div>
+                        
+//                         {/* 嵌套回复 */}
+//                         {Array.isArray(comment.replies) && comment.replies.length > 0 && (
+//                           <div className="nested-replies">
+//                             {comment.replies.map((reply, replyIndex) => (
+//                               <div className="reply-item" key={reply.id || `${comment.id || index}-${replyIndex}`}>
+//                                 <p className="reply-content">
+//                                   {reply.reply_to_username ? 
+//                                     <span className="reply-prefix">{reply.username} 回复 {reply.reply_to_username}:</span> : 
+//                                     <span>{reply.username}:</span>
+//                                   }
+//                                   {reply.content}
+//                                 </p>
+//                                 <button 
+//                                   className="reply-btn" 
+//                                   onClick={() => toggleReplyBox(feed.postNo, reply.id || `${comment.id || index}-${replyIndex}`, reply.username)}
+//                                 >
+//                                   回复
+//                                 </button>
+                                
+//                                 {/* 该回复的回复框 */}
+//                                 <div id={`reply-box-${feed.postNo}-${reply.id || `${comment.id || index}-${replyIndex}`}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
+//                                   <textarea
+//                                     id={`comment-input-${feed.postNo}-${reply.id || `${comment.id || index}-${replyIndex}`}`}
+//                                     className="comment-input"
+//                                     placeholder={`回复 ${reply.username}...`}
+//                                   />
+//                                   <button
+//                                     className="submit-comment-btn"
+//                                     onClick={() => handleComment(feed.postNo, reply.id || `${comment.id || index}-${replyIndex}`, reply.username)}
+//                                   >
+//                                     发布回复
+//                                   </button>
+//                                 </div>
+//                               </div>
+//                             ))}
+//                           </div>
+//                         )}
+//                       </div>
+//                     ))}
+//                   </div>
+//                 </div>
+//               )}
+//             </div>
+//           ))
+//         )}
+//       </div>
+
+//       {/* Modal 对话框 */}
+//       {showModal && (
+//         <div className="modal-overlay" onClick={() => setShowModal(false)}>
+//           <div className="modal-dialog" onClick={e => e.stopPropagation()}>
+//             <h3>发布新动态</h3>
+//             <input
+//               type="text"
+//               placeholder="标题"
+//               value={title}
+//               onChange={e => setTitle(e.target.value)}
+//             />
+//             <textarea
+//               placeholder="写下你的内容..."
+//               value={content}
+//               onChange={e => setContent(e.target.value)}
+//             />
+//             <label className="file-label">
+//               选择图片
+//               <input
+//                 type="file"
+//                 accept="image/*"
+//                 multiple
+//                 onChange={handleImageChange}
+//                 style={{ display: 'none' }}
+//               />
+//             </label>
+//             <div className="cf-preview">
+//               {previewUrls.map((url, i) => (
+//                 <img key={i} src={url} alt={`预览${i}`} />
+//               ))}
+//             </div>
+//             <div className="modal-actions">
+//               <button className="btn cancel" onClick={() => setShowModal(false)}>
+//                 取消
+//               </button>
+//               <button className="btn submit" onClick={handleSubmit}>
+//                 发布
+//               </button>
+//             </div>
+//           </div>
+//         </div>
+//       )}
+//     </div>
+//   );
+// };
+
+// export default FriendMoments;
+// // FriendMoments.js
+// import React, { useContext, useState, useEffect } from 'react'; 
+// import axios from 'axios';
+// import './FriendMoments.css';
+// import Header from '../../components/Header';
+// import { Edit, GoodTwo, Comment } from '@icon-park/react';
+// import { UserContext } from '../../context/UserContext'; // 引入用户上下文
+
+// // 修改后的封面图 URL 拼接函数
+// const formatImageUrl = (url) => {
+//   if (!url) return '';
+//   const filename = url.split('/').pop(); // 提取文件名部分
+//   return `http://localhost:5011/uploads/dynamic/${filename}`;
+// };
+
+// const FriendMoments = () => {
+//   const [feeds, setFeeds] = useState([]);
+//   const [filteredFeeds, setFilteredFeeds] = useState([]);
+//   const [query, setQuery] = useState('');
+//   const [loading, setLoading] = useState(true);
+//   const [error, setError] = useState(null);
+
+//   // 从上下文中获取用户信息
+//   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([]);
+
+//   // 检查用户是否已登录
+//   const isLoggedIn = !!userId;
+
+//   // 拉取好友动态列表
+//   const fetchFeeds = async () => {
+//     if (!isLoggedIn) {
+//       setLoading(false);
+//       setError('请先登录');
+//       return;
+//     }
+
+//     setLoading(true);
+//     setError(null);
+//     try {
+//       // 注意这里修改了API路径,使用getAllDynamics接口
+//       const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
+      
+//       // 检查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);
+//       setError('获取动态列表失败,请稍后重试');
+//     } finally {
+//       setLoading(false);
+//     }
+//   };
+
+//   useEffect(() => {
+//     fetchFeeds();
+//   }, [userId]);
+
+//   // 搜索处理
+//   const handleSearch = () => {
+//     const q = query.trim().toLowerCase();
+//     if (!q) {
+//       setFilteredFeeds(feeds);
+//       return;
+//     }
+//     setFilteredFeeds(
+//       feeds.filter(f => 
+//         (f.title || '').toLowerCase().includes(q) || 
+//         (f.postContent || '').toLowerCase().includes(q)
+//       )
+//     );
+//   };
+
+//   const handleReset = () => {
+//     setQuery('');
+//     setFilteredFeeds(feeds);
+//   };
+
+//   // 对话框内:处理图片选择
+//   const handleImageChange = (e) => {
+//     const files = Array.from(e.target.files);
+//     if (!files.length) return;
+    
+//     const previewUrls = files.map(file => URL.createObjectURL(file));
+    
+//     setSelectedImages(files);
+//     setPreviewUrls(previewUrls);
+//   };
+
+//   // 对话框内:提交新动态
+//   const handleSubmit = async () => {
+//     if (!isLoggedIn) {
+//       alert('请先登录');
+//       return;
+//     }
+
+//     if (!content.trim()) {
+//       alert('内容不能为空');
+//       return;
+//     }
+
+//     try {
+//       // 使用formData格式提交
+//       const formData = new FormData();
+//       formData.append('title', title.trim() || '');
+//       formData.append('content', content.trim());
+      
+//       // 添加图片文件
+//       selectedImages.forEach((file, index) => {
+//         formData.append('image_url', file);
+//       });
+
+//       // 调用创建动态API
+//       await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
+//         headers: {
+//           'Content-Type': 'multipart/form-data'
+//         }
+//       });
+
+//       // 重置表单
+//       setTitle('');
+//       setContent('');
+//       setSelectedImages([]);
+//       setPreviewUrls([]);
+//       setShowModal(false);
+//       fetchFeeds();
+//       alert('发布成功');
+//     } catch (err) {
+//       console.error('发布失败', err);
+//       alert('发布失败,请稍后重试');
+//     }
+//   };
+
+//   // 删除动态 - 注意:API文档中未提供删除接口,这里保留原代码
+//   const handleDelete = async (dynamicId) => {
+  
+//     if (!isLoggedIn) {
+//       alert('请先登录');
+//       return;
+//     }
+
+//     if (!window.confirm('确定要删除这条动态吗?')) return;
+//     try {
+//       // 注意:API文档中未提供删除接口,这里使用原代码中的路径
+//       await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
+//       fetchFeeds();
+//       alert('删除成功');
+//     } catch (err) {
+//       console.error('删除失败', err);
+//       alert('删除失败,请稍后重试');
+//     }
+//   };
+
+//   // 点赞动态
+//   const handleLike = async (dynamicId, islike) => {
+//     if (islike) {
+//       handleUnlike(dynamicId);
+//       return
+//     }
+//     if (!isLoggedIn) {
+//       alert('请先登录');
+//       return;
+//     }
+
+//     // 验证dynamicId是否有效
+//     if (!dynamicId) {
+//       console.error('无效的dynamicId:', dynamicId);
+//       alert('点赞失败:动态ID无效');
+//       return;
+//     }
+
+//     console.log('当前用户ID:', userId);
+//     console.log('即将点赞的动态ID:', dynamicId);
+    
+//     try {
+//       // 确保参数是整数类型
+//       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) {
+//         // 更新本地状态
+//         feeds.forEach(feed => {
+//           if (feed.postNo === dynamicId) {
+//             feed.postLikeNum = (feed.postLikeNum || 0) + 1;
+//             feed.liked = true;
+//           }
+//         });
+//         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 {
+//       // 确保参数是整数类型
+//       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`, {
+//         headers: {
+//           'Content-Type': 'application/json' // 明确指定JSON格式
+//         },
+//         data: requestData // 将参数放在data属性中
+//       });
+      
+//       console.log('取消点赞API响应:', res.data);
+      
+//       if (res.status === 200) {
+//         // 更新本地状态
+//         feeds.forEach(feed => {
+//           if (feed.postNo === dynamicId) {
+//             feed.postLikeNum = Math.max(0, (feed.postLikeNum || 0) - 1);
+//             feed.liked = false;
+//           }
+//         });
+//         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, parentCommentId = null, replyToUsername = '') => {
+//     if (!isLoggedIn) {
+//       alert('请先登录');
+//       return;
+//     }
+
+//     const commentInputRef = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
+//     if (!commentInputRef || !commentInputRef.value.trim()) {
+//       alert('评论内容不能为空');
+//       return;
+//     }
+
+//     const commentContent = commentInputRef.value.trim();
+
+//     try {
+//       // 准备请求数据
+//       const requestData = {
+//         content: commentContent
+//       };
+      
+//       // 如果是回复,添加parent_comment_id
+//       if (parentCommentId) {
+//         requestData.parent_comment_id = parentCommentId;
+//       }
+      
+//       const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, requestData);
+
+//       if (res.status === 200 || res.status === 201) {
+//         // 成功获取评论数据
+//         const newComment = {
+//           user_id: userId,
+//           username: username,
+//           content: commentContent,
+//           time: new Date().toISOString(), // 使用当前时间作为评论时间
+//           // 如果是回复,添加parent_comment_id和reply_to_username
+//           ...(parentCommentId && { parent_comment_id: parentCommentId }),
+//           ...(replyToUsername && { reply_to_username: replyToUsername })
+//         };
+
+//         // 更新本地状态,添加新评论
+//         setFeeds(prevFeeds => {
+//           return prevFeeds.map(feed => {
+//             if (feed.postNo === dynamicId) {
+//               // 确保comments是数组,并且正确合并新评论
+//               const currentComments = Array.isArray(feed.comments) ? feed.comments : [];
+              
+//               if (parentCommentId) {
+//                 // 查找父评论并添加回复
+//                 return {
+//                   ...feed,
+//                   comments: currentComments.map(comment => {
+//                     if (comment.id === parentCommentId || comment.postNo === parentCommentId) {
+//                       // 如果父评论已有replies数组,添加到其中
+//                       if (Array.isArray(comment.replies)) {
+//                         return {
+//                           ...comment,
+//                           replies: [...comment.replies, newComment]
+//                         };
+//                       } else {
+//                         // 否则创建新的replies数组
+//                         return {
+//                           ...comment,
+//                           replies: [newComment]
+//                         };
+//                       }
+//                     }
+//                     return comment;
+//                   })
+//                 };
+//               } else {
+//                 // 普通评论,添加到评论列表
+//                 return {
+//                   ...feed,
+//                   comments: [...currentComments, newComment]
+//                 };
+//               }
+//             }
+//             return feed;
+//           });
+//         });
+
+//         // 清空输入框
+//         if (commentInputRef) {
+//           commentInputRef.value = '';
+//         }
+        
+//         // 隐藏回复框
+//         toggleReplyBox(dynamicId, parentCommentId);
+//       } else {
+//         alert(res.data.error || '评论失败');
+//       }
+//     } catch (err) {
+//       console.error('评论失败', err);
+//       alert('评论失败,请稍后重试');
+//     }
+//   };
+
+//   // 切换回复框显示状态
+//   const toggleReplyBox = (dynamicId, parentCommentId = null) => {
+//     const replyBoxId = `reply-box-${dynamicId}-${parentCommentId}`;
+//     const replyBox = document.getElementById(replyBoxId);
+    
+//     if (replyBox) {
+//       replyBox.style.display = replyBox.style.display === 'none' ? 'block' : 'none';
+      
+//       // 如果显示,聚焦到输入框
+//       if (replyBox.style.display === 'block') {
+//         const commentInput = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
+//         if (commentInput) commentInput.focus();
+//       }
+//     }
+//   };
+
+//   return (
+//     <div className="friend-moments-container">
+//       <Header />
+//       <div className="fm-header">
+//         <button className="create-btn" onClick={() => setShowModal(true)}>
+//           <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
+//           创建动态
+//         </button>
+//       </div>
+
+//       <div className="feed-list">
+//         {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
+//                   className="user-avatar"
+//                   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={formatImageUrl(feed.imageUrl)} alt="动态图片" />
+//                   ) : (
+//                     feed.imageUrl.map((url, i) => (
+//                       <img key={i} src={formatImageUrl(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={() => toggleReplyBox(feed.postNo)}
+//                   >
+//                     <Comment theme="outline" size="24" fill="#333" />
+//                     <span>评论</span>
+//                   </button>
+//                 </div>
+                
+//                 {feed.user_id === userId && (
+//                   <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
+//                     删除
+//                   </button>
+//                 )}
+//               </div>
+
+//               {/* 动态的评论输入框 */}
+//               <div id={`reply-box-${feed.postNo}-null`} className="comment-box" style={{display: 'none'}}>
+//                 <textarea
+//                   id={`comment-input-${feed.postNo}-null`}
+//                   className="comment-input"
+//                   placeholder="请输入评论内容..."
+//                 />
+//                 <button
+//                   className="submit-comment-btn"
+//                   onClick={() => handleComment(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-time">
+//                             {new Date(comment.time || Date.now()).toLocaleString()}
+//                           </span>
+//                         </div>
+//                         <p className="comment-content">
+//                           {/* 显示回复格式 */}
+//                           {comment.reply_to_username ? 
+//                             <span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> : 
+//                             <span>{comment.username}:</span>
+//                           }
+//                           {comment.content}
+//                         </p>
+//                         <button 
+//                           className="reply-btn" 
+//                           onClick={() => toggleReplyBox(feed.postNo, comment.id || index)}
+//                         >
+//                           回复
+//                         </button>
+                        
+//                         {/* 该评论的回复框 */}
+//                         <div id={`reply-box-${feed.postNo}-${comment.id || index}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
+//                           <textarea
+//                             id={`comment-input-${feed.postNo}-${comment.id || index}`}
+//                             className="comment-input"
+//                             placeholder={`回复 ${comment.username}...`}
+//                           />
+//                           <button
+//                             className="submit-comment-btn"
+//                             onClick={() => handleComment(feed.postNo, comment.id || index, comment.username)}
+//                           >
+//                             发布回复
+//                           </button>
+//                         </div>
+                        
+//                         {/* 嵌套回复 */}
+//                         {Array.isArray(comment.replies) && comment.replies.length > 0 && (
+//                           <div className="nested-replies">
+//                             {comment.replies.map((reply, replyIndex) => (
+//                               <div className="reply-item" key={replyIndex}>
+//                                 <p className="reply-content">
+//                                   {reply.reply_to_username ? 
+//                                     <span className="reply-prefix">{reply.username} 回复 {reply.reply_to_username}:</span> : 
+//                                     <span>{reply.username}:</span>
+//                                   }
+//                                   {reply.content}
+//                                 </p>
+//                                 <button 
+//                                   className="reply-btn" 
+//                                   onClick={() => toggleReplyBox(feed.postNo, reply.id || `${index}-${replyIndex}`, reply.username)}
+//                                 >
+//                                   回复
+//                                 </button>
+                                
+//                                 {/* 该回复的回复框 */}
+//                                 <div id={`reply-box-${feed.postNo}-${reply.id || `${index}-${replyIndex}`}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
+//                                   <textarea
+//                                     id={`comment-input-${feed.postNo}-${reply.id || `${index}-${replyIndex}`}`}
+//                                     className="comment-input"
+//                                     placeholder={`回复 ${reply.username}...`}
+//                                   />
+//                                   <button
+//                                     className="submit-comment-btn"
+//                                     onClick={() => handleComment(feed.postNo, reply.id || `${index}-${replyIndex}`, reply.username)}
+//                                   >
+//                                     发布回复
+//                                   </button>
+//                                 </div>
+//                               </div>
+//                             ))}
+//                           </div>
+//                         )}
+//                       </div>
+//                     ))}
+//                   </div>
+//                 </div>
+//               )}
+//             </div>
+//           ))
+//         )}
+//       </div>
+
+//       {/* Modal 对话框 */}
+//       {showModal && (
+//         <div className="modal-overlay" onClick={() => setShowModal(false)}>
+//           <div className="modal-dialog" onClick={e => e.stopPropagation()}>
+//             <h3>发布新动态</h3>
+//             <input
+//               type="text"
+//               placeholder="标题"
+//               value={title}
+//               onChange={e => setTitle(e.target.value)}
+//             />
+//             <textarea
+//               placeholder="写下你的内容..."
+//               value={content}
+//               onChange={e => setContent(e.target.value)}
+//             />
+//             <label className="file-label">
+//               选择图片
+//               <input
+//                 type="file"
+//                 accept="image/*"
+//                 multiple
+//                 onChange={handleImageChange}
+//                 style={{ display: 'none' }}
+//               />
+//             </label>
+//             <div className="cf-preview">
+//               {previewUrls.map((url, i) => (
+//                 <img key={i} src={url} alt={`预览${i}`} />
+//               ))}
+//             </div>
+//             <div className="modal-actions">
+//               <button className="btn cancel" onClick={() => setShowModal(false)}>
+//                 取消
+//               </button>
+//               <button className="btn submit" onClick={handleSubmit}>
+//                 发布
+//               </button>
+//             </div>
+//           </div>
+//         </div>
+//       )}
+//     </div>
+//   );
+// };
+
+// export default FriendMoments; 
+
+
+// FriendMoments.js
 import React, { useContext, useState, useEffect } from 'react'; 
 import axios from 'axios';
 import './FriendMoments.css';
@@ -19,6 +1358,8 @@
   const [loading, setLoading] = useState(true);
   const [error, setError] = useState(null);
   const [commentBoxVisibleId, setCommentBoxVisibleId] = useState(null); // 当前显示评论框的动态ID
+  const [replyToCommentId, setReplyToCommentId] = useState(null); // 当前回复的评论ID
+  const [replyToUsername, setReplyToUsername] = useState(''); // 当前回复的用户名
   const [commentInput, setCommentInput] = useState(''); // 当前输入的评论内容
 
   // 从上下文中获取用户信息
@@ -181,7 +1522,7 @@
   };
 
   // 点赞动态
-  const handleLike = async (dynamicId,islike) => {
+  const handleLike = async (dynamicId, islike) => {
     if (islike) {
       handleUnlike(dynamicId);
       return
@@ -198,7 +1539,6 @@
       return;
     }
 
-
     console.log('当前用户ID:', userId);
     console.log('即将点赞的动态ID:', dynamicId);
     
@@ -325,73 +1665,103 @@
   };
 
   // 评论好友动态
-  // 评论好友动态
-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 || '评论失败');
+  const handleComment = async (dynamicId) => {
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
     }
-  } catch (err) {
-    console.error('评论失败', err);
-    alert('评论失败,请稍后重试');
-  }
-};
+
+    if (!commentInput.trim()) {
+      alert('评论内容不能为空');
+      return;
+    }
+
+    try {
+      // 准备请求数据
+      const requestData = {
+        content: commentInput.trim()
+      };
+      
+      // 如果是回复,添加parent_comment_id
+      if (replyToCommentId) {
+        requestData.parent_comment_id = replyToCommentId;
+      }
+      
+      const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, requestData);
+
+      if (res.status === 200 || res.status === 201) {
+        // 成功获取评论数据
+        const newComment = {
+          user_id: userId,
+          username: username,
+          content: commentInput.trim(),
+          time: new Date().toISOString(), // 使用当前时间作为评论时间
+          // 如果是回复,添加parent_comment_id和reply_to_username
+          ...(replyToCommentId && { parent_comment_id: replyToCommentId }),
+          ...(replyToUsername && { reply_to_username: replyToUsername })
+        };
+
+        // 更新本地状态,添加新评论
+        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;
+          });
+        });
+
+        // 清空回复状态
+        setReplyToCommentId(null);
+        setReplyToUsername('');
+        setCommentInput('');
+        setCommentBoxVisibleId(null); // 关闭评论框
+      } else {
+        alert(res.data.error || '评论失败');
+      }
+    } catch (err) {
+      console.error('评论失败', err);
+      alert('评论失败,请稍后重试');
+    }
+  };
+
+  // 切换回复框显示状态
+  const toggleReplyBox = (dynamicId, commentId = null, username = '') => {
+    // 如果点击的是当前正在回复的评论,关闭回复框
+    if (commentBoxVisibleId === dynamicId && replyToCommentId === commentId) {
+      setCommentBoxVisibleId(null);
+      setReplyToCommentId(null);
+      setReplyToUsername('');
+      setCommentInput('');
+      return;
+    }
+    
+    // 显示回复框,设置回复目标
+    setCommentBoxVisibleId(dynamicId);
+    setReplyToCommentId(commentId);
+    setReplyToUsername(username);
+    setCommentInput(username ? `回复 ${username}: ` : '');
+  };
 
   return (
     <div className="friend-moments-container">
@@ -419,11 +1789,11 @@
             <div className="feed-item" key={feed.postNo || `feed-${Math.random()}`}>
               {/* 显示发布者信息 */}
               <div className="feed-author">
-              <img
-                className="user-avatar"
-                src={feed.avatar_url || 'https://example.com/default-avatar.jpg'}
-                alt={feed.username || '用户头像'}
-              />
+                <img
+                  className="user-avatar"
+                  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>
@@ -445,49 +1815,48 @@
                 </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={() => 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('');
+                      toggleReplyBox(feed.postNo);
                     }}
                   >
                     <Comment theme="outline" size="24" fill="#333" />
                     <span>评论</span>
                   </button>
+                </div>
+                
+                {feed.user_id === userId && (
+                  <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
+                    删除
+                  </button>
+                )}
+              </div>
 
-    {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>
+              {/* 评论输入框 */}
+              {commentBoxVisibleId === feed.postNo && (
+                <div className="comment-box">
+                  <textarea
+                    className="comment-input"
+                    placeholder={replyToUsername ? `回复 ${replyToUsername}...` : '请输入评论内容...'}
+                    value={commentInput}
+                    onChange={(e) => setCommentInput(e.target.value)}
+                  />
+                  <button
+                    className="submit-comment-btn"
+                    onClick={() => handleComment(feed.postNo)}
+                  >
+                    发布评论
+                  </button>
+                </div>
+              )}
 
               {/* 评论列表 */}
               {Array.isArray(feed.comments) && feed.comments.length > 0 && (
@@ -498,18 +1867,52 @@
                       <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>
+                        <p className="comment-content">
+                          {/* 显示回复格式 */}
+                          {comment.reply_to_username ? 
+                            <span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> : 
+                            <span>{comment.username}:</span>
+                          }
+                          {comment.content}
+                        </p>
+                        <button 
+                          className="reply-btn" 
+                          onClick={() => toggleReplyBox(feed.postNo, comment.id || index, comment.username)}
+                        >
+                          回复
+                        </button>
+                        
+                        {/* 嵌套回复 */}
+                        {Array.isArray(comment.replies) && comment.replies.length > 0 && (
+                          <div className="nested-replies">
+                            {comment.replies.map((reply, replyIndex) => (
+                              <div className="reply-item" key={replyIndex}>
+                                <p className="reply-content">
+                                  {reply.reply_to_username ? 
+                                    <span className="reply-prefix">{reply.username} 回复 {reply.reply_to_username}:</span> : 
+                                    <span>{reply.username}:</span>
+                                  }
+                                  {reply.content}
+                                </p>
+                                <button 
+                                  className="reply-btn" 
+                                  onClick={() => toggleReplyBox(feed.postNo, reply.id || `${index}-${replyIndex}`, reply.username)}
+                                >
+                                  回复
+                                </button>
+                              </div>
+                            ))}
+                          </div>
+                        )}
                       </div>
                     ))}
                   </div>
                 </div>
               )}
-
             </div>
           ))
         )}
@@ -561,4 +1964,4 @@
   );
 };
 
-export default FriendMoments;  
\ No newline at end of file
+export default FriendMoments;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/CommentForm.css b/src/pages/InterestGroup/CommentForm.css
new file mode 100644
index 0000000..7d80eec
--- /dev/null
+++ b/src/pages/InterestGroup/CommentForm.css
@@ -0,0 +1,100 @@
+/* CommentForm.css */
+.comment-form-container {
+  margin-top: 1rem;
+  padding: 1rem;
+  background-color: #f8f4e9; /* 米白色背景 */
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  transition: all 0.3s ease;
+}
+
+.comment-form {
+  display: flex;
+  flex-direction: column;
+}
+
+.form-group {
+  position: relative;
+  margin-bottom: 1rem;
+}
+
+.comment-input {
+  width: 100%;
+  min-height: 80px;
+  padding: 1rem;
+  border: 1px solid #e6d5b8; /* 米棕色边框 */
+  border-radius: 6px;
+  background-color: #fff;
+  font-size: 1rem;
+  line-height: 1.5;
+  resize: vertical;
+  transition: all 0.3s ease;
+  outline: none;
+}
+
+.comment-input:focus {
+  border-color: #d4a5a5; /* 粉色边框 */
+  box-shadow: 0 0 0 3px rgba(212, 165, 165, 0.2); /* 粉色阴影 */
+}
+
+.floating-label {
+  position: absolute;
+  top: -8px;
+  left: 12px;
+  padding: 0 4px;
+  background-color: #fff;
+  color: #8c7a51; /* 深棕色文本 */
+  font-size: 0.875rem;
+  transition: all 0.2s ease;
+  pointer-events: none;
+  opacity: 0;
+  transform: translateY(10px);
+}
+
+.form-group.focused .floating-label,
+.comment-input:not(:placeholder-shown) + .floating-label {
+  opacity: 1;
+  transform: translateY(0);
+}
+
+.form-actions {
+  display: flex;
+  justify-content: flex-end;
+  gap: 0.75rem;
+}
+
+.cancel-button,
+.submit-button {
+  padding: 0.5rem 1.25rem;
+  border: none;
+  border-radius: 4px;
+  font-size: 0.9rem;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.cancel-button {
+  background-color: transparent;
+  color: #8c7a51; /* 深棕色文本 */
+}
+
+.cancel-button:hover {
+  background-color: #f5f5f5;
+}
+
+.submit-button {
+  background-color: #d4a5a5; /* 粉色背景 */
+  color: #fff;
+}
+
+.submit-button:hover {
+  background-color: #c28d8d; /* 深粉色 */
+  transform: translateY(-1px);
+  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+}
+
+.submit-button:disabled {
+  background-color: #e6d5b8; /* 米棕色 */
+  cursor: not-allowed;
+}
\ No newline at end of file
diff --git a/src/pages/InterestGroup/CommentForm.jsx b/src/pages/InterestGroup/CommentForm.jsx
new file mode 100644
index 0000000..1d85a0c
--- /dev/null
+++ b/src/pages/InterestGroup/CommentForm.jsx
@@ -0,0 +1,53 @@
+import React, { useState } from 'react';
+import './CommentForm.css';
+
+const CommentForm = ({ onSubmit, onCancel }) => {
+  const [content, setContent] = useState('');
+  const [isFocused, setIsFocused] = useState(false);
+
+  const handleSubmit = (e) => {
+    e.preventDefault();
+    if (content.trim()) {
+      onSubmit(content);
+      setContent('');
+    }
+  };
+
+  return (
+    <div className="comment-form-container">
+      <form className="comment-form" onSubmit={handleSubmit}>
+        <div className={`form-group ${isFocused ? 'focused' : ''}`}>
+          <textarea
+            className="comment-input"
+            placeholder="分享你的想法..."
+            value={content}
+            onChange={(e) => setContent(e.target.value)}
+            onFocus={() => setIsFocused(true)}
+            onBlur={() => setIsFocused(false)}
+            required
+          />
+          <div className="floating-label">添加评论</div>
+        </div>
+        
+        <div className="form-actions">
+          <button 
+            type="button" 
+            className="cancel-button"
+            onClick={onCancel}
+          >
+            取消
+          </button>
+          <button 
+            type="submit" 
+            className="submit-button"
+            disabled={!content.trim()}
+          >
+            发布评论
+          </button>
+        </div>
+      </form>
+    </div>
+  );
+};
+
+export default CommentForm;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/CreatePostForm.jsx b/src/pages/InterestGroup/CreatePostForm.jsx
index 6848b54..ce80a0a 100644
--- a/src/pages/InterestGroup/CreatePostForm.jsx
+++ b/src/pages/InterestGroup/CreatePostForm.jsx
@@ -1,29 +1,218 @@
-import React, { useState } from 'react';
+// import React, { useState } from 'react';
+// import { useGroupStore } from '../../context/useGroupStore';
+
+// const CreatePostForm = ({ groupId, onClose, onPostCreated }) => {
+//   const { userId, handleCreatePost } = useGroupStore();
+//   const [title, setTitle] = useState('');
+//   const [content, setContent] = useState('');
+//   const [images, setImages] = useState([]);
+//   const [loading, setLoading] = useState(false);
+//   const [error, setError] = useState('');
+//   const [formError, setFormError] = useState({});
+
+//   // 表单验证
+//   const validateForm = () => {
+//     const errors = {};
+//     let isValid = true;
+    
+//     if (!title.trim()) {
+//       errors.title = '请输入帖子标题';
+//       isValid = false;
+//     }
+    
+//     if (!content.trim()) {
+//       errors.content = '请输入帖子内容';
+//       isValid = false;
+//     }
+    
+//     setFormError(errors);
+//     return isValid;
+//   };
+
+//   const handleSubmit = async (e) => {
+//     e.preventDefault();
+    
+//     // 先进行表单验证
+//     if (!validateForm()) {
+//       return;
+//     }
+    
+//     console.log('点击发布,准备发送请求');
+//     setLoading(true);
+//     setError('');
+
+//     try {
+//       // 检查必要条件
+//       if (!groupId) {
+//         throw new Error('小组ID缺失');
+//       }
+      
+//       if (!userId) {
+//         throw new Error('用户ID缺失,请先登录');
+//       }
+      
+//       // 打印关键变量进行调试
+//       console.log('准备发布帖子:', {
+//         groupId,
+//         userId,
+//         title,
+//         content,
+//         imagesCount: images.length
+//       });
+      
+//       // 调用创建帖子的方法
+//       const success = await handleCreatePost(groupId, userId, content, title, images);
+      
+//       if (success) {
+//         alert('帖子发布成功');
+//         onPostCreated();  // 触发刷新
+//         onClose();        // 关闭弹窗
+//       } else {
+//         setError('帖子发布失败,请重试');
+//       }
+//     } catch (error) {
+//       console.error('发布帖子错误:', error);
+//       setError(error.message || '帖子发布失败');
+//     } finally {
+//       setLoading(false);
+//     }
+//   };
+
+//   return (
+//     <div className="create-post-form">
+//       <h4>发布新帖子</h4>
+      
+//       <div className="form-group">
+//         <input
+//           type="text"
+//           placeholder="帖子标题"
+//           value={title}
+//           onChange={(e) => setTitle(e.target.value)}
+//           required
+//         />
+//         {formError.title && <p className="error-message">{formError.title}</p>}
+//       </div>
+      
+//       <div className="form-group">
+//         <textarea
+//           placeholder="帖子内容"
+//           value={content}
+//           onChange={(e) => setContent(e.target.value)}
+//           required
+//         />
+//         {formError.content && <p className="error-message">{formError.content}</p>}
+//       </div>
+      
+//       <div className="form-group">
+//         <input
+//           type="file"
+//           multiple
+//           onChange={(e) => setImages(e.target.files)}
+//         />
+//       </div>
+      
+//       {error && <p className="error-message">{error}</p>}
+      
+//       <div className="button-group">
+//         <button onClick={handleSubmit} disabled={loading}>
+//           {loading ? '发布中...' : '发布'}
+//         </button>
+//         <button onClick={onClose} disabled={loading}>
+//           取消
+//         </button>
+//       </div>
+//     </div>
+//   );
+// };
+
+// export default CreatePostForm;
+
+import React, { useState, useEffect } from 'react';
+import { useUser } from '../../context/UserContext';
 import { useGroupStore } from '../../context/useGroupStore';
 
-const CreatePostForm = ({ groupId, onClose }) => {
-  const { userId, handleCreatePost } = useGroupStore();
+const CreatePostForm = ({ groupId, onClose, onPostCreated }) => {
+  const { user, loading: userLoading } = useUser();
+  const { handleCreatePost } = useGroupStore();
+  
   const [title, setTitle] = useState('');
   const [content, setContent] = useState('');
   const [images, setImages] = useState([]);
   const [loading, setLoading] = useState(false);
   const [error, setError] = useState('');
+  const [formError, setFormError] = useState({});
+
+  // 处理用户状态加载中或未登录的情况
+  if (userLoading) {
+    return <div className="create-post-form loading">加载用户信息...</div>;
+  }
+
+  if (!user) {
+    return (
+      <div className="create-post-form">
+        <div className="error-message">请先登录以发布帖子</div>
+        <button className="close-btn" onClick={onClose}>
+          关闭
+        </button>
+      </div>
+    );
+  }
+
+  // 表单验证
+  const validateForm = () => {
+    const errors = {};
+    let isValid = true;
+    
+    if (!title.trim()) {
+      errors.title = '请输入帖子标题';
+      isValid = false;
+    }
+    
+    if (!content.trim()) {
+      errors.content = '请输入帖子内容';
+      isValid = false;
+    }
+    
+    setFormError(errors);
+    return isValid;
+  };
 
   const handleSubmit = async (e) => {
     e.preventDefault();
+    
+    if (!validateForm()) {
+      return;
+    }
+    
+    console.log('点击发布,准备发送请求');
     setLoading(true);
     setError('');
 
     try {
-      const success = await handleCreatePost(groupId, userId, content, title, images);
+      if (!groupId) {
+        throw new Error('小组ID缺失');
+      }
+      
+      console.log('准备发布帖子:', {
+        groupId,
+        userId: user.userId,
+        title,
+        content,
+        imagesCount: images.length
+      });
+      
+      // 调用创建帖子方法,不再传递 userId 参数
+      const success = await handleCreatePost(groupId, content, title, images);
       
       if (success) {
         alert('帖子发布成功');
+        onPostCreated();
         onClose();
       } else {
-        setError('帖子发布失败');
+        setError('帖子发布失败,请重试');
       }
     } catch (error) {
+      console.error('发布帖子错误:', error);
       setError(error.message || '帖子发布失败');
     } finally {
       setLoading(false);
@@ -33,32 +222,44 @@
   return (
     <div className="create-post-form">
       <h4>发布新帖子</h4>
-      <input
-        type="text"
-        placeholder="帖子标题"
-        value={title}
-        onChange={(e) => setTitle(e.target.value)}
-        required
-      />
-      <textarea
-        placeholder="帖子内容"
-        value={content}
-        onChange={(e) => setContent(e.target.value)}
-        required
-      />
-      <input
-        type="file"
-        multiple
-        onChange={(e) => setImages(e.target.files)}
-      />
       
-      {error && <p className="error">{error}</p>}
+      <div className="form-group">
+        <input
+          type="text"
+          placeholder="帖子标题"
+          value={title}
+          onChange={(e) => setTitle(e.target.value)}
+          required
+        />
+        {formError.title && <div className="error-message">{formError.title}</div>}
+      </div>
+      
+      <div className="form-group">
+        <textarea
+          placeholder="帖子内容"
+          value={content}
+          onChange={(e) => setContent(e.target.value)}
+          required
+        />
+        {formError.content && <div className="error-message">{formError.content}</div>}
+      </div>
+      
+      <div className="form-group">
+        <label>上传图片:</label>
+        <input
+          type="file"
+          multiple
+          onChange={(e) => setImages(e.target.files)}
+        />
+      </div>
+      
+      {error && <div className="error-message">{error}</div>}
       
       <div className="button-group">
-        <button onClick={handleSubmit} disabled={loading}>
+        <button className="submit-btn" onClick={handleSubmit} disabled={loading}>
           {loading ? '发布中...' : '发布'}
         </button>
-        <button onClick={onClose} disabled={loading}>
+        <button className="cancel-btn" onClick={onClose} disabled={loading}>
           取消
         </button>
       </div>
diff --git a/src/pages/InterestGroup/GroupDetail.css b/src/pages/InterestGroup/GroupDetail.css
new file mode 100644
index 0000000..d1968d4
--- /dev/null
+++ b/src/pages/InterestGroup/GroupDetail.css
@@ -0,0 +1,335 @@
+.group-detail {
+  padding: 2rem;
+  background: #fdf7f2;
+  font-family: 'Segoe UI', sans-serif;
+  color: #5e4638;
+}
+
+.group-title {
+  font-size: 2rem;
+  margin-bottom: 1.5rem;
+  border-bottom: 2px solid #eacfc0;
+  padding-bottom: 0.5rem;
+}
+
+.group-section {
+  margin-top: 5%;
+}
+
+.member-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 1rem;
+}
+
+.member-card {
+  background: #fff2ef;
+  border: 1px solid #f3d9d4;
+  border-radius: 10px;
+  padding: 1rem;
+  width: 120px;
+  text-align: center;
+  box-shadow: 2px 2px 5px #f0cfc9;
+}
+
+.member-card img {
+  width: 60px;
+  height: 60px;
+  border-radius: 50%;
+  margin-bottom: 0.5rem;
+}
+
+.post-list {
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  margin-top: -2%;
+  margin-left: -1%;
+}
+
+.post-card {
+  background: #fffaf9;
+  border-left: 5px solid #d8a79e;
+  padding: 1rem;
+  border-radius: 8px;
+  box-shadow: 1px 1px 6px #e3ccc6;
+}
+
+.post-card h3 {
+  color: #b56b5c;
+  margin-bottom: 0.5rem;
+}
+
+.post-card span {
+  display: block;
+  font-size: 0.85rem;
+  color: #8c6f63;
+  margin-top: 0.25rem;
+}
+
+.like-count {
+  font-size: 5rem;
+  vertical-align: middle;
+  display: flex;
+  align-items: center;
+}
+
+
+.group-section h2 {
+  color: #555;
+  margin-top: 0;
+  border-bottom: 1px solid #eee;
+  padding-bottom: 10px;
+}
+
+
+.post-card {
+  border: 1px solid #eee;
+  border-radius: 6px;
+  padding: 15px;
+  transition: box-shadow 0.3s;
+}
+
+.post-card:hover {
+  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
+}
+
+/* .post-header {
+  margin-bottom: 10px;
+} */
+
+.post-title {
+  margin: 0 0 8px 0;
+  color: #333;
+  font-size: 1.1rem;
+}
+
+
+.author-avatar {
+  width: 70px;
+  height: 70px;
+  border-radius: 50%;
+  margin-right: 15px;
+  vertical-align: middle;
+}
+
+.comment-button:hover {
+  color: #40a9ff;
+}
+
+.comments-section {
+  margin-top: 15px;
+  padding-top: 15px;
+  border-top: 1px solid #eee;
+}
+
+.comments-title {
+  font-size: 1rem;
+  color: #666;
+  margin-bottom: 10px;
+}
+
+.comment-item {
+  margin-bottom: 15px;
+  padding-bottom: 10px;
+  border-bottom: 1px solid #f5f5f5;
+}
+
+.comment-header {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 5px;
+}
+
+.comment-avatar {
+  width: 35px;
+  height: 35px;
+  border-radius: 50%;
+}
+
+.comment-author {
+  font-weight: bold;
+  color: #333;
+}
+
+.comment-time {
+  font-size: 0.8rem;
+  color: #999;
+}
+
+.comment-content {
+  color: #555;
+  margin-left: 45px;
+}
+
+.empty-message {
+  color: #999;
+  text-align: center;
+  padding: 20px 0;
+}
+
+/* GroupDetail.css */
+.member-link {
+  text-decoration: none; /* 移除下划线 */
+  color: inherit; /* 继承父元素颜色 */
+  display: block; /* 使链接覆盖整个卡片 */
+}
+
+.member-card {
+  transition: transform 0.2s, box-shadow 0.2s;
+  cursor: pointer; /* 显示手型光标 */
+}
+
+.member-card:hover {
+  transform: translateY(-4px);
+  box-shadow: 0 8px 16px rgba(0,0,0,0.08);
+  border-color: #eacfc0; /* 悬停时边框颜色变化 */
+}
+
+.member-name {
+  margin-top: 8px;
+  white-space: nowrap; /* 防止名称换行 */
+  overflow: hidden;
+  text-overflow: ellipsis; /* 超出部分显示省略号 */
+}
+
+/* GroupDetail.css */
+.post-actions-bar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin: 20px 0;
+  padding: 10px;
+  background-color: #fff8f5;
+  border-radius: 6px;
+  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+}
+
+.create-post-btn {
+  background-color: #b56b5c;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  padding: 10px 16px;
+  font-size: 16px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s;
+  display: flex;
+  align-items: center;
+}
+
+.create-post-btn:hover {
+  background-color: #9c5a4c;
+  transform: translateY(-1px);
+  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
+}
+
+.create-post-btn:active {
+  transform: translateY(0);
+  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+}
+
+.login-hint {
+  color: #999;
+  font-style: italic;
+  margin: 0;
+}
+
+/* GroupDetail.css */
+.post-list-header {
+  margin-bottom:2%;
+}
+
+.create-post-btn {
+  background-color: #b56b5c;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  padding: 10px 16px;
+  font-size: 16px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s;
+  display: flex;
+  align-items: center;
+}
+
+.create-post-btn:hover {
+  background-color: #9c5a4c;
+  transform: translateY(-1px);
+  box-shadow: 0 2px 5px rgba(0,0,0,0.1);
+}
+
+.create-post-btn:active {
+  transform: translateY(0);
+  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+}
+
+.login-hint {
+  color: #999;
+  font-style: italic;
+  margin: 0;
+  padding: 8px 0;
+}
+
+/* 米棕色背景 + 深粉色按钮 */
+.create-post-btn {
+  background-color: #d36c6c;
+  color: #fff;
+  border: none;
+  padding: 8px 16px;
+  font-size: 16px;
+  border-radius: 8px;
+  cursor: pointer;
+  transition: background-color 0.3s;
+}
+
+.create-post-btn:hover {
+  background-color: #b45555;
+}
+
+/* 对话框背景遮罩 */
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(100, 80, 60, 0.6);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+/* 对话框内容区 */
+.modal-content {
+  background-color: #f5f0e6;
+  padding: 24px;
+  border-radius: 12px;
+  width: 90%;
+  max-width: 600px;
+  position: relative;
+  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
+  animation: fadeIn 0.3s ease-out;
+}
+
+/* 关闭按钮 */
+.modal-close {
+  position: absolute;
+  top: 10px;
+  right: 16px;
+  font-size: 24px;
+  background: none;
+  border: none;
+  color: #d36c6c;
+  cursor: pointer;
+}
+
+/* 动画效果 */
+@keyframes fadeIn {
+  from { opacity: 0; transform: scale(0.95); }
+  to { opacity: 1; transform: scale(1); }
+}
diff --git a/src/pages/InterestGroup/GroupDetail.jsx b/src/pages/InterestGroup/GroupDetail.jsx
new file mode 100644
index 0000000..18ea23e
--- /dev/null
+++ b/src/pages/InterestGroup/GroupDetail.jsx
@@ -0,0 +1,189 @@
+import React, { useEffect, useState } from 'react';
+import { useParams } from 'wouter';
+import { useUser } from '../../context/UserContext';
+import GroupMembers from './GroupMembers';
+import GroupPosts from './GroupPosts';
+import CreatePostForm from './CreatePostForm';
+import './GroupDetail.css';
+
+const GroupDetail = () => {
+  const { groupId } = useParams();
+  console.log('GroupDetail groupId:', groupId);
+  
+  const { user } = useUser();
+  const userId = user?.userId;
+
+  const [members, setMembers] = useState([]);
+  const [posts, setPosts] = useState([]);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(null);
+  const [showCommentForm, setShowCommentForm] = useState(null);
+  const [refetchKey, setRefetchKey] = useState(0);
+  const [showCreatePost, setShowCreatePost] = useState(false);
+  const [isMember, setIsMember] = useState(false);
+
+  useEffect(() => {
+    if (!groupId) {
+      setError('小组ID缺失');
+      setLoading(false);
+      return;
+    }
+    
+    const fetchGroupData = async () => {
+      try {
+        const res1 = await fetch(`/echo/groups/${groupId}/members`);
+        const membersData = await res1.json();
+
+        const res2 = await fetch(`/echo/groups/${groupId}/getAllPosts`);
+        const postsData = await res2.json();
+
+        if (res1.ok) {
+          setMembers(membersData.members || []);
+          setIsMember(userId && membersData.members.some(m => m.user_id === userId));
+        }
+        
+        if (res2.ok) {
+          const postsWithLikes = postsData.posts?.map(post => ({
+            ...post,
+            userLiked: false,
+            likes: post.likes || 0
+          })) || [];
+          setPosts(postsWithLikes);
+        }
+      } catch (err) {
+        setError('加载失败,请稍后重试');
+      } finally {
+        setLoading(false);
+      }
+    };
+
+    fetchGroupData();
+  }, [groupId, refetchKey, userId]);
+
+  const toggleLike = async (postId) => {
+    const postIndex = posts.findIndex(p => p.group_post_id === postId);
+    if (postIndex === -1) return;
+    
+    const currentPost = posts[postIndex];
+    const isLiked = currentPost.userLiked;
+    
+    try {
+      const response = await fetch(
+        `/echo/groups/${postId}/${isLiked ? 'unlike' : 'like'}`,
+        {
+          method: 'POST',
+          headers: {
+            'Content-Type': 'application/json',
+          },
+        }
+      );
+      
+      const data = await response.json();
+      if (response.ok && data.status === 'success') {
+        const updatedPosts = [...posts];
+        updatedPosts[postIndex] = {
+          ...currentPost,
+          userLiked: !isLiked,
+          likes: isLiked ? currentPost.likes - 1 : currentPost.likes + 1
+        };
+        setPosts(updatedPosts);
+        
+        setTimeout(() => {
+          setRefetchKey(prev => prev + 1);
+        }, 200);
+      } else {
+        console.error(isLiked ? '取消点赞失败' : '点赞失败:', data.message);
+      }
+    } catch (error) {
+      console.error(isLiked ? '取消点赞请求出错' : '点赞请求出错:', error);
+    }
+  };
+
+  const handleSubmitComment = async (postId, content) => {
+    if (!userId) {
+      alert('请先登录');
+      return;
+    }
+    
+    try {
+      const response = await fetch(`/echo/groups/${postId}/comment`, {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          userId,
+          content
+        })
+      });
+      
+      const data = await response.json();
+      if (response.ok && data.status === 'success') {
+        setPosts(prevPosts => prevPosts.map(post => 
+          post.group_post_id === postId ? 
+          {...post, comments: [...(post.comments || []), {
+            id: Date.now(),
+            userId,
+            username: user.username,
+            content,
+            time: new Date().toISOString()
+          }]} : 
+          post
+        ));
+        setShowCommentForm(null);
+        setRefetchKey(prev => prev + 1);
+      } else {
+        console.error('评论失败:', data.message);
+      }
+    } catch (error) {
+      console.error('评论请求出错:', error);
+    }
+  };
+
+  const handlePostCreated = () => {
+    setShowCreatePost(false);
+    setRefetchKey(prev => prev + 1);
+  };
+
+  if (loading) return <div className="group-detail"><p>加载中...</p></div>;
+  if (error) return <div className="group-detail"><p>{error}</p></div>;
+
+  return (
+    <div className="group-detail">
+      <h1 className="group-title">兴趣小组详情</h1>
+      
+      <GroupMembers members={members} />
+      
+      <GroupPosts 
+        posts={posts}
+        members={members}
+        userId={userId}
+        toggleLike={toggleLike}
+        handleSubmitComment={handleSubmitComment}
+        showCommentForm={showCommentForm}
+        setShowCommentForm={setShowCommentForm}
+        isMember={isMember}
+        onShowCreatePost={() => setShowCreatePost(true)}
+        loginHint={!userId ? "请登录后发布帖子" : "加入小组后即可发布帖子"}
+      />
+    
+
+      {showCreatePost && (
+        <div className="modal-overlay">
+            <div className="modal-content">
+            <button className="modal-close" onClick={() => setShowCreatePost(false)}>×</button>
+            <CreatePostForm 
+                groupId={groupId}
+                onClose={() => setShowCreatePost(false)}
+                onPostCreated={handlePostCreated}
+            />
+            </div>
+        </div>
+        )}
+
+
+    </div>
+  );
+};
+
+export default GroupDetail;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/GroupItem.jsx b/src/pages/InterestGroup/GroupItem.jsx
index ea2253f..8e6068b 100644
--- a/src/pages/InterestGroup/GroupItem.jsx
+++ b/src/pages/InterestGroup/GroupItem.jsx
@@ -1,70 +1,69 @@
 import React, { useState, useEffect } from 'react';
 import { useGroupStore } from '../../context/useGroupStore';
 import { useUser } from '../../context/UserContext';
-import CreatePostForm from './CreatePostForm';
-import axios from 'axios';
+import { useLocation } from 'wouter';
+import './GroupDetail.css';
 
 const GroupItem = ({ group }) => {
-  const { handleJoinGroup, joinStatus, setJoinStatus,fetchGroupList } = useGroupStore();
+  const [, setLocation] = useLocation();
+  const { handleJoinGroup, joinStatus, setJoinStatus, fetchGroupList } = useGroupStore();
   const { user } = useUser();
 
   const userId = user?.userId;
   const groupId = group.groupId;
 
   const [isMember, setIsMember] = useState(false);
-  const [loading, setLoading] = useState(false); // 新增:加载状态
-  const [error, setError] = useState(''); // 新增:错误信息
+  const [loading, setLoading] = useState(false);
+  const [error, setError] = useState('');
 
   useEffect(() => {
-    console.log('joinStatus updated:', joinStatus);
     setIsMember(joinStatus[groupId] === '加入成功');
   }, [joinStatus, groupId]);
 
-  // 初始挂载时检查成员状态(新增)
   useEffect(() => {
     if (userId && groupId) {
       checkMembershipStatus();
     }
   }, [userId, groupId]);
 
-  // 检查成员状态(新增)
   const checkMembershipStatus = async () => {
     try {
-      const res = await axios.get(`/echo/groups/${groupId}/members`);
+      const res = await fetch(`/echo/groups/${groupId}/members`);
       const isMember = res.data.members.some(member => member.user_id === userId);
       setIsMember(isMember);
-      // setJoinStatus(groupId, isMember ? '加入成功' : '未加入');
     } catch (error) {
       console.error('检查成员状态失败:', error);
     }
   };
 
-  const [showCreatePost, setShowCreatePost] = useState(false);
-
   const handleLeaveGroup = async () => {
     setLoading(true);
     try {
-      const res = await axios.post(`/echo/groups/${groupId}/leave`, {
-        user_id: userId,
+      const res = await fetch(`/echo/groups/${groupId}/leave`, {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify({
+          user_id: userId,
+        }),
       });
-      if (res.data.status === 'success') {
-          fetchGroupList(); // 刷新小组列表
-        // setJoinStatus(groupId, '未加入');
+      
+      if (res.ok && res.data.status === 'success') {
+        fetchGroupList();
         setIsMember(false);
-        // 可选:刷新小组成员计数
         group.memberCount = (group.memberCount || 0) - 1;
       } else {
         setError(res.data.message || '退出失败');
       }
     } catch (error) {
-      console.error('退出小组失败:', error);
-      setError('退出小组失败');
+      // console.error('退出小组失败:', error);
+      // setError('退出小组失败');
     } finally {
       setLoading(false);
     }
   };
 
-  // 修改加入小组逻辑(新增)
   const handleJoin = async () => {
     setLoading(true);
     try {
@@ -72,7 +71,6 @@
       if (res && res.status === 'success') {
         setJoinStatus(groupId, '加入成功');
         setIsMember(true);
-        // 可选:刷新小组成员计数
         group.memberCount = (group.memberCount || 0) + 1;
       } else {
         setError(res?.message || '加入失败');
@@ -98,15 +96,12 @@
           <h3>{group.groupName}</h3>
           <p style={{ color: '#BA929A' }}>{group.memberCount || 0}人加入了小组</p>
 
-          {/* 加入/退出按钮逻辑 */}
           {userId && (
             <button
-              onClick={() => {
-                if (isMember) {
-                  handleLeaveGroup();
-                } else {
-                  handleJoin();
-                }
+              style={{ color: '#2167c9', background: 'none', border: 'none', padding: 0, cursor: 'pointer', fontSize: '16px' }}
+              onClick={(e) => {
+                e.stopPropagation();
+                isMember ? handleLeaveGroup() : handleJoin();
               }}
               disabled={loading}
             >
@@ -115,15 +110,7 @@
           )}
           {!userId && <button disabled>请登录</button>}
 
-          {/* 显示错误信息(新增) */}
           {error && <p style={{ color: 'red' }}>{error}</p>}
-
-          {/* 发布帖子按钮 */}
-          {userId && isMember && (
-            <button onClick={() => setShowCreatePost(!showCreatePost)}>
-              +发布帖子
-            </button>
-          )}
         </div>
       </div>
 
@@ -132,12 +119,22 @@
       </div>
       <p>分类:{group.category}</p>
 
-      {showCreatePost && (
-        <CreatePostForm 
-          groupId={groupId}
-          onClose={() => setShowCreatePost(false)}
-        />
-      )}
+      <button
+        style={{
+          background: 'none',
+          border: 'none',
+          color: '#985F6F',
+          fontSize: '16px',
+          cursor: 'pointer',
+          textDecoration: 'underline',
+          marginBottom: '8px',
+          float: 'right',
+          clear: 'both',
+        }}
+        onClick={() => setLocation(`/group/${groupId}`)}
+      >
+        查看详情
+      </button>
     </div>
   );
 };
diff --git a/src/pages/InterestGroup/GroupList.jsx b/src/pages/InterestGroup/GroupList.jsx
index 6970f1d..937da76 100644
--- a/src/pages/InterestGroup/GroupList.jsx
+++ b/src/pages/InterestGroup/GroupList.jsx
@@ -17,7 +17,7 @@
   return (
     <div className="group-list">
       {groups.map(group => (
-        <GroupItem key={group.group_id} group={group} />
+        <GroupItem key={group.groupId} group={group} />
       ))}
     </div>
   );
diff --git a/src/pages/InterestGroup/GroupMembers.jsx b/src/pages/InterestGroup/GroupMembers.jsx
new file mode 100644
index 0000000..037c4be
--- /dev/null
+++ b/src/pages/InterestGroup/GroupMembers.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Link } from 'wouter';
+import './GroupDetail.css';
+
+const GroupMembers = ({ members }) => {
+  return (
+    <section className="group-section">
+      <h2>成员列表</h2>
+      <div className="member-list">
+        {members.length > 0 ? (
+          members.map(m => (
+            <Link href={`/information/${m.user_id}`} key={m.user_id} className="member-link">
+              <div className="member-card">
+                <img 
+                  src={m.avatar_url || 'https://picsum.photos/100/100'} 
+                  alt={m.username} 
+                  className="member-avatar"
+                />
+                <p className="member-name">{m.username}</p>
+              </div>
+            </Link>
+          ))
+        ) : (
+          <p className="empty-message">暂无成员</p>
+        )}
+      </div>
+    </section>
+  );
+};
+
+export default GroupMembers;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/GroupPosts.jsx b/src/pages/InterestGroup/GroupPosts.jsx
new file mode 100644
index 0000000..7bd16ba
--- /dev/null
+++ b/src/pages/InterestGroup/GroupPosts.jsx
@@ -0,0 +1,112 @@
+import React from 'react';
+import CommentForm from './CommentForm';
+import { GoodTwo, Comment } from '@icon-park/react';
+import './GroupDetail.css';
+
+const GroupPosts = ({ 
+  posts, 
+  members, 
+  userId, 
+  toggleLike, 
+  handleSubmitComment, 
+  showCommentForm, 
+  setShowCommentForm,
+  isMember,
+  onShowCreatePost,
+  loginHint
+}) => {
+  return (
+    <section className="group-section">
+      <h2>讨论帖子</h2>
+      
+      <div className="post-list-header">
+        {userId && isMember && (
+          <button 
+            className="create-post-btn" 
+            onClick={onShowCreatePost}
+          >
+            + 发布帖子
+          </button>
+        )}
+        {(!userId || !isMember) && <p className="login-hint">{loginHint}</p>}
+      </div>
+      
+      <div className="post-list">
+        {posts.length > 0 ? (
+          posts.map(post => (
+            <div key={post.group_post_id} className="post-card">
+              <div className="post-header">
+                <h3 className="post-title">{post.title}</h3>
+                <div className="post-meta">
+                  <span className="post-author">
+                    <img 
+                      src={members.find(m => m.user_id === post.user_id)?.avatar_url || 'https://picsum.photos/50/50'} 
+                      alt={post.username} 
+                      className="author-avatar"
+                    />
+                    {post.username}
+                  </span>
+                  <span className="post-time">{new Date(post.time).toLocaleString()}</span>
+                </div>
+              </div>
+              
+              <div className="post-content">
+                <p>{post.content}</p>
+              </div>
+              
+              <div className="post-actions">
+                <span className="like-button" onClick={() => userId ? toggleLike(post.group_post_id) : alert('请先登录')}>
+                  <GoodTwo 
+                    theme="outline" 
+                    size="30" 
+                    fill={post.userLiked ? '#ff4d4f' : '#8c8c8c'} 
+                    style={{ verticalAlign: 'middle', marginRight: '4px' }}
+                  />
+                  <span className="like-count">{post.likes || 0}</span>
+                </span>
+                
+                <button className="icon-btn" onClick={() => setShowCommentForm(post.group_post_id)}>
+                  <Comment theme="outline" size="30" fill="#8c8c8c"/>
+                  <span>评论</span>
+                </button>
+              </div>
+              
+              {/* 评论表单 */}
+              {showCommentForm === post.group_post_id && (
+                <CommentForm
+                  onSubmit={(content) => handleSubmitComment(post.group_post_id, content)}
+                  onCancel={() => setShowCommentForm(null)}
+                />
+              )}
+              
+              {/* 显示评论 */}
+              {post.comments && post.comments.length > 0 && (
+                <div className="comments-section">
+                  <h4 className="comments-title">评论 ({post.comments.length})</h4>
+                  {post.comments.map(comment => (
+                    <div key={comment.id || comment.comment_id} className="comment-item">
+                      <div className="comment-header">
+                        <img 
+                          src={members.find(m => m.user_id === comment.userId)?.avatar_url || 'https://picsum.photos/40/40'} 
+                          alt={comment.username || '用户'} 
+                          className="comment-avatar"
+                        />
+                        <span className="comment-author">{comment.username || '用户'}</span>
+                        <span className="comment-time">{new Date(comment.time).toLocaleString()}</span>
+                      </div>
+                      <div className="comment-content">{comment.content}</div>
+                    </div>
+                  ))}
+                </div>
+              )}
+            </div>
+          ))
+        ) : (
+          <p className="empty-message">暂无帖子</p>
+        )}
+      </div>
+    </section>
+  );
+};
+
+export default GroupPosts;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/InterestGroup.css b/src/pages/InterestGroup/InterestGroup.css
index f819038..e44eea1 100644
--- a/src/pages/InterestGroup/InterestGroup.css
+++ b/src/pages/InterestGroup/InterestGroup.css
@@ -207,8 +207,8 @@
 }    
 
 .create-group-btn {
-  background-color: #f2d0c9; /* 浅粉色 */
-  color: #4e342e; /* 深棕色 */
+  background-color: #4e342e; /* 浅粉色 */
+  color: #fdfdfd; /* 深棕色 */
   border: none;
   padding: 10px 20px;
   margin: 20px 0;
diff --git a/src/pages/UserInfo/UserInfo.css b/src/pages/UserInfo/UserInfo.css
new file mode 100644
index 0000000..476cc86
--- /dev/null
+++ b/src/pages/UserInfo/UserInfo.css
@@ -0,0 +1,61 @@
+/* src/pages/UserInfo.css */
+.user-info-container {
+  display: flex;
+  justify-content: center;
+  padding: 40px 20px;
+  background-color: #f8f1e9; /* 米色背景 */
+  min-height: 100vh;
+}
+
+.user-card {
+  background-color: #fff0f5; /* 淡粉背景 */
+  border-radius: 16px;
+  padding: 30px;
+  max-width: 500px;
+  width: 100%;
+  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
+  text-align: center;
+  font-family: 'Segoe UI', sans-serif;
+}
+
+.avatar {
+  width: 120px;
+  height: 120px;
+  object-fit: cover;
+  border-radius: 50%;
+  border: 4px solid #d2b48c; /* 浅棕色边框 */
+  margin-bottom: 20px;
+}
+
+.nickname {
+  font-size: 24px;
+  font-weight: bold;
+  color: #8b4513; /* 深棕色 */
+  margin-bottom: 8px;
+}
+
+.bio {
+  color: #a0522d; /* 棕红色 */
+  font-style: italic;
+  margin-bottom: 20px;
+}
+
+.details {
+  text-align: left;
+  font-size: 16px;
+  line-height: 1.8;
+  color: #5c4033;
+}
+
+.error {
+  color: red;
+  text-align: center;
+  margin-top: 40px;
+}
+
+.loading {
+  text-align: center;
+  font-size: 18px;
+  margin-top: 40px;
+  color: #8b4513;
+}
diff --git a/src/pages/UserInfo/UserInfo.jsx b/src/pages/UserInfo/UserInfo.jsx
index a50e81b..80aab84 100644
--- a/src/pages/UserInfo/UserInfo.jsx
+++ b/src/pages/UserInfo/UserInfo.jsx
@@ -1,9 +1,86 @@
-// src/pages/UserInfo.js
+// // src/pages/UserInfo.js
+// import React, { useEffect, useState } from 'react';
+// import axios from 'axios';
+// import { useLocation } from 'wouter';
+
+// const DEFAULT_AVATAR_URL = '/default-avatar.png'; // 替换为你的默认头像地址
+
+// const UserInfo = () => {
+//   const [location] = useLocation();
+//   const userId = location.split('/').pop();
+//   const [userInfo, setUserInfo] = useState(null);
+//   const [error, setError] = useState(null);
+
+//   useEffect(() => {
+//     const fetchUserInfo = async () => {
+//       try {
+//         setError(null);
+//         const { data: raw } = await axios.get(`/echo/user/${userId}/getProfile`);
+
+//         if (!raw) {
+//           setError('用户数据为空');
+//           setUserInfo(null);
+//           return;
+//         }
+
+//         const profile = {
+//           avatarUrl: raw.avatarUrl
+//             ? `${process.env.REACT_APP_AVATAR_BASE_URL}${raw.avatarUrl}`
+//             : DEFAULT_AVATAR_URL,
+//           nickname: raw.username || '未知用户',
+//           email: raw.email || '未填写',
+//           gender: raw.gender || '保密',
+//           bio: raw.description || '无',
+//           interests: raw.hobbies ? raw.hobbies.split(',') : [],
+//           level: raw.level || '未知',
+//           experience: raw.experience ?? 0,
+//           uploadAmount: raw.uploadCount ?? 0,
+//           downloadAmount: raw.downloadCount ?? 0,
+//           shareRate: raw.shareRate ?? 0,
+//           joinedDate: raw.registrationTime,
+//         };
+
+//         setUserInfo(profile);
+//       } catch (err) {
+//         setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
+//         setUserInfo(null);
+//       }
+//     };
+
+//     fetchUserInfo();
+//   }, [userId]);
+
+//   if (error) return <p>{error}</p>;
+//   if (!userInfo) return <p>加载中...</p>;
+
+//   return (
+//     <div className="user-profile">
+//       <img src={userInfo.avatarUrl} alt="头像" />
+//       <h2>{userInfo.nickname}</h2>
+//       <p>邮箱:{userInfo.email}</p>
+//       <p>性别:{userInfo.gender}</p>
+//       <p>简介:{userInfo.bio}</p>
+//       <p>兴趣爱好:{userInfo.interests.join('、')}</p>
+//       <p>等级:{userInfo.level}</p>
+//       <p>经验值:{userInfo.experience}</p>
+//       <p>上传量:{userInfo.uploadAmount}</p>
+//       <p>下载量:{userInfo.downloadAmount}</p>
+//       <p>分享率:{userInfo.shareRate}</p>
+//       <p>注册时间:{userInfo.joinedDate}</p>
+//     </div>
+//   );
+// };
+
+// export default UserInfo;
+
+
+// src/pages/UserInfo.jsx
 import React, { useEffect, useState } from 'react';
 import axios from 'axios';
 import { useLocation } from 'wouter';
+import './UserInfo.css';
 
-const DEFAULT_AVATAR_URL = '/default-avatar.png'; // 替换为你的默认头像地址
+const DEFAULT_AVATAR_URL = '/default-avatar.png';
 
 const UserInfo = () => {
   const [location] = useLocation();
@@ -16,10 +93,8 @@
       try {
         setError(null);
         const { data: raw } = await axios.get(`/echo/user/${userId}/getProfile`);
-
         if (!raw) {
           setError('用户数据为空');
-          setUserInfo(null);
           return;
         }
 
@@ -43,30 +118,33 @@
         setUserInfo(profile);
       } catch (err) {
         setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
-        setUserInfo(null);
       }
     };
 
     fetchUserInfo();
   }, [userId]);
 
-  if (error) return <p>{error}</p>;
-  if (!userInfo) return <p>加载中...</p>;
+  if (error) return <p className="error">{error}</p>;
+  if (!userInfo) return <p className="loading">加载中...</p>;
 
   return (
-    <div className="user-profile">
-      <img src={userInfo.avatarUrl} alt="头像" />
-      <h2>{userInfo.nickname}</h2>
-      <p>邮箱:{userInfo.email}</p>
-      <p>性别:{userInfo.gender}</p>
-      <p>简介:{userInfo.bio}</p>
-      <p>兴趣爱好:{userInfo.interests.join('、')}</p>
-      <p>等级:{userInfo.level}</p>
-      <p>经验值:{userInfo.experience}</p>
-      <p>上传量:{userInfo.uploadAmount}</p>
-      <p>下载量:{userInfo.downloadAmount}</p>
-      <p>分享率:{userInfo.shareRate}</p>
-      <p>注册时间:{userInfo.joinedDate}</p>
+    <div className="user-info-container">
+      <div className="user-card">
+        <img className="avatar" src={userInfo.avatarUrl} alt="用户头像" />
+        <h2 className="nickname">{userInfo.nickname}</h2>
+        <p className="bio">{userInfo.bio}</p>
+        <div className="details">
+          <p><strong>邮箱:</strong>{userInfo.email}</p>
+          <p><strong>性别:</strong>{userInfo.gender}</p>
+          <p><strong>兴趣爱好:</strong>{userInfo.interests.join('、')}</p>
+          <p><strong>等级:</strong>{userInfo.level}</p>
+          <p><strong>经验值:</strong>{userInfo.experience}</p>
+          <p><strong>上传量:</strong>{userInfo.uploadAmount}</p>
+          <p><strong>下载量:</strong>{userInfo.downloadAmount}</p>
+          <p><strong>分享率:</strong>{userInfo.shareRate}</p>
+          <p><strong>注册时间:</strong>{userInfo.joinedDate}</p>
+        </div>
+      </div>
     </div>
   );
 };