blob: c58ed33198e31ace62f0b889f22149a0076fa95b [file] [log] [blame]
Krishya57cc17b2025-05-26 16:43:34 +08001// import React, { useEffect, useState } from 'react';
2// import { useParams } from 'wouter';
3// import { GoodTwo, Star } from '@icon-park/react';
4// import { getPostDetail, getPostComments, likePost, unlikePost, addCommentToPost, collectPost } from './api'; // 引入你的 API 函数
5// import './PostDetailPage.css';
6// import { useUser } from '../../../context/UserContext'; // 注意路径
7// import Header from '../../../components/Header';
8
9// const PostDetailPage = () => {
10// 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(''); // 新评论内容
16// const [isAnonymous, setIsAnonymous] = useState(false); // 是否匿名
17// const [isLiked, setIsLiked] = useState(false); // 是否已点赞
18// const [isCollected, setIsCollected] = useState(false); // 是否已收藏
19// const [replyToCommentId, setReplyToCommentId] = useState(null); // 回复的评论ID
20
21// // 获取当前用户ID(假设从上下文中获取)
22// const { user } = useUser(); // 你需要从用户上下文获取用户 ID
23
24// useEffect(() => {
25// const fetchPostDetail = async () => {
26// setLoading(true);
27// setErrorMsg('');
28// try {
29// // 获取帖子详情
30// const postData = await getPostDetail(postId);
31// setPostDetail(postData);
32
33// // 获取帖子评论
34// const commentsData = await getPostComments(postId);
35// setComments(commentsData);
36
37// // 设置是否已经点赞
38// if (postData.likedByUser) {
39// setIsLiked(true);
40// } else {
41// setIsLiked(false);
42// }
43
44// // 设置是否已经收藏
45// if (postData.collectedByUser) {
46// setIsCollected(true);
47// } else {
48// setIsCollected(false);
49// }
50// } catch (err) {
51// console.error('加载失败:', err);
52// setErrorMsg('加载失败,请稍后重试');
53// } finally {
54// setLoading(false);
55// }
56// };
57
58// fetchPostDetail();
59// }, [postId]);
60
61// // 点赞功能
62// const toggleLike = async () => {
63// if (!user) {
64// alert('请先登录');
65// return;
66// }
67
68// try {
69// if (isLiked) {
70// // 取消点赞
71// await unlikePost(postId, user.id);
72// setIsLiked(false);
73// setPostDetail((prev) => ({
74// ...prev,
75// postLikeNum: prev.postLikeNum - 1,
76// }));
77// } else {
78// // 点赞
79// await likePost(postId, user.id);
80// setIsLiked(true);
81// setPostDetail((prev) => ({
82// ...prev,
83// postLikeNum: prev.postLikeNum + 1,
84// }));
85// }
86// } catch (err) {
87// console.error('点赞失败:', err);
88// alert('点赞失败,请稍后再试');
89// }
90// };
91
92// // 收藏功能
93// const toggleCollect = async () => {
94// if (!user) {
95// alert('请先登录');
96// return;
97// }
98
99// try {
100// const action = isCollected ? 'cancel' : 'collect';
101// // 调用收藏 API
102// await collectPost(postId, user.id, action);
103// setIsCollected(!isCollected);
104// setPostDetail((prev) => ({
105// ...prev,
106// postCollectNum: isCollected ? prev.postCollectNum - 1 : prev.postCollectNum + 1,
107// }));
108// } catch (err) {
109// console.error('收藏失败:', err);
110// alert('收藏失败,请稍后再试');
111// }
112// };
113
114// // 添加评论
115// const handleAddComment = async () => {
116// if (!newComment.trim()) {
117// alert('评论内容不能为空');
118// return;
119// }
120
121// try {
122// // 调用 API 添加评论,若为回复评论则传递父评论ID(com_comment_id)
123// const commentData = await addCommentToPost(postId, user.id, newComment, isAnonymous, replyToCommentId);
124// // 更新评论列表
125// setComments((prev) => [
126// ...prev,
127// {
128// commentId: commentData.commentId,
129// post_id: postId,
130// userId: user.id,
131// content: newComment,
132// isAnonymous,
133// commentTime: new Date().toISOString(),
134// comCommentId: replyToCommentId, // 回复评论时传递父评论ID
135// },
136// ]);
137// // 清空评论框和回复状态
138// setNewComment('');
139// setReplyToCommentId(null);
140// } catch (err) {
141// console.error('评论添加失败:', err);
142// alert('评论失败,请稍后再试');
143// }
144// };
145
146// // 回复评论
147// const handleReply = (commentId) => {
148// setReplyToCommentId(commentId); // 设置父评论ID为当前评论的ID
149// };
150
151// return (
152// <div className="post-detail-page">
153// <Header />
154// {loading ? (
155// <p>加载中...</p>
156// ) : errorMsg ? (
157// <p className="error-text">{errorMsg}</p>
158// ) : postDetail ? (
159// <div className="post-detail">
160// <h1>{postDetail.title}</h1>
161// <div className="post-meta">
162// <span className="post-user">用户ID: {postDetail.user_id}</span>
163// <span className="post-time">
164// 发布时间:{new Date(postDetail.postTime).toLocaleString()}
165// </span>
166// </div>
167// <div className="post-content">
168// <p>{postDetail.postContent}</p>
169// {Array.isArray(postDetail.imgUrl) ? (
170// <div className="post-images">
171// {postDetail.imgUrl.map((url, idx) => (
172// <img key={idx} src={url} alt={`图片${idx}`} />
173// ))}
174// </div>
175// ) : (
176// postDetail.imgUrl && (
177// <img className="post-image" src={postDetail.imgUrl} alt="帖子图片" />
178// )
179// )}
180
181// </div>
182
183// {/* 点赞和收藏 */}
184// <div className="post-actions">
185// <button
186// className="icon-btn"
187// onClick={toggleLike} // 点赞操作
188// >
189// <GoodTwo
190// theme="outline"
191// size="20"
192// fill={isLiked ? '#f00' : '#ccc'} // 如果已点赞,显示红色
193// />
194// <span>{postDetail.postLikeNum}</span>
195// </button>
196// <button
197// className="icon-btn"
198// onClick={toggleCollect} // 收藏操作
199// >
200// <Star
201// theme="outline"
202// size="20"
203// fill={isCollected ? '#ffd700' : '#ccc'} // 如果已收藏,显示金色
204// />
205// <span>{postDetail.postCollectNum}</span>
206// </button>
207// </div>
208
209// <hr className="divider" />
210// {/* 评论部分 */}
211// <h3>评论区</h3>
212// <div className="comments-section">
213// {comments.length ? (
214// comments.map((comment) => (
215// <div key={comment.commentId} className="comment">
216// <div className="comment-header">
217// <span className="comment-user">用户 ID: {comment.userId}</span>
218// <button className="reply-btn" onClick={() => handleReply(comment.commentId)}>回复</button>
219// </div>
220// <p className="comment-content">{comment.content}</p>
221// <div className="comment-time">
222// {new Date(comment.commentTime).toLocaleString()}
223// </div>
224
225// {/* 回复框,只有在当前评论是正在回复的评论时显示 */}
226// {replyToCommentId === comment.commentId && (
227// <div className="reply-form">
228// <textarea
229// placeholder="输入你的回复..."
230// value={newComment}
231// onChange={(e) => setNewComment(e.target.value)}
232// />
233// <div className="comment-options">
234// <label>
235// <input
236// type="checkbox"
237// checked={isAnonymous}
238// onChange={() => setIsAnonymous(!isAnonymous)}
239// />
240// 匿名评论
241// </label>
242// <button onClick={handleAddComment}>发布回复</button>
243// </div>
244// </div>
245// )}
246// </div>
247// ))
248// ) : (
249// <p>暂无评论</p>
250// )}
251
252// {/* 添加评论表单 */}
253// <div className="add-comment-form">
254// <textarea
255// placeholder="输入你的评论..."
256// value={newComment}
257// onChange={(e) => setNewComment(e.target.value)}
258// />
259// <div className="comment-options">
260// <label>
261// <input
262// type="checkbox"
263// checked={isAnonymous}
264// onChange={() => setIsAnonymous(!isAnonymous)}
265// />
266// 匿名评论
267// </label>
268// <button onClick={handleAddComment}>发布评论</button>
269// </div>
270// </div>
271// </div>
272// </div>
273// ) : (
274// <p>帖子不存在</p>
275// )}
276// </div>
277// );
278// };
279
280// export default PostDetailPage;
281
22301009237217b2025-04-20 15:15:25 +0800282import React, { useEffect, useState } from 'react';
283import { useParams } from 'wouter';
284import { GoodTwo, Star } from '@icon-park/react';
Krishya57cc17b2025-05-26 16:43:34 +0800285import { getPostDetail, getPostComments, likePost, unlikePost, addCommentToPost, collectPost, uncollectPost } from './api'; // 引入你的 API 函数
Krishya7ec1dd02025-04-19 15:29:03 +0800286import './PostDetailPage.css';
22301009237217b2025-04-20 15:15:25 +0800287import { useUser } from '../../../context/UserContext'; // 注意路径
Krishyac0f7e9b2025-04-22 15:28:28 +0800288import Header from '../../../components/Header';
Krishya7ec1dd02025-04-19 15:29:03 +0800289
290const PostDetailPage = () => {
22301009237217b2025-04-20 15:15:25 +0800291 const { postId } = useParams(); // 获取帖子ID
292 const [postDetail, setPostDetail] = useState(null);
293 const [comments, setComments] = useState([]);
294 const [loading, setLoading] = useState(true);
295 const [errorMsg, setErrorMsg] = useState('');
296 const [newComment, setNewComment] = useState(''); // 新评论内容
Krishya57cc17b2025-05-26 16:43:34 +0800297 // const [isAnonymous, setIsAnonymous] = useState(false); // 是否匿名
22301009237217b2025-04-20 15:15:25 +0800298 const [isLiked, setIsLiked] = useState(false); // 是否已点赞
299 const [isCollected, setIsCollected] = useState(false); // 是否已收藏
300 const [replyToCommentId, setReplyToCommentId] = useState(null); // 回复的评论ID
Krishya7ec1dd02025-04-19 15:29:03 +0800301
22301009237217b2025-04-20 15:15:25 +0800302 // 获取当前用户ID(假设从上下文中获取)
303 const { user } = useUser(); // 你需要从用户上下文获取用户 ID
Krishya7ec1dd02025-04-19 15:29:03 +0800304
22301009237217b2025-04-20 15:15:25 +0800305 useEffect(() => {
306 const fetchPostDetail = async () => {
307 setLoading(true);
308 setErrorMsg('');
309 try {
310 // 获取帖子详情
311 const postData = await getPostDetail(postId);
312 setPostDetail(postData);
Krishya7ec1dd02025-04-19 15:29:03 +0800313
22301009237217b2025-04-20 15:15:25 +0800314 // 获取帖子评论
315 const commentsData = await getPostComments(postId);
316 setComments(commentsData);
Krishya7ec1dd02025-04-19 15:29:03 +0800317
22301009237217b2025-04-20 15:15:25 +0800318 // 设置是否已经点赞
319 if (postData.likedByUser) {
320 setIsLiked(true);
Krishya7ec1dd02025-04-19 15:29:03 +0800321 } else {
22301009237217b2025-04-20 15:15:25 +0800322 setIsLiked(false);
Krishya7ec1dd02025-04-19 15:29:03 +0800323 }
Krishya7ec1dd02025-04-19 15:29:03 +0800324
22301009237217b2025-04-20 15:15:25 +0800325 // 设置是否已经收藏
326 if (postData.collectedByUser) {
327 setIsCollected(true);
Krishya7ec1dd02025-04-19 15:29:03 +0800328 } else {
22301009237217b2025-04-20 15:15:25 +0800329 setIsCollected(false);
Krishya7ec1dd02025-04-19 15:29:03 +0800330 }
22301009237217b2025-04-20 15:15:25 +0800331 } catch (err) {
332 console.error('加载失败:', err);
333 setErrorMsg('加载失败,请稍后重试');
334 } finally {
335 setLoading(false);
336 }
Krishya7ec1dd02025-04-19 15:29:03 +0800337 };
338
22301009237217b2025-04-20 15:15:25 +0800339 fetchPostDetail();
340 }, [postId]);
Krishya7ec1dd02025-04-19 15:29:03 +0800341
22301009237217b2025-04-20 15:15:25 +0800342 // 点赞功能
343 const toggleLike = async () => {
344 if (!user) {
345 alert('请先登录');
346 return;
347 }
Krishya7ec1dd02025-04-19 15:29:03 +0800348
22301009237217b2025-04-20 15:15:25 +0800349 try {
350 if (isLiked) {
351 // 取消点赞
352 await unlikePost(postId, user.id);
353 setIsLiked(false);
354 setPostDetail((prev) => ({
355 ...prev,
356 postLikeNum: prev.postLikeNum - 1,
357 }));
358 } else {
359 // 点赞
360 await likePost(postId, user.id);
361 setIsLiked(true);
362 setPostDetail((prev) => ({
363 ...prev,
364 postLikeNum: prev.postLikeNum + 1,
365 }));
366 }
367 } catch (err) {
368 console.error('点赞失败:', err);
369 alert('点赞失败,请稍后再试');
370 }
371 };
Krishya7ec1dd02025-04-19 15:29:03 +0800372
Krishya57cc17b2025-05-26 16:43:34 +0800373// 收藏功能
374const toggleCollect = async () => {
22301009237217b2025-04-20 15:15:25 +0800375 if (!user) {
Krishya57cc17b2025-05-26 16:43:34 +0800376 alert('请先登录');
377 return;
22301009237217b2025-04-20 15:15:25 +0800378 }
Krishya7ec1dd02025-04-19 15:29:03 +0800379
22301009237217b2025-04-20 15:15:25 +0800380 try {
Krishya57cc17b2025-05-26 16:43:34 +0800381 if (isCollected) {
382 // 取消收藏 - 使用原有的collectPost函数,传递action: "cancel"
383 await collectPost(postId, user.id, "cancel");
384 setIsCollected(false);
385 setPostDetail((prev) => ({
386 ...prev,
387 postCollectNum: prev.postCollectNum - 1,
388 }));
389 } else {
390 // 收藏
391 await collectPost(postId, user.id, "collect");
392 setIsCollected(true);
393 setPostDetail((prev) => ({
394 ...prev,
395 postCollectNum: prev.postCollectNum + 1,
396 }));
397 }
22301009237217b2025-04-20 15:15:25 +0800398 } catch (err) {
Krishya57cc17b2025-05-26 16:43:34 +0800399 console.error('收藏操作失败:', err);
400 alert('收藏操作失败,请稍后再试');
22301009237217b2025-04-20 15:15:25 +0800401 }
Krishya57cc17b2025-05-26 16:43:34 +0800402};
22301009237217b2025-04-20 15:15:25 +0800403
404 // 添加评论
405 const handleAddComment = async () => {
406 if (!newComment.trim()) {
407 alert('评论内容不能为空');
408 return;
409 }
410
411 try {
412 // 调用 API 添加评论,若为回复评论则传递父评论ID(com_comment_id)
Krishya57cc17b2025-05-26 16:43:34 +0800413 const commentData = await addCommentToPost(postId, user.id, newComment, replyToCommentId);
22301009237217b2025-04-20 15:15:25 +0800414 // 更新评论列表
415 setComments((prev) => [
416 ...prev,
417 {
418 commentId: commentData.commentId,
419 post_id: postId,
420 userId: user.id,
421 content: newComment,
Krishya57cc17b2025-05-26 16:43:34 +0800422 // isAnonymous,
22301009237217b2025-04-20 15:15:25 +0800423 commentTime: new Date().toISOString(),
424 comCommentId: replyToCommentId, // 回复评论时传递父评论ID
425 },
426 ]);
427 // 清空评论框和回复状态
428 setNewComment('');
429 setReplyToCommentId(null);
430 } catch (err) {
431 console.error('评论添加失败:', err);
432 alert('评论失败,请稍后再试');
433 }
434 };
435
436 // 回复评论
437 const handleReply = (commentId) => {
438 setReplyToCommentId(commentId); // 设置父评论ID为当前评论的ID
439 };
440
441 return (
442 <div className="post-detail-page">
Krishyac0f7e9b2025-04-22 15:28:28 +0800443 <Header />
22301009237217b2025-04-20 15:15:25 +0800444 {loading ? (
445 <p>加载中...</p>
446 ) : errorMsg ? (
447 <p className="error-text">{errorMsg}</p>
448 ) : postDetail ? (
449 <div className="post-detail">
450 <h1>{postDetail.title}</h1>
451 <div className="post-meta">
Krishya1300cad2025-04-20 22:16:45 +0800452 <span className="post-user">用户ID: {postDetail.user_id}</span>
22301009237217b2025-04-20 15:15:25 +0800453 <span className="post-time">
Krishya1300cad2025-04-20 22:16:45 +0800454 发布时间:{new Date(postDetail.postTime).toLocaleString()}
22301009237217b2025-04-20 15:15:25 +0800455 </span>
22301009237217b2025-04-20 15:15:25 +0800456 </div>
457 <div className="post-content">
458 <p>{postDetail.postContent}</p>
Krishya1300cad2025-04-20 22:16:45 +0800459 {Array.isArray(postDetail.imgUrl) ? (
460 <div className="post-images">
461 {postDetail.imgUrl.map((url, idx) => (
462 <img key={idx} src={url} alt={`图片${idx}`} />
463 ))}
464 </div>
465 ) : (
466 postDetail.imgUrl && (
467 <img className="post-image" src={postDetail.imgUrl} alt="帖子图片" />
468 )
22301009237217b2025-04-20 15:15:25 +0800469 )}
Krishya1300cad2025-04-20 22:16:45 +0800470
22301009237217b2025-04-20 15:15:25 +0800471 </div>
472
473 {/* 点赞和收藏 */}
474 <div className="post-actions">
475 <button
476 className="icon-btn"
477 onClick={toggleLike} // 点赞操作
478 >
479 <GoodTwo
480 theme="outline"
Krishya1300cad2025-04-20 22:16:45 +0800481 size="20"
22301009237217b2025-04-20 15:15:25 +0800482 fill={isLiked ? '#f00' : '#ccc'} // 如果已点赞,显示红色
483 />
484 <span>{postDetail.postLikeNum}</span>
485 </button>
486 <button
487 className="icon-btn"
488 onClick={toggleCollect} // 收藏操作
489 >
490 <Star
491 theme="outline"
Krishya1300cad2025-04-20 22:16:45 +0800492 size="20"
22301009237217b2025-04-20 15:15:25 +0800493 fill={isCollected ? '#ffd700' : '#ccc'} // 如果已收藏,显示金色
494 />
495 <span>{postDetail.postCollectNum}</span>
496 </button>
497 </div>
Krishya1300cad2025-04-20 22:16:45 +0800498
499 <hr className="divider" />
22301009237217b2025-04-20 15:15:25 +0800500 {/* 评论部分 */}
Krishya1300cad2025-04-20 22:16:45 +0800501 <h3>评论区</h3>
22301009237217b2025-04-20 15:15:25 +0800502 <div className="comments-section">
22301009237217b2025-04-20 15:15:25 +0800503 {comments.length ? (
504 comments.map((comment) => (
505 <div key={comment.commentId} className="comment">
Krishya1300cad2025-04-20 22:16:45 +0800506 <div className="comment-header">
22301009237217b2025-04-20 15:15:25 +0800507 <span className="comment-user">用户 ID: {comment.userId}</span>
Krishya1300cad2025-04-20 22:16:45 +0800508 <button className="reply-btn" onClick={() => handleReply(comment.commentId)}>回复</button>
22301009237217b2025-04-20 15:15:25 +0800509 </div>
Krishya1300cad2025-04-20 22:16:45 +0800510 <p className="comment-content">{comment.content}</p>
511 <div className="comment-time">
512 {new Date(comment.commentTime).toLocaleString()}
513 </div>
22301009237217b2025-04-20 15:15:25 +0800514
515 {/* 回复框,只有在当前评论是正在回复的评论时显示 */}
516 {replyToCommentId === comment.commentId && (
517 <div className="reply-form">
518 <textarea
519 placeholder="输入你的回复..."
520 value={newComment}
521 onChange={(e) => setNewComment(e.target.value)}
522 />
523 <div className="comment-options">
Krishya57cc17b2025-05-26 16:43:34 +0800524 {/* <label> */}
525 {/* <input */}
526 {/* type="checkbox" */}
527 {/* checked={isAnonymous} */}
528 {/* onChange={() => setIsAnonymous(!isAnonymous)} */}
529 {/* /> */}
530 {/* 匿名评论 */}
531 {/* </label> */}
22301009237217b2025-04-20 15:15:25 +0800532 <button onClick={handleAddComment}>发布回复</button>
533 </div>
534 </div>
535 )}
536 </div>
537 ))
538 ) : (
539 <p>暂无评论</p>
540 )}
541
542 {/* 添加评论表单 */}
543 <div className="add-comment-form">
544 <textarea
545 placeholder="输入你的评论..."
546 value={newComment}
547 onChange={(e) => setNewComment(e.target.value)}
548 />
549 <div className="comment-options">
Krishya57cc17b2025-05-26 16:43:34 +0800550 {/* <label>
22301009237217b2025-04-20 15:15:25 +0800551 <input
552 type="checkbox"
553 checked={isAnonymous}
554 onChange={() => setIsAnonymous(!isAnonymous)}
555 />
556 匿名评论
Krishya57cc17b2025-05-26 16:43:34 +0800557 </label> */}
22301009237217b2025-04-20 15:15:25 +0800558 <button onClick={handleAddComment}>发布评论</button>
559 </div>
560 </div>
561 </div>
Krishya7ec1dd02025-04-19 15:29:03 +0800562 </div>
22301009237217b2025-04-20 15:15:25 +0800563 ) : (
564 <p>帖子不存在</p>
565 )}
566 </div>
567 );
Krishya7ec1dd02025-04-19 15:29:03 +0800568};
569
Krishya57cc17b2025-05-26 16:43:34 +0800570export default PostDetailPage;