修改好友动态、兴趣小组
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>
);