blob: 159bdfaf3c2f26b8035a0a24c43c79a666c454de [file] [log] [blame]
Krishya8f2fec82025-06-04 21:54:46 +08001import React, { useContext, useEffect, useState } from 'react';
22301009237217b2025-04-20 15:15:25 +08002import { useParams } from 'wouter';
3import { GoodTwo, Star } from '@icon-park/react';
Krishya57cc17b2025-05-26 16:43:34 +08004import { getPostDetail, getPostComments, likePost, unlikePost, addCommentToPost, collectPost, uncollectPost } from './api'; // 引入你的 API 函数
Krishya7ec1dd02025-04-19 15:29:03 +08005import './PostDetailPage.css';
Krishya8f2fec82025-06-04 21:54:46 +08006import { UserContext, useUser } from '../../../context/UserContext'; // 注意路径
Krishyac0f7e9b2025-04-22 15:28:28 +08007import Header from '../../../components/Header';
Krishya7ec1dd02025-04-19 15:29:03 +08008
9const PostDetailPage = () => {
22301009237217b2025-04-20 15:15:25 +080010 const { postId } = useParams(); // 获取帖子ID
11 const [postDetail, setPostDetail] = useState(null);
12 const [comments, setComments] = useState([]);
13 const [loading, setLoading] = useState(true);
14 const [errorMsg, setErrorMsg] = useState('');
15 const [newComment, setNewComment] = useState(''); // 新评论内容
Krishya57cc17b2025-05-26 16:43:34 +080016 // const [isAnonymous, setIsAnonymous] = useState(false); // 是否匿名
22301009237217b2025-04-20 15:15:25 +080017 const [isLiked, setIsLiked] = useState(false); // 是否已点赞
18 const [isCollected, setIsCollected] = useState(false); // 是否已收藏
19 const [replyToCommentId, setReplyToCommentId] = useState(null); // 回复的评论ID
Krishya2283d882025-05-27 22:25:19 +080020 const [replyToUsername, setReplyToUsername] = useState(null);
Krishya7ec1dd02025-04-19 15:29:03 +080021
22301009237217b2025-04-20 15:15:25 +080022 // 获取当前用户ID(假设从上下文中获取)
Krishya8f2fec82025-06-04 21:54:46 +080023 const { user } = useContext(UserContext);
24 // const { user } = useUser(); // 你需要从用户上下文获取用户 ID
Krishya7ec1dd02025-04-19 15:29:03 +080025
22301009237217b2025-04-20 15:15:25 +080026 useEffect(() => {
27 const fetchPostDetail = async () => {
28 setLoading(true);
29 setErrorMsg('');
30 try {
31 // 获取帖子详情
32 const postData = await getPostDetail(postId);
33 setPostDetail(postData);
Krishya7ec1dd02025-04-19 15:29:03 +080034
22301009237217b2025-04-20 15:15:25 +080035 // 获取帖子评论
36 const commentsData = await getPostComments(postId);
37 setComments(commentsData);
Krishya7ec1dd02025-04-19 15:29:03 +080038
22301009237217b2025-04-20 15:15:25 +080039 // 设置是否已经点赞
40 if (postData.likedByUser) {
41 setIsLiked(true);
Krishya7ec1dd02025-04-19 15:29:03 +080042 } else {
22301009237217b2025-04-20 15:15:25 +080043 setIsLiked(false);
Krishya7ec1dd02025-04-19 15:29:03 +080044 }
Krishya7ec1dd02025-04-19 15:29:03 +080045
22301009237217b2025-04-20 15:15:25 +080046 // 设置是否已经收藏
47 if (postData.collectedByUser) {
48 setIsCollected(true);
Krishya7ec1dd02025-04-19 15:29:03 +080049 } else {
22301009237217b2025-04-20 15:15:25 +080050 setIsCollected(false);
Krishya7ec1dd02025-04-19 15:29:03 +080051 }
22301009237217b2025-04-20 15:15:25 +080052 } catch (err) {
53 console.error('加载失败:', err);
54 setErrorMsg('加载失败,请稍后重试');
55 } finally {
56 setLoading(false);
57 }
Krishya7ec1dd02025-04-19 15:29:03 +080058 };
59
22301009237217b2025-04-20 15:15:25 +080060 fetchPostDetail();
61 }, [postId]);
Krishya7ec1dd02025-04-19 15:29:03 +080062
22301009237217b2025-04-20 15:15:25 +080063 // 点赞功能
64 const toggleLike = async () => {
65 if (!user) {
66 alert('请先登录');
67 return;
68 }
Krishya7ec1dd02025-04-19 15:29:03 +080069
22301009237217b2025-04-20 15:15:25 +080070 try {
71 if (isLiked) {
72 // 取消点赞
Krishya8f2fec82025-06-04 21:54:46 +080073 await unlikePost(postId, user.userId);
22301009237217b2025-04-20 15:15:25 +080074 setIsLiked(false);
75 setPostDetail((prev) => ({
76 ...prev,
77 postLikeNum: prev.postLikeNum - 1,
78 }));
79 } else {
80 // 点赞
Krishya8f2fec82025-06-04 21:54:46 +080081 await likePost(postId, user.userId);
22301009237217b2025-04-20 15:15:25 +080082 setIsLiked(true);
83 setPostDetail((prev) => ({
84 ...prev,
85 postLikeNum: prev.postLikeNum + 1,
86 }));
87 }
88 } catch (err) {
89 console.error('点赞失败:', err);
90 alert('点赞失败,请稍后再试');
91 }
92 };
Krishya7ec1dd02025-04-19 15:29:03 +080093
Krishya57cc17b2025-05-26 16:43:34 +080094// 收藏功能
95const toggleCollect = async () => {
22301009237217b2025-04-20 15:15:25 +080096 if (!user) {
Krishya57cc17b2025-05-26 16:43:34 +080097 alert('请先登录');
98 return;
22301009237217b2025-04-20 15:15:25 +080099 }
Krishya7ec1dd02025-04-19 15:29:03 +0800100
22301009237217b2025-04-20 15:15:25 +0800101 try {
Krishya57cc17b2025-05-26 16:43:34 +0800102 if (isCollected) {
103 // 取消收藏 - 使用原有的collectPost函数,传递action: "cancel"
Krishya8f2fec82025-06-04 21:54:46 +0800104 await collectPost(postId, user.userId, "cancel");
Krishya57cc17b2025-05-26 16:43:34 +0800105 setIsCollected(false);
106 setPostDetail((prev) => ({
107 ...prev,
108 postCollectNum: prev.postCollectNum - 1,
109 }));
110 } else {
111 // 收藏
Krishya8f2fec82025-06-04 21:54:46 +0800112 await collectPost(postId, user.userId, "collect");
Krishya57cc17b2025-05-26 16:43:34 +0800113 setIsCollected(true);
114 setPostDetail((prev) => ({
115 ...prev,
116 postCollectNum: prev.postCollectNum + 1,
117 }));
118 }
22301009237217b2025-04-20 15:15:25 +0800119 } catch (err) {
Krishya57cc17b2025-05-26 16:43:34 +0800120 console.error('收藏操作失败:', err);
121 alert('收藏操作失败,请稍后再试');
22301009237217b2025-04-20 15:15:25 +0800122 }
Krishya57cc17b2025-05-26 16:43:34 +0800123};
22301009237217b2025-04-20 15:15:25 +0800124
Krishya8f2fec82025-06-04 21:54:46 +0800125// 添加评论
Krishya2283d882025-05-27 22:25:19 +0800126const handleAddComment = async () => {
Krishya8f2fec82025-06-04 21:54:46 +0800127 // 直接使用组件顶层获取的 user
128 if (!user || !user.userId) {
129 alert('请先登录后再评论');
130 return;
131 }
132
Krishya2283d882025-05-27 22:25:19 +0800133 if (!newComment.trim()) {
134 alert('评论内容不能为空');
135 return;
136 }
22301009237217b2025-04-20 15:15:25 +0800137
Krishya2283d882025-05-27 22:25:19 +0800138 try {
Krishya8f2fec82025-06-04 21:54:46 +0800139 // 构建评论数据
Krishya2283d882025-05-27 22:25:19 +0800140 const commentPayload = {
141 content: newComment,
Krishya8f2fec82025-06-04 21:54:46 +0800142 userId: user.userId, // 使用已获取的用户ID
Krishya2283d882025-05-27 22:25:19 +0800143 isAnonymous: false,
144 com_comment_id: replyToCommentId || null,
145 };
146
Krishya8f2fec82025-06-04 21:54:46 +0800147 // 发送评论请求
Krishya2283d882025-05-27 22:25:19 +0800148 const commentData = await addCommentToPost(postId, commentPayload);
149
Krishya8f2fec82025-06-04 21:54:46 +0800150 // 更新评论列表
151 const newCommentItem = {
152 commentId: commentData?.commentId || Date.now(),
153 post_id: postId,
154 userId: user.userId,
155 content: newComment,
156 commentTime: new Date().toISOString(),
157 comCommentId: replyToCommentId,
158 };
Krishya2283d882025-05-27 22:25:19 +0800159
Krishya8f2fec82025-06-04 21:54:46 +0800160 setComments((prevComments) => [newCommentItem, ...prevComments]);
161
162 // 重置表单
Krishya2283d882025-05-27 22:25:19 +0800163 setNewComment('');
164 setReplyToCommentId(null);
Krishya8f2fec82025-06-04 21:54:46 +0800165
166 // alert('评论成功!');
167 } catch (error) {
168 console.error('评论失败:', error);
169
170 const errorMessage =
171 error.response?.data?.message ||
172 error.message ||
173 '评论失败,请稍后再试';
174
175 alert(errorMessage);
Krishya2283d882025-05-27 22:25:19 +0800176 }
177};
178
179
22301009237217b2025-04-20 15:15:25 +0800180
181 // 回复评论
182 const handleReply = (commentId) => {
Krishya2283d882025-05-27 22:25:19 +0800183 setReplyToCommentId(commentId);
184 const comment = comments.find(c => c.commentId === commentId);
185 if (comment) {
186 // 这里用用户名或者用户ID
187 setReplyToUsername(comment.username || comment.userId);
188 } else {
189 setReplyToUsername(null);
190 }
191};
192
193const findUsernameByCommentId = (id) => {
194 const comment = comments.find(c => c.commentId === id);
195 return comment ? (comment.username || comment.userId) : '未知用户';
196};
197
22301009237217b2025-04-20 15:15:25 +0800198
199 return (
200 <div className="post-detail-page">
Krishyac0f7e9b2025-04-22 15:28:28 +0800201 <Header />
22301009237217b2025-04-20 15:15:25 +0800202 {loading ? (
203 <p>加载中...</p>
204 ) : errorMsg ? (
205 <p className="error-text">{errorMsg}</p>
206 ) : postDetail ? (
207 <div className="post-detail">
208 <h1>{postDetail.title}</h1>
209 <div className="post-meta">
Krishya1300cad2025-04-20 22:16:45 +0800210 <span className="post-user">用户ID: {postDetail.user_id}</span>
22301009237217b2025-04-20 15:15:25 +0800211 <span className="post-time">
Krishya1300cad2025-04-20 22:16:45 +0800212 发布时间:{new Date(postDetail.postTime).toLocaleString()}
22301009237217b2025-04-20 15:15:25 +0800213 </span>
22301009237217b2025-04-20 15:15:25 +0800214 </div>
215 <div className="post-content">
216 <p>{postDetail.postContent}</p>
Krishya1300cad2025-04-20 22:16:45 +0800217 {Array.isArray(postDetail.imgUrl) ? (
218 <div className="post-images">
219 {postDetail.imgUrl.map((url, idx) => (
220 <img key={idx} src={url} alt={`图片${idx}`} />
221 ))}
222 </div>
223 ) : (
224 postDetail.imgUrl && (
225 <img className="post-image" src={postDetail.imgUrl} alt="帖子图片" />
226 )
22301009237217b2025-04-20 15:15:25 +0800227 )}
Krishya1300cad2025-04-20 22:16:45 +0800228
22301009237217b2025-04-20 15:15:25 +0800229 </div>
230
231 {/* 点赞和收藏 */}
232 <div className="post-actions">
233 <button
234 className="icon-btn"
235 onClick={toggleLike} // 点赞操作
236 >
237 <GoodTwo
238 theme="outline"
Krishya1300cad2025-04-20 22:16:45 +0800239 size="20"
22301009237217b2025-04-20 15:15:25 +0800240 fill={isLiked ? '#f00' : '#ccc'} // 如果已点赞,显示红色
241 />
242 <span>{postDetail.postLikeNum}</span>
243 </button>
244 <button
245 className="icon-btn"
246 onClick={toggleCollect} // 收藏操作
247 >
248 <Star
249 theme="outline"
Krishya1300cad2025-04-20 22:16:45 +0800250 size="20"
22301009237217b2025-04-20 15:15:25 +0800251 fill={isCollected ? '#ffd700' : '#ccc'} // 如果已收藏,显示金色
252 />
253 <span>{postDetail.postCollectNum}</span>
254 </button>
255 </div>
Krishya1300cad2025-04-20 22:16:45 +0800256
257 <hr className="divider" />
22301009237217b2025-04-20 15:15:25 +0800258 {/* 评论部分 */}
Krishya1300cad2025-04-20 22:16:45 +0800259 <h3>评论区</h3>
Krishya2283d882025-05-27 22:25:19 +0800260 <div className="comments-section">
22301009237217b2025-04-20 15:15:25 +0800261 {comments.length ? (
262 comments.map((comment) => (
263 <div key={comment.commentId} className="comment">
Krishya1300cad2025-04-20 22:16:45 +0800264 <div className="comment-header">
22301009237217b2025-04-20 15:15:25 +0800265 <span className="comment-user">用户 ID: {comment.userId}</span>
Krishya1300cad2025-04-20 22:16:45 +0800266 <button className="reply-btn" onClick={() => handleReply(comment.commentId)}>回复</button>
22301009237217b2025-04-20 15:15:25 +0800267 </div>
Krishya2283d882025-05-27 22:25:19 +0800268
269 <p className="comment-content">
270 {comment.comCommentId ? (
271 <>
272 <span className="reply-to">回复 {findUsernameByCommentId(comment.comCommentId)}:</span>
273 {comment.content}
274 </>
275 ) : (
276 comment.content
277 )}
278 </p>
279
Krishya1300cad2025-04-20 22:16:45 +0800280 <div className="comment-time">
281 {new Date(comment.commentTime).toLocaleString()}
282 </div>
22301009237217b2025-04-20 15:15:25 +0800283
Krishya2283d882025-05-27 22:25:19 +0800284 {/* 回复框 */}
22301009237217b2025-04-20 15:15:25 +0800285 {replyToCommentId === comment.commentId && (
286 <div className="reply-form">
Krishya2283d882025-05-27 22:25:19 +0800287 <div className="replying-to">
288 回复 <strong>{replyToUsername}</strong>:
289 </div>
22301009237217b2025-04-20 15:15:25 +0800290 <textarea
291 placeholder="输入你的回复..."
292 value={newComment}
293 onChange={(e) => setNewComment(e.target.value)}
294 />
295 <div className="comment-options">
22301009237217b2025-04-20 15:15:25 +0800296 <button onClick={handleAddComment}>发布回复</button>
297 </div>
298 </div>
299 )}
300 </div>
301 ))
302 ) : (
303 <p>暂无评论</p>
304 )}
305
Krishya2283d882025-05-27 22:25:19 +0800306
22301009237217b2025-04-20 15:15:25 +0800307 {/* 添加评论表单 */}
308 <div className="add-comment-form">
309 <textarea
310 placeholder="输入你的评论..."
311 value={newComment}
312 onChange={(e) => setNewComment(e.target.value)}
313 />
314 <div className="comment-options">
Krishya57cc17b2025-05-26 16:43:34 +0800315 {/* <label>
22301009237217b2025-04-20 15:15:25 +0800316 <input
317 type="checkbox"
318 checked={isAnonymous}
319 onChange={() => setIsAnonymous(!isAnonymous)}
320 />
321 匿名评论
Krishya57cc17b2025-05-26 16:43:34 +0800322 </label> */}
22301009237217b2025-04-20 15:15:25 +0800323 <button onClick={handleAddComment}>发布评论</button>
324 </div>
325 </div>
326 </div>
Krishya7ec1dd02025-04-19 15:29:03 +0800327 </div>
22301009237217b2025-04-20 15:15:25 +0800328 ) : (
329 <p>帖子不存在</p>
330 )}
331 </div>
332 );
Krishya7ec1dd02025-04-19 15:29:03 +0800333};
334
Krishya57cc17b2025-05-26 16:43:34 +0800335export default PostDetailPage;