blob: 0dc7289757e99a41c018562be0416306fe452e59 [file] [log] [blame]
95630366980c1f272025-06-20 14:08:54 +08001import React, { useState, useEffect } from 'react'
2import { useParams, useNavigate } from 'react-router-dom'
3import { ArrowLeft, ThumbsUp, MessageCircle, Share2, BookmarkPlus, Heart, Eye } from 'lucide-react'
4import { searchAPI } from '../api/search_jwlll'
5import '../style/PostDetail.css'
6
7export default function PostDetail() {
8 const { id } = useParams()
9 const navigate = useNavigate()
10 const [post, setPost] = useState(null)
11 const [loading, setLoading] = useState(true)
12 const [error, setError] = useState(null)
13 const [liked, setLiked] = useState(false)
14 const [bookmarked, setBookmarked] = useState(false)
15 const [likeCount, setLikeCount] = useState(0)
16 const [comments, setComments] = useState([])
17 const [newComment, setNewComment] = useState('')
18 const [showComments, setShowComments] = useState(false)
19
20 const DEFAULT_USER_ID = '3' // 默认用户ID
21
22 useEffect(() => {
23 fetchPostDetail()
24 fetchComments()
25 }, [id])
26
27 const fetchPostDetail = async () => {
28 setLoading(true)
29 setError(null)
30 try {
31 const data = await searchAPI.getPostDetail(id)
32 setPost(data)
33 setLikeCount(data.heat || 0)
34 } catch (error) {
35 console.error('获取帖子详情失败:', error)
36 setError('帖子不存在或已被删除')
37 } finally {
38 setLoading(false)
39 }
40 }
41
42 const fetchComments = async () => {
43 try {
44 const data = await searchAPI.getComments(id)
45 setComments(data.comments || [])
46 } catch (error) {
47 console.error('获取评论失败:', error)
48 }
49 }
50
51 const handleBack = () => {
52 navigate(-1)
53 }
54
55 const handleLike = async () => {
56 try {
57 const newLiked = !liked
58 if (newLiked) {
59 await searchAPI.likePost(id, DEFAULT_USER_ID)
60 } else {
61 await searchAPI.unlikePost(id, DEFAULT_USER_ID)
62 }
63 setLiked(newLiked)
64 setLikeCount(prev => newLiked ? prev + 1 : prev - 1)
65 } catch (error) {
66 console.error('点赞失败:', error)
67 // 回滚状态
68 setLiked(!liked)
69 setLikeCount(prev => liked ? prev + 1 : prev - 1)
70 }
71 }
72
73 const handleBookmark = () => {
74 setBookmarked(!bookmarked)
75 // 实际项目中这里应该调用后端API保存收藏状态
76 }
77
78 const handleShare = () => {
79 // 分享功能
80 if (navigator.share) {
81 navigator.share({
82 title: post?.title,
83 text: post?.content,
84 url: window.location.href,
85 })
86 } else {
87 // 复制链接到剪贴板
88 navigator.clipboard.writeText(window.location.href)
89 alert('链接已复制到剪贴板')
90 }
91 }
92
93 const handleAddComment = async (e) => {
94 e.preventDefault()
95 if (!newComment.trim()) return
96
97 try {
98 await searchAPI.addComment(id, DEFAULT_USER_ID, newComment)
99 setNewComment('')
100 fetchComments() // 刷新评论列表
101 } catch (error) {
102 console.error('添加评论失败:', error)
103 alert('评论失败,请重试')
104 }
105 }
106
107 if (loading) {
108 return (
109 <div className="post-detail">
110 <div className="loading-container">
111 <div className="loading-spinner"></div>
112 <p>加载中...</p>
113 </div>
114 </div>
115 )
116 }
117
118 if (error) {
119 return (
120 <div className="post-detail">
121 <div className="error-container">
122 <h2>😔 出错了</h2>
123 <p>{error}</p>
124 <button onClick={handleBack} className="back-btn">
125 <ArrowLeft size={20} />
126 返回
127 </button>
128 </div>
129 </div>
130 )
131 }
132
133 if (!post) {
134 return (
135 <div className="post-detail">
136 <div className="error-container">
137 <h2>😔 帖子不存在</h2>
138 <p>该帖子可能已被删除或不存在</p>
139 <button onClick={handleBack} className="back-btn">
140 <ArrowLeft size={20} />
141 返回
142 </button>
143 </div>
144 </div>
145 )
146 }
147
148 return (
149 <div className="post-detail">
150 {/* 顶部导航栏 */}
151 <header className="post-header">
152 <button onClick={handleBack} className="back-btn">
153 <ArrowLeft size={20} />
154 返回
155 </button>
156 <div className="header-actions">
157 <button onClick={handleShare} className="action-btn">
158 <Share2 size={20} />
159 </button>
160 <button
161 onClick={handleBookmark}
162 className={`action-btn ${bookmarked ? 'active' : ''}`}
163 >
164 <BookmarkPlus size={20} />
165 </button>
166 </div>
167 </header>
168
169 {/* 主要内容区 */}
170 <main className="post-content">
171 {/* 帖子标题 */}
172 <h1 className="post-title">{post.title}</h1>
173
174 {/* 作者信息和元数据 */}
175 <div className="post-meta">
176 <div className="author-info">
177 <div className="avatar">
178 {post.author ? post.author.charAt(0).toUpperCase() : 'U'}
179 </div>
180 <div className="author-details">
181 <span className="author-name">{post.author || '匿名用户'}</span>
182 <span className="post-date">
183 {post.create_time ? new Date(post.create_time).toLocaleDateString('zh-CN') : '未知时间'}
184 </span>
185 </div>
186 </div>
187 <div className="post-stats">
188 <span className="stat-item">
189 <Eye size={16} />
190 {post.views || 0}
191 </span>
192 <span className="stat-item">
193 <Heart size={16} />
194 {likeCount}
195 </span>
196 </div>
197 </div>
198
199 {/* 标签 */}
200 {post.tags && post.tags.length > 0 && (
201 <div className="post-tags">
202 {post.tags.map((tag, index) => (
203 <span key={index} className="tag">{tag}</span>
204 ))}
205 </div>
206 )}
207
208 {/* 帖子正文 */}
209 <div className="post-body">
210 <p>{post.content}</p>
211 </div>
212
213 {/* 类别信息 */}
214 {(post.category || post.type) && (
215 <div className="post-category">
216 {post.category && (
217 <>
218 <span className="category-label">分类:</span>
219 <span className="category-name">{post.category}</span>
220 </>
221 )}
222 {post.type && (
223 <>
224 <span className="category-label" style={{marginLeft: '1em'}}>类型:</span>
225 <span className="category-name">{post.type}</span>
226 </>
227 )}
228 </div>
229 )}
230
231 {/* 评论区 */}
232 <div className="comments-section">
233 <div className="comments-header">
234 <button
235 onClick={() => setShowComments(!showComments)}
236 className="comments-toggle"
237 >
238 <MessageCircle size={20} />
239 评论 ({comments.length})
240 </button>
241 </div>
242
243 {showComments && (
244 <div className="comments-content">
245 {/* 添加评论 */}
246 <form onSubmit={handleAddComment} className="comment-form">
247 <textarea
248 value={newComment}
249 onChange={(e) => setNewComment(e.target.value)}
250 placeholder="写下你的评论..."
251 className="comment-input"
252 rows={3}
253 />
254 <button type="submit" className="comment-submit">
255 发布评论
256 </button>
257 </form>
258
259 {/* 评论列表 */}
260 <div className="comments-list">
261 {comments.length === 0 ? (
262 <p className="no-comments">暂无评论</p>
263 ) : (
264 comments.map((comment, index) => (
265 <div key={index} className="comment-item">
266 <div className="comment-author">
267 <div className="comment-avatar">
268 {comment.user_name ? comment.user_name.charAt(0).toUpperCase() : 'U'}
269 </div>
270 <span className="comment-name">{comment.user_name || '匿名用户'}</span>
271 <span className="comment-time">
272 {comment.create_time ? new Date(comment.create_time).toLocaleString('zh-CN') : ''}
273 </span>
274 </div>
275 <div className="comment-content">
276 {comment.content}
277 </div>
278 </div>
279 ))
280 )}
281 </div>
282 </div>
283 )}
284 </div>
285 </main>
286
287 {/* 底部操作栏 */}
288 <footer className="post-footer">
289 <div className="action-bar">
290 <button
291 onClick={handleLike}
292 className={`action-button ${liked ? 'liked' : ''}`}
293 >
294 <ThumbsUp size={20} />
295 <span>{likeCount}</span>
296 </button>
297
298 <button
299 onClick={() => setShowComments(!showComments)}
300 className="action-button"
301 >
302 <MessageCircle size={20} />
303 <span>评论</span>
304 </button>
305
306 <button onClick={handleShare} className="action-button">
307 <Share2 size={20} />
308 <span>分享</span>
309 </button>
310
311 <button
312 onClick={handleBookmark}
313 className={`action-button ${bookmarked ? 'bookmarked' : ''}`}
314 >
315 <BookmarkPlus size={20} />
316 <span>收藏</span>
317 </button>
318 </div>
319 </footer>
320 </div>
321 )
322}