blob: c0f218f36109fcc71cb1c8d12d44633186a5992d [file] [log] [blame]
import React, { useState, useEffect } from 'react';
import { useRoute } from 'wouter';
import {
getPostDetail,
getPostComments,
likePost,
unlikePost,
addCommentToPost,
replyToComment,
likeComment,
unlikeComment,
getUserInfo
} from './api';
import './PostDetailPage.css';
import axios from 'axios';
const API_BASE = process.env.REACT_APP_API_BASE;
const PostHeader = ({ post }) => {
const anonymousAvatar = '/assets/img/anonymous.jpg';
return (
<div className="post-header">
<div className="author-info">
<img className="avatar" src={post.isAnonymous? anonymousAvatar : post.userProfile.avatar_url} alt="头像" />
<span className="author-name">{post.isAnonymous? '某同学' : post.userProfile.nickname}</span>
</div>
<h1 className="post-title">{post.title}</h1>
</div>
);
};
const PostContent = ({ content }) => {
return (
<div className="post-content" dangerouslySetInnerHTML={{ __html: content }} />
);
};
const PostActions = ({ post, onLike, onFavorite }) => {
return (
<div className="post-actions">
<div className="action-item" onClick={onLike}>
<i className={post.liked? 'liked' : 'unliked'} />
<span>{post.likeCount || 0}</span>
</div>
<div className="action-item" onClick={onFavorite}>
<i className={post.favorited? 'favorited' : 'unfavorited'} />
<span>{post.favorites || 0}</span>
</div>
</div>
);
};
const CommentInput = ({ onSubmitComment, isFlag }) => {
const [content, setContent] = useState('');
useEffect(() => {
if (isFlag) {
setContent('');
}
}, [isFlag]);
const handleSubmit = () => {
if (content) {
onSubmitComment(content);
}
};
return (
<div className="comment-input">
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="写下你的评论..."
className="comment-textarea"
/>
<div className="button-container">
<button
type="button"
onClick={handleSubmit}
disabled={!content}
className="submit-button"
>
发布评论
</button>
</div>
</div>
);
};
const CommentItem = ({ comment, onLikeComment, onReplyComment }) => {
const [showReplyInput, setShowReplyInput] = useState(false);
const [replyContent, setReplyContent] = useState('');
const queryUserInfo = async (id) => {
if (!id) {
return;
}
try {
const userData = await getUserInfo(id);
console.log(userData);
// 这里可以添加跳转逻辑等,比如根据用户ID跳转到对应个人信息页面
} catch (error) {
console.error('获取用户信息失败:', error);
}
};
const handleLike = () => {
onLikeComment(comment);
};
const handleReply = () => {
setShowReplyInput(!showReplyInput);
};
const handleSubmitReply = () => {
if (replyContent) {
onReplyComment(comment, replyContent);
setReplyContent('');
setShowReplyInput(false);
}
};
return (
<div className="comment-item">
<img className="avatar" src={comment.author.avatar_url} alt="头像" onClick={() => queryUserInfo(comment.author.userId)} />
<div className="comment-content">
<div className="comment-author">{comment.author.nickname}</div>
<div className="comment-text">{comment.content}</div>
<div className="comment-actions">
<div className="action-item" onClick={handleLike}>
<i className={comment.liked? 'liked' : 'unliked'} />
<span>{comment.likeCount || 0}</span>
</div>
<button type="button" onClick={handleReply}>回复</button>
</div>
{showReplyInput && (
<div className="reply-input">
<textarea
value={replyContent}
onChange={(e) => setReplyContent(e.target.value)}
placeholder="写下你的回复..."
className="reply-textarea"
/>
<button
type="button"
onClick={handleSubmitReply}
disabled={!replyContent}
className="submit-button"
>
发布回复
</button>
</div>
)}
{comment.replies && comment.replies.length > 0 && (
<div className="reply-list">
{comment.replies.map(reply => (
<CommentItem
key={reply.id}
comment={reply}
onLikeComment={onLikeComment}
onReplyComment={onReplyComment}
/>
))}
</div>
)}
</div>
</div>
);
};
const CommentsList = ({ comments, onLikeComment, onReplyComment }) => {
return (
<div className="comments-list">
<h2>评论</h2>
{comments.map(comment => (
<CommentItem
key={comment.id}
comment={comment}
onLikeComment={onLikeComment}
onReplyComment={onReplyComment}
/>
))}
</div>
);
};
const PostDetailPage = () => {
const [post, setPost] = useState(null);
const [loading, setLoading] = useState(true);
const [errorMsg, setErrorMsg] = useState('');
const [comments, setComments] = useState([]);
const [isFlag, setIsFlag] = useState(false);
const { params } = useRoute('/forum/post/:postId');
const postId = params?.postId;
useEffect(() => {
const fetchPostDetail = async () => {
setLoading(true);
setErrorMsg('');
try {
const postDetail = await getPostDetail(postId);
const postComments = await getPostComments(postId);
setPost(postDetail);
setComments(postComments);
} catch (error) {
console.error('获取帖子详情失败:', error);
setErrorMsg('加载失败,请稍后重试');
} finally {
setLoading(false);
}
};
if (postId) {
fetchPostDetail();
}
}, [postId]);
const handleLike = async () => {
if (!post.liked) {
try {
await likePost(postId);
const newPost = { ...post, liked: true, likeCount: post.likeCount + 1 };
setPost(newPost);
} catch (err) {
console.error('点赞失败:', err);
}
} else {
try {
await unlikePost(postId);
const newPost = { ...post, liked: false, likeCount: post.likeCount - 1 };
setPost(newPost);
} catch (err) {
console.error('取消点赞失败:', err);
}
}
};
const handleFavorite = () => {
const newPost = { ...post, favorited: !post.favorited, favorites: post.favorited? post.favorites - 1 : post.favorites + 1 };
setPost(newPost);
if (newPost.favorited) {
axios.post(`${API_BASE}/echo/forum/posts/${postId}/favorite`).catch(err => {
console.error('收藏失败:', err);
});
} else {
axios.delete(`${API_BASE}/echo/forum/posts/${postId}/unfavorite`).catch(err => {
console.error('取消收藏失败:', err);
});
}
};
const likeCommentAction = async (comment) => {
if (!comment.liked) {
try {
await likeComment(comment.id);
const newComment = { ...comment, liked: true, likeCount: comment.likeCount + 1 };
setComments(comments.map(c => c.id === comment.id? newComment : c));
} catch (err) {
console.error('点赞评论失败:', err);
}
} else {
try {
await unlikeComment(comment.id);
const newComment = { ...comment, liked: false, likeCount: comment.likeCount - 1 };
setComments(comments.map(c => c.id === comment.id? newComment : c));
} catch (err) {
console.error('取消点赞评论失败:', err);
}
}
};
const replyCommentAction = async (comment, replyContent) => {
try {
await replyToComment(comment.id, replyContent);
setIsFlag(true);
const commentResponse = await getPostComments(postId);
setComments(commentResponse.data);
} catch (error) {
console.error('回复评论失败:', error);
}
};
const addCommentAction = async (content) => {
try {
await addCommentToPost(postId, content);
setIsFlag(true);
const commentResponse = await getPostComments(postId);
setComments(commentResponse.data);
} catch (error) {
console.error('添加评论失败:', error);
}
};
if (loading) return <p>加载中...</p>;
if (errorMsg) return <p className="error-text">{errorMsg}</p>;
if (!post) return <p>没有找到该帖子。</p>;
return (
<div className="post-detail-page">
<PostHeader post={post} />
<PostContent content={post.content} />
<PostActions post={post} onLike={handleLike} onFavorite={handleFavorite} />
<CommentInput onSubmitComment={addCommentAction} isFlag={isFlag} />
<CommentsList comments={comments} onLikeComment={likeCommentAction} onReplyComment={replyCommentAction} />
</div>
);
};
export default PostDetailPage;