// src/components/EventDetailPanel/RelatedConceptsSection/DetailedConceptCard.js // 详细概念卡片组件 import React from 'react'; import { Box, HStack, VStack, Text, Badge, Card, CardBody, Divider, SimpleGrid, useColorModeValue, } from '@chakra-ui/react'; import ConceptStockItem from './ConceptStockItem'; /** * 详细概念卡片组件 * @param {Object} props * @param {Object} props.concept - 概念对象(兼容 v1/v2 API) * - concept: 概念名称 * - stock_count: 相关股票数量 * - score: 相关度(0-1) * - price_info.avg_change_pct: 平均涨跌幅 * - description: 概念描述 * - outbreak_dates / happened_times: 爆发日期数组 * - stocks: 相关股票数组 [{ name/stock_name, code/stock_code }] * @param {Function} props.onClick - 点击回调 */ const DetailedConceptCard = ({ concept, onClick }) => { const cardBg = useColorModeValue('white', 'gray.700'); const borderColor = useColorModeValue('gray.200', 'gray.600'); const headingColor = useColorModeValue('gray.700', 'gray.200'); const stockCountColor = useColorModeValue('gray.500', 'gray.400'); // 计算相关度百分比 const relevanceScore = Math.round((concept.score || 0) * 100); // 计算涨跌幅颜色 const changePct = parseFloat(concept.price_info?.avg_change_pct); const changeColor = changePct > 0 ? 'red' : changePct < 0 ? 'green' : 'gray'; const changeSymbol = changePct > 0 ? '+' : ''; return ( onClick(concept)} > {/* 头部信息 */} {/* 左侧:概念名称 + Badge */} {concept.concept} 相关度: {relevanceScore}% {concept.stock_count} 只股票 {/* 右侧:涨跌幅 */} {concept.price_info?.avg_change_pct && ( 平均涨跌幅 {changeSymbol}{changePct.toFixed(2)}% )} {/* 概念描述 */} {concept.description && ( {concept.description} )} {/* 爆发日期(兼容 happened_times 和 outbreak_dates) */} {((concept.outbreak_dates && concept.outbreak_dates.length > 0) || (concept.happened_times && concept.happened_times.length > 0)) && ( 爆发日期: {(concept.outbreak_dates || concept.happened_times).map((date, idx) => ( {date} ))} )} {/* 核心相关股票 */} {concept.stocks && concept.stocks.length > 0 && ( 核心相关股票 共 {concept.stock_count} 只 {/* 可滚动容器 - 默认显示4条,可滚动查看全部 */} { const element = e.currentTarget; const scrollTop = element.scrollTop; const scrollHeight = element.scrollHeight; const clientHeight = element.clientHeight; // 如果在滚动范围内,阻止事件冒泡到父容器 if ( (e.deltaY < 0 && scrollTop > 0) || // 向上滚动且未到顶部 (e.deltaY > 0 && scrollTop + clientHeight < scrollHeight) // 向下滚动且未到底部 ) { e.stopPropagation(); } }} css={{ overscrollBehavior: 'contain', // 防止滚动链 '&::-webkit-scrollbar': { width: '6px', }, '&::-webkit-scrollbar-track': { background: '#f1f1f1', }, '&::-webkit-scrollbar-thumb': { background: '#888', borderRadius: '3px', }, '&::-webkit-scrollbar-thumb:hover': { background: '#555', }, }} > {concept.stocks.map((stock, idx) => ( ))} )} ); }; export default DetailedConceptCard;