diff --git a/src/views/Community/components/HeroPanel.js b/src/views/Community/components/HeroPanel.js index c8dca173..cb82d09b 100644 --- a/src/views/Community/components/HeroPanel.js +++ b/src/views/Community/components/HeroPanel.js @@ -418,7 +418,9 @@ const DetailModal = ({ isOpen, onClose, selectedDate, ztDetail, events, loading const [detailDrawerVisible, setDetailDrawerVisible] = useState(false); const [selectedContent, setSelectedContent] = useState(null); const [ztViewMode, setZtViewMode] = useState('sector'); // 'sector' | 'stock' - const [expandedSectors, setExpandedSectors] = useState({}); // 跟踪展开的板块 + const [sectorStocksModalVisible, setSectorStocksModalVisible] = useState(false); // 板块股票弹窗 + const [selectedSectorInfo, setSelectedSectorInfo] = useState(null); // 选中的板块信息 + const [selectedSectorFilter, setSelectedSectorFilter] = useState(null); // 按个股视图的板块筛选 const [stocksDrawerVisible, setStocksDrawerVisible] = useState(false); const [selectedEventStocks, setSelectedEventStocks] = useState([]); const [selectedEventTime, setSelectedEventTime] = useState(null); @@ -464,6 +466,16 @@ const DetailModal = ({ isOpen, onClose, selectedDate, ztDetail, events, loading .sort((a, b) => b._continuousDays - a._continuousDays); // 降序排列 }, [ztDetail]); + // 筛选后的股票列表(按板块筛选) + const filteredStockList = useMemo(() => { + if (!selectedSectorFilter) return stockList; + // 根据选中板块筛选 + const sectorData = ztDetail?.sector_data?.[selectedSectorFilter]; + if (!sectorData?.stock_codes) return stockList; + const sectorStockCodes = new Set(sectorData.stock_codes); + return stockList.filter(stock => sectorStockCodes.has(stock.scode)); + }, [stockList, selectedSectorFilter, ztDetail]); + // 热门关键词 const hotKeywords = useMemo(() => { if (!ztDetail?.word_freq_data) return []; @@ -956,89 +968,99 @@ const DetailModal = ({ isOpen, onClose, selectedDate, ztDetail, events, loading dataIndex: 'stocks', key: 'stocks', render: (stocks, record) => { - // 根据股票代码查找股票详情 - const getStockInfo = (code) => { - const stockInfo = stockList.find(s => s.scode === code); - return stockInfo || { sname: code, scode: code }; + // 根据股票代码查找股票详情,并按连板天数排序 + const getStockInfoList = () => { + return stocks + .map(code => { + const stockInfo = stockList.find(s => s.scode === code); + return stockInfo || { sname: code, scode: code, _continuousDays: 1 }; + }) + .sort((a, b) => (b._continuousDays || 1) - (a._continuousDays || 1)); }; - const sectorName = record.name; - const isExpanded = expandedSectors[sectorName]; - const displayStocks = isExpanded ? stocks : stocks.slice(0, 5); - const hasMore = stocks.length > 5; + const stockInfoList = getStockInfoList(); + const displayStocks = stockInfoList.slice(0, 4); - const toggleExpand = (e) => { + const handleShowAll = (e) => { e.stopPropagation(); - setExpandedSectors(prev => ({ - ...prev, - [sectorName]: !prev[sectorName] - })); + setSelectedSectorInfo({ + name: record.name, + count: record.count, + stocks: stockInfoList, + }); + setSectorStocksModalVisible(true); }; return ( - - - {displayStocks.map((code) => { - const info = getStockInfo(code); - return ( - -
{info.sname}
-
{code}
- {info.core_sectors && ( -
- {info.core_sectors.slice(0, 2).join(' · ')} -
- )} - {info.continuous_days && ( -
- {info.continuous_days} -
- )} - - } - placement="top" + + {displayStocks.map((info) => ( + +
{info.sname}
+
{info.scode}
+ {info.continuous_days && ( +
+ {info.continuous_days} +
+ )} + + } + placement="top" + > + = 3 + ? 'rgba(255, 77, 79, 0.2)' + : info._continuousDays >= 2 + ? 'rgba(250, 140, 22, 0.2)' + : 'rgba(59, 130, 246, 0.15)', + border: info._continuousDays >= 3 + ? '1px solid rgba(255, 77, 79, 0.4)' + : info._continuousDays >= 2 + ? '1px solid rgba(250, 140, 22, 0.4)' + : '1px solid rgba(59, 130, 246, 0.3)', + borderRadius: '6px', + }} + > + = 3 ? '#ff4d4f' : info._continuousDays >= 2 ? '#fa8c16' : '#60A5FA', + fontSize: '13px' + }} > - - - {info.sname} - - -
- ); - })} -
- {hasMore && ( + {info.sname} + {info._continuousDays > 1 && ( + + ({info._continuousDays}板) + + )} + + +
+ ))} + {stocks.length > 4 && ( )} -
+ ); }, }, @@ -1702,20 +1724,97 @@ const DetailModal = ({ isOpen, onClose, selectedDate, ztDetail, events, loading {/* 个股视图 */} {ztViewMode === 'stock' && ( - - - + + {/* 板块筛选器 */} + + + 板块筛选: + setSelectedSectorFilter(null)} + transition="all 0.2s" + _hover={{ bg: 'rgba(255,215,0,0.15)' }} + > + 全部 ({stockList.length}) + + + + {sectorList.slice(0, 10).map((sector) => ( + setSelectedSectorFilter( + selectedSectorFilter === sector.name ? null : sector.name + )} + transition="all 0.2s" + _hover={{ bg: 'rgba(59,130,246,0.1)' }} + > + {sector.name} ({sector.count}) + + ))} + + + + {/* 筛选结果提示 */} + {selectedSectorFilter && ( + + + + 当前筛选:{selectedSectorFilter} + + + 共 {filteredStockList.length} 只 + + + + )} + + +
+ + )} ) : ( @@ -1885,6 +1984,285 @@ const DetailModal = ({ isOpen, onClose, selectedDate, ztDetail, events, loading size="5xl" /> )} + + {/* 板块股票弹窗 */} + { + setSectorStocksModalVisible(false); + setSelectedSectorInfo(null); + }} + size="4xl" + scrollBehavior="inside" + > + + + + + + + + + + + {selectedSectorInfo?.name} + + + {selectedSectorInfo?.count} 只涨停 + + + + 按连板天数降序排列 + + + + + + + {selectedSectorInfo?.stocks?.length > 0 ? ( + + {/* 快速统计 */} + + {(() => { + const stats = { '首板': 0, '2连板': 0, '3连板': 0, '4连板+': 0 }; + selectedSectorInfo.stocks.forEach(s => { + const days = s._continuousDays || 1; + if (days === 1) stats['首板']++; + else if (days === 2) stats['2连板']++; + else if (days === 3) stats['3连板']++; + else stats['4连板+']++; + }); + return Object.entries(stats).map(([key, value]) => ( + value > 0 && ( + + + {key}: {value} + + + ) + )); + })()} + + + {/* 股票列表 */} + +
( + + + {record.sname} + + {record.scode} + + ), + }, + { + title: '连板', + dataIndex: 'continuous_days', + key: 'continuous', + width: 90, + align: 'center', + render: (text, record) => { + const days = record._continuousDays || 1; + const getDaysStyle = (d) => { + if (d >= 5) return { bg: 'linear-gradient(135deg, #ff4d4f 0%, #ff7875 100%)', text: '#fff' }; + if (d >= 3) return { bg: 'linear-gradient(135deg, #fa541c 0%, #ff7a45 100%)', text: '#fff' }; + if (d >= 2) return { bg: 'linear-gradient(135deg, #fa8c16 0%, #ffc53d 100%)', text: '#fff' }; + return { bg: 'rgba(255,255,255,0.1)', text: '#888' }; + }; + const style = getDaysStyle(days); + return ( + + {text || '首板'} + + ); + }, + }, + { + title: '涨停时间', + dataIndex: 'formatted_time', + key: 'time', + width: 90, + align: 'center', + render: (time) => { + const getTimeStyle = (t) => { + if (t <= '09:30:00') return { bg: '#ff4d4f', text: '#fff' }; + if (t <= '09:35:00') return { bg: '#fa541c', text: '#fff' }; + if (t <= '10:00:00') return { bg: '#fa8c16', text: '#fff' }; + return { bg: 'rgba(255,255,255,0.1)', text: '#888' }; + }; + const style = getTimeStyle(time || '15:00:00'); + return ( + + {time?.substring(0, 5) || '-'} + + ); + }, + }, + { + title: '核心板块', + dataIndex: 'core_sectors', + key: 'sectors', + render: (sectors) => ( + + {(sectors || []).slice(0, 2).map((sector, idx) => ( + + {sector} + + ))} + + ), + }, + { + title: 'K线图', + key: 'kline', + width: 80, + align: 'center', + render: (_, record) => ( + + ), + }, + { + title: '操作', + key: 'action', + width: 90, + align: 'center', + render: (_, record) => { + const code = record.scode; + const inWatchlist = isStockInWatchlist(code); + return ( + + ); + }, + }, + ]} + rowKey="scode" + size="small" + pagination={false} + scroll={{ y: 400 }} + /> + + + ) : ( +
+ 暂无股票数据 +
+ )} + + + ); };