增加帖子详情api与前端页面,需完善按钮与显示
Change-Id: I84d3aace81055b8dc372f91942523d163b1ec463
diff --git a/JWLLL/API_front/src/components/PostDetail.jsx b/JWLLL/API_front/src/components/PostDetail.jsx
new file mode 100644
index 0000000..f7506ac
--- /dev/null
+++ b/JWLLL/API_front/src/components/PostDetail.jsx
@@ -0,0 +1,227 @@
+import React, { useState, useEffect } from 'react'
+import { useParams, useNavigate } from 'react-router-dom'
+import { ArrowLeft, ThumbsUp, MessageCircle, Share2, BookmarkPlus, Heart, Eye } from 'lucide-react'
+import '../style/PostDetail.css'
+
+export default function PostDetail() {
+ const { id } = useParams()
+ const navigate = useNavigate()
+ const [post, setPost] = useState(null)
+ const [loading, setLoading] = useState(true)
+ const [error, setError] = useState(null)
+ const [liked, setLiked] = useState(false)
+ const [bookmarked, setBookmarked] = useState(false)
+ const [likeCount, setLikeCount] = useState(0)
+ useEffect(() => {
+ fetchPostDetail()
+ }, [id])
+
+ const fetchPostDetail = async () => {
+ setLoading(true)
+ setError(null)
+ try {
+ // 根据ID获取帖子详情,使用本地服务器地址
+ const response = await fetch(`http://127.0.0.1:5000/post/${id}`)
+ if (!response.ok) {
+ throw new Error('帖子不存在或已被删除')
+ }
+ const data = await response.json()
+ setPost(data)
+ setLikeCount(data.heat || 0)
+ } catch (error) {
+ console.error('获取帖子详情失败:', error)
+ setError(error.message)
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ const handleBack = () => {
+ navigate(-1)
+ }
+
+ const handleLike = async () => {
+ try {
+ // 模拟点赞API调用
+ const newLiked = !liked
+ setLiked(newLiked)
+ setLikeCount(prev => newLiked ? prev + 1 : prev - 1)
+
+ // 实际项目中这里应该调用后端API
+ // await fetch(`/post/${id}/like`, { method: 'POST' })
+ } catch (error) {
+ console.error('点赞失败:', error)
+ // 回滚状态
+ setLiked(!liked)
+ setLikeCount(prev => liked ? prev + 1 : prev - 1)
+ }
+ }
+
+ const handleBookmark = () => {
+ setBookmarked(!bookmarked)
+ // 实际项目中这里应该调用后端API保存收藏状态
+ }
+
+ const handleShare = () => {
+ // 分享功能
+ if (navigator.share) {
+ navigator.share({
+ title: post?.title,
+ text: post?.content,
+ url: window.location.href,
+ })
+ } else {
+ // 复制链接到剪贴板
+ navigator.clipboard.writeText(window.location.href)
+ alert('链接已复制到剪贴板')
+ }
+ }
+
+ if (loading) {
+ return (
+ <div className="post-detail">
+ <div className="loading-container">
+ <div className="loading-spinner"></div>
+ <p>加载中...</p>
+ </div>
+ </div>
+ )
+ }
+
+ if (error) {
+ return (
+ <div className="post-detail">
+ <div className="error-container">
+ <h2>😔 出错了</h2>
+ <p>{error}</p>
+ <button onClick={handleBack} className="back-btn">
+ <ArrowLeft size={20} />
+ 返回
+ </button>
+ </div>
+ </div>
+ )
+ }
+
+ if (!post) {
+ return (
+ <div className="post-detail">
+ <div className="error-container">
+ <h2>😔 帖子不存在</h2>
+ <p>该帖子可能已被删除或不存在</p>
+ <button onClick={handleBack} className="back-btn">
+ <ArrowLeft size={20} />
+ 返回
+ </button>
+ </div>
+ </div>
+ )
+ }
+
+ return (
+ <div className="post-detail">
+ {/* 顶部导航栏 */}
+ <header className="post-header">
+ <button onClick={handleBack} className="back-btn">
+ <ArrowLeft size={20} />
+ 返回
+ </button>
+ <div className="header-actions">
+ <button onClick={handleShare} className="action-btn">
+ <Share2 size={20} />
+ </button>
+ <button
+ onClick={handleBookmark}
+ className={`action-btn ${bookmarked ? 'active' : ''}`}
+ >
+ <BookmarkPlus size={20} />
+ </button>
+ </div>
+ </header>
+
+ {/* 主要内容区 */}
+ <main className="post-content">
+ {/* 帖子标题 */}
+ <h1 className="post-title">{post.title}</h1>
+
+ {/* 作者信息和元数据 */}
+ <div className="post-meta">
+ <div className="author-info">
+ <div className="avatar">
+ {post.author ? post.author.charAt(0).toUpperCase() : 'U'}
+ </div>
+ <div className="author-details">
+ <span className="author-name">{post.author || '匿名用户'}</span>
+ <span className="post-date">
+ {post.create_time ? new Date(post.create_time).toLocaleDateString('zh-CN') : '未知时间'}
+ </span>
+ </div>
+ </div>
+ <div className="post-stats">
+ <span className="stat-item">
+ <Eye size={16} />
+ {post.views || 0}
+ </span>
+ <span className="stat-item">
+ <Heart size={16} />
+ {likeCount}
+ </span>
+ </div>
+ </div>
+
+ {/* 标签 */}
+ {post.tags && post.tags.length > 0 && (
+ <div className="post-tags">
+ {post.tags.map((tag, index) => (
+ <span key={index} className="tag">{tag}</span>
+ ))}
+ </div>
+ )}
+
+ {/* 帖子正文 */}
+ <div className="post-body">
+ <p>{post.content}</p>
+ </div>
+
+ {/* 类别信息 */}
+ {post.category && (
+ <div className="post-category">
+ <span className="category-label">分类:</span>
+ <span className="category-name">{post.category}</span>
+ </div>
+ )}
+ </main>
+
+ {/* 底部操作栏 */}
+ <footer className="post-footer">
+ <div className="action-bar">
+ <button
+ onClick={handleLike}
+ className={`action-button ${liked ? 'liked' : ''}`}
+ >
+ <ThumbsUp size={20} />
+ <span>{likeCount}</span>
+ </button>
+
+ <button className="action-button">
+ <MessageCircle size={20} />
+ <span>评论</span>
+ </button>
+
+ <button onClick={handleShare} className="action-button">
+ <Share2 size={20} />
+ <span>分享</span>
+ </button>
+
+ <button
+ onClick={handleBookmark}
+ className={`action-button ${bookmarked ? 'bookmarked' : ''}`}
+ >
+ <BookmarkPlus size={20} />
+ <span>收藏</span>
+ </button>
+ </div>
+ </footer>
+ </div>
+ )
+}