blob: bf756713cbd21744f21bfe1eed605c1104bec0ee [file] [log] [blame]
2230113338fd3882025-06-06 23:33:57 +08001import React, { useState, useEffect } from "react";
wht6a1b6782025-06-06 19:14:59 +08002import { useNavigate } from "react-router-dom";
2230113338fd3882025-06-06 23:33:57 +08003import { API_BASE_URL } from "./config";
TRM-codingfa3ffdf2025-06-09 22:47:42 +08004import HomeIcon from "@mui/icons-material/Home";
5import MovieIcon from "@mui/icons-material/Movie";
6import TvIcon from "@mui/icons-material/Tv";
7import MusicNoteIcon from "@mui/icons-material/MusicNote";
8import AnimationIcon from "@mui/icons-material/Animation";
9import SportsEsportsIcon from "@mui/icons-material/SportsEsports";
10import SportsMartialArtsIcon from "@mui/icons-material/SportsMartialArts";
11import PersonIcon from "@mui/icons-material/Person";
12import AccountCircleIcon from "@mui/icons-material/AccountCircle";
13import ForumIcon from "@mui/icons-material/Forum";
14import HelpIcon from "@mui/icons-material/Help";
15import SearchIcon from "@mui/icons-material/Search";
16import PostAddIcon from "@mui/icons-material/PostAdd";
17import "./SharedStyles.css";
wht6a1b6782025-06-06 19:14:59 +080018
TRM-codingfa3ffdf2025-06-09 22:47:42 +080019const navItems = [
20 { label: "首页", icon: <HomeIcon className="emerald-nav-icon" />, path: "/home", type: "home" },
21 { label: "电影", icon: <MovieIcon className="emerald-nav-icon" />, path: "/movie", type: "movie" },
22 { label: "剧集", icon: <TvIcon className="emerald-nav-icon" />, path: "/tv", type: "tv" },
23 { label: "音乐", icon: <MusicNoteIcon className="emerald-nav-icon" />, path: "/music", type: "music" },
24 { label: "动漫", icon: <AnimationIcon className="emerald-nav-icon" />, path: "/anime", type: "anime" },
25 { label: "游戏", icon: <SportsEsportsIcon className="emerald-nav-icon" />, path: "/game", type: "game" },
26 { label: "体育", icon: <SportsMartialArtsIcon className="emerald-nav-icon" />, path: "/sport", type: "sport" },
27 { label: "资料", icon: <PersonIcon className="emerald-nav-icon" />, path: "/info", type: "info" },
28 { label: "论坛", icon: <ForumIcon className="emerald-nav-icon" />, path: "/forum", type: "forum" },
29 { label: "发布", icon: <AccountCircleIcon className="emerald-nav-icon" />, path: "/publish", type: "publish" },
30 { label: "求种", icon: <HelpIcon className="emerald-nav-icon" />, path: "/begseed", type: "help" },
31];
32
33// 论坛文字雨内容
34const forumTexts = [
35 "讨论", "交流", "分享", "观点", "话题", "回复", "发帖", "社区",
36 "对话", "互动", "评论", "建议", "意见", "经验", "心得", "推荐",
37 "新手", "老鸟", "攻略", "指南", "教程", "资源", "福利", "活动"
wht6a1b6782025-06-06 19:14:59 +080038];
39
40export default function ForumPage() {
41 const navigate = useNavigate();
2230113338fd3882025-06-06 23:33:57 +080042 const [posts, setPosts] = useState([]);
223011339e292152025-06-08 00:34:37 +080043 const [searchQuery, setSearchQuery] = useState('');
TRM-codingfa3ffdf2025-06-09 22:47:42 +080044 const [userInfo, setUserInfo] = useState({ avatar_url: '', username: '' });
45 const [userPT, setUserPT] = useState({ magic: 0, ratio: 0, upload: 0, download: 0 });
2230113338fd3882025-06-06 23:33:57 +080046
47 useEffect(() => {
TRM-codingfa3ffdf2025-06-09 22:47:42 +080048 // 获取用户信息
2230113338fd3882025-06-06 23:33:57 +080049 const match = document.cookie.match('(^|;)\\s*userId=([^;]+)');
50 const userId = match ? match[2] : null;
TRM-codingfa3ffdf2025-06-09 22:47:42 +080051 if (userId) {
52 fetch(`${API_BASE_URL}/api/get-userpt?userid=${encodeURIComponent(userId)}`)
53 .then(res => res.json())
54 .then(data => {
55 setUserInfo({ avatar_url: data.user.avatar_url, username: data.user.username });
56 setUserPT({
57 magic: data.magic_value || data.magic || 0,
58 ratio: data.share_ratio || data.share || 0,
59 upload: data.upload_amount || data.upload || 0,
60 download: data.download_amount || data.download || 0,
61 });
62 })
63 .catch(err => console.error('Fetching user profile failed', err));
64 }
65
66 // 获取论坛帖子
2230113338fd3882025-06-06 23:33:57 +080067 fetch(`${API_BASE_URL}/api/forum`)
223011339e292152025-06-08 00:34:37 +080068 .then(res => {
69 // console.log("fetch raw response:", res);
70 return res.json();
71 })
72 .then(data => {
73 // console.log("fetch forum data:", data);
74 const formattedPosts = data.map(post => ({
75 post_id: post.postid,
76 title: post.posttitle,
77 content: post.postcontent,
78 author_id: post.postuserid,
79 author_name: post.author?.username || '',
80 created_at: new Date(post.posttime).toLocaleString(),
81 reply_count: post.replytime,
82 view_count: post.readtime,
83 }));
84 setPosts(formattedPosts);
85 })
2230113338fd3882025-06-06 23:33:57 +080086 .catch(() => setPosts([]));
87 }, []);
223011339e292152025-06-08 00:34:37 +080088
89 // Handler to perform search based on input value
90 const handleSearch = () => {
91 fetch(`${API_BASE_URL}/api/search-posts?keyword=${encodeURIComponent(searchQuery)}`)
92 .then(res => res.json())
93 .then(data => {
94 const formattedPosts = data.map(post => ({
95 post_id: post.postid,
96 title: post.posttitle,
97 content: post.postcontent,
98 author_id: post.postuserid,
99 author_name: post.author?.username || '',
100 created_at: new Date(post.posttime).toLocaleString(),
101 reply_count: post.replytime,
102 view_count: post.readtime,
103 }));
104 setPosts(formattedPosts);
105 })
106 .catch(() => setPosts([]));
107 };
2230113338fd3882025-06-06 23:33:57 +0800108
wht6a1b6782025-06-06 19:14:59 +0800109 return (
TRM-codingfa3ffdf2025-06-09 22:47:42 +0800110 <div className="emerald-home-container">
111 {/* 文字雨背景效果 */}
112 <div className="forum-text-rain">
113 {forumTexts.map((text, index) => (
114 <div key={index} className="text-drop" style={{
115 left: `${(index * 3.5) % 100}%`,
116 animationDelay: `${(index * 0.8) % 10}s`,
117 animationDuration: `${8 + (index % 5)}s`
118 }}>
119 {text}
120 </div>
121 ))}
wht6a1b6782025-06-06 19:14:59 +0800122 </div>
TRM-codingfa3ffdf2025-06-09 22:47:42 +0800123
124 {/* 浮动园林装饰元素 */}
125 <div className="floating-garden-elements">
126 <div className="garden-element">💬</div>
127 <div className="garden-element">📝</div>
128 <div className="garden-element">🗨️</div>
129 <div className="garden-element">✍️</div>
130 </div>
131
132 <div className="emerald-content">
133 {/* NeuraFlux用户栏 */}
134 <div className="emerald-user-bar">
135 <div className="emerald-user-avatar" onClick={() => navigate('/user')}>
136 {userInfo.avatar_url ? (
137 <img src={userInfo.avatar_url} alt="用户头像" style={{ width: 38, height: 38, borderRadius: '50%', objectFit: 'cover' }} />
138 ) : (
139 <AccountCircleIcon style={{ fontSize: 38, color: 'white' }} />
140 )}
wht6a1b6782025-06-06 19:14:59 +0800141 </div>
TRM-codingfa3ffdf2025-06-09 22:47:42 +0800142 <div className="emerald-brand-section">
143 <div className="emerald-brand-icon">⚡</div>
144 <div className="emerald-user-label">NeuraFlux</div>
wht6a1b6782025-06-06 19:14:59 +0800145 </div>
TRM-codingfa3ffdf2025-06-09 22:47:42 +0800146 <div className="emerald-user-stats">
147 <span className="emerald-stat-item">
148 魔力值: <span className="emerald-stat-value">{userPT.magic}</span>
149 </span>
150 <span className="emerald-stat-item">
151 分享率: <span className="emerald-stat-value">{userPT.ratio}</span>
152 </span>
153 <span className="emerald-stat-item">
154 上传: <span className="emerald-stat-value">{userPT.upload}GB</span>
155 </span>
156 <span className="emerald-stat-item">
157 下载: <span className="emerald-stat-value">{userPT.download}GB</span>
158 </span>
wht6a1b6782025-06-06 19:14:59 +0800159 </div>
160 </div>
TRM-codingfa3ffdf2025-06-09 22:47:42 +0800161
162 {/* NeuraFlux导航栏 */}
163 <nav className="emerald-nav-bar">
164 {navItems.map((item) => (
165 <div
166 key={item.label}
167 className={`emerald-nav-item ${item.label === "论坛" ? "active" : ""}`}
168 data-type={item.type}
169 onClick={() => navigate(item.path)}
170 >
171 {item.icon}
172 <span className="emerald-nav-label">{item.label}</span>
173 </div>
174 ))}
175 </nav>
176
177 {/* 论坛内容区域 */}
178 <div className="emerald-content-section">
179 <h1 className="emerald-page-title">💬 NeuraFlux论坛</h1>
180 <p style={{ textAlign: 'center', color: '#2d5016', fontSize: '18px', marginBottom: '30px' }}>
181 欢迎来到NeuraFlux社区论坛,这里是知识与思想的碰撞之地
182 </p>
183
184 {/* 论坛工具栏 */}
185 <div className="forum-toolbar">
186 <div className="search-section">
187 <div className="search-input-container">
188 <SearchIcon className="search-icon" />
189 <input
190 type="text"
191 placeholder="搜索论坛话题..."
192 value={searchQuery}
193 onChange={(e) => setSearchQuery(e.target.value)}
194 className="forum-search-input"
195 />
196 </div>
197 <button onClick={handleSearch} className="forum-search-btn">
198 搜索
199 </button>
200 </div>
201 <button className="new-post-btn" onClick={() => navigate('/publish')}>
202 <PostAddIcon style={{ marginRight: '8px' }} />
203 发布新话题
204 </button>
205 </div>
206
207 {/* 帖子列表 */}
208 <div className="forum-posts-container">
209 {posts.length > 0 ? (
210 posts.map((post) => (
211 <div
212 key={post.post_id}
213 className="forum-post-card"
214 onClick={() => navigate(`/forum/${post.post_id}`)}
215 >
216 <div className="post-header">
217 <div className="post-author-info">
218 <div className="author-avatar">
219 <AccountCircleIcon style={{ fontSize: 28, color: '#2d5016' }} />
220 </div>
221 <div className="author-details">
222 <span className="author-name">{post.author_name}</span>
223 <span className="post-time">{post.created_at}</span>
224 </div>
225 </div>
226 <div className="post-stats">
227 <span className="stat-item">👁 {post.view_count}</span>
228 <span className="stat-item">💬 {post.reply_count}</span>
229 </div>
230 </div>
231
232 <div className="post-content">
233 <h3 className="post-title">{post.title}</h3>
234 <p className="post-preview">{post.content}</p>
235 </div>
236
237 <div className="post-footer">
238 <div className="post-tags">
239 <span className="post-tag">讨论</span>
240 </div>
241 <div className="post-actions">
242 <span className="action-btn">查看详情 →</span>
243 </div>
244 </div>
245 </div>
246 ))
247 ) : (
248 <div className="empty-state">
249 <ForumIcon style={{ fontSize: 64, color: '#90ee90', marginBottom: '16px' }} />
250 <h3 style={{ color: '#2d5016', marginBottom: '8px' }}>暂无帖子</h3>
251 <p style={{ color: '#666', marginBottom: '20px' }}>快来发布第一个话题吧!</p>
252 <button className="new-post-btn" onClick={() => navigate('/publish')}>
253 <PostAddIcon style={{ marginRight: '8px' }} />
254 发布话题
255 </button>
256 </div>
257 )}
258 </div>
259 </div>
260 </div>
wht6a1b6782025-06-06 19:14:59 +0800261 </div>
262 );
263}