| import React, { useState, useEffect } from 'react'; |
| import { Link } from 'wouter'; |
| import axios from 'axios'; |
| import { GoodTwo, Comment } from '@icon-park/react'; |
| import logo from '../../assets/logo.png'; |
| import './ForumPage.css'; |
| |
| const API_BASE = process.env.REACT_APP_API_BASE; |
| |
| const ForumPage = () => { |
| const [posts, setPosts] = useState([]); |
| const [total, setTotal] = useState(0); |
| const [page, setPage] = useState(1); |
| const [size, setSize] = useState(10); |
| const [loading, setLoading] = useState(true); |
| const [errorMsg, setErrorMsg] = useState(''); |
| |
| const totalPages = Math.ceil(total / size); |
| |
| useEffect(() => { |
| const fetchPosts = async () => { |
| setLoading(true); |
| setErrorMsg(''); |
| try { |
| const response = await axios.get(`${API_BASE}/echo/forum/posts/getAllPost`, { |
| params: { page, size } |
| }); |
| const postsData = response.data.posts || []; |
| |
| const userIds = [...new Set(postsData.map(post => post.user_id))]; |
| const userProfiles = await Promise.all( |
| userIds.map(async id => { |
| try { |
| const res = await axios.get(`${API_BASE}/echo/user/profile`, { |
| params: { user_id: id } |
| }); |
| return { id, profile: res.data }; |
| } catch { |
| return { id, profile: { nickname: '未知用户', avatar_url: 'default-avatar.png' } }; |
| } |
| }) |
| ); |
| |
| const userMap = {}; |
| userProfiles.forEach(({ id, profile }) => { |
| userMap[id] = profile; |
| }); |
| |
| const postsWithProfiles = postsData.map(post => ({ |
| ...post, |
| userProfile: userMap[post.user_id] || { nickname: '未知用户', avatar_url: 'default-avatar.png' } |
| })); |
| |
| setPosts(postsWithProfiles); |
| setTotal(response.data.total || 0); |
| } catch (error) { |
| console.error('获取帖子失败:', error); |
| setErrorMsg('加载失败,请稍后重试'); |
| } finally { |
| setLoading(false); |
| } |
| }; |
| fetchPosts(); |
| }, [page, size]); |
| |
| const toggleLike = async (postId, liked) => { |
| try { |
| if (liked) { |
| await axios.delete(`${API_BASE}/echo/forum/posts/${postId}/unlike`); |
| } else { |
| await axios.post(`${API_BASE}/echo/forum/posts/${postId}/like`); |
| } |
| |
| setPosts(prevPosts => |
| prevPosts.map(post => |
| post.id === postId |
| ? { |
| ...post, |
| liked: !liked, |
| likeCount: liked ? post.likeCount - 1 : post.likeCount + 1 |
| } |
| : post |
| ) |
| ); |
| } catch (error) { |
| console.error('点赞操作失败:', error); |
| } |
| }; |
| |
| return ( |
| <div className="forum-page"> |
| <header className="header"> |
| <div className="logo-and-name"> |
| <img src={logo} alt="网站logo" className="logo" /> |
| <span className="site-name">Echo</span> |
| </div> |
| <div className="user-and-message"> |
| <img src="user-avatar.png" alt="用户头像" className="user-avatar" /> |
| <span className="message-center">消息</span> |
| </div> |
| </header> |
| |
| <nav className="nav"> |
| <Link to="/friend-moments" className="nav-item">好友动态</Link> |
| <Link to="/forum" className="nav-item active">论坛</Link> |
| <Link to="/interest-groups" className="nav-item">兴趣小组</Link> |
| <Link to="/seed-list" className="nav-item">种子列表</Link> |
| <Link to="/publish-seed" className="nav-item">发布种子</Link> |
| </nav> |
| |
| <div className="forum-content"> |
| <h2>论坛帖子列表</h2> |
| |
| {loading ? ( |
| <p>加载中...</p> |
| ) : errorMsg ? ( |
| <p className="error-text">{errorMsg}</p> |
| ) : posts.length === 0 ? ( |
| <p>暂无帖子。</p> |
| ) : ( |
| <div className="post-list"> |
| {posts.map(post => ( |
| <div key={post.id} className="post-card"> |
| <div className="post-card-top"> |
| <div className="user-info"> |
| <img className="avatar" src={post.userProfile.avatar_url} alt="头像" /> |
| <span className="nickname">{post.userProfile.nickname}</span> |
| </div> |
| {post.cover_image_url && ( |
| <img className="cover-image" src={post.cover_image_url} alt="封面" /> |
| )} |
| </div> |
| <h3>{post.title}</h3> |
| <p className="post-meta"> |
| 发布时间:{new Date(post.created_at).toLocaleString()} |
| </p> |
| <div className="post-actions"> |
| <button |
| className="icon-btn" |
| onClick={() => toggleLike(post.id, post.liked)} |
| > |
| <GoodTwo theme="outline" size="24" fill={post.liked ? '#f00' : '#fff'} /> |
| <span>{post.likeCount || 0}</span> |
| </button> |
| <Link href={`/forum/post/${post.id}`} className="icon-btn"> |
| <Comment theme="outline" size="24" fill="#fff" /> |
| <span>{post.commentCount || 0}</span> |
| </Link> |
| </div> |
| <Link href={`/forum/post/${post.id}`} className="btn-secondary">查看详情</Link> |
| </div> |
| ))} |
| </div> |
| )} |
| |
| <div className="pagination"> |
| <button disabled={page === 1} onClick={() => setPage(page - 1)}>上一页</button> |
| <span>第 {page} 页 / 共 {totalPages} 页</span> |
| <button disabled={page === totalPages} onClick={() => setPage(page + 1)}>下一页</button> |
| </div> |
| </div> |
| </div> |
| ); |
| }; |
| |
| export default ForumPage; |