// src/components/EventCommentSection/EventCommentSection.js /** * 事件评论区主组件 * 功能:整合评论列表 + 评论输入框,管理评论数据 */ import React, { useState, useEffect, useCallback } from 'react'; import { Box, VStack, Heading, Badge, HStack, Divider, useColorModeValue, useToast, } from '@chakra-ui/react'; import { useAuth } from '../../contexts/AuthContext'; import { eventService } from '../../services/eventService'; import { logger } from '../../utils/logger'; import CommentList from './CommentList'; import CommentInput from './CommentInput'; /** * 事件评论区组件 * @param {Object} props * @param {number} props.eventId - 事件 ID */ const EventCommentSection = ({ eventId }) => { const { user } = useAuth(); const toast = useToast(); const dividerColor = useColorModeValue('gray.200', 'gray.600'); const headingColor = useColorModeValue('gray.700', 'gray.200'); const sectionBg = useColorModeValue('gray.50', 'gray.750'); // 状态管理 const [comments, setComments] = useState([]); const [loading, setLoading] = useState(false); const [commentText, setCommentText] = useState(''); const [submitting, setSubmitting] = useState(false); const [totalCount, setTotalCount] = useState(0); // 总评论数(从后端获取) // 加载评论列表 const loadComments = useCallback(async () => { if (!eventId) return; setLoading(true); try { // 加载第1页,每页5条评论 const result = await eventService.getPosts(eventId, 'latest', 1, 5); if (result.success) { setComments(result.data || []); // 保存总评论数(从 pagination.total 读取) setTotalCount(result.pagination?.total || result.data?.length || 0); logger.info('EventCommentSection', '评论加载成功', { eventId, count: result.data?.length || 0, total: result.pagination?.total || 0, }); } } catch (error) { logger.error('EventCommentSection', 'loadComments', error, { eventId }); toast({ title: '加载评论失败', description: error.message || '请稍后重试', status: 'error', duration: 3000, isClosable: true, }); } finally { setLoading(false); } }, [eventId, toast]); // 发表评论 const handleSubmitComment = useCallback(async () => { if (!commentText.trim()) { toast({ title: '请输入评论内容', status: 'warning', duration: 2000, isClosable: true, }); return; } setSubmitting(true); try { const result = await eventService.createPost(eventId, { content: commentText.trim(), content_type: 'text', }); if (result.success) { // 乐观更新:立即将新评论添加到本地 state,避免重新加载导致的闪烁 const newComment = { id: result.data?.id || `comment_optimistic_${Date.now()}`, content: commentText.trim(), content_type: 'text', author: { id: user?.id || 'current_user', username: user?.username || '当前用户', avatar: user?.avatar || null, }, created_at: new Date().toISOString(), likes_count: 0, is_liked: false, }; // 将新评论追加到列表末尾(最新评论在底部) setComments([...comments, newComment]); // 总评论数 +1 setTotalCount(totalCount + 1); toast({ title: '评论发布成功', status: 'success', duration: 2000, isClosable: true, }); setCommentText(''); // 清空输入框 // ✅ 不再调用 loadComments(),避免 loading 状态导致高度闪烁 logger.info('EventCommentSection', '评论发布成功(乐观更新)', { eventId, content: commentText.trim(), commentId: newComment.id, }); } else { throw new Error(result.message || '评论发布失败'); } } catch (error) { logger.error('EventCommentSection', 'handleSubmitComment', error, { eventId }); toast({ title: '评论发布失败', description: error.message || '请稍后重试', status: 'error', duration: 3000, isClosable: true, }); } finally { setSubmitting(false); } }, [eventId, commentText, toast, comments, user, totalCount]); // 初始加载评论 useEffect(() => { loadComments(); }, [loadComments]); return ( {/* 标题栏 */} 讨论区 {totalCount} 条评论 {/* 评论列表 */} {/* 评论输入框(仅登录用户显示) */} {user && ( setCommentText(e.target.value)} onSubmit={handleSubmitComment} isSubmitting={submitting} maxLength={500} placeholder="说点什么..." /> )} ); }; export default EventCommentSection;