修改好友动态、兴趣小组

Change-Id: I8dc8f304f9ac9c968e316bc997b2aeb58b26fe48
diff --git a/src/App.js b/src/App.js
index 1209f65..67df715 100644
--- a/src/App.js
+++ b/src/App.js
@@ -7,6 +7,7 @@
 import SeedList from './pages/SeedList/SeedList';
 import PostDetailPage from './pages/Forum/posts-detail/PostDetailPage';
 import { UserProvider } from './context/UserContext';
+import { GroupProvider } from './context/useGroupStore'; // 导入 GroupProvider
 import PublishSeed from './pages/PublishSeed/PublishSeed';
 import SeedDetail from './pages/SeedList/SeedDetail/SeedDetail';
 import InterestGroup from './pages/InterestGroup/InterestGroup';
@@ -32,30 +33,31 @@
 function App() {
   return (
     <UserProvider>
-      <>
-        <Route path="/" component={RedirectToAuth} />
-        <Route path="/auth" component={AuthPage} />
-        <Route path="/friend-moments" component={FriendMoments} />
-        <Route path="/friend-moments/create" component={CreateMoment} />
-        <Route path="/forum" component={ForumPage} />
-        <Route path="/forum/post/:postId" component={PostDetailPage} />
-        <Route path="/forum/create-post" component={CreatePostPage} />
-        <Route path="/seed-list" component={SeedList} />
-        {/* <Route path="/publish-seed" component={PublishSeed} /> */}
-        <Route path="/publish-seed" component={SimpleUploader} />
-        <Route path="/seed/:seed_id" component={SeedDetail} />
-        <Route path="/interest-groups" component={InterestGroup} />
-        <Route path="/user/profile" component={UserProfile} />
-        <Route path="/messages" component={MessagePage} />
-        <Route path="/promotions" component={PromotionsPage} />
-        <Route path="/level" component={LevelPage} />
-        <Route path="/user/newbie-tasks" component={NewbieTasks} />
-        {/* <Route path="/user/dynamics" component={UserDynamics} /> */}
-        <Route path="/user/friends" component={UserFriends} />
-        <Route path="/user/collections" component={UserCollect} />
-      </>
+      <GroupProvider> {/* 添加 GroupProvider */}
+        <>
+          <Route path="/" component={RedirectToAuth} />
+          <Route path="/auth" component={AuthPage} />
+          <Route path="/friend-moments" component={FriendMoments} />
+          <Route path="/friend-moments/create" component={CreateMoment} />
+          <Route path="/forum" component={ForumPage} />
+          <Route path="/forum/post/:postId" component={PostDetailPage} />
+          <Route path="/forum/create-post" component={CreatePostPage} />
+          <Route path="/seed-list" component={SeedList} />
+          {/* <Route path="/publish-seed" component={PublishSeed} /> */}
+          <Route path="/publish-seed" component={SimpleUploader} />
+          <Route path="/seed/:seed_id" component={SeedDetail} />
+          <Route path="/interest-groups" component={InterestGroup} />
+          <Route path="/user/profile" component={UserProfile} />
+          <Route path="/messages" component={MessagePage} />
+          <Route path="/promotions" component={PromotionsPage} />
+          <Route path="/level" component={LevelPage} />
+          <Route path="/user/newbie-tasks" component={NewbieTasks} />
+          <Route path="/user/friends" component={UserFriends} />
+          <Route path="/user/collections" component={UserCollect} />
+        </>
+      </GroupProvider>
     </UserProvider>
   );
 }
 
-export default App;
+export default App;
\ No newline at end of file
diff --git a/src/components/Auth/Login.jsx b/src/components/Auth/Login.jsx
deleted file mode 100644
index 19d161d..0000000
--- a/src/components/Auth/Login.jsx
+++ /dev/null
@@ -1,213 +0,0 @@
-// import React, { useState } from 'react';
-// import '../../pages/AuthPage/AuthPage.css';
-// import image from './logo.svg'; // 引入图片
-// const Login = ({ onRegisterClick }) => {
-//   const [formData, setFormData] = useState({
-//     username: '',
-//     password: ''
-//   });
-
-//   const handleChange = (e) => {
-//     const { name, value } = e.target;
-//     setFormData(prev => ({ ...prev, [name]: value }));
-//   };
-
-//   const handleSubmit = async (e) => {
-//     e.preventDefault();
-//     try {
-//       const response = await fetch('http://localhost:8080/user/login', {
-//         method: 'POST',
-//         headers: {
-//           'Content-Type': 'application/json',
-//         },
-//         body: JSON.stringify(formData),
-//       });
-  
-//       const result = await response.json();
-//       if (response.ok && result.code === "0") {
-//         console.log('登录成功:', result);
-//         // 处理成功逻辑
-//       } else {
-//         console.error('登录失败:', result);
-//         // 处理失败逻辑
-//       }
-//     } catch (error) {
-//       console.error('请求错误:', error);
-//       // 处理请求错误
-//     }
-//   };
-
-//   return (
-//     <div className="auth-container">
-//       <img 
-//         src={image} 
-//         alt="描述" 
-//         style={{ width: '30%', height: 'auto'}} 
-//       />
-//       <div className="auth-form-section">
-//         {/* <h3>欢迎来到EchoTorent !</h3> */}
-//         <h3>用户登录</h3>
-//         <form onSubmit={handleSubmit}>
-//           <div className="form-group">
-//             <label>用户名</label>
-//             <input
-//               type="text"
-//               name="username"
-//               placeholder="请输入用户名"
-//               value={formData.username}
-//               onChange={handleChange}
-//               className="form-input"
-//             />
-//           </div>
-//           <div className="form-group">
-//             <label>密码</label>
-//             <input
-//               type="password"
-//               name="password"
-//               placeholder="请输入密码"
-//               value={formData.password}
-//               onChange={handleChange}
-//               className="form-input"
-//             />
-//             <button 
-//               type="button" 
-//               className="link-button forgot-password" 
-//               onClick={() => console.log('跳转到忘记密码页面')}
-//             >
-//               忘记密码?
-//             </button>
-//           </div>
-//           <button type="submit" className="auth-button">
-//             登录
-//           </button>
-//           <p className="register-link">
-//             没有账号? 
-//             <button onClick={onRegisterClick} className="link-button">
-//                点击注册
-//             </button>
-//           </p>
-//         </form>
-//       </div>
-//     </div>
-//   );
-// };
-
-// export default Login;
-
-
-// import React, { useState } from 'react';
-// import '../../pages/AuthPage/AuthPage.css';
-// import image from './logo.svg';
-
-// 
-
-// const Login = ({ onRegisterClick }) => {
-//   const [formData, setFormData] = useState({
-//     username: '',
-//     password: ''
-//   });
-//   const [error, setError] = useState('');
-//   const [isSubmitting, setIsSubmitting] = useState(false);
-
-//   const handleSubmit = async (e) => {
-//     e.preventDefault();
-//     setIsSubmitting(true);
-//     setError('');
-
-//     try {
-//       const response = await fetch(`/user/login`, {
-//         method: 'POST',
-//         headers: {
-//           'Content-Type': 'application/json',
-//         },
-//         body: JSON.stringify(formData),
-//       });
-
-//       const result = await response.json();
-      
-//       if (!response.ok) {
-//         throw new Error(result.message || '登录失败');
-//       }
-
-//       console.log('登录成功:', result);
-//       // 这里可以添加登录成功后的跳转逻辑
-//       alert('登录成功!');
-//     } catch (error) {
-//       console.error('登录错误:', error);
-//       setError(error.message || '登录过程中出现错误');
-//     } finally {
-//       setIsSubmitting(false);
-//     }
-//   };
-
-//   const handleChange = (e) => {
-//     const { name, value } = e.target;
-//     setFormData(prev => ({ ...prev, [name]: value }));
-//   };
-
-//   return (
-//     <div className="auth-container">
-//       <img
-//         src={image}
-//         alt="网站Logo"
-//         style={{ width: '30%', height: 'auto' }}
-//       />
-//       <div className="auth-form-section">
-//         <h3>用户登录</h3>
-//         {error && <div className="error-message">{error}</div>}
-//         <form onSubmit={handleSubmit}>
-//           <div className="form-group">
-//             <label>用户名</label>
-//             <input
-//               type="text"
-//               name="username"
-//               placeholder="请输入用户名"
-//               value={formData.username}
-//               onChange={handleChange}
-//               className="form-input"
-//               required
-//             />
-//           </div>
-//           <div className="form-group">
-//             <label>密码</label>
-//             <input
-//               type="password"
-//               name="password"
-//               placeholder="请输入密码"
-//               value={formData.password}
-//               onChange={handleChange}
-//               className="form-input"
-//               required
-//             />
-//             <button
-//               type="button"
-//               className="link-button forgot-password"
-//               onClick={() => console.log('跳转到忘记密码页面')}
-//             >
-//               忘记密码?
-//             </button>
-//           </div>
-//           <button 
-//             type="submit" 
-//             className="auth-button"
-//             disabled={isSubmitting}
-//           >
-//             {isSubmitting ? '登录中...' : '登录'}
-//           </button>
-//           <p className="register-link">
-//             没有账号?{' '}
-//             <button 
-//               type="button"
-//               onClick={onRegisterClick} 
-//               className="link-button"
-//             >
-//               点击注册
-//             </button>
-//           </p>
-//         </form>
-//       </div>
-//     </div>
-//   );
-// };
-
-// export default Login;
\ No newline at end of file
diff --git a/src/components/Auth/Login.test.jsx.txt b/src/components/Auth/Login.test.jsx.txt
deleted file mode 100644
index 4631a5f..0000000
--- a/src/components/Auth/Login.test.jsx.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-// import React from 'react';
-// import { render, screen, fireEvent } from '@testing-library/react';
-// import Login from './Login';
-
-// describe('Login component', () => {
-//   test('renders login form', () => {
-//     const onRegisterClick = jest.fn();
-//     render(<Login onRegisterClick={onRegisterClick} />);
-
-//     const usernameInput = screen.getByPlaceholderText('请输入用户名');
-//     const passwordInput = screen.getByPlaceholderText('请输入密码');
-//     const loginButton = screen.getByText('登录');
-
-//     expect(usernameInput).toBeInTheDocument();
-//     expect(passwordInput).toBeInTheDocument();
-//     expect(loginButton).toBeInTheDocument();
-//   });
-
-//   test('calls onRegisterClick when "点击注册" is clicked', () => {
-//     const onRegisterClick = jest.fn();
-//     render(<Login onRegisterClick={onRegisterClick} />);
-
-//     const registerButton = screen.getByText('点击注册');
-//     fireEvent.click(registerButton);
-
-//     expect(onRegisterClick).toHaveBeenCalled();
-//   });
-// });
\ No newline at end of file
diff --git a/src/components/Auth/Register.jsx b/src/components/Auth/Register.jsx
deleted file mode 100644
index d98a449..0000000
--- a/src/components/Auth/Register.jsx
+++ /dev/null
@@ -1,261 +0,0 @@
-// import React, { useState } from 'react';
-// import '../../pages/AuthPage/AuthPage.css';
-// import image from './logo.svg'; // 引入图片
-
-// const Register = ({ onLoginClick }) => {
-//   const [formData, setFormData] = useState({
-//     username: '',
-//     password: '',
-//     email: ''
-//   });
-//   const [verificationCode, setVerificationCode] = useState('');
-
-//   const handleSubmit = async (e) => {
-//     e.preventDefault();
-//     // 注册逻辑
-//   };
-
-//   const verifyEmailCode = async () => {
-//     try {
-//       const response = await fetch('http://localhost:8080/user/verify-code', {
-//         method: 'POST',
-//         headers: {
-//           'Content-Type': 'application/json',
-//         },
-//         body: JSON.stringify({
-//           email: formData.email,
-//           code: verificationCode,
-//         }),
-//       });
-
-//       const result = await response.json();
-//       if (response.ok && result.code === "0") {
-//         console.log('邮箱验证成功:', result.msg);
-//         // 处理成功逻辑
-//       } else {
-//         console.error('邮箱验证失败:', result.msg);
-//         // 处理失败逻辑
-//       }
-//     } catch (error) {
-//       console.error('请求错误:', error);
-//       // 处理请求错误
-//     }
-//   };
-
-
-//   return (
-//     <div className="auth-container">
-//       <img 
-//         src={image} 
-//         alt="描述" 
-//         style={{ width: '30%', height: 'auto'}} 
-//       />
-//       <div className="auth-form-section">
-//         <h3>用户注册</h3>
-//         <form onSubmit={handleSubmit}>
-//           <div className="form-group">
-//             <label>用户名</label>
-//             <input
-//               type="text"
-//               className="form-input"
-//               placeholder="请输入用户名"
-//               value={formData.username}
-//               onChange={(e) => setFormData({ ...formData, username: e.target.value })}
-//               required
-//             />
-//           </div>
-//           <div className="form-group">
-//             <label>密码</label>
-//             <input
-//               type="password"
-//               className="form-input"
-//               placeholder="请输入密码"
-//               value={formData.password}
-//               onChange={(e) => setFormData({ ...formData, password: e.target.value })}
-//               required
-//             />
-//           </div>
-//           <div className="form-group">
-//             <label>邮箱</label>
-//             <div style={{ display: 'flex', alignItems: 'center' }}>
-//               <input
-//                 type="email"
-//                 className="form-input"
-//                 placeholder="请输入邮箱"
-//                 value={formData.email}
-//                 onChange={(e) => setFormData({ ...formData, email: e.target.value })}
-//                 required
-//                 style={{ flex: 1, marginRight: '10px' }}
-//               />
-//               <button type="button" onClick={verifyEmailCode} className="verify-button">
-//                 验证邮箱
-//               </button>
-//             </div>
-//           </div>
-//           <div className="form-group">
-//             <label>验证码</label>
-//             <input
-//               type="text"
-//               className="form-input"
-//               placeholder="请输入邮箱验证码"
-//               value={verificationCode}
-//               onChange={(e) => setVerificationCode(e.target.value)}
-//               required
-//             />
-//           </div>
-//           <button type="submit" className="auth-button">
-//             注册
-//           </button>
-//           <p className="login-link">
-//             已有账号? 
-//             <button onClick={onLoginClick} className="link-button">
-//               点击登录
-//             </button>
-//           </p>
-//         </form>
-//       </div>
-//     </div>
-//   );
-// };
-
-// export default Register;
-
-// import React, { useState } from 'react';
-// import '../../pages/AuthPage/AuthPage.css';
-// import image from './logo.svg';
-
-// const API_BASE = process.env.REACT_APP_API_BASE || '/echo';
-
-// const Register = ({ onLoginClick }) => {
-//   const [formData, setFormData] = useState({
-//     username: '',
-//     email: '',
-//     password: '',
-//     role: 'user',
-//     inviteCode: ''
-//   });
-//   const [error, setError] = useState('');
-//   const [isSubmitting, setIsSubmitting] = useState(false);
-
-//   const handleSubmit = async (e) => {
-//     e.preventDefault();
-//     setIsSubmitting(true);
-//     setError('');
-
-//     try {
-//       const response = await fetch(`/user/register`, {
-//         method: 'POST',
-//         headers: {
-//           'Content-Type': 'application/json',
-//         },
-//         body: JSON.stringify(formData),
-//       });
-
-//       const result = await response.json();
-      
-//       if (!response.ok) {
-//         throw new Error(result.message || '注册失败');
-//       }
-
-//       console.log('注册成功:', result);
-//       // 这里可以添加注册成功后的跳转逻辑
-//       alert('注册成功!');
-//     } catch (error) {
-//       console.error('注册错误:', error);
-//       setError(error.message || '注册过程中出现错误');
-//     } finally {
-//       setIsSubmitting(false);
-//     }
-//   };
-
-//   const handleChange = (e) => {
-//     const { name, value } = e.target;
-//     setFormData(prev => ({ ...prev, [name]: value }));
-//   };
-
-//   return (
-//     <div className="auth-container">
-//       <img
-//         src={image}
-//         alt="网站Logo"
-//         style={{ width: '30%', height: 'auto' }}
-//       />
-//       <div className="auth-form-section">
-//         <h3>用户注册</h3>
-//         {error && <div className="error-message">{error}</div>}
-//         <form onSubmit={handleSubmit}>
-//           <div className="form-group">
-//             <label>用户名</label>
-//             <input
-//               type="text"
-//               name="username"
-//               className="form-input"
-//               placeholder="请输入用户名"
-//               value={formData.username}
-//               onChange={handleChange}
-//               required
-//               minLength="3"
-//               maxLength="20"
-//             />
-//           </div>
-//           <div className="form-group">
-//             <label>邮箱</label>
-//             <input
-//               type="email"
-//               name="email"
-//               className="form-input"
-//               placeholder="请输入邮箱"
-//               value={formData.email}
-//               onChange={handleChange}
-//               required
-//             />
-//           </div>
-//           <div className="form-group">
-//             <label>密码</label>
-//             <input
-//               type="password"
-//               name="password"
-//               className="form-input"
-//               placeholder="请输入密码"
-//               value={formData.password}
-//               onChange={handleChange}
-//               required
-//               minLength="6"
-//             />
-//           </div>
-//           <div className="form-group">
-//             <label>邀请码</label>
-//             <input
-//               type="text"
-//               name="inviteCode"
-//               className="form-input"
-//               placeholder="请输入邀请码"
-//               value={formData.inviteCode}
-//               onChange={handleChange}
-//               required
-//             />
-//           </div>
-//           <button 
-//             type="submit" 
-//             className="auth-button"
-//             disabled={isSubmitting}
-//           >
-//             {isSubmitting ? '注册中...' : '注册'}
-//           </button>
-//           <p className="login-link">
-//             已有账号?{' '}
-//             <button 
-//               type="button"
-//               onClick={onLoginClick} 
-//               className="link-button"
-//             >
-//               点击登录
-//             </button>
-//           </p>
-//         </form>
-//       </div>
-//     </div>
-//   );
-// };
-
-// export default Register;
\ No newline at end of file
diff --git a/src/components/Auth/Register.test.jsx.txt b/src/components/Auth/Register.test.jsx.txt
deleted file mode 100644
index 356fadd..0000000
--- a/src/components/Auth/Register.test.jsx.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-// import React from 'react';
-// import { render, screen, fireEvent } from '@testing-library/react';
-// import Register from './Register';
-
-// describe('Register component', () => {
-//   test('renders register form', () => {
-//     const onLoginClick = jest.fn();
-//     render(<Register onLoginClick={onLoginClick} />);
-
-//     const usernameInput = screen.getByPlaceholderText('请输入用户名');
-//     const passwordInput = screen.getByPlaceholderText('请输入密码');
-//     const emailInput = screen.getByPlaceholderText('请输入邮箱');
-//     const verifyButton = screen.getByText('验证邮箱');
-//     const registerButton = screen.getByText('注册');
-
-//     expect(usernameInput).toBeInTheDocument();
-//     expect(passwordInput).toBeInTheDocument();
-//     expect(emailInput).toBeInTheDocument();
-//     expect(verifyButton).toBeInTheDocument();
-//     expect(registerButton).toBeInTheDocument();
-//   });
-
-//   test('calls onLoginClick when "点击登录" is clicked', () => {
-//     const onLoginClick = jest.fn();
-//     render(<Register onLoginClick={onLoginClick} />);
-
-//     const loginButton = screen.getByText('点击登录');
-//     fireEvent.click(loginButton);
-
-//     expect(onLoginClick).toHaveBeenCalled();
-//   });
-// });
\ No newline at end of file
diff --git a/src/context/useGroupStore.js b/src/context/useGroupStore.js
new file mode 100644
index 0000000..985bc33
--- /dev/null
+++ b/src/context/useGroupStore.js
@@ -0,0 +1,113 @@
+import { createContext, useContext, useState, useCallback } from 'react';
+import { fetchGroups, joinGroup, createPost } from '../services/groupService';
+
+const GroupContext = createContext();
+
+export const GroupProvider = ({ children }) => {
+  const [groups, setGroups] = useState([]);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(null);
+  const [category, setCategory] = useState('');
+  const [name, setName] = useState('');
+  const [page, setPage] = useState(1);
+  const [size, setSize] = useState(10);
+  const [totalPages, setTotalPages] = useState(1);
+  const [sortBy, setSortBy] = useState('member_count');
+  const [joinStatus, setJoinStatus] = useState({});
+
+  // 获取小组列表
+  const fetchGroupList = useCallback(async () => {
+    try {
+      setLoading(true);
+      setError(null);
+      
+      const requestData = {
+        page,
+        size,
+        sort_by: sortBy
+      };
+      
+      if (category) requestData.category = category;
+      if (name) requestData.name = name;
+      
+      const response = await fetchGroups(requestData);
+      
+      if (response.status === 'success') {
+        setGroups(response.items || []);
+        setTotalPages(response.total_pages || 1);
+      } else {
+        setError('获取兴趣小组列表失败');
+      }
+    } catch (err) {
+      setError('请求失败,请稍后再试');
+    } finally {
+      setLoading(false);
+    }
+  }, [category, name, page, size, sortBy]);
+
+  // 加入小组
+  const handleJoinGroup = useCallback(async (groupId, userId) => {
+    if (!userId) return;
+
+    try {
+      setJoinStatus(prev => ({ ...prev, [groupId]: '请求中' }));
+      const response = await joinGroup(groupId, userId);
+      
+      if (response.status === 'success') {
+        setJoinStatus(prev => ({ ...prev, [groupId]: '加入成功' }));
+        fetchGroupList(); // 刷新列表
+      } else {
+        setJoinStatus(prev => ({ ...prev, [groupId]: '加入失败' }));
+      }
+    } catch (error) {
+      setJoinStatus(prev => ({ ...prev, [groupId]: '请求失败' }));
+    }
+  }, [fetchGroupList]);
+
+  // 创建帖子
+  const handleCreatePost = useCallback(async (groupId, userId, content, title, images) => {
+    if (!userId || !content || !title) return;
+
+    try {
+      const response = await createPost(groupId, userId, content, title, images);
+      
+      if (response.post_id) {
+        return true; // 成功
+      } else {
+        throw new Error('创建帖子失败');
+      }
+    } catch (error) {
+      console.error('创建帖子错误:', error);
+      return false;
+    }
+  }, []);
+
+  const value = {
+    groups,
+    loading,
+    error,
+    category,
+    setCategory,
+    name,
+    setName,
+    page,
+    setPage,
+    size,
+    setSize,
+    totalPages,
+    sortBy,
+    setSortBy,
+    joinStatus,
+    fetchGroupList,
+    handleJoinGroup,
+    handleCreatePost
+  };
+
+  return (
+    <GroupContext.Provider value={value}>
+      {children}
+    </GroupContext.Provider>
+  );
+};
+
+export const useGroupStore = () => useContext(GroupContext);
\ No newline at end of file
diff --git a/src/pages/Forum/posts-main/components/CreatePostButton.jsx b/src/pages/Forum/posts-main/components/CreatePostButton.jsx
index e324056..0aa24fb 100644
--- a/src/pages/Forum/posts-main/components/CreatePostButton.jsx
+++ b/src/pages/Forum/posts-main/components/CreatePostButton.jsx
@@ -4,6 +4,10 @@
 import './CreatePostButton.css';
 import { useUser } from '../../../../context/UserContext';
 
+const user = JSON.parse(localStorage.getItem('user')); // user = { user_id: 123, ... }
+const userId = user?.userId;
+
+
 const CreatePostButton = () => {
   const { user } = useUser();
   const userId = user?.userId;  // 这里改为 userId,跟 UserContext 统一
diff --git a/src/pages/FriendMoments/FriendMoments.css b/src/pages/FriendMoments/FriendMoments.css
index 1059f10..087abcb 100644
--- a/src/pages/FriendMoments/FriendMoments.css
+++ b/src/pages/FriendMoments/FriendMoments.css
@@ -11,7 +11,11 @@
   padding: 2%;
 }
 
-
+.like-container{
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
 .f-search-bar {
   display: flex;
   align-items: center;
diff --git a/src/pages/FriendMoments/FriendMoments.jsx b/src/pages/FriendMoments/FriendMoments.jsx
index fd017b2..526c06d 100644
--- a/src/pages/FriendMoments/FriendMoments.jsx
+++ b/src/pages/FriendMoments/FriendMoments.jsx
@@ -1,32 +1,76 @@
-import React, { useState, useEffect } from 'react';
+import React, { useContext, useState, useEffect } from 'react'; 
 import axios from 'axios';
 import './FriendMoments.css';
 import Header from '../../components/Header';
-import { Edit } from '@icon-park/react';
+import { Edit, GoodTwo, Comment } from '@icon-park/react';
+import { UserContext } from '../../context/UserContext'; // 引入用户上下文
 
 const FriendMoments = () => {
   const [feeds, setFeeds] = useState([]);
   const [filteredFeeds, setFilteredFeeds] = useState([]);
   const [query, setQuery] = useState('');
-  const [userId, setUserId] = useState(456); // 从状态管理或登录信息获取
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState(null);
+  const [commentBoxVisibleId, setCommentBoxVisibleId] = useState(null); // 当前显示评论框的动态ID
+  const [commentInput, setCommentInput] = useState(''); // 当前输入的评论内容
+
+  // 从上下文中获取用户信息
+  const { user } = useContext(UserContext);
+  const userId = user?.userId || null; // 从用户上下文中获取userId
+  const username = user?.username || '未知用户'; // 获取用户名
 
   // Modal state & form fields
   const [showModal, setShowModal] = useState(false);
   const [title, setTitle] = useState('');
   const [content, setContent] = useState('');
   const [selectedImages, setSelectedImages] = useState([]);
-  const [previewUrls, setPreviewUrls] = useState([]); // 新增:图片预览URLs
+  const [previewUrls, setPreviewUrls] = useState([]);
+
+  // 检查用户是否已登录
+  const isLoggedIn = !!userId;
 
   // 拉取好友动态列表
   const fetchFeeds = async () => {
+    if (!isLoggedIn) {
+      setLoading(false);
+      setError('请先登录');
+      return;
+    }
+
+    setLoading(true);
+    setError(null);
     try {
-      // 修改为新的API路径
+      // 注意这里修改了API路径,使用getAllDynamics接口
       const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
-      setFeeds(res.data.posts || []);
-      setFilteredFeeds(res.data.posts || []);
+      
+      // 检查API返回的数据结构
+      console.log('API响应数据:', res.data);
+      
+      // 从响应中提取dynamic数组
+      const dynamicList = res.data.dynamic || [];
+      
+      // 将API返回的数据结构转换为前端期望的格式
+      const formattedFeeds = dynamicList.map(item => ({
+        postNo: item.dynamic_id, // 使用API返回的dynamic_id作为帖子ID
+        title: item.title,
+        postContent: item.content,
+        imageUrl: item.images, // 使用API返回的images字段
+        postTime: item.time, // 使用API返回的time字段
+        postLikeNum: item.likes?.length || 0, // 点赞数
+        liked: item.likes?.some(like => like.user_id === userId), // 当前用户是否已点赞
+        user_id: item.user_id, // 发布者ID
+        username: item.username, // 发布者昵称
+        avatar_url: item.avatar_url, // 发布者头像
+        comments: item.comments || [] // 评论列表
+      }));
+      
+      setFeeds(formattedFeeds);
+      setFilteredFeeds(formattedFeeds);
     } catch (err) {
       console.error('获取动态列表失败:', err);
-      alert('获取动态列表失败,请稍后重试');
+      setError('获取动态列表失败,请稍后重试');
+    } finally {
+      setLoading(false);
     }
   };
 
@@ -59,23 +103,27 @@
     const files = Array.from(e.target.files);
     if (!files.length) return;
     
-    // 生成预览URLs
     const previewUrls = files.map(file => URL.createObjectURL(file));
     
     setSelectedImages(files);
-    setPreviewUrls(previewUrls); // 更新预览URLs
+    setPreviewUrls(previewUrls);
   };
 
   // 对话框内:提交新动态
   const handleSubmit = async () => {
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
+    }
+
     if (!content.trim()) {
       alert('内容不能为空');
       return;
     }
 
     try {
+      // 使用formData格式提交
       const formData = new FormData();
-      formData.append('user_id', userId);
       formData.append('title', title.trim() || '');
       formData.append('content', content.trim());
       
@@ -84,7 +132,7 @@
         formData.append('image_url', file);
       });
 
-      // 修改为新的API路径
+      // 调用创建动态API
       await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
         headers: {
           'Content-Type': 'multipart/form-data'
@@ -95,7 +143,7 @@
       setTitle('');
       setContent('');
       setSelectedImages([]);
-      setPreviewUrls([]); // 重置预览URLs
+      setPreviewUrls([]);
       setShowModal(false);
       fetchFeeds();
       alert('发布成功');
@@ -105,11 +153,17 @@
     }
   };
 
-  // 删除动态
+  // 删除动态 - 注意:API文档中未提供删除接口,这里保留原代码
   const handleDelete = async (dynamicId) => {
+  
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
+    }
+
     if (!window.confirm('确定要删除这条动态吗?')) return;
     try {
-      // 修改为新的API路径
+      // 注意:API文档中未提供删除接口,这里使用原代码中的路径
       await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
       fetchFeeds();
       alert('删除成功');
@@ -120,64 +174,224 @@
   };
 
   // 点赞动态
-  const handleLike = async (dynamicId) => {
+  const handleLike = async (dynamicId,islike) => {
+    if (islike) {
+      handleUnlike(dynamicId);
+      return
+    }
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
+    }
+
+    // 验证dynamicId是否有效
+    if (!dynamicId) {
+      console.error('无效的dynamicId:', dynamicId);
+      alert('点赞失败:动态ID无效');
+      return;
+    }
+
+    // 检查是否已经点赞,防止重复请求
+    // const currentFeed = feeds.find(feed => feed.postNo === dynamicId);
+    // if (currentFeed && currentFeed.liked) {
+    //   console.warn('尝试重复点赞,已忽略');
+    //   return;
+    // }
+
+    console.log('当前用户ID:', userId);
+    console.log('即将点赞的动态ID:', dynamicId);
+    
     try {
-      // 调用新的点赞API
-      const res = await axios.post(`/echo/dynamic/like`, {
-        userId,
-        dynamicId
+      // 确保参数是整数类型
+      const requestData = {
+        userId: parseInt(userId),
+        dynamicId: parseInt(dynamicId)
+      };
+      
+      // 验证参数是否为有效数字
+      if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
+        console.error('无效的参数:', requestData);
+        alert('点赞失败:参数格式错误');
+        return;
+      }
+      
+      console.log('点赞请求数据:', requestData);
+      
+      const res = await axios.post(`/echo/dynamic/like`, requestData, {
+        headers: {
+          'Content-Type': 'application/json' // 明确指定JSON格式
+        }
       });
       
+      console.log('点赞API响应:', res.data);
+      
       if (res.status === 200) {
         // 更新本地状态
-        setFeeds(feeds.map(feed => {
+        feeds.forEach(feed => {
           if (feed.postNo === dynamicId) {
-            return {
-              ...feed,
-              postLikeNum: (feed.postLikeNum || 0) + 1,
-              liked: true
-            };
+            feed.postLikeNum = (feed.postLikeNum || 0) + 1;
+            feed.liked = true;
           }
-          return feed;
-        }));
+        });
+        setFeeds([...feeds]); // 更新状态以触发重新渲染
       } else {
         alert(res.data.message || '点赞失败');
       }
     } catch (err) {
       console.error('点赞失败', err);
+      
+      // 检查错误响应,获取更详细的错误信息
+      if (err.response) {
+        console.error('错误响应数据:', err.response.data);
+        console.error('错误响应状态:', err.response.status);
+        console.error('错误响应头:', err.response.headers);
+      }
+      
       alert('点赞失败,请稍后重试');
     }
   };
 
   // 取消点赞
   const handleUnlike = async (dynamicId) => {
+    if (!isLoggedIn) {
+      alert('请先登录');
+      return;
+    }
+
+    // 验证dynamicId是否有效
+    if (!dynamicId) {
+      console.error('无效的dynamicId:', dynamicId);
+      alert('取消点赞失败:动态ID无效');
+      return;
+    }
+
+    // 检查是否已经取消点赞,防止重复请求
+    const currentFeed = feeds.find(feed => feed.postNo === dynamicId);
+    if (currentFeed && !currentFeed.liked) {
+      console.warn('尝试重复取消点赞,已忽略');
+      return;
+    }
+
     try {
-      // 调用新的取消点赞API
+      // 确保参数是整数类型
+      const requestData = {
+        userId: parseInt(userId),
+        dynamicId: parseInt(dynamicId)
+      };
+      
+      // 验证参数是否为有效数字
+      if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
+        console.error('无效的参数:', requestData);
+        alert('取消点赞失败:参数格式错误');
+        return;
+      }
+      
+      console.log('取消点赞请求数据:', requestData);
+      
       const res = await axios.delete(`/echo/dynamic/unlike`, {
-        data: { userId, dynamicId }
+        headers: {
+          'Content-Type': 'application/json' // 明确指定JSON格式
+        },
+        data: requestData // 将参数放在data属性中
       });
       
+      console.log('取消点赞API响应:', res.data);
+      
       if (res.status === 200) {
         // 更新本地状态
-        setFeeds(feeds.map(feed => {
+        feeds.forEach(feed => {
           if (feed.postNo === dynamicId) {
-            return {
-              ...feed,
-              postLikeNum: Math.max(0, (feed.postLikeNum || 0) - 1),
-              liked: false
-            };
+            feed.postLikeNum = Math.max(0, (feed.postLikeNum || 0) - 1);
+            feed.liked = false;
           }
-          return feed;
-        }));
+        });
+        setFeeds([...feeds]); // 更新状态以触发重新渲染
       } else {
         alert(res.data.message || '取消点赞失败');
       }
     } catch (err) {
       console.error('取消点赞失败', err);
+      
+      // 检查错误响应,获取更详细的错误信息
+      if (err.response) {
+        console.error('错误响应数据:', err.response.data);
+        console.error('错误响应状态:', err.response.status);
+        console.error('错误响应头:', err.response.headers);
+      }
+      
       alert('取消点赞失败,请稍后重试');
     }
   };
 
+  // 评论好友动态
+  // 评论好友动态
+const handleComment = async (dynamicId) => {
+  if (!isLoggedIn) {
+    alert('请先登录');
+    return;
+  }
+
+  if (!commentInput.trim()) {
+    alert('评论内容不能为空');
+    return;
+  }
+
+  try {
+    const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, {
+      content: commentInput.trim()
+    });
+
+    if (res.status === 200 || res.status === 201) {
+      // 成功获取评论数据
+      const newComment = {
+        user_id: userId,
+        username: username,
+        content: commentInput.trim(),
+        time: new Date().toISOString() // 使用当前时间作为评论时间
+      };
+
+      // 更新本地状态,添加新评论
+      setFeeds(prevFeeds => {
+        return prevFeeds.map(feed => {
+          if (feed.postNo === dynamicId) {
+            // 确保comments是数组,并且正确合并新评论
+            const currentComments = Array.isArray(feed.comments) ? feed.comments : [];
+            return {
+              ...feed,
+              comments: [...currentComments, newComment]
+            };
+          }
+          return feed;
+        });
+      });
+
+      // 更新过滤后的动态列表
+      setFilteredFeeds(prevFeeds => {
+        return prevFeeds.map(feed => {
+          if (feed.postNo === dynamicId) {
+            // 确保comments是数组,并且正确合并新评论
+            const currentComments = Array.isArray(feed.comments) ? feed.comments : [];
+            return {
+              ...feed,
+              comments: [...currentComments, newComment]
+            };
+          }
+          return feed;
+        });
+      });
+
+      // alert('评论成功');
+      setCommentInput('');
+      setCommentBoxVisibleId(null); // 关闭评论框
+    } else {
+      alert(res.data.error || '评论失败');
+    }
+  } catch (err) {
+    console.error('评论失败', err);
+    alert('评论失败,请稍后重试');
+  }
+};
+
   return (
     <div className="friend-moments-container">
       <Header />
@@ -186,7 +400,7 @@
           <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
           创建动态
         </button>
-        <div className="f-search-bar">
+        {/* <div className="f-search-bar">
           <input
             className="search-input"
             type="text"
@@ -196,46 +410,115 @@
           />
           <button className="search-btn" onClick={handleSearch}>搜索</button>
           <button className="search-btn" onClick={handleReset}>重置</button>
-        </div>
+        </div> */}
       </div>
 
       <div className="feed-list">
-        {filteredFeeds.map(feed => (
-          <div className="feed-item" key={feed.postNo}>
-            {feed.title && <h4>{feed.title}</h4>}
-            <p>{feed.postContent}</p>
-
-            {feed.imageUrl && feed.imageUrl.split(',').length > 0 && (
-              <div className="feed-images">
-                {feed.imageUrl.split(',').map((url, i) => (
-                  <img key={i} src={url} alt={`动态图${i}`} />
-                ))}
-              </div>
-            )}
-
-            <div className="feed-footer">
-              <span className="feed-date">
-                {new Date(feed.postTime).toLocaleString()}
-              </span>
-              <div className="like-container">
-                {feed.liked ? (
-                  <button className="unlike-btn" onClick={() => handleUnlike(feed.postNo)}>
-                    已点赞 ({feed.postLikeNum || 0})
-                  </button>
-                ) : (
-                  <button className="like-btn" onClick={() => handleLike(feed.postNo)}>
-                    点赞 ({feed.postLikeNum || 0})
-                  </button>
-                )}
-              </div>
-              {feed.user_id === userId && (
-                <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
-                  删除
-                </button>
-              )}
-            </div>
+        {loading ? (
+          <div className="loading-message">加载中...</div>
+        ) : error ? (
+          <div className="error-message">{error}</div>
+        ) : !isLoggedIn ? (
+          <div className="login-prompt">
+            <p>请先登录查看好友动态</p>
           </div>
-        ))}
+        ) : filteredFeeds.length === 0 ? (
+          <div className="empty-message">暂无动态</div>
+        ) : (
+          filteredFeeds.map(feed => (
+            <div className="feed-item" key={feed.postNo || `feed-${Math.random()}`}>
+              {/* 显示发布者信息 */}
+              <div className="feed-author">
+                <img src={feed.avatar_url || 'https://example.com/default-avatar.jpg'} alt={feed.username || '用户头像'} />
+                <div>
+                  <h4>{feed.username || '未知用户'}</h4>
+                  <span className="feed-date">{new Date(feed.postTime || Date.now()).toLocaleString()}</span>
+                </div>
+              </div>
+
+              {feed.title && <h4 className="feed-title">{feed.title}</h4>}
+              <p className="feed-content">{feed.postContent || '无内容'}</p>
+
+              {feed.imageUrl && (
+                <div className="feed-images">
+                  {/* 处理可能是单张图片或多张图片的情况 */}
+                  {typeof feed.imageUrl === 'string' ? (
+                    <img src={feed.imageUrl} alt="动态图片" />
+                  ) : (
+                    feed.imageUrl.map((url, i) => (
+                      <img key={i} src={url} alt={`动态图${i}`} />
+                    ))
+                  )}
+                </div>
+              )}
+
+              <div className="feed-footer">
+                <div className="like-container">
+                    <button className="icon-btn" onClick={() => handleLike(feed.postNo, feed.liked, feed.user_id)}>
+                      <GoodTwo theme="outline" size="24" fill={feed.liked ? '#f00' : '#fff'} />
+                      <span>{feed.postLikeNum || 0}</span>
+                    
+                    </button>
+
+                  <button
+                    className="icon-btn"
+                    onClick={() => {
+                      setCommentBoxVisibleId(feed.postNo);
+                      setCommentInput('');
+                    }}
+                  >
+                    <Comment theme="outline" size="24" fill="#333" />
+                    <span>评论</span>
+                  </button>
+
+    {commentBoxVisibleId === feed.postNo && (
+      <div className="comment-box">
+        <textarea
+          className="comment-input"
+          placeholder="请输入评论内容..."
+          value={commentInput}
+          onChange={(e) => setCommentInput(e.target.value)}
+        />
+        <button
+          className="submit-comment-btn"
+          onClick={() => handleComment(feed.postNo)}
+        >
+          发布评论
+        </button>
+      </div>
+    )}
+  </div>
+  {feed.user_id === userId && (
+    <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
+      删除
+    </button>
+  )}
+</div>
+
+              {/* 评论列表 */}
+              {Array.isArray(feed.comments) && feed.comments.length > 0 && (
+                <div className="comments-container">
+                  <h5>评论 ({feed.comments.length})</h5>
+                  <div className="comments-list">
+                    {feed.comments.map((comment, index) => (
+                      <div className="comment-item" key={index}>
+                        <div className="comment-header">
+                          <span className="comment-user">{comment.username || '用户'}</span>
+                          {/* <span className="comment-user-id">ID: {comment.user_id}</span> */}
+                          <span className="comment-time">
+                            {new Date(comment.time || Date.now()).toLocaleString()}
+                          </span>
+                        </div>
+                        <p className="comment-content">{comment.content}</p>
+                      </div>
+                    ))}
+                  </div>
+                </div>
+              )}
+
+            </div>
+          ))
+        )}
       </div>
 
       {/* Modal 对话框 */}
@@ -265,7 +548,7 @@
               />
             </label>
             <div className="cf-preview">
-              {previewUrls.map((url, i) => ( // 使用定义的previewUrls
+              {previewUrls.map((url, i) => (
                 <img key={i} src={url} alt={`预览${i}`} />
               ))}
             </div>
@@ -284,4 +567,4 @@
   );
 };
 
-export default FriendMoments;
\ No newline at end of file
+export default FriendMoments;  
\ No newline at end of file
diff --git a/src/pages/InterestGroup/CreatePostForm.jsx b/src/pages/InterestGroup/CreatePostForm.jsx
new file mode 100644
index 0000000..6848b54
--- /dev/null
+++ b/src/pages/InterestGroup/CreatePostForm.jsx
@@ -0,0 +1,69 @@
+import React, { useState } from 'react';
+import { useGroupStore } from '../../context/useGroupStore';
+
+const CreatePostForm = ({ groupId, onClose }) => {
+  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 handleSubmit = async (e) => {
+    e.preventDefault();
+    setLoading(true);
+    setError('');
+
+    try {
+      const success = await handleCreatePost(groupId, userId, content, title, images);
+      
+      if (success) {
+        alert('帖子发布成功');
+        onClose();
+      } else {
+        setError('帖子发布失败');
+      }
+    } catch (error) {
+      setError(error.message || '帖子发布失败');
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  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="button-group">
+        <button onClick={handleSubmit} disabled={loading}>
+          {loading ? '发布中...' : '发布'}
+        </button>
+        <button onClick={onClose} disabled={loading}>
+          取消
+        </button>
+      </div>
+    </div>
+  );
+};
+
+export default CreatePostForm;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/GroupFilters.jsx b/src/pages/InterestGroup/GroupFilters.jsx
new file mode 100644
index 0000000..c93b495
--- /dev/null
+++ b/src/pages/InterestGroup/GroupFilters.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { useGroupStore } from '../../context/useGroupStore';
+
+const GroupFilters = () => {
+  const { 
+    category, setCategory, 
+    name, setName, 
+    sortBy, setSortBy,
+    handleSearch
+  } = useGroupStore();
+
+  const handleSortChange = (e) => {
+    const sortValueMap = {
+      'member_count': 'member_count',
+      'name': 'groupName',
+      'category': 'category'
+    };
+    const backendValue = sortValueMap[e.target.value] || 'member_count';
+    setSortBy(backendValue);
+  };
+
+  return (
+    <div className="filter-search-sort-container">
+      <div className="filter">
+        <label>分类:</label>
+        <select onChange={(e) => setCategory(e.target.value)} value={category}>
+          <option value="">全部</option>
+          <option value="影视">影视</option>
+          <option value="游戏">游戏</option>
+          <option value="学习">学习</option>
+          <option value="体育">体育</option>
+          <option value="其他">其他</option>
+        </select>
+      </div>
+
+      <div className="sort">
+        <label>排序:</label>
+        <select onChange={handleSortChange} value={sortBy}>
+          <option value="member_count">按成员数排序</option>
+          <option value="name">按名称排序</option>
+          <option value="category">按分类排序</option>
+        </select>
+      </div>
+
+      <div className="search">
+        <input
+          type="text"
+          value={name}
+          onChange={(e) => setName(e.target.value)}
+          placeholder="输入小组名称搜索"
+        />
+        <button onClick={handleSearch}>搜索</button>
+      </div>
+    </div>
+  );
+};
+
+export default GroupFilters;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/GroupItem.jsx b/src/pages/InterestGroup/GroupItem.jsx
new file mode 100644
index 0000000..4f76bac
--- /dev/null
+++ b/src/pages/InterestGroup/GroupItem.jsx
@@ -0,0 +1,178 @@
+// import React, { useState } from 'react';
+// import { useGroupStore } from '../../context/useGroupStore';
+// import { useUser } from '../../context/UserContext'; // ✅ 新增:引入 UserContext
+// import CreatePostForm from './CreatePostForm';
+
+// const GroupItem = ({ group }) => {
+//   const { handleJoinGroup, joinStatus } = useGroupStore();
+//   const { user } = useUser(); // ✅ 获取 user
+//   const userId = user?.userId; // ✅ 安全获取 userId
+//   const [showCreatePost, setShowCreatePost] = useState(false);
+
+//   return (
+//     <div className="group-item">
+//       <div className="group-content">
+//         <img
+//           style={{ width: '40%', height: '40%' }}
+//           src={group.cover_image || 'https://picsum.photos/200/200'}
+//           alt={group.groupName || group.name}
+//           className="group-cover"
+//         />
+//         <div className="group-info-right">
+//           <h3>{group.groupName || group.name}</h3>
+//           <p style={{ color: '#BA929A' }}>{group.memberCount || 0}人加入了小组</p>
+//           <button
+//             onClick={() => handleJoinGroup(group.group_id, userId)}
+//             disabled={joinStatus[group.group_id] === '加入成功' || !userId}
+//           >
+//             {joinStatus[group.group_id] === '加入成功' ? '已加入' : userId ? '+加入小组' : '请登录'}
+//           </button>
+
+//           {userId && joinStatus[group.group_id] === '加入成功' && (
+//             <button onClick={() => setShowCreatePost(!showCreatePost)}>
+//               +发布帖子
+//             </button>
+//           )}
+//         </div>
+//       </div>
+
+//       <div className="group-description">
+//         <p>{group.description}</p>
+//       </div>
+//       <p>分类:{group.category}</p>
+
+//       {showCreatePost && (
+//         <CreatePostForm 
+//           groupId={group.group_id} 
+//           onClose={() => setShowCreatePost(false)} 
+//         />
+//       )}
+//     </div>
+//   );
+// };
+
+// export default GroupItem;
+
+
+import React, { useState } from 'react';
+import { useGroupStore } from '../../context/useGroupStore';
+import { useUser } from '../../context/UserContext';
+import CreatePostForm from './CreatePostForm';
+
+const GroupItem = ({ group }) => {
+
+  console.log('group:', group);
+  const { handleJoinGroup, joinStatus } = useGroupStore();
+  const { user } = useUser();
+  
+  const userId = user?.userId;
+  const groupId = group.groupId; // ✅ 使用正确字段
+console.log('加入小组请求 - groupId:', group.group_id, 'userId:', userId);
+
+  const [showCreatePost, setShowCreatePost] = useState(false);
+
+  return (
+    <div className="group-item">
+      <div className="group-content">
+        <img
+          style={{ width: '40%', height: '40%' }}
+          src={group.cover_image || 'https://picsum.photos/200/200'}
+          alt={group.groupName}
+          className="group-cover"
+        />
+        <div className="group-info-right">
+          <h3>{group.groupName}</h3> {/* ✅ 使用 groupName */}
+          <p style={{ color: '#BA929A' }}>{group.memberCount || 0}人加入了小组</p>
+
+          <button
+            onClick={() => handleJoinGroup(groupId, userId)}
+            disabled={joinStatus[groupId] === '加入成功' || !userId}
+          >
+            
+            {joinStatus[groupId] === '加入成功' ? '已加入' : userId ? '+加入小组' : '请登录'}
+          </button>
+
+          {userId && joinStatus[groupId] === '加入成功' && (
+            <button onClick={() => setShowCreatePost(!showCreatePost)}>
+              +发布帖子
+            </button>
+          )}
+        </div>
+      </div>
+
+      <div className="group-description">
+        <p>{group.description}</p>
+      </div>
+      <p>分类:{group.category}</p>
+
+      {showCreatePost && (
+        <CreatePostForm 
+          groupId={groupId}
+          onClose={() => setShowCreatePost(false)}
+        />
+      )}
+    </div>
+  );
+};
+
+export default GroupItem;
+
+
+// import React, { useState } from 'react';
+// import { useGroupStore } from '../../context/useGroupStore';
+// import { useUser } from '../../context/UserContext';
+// import CreatePostForm from './CreatePostForm';
+
+// const GroupItem = ({ group }) => {
+//     console.log('group:', group);
+
+//   const { handleJoinGroup, joinStatus } = useGroupStore();
+//   const { user } = useUser();
+//   const userId = user?.userId; // 确保使用正确的字段名(取自 localStorage 的结构)
+//   const [showCreatePost, setShowCreatePost] = useState(false);
+
+//   return (
+//     <div className="group-item">
+//       <div className="group-content">
+//         <img
+//           style={{ width: '40%', height: '40%' }}
+//           src={group.cover_image || 'https://picsum.photos/200/200'}
+//           alt={group.name}
+//           className="group-cover"
+//         />
+//         <div className="group-info-right">
+//           <h3>{group.name}</h3>
+//           <p style={{ color: '#BA929A' }}>{group.member_count || 0}人加入了小组</p>
+
+//           <button
+//             onClick={() => handleJoinGroup(group.group_id, userId)}
+//             disabled={joinStatus[group.group_id] === '加入成功' || !userId}
+//           >
+//             {joinStatus[group.group_id] === '加入成功' ? '已加入' : userId ? '+加入小组' : '请登录'}
+//           </button>
+
+//           {userId && joinStatus[group.group_id] === '加入成功' && (
+//             <button onClick={() => setShowCreatePost(!showCreatePost)}>
+//               +发布帖子
+//             </button>
+//           )}
+//         </div>
+//       </div>
+
+//       <div className="group-description">
+//         <p>{group.description}</p>
+//       </div>
+//       <p>分类:{group.category}</p>
+
+//       {showCreatePost && (
+//         <CreatePostForm 
+//           groupId={group.group_id}
+//           onClose={() => setShowCreatePost(false)}
+//         />
+//       )}
+//     </div>
+//   );
+// };
+
+// export default GroupItem;
+
diff --git a/src/pages/InterestGroup/GroupList.jsx b/src/pages/InterestGroup/GroupList.jsx
new file mode 100644
index 0000000..6970f1d
--- /dev/null
+++ b/src/pages/InterestGroup/GroupList.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import GroupItem from './GroupItem';
+import { useGroupStore } from '../../context/useGroupStore';
+
+const GroupList = () => {
+  const { groups, loading, error } = useGroupStore();
+
+  if (loading) return <p>加载中...</p>;
+  if (error) return <p className="error">{error}</p>;
+  if (!groups || groups.length === 0) return (
+    <div className="empty-state">
+      <p>没有找到匹配的兴趣小组</p>
+      <p>请尝试调整筛选条件或搜索关键词</p>
+    </div>
+  );
+
+  return (
+    <div className="group-list">
+      {groups.map(group => (
+        <GroupItem key={group.group_id} group={group} />
+      ))}
+    </div>
+  );
+};
+
+export default GroupList;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/GroupPagination.jsx b/src/pages/InterestGroup/GroupPagination.jsx
new file mode 100644
index 0000000..14b093b
--- /dev/null
+++ b/src/pages/InterestGroup/GroupPagination.jsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { useGroupStore } from '../../context/useGroupStore';
+
+const GroupPagination = () => {
+  const { page, totalPages, setPage } = useGroupStore();
+
+  const handlePrevPage = () => {
+    if (page > 1) setPage(page - 1);
+  };
+
+  const handleNextPage = () => {
+    if (page < totalPages) setPage(page + 1);
+  };
+
+  return (
+    <div className="pagination">
+      <button onClick={handlePrevPage} disabled={page <= 1}>
+        上一页
+      </button>
+      <span>第 {page} 页 / 共 {totalPages} 页</span>
+      <button onClick={handleNextPage} disabled={page >= totalPages}>
+        下一页
+      </button>
+    </div>
+  );
+};
+
+export default GroupPagination;
\ No newline at end of file
diff --git a/src/pages/InterestGroup/InterestGroup.jsx b/src/pages/InterestGroup/InterestGroup.jsx
index a68f20c..b89cf57 100644
--- a/src/pages/InterestGroup/InterestGroup.jsx
+++ b/src/pages/InterestGroup/InterestGroup.jsx
@@ -1,221 +1,25 @@
-import React, { useEffect, useState } from 'react';
-import axios from 'axios';
+import React, { useEffect } from 'react';
+import Header from '../../components/Header';
+import { useGroupStore } from '../../context/useGroupStore';
+import GroupFilters from './GroupFilters';
+import GroupList from './GroupList';
+import GroupPagination from './GroupPagination';
 import './InterestGroup.css';
-import Header from '../../components/Header'; // 导入 Header 组件
-
-
-
 const InterestGroup = () => {
-  const [groups, setGroups] = useState([]);
-  const [loading, setLoading] = useState(true);
-  const [error, setError] = useState(null);
-  const [category, setCategory] = useState('');
-  const [name, setName] = useState('');
-  const [page, setPage] = useState(1);
-  const [size, setSize] = useState(10);
-  const [totalPages, setTotalPages] = useState(1);
-  const [sortBy, setSortBy] = useState('member_count'); // 默认按照成员数排序
-  const [joinStatus, setJoinStatus] = useState({}); // 存储每个小组的加入状态
+  const { fetchGroupList, setPage, handleSearch } = useGroupStore();
 
+  // 初始化加载
   useEffect(() => {
-    // 请求兴趣小组列表
-    const fetchGroups = async () => {
-      try {
-        setLoading(true);
-        setError(null);
-        const response = await axios.get(`/echo/groups`, {
-          params: {
-            category,
-            name,
-            page,
-            size,
-            sort_by: sortBy
-          }
-        });
-
-        if (response.data.status === 'success') {
-          setGroups(response.data.items);
-          setTotalPages(response.data.total_pages); // 更新总页数
-        } else {
-          setError('获取兴趣小组列表失败');
-        }
-      } catch (err) {
-        setError('请求失败,请稍后再试');
-      } finally {
-        setLoading(false);
-      }
-    };
-
-    fetchGroups();
-  }, [category, name, page, size, sortBy]);
-
-  const handleCategoryChange = (e) => {
-    setCategory(e.target.value);
-    setPage(1); // 重置为第一页
-  };
-
-  const handleSearchChange = (e) => {
-    setName(e.target.value);
-    setPage(1); // 重置为第一页
-  };
-
-  const handleSortChange = (e) => {
-    setSortBy(e.target.value);
-  };
-
-  const handlePageChange = (newPage) => {
-    if (newPage > 0 && newPage <= totalPages) {
-      setPage(newPage);
-    }
-  };
-
-  // 加入兴趣小组
-  const handleJoinGroup = async (groupId) => {
-    const userId = 1; // 假设用户ID为1,可以根据实际情况获取
-
-    try {
-      const response = await axios.post(`/echo/groups/${groupId}/join`, {
-        user_id: userId
-      });
-
-      if (response.data.status === 'success') {
-        setJoinStatus(prevState => ({
-          ...prevState,
-          [groupId]: '加入成功'
-        }));
-      } else {
-        setJoinStatus(prevState => ({
-          ...prevState,
-          [groupId]: '加入失败'
-        }));
-      }
-    } catch (error) {
-      setJoinStatus(prevState => ({
-        ...prevState,
-        [groupId]: '请求失败,请稍后再试'
-      }));
-    }
-  };
-
-  const handleSearch = () => {
-    // 触发搜索逻辑,通过修改 name 状态重新请求数据
-    setPage(1);
-  };
+    fetchGroupList();
+  }, [fetchGroupList]);
 
   return (
     <div className="interest-group-container">
-      {/* Header 组件放在页面最上方 */}
       <Header />
       <div className="interest-group-card">
-        {/* <h1>兴趣小组列表</h1> */}
-        {/* 水平排列的筛选、搜索和排序容器 */}
-        <div className="filter-search-sort-container">
-          {/* 分类筛选 */}
-          <div className="filter">
-            <label>分类:</label>
-            <select onChange={handleCategoryChange} value={category} style={{ width: '150px' }}>
-              <option value="">全部</option>
-              <option value="影视">影视</option>
-              <option value="游戏">游戏</option>
-              <option value="学习">学习</option>
-              <option value="体育">体育</option>
-              <option value="其他">其他</option>
-            </select>
-          </div>
-
-          {/* 排序 */}
-          <div className="sort">
-            <label>排序:</label>
-            <select onChange={handleSortChange} value={sortBy} style={{ width: '150px' }}>
-              <option value="member_count">按成员数排序</option>
-              <option value="name">按名称排序</option>
-              <option value="category">按分类排序</option>
-            </select>
-          </div>
-
-          {/* 搜索框 */}
-          <div className="search">
-            <input
-              type="text"
-              value={name}
-              onChange={handleSearchChange}
-              placeholder="输入小组名称搜索"
-            />
-            <button onClick={handleSearch} style={{ backgroundColor: '#BA929A', color: 'white' , padding: '5px 10px'}}>搜索</button>
-          </div>
-        </div>
-
-        {/* 加载中提示 */}
-        {loading && <p>加载中...</p>}
-
-        {/* 错误提示 */}
-        {error && <p className="error">{error}</p>}
-
-        {/* 小组列表 */}
-        {!loading && !error && (
-          <div className="group-list">
-            {groups.map((group) => (
-              <div className="group-item" key={group.group_id}>
-                <div className="group-content">
-                  <img
-                    style={{ width: '40%', height: '40%'}}
-                    src={group.cover_image}
-                    alt={group.name}
-                    className="group-cover"
-                  />
-                  <div
-                    className="group-info-right"
-                    style={{
-                      display: 'flex',
-                      flexDirection: 'column',
-                      alignItems: 'flex-start',
-                      gap: '4px', // 控制元素之间的垂直间距
-                    }}
-                  >
-                    <h3 style={{ margin: 0 }}>{group.name}</h3>
-                    <p style={{ color: '#BA929A', margin: 0 }}>{group.member_count}人加入了小组</p>
-                    <button
-                      onClick={() => handleJoinGroup(group.group_id)}
-                      disabled={joinStatus[group.group_id] === '加入成功'}
-                      style={{
-                        background: 'none',
-                        color: '#007bff',
-                        padding: 0,
-                        marginTop: '4px',
-                        /*左对齐*/
-                        textAlign: 'left',
-                        marginLeft: '0',
-                        cursor: joinStatus[group.group_id] === '加入成功' ? 'default' : 'pointer',
-                      }}
-                    >
-                      {joinStatus[group.group_id] === '加入成功' ? '已加入' : '+加入小组'}
-                    </button>
-                  </div>
-
-                </div>
-                <div className="group-description">
-                  <p>{group.description}</p>
-                </div>
-                <p>分类:{group.category}</p>
-        
-              </div>
-            ))}
-          </div>
-        )}    
-
-        {/* 分页 */}
-        <div className="pagination">
-          <button onClick={() => handlePageChange(page - 1)} disabled={page <= 1}>
-            上一页
-          </button>
-          <span>第 {page} 页 / 共 {totalPages} 页</span>
-          <button
-            onClick={() => handlePageChange(page + 1)}
-            disabled={page >= totalPages}
-          >
-            下一页
-          </button>
-        </div>
+        <GroupFilters />
+        <GroupList />
+        <GroupPagination />
       </div>
     </div>
   );
diff --git a/src/services/groupService.js b/src/services/groupService.js
new file mode 100644
index 0000000..29e99af
--- /dev/null
+++ b/src/services/groupService.js
@@ -0,0 +1,91 @@
+// import axios from 'axios';
+
+// // 获取所有小组
+// export const fetchGroups = async (params) => {
+//   const response = await axios.post('/echo/groups/getAllGroups', params);
+//   return response.data;
+// };
+
+// // 加入小组
+// export const joinGroup = async (groupId, userId) => {
+//   const response = await axios.post(`/echo/groups/${groupId}/join`, { user_id: userId });
+//   return response.data;
+// };
+
+// // 创建帖子
+// export const createPost = async (groupId, userId, content, title, images) => {
+//   const formData = new FormData();
+//   formData.append('user_id', userId);
+//   formData.append('content', content);
+//   formData.append('title', title);
+  
+//   if (images && images.length > 0) {
+//     for (let i = 0; i < images.length; i++) {
+//       formData.append('images', images[i]);
+//     }
+//   }
+
+//   const response = await axios.post(`/echo/groups/${groupId}/createPost`, formData, {
+//     headers: { 'Content-Type': 'multipart/form-data' }
+//   });
+  
+//   return response.data;
+// };
+
+import axios from 'axios';
+
+// 获取所有小组
+export const fetchGroups = async (params) => {
+  try {
+    const response = await axios.post('/echo/groups/getAllGroups', params);
+    return response.data;
+  } catch (error) {
+    console.error('获取小组列表失败:', error.response?.data || error.message);
+    return { status: 'failure', message: '获取小组失败' };
+  }
+};
+
+// 加入小组
+export const joinGroup = async (groupId, userId) => {
+  try {
+    const response = await axios.post(
+      `/echo/groups/${groupId}/join`,
+      { user_id: userId },
+      {
+        headers: {
+          'Content-Type': 'application/json'  // ✅ 明确设置为 JSON
+        }
+      }
+    );
+    return response.data;
+  } catch (error) {
+    console.error('加入小组失败:', error.response?.data || error.message);
+    return { status: 'failure', message: '加入小组失败' };
+  }
+};
+
+
+// 创建帖子
+export const createPost = async (groupId, userId, content, title, images) => {
+  try {
+    const formData = new FormData();
+    formData.append('user_id', userId);
+    formData.append('content', content);
+    formData.append('title', title);
+
+    if (images && images.length > 0) {
+      for (let i = 0; i < images.length; i++) {
+        formData.append('images', images[i]);
+      }
+    }
+
+    const response = await axios.post(`/echo/groups/${groupId}/createPost`, formData, {
+      headers: { 'Content-Type': 'multipart/form-data' }
+    });
+
+    return response.data;
+  } catch (error) {
+    console.error('创建帖子失败:', error.response?.data || error.message);
+    return { status: 'failure', message: '创建帖子失败' };
+  }
+};