diff --git a/src/views/StockOverview/components/HotspotOverview/index.js b/src/views/StockOverview/components/HotspotOverview/index.js
index f93b4535..17092fc1 100644
--- a/src/views/StockOverview/components/HotspotOverview/index.js
+++ b/src/views/StockOverview/components/HotspotOverview/index.js
@@ -3,8 +3,9 @@
* 展示大盘分时走势 + 概念异动标注
*
* 布局设计:
- * - 顶部:统计摘要(指数信息 + 异动统计)
+ * - 顶部:标题 + 日期选择器 + 异动数量
* - 中部:大尺寸分时图(主要展示区域)
+ * - 下方:统计卡片(指数信息 + 异动统计)
* - 底部:异动列表(横向滚动卡片)
*/
import React, { useState, useCallback } from 'react';
@@ -39,6 +40,7 @@ import {
import { useHotspotData } from './hooks';
import { IndexMinuteChart, AlertDetailDrawer } from './components';
import { ALERT_TYPE_CONFIG, getAlertTypeLabel } from './utils/chartHelpers';
+import TradeDatePicker from '@components/TradeDatePicker';
import {
glassEffect,
colors,
@@ -192,10 +194,15 @@ const CompactAlertCard = ({ alert, onClick, isSelected }) => {
* 热点概览主组件
* @param {Object} props
* @param {Date|null} props.selectedDate - 选中的交易日期
+ * @param {Function} props.onDateChange - 日期变更回调
+ * @param {Date} props.minDate - 最小可选日期
+ * @param {Date} props.maxDate - 最大可选日期
*/
-const HotspotOverview = ({ selectedDate }) => {
+const HotspotOverview = ({ selectedDate, onDateChange, minDate, maxDate }) => {
const [selectedAlert, setSelectedAlert] = useState(null);
const [drawerAlertData, setDrawerAlertData] = useState(null);
+ // 选中的异动类型过滤器(null 表示全部)
+ const [selectedAlertType, setSelectedAlertType] = useState(null);
// 右边栏抽屉控制
const { isOpen: isDrawerOpen, onOpen: onDrawerOpen, onClose: onDrawerClose } = useDisclosure();
@@ -231,6 +238,11 @@ const HotspotOverview = ({ selectedDate }) => {
onDrawerOpen();
}, [onDrawerOpen]);
+ // 点击异动类型标签 - 切换过滤器
+ const handleAlertTypeClick = useCallback((type) => {
+ setSelectedAlertType(prevType => prevType === type ? null : type);
+ }, []);
+
// 渲染加载状态 - Glassmorphism 风格
if (loading) {
return (
@@ -335,6 +347,11 @@ const HotspotOverview = ({ selectedDate }) => {
const { index, alerts, alert_summary } = data;
+ // 根据选中的类型过滤异动列表
+ const filteredAlerts = selectedAlertType
+ ? alerts.filter(alert => alert.alert_type === selectedAlertType)
+ : alerts;
+
// 计算市场颜色
const marketColor = getMarketColor(index?.change_pct || 0);
const marketGlow = getMarketGlow(index?.change_pct || 0);
@@ -415,6 +432,18 @@ const HotspotOverview = ({ selectedDate }) => {
+ {/* 日期选择器 */}
+ {onDateChange && (
+
+ )}
{alerts.length > 0 && (
{
)}
-
+
@@ -449,7 +478,65 @@ const HotspotOverview = ({ selectedDate }) => {
- {/* 统计摘要 - Glassmorphism Bento Grid */}
+ {/* 大尺寸分时图 - Glassmorphism(移到统计卡片前面) */}
+
+ {/* 图表区域背景光晕 */}
+
+
+
+
+
+
+ 大盘分时走势
+
+
+
+
+
+
+
+
+ {/* 统计摘要 - Glassmorphism Bento Grid(移到分时图后面) */}
{/* 指数信息卡片 */}
{
}}
>
- 今日异动
-
- {alerts.length} 次
-
+
+ 今日异动
+ (点击筛选)
+
+
+ {selectedAlertType && (
+ setSelectedAlertType(null)}
+ _hover={{ textDecoration: 'underline' }}
+ >
+ 清除筛选
+
+ )}
+
+ {selectedAlertType ? `${filteredAlerts.length}/${alerts.length}` : alerts.length} 次
+
+
{Object.entries(alert_summary || {})
@@ -563,6 +666,7 @@ const HotspotOverview = ({ selectedDate }) => {
.map(([type, count]) => {
const config = ALERT_TYPE_CONFIG[type];
if (!config) return null;
+ const isSelected = selectedAlertType === type;
return (
{
px={3}
py={1.5}
borderRadius="full"
- bg={`${config.color}15`}
- border={`1px solid ${config.color}25`}
+ bg={isSelected ? `${config.color}35` : `${config.color}15`}
+ border={isSelected ? `2px solid ${config.color}` : `1px solid ${config.color}25`}
+ cursor="pointer"
transition="all 0.2s"
+ transform={isSelected ? 'scale(1.05)' : 'scale(1)'}
+ boxShadow={isSelected ? `0 0 20px ${config.color}40` : 'none'}
+ onClick={() => handleAlertTypeClick(type)}
_hover={{
bg: `${config.color}25`,
boxShadow: `0 0 15px ${config.color}30`,
+ transform: 'scale(1.02)',
}}
>
- {config.label}
+ {config.label}
{
- {/* 大尺寸分时图 - Glassmorphism */}
-
- {/* 图表区域背景光晕 */}
-
-
-
-
-
-
- 大盘分时走势
-
-
-
-
-
-
-
-
{/* 异动列表 - Glassmorphism 横向滚动 */}
{alerts.length > 0 && (
@@ -670,7 +721,11 @@ const HotspotOverview = ({ selectedDate }) => {
/>
异动记录
- (点击卡片查看详情)
+
+ {selectedAlertType
+ ? `(已筛选 ${ALERT_TYPE_CONFIG[selectedAlertType]?.label || selectedAlertType},共 ${filteredAlerts.length} 条)`
+ : '(点击卡片查看详情)'}
+
{/* 横向滚动卡片 */}
@@ -688,7 +743,7 @@ const HotspotOverview = ({ selectedDate }) => {
}}
>
- {[...alerts]
+ {[...filteredAlerts]
.sort((a, b) => (b.time || '').localeCompare(a.time || ''))
.map((alert, idx) => (
{
)}
{/* 无异动提示 - Glassmorphism */}
- {alerts.length === 0 && (
+ {filteredAlerts.length === 0 && (
{
css={css`filter: drop-shadow(0 0 10px rgba(139, 92, 246, 0.3));`}
/>
- 当日暂无概念异动数据
+
+ {selectedAlertType
+ ? `未找到「${ALERT_TYPE_CONFIG[selectedAlertType]?.label || selectedAlertType}」类型的异动`
+ : '当日暂无概念异动数据'}
+
+ {selectedAlertType && (
+ setSelectedAlertType(null)}
+ _hover={{ textDecoration: 'underline' }}
+ >
+ 查看全部异动
+
+ )}
)}
diff --git a/src/views/StockOverview/index.js b/src/views/StockOverview/index.js
index 97a099d3..4cb1130b 100644
--- a/src/views/StockOverview/index.js
+++ b/src/views/StockOverview/index.js
@@ -48,7 +48,7 @@ import {
Skeleton,
SkeletonText,
} from '@chakra-ui/react';
-import { Search, X, ArrowRight, TrendingUp, Info, ChevronRight, Calendar, LineChart, Flame, Rocket, Brain, ArrowUp, ArrowDown, BarChart2, Tag as TagIcon, Layers, Zap } from 'lucide-react';
+import { Search, X, ArrowRight, TrendingUp, Info, ChevronRight, Calendar, LineChart, Flame, Rocket, Brain, ArrowUp, ArrowDown, BarChart2, Tag as TagIcon, Layers, Zap, Wallet, Banknote, Scale } from 'lucide-react';
import ConceptStocksModal from '@components/ConceptStocksModal';
import TradeDatePicker from '@components/TradeDatePicker';
import HotspotOverview from './components/HotspotOverview';
@@ -265,12 +265,14 @@ const StockOverview = () => {
const newStats = {
...(prevStats || {}), // 先保留所有现有字段(包括 rising_count/falling_count)
...data.summary, // 然后覆盖 summary 字段
+ yesterday: data.yesterday, // 保存昨日对比数据
date: data.trade_date
};
return newStats;
});
const newStats = {
...data.summary,
+ yesterday: data.yesterday,
date: data.trade_date
};
// 日期和可选日期列表由 fetchTopConcepts 统一设置,这里不再设置
@@ -674,42 +676,69 @@ const StockOverview = () => {
onResultSelect: (item, index) => handleSelectStock(item.raw, index),
}}
stats={{
- columns: { base: 2, md: 4 },
+ columns: { base: 1, sm: 3, md: 3 },
items: [
{
key: 'marketCap',
label: 'A股总市值',
value: marketStats ? `${(marketStats.total_market_cap / 10000).toFixed(1)}万亿` : null,
+ // 市值趋势对比
+ trend: marketStats?.yesterday?.total_market_cap ? (() => {
+ const change = ((marketStats.total_market_cap - marketStats.yesterday.total_market_cap) / marketStats.yesterday.total_market_cap) * 100;
+ return {
+ direction: change > 0.01 ? 'up' : change < -0.01 ? 'down' : 'flat',
+ percent: Math.abs(change),
+ };
+ })() : undefined,
+ // 水印背景图标 - 钱袋图标
+ watermark: { icon: Wallet, color: goldColor, opacity: 0.1 },
},
{
key: 'amount',
label: '今日成交额',
value: marketStats ? `${(marketStats.total_amount / 10000).toFixed(1)}万亿` : null,
+ // 成交额趋势对比(放量/缩量)
+ trend: marketStats?.yesterday?.total_amount ? (() => {
+ const change = ((marketStats.total_amount - marketStats.yesterday.total_amount) / marketStats.yesterday.total_amount) * 100;
+ return {
+ direction: change > 0.01 ? 'up' : change < -0.01 ? 'down' : 'flat',
+ percent: Math.abs(change),
+ label: change > 5 ? '放量' : change < -5 ? '缩量' : undefined,
+ };
+ })() : undefined,
+ // 水印背景图标 - 钞票图标
+ watermark: { icon: Banknote, color: goldColor, opacity: 0.1 },
},
{
key: 'rising',
- label: '上涨家数',
- value: marketStats?.rising_count,
- valueColor: '#ff4d4d',
- },
- {
- key: 'falling',
- label: '下跌家数',
- value: marketStats?.falling_count,
- valueColor: 'green.400',
+ label: '多空对比',
+ // 显示为 "上涨/下跌" 格式,使用自定义渲染
+ value: (marketStats?.rising_count && marketStats?.falling_count)
+ ? `${marketStats.rising_count}/${marketStats.falling_count}`
+ : marketStats?.rising_count,
+ // 涨跌进度条(不显示底部标签)
+ progressBar: (marketStats?.rising_count && marketStats?.falling_count) ? {
+ value: marketStats.rising_count,
+ total: marketStats.falling_count,
+ positiveColor: '#ff4d4d',
+ negativeColor: '#22c55e',
+ } : undefined,
+ // 水印背景图标 - 天平图标
+ watermark: { icon: Scale, color: goldColor, opacity: 0.1 },
},
],
}}
/>
- {/* 主内容区 */}
-
- {/* 日期选择器 */}
-
-
- {
+ {/* 主内容区 - 负 margin 使卡片向上浮动,与 Hero 产生重叠纵深感 */}
+
+ {/* 热点概览 - 大盘走势 + 概念异动 */}
+ {/* 只在 selectedDate 确定后渲染,避免 null → 日期 的双重请求 */}
+
+ {selectedDate ? (
+ {
const dateStr = date.toISOString().split('T')[0];
const previousDateStr = selectedDate ? selectedDate.toISOString().split('T')[0] : null;
trackDateChanged(dateStr, previousDateStr);
@@ -718,25 +747,9 @@ const StockOverview = () => {
fetchMarketStats(dateStr);
fetchTopConcepts(dateStr);
}}
- latestTradeDate={null}
minDate={tradingDays.length > 0 ? new Date(tradingDays[0]) : undefined}
maxDate={tradingDays.length > 0 ? new Date(tradingDays[tradingDays.length - 1]) : undefined}
- label="交易日期"
- isDarkMode={true}
/>
-
- {selectedDate && (
-
- 当前显示 {selectedDate.toISOString().split('T')[0]} 的市场数据
-
- )}
-
-
- {/* 热点概览 - 大盘走势 + 概念异动 */}
- {/* 只在 selectedDate 确定后渲染,避免 null → 日期 的双重请求 */}
-
- {selectedDate ? (
-
) : (