blob: a505d88d02db0bcbf1bd1dbbc6e3e3642db43a97 [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';
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';
22301009237217b2025-04-20 15:15:25 +08006import { 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(假设从上下文中获取)
23 const { user } = useUser(); // 你需要从用户上下文获取用户 ID
Krishya7ec1dd02025-04-19 15:29:03 +080024
22301009237217b2025-04-20 15:15:25 +080025 useEffect(() => {
26 const fetchPostDetail = async () => {
27 setLoading(true);
28 setErrorMsg('');
29 try {
30 // 获取帖子详情
31 const postData = await getPostDetail(postId);
32 setPostDetail(postData);
Krishya7ec1dd02025-04-19 15:29:03 +080033
22301009237217b2025-04-20 15:15:25 +080034 // 获取帖子评论
35 const commentsData = await getPostComments(postId);
36 setComments(commentsData);
Krishya7ec1dd02025-04-19 15:29:03 +080037
22301009237217b2025-04-20 15:15:25 +080038 // 设置是否已经点赞
39 if (postData.likedByUser) {
40 setIsLiked(true);
Krishya7ec1dd02025-04-19 15:29:03 +080041 } else {
22301009237217b2025-04-20 15:15:25 +080042 setIsLiked(false);
Krishya7ec1dd02025-04-19 15:29:03 +080043 }
Krishya7ec1dd02025-04-19 15:29:03 +080044
22301009237217b2025-04-20 15:15:25 +080045 // 设置是否已经收藏
46 if (postData.collectedByUser) {
47 setIsCollected(true);
Krishya7ec1dd02025-04-19 15:29:03 +080048 } else {
22301009237217b2025-04-20 15:15:25 +080049 setIsCollected(false);
Krishya7ec1dd02025-04-19 15:29:03 +080050 }
22301009237217b2025-04-20 15:15:25 +080051 } catch (err) {
52 console.error('加载失败:', err);
53 setErrorMsg('加载失败,请稍后重试');
54 } finally {
55 setLoading(false);
56 }
Krishya7ec1dd02025-04-19 15:29:03 +080057 };
58
22301009237217b2025-04-20 15:15:25 +080059 fetchPostDetail();
60 }, [postId]);
Krishya7ec1dd02025-04-19 15:29:03 +080061
22301009237217b2025-04-20 15:15:25 +080062 // 点赞功能
63 const toggleLike = async () => {
64 if (!user) {
65 alert('请先登录');
66 return;
67 }
Krishya7ec1dd02025-04-19 15:29:03 +080068
22301009237217b2025-04-20 15:15:25 +080069 try {
70 if (isLiked) {
71 // 取消点赞
72 await unlikePost(postId, user.id);
73 setIsLiked(false);
74 setPostDetail((prev) => ({
75 ...prev,
76 postLikeNum: prev.postLikeNum - 1,
77 }));
78 } else {
79 // 点赞
80 await likePost(postId, user.id);
81 setIsLiked(true);
82 setPostDetail((prev) => ({
83 ...prev,
84 postLikeNum: prev.postLikeNum + 1,
85 }));
86 }
87 } catch (err) {
88 console.error('点赞失败:', err);
89 alert('点赞失败,请稍后再试');
90 }
91 };
Krishya7ec1dd02025-04-19 15:29:03 +080092
Krishya57cc17b2025-05-26 16:43:34 +080093// 收藏功能
94const toggleCollect = async () => {
22301009237217b2025-04-20 15:15:25 +080095 if (!user) {
Krishya57cc17b2025-05-26 16:43:34 +080096 alert('请先登录');
97 return;
22301009237217b2025-04-20 15:15:25 +080098 }
Krishya7ec1dd02025-04-19 15:29:03 +080099
22301009237217b2025-04-20 15:15:25 +0800100 try {
Krishya57cc17b2025-05-26 16:43:34 +0800101 if (isCollected) {
102 // 取消收藏 - 使用原有的collectPost函数,传递action: "cancel"
103 await collectPost(postId, user.id, "cancel");
104 setIsCollected(false);
105 setPostDetail((prev) => ({
106 ...prev,
107 postCollectNum: prev.postCollectNum - 1,
108 }));
109 } else {
110 // 收藏
111 await collectPost(postId, user.id, "collect");
112 setIsCollected(true);
113 setPostDetail((prev) => ({
114 ...prev,
115 postCollectNum: prev.postCollectNum + 1,
116 }));
117 }
22301009237217b2025-04-20 15:15:25 +0800118 } catch (err) {
Krishya57cc17b2025-05-26 16:43:34 +0800119 console.error('收藏操作失败:', err);
120 alert('收藏操作失败,请稍后再试');
22301009237217b2025-04-20 15:15:25 +0800121 }
Krishya57cc17b2025-05-26 16:43:34 +0800122};
22301009237217b2025-04-20 15:15:25 +0800123
124 // 添加评论
Krishya2283d882025-05-27 22:25:19 +0800125const handleAddComment = async () => {
126 if (!newComment.trim()) {
127 alert('评论内容不能为空');
128 return;
129 }
22301009237217b2025-04-20 15:15:25 +0800130
Krishya2283d882025-05-27 22:25:19 +0800131 try {
132 const commentPayload = {
133 content: newComment,
134 userId: user.id,
135 isAnonymous: false,
136 com_comment_id: replyToCommentId || null,
137 };
138
139 const commentData = await addCommentToPost(postId, commentPayload);
140
141 setComments((prev) => [
142 ...prev,
143 {
144 commentId: (commentData && commentData.commentId) || Date.now(),
145 post_id: postId,
146 userId: user.id,
147 content: newComment,
148 commentTime: new Date().toISOString(),
149 comCommentId: replyToCommentId,
150 },
151 ]);
152
153 setNewComment('');
154 setReplyToCommentId(null);
155 } catch (err) {
156 console.error('评论添加失败:', err);
157 alert('评论失败,请稍后再试');
158 }
159};
160
161
22301009237217b2025-04-20 15:15:25 +0800162
163 // 回复评论
164 const handleReply = (commentId) => {
Krishya2283d882025-05-27 22:25:19 +0800165 setReplyToCommentId(commentId);
166 const comment = comments.find(c => c.commentId === commentId);
167 if (comment) {
168 // 这里用用户名或者用户ID
169 setReplyToUsername(comment.username || comment.userId);
170 } else {
171 setReplyToUsername(null);
172 }
173};
174
175const findUsernameByCommentId = (id) => {
176 const comment = comments.find(c => c.commentId === id);
177 return comment ? (comment.username || comment.userId) : '未知用户';
178};
179
22301009237217b2025-04-20 15:15:25 +0800180
181 return (
182 <div className="post-detail-page">
Krishyac0f7e9b2025-04-22 15:28:28 +0800183 <Header />
22301009237217b2025-04-20 15:15:25 +0800184 {loading ? (
185 <p>加载中...</p>
186 ) : errorMsg ? (
187 <p className="error-text">{errorMsg}</p>
188 ) : postDetail ? (
189 <div className="post-detail">
190 <h1>{postDetail.title}</h1>
191 <div className="post-meta">
Krishya1300cad2025-04-20 22:16:45 +0800192 <span className="post-user">用户ID: {postDetail.user_id}</span>
22301009237217b2025-04-20 15:15:25 +0800193 <span className="post-time">
Krishya1300cad2025-04-20 22:16:45 +0800194 发布时间:{new Date(postDetail.postTime).toLocaleString()}
22301009237217b2025-04-20 15:15:25 +0800195 </span>
22301009237217b2025-04-20 15:15:25 +0800196 </div>
197 <div className="post-content">
198 <p>{postDetail.postContent}</p>
Krishya1300cad2025-04-20 22:16:45 +0800199 {Array.isArray(postDetail.imgUrl) ? (
200 <div className="post-images">
201 {postDetail.imgUrl.map((url, idx) => (
202 <img key={idx} src={url} alt={`图片${idx}`} />
203 ))}
204 </div>
205 ) : (
206 postDetail.imgUrl && (
207 <img className="post-image" src={postDetail.imgUrl} alt="帖子图片" />
208 )
22301009237217b2025-04-20 15:15:25 +0800209 )}
Krishya1300cad2025-04-20 22:16:45 +0800210
22301009237217b2025-04-20 15:15:25 +0800211 </div>
212
213 {/* 点赞和收藏 */}
214 <div className="post-actions">
215 <button
216 className="icon-btn"
217 onClick={toggleLike} // 点赞操作
218 >
219 <GoodTwo
220 theme="outline"
Krishya1300cad2025-04-20 22:16:45 +0800221 size="20"
22301009237217b2025-04-20 15:15:25 +0800222 fill={isLiked ? '#f00' : '#ccc'} // 如果已点赞,显示红色
223 />
224 <span>{postDetail.postLikeNum}</span>
225 </button>
226 <button
227 className="icon-btn"
228 onClick={toggleCollect} // 收藏操作
229 >
230 <Star
231 theme="outline"
Krishya1300cad2025-04-20 22:16:45 +0800232 size="20"
22301009237217b2025-04-20 15:15:25 +0800233 fill={isCollected ? '#ffd700' : '#ccc'} // 如果已收藏,显示金色
234 />
235 <span>{postDetail.postCollectNum}</span>
236 </button>
237 </div>
Krishya1300cad2025-04-20 22:16:45 +0800238
239 <hr className="divider" />
22301009237217b2025-04-20 15:15:25 +0800240 {/* 评论部分 */}
Krishya1300cad2025-04-20 22:16:45 +0800241 <h3>评论区</h3>
Krishya2283d882025-05-27 22:25:19 +0800242 <div className="comments-section">
22301009237217b2025-04-20 15:15:25 +0800243 {comments.length ? (
244 comments.map((comment) => (
245 <div key={comment.commentId} className="comment">
Krishya1300cad2025-04-20 22:16:45 +0800246 <div className="comment-header">
22301009237217b2025-04-20 15:15:25 +0800247 <span className="comment-user">用户 ID: {comment.userId}</span>
Krishya1300cad2025-04-20 22:16:45 +0800248 <button className="reply-btn" onClick={() => handleReply(comment.commentId)}>回复</button>
22301009237217b2025-04-20 15:15:25 +0800249 </div>
Krishya2283d882025-05-27 22:25:19 +0800250
251 <p className="comment-content">
252 {comment.comCommentId ? (
253 <>
254 <span className="reply-to">回复 {findUsernameByCommentId(comment.comCommentId)}:</span>
255 {comment.content}
256 </>
257 ) : (
258 comment.content
259 )}
260 </p>
261
Krishya1300cad2025-04-20 22:16:45 +0800262 <div className="comment-time">
263 {new Date(comment.commentTime).toLocaleString()}
264 </div>
22301009237217b2025-04-20 15:15:25 +0800265
Krishya2283d882025-05-27 22:25:19 +0800266 {/* 回复框 */}
22301009237217b2025-04-20 15:15:25 +0800267 {replyToCommentId === comment.commentId && (
268 <div className="reply-form">
Krishya2283d882025-05-27 22:25:19 +0800269 <div className="replying-to">
270 回复 <strong>{replyToUsername}</strong>:
271 </div>
22301009237217b2025-04-20 15:15:25 +0800272 <textarea
273 placeholder="输入你的回复..."
274 value={newComment}
275 onChange={(e) => setNewComment(e.target.value)}
276 />
277 <div className="comment-options">
22301009237217b2025-04-20 15:15:25 +0800278 <button onClick={handleAddComment}>发布回复</button>
279 </div>
280 </div>
281 )}
282 </div>
283 ))
284 ) : (
285 <p>暂无评论</p>
286 )}
287
Krishya2283d882025-05-27 22:25:19 +0800288
22301009237217b2025-04-20 15:15:25 +0800289 {/* 添加评论表单 */}
290 <div className="add-comment-form">
291 <textarea
292 placeholder="输入你的评论..."
293 value={newComment}
294 onChange={(e) => setNewComment(e.target.value)}
295 />
296 <div className="comment-options">
Krishya57cc17b2025-05-26 16:43:34 +0800297 {/* <label>
22301009237217b2025-04-20 15:15:25 +0800298 <input
299 type="checkbox"
300 checked={isAnonymous}
301 onChange={() => setIsAnonymous(!isAnonymous)}
302 />
303 匿名评论
Krishya57cc17b2025-05-26 16:43:34 +0800304 </label> */}
22301009237217b2025-04-20 15:15:25 +0800305 <button onClick={handleAddComment}>发布评论</button>
306 </div>
307 </div>
308 </div>
Krishya7ec1dd02025-04-19 15:29:03 +0800309 </div>
22301009237217b2025-04-20 15:15:25 +0800310 ) : (
311 <p>帖子不存在</p>
312 )}
313 </div>
314 );
Krishya7ec1dd02025-04-19 15:29:03 +0800315};
316
Krishya57cc17b2025-05-26 16:43:34 +0800317export default PostDetailPage;