修改好友动态、兴趣小组

Change-Id: I8dc8f304f9ac9c968e316bc997b2aeb58b26fe48
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>
   );