import React, { useState, useEffect, useCallback } from 'react'; import { Box, VStack, HStack, Text, Badge, Button, Icon, Center, Spinner, LinkBox, LinkOverlay, Tooltip, Tag, TagLabel, Wrap, WrapItem, useColorModeValue, useToast, } from '@chakra-ui/react'; import { Link } from 'react-router-dom'; import { FiCalendar, FiClock, FiStar, FiTrendingUp, FiAlertCircle, } from 'react-icons/fi'; import { eventService } from '../../../services/eventService'; import moment from 'moment'; export default function MyFutureEvents({ limit = 5 }) { const [futureEvents, setFutureEvents] = useState([]); const [loading, setLoading] = useState(true); const toast = useToast(); // 颜色主题 const borderColor = useColorModeValue('gray.200', 'gray.600'); const hoverBg = useColorModeValue('gray.50', 'gray.700'); const secondaryText = useColorModeValue('gray.600', 'gray.400'); const importanceBg = useColorModeValue('yellow.50', 'yellow.900'); const importanceColor = useColorModeValue('yellow.600', 'yellow.300'); // 加载关注的未来事件 const loadFutureEvents = useCallback(async () => { try { setLoading(true); const response = await eventService.calendar.getFollowingEvents(); if (response.success) { // 按时间排序,最近的在前 const sortedEvents = (response.data || []).sort((a, b) => moment(a.calendar_time).valueOf() - moment(b.calendar_time).valueOf() ); setFutureEvents(sortedEvents); } } catch (error) { console.error('加载未来事件失败:', error); toast({ title: '加载失败', description: '无法加载关注的未来事件', status: 'error', duration: 3000, isClosable: true, }); } finally { setLoading(false); } }, [toast]); useEffect(() => { loadFutureEvents(); }, [loadFutureEvents]); // 取消关注 const handleUnfollow = async (eventId) => { try { const response = await eventService.calendar.toggleFollow(eventId); if (response.success) { setFutureEvents(prev => prev.filter(event => event.id !== eventId)); toast({ title: '取消关注成功', status: 'success', duration: 2000, isClosable: true, }); } } catch (error) { console.error('取消关注失败:', error); toast({ title: '操作失败', description: '取消关注失败,请重试', status: 'error', duration: 3000, isClosable: true, }); } }; // 格式化时间 const formatEventTime = (time) => { const eventTime = moment(time); const now = moment(); const daysDiff = eventTime.diff(now, 'days'); if (daysDiff === 0) { return { date: '今天', time: eventTime.format('HH:mm'), color: 'red', urgent: true }; } else if (daysDiff === 1) { return { date: '明天', time: eventTime.format('HH:mm'), color: 'orange', urgent: true }; } else if (daysDiff <= 7) { return { date: `${daysDiff}天后`, time: eventTime.format('MM/DD HH:mm'), color: 'yellow', urgent: false }; } else { return { date: eventTime.format('MM月DD日'), time: eventTime.format('HH:mm'), color: 'gray', urgent: false }; } }; // 获取重要性颜色 const getImportanceColor = (star) => { if (star >= 5) return 'red'; if (star >= 4) return 'orange'; if (star >= 3) return 'yellow'; return 'blue'; }; if (loading) { return (
); } if (futureEvents.length === 0) { return (
暂无关注的未来事件
); } return ( {futureEvents.slice(0, limit).map((event) => { const timeInfo = formatEventTime(event.calendar_time); return ( {/* 紧急标记 */} {timeInfo.urgent && ( 即将发生 )} {/* 标题 */} {event.title} {/* 时间和重要性 */} {timeInfo.date} {timeInfo.time} {/* 重要性星级 */} {[...Array(5)].map((_, i) => ( ))} {/* 标签和相关信息 */} {event.type && ( {event.type === 'event' ? '事件' : '数据'} )} {event.related_stocks && event.related_stocks.length > 0 && ( {event.related_stocks.length}只相关股票 )} {/* 操作按钮 */} {/* 预测信息 */} {event.forecast && ( 预测 {event.forecast} )} ); })} {/* 查看更多 */} {futureEvents.length > limit && ( )} ); }