/**
* 热点概览组件 - Modern Spatial & Glassmorphism 设计
* 展示大盘分时走势 + 概念异动标注
*
* 布局设计:
* - 顶部:统计摘要(指数信息 + 异动统计)
* - 中部:大尺寸分时图(主要展示区域)
* - 底部:异动列表(横向滚动卡片)
*/
import React, { useState, useCallback } from 'react';
import {
Box,
Heading,
Text,
HStack,
VStack,
Spinner,
Center,
Icon,
Flex,
Spacer,
Tooltip,
IconButton,
Collapse,
SimpleGrid,
useDisclosure,
} from '@chakra-ui/react';
import { keyframes, css } from '@emotion/react';
import {
Flame,
List,
LineChart,
ChevronDown,
ChevronUp,
Info,
Zap,
AlertCircle,
TrendingUp,
TrendingDown,
Sparkles,
} from 'lucide-react';
import { useHotspotData } from './hooks';
import { IndexMinuteChart, ConceptAlertList, AlertSummary, AlertDetailDrawer } from './components';
import { ALERT_TYPE_CONFIG, getAlertTypeLabel } from './utils/chartHelpers';
import {
glassEffect,
colors,
glowEffects,
getMarketColor,
getMarketGlow,
} from '../../theme/glassTheme';
// 动画效果
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.6; transform: scale(1); }
50% { opacity: 1; transform: scale(1.02); }
`;
const floatAnimation = keyframes`
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-3px); }
`;
const shimmer = keyframes`
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
`;
/**
* 紧凑型异动卡片(用于横向滚动)- Glassmorphism 风格
*/
const CompactAlertCard = ({ alert, onClick, isSelected }) => {
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.3s cubic-bezier(0.4, 0, 0.2, 1)"
position="relative"
overflow="hidden"
_hover={{
bg: 'rgba(255, 255, 255, 0.05)',
border: `1px solid ${config.color}50`,
transform: 'translateY(-4px)',
boxShadow: `0 8px 25px ${config.color}20, inset 0 1px 0 rgba(255,255,255,0.1)`,
}}
css={isSelected ? css`animation: ${floatAnimation} 3s ease-in-out infinite;` : undefined}
>
{/* 顶部渐变发光条 */}
{/* 背景光晕 */}
{isSelected && (
)}
{/* 时间 + 类型 */}
{alert.time}
{getAlertTypeLabel(alert.alert_type)}
{/* 概念名称 */}
{alert.concept_name}
{/* 分数 + Alpha */}
评分
{Math.round(alert.final_score || 0)}
{alert.alpha != null && (
α {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 [autoExpandAlertKey, setAutoExpandAlertKey] = useState(null);
const [drawerAlertData, setDrawerAlertData] = useState(null);
// 右边栏抽屉控制
const { isOpen: isDrawerOpen, onOpen: onDrawerOpen, onClose: onDrawerClose } = useDisclosure();
// 获取数据
const { loading, error, data } = useHotspotData(selectedDate);
// Glassmorphism 颜色主题
const cardBg = glassEffect.card.bg;
const borderColor = colors.border.primary;
const textColor = colors.text.primary;
const subTextColor = colors.text.secondary;
const sectionBg = glassEffect.light.bg;
const scrollbarColor = 'rgba(139, 92, 246, 0.3)';
// 点击分时图上的异动标注 - 打开右边栏抽屉显示详情
const handleChartAlertClick = useCallback((alertGroupData) => {
// alertGroupData 包含 { alerts, timeRange, alertCount, time }
setDrawerAlertData(alertGroupData);
onDrawerOpen();
}, [onDrawerOpen]);
// 点击底部异动卡片 - 展开详细列表并选中
const handleAlertClick = useCallback((alert) => {
setSelectedAlert(alert);
// 自动展开详细列表并设置需要展开的项
setShowDetailList(true);
const alertKey = `${alert.concept_id}-${alert.time}`;
setAutoExpandAlertKey(alertKey);
}, []);
// 渲染加载状态 - Glassmorphism 风格
if (loading) {
return (
{/* 极光背景 */}
{/* 顶部发光条 */}
加载热点概览数据
正在获取市场异动信息...
);
}
// 渲染错误状态 - Glassmorphism 风格
if (error) {
return (
数据加载失败
{error}
);
}
if (!data) return null;
const { index, alerts, alert_summary } = data;
// 计算市场颜色
const marketColor = getMarketColor(index?.change_pct || 0);
const marketGlow = getMarketGlow(index?.change_pct || 0);
return (
{/* 极光背景装饰 */}
{/* 顶部发光装饰条 */}
{/* 头部 - Glassmorphism */}
{/* 图标发光效果 */}
热点概览
实时概念异动监控
{alerts.length > 0 && (
{alerts.length}
)}
{/* 统计摘要 - Glassmorphism Bento Grid */}
{/* 指数信息卡片 */}
{/* 背景光晕 */}
{index?.name || '上证指数'}
{index?.latest_price?.toFixed(2) || '-'}
= 0 ? TrendingUp : TrendingDown}
boxSize={4}
color={marketColor}
css={css`filter: drop-shadow(0 0 4px ${marketColor});`}
/>
{(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, 5)
.map(([type, count]) => {
const config = ALERT_TYPE_CONFIG[type];
if (!config) return null;
return (
{config.label}
{count}
);
})}
{/* 大尺寸分时图 - Glassmorphism */}
{/* 图表区域背景光晕 */}
大盘分时走势
{/* 异动列表 - Glassmorphism 横向滚动 */}
{alerts.length > 0 && (
异动记录
(点击卡片查看个股详情)
}
size="sm"
variant="ghost"
borderRadius="12px"
color={colors.text.secondary}
_hover={{
bg: 'rgba(255,255,255,0.05)',
color: textColor,
}}
onClick={() => setShowDetailList(!showDetailList)}
aria-label="切换详细列表"
/>
{/* 横向滚动卡片 */}
{[...alerts]
.sort((a, b) => (b.time || '').localeCompare(a.time || ''))
.map((alert, idx) => (
))}
{/* 详细列表(可展开) - Glassmorphism */}
{/* 背景光晕 */}
setAutoExpandAlertKey(null)}
/>
)}
{/* 无异动提示 - Glassmorphism */}
{alerts.length === 0 && (
{/* 背景光晕 */}
当日暂无概念异动数据
)}
{/* 异动详情右边栏抽屉 */}
);
};
export default HotspotOverview;