From 153d8d40adcf149c18a41b409a1fe9ab1bf3bc7b Mon Sep 17 00:00:00 2001 From: Leo <98382335+gaoziman@users.noreply.github.com> Date: Mon, 13 Oct 2025 21:37:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BA=E8=AF=84=E8=AE=BA=E5=8C=BA?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AE=A4=E8=AF=81=E5=AE=88=E5=8D=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在发表评论功能中添加认证检查 - 在评论点赞功能中添加认证检查 - 未登录用户操作时显示提示并跳转到登录页 - 移除未使用的imports优化代码 --- src/components/CommentSection/index.tsx | 132 ++++++++++++++++-------- 1 file changed, 90 insertions(+), 42 deletions(-) diff --git a/src/components/CommentSection/index.tsx b/src/components/CommentSection/index.tsx index 4cc3b8c..987b989 100644 --- a/src/components/CommentSection/index.tsx +++ b/src/components/CommentSection/index.tsx @@ -1,16 +1,19 @@ /** * 评论区组件 + * 对接后端评论API和点赞功能 */ import React, { useState, useEffect } from 'react' -import { List, Avatar, Rate, Button, Input, message, Empty } from 'antd' +import { List, Avatar, Button, Input, message, Empty } from 'antd' import { LikeOutlined, LikeFilled } from '@ant-design/icons' import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import 'dayjs/locale/zh-cn' -import type { Comment } from '@types/index' -import { getCommentsByTarget, addComment } from '@services/api' +import type { CommentItem, CommentTargetType } from '@/types' +import { getCommentList, addComment } from '@services/commentApi' +import { toggleLike } from '@services/likeApi' import { useUserStore } from '@store/useUserStore' +import { requireAuth } from '@/utils/authGuard' import './index.css' dayjs.extend(relativeTime) @@ -19,43 +22,53 @@ dayjs.locale('zh-cn') const { TextArea } = Input interface CommentSectionProps { - targetType: 'heritage' | 'inheritor' | 'course' | 'news' - targetId: string - showRating?: boolean + targetType: CommentTargetType + targetId: string | number } const CommentSection: React.FC = ({ targetType, targetId, - showRating = false, }) => { - const [comments, setComments] = useState([]) + const [comments, setComments] = useState([]) const [loading, setLoading] = useState(false) const [submitting, setSubmitting] = useState(false) const [content, setContent] = useState('') - const [rating, setRating] = useState(5) + const [total, setTotal] = useState(0) + const [currentPage, setCurrentPage] = useState(1) + const [pageSize] = useState(10) - const { user, isAuthenticated } = useUserStore() + const { isAuthenticated } = useUserStore() useEffect(() => { fetchComments() - }, [targetType, targetId]) + }, [targetType, targetId, currentPage]) const fetchComments = async () => { setLoading(true) try { - const data = await getCommentsByTarget(targetType, targetId) - setComments(data) - } catch (error) { + const numericId = typeof targetId === 'string' ? parseInt(targetId) : targetId + const result = await getCommentList({ + targetType, + targetId: numericId, + pageNum: currentPage, + pageSize: pageSize, + sortType: 'latest' + }) + + setComments(result.records) + setTotal(result.total) + } catch (error: any) { console.error('Failed to fetch comments:', error) + message.error(error.message || '获取评论失败') } finally { setLoading(false) } } const handleSubmit = async () => { - if (!isAuthenticated) { - message.warning('请先登录后再发表评论') + // 🔥 认证守卫:未登录时提示并跳转到登录页 + if (!requireAuth('发表评论')) { return } @@ -66,44 +79,67 @@ const CommentSection: React.FC = ({ setSubmitting(true) try { - const newComment = await addComment({ - userId: user!.id, - userName: user!.nickname, - userAvatar: user!.avatar, + const numericId = typeof targetId === 'string' ? parseInt(targetId) : targetId + await addComment({ targetType, - targetId, - content, - rating: showRating ? rating : undefined, - likeCount: 0, - replyCount: 0, + targetId: numericId, + content: content.trim(), }) - setComments([newComment, ...comments]) setContent('') - setRating(5) message.success('评论发表成功') - } catch (error) { - message.error('评论发表失败') + + // 重新加载评论列表 + setCurrentPage(1) + fetchComments() + } catch (error: any) { + console.error('Failed to add comment:', error) + message.error(error.message || '评论发表失败') } finally { setSubmitting(false) } } + // 处理评论点赞 + const handleCommentLike = async (commentId: number, isLiked: boolean) => { + // 🔥 认证守卫:未登录时提示并跳转到登录页 + if (!requireAuth('点赞评论')) { + return + } + + try { + await toggleLike({ + targetType: 'comment', + targetId: commentId + }, isLiked) + + // 更新评论的点赞状态和数量 + setComments(prevComments => + prevComments.map(comment => { + if (comment.id === commentId) { + return { + ...comment, + isLiked: !isLiked, + likeCount: isLiked ? comment.likeCount - 1 : comment.likeCount + 1 + } + } + return comment + }) + ) + } catch (error: any) { + message.error(error.message || '操作失败') + } + } + return (
-

全部评论 ({comments.length})

+

全部评论 ({total})

{/* 评论输入框 */} {isAuthenticated && (
- {showRating && ( -
- 评分: - -
- )}