blob: a272fb8e2c7e1cf813695b0ea133a00ba9da7942 [file] [log] [blame]
22301009237217b2025-04-20 15:15:25 +08001import React, { useEffect, useState } from 'react';
2import { useParams } from 'wouter';
3import { GoodTwo, Star } from '@icon-park/react';
4import { getPostDetail, getPostComments, likePost, unlikePost, addCommentToPost, collectPost } from './api'; // 引入你的 API 函数
Krishya7ec1dd02025-04-19 15:29:03 +08005import './PostDetailPage.css';
22301009237217b2025-04-20 15:15:25 +08006import { useUser } from '../../../context/UserContext'; // 注意路径
Krishya7ec1dd02025-04-19 15:29:03 +08007
8const PostDetailPage = () => {
22301009237217b2025-04-20 15:15:25 +08009 const { postId } = useParams(); // 获取帖子ID
10 const [postDetail, setPostDetail] = useState(null);
11 const [comments, setComments] = useState([]);
12 const [loading, setLoading] = useState(true);
13 const [errorMsg, setErrorMsg] = useState('');
14 const [newComment, setNewComment] = useState(''); // 新评论内容
15 const [isAnonymous, setIsAnonymous] = useState(false); // 是否匿名
16 const [isLiked, setIsLiked] = useState(false); // 是否已点赞
17 const [isCollected, setIsCollected] = useState(false); // 是否已收藏
18 const [replyToCommentId, setReplyToCommentId] = useState(null); // 回复的评论ID
Krishya7ec1dd02025-04-19 15:29:03 +080019
22301009237217b2025-04-20 15:15:25 +080020 // 获取当前用户ID(假设从上下文中获取)
21 const { user } = useUser(); // 你需要从用户上下文获取用户 ID
Krishya7ec1dd02025-04-19 15:29:03 +080022
22301009237217b2025-04-20 15:15:25 +080023 useEffect(() => {
24 const fetchPostDetail = async () => {
25 setLoading(true);
26 setErrorMsg('');
27 try {
28 // 获取帖子详情
29 const postData = await getPostDetail(postId);
30 setPostDetail(postData);
Krishya7ec1dd02025-04-19 15:29:03 +080031
22301009237217b2025-04-20 15:15:25 +080032 // 获取帖子评论
33 const commentsData = await getPostComments(postId);
34 setComments(commentsData);
Krishya7ec1dd02025-04-19 15:29:03 +080035
22301009237217b2025-04-20 15:15:25 +080036 // 设置是否已经点赞
37 if (postData.likedByUser) {
38 setIsLiked(true);
Krishya7ec1dd02025-04-19 15:29:03 +080039 } else {
22301009237217b2025-04-20 15:15:25 +080040 setIsLiked(false);
Krishya7ec1dd02025-04-19 15:29:03 +080041 }
Krishya7ec1dd02025-04-19 15:29:03 +080042
22301009237217b2025-04-20 15:15:25 +080043 // 设置是否已经收藏
44 if (postData.collectedByUser) {
45 setIsCollected(true);
Krishya7ec1dd02025-04-19 15:29:03 +080046 } else {
22301009237217b2025-04-20 15:15:25 +080047 setIsCollected(false);
Krishya7ec1dd02025-04-19 15:29:03 +080048 }
22301009237217b2025-04-20 15:15:25 +080049 } catch (err) {
50 console.error('加载失败:', err);
51 setErrorMsg('加载失败,请稍后重试');
52 } finally {
53 setLoading(false);
54 }
Krishya7ec1dd02025-04-19 15:29:03 +080055 };
56
22301009237217b2025-04-20 15:15:25 +080057 fetchPostDetail();
58 }, [postId]);
Krishya7ec1dd02025-04-19 15:29:03 +080059
22301009237217b2025-04-20 15:15:25 +080060 // 点赞功能
61 const toggleLike = async () => {
62 if (!user) {
63 alert('请先登录');
64 return;
65 }
Krishya7ec1dd02025-04-19 15:29:03 +080066
22301009237217b2025-04-20 15:15:25 +080067 try {
68 if (isLiked) {
69 // 取消点赞
70 await unlikePost(postId, user.id);
71 setIsLiked(false);
72 setPostDetail((prev) => ({
73 ...prev,
74 postLikeNum: prev.postLikeNum - 1,
75 }));
76 } else {
77 // 点赞
78 await likePost(postId, user.id);
79 setIsLiked(true);
80 setPostDetail((prev) => ({
81 ...prev,
82 postLikeNum: prev.postLikeNum + 1,
83 }));
84 }
85 } catch (err) {
86 console.error('点赞失败:', err);
87 alert('点赞失败,请稍后再试');
88 }
89 };
Krishya7ec1dd02025-04-19 15:29:03 +080090
22301009237217b2025-04-20 15:15:25 +080091 // 收藏功能
92 const toggleCollect = async () => {
93 if (!user) {
94 alert('请先登录');
95 return;
96 }
Krishya7ec1dd02025-04-19 15:29:03 +080097
22301009237217b2025-04-20 15:15:25 +080098 try {
99 const action = isCollected ? 'cancel' : 'collect';
100 // 调用收藏 API
101 await collectPost(postId, user.id, action);
102 setIsCollected(!isCollected);
103 setPostDetail((prev) => ({
104 ...prev,
105 postCollectNum: isCollected ? prev.postCollectNum - 1 : prev.postCollectNum + 1,
106 }));
107 } catch (err) {
108 console.error('收藏失败:', err);
109 alert('收藏失败,请稍后再试');
110 }
111 };
112
113 // 添加评论
114 const handleAddComment = async () => {
115 if (!newComment.trim()) {
116 alert('评论内容不能为空');
117 return;
118 }
119
120 try {
121 // 调用 API 添加评论,若为回复评论则传递父评论ID(com_comment_id)
122 const commentData = await addCommentToPost(postId, user.id, newComment, isAnonymous, replyToCommentId);
123 // 更新评论列表
124 setComments((prev) => [
125 ...prev,
126 {
127 commentId: commentData.commentId,
128 post_id: postId,
129 userId: user.id,
130 content: newComment,
131 isAnonymous,
132 commentTime: new Date().toISOString(),
133 comCommentId: replyToCommentId, // 回复评论时传递父评论ID
134 },
135 ]);
136 // 清空评论框和回复状态
137 setNewComment('');
138 setReplyToCommentId(null);
139 } catch (err) {
140 console.error('评论添加失败:', err);
141 alert('评论失败,请稍后再试');
142 }
143 };
144
145 // 回复评论
146 const handleReply = (commentId) => {
147 setReplyToCommentId(commentId); // 设置父评论ID为当前评论的ID
148 };
149
150 return (
151 <div className="post-detail-page">
152 {loading ? (
153 <p>加载中...</p>
154 ) : errorMsg ? (
155 <p className="error-text">{errorMsg}</p>
156 ) : postDetail ? (
157 <div className="post-detail">
158 <h1>{postDetail.title}</h1>
159 <div className="post-meta">
Krishya1300cad2025-04-20 22:16:45 +0800160 <span className="post-user">用户ID: {postDetail.user_id}</span>
22301009237217b2025-04-20 15:15:25 +0800161 <span className="post-time">
Krishya1300cad2025-04-20 22:16:45 +0800162 发布时间:{new Date(postDetail.postTime).toLocaleString()}
22301009237217b2025-04-20 15:15:25 +0800163 </span>
22301009237217b2025-04-20 15:15:25 +0800164 </div>
165 <div className="post-content">
166 <p>{postDetail.postContent}</p>
Krishya1300cad2025-04-20 22:16:45 +0800167 {Array.isArray(postDetail.imgUrl) ? (
168 <div className="post-images">
169 {postDetail.imgUrl.map((url, idx) => (
170 <img key={idx} src={url} alt={`图片${idx}`} />
171 ))}
172 </div>
173 ) : (
174 postDetail.imgUrl && (
175 <img className="post-image" src={postDetail.imgUrl} alt="帖子图片" />
176 )
22301009237217b2025-04-20 15:15:25 +0800177 )}
Krishya1300cad2025-04-20 22:16:45 +0800178
22301009237217b2025-04-20 15:15:25 +0800179 </div>
180
181 {/* 点赞和收藏 */}
182 <div className="post-actions">
183 <button
184 className="icon-btn"
185 onClick={toggleLike} // 点赞操作
186 >
187 <GoodTwo
188 theme="outline"
Krishya1300cad2025-04-20 22:16:45 +0800189 size="20"
22301009237217b2025-04-20 15:15:25 +0800190 fill={isLiked ? '#f00' : '#ccc'} // 如果已点赞,显示红色
191 />
192 <span>{postDetail.postLikeNum}</span>
193 </button>
194 <button
195 className="icon-btn"
196 onClick={toggleCollect} // 收藏操作
197 >
198 <Star
199 theme="outline"
Krishya1300cad2025-04-20 22:16:45 +0800200 size="20"
22301009237217b2025-04-20 15:15:25 +0800201 fill={isCollected ? '#ffd700' : '#ccc'} // 如果已收藏,显示金色
202 />
203 <span>{postDetail.postCollectNum}</span>
204 </button>
205 </div>
Krishya1300cad2025-04-20 22:16:45 +0800206
207 <hr className="divider" />
22301009237217b2025-04-20 15:15:25 +0800208 {/* 评论部分 */}
Krishya1300cad2025-04-20 22:16:45 +0800209 <h3>评论区</h3>
22301009237217b2025-04-20 15:15:25 +0800210 <div className="comments-section">
22301009237217b2025-04-20 15:15:25 +0800211 {comments.length ? (
212 comments.map((comment) => (
213 <div key={comment.commentId} className="comment">
Krishya1300cad2025-04-20 22:16:45 +0800214 <div className="comment-header">
22301009237217b2025-04-20 15:15:25 +0800215 <span className="comment-user">用户 ID: {comment.userId}</span>
Krishya1300cad2025-04-20 22:16:45 +0800216 <button className="reply-btn" onClick={() => handleReply(comment.commentId)}>回复</button>
22301009237217b2025-04-20 15:15:25 +0800217 </div>
Krishya1300cad2025-04-20 22:16:45 +0800218 <p className="comment-content">{comment.content}</p>
219 <div className="comment-time">
220 {new Date(comment.commentTime).toLocaleString()}
221 </div>
22301009237217b2025-04-20 15:15:25 +0800222
223 {/* 回复框,只有在当前评论是正在回复的评论时显示 */}
224 {replyToCommentId === comment.commentId && (
225 <div className="reply-form">
226 <textarea
227 placeholder="输入你的回复..."
228 value={newComment}
229 onChange={(e) => setNewComment(e.target.value)}
230 />
231 <div className="comment-options">
232 <label>
233 <input
234 type="checkbox"
235 checked={isAnonymous}
236 onChange={() => setIsAnonymous(!isAnonymous)}
237 />
238 匿名评论
239 </label>
240 <button onClick={handleAddComment}>发布回复</button>
241 </div>
242 </div>
243 )}
244 </div>
245 ))
246 ) : (
247 <p>暂无评论</p>
248 )}
249
250 {/* 添加评论表单 */}
251 <div className="add-comment-form">
252 <textarea
253 placeholder="输入你的评论..."
254 value={newComment}
255 onChange={(e) => setNewComment(e.target.value)}
256 />
257 <div className="comment-options">
258 <label>
259 <input
260 type="checkbox"
261 checked={isAnonymous}
262 onChange={() => setIsAnonymous(!isAnonymous)}
263 />
264 匿名评论
265 </label>
266 <button onClick={handleAddComment}>发布评论</button>
267 </div>
268 </div>
269 </div>
Krishya7ec1dd02025-04-19 15:29:03 +0800270 </div>
22301009237217b2025-04-20 15:15:25 +0800271 ) : (
272 <p>帖子不存在</p>
273 )}
274 </div>
275 );
Krishya7ec1dd02025-04-19 15:29:03 +0800276};
277
22301009237217b2025-04-20 15:15:25 +0800278export default PostDetailPage;