// src/views/Community/index.js import React, { useState, useEffect, useCallback } from 'react'; import { useSearchParams, useNavigate } from 'react-router-dom'; import { Box, Container, Grid, GridItem, Card, CardBody, CardHeader, Button, Text, Heading, VStack, HStack, Badge, Spinner, useToast, Flex, Tag, TagLabel, TagCloseButton, IconButton, Wrap, WrapItem, Stat, StatLabel, StatNumber, StatHelpText, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalCloseButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, DrawerCloseButton, useDisclosure, Center, Image, Divider, useColorModeValue, Link, } from '@chakra-ui/react'; import { RepeatIcon, TimeIcon, InfoIcon, SearchIcon, CalendarIcon, StarIcon, ChevronRightIcon, CloseIcon, } from '@chakra-ui/icons'; // 导入组件 import MidjourneyHeroSection from './components/MidjourneyHeroSection'; import EventFilters from './components/EventFilters'; import EventList from './components/EventList'; import EventDetailModal from './components/EventDetailModal'; import StockDetailPanel from './components/StockDetailPanel'; import SearchBox from './components/SearchBox'; import PopularKeywords from './components/PopularKeywords'; import HotEvents from './components/HotEvents'; import ImportanceLegend from './components/ImportanceLegend'; import InvestmentCalendar from './components/InvestmentCalendar'; import { eventService } from '../../services/eventService'; // 导航栏已由 MainLayout 提供,无需在此导入 const filterLabelMap = { date_range: v => v ? `日期: ${v}` : '', sort: v => v ? `排序: ${v === 'new' ? '最新' : v === 'hot' ? '热门' : v === 'returns' ? '收益率' : v}` : '', importance: v => v && v !== 'all' ? `重要性: ${v}` : '', industry_classification: v => v ? `行业: ${v}` : '', industry_code: v => v ? `行业代码: ${v}` : '', q: v => v ? `关键词: ${v}` : '', }; const Community = () => { const [searchParams, setSearchParams] = useSearchParams(); const navigate = useNavigate(); const toast = useToast(); // Chakra UI hooks const bgColor = useColorModeValue('gray.50', 'gray.900'); const cardBg = useColorModeValue('white', 'gray.800'); const borderColor = useColorModeValue('gray.200', 'gray.700'); // Modal/Drawer控制 const { isOpen: isEventModalOpen, onOpen: onEventModalOpen, onClose: onEventModalClose } = useDisclosure(); const { isOpen: isStockDrawerOpen, onOpen: onStockDrawerOpen, onClose: onStockDrawerClose } = useDisclosure(); // 状态管理 const [events, setEvents] = useState([]); const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 }); const [loading, setLoading] = useState(false); const [selectedEvent, setSelectedEvent] = useState(null); const [selectedEventForStock, setSelectedEventForStock] = useState(null); const [popularKeywords, setPopularKeywords] = useState([]); const [hotEvents, setHotEvents] = useState([]); const [lastUpdateTime, setLastUpdateTime] = useState(new Date()); // 从URL获取筛选参数 const getFiltersFromUrl = useCallback(() => { return { sort: searchParams.get('sort') || 'new', importance: searchParams.get('importance') || 'all', date_range: searchParams.get('date_range') || '', q: searchParams.get('q') || '', search_type: searchParams.get('search_type') || 'topic', industry_classification: searchParams.get('industry_classification') || '', industry_code: searchParams.get('industry_code') || '', page: parseInt(searchParams.get('page') || '1', 10) }; }, [searchParams]); // 更新URL参数 const updateUrlParams = useCallback((params) => { const newParams = new URLSearchParams(searchParams); Object.entries(params).forEach(([key, value]) => { if (value) { newParams.set(key, value); } else { newParams.delete(key); } }); setSearchParams(newParams); }, [searchParams, setSearchParams]); // 加载事件列表 const loadEvents = useCallback(async (page = 1) => { setLoading(true); try { const filters = getFiltersFromUrl(); const response = await eventService.getEvents({ ...filters, page, per_page: pagination.pageSize }); if (response.success) { setEvents(response.data.events); setPagination({ current: response.data.pagination.page, pageSize: response.data.pagination.per_page, total: response.data.pagination.total }); setLastUpdateTime(new Date()); } } catch (error) { console.error('Failed to load events:', error); toast({ title: '加载失败', description: '无法加载事件列表', status: 'error', duration: 3000, isClosable: true, }); } finally { setLoading(false); } }, [getFiltersFromUrl, pagination.pageSize, toast]); // 加载热门关键词 const loadPopularKeywords = useCallback(async () => { try { const response = await eventService.getPopularKeywords(20); if (response.success) { setPopularKeywords(response.data); } } catch (error) { console.error('Failed to load popular keywords:', error); } }, []); // 加载热点事件 const loadHotEvents = useCallback(async () => { try { const response = await eventService.getHotEvents({ days: 5, limit: 4 }); if (response.success) { setHotEvents(response.data); } } catch (error) { console.error('Failed to load hot events:', error); } }, []); // 处理筛选变化 const handleFilterChange = useCallback((filterType, value) => { updateUrlParams({ [filterType]: value, page: 1 }); }, [updateUrlParams]); // 处理分页变化 const handlePageChange = useCallback((page) => { updateUrlParams({ page }); loadEvents(page); window.scrollTo(0, 0); }, [updateUrlParams, loadEvents]); // 处理事件点击 const handleEventClick = useCallback((event) => { setSelectedEventForStock(event); onStockDrawerOpen(); }, [onStockDrawerOpen]); // 处理查看详情 const handleViewDetail = useCallback((eventId) => { navigate(`/event-detail/${eventId}`); }, [navigate]); // 处理关键词点击 const handleKeywordClick = useCallback((keyword) => { updateUrlParams({ q: keyword, page: 1 }); }, [updateUrlParams]); // 处理标签删除 const handleRemoveFilterTag = (key) => { let reset = ''; if (key === 'sort') reset = 'new'; if (key === 'importance') reset = 'all'; updateUrlParams({ [key]: reset, page: 1 }); loadEvents(1); }; // 获取筛选标签 const filters = getFiltersFromUrl(); const filterTags = Object.entries(filters) .filter(([key, value]) => { if (key === 'industry_code') return !!value; if (key === 'importance') return value && value !== 'all'; if (key === 'sort') return value && value !== 'new'; if (key === 'date_range') return !!value; if (key === 'q') return !!value; return false; }) .map(([key, value]) => { if (key === 'industry_code') return { key, label: `行业代码: ${value}` }; return { key, label: filterLabelMap[key] ? filterLabelMap[key](value) : `${key}: ${value}` }; }); // 初始化加载 useEffect(() => { const page = parseInt(searchParams.get('page') || '1', 10); loadEvents(page); loadPopularKeywords(); loadHotEvents(); }, [searchParams, loadEvents, loadPopularKeywords, loadHotEvents]); return ( {/* 导航栏已由 MainLayout 提供 */} {/* Midjourney风格英雄区域 */} {/* 主内容区域 */} {/* 左侧主要内容 */} {/* 筛选器 - 需要改造为Chakra UI版本 */} {/* 筛选标签 */} {filterTags.length > 0 && ( {filterTags.map(tag => ( {tag.label} handleRemoveFilterTag(tag.key)} /> ))} )} {/* 事件列表卡片 */} 实时事件时间轴 全网监控 智能捕获 深度分析 最后更新: {lastUpdateTime.toLocaleTimeString()} {loading ? (
正在加载最新事件...
) : events.length > 0 ? ( ) : (
暂无事件数据
)}
{/* 右侧侧边栏 */} {/* 搜索框 - 需要改造为Chakra UI版本 */} { updateUrlParams({ ...values, page: 1 }); }} /> {/* 投资日历 - 需要改造为Chakra UI版本 */} 投资日历 {/* 热门关键词 - 需要改造为Chakra UI版本 */} 热门关键词 {/* 重要性说明 - 需要改造为Chakra UI版本 */} 重要性说明
{/* 热点事件 - 需要改造为Chakra UI版本 */} {hotEvents.length > 0 && ( 🔥 热点事件 )}
{/* Footer区域 */} © 2024 价值前沿. 保留所有权利. 京公网安备11010802046286号 京ICP备2025107343号-1 {/* 事件详情模态框 - 使用Chakra UI Modal */} 事件详情 { setSelectedEvent(null); onEventModalClose(); }} /> {/* 股票详情抽屉 - 使用原组件自带的 Antd Drawer,避免与 Chakra Drawer 重叠导致空白 */} { setSelectedEventForStock(null); onStockDrawerClose(); }} />
); }; export default Community;