/**
* 热点概览组件 - 科技感设计
* 展示大盘分时走势 + 概念异动标注
*
* 布局设计:
* - 顶部:统计摘要(指数信息 + 异动统计)
* - 中部:大尺寸分时图(主要展示区域)
* - 底部:异动列表(横向滚动卡片)
*/
import React, { useState, useCallback } from 'react';
import {
Box,
Heading,
Text,
HStack,
VStack,
Spinner,
Center,
Icon,
Flex,
Spacer,
Tooltip,
useColorModeValue,
IconButton,
Collapse,
SimpleGrid,
} from '@chakra-ui/react';
import { keyframes } from '@emotion/react';
import {
Flame,
List,
LineChart,
ChevronDown,
ChevronUp,
Info,
Zap,
AlertCircle,
TrendingUp,
TrendingDown,
} from 'lucide-react';
import { useHotspotData } from './hooks';
import { IndexMinuteChart, ConceptAlertList, AlertSummary } from './components';
import { ALERT_TYPE_CONFIG, getAlertTypeLabel } from './utils/chartHelpers';
// 动画效果
const gradientShift = keyframes`
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
`;
const pulseGlow = keyframes`
0%, 100% { opacity: 0.5; }
50% { opacity: 1; }
`;
/**
* 紧凑型异动卡片(用于横向滚动)
*/
const CompactAlertCard = ({ alert, onClick, isSelected }) => {
const cardBg = useColorModeValue('white', '#0d0d0d');
const borderColor = useColorModeValue('gray.200', '#2d2d2d');
const textColor = useColorModeValue('gray.800', 'white');
const subTextColor = useColorModeValue('gray.500', 'gray.400');
const config = ALERT_TYPE_CONFIG[alert.alert_type] || ALERT_TYPE_CONFIG.surge;
const isUp = alert.alert_type !== 'surge_down';
return (
onClick?.(alert)}
transition="all 0.2s"
_hover={{
borderColor: config.color,
transform: 'translateY(-2px)',
boxShadow: `0 4px 15px ${config.color}25`,
}}
position="relative"
overflow="hidden"
>
{/* 顶部渐变条 */}
{/* 时间 + 类型 */}
{alert.time}
{getAlertTypeLabel(alert.alert_type)}
{/* 概念名称 */}
{alert.concept_name}
{/* 分数 + Alpha */}
评分
{Math.round(alert.final_score || 0)}
{alert.alpha != null && (
= 0 ? '#ff4d4f' : '#52c41a'}
>
α {alert.alpha >= 0 ? '+' : ''}{alert.alpha.toFixed(1)}%
)}
);
};
/**
* 热点概览主组件
* @param {Object} props
* @param {Date|null} props.selectedDate - 选中的交易日期
*/
const HotspotOverview = ({ selectedDate }) => {
const [selectedAlert, setSelectedAlert] = useState(null);
const [showDetailList, setShowDetailList] = useState(false);
// 获取数据
const { loading, error, data } = useHotspotData(selectedDate);
// 颜色主题
const cardBg = useColorModeValue('white', '#0a0a0a');
const borderColor = useColorModeValue('gray.200', '#1f1f1f');
const textColor = useColorModeValue('gray.800', 'white');
const subTextColor = useColorModeValue('gray.600', 'gray.400');
const sectionBg = useColorModeValue('gray.50', '#0d0d0d');
const scrollbarColor = useColorModeValue('#ddd', '#333');
// 点击异动标注
const handleAlertClick = useCallback((alert) => {
setSelectedAlert(alert);
}, []);
// 渲染加载状态
if (loading) {
return (
加载热点概览数据
正在获取市场异动信息...
);
}
// 渲染错误状态
if (error) {
return (
数据加载失败
{error}
);
}
if (!data) return null;
const { index, alerts, alert_summary } = data;
return (
{/* 顶部装饰条 */}
{/* 头部 */}
热点概览
实时概念异动监控
{alerts.length > 0 && (
{alerts.length}
)}
{/* 统计摘要 - 简化版 */}
{/* 指数信息 */}
{index?.name || '上证指数'}
= 0 ? '#ff4d4f' : '#52c41a'}
>
{index?.latest_price?.toFixed(2) || '-'}
= 0 ? 'red.50' : 'green.50'}
>
= 0 ? TrendingUp : TrendingDown}
boxSize={3}
color={(index?.change_pct || 0) >= 0 ? '#ff4d4f' : '#52c41a'}
/>
= 0 ? '#ff4d4f' : '#52c41a'}
>
{(index?.change_pct || 0) >= 0 ? '+' : ''}{(index?.change_pct || 0).toFixed(2)}%
高 {index?.high?.toFixed(2)}
低 {index?.low?.toFixed(2)}
{/* 异动统计 */}
今日异动
{alerts.length} 次
{Object.entries(alert_summary || {})
.filter(([_, count]) => count > 0)
.slice(0, 4)
.map(([type, count]) => {
const config = ALERT_TYPE_CONFIG[type];
if (!config) return null;
return (
{config.label}
{count}
);
})}
{/* 大尺寸分时图 */}
大盘分时走势
{/* 异动列表 - 横向滚动 */}
{alerts.length > 0 && (
异动记录
(横向滚动查看更多)
}
size="sm"
variant="ghost"
borderRadius="lg"
onClick={() => setShowDetailList(!showDetailList)}
aria-label="切换详细列表"
/>
{/* 横向滚动卡片 */}
{[...alerts]
.sort((a, b) => (b.time || '').localeCompare(a.time || ''))
.map((alert, idx) => (
))}
{/* 详细列表(可展开) */}
)}
{/* 无异动提示 */}
{alerts.length === 0 && (
当日暂无概念异动数据
)}
);
};
export default HotspotOverview;