diff --git a/src/components/EventCommentSection/CommentItem.js b/src/components/EventCommentSection/CommentItem.js index 6ebea5a8..9fe3ddf8 100644 --- a/src/components/EventCommentSection/CommentItem.js +++ b/src/components/EventCommentSection/CommentItem.js @@ -1,29 +1,63 @@ // src/components/EventCommentSection/CommentItem.js /** * 单条评论组件 - * 功能:显示用户头像、昵称、时间、评论内容 + * 功能:显示用户头像、昵称、时间、评论内容、删除按钮 */ -import React from 'react'; +import React, { useState } from 'react'; import { Box, HStack, VStack, Avatar, Text, + IconButton, useColorModeValue, + Tooltip, + AlertDialog, + AlertDialogBody, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogContent, + AlertDialogOverlay, + Button, + useDisclosure, } from '@chakra-ui/react'; +import { DeleteIcon } from '@chakra-ui/icons'; import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; dayjs.locale('zh-cn'); -const CommentItem = ({ comment }) => { +const CommentItem = ({ comment, currentUserId, onDelete }) => { + const { isOpen, onOpen, onClose } = useDisclosure(); + const cancelRef = React.useRef(); + const [isDeleting, setIsDeleting] = useState(false); const itemBg = useColorModeValue('gray.50', 'gray.700'); const usernameColor = useColorModeValue('gray.800', 'gray.100'); const timeColor = useColorModeValue('gray.500', 'gray.400'); const contentColor = useColorModeValue('gray.700', 'gray.300'); + // 判断当前用户是否可以删除此评论 + const canDelete = currentUserId && ( + comment.author?.id === currentUserId || + comment.user_id === currentUserId + ); + + // 处理删除 + const handleDelete = async () => { + if (!onDelete) return; + setIsDeleting(true); + try { + await onDelete(comment.id); + onClose(); + } catch (error) { + // 错误由父组件处理 + } finally { + setIsDeleting(false); + } + }; + // 格式化时间 const formatTime = (timestamp) => { const now = dayjs(); @@ -46,43 +80,99 @@ const CommentItem = ({ comment }) => { }; return ( - - - {/* 用户头像 */} - + <> + + + {/* 用户头像 */} + - {/* 评论内容区 */} - - {/* 用户名和时间 */} - - - {comment.author?.username || 'Anonymous'} - - - {formatTime(comment.created_at)} - - + {/* 评论内容区 */} + + {/* 用户名和时间 */} + + + + {comment.author?.username || 'Anonymous'} + + + {formatTime(comment.created_at)} + + - {/* 评论内容 */} - - {comment.content} - - - - + {/* 删除按钮 - 只对自己的评论显示 */} + {canDelete && ( + + } + size="xs" + variant="ghost" + colorScheme="red" + aria-label="删除评论" + onClick={onOpen} + opacity={0.6} + _hover={{ opacity: 1 }} + /> + + )} + + + {/* 评论内容 */} + + {comment.content} + + + + + + {/* 删除确认对话框 */} + + + + + 删除评论 + + + + 确定要删除这条评论吗?此操作不可撤销。 + + + + + + + + + + ); }; diff --git a/src/components/EventCommentSection/CommentList.js b/src/components/EventCommentSection/CommentList.js index 0a08078f..0770e112 100644 --- a/src/components/EventCommentSection/CommentList.js +++ b/src/components/EventCommentSection/CommentList.js @@ -16,7 +16,7 @@ import { import { ChatIcon } from '@chakra-ui/icons'; import CommentItem from './CommentItem'; -const CommentList = ({ comments, loading }) => { +const CommentList = ({ comments, loading, currentUserId, onDelete }) => { const emptyTextColor = useColorModeValue('gray.500', 'gray.400'); const emptyBgColor = useColorModeValue('gray.50', 'gray.700'); @@ -58,7 +58,12 @@ const CommentList = ({ comments, loading }) => { return ( {comments.map((comment) => ( - + ))} ); diff --git a/src/components/EventCommentSection/EventCommentSection.tsx b/src/components/EventCommentSection/EventCommentSection.tsx index 47e4dad1..d69a56f6 100644 --- a/src/components/EventCommentSection/EventCommentSection.tsx +++ b/src/components/EventCommentSection/EventCommentSection.tsx @@ -144,8 +144,9 @@ const EventCommentSection: React.FC = ({ eventId }) => content_type: 'text', author: { id: user?.id || 'current_user', - username: user?.username || '当前用户', - avatar: user?.avatar || null, + // 与导航区保持一致:优先显示昵称 + username: user?.nickname || user?.username || user?.email || '当前用户', + avatar: user?.avatar_url || null, }, created_at: new Date().toISOString(), likes_count: 0, @@ -187,6 +188,51 @@ const EventCommentSection: React.FC = ({ eventId }) => } }, [eventId, commentText, toast, user, setComments, setTotalCount]); + /** + * 删除评论 + */ + const handleDeleteComment = useCallback(async (commentId: string | number) => { + try { + const result = await eventService.deletePost(commentId); + + if (result.success) { + // 从本地 state 中移除该评论 + setComments((prevComments) => + prevComments.filter((comment) => comment.id !== commentId) + ); + // 总评论数 -1 + setTotalCount((prevTotal) => Math.max(0, prevTotal - 1)); + + toast({ + title: '评论已删除', + status: 'success', + duration: 2000, + isClosable: true, + }); + + logger.info('EventCommentSection', '评论删除成功', { + eventId, + commentId, + }); + } else { + throw new Error(result.message || '删除评论失败'); + } + } catch (error: any) { + logger.error('EventCommentSection', 'handleDeleteComment', error, { + eventId, + commentId, + }); + toast({ + title: '删除评论失败', + description: error.message || '请稍后重试', + status: 'error', + duration: 3000, + isClosable: true, + }); + throw error; // 重新抛出让 CommentItem 知道删除失败 + } + }, [eventId, toast, setComments, setTotalCount]); + return ( {/* 标题栏 */} @@ -203,7 +249,12 @@ const EventCommentSection: React.FC = ({ eventId }) => {/* 评论列表 */} - + {/* 加载更多按钮(仅当有更多评论时显示) */} diff --git a/src/mocks/handlers/event.js b/src/mocks/handlers/event.js index a8f488e5..95c23f6d 100644 --- a/src/mocks/handlers/event.js +++ b/src/mocks/handlers/event.js @@ -5,6 +5,7 @@ import { http, HttpResponse } from 'msw'; import { getEventRelatedStocks, generateMockEvents, generateHotEvents, generatePopularKeywords, generateDynamicNewsEvents } from '../data/events'; import { getMockFutureEvents, getMockEventCountsForMonth, toggleEventFollowStatus, isEventFollowed } from '../data/account'; import { generatePopularConcepts } from './concept'; +import { getCurrentUser } from '../data/users'; // 模拟网络延迟 const delay = (ms = 300) => new Promise(resolve => setTimeout(resolve, ms)); @@ -1498,15 +1499,19 @@ export const eventHandlers = [ console.log('[Mock] 发表评论, eventId:', eventId, 'content:', body.content); try { + // 获取当前登录用户信息 + const currentUser = getCurrentUser(); + // 模拟创建新评论 const newComment = { id: `comment_${eventId}_${Date.now()}`, content: body.content, content_type: body.content_type || 'text', author: { - id: 'current_user', - username: '当前用户', - avatar: null, + id: currentUser?.id || 'current_user', + // 与导航区保持一致:优先显示昵称 + username: currentUser?.nickname || currentUser?.username || currentUser?.email || '当前用户', + avatar: currentUser?.avatar_url || null, }, created_at: new Date().toISOString(), likes_count: 0,