合并
Change-Id: I19ca58c58a513cba20c162c9ed7cbab90e060bf6
diff --git a/src/components/Dashboard.jsx b/src/components/Dashboard.jsx
index 97a01cc..836daa7 100644
--- a/src/components/Dashboard.jsx
+++ b/src/components/Dashboard.jsx
@@ -3,7 +3,7 @@
// import { getUserInfo } from '../api/auth';
import {createTorrent, getTorrents} from '../api/torrent';
import './Dashboard.css';
-import {createPost, getPosts} from '../api/helpPost';
+import {createPost, getPosts, getPostDetail} from '../api/helpPost';
const Dashboard = ({onLogout}) => {
@@ -34,6 +34,8 @@
const [helpError, setHelpError] = useState(null);
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
+ const [likedPosts,setLikedPosts] = useState({});
+
// 添加状态
const [torrentPosts, setTorrentPosts] = useState([]);
@@ -179,28 +181,29 @@
const handlePostSubmit = async (e) => {
e.preventDefault();
try {
- const username = localStorage.getItem('username');
- const response = await createPost(
- postTitle,
- postContent,
- username
- );
-
- if (response.data.code === 200) {
- // 刷新帖子列表
- await fetchHelpPosts();
- // 重置表单
- setShowPostModal(false);
- setPostTitle('');
- setPostContent('');
- setSelectedImage(null);
- } else {
- setHelpError(response.data.message || '发帖失败');
- }
+ const username = localStorage.getItem('username');
+ const response = await createPost(
+ postTitle,
+ postContent,
+ username,
+ selectedImage
+ );
+
+ if (response.data.code === 200) {
+ // 刷新帖子列表
+ await fetchHelpPosts(currentPage);
+ // 重置表单
+ setShowPostModal(false);
+ setPostTitle('');
+ setPostContent('');
+ setSelectedImage(null);
+ } else {
+ setHelpError(response.data.message || '发帖失败');
+ }
} catch (err) {
- setHelpError(err.message || '发帖失败');
+ setHelpError(err.message || '发帖失败');
}
- };
+ };
// 获取Torrent帖子列表
const fetchTorrentPosts = async (page = 1) => {
@@ -232,20 +235,40 @@
const fetchHelpPosts = async (page = 1) => {
setHelpLoading(true);
try {
- const response = await getPosts(page);
- if (response.data.code === 200) {
- setHelpPosts(response.data.data.records);
- setTotalPages(Math.ceil(response.data.data.total / 5)); // 假设每页5条
- setCurrentPage(page);
- } else {
- setHelpError(response.data.message || '获取求助帖失败');
- }
+ const response = await getPosts(page);
+ if (response.data.code === 200) {
+ const postsWithCounts = await Promise.all(
+ response.data.data.records.map(async (post) => {
+ try {
+ const detailResponse = await getPostDetail(post.id);
+ if (detailResponse.data.code === 200) {
+ return {
+ ...post,
+ replyCount: detailResponse.data.data.post.replyCount || 0,
+ isLiked: false // 根据需要添加其他字段
+ };
+ }
+ return post; // 如果获取详情失败,返回原始帖子数据
+ } catch (err) {
+ console.error(`获取帖子${post.id}详情失败:`, err);
+ return post;
+ }
+ })
+ );
+ setHelpPosts(postsWithCounts);
+ setTotalPages(Math.ceil(response.data.data.total / 5)); // 假设每页5条
+ setCurrentPage(page);
+ } else {
+ setHelpError(response.data.message || '获取求助帖失败');
+ }
} catch (err) {
- setHelpError(err.message || '获取求助帖失败');
+ setHelpError(err.message || '获取求助帖失败');
} finally {
- setHelpLoading(false);
+ setHelpLoading(false);
}
- };
+ };
+
+
useEffect(() => {
if (activeTab === 'help') {
fetchHelpPosts(currentPage);
diff --git a/src/components/HelpDetail.jsx b/src/components/HelpDetail.jsx
index da50850..7e7b7c8 100644
--- a/src/components/HelpDetail.jsx
+++ b/src/components/HelpDetail.jsx
@@ -3,12 +3,14 @@
import {
getPostDetail,
addPostComment,
- likePost
+ likePost,
+ deletePost
} from '../api/helpPost';
import {
likePostComment,
getCommentReplies,
- addCommentReply
+ addCommentReply,
+ deleteComment
} from '../api/helpComment';
import './HelpDetail.css';
@@ -22,12 +24,13 @@
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [newComment, setNewComment] = useState('');
- const [newReply, setNewReply] = useState({});
- const [images, setImages] = useState([]);
+ const [replyContent, setReplyContent] = useState('');
+ const [replyImage, setReplyImage] = useState([]);
+ const [commentImage, setCommentImage] = useState([]);
const [expandedReplies, setExpandedReplies] = useState({}); // 记录哪些评论的回复是展开的
const [loadingReplies, setLoadingReplies] = useState({});
const [setReplyingTo] = useState(null);
- const [replyContent, setReplyContent] = useState('');
+
const [activeReplyId, setActiveReplyId] = useState(null);
const [replyModal, setReplyModal] = useState({
@@ -58,7 +61,7 @@
setReplyContent('');
};
- const Comment = ({ comment, onLike, onReply, isReply = false }) => {
+ const Comment = ({ comment, onLike, onReply, onDelete, isReply = false }) => {
return (
<div className={`comment-container ${isReply ? "is-reply" : ""}`}>
<div className="comment-item">
@@ -76,6 +79,17 @@
</span>
</div>
<p className="comment-text">{comment.content}</p>
+ {/* 添加评论图片展示 */}
+ {comment.imageUrl && (
+ <div className="comment-image-container">
+ <img
+ src={`http://localhost:8088${comment.imageUrl}`}
+ alt="评论图片"
+ className="comment-image"
+ onClick={() => window.open(comment.imageUrl, '_blank')}
+ />
+ </div>
+ )}
<div className="comment-actions">
<button onClick={() => onLike(comment.id)}>
👍 ({comment.likeCount || 0})
@@ -83,6 +97,14 @@
<button onClick={() => onReply(comment.id, comment.authorId)}>
回复
</button>
+ {comment.authorId === localStorage.getItem('username') && (
+ <button
+ className="delete-comment-btn"
+ onClick={() => onDelete(comment.id)}
+ >
+ 删除
+ </button>
+ )}
</div>
</div>
</div>
@@ -99,6 +121,7 @@
onLike={handleLikeComment}
onReply={openReplyModal}
isReply={depth > 0}
+ onDelete={handleDeleteComment}
/>
{/* 递归渲染所有回复 */}
@@ -140,6 +163,19 @@
setError('点赞失败: ' + (err.response?.data?.message || err.message));
}
};
+
+ // 添加删除处理函数
+ const handleDeletePost = async (postId) => {
+ if (window.confirm('确定要删除这个帖子吗?所有评论也将被删除!')) {
+ try {
+ const username = localStorage.getItem('username');
+ await deletePost(postId, username);
+ navigate('/dashboard/help'); // 删除成功后返回求助区
+ } catch (err) {
+ setError('删除失败: ' + (err.response?.data?.message || err.message));
+ }
+ }
+ };
const handleCommentSubmit = async (e) => {
e.preventDefault();
@@ -196,6 +232,18 @@
}
};
+ const handleDeleteComment = async (commentId) => {
+ if (window.confirm('确定要删除这条评论吗?')) {
+ try {
+ const username = localStorage.getItem('username');
+ await deleteComment(commentId, username);
+ await fetchPostDetail(); // 刷新评论列表
+ } catch (err) {
+ setError('删除失败: ' + (err.response?.data?.message || err.message));
+ }
+ }
+ };
+
// 修改startReply函数
const startReply = (commentId) => {
@@ -217,15 +265,16 @@
try {
const username = localStorage.getItem('username');
const response = await addCommentReply(replyModal.replyingTo, {
+ authorId: username,
content: replyContent,
- authorId: username
+ image: replyImage
});
console.log('回复响应:', response.data); // 调试
if (response.data && response.data.code === 200) {
await fetchPostDetail();
-
+ setReplyContent('');
closeReplyModal();
}
} catch (err) {
@@ -251,15 +300,15 @@
}));
};
- const handleImageUpload = (e) => {
- const files = Array.from(e.target.files);
- const newImages = files.map(file => URL.createObjectURL(file));
- setImages(prev => [...prev, ...newImages]);
- };
+ // const handleImageUpload = (e) => {
+ // const files = Array.from(e.target.files);
+ // const newImages = files.map(file => URL.createObjectURL(file));
+ // setImages(prev => [...prev, ...newImages]);
+ // };
- const handleRemoveImage = (index) => {
- setImages(prev => prev.filter((_, i) => i !== index));
- };
+ // const handleRemoveImage = (index) => {
+ // setImages(prev => prev.filter((_, i) => i !== index));
+ // };
@@ -284,9 +333,19 @@
<div className="post-author">{post.authorId}</div>
<div className="post-date">
{new Date(post.createTime).toLocaleString()}
- </div>
+ </div>
</div>
- {post.isSolved && <span className="solved-badge">已解决</span>}
+ {post.isSolved && <span ClassName="solved-badge">已解决</span>}
+ <div classname="delete-post">
+ {post.authorId === localStorage.getItem('username') && (
+ <button
+ className="delete-button"
+ onClick={() => handleDeletePost(post.id)}
+ >
+ 删除帖子
+ </button>
+ )}
+ </div>
</div>
<h1 className="post-title">{post.title}</h1>
@@ -295,6 +354,21 @@
{post.content.split('\n').map((para, i) => (
<p key={i}>{para}</p>
))}
+ {/* 添加帖子图片展示 */}
+ {post.imageUrl && (
+ <div className="post-image-container">
+ <img
+ src={`http://localhost:8088${post.imageUrl}`}
+ alt="帖子图片"
+ className="post-image"
+ // onError={(e) => {
+ // e.target.onerror = null;
+ // e.target.src = 'https://via.placeholder.com/400x300?text=图片加载失败';
+ // console.error('图片加载失败:', post.imageUrl);
+ // }}
+ />
+ </div>
+ )}
</div>
<div className="post-actions">
@@ -325,8 +399,21 @@
required
/>
<button type="submit">发表评论</button>
+
+ {/* 图片上传部分 */}
+ <div className="form-group">
+ <div className="upload-image-btn">
+ <input
+ type="file"
+ accept="image/*"
+ onChange={(e) => setCommentImage(e.target.files[0])}
+ data-testid="comment-image-input"
+ />
+ </div>
+ </div>
</form>
+
<div className="comment-list">
{comments.map(comment => renderComment(comment))}
</div>
@@ -347,6 +434,18 @@
autoFocus
required
/>
+
+ {/* 图片上传部分 */}
+ <div className="form-group">
+ <div className="upload-image-btn">
+ <input
+ type="file"
+ accept="image/*"
+ onChange={(e) => setReplyImage(e.target.files[0])}
+ />
+ </div>
+ </div>
+
<div className="modal-actions">
<button type="button" onClick={closeReplyModal} className="cancel-btn">
取消