/** * 预测话题评论区组件 * 支持发布评论、嵌套回复、点赞、庄主标识、观点IPO投资 */ import React, { useState, useEffect } from 'react'; import { Box, VStack, HStack, Text, Avatar, Textarea, Button, Flex, IconButton, Divider, useToast, Badge, Tooltip, } from '@chakra-ui/react'; import { motion, AnimatePresence } from 'framer-motion'; import { Heart, MessageCircle, Send, TrendingUp, Crown, Pin } from 'lucide-react'; import { forumColors } from '@theme/forumTheme'; import { createComment, getComments, likeComment, } from '@services/predictionMarketService.api'; import { useAuth } from '@contexts/AuthContext'; const MotionBox = motion(Box); const CommentItem = ({ comment, topicId, topic, onReply, onInvest }) => { const [isLiked, setIsLiked] = useState(false); const [likes, setLikes] = useState(comment.likes_count || 0); const [showReply, setShowReply] = useState(false); // 处理点赞 const handleLike = async () => { try { const response = await likeComment(comment.id); if (response.success) { setLikes(response.likes_count); setIsLiked(response.action === 'like'); } } catch (error) { console.error('点赞失败:', error); } }; // 格式化时间 const formatTime = (dateString) => { const date = new Date(dateString); const now = new Date(); const diff = now - date; const minutes = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); if (minutes < 1) return '刚刚'; if (minutes < 60) return `${minutes}分钟前`; if (hours < 24) return `${hours}小时前`; if (days < 7) return `${days}天前`; return date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit', }); }; // 判断是否是庄主 const isYesLord = comment.user?.id === topic?.yes_lord_id; const isNoLord = comment.user?.id === topic?.no_lord_id; const isLord = isYesLord || isNoLord; return ( {/* 头像 */} {/* 评论内容 */} {/* 用户名和时间 */} {comment.user?.nickname || comment.user?.username || '匿名用户'} {/* 庄主标识 */} {isLord && ( {isYesLord ? 'YES庄' : 'NO庄'} )} {/* 置顶标识 */} {comment.is_pinned && ( 置顶 )} {formatTime(comment.created_at)} {/* 评论正文 */} {comment.content} {/* 观点IPO投资统计 */} {comment.total_investment > 0 && ( {comment.investor_count || 0}人投资 总投资: {comment.total_investment} 积分 {comment.is_verified && ( {comment.verification_result === 'correct' ? '✓ 预测正确' : '✗ 预测错误'} )} )} {/* 操作按钮 */} {likes > 0 ? likes : '点赞'} setShowReply(!showReply)} _hover={{ color: forumColors.primary[500] }} > 回复 {/* 投资观点按钮 */} {!comment.is_verified && onInvest && ( )} {/* 回复输入框 */} {showReply && ( { setShowReply(false); if (onReply) onReply(); }} /> )} {/* 回复列表 */} {comment.replies && comment.replies.length > 0 && ( {comment.replies.map((reply) => ( {reply.user?.nickname || reply.user?.username || '匿名用户'} {formatTime(reply.created_at)} {reply.content} ))} )} ); }; const ReplyInput = ({ topicId, parentId = null, placeholder, onSubmit }) => { const toast = useToast(); const { user } = useAuth(); const [content, setContent] = useState(''); const [isSubmitting, setIsSubmitting] = useState(false); const handleSubmit = async () => { if (!content.trim()) { toast({ title: '请输入评论内容', status: 'warning', duration: 2000, }); return; } setIsSubmitting(true); try { const response = await createComment(topicId, { content: content.trim(), parent_id: parentId, }); if (response.success) { toast({ title: '评论成功', status: 'success', duration: 2000, }); setContent(''); if (onSubmit) onSubmit(); } } catch (error) { console.error('评论失败:', error); toast({ title: '评论失败', description: error.response?.data?.error || error.message, status: 'error', duration: 3000, }); } finally { setIsSubmitting(false); } }; return (