// src/views/Community/components/DynamicNewsDetail/StockListItem.js // 股票卡片组件(融合表格功能的卡片样式) import React, { useState } from 'react'; import { Box, Flex, VStack, SimpleGrid, Text, Button, IconButton, Collapse, useColorModeValue, } from '@chakra-ui/react'; import { StarIcon } from '@chakra-ui/icons'; import MiniTimelineChart from '../StockDetailPanel/components/MiniTimelineChart'; import MiniKLineChart from './MiniKLineChart'; import StockChartModal from '../../../../components/StockChart/StockChartModal'; /** * 股票卡片组件 * @param {Object} props * @param {Object} props.stock - 股票对象 * @param {string} props.stock.stock_name - 股票名称 * @param {string} props.stock.stock_code - 股票代码 * @param {string} props.stock.relation_desc - 关联描述 * @param {Object} props.quote - 股票行情数据(可选) * @param {number} props.quote.change - 涨跌幅 * @param {string} props.eventTime - 事件时间(可选) * @param {boolean} props.isInWatchlist - 是否在自选股中 * @param {Function} props.onWatchlistToggle - 切换自选股回调 */ const StockListItem = ({ stock, quote = null, eventTime = null, isInWatchlist = false, onWatchlistToggle }) => { const cardBg = useColorModeValue('white', 'gray.800'); const borderColor = useColorModeValue('gray.200', 'gray.700'); const codeColor = useColorModeValue('blue.600', 'blue.300'); const nameColor = useColorModeValue('gray.700', 'gray.300'); const descColor = useColorModeValue('gray.600', 'gray.400'); const dividerColor = useColorModeValue('gray.200', 'gray.600'); const [isDescExpanded, setIsDescExpanded] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false); const handleViewDetail = () => { const stockCode = stock.stock_code.split('.')[0]; window.open(`https://valuefrontier.cn/company?scode=${stockCode}`, '_blank'); }; const handleWatchlistClick = (e) => { e.stopPropagation(); onWatchlistToggle?.(stock.stock_code, isInWatchlist); }; // 格式化涨跌幅显示 const formatChange = (value) => { if (value === null || value === undefined || isNaN(value)) return '--'; const prefix = value > 0 ? '+' : ''; return `${prefix}${parseFloat(value).toFixed(2)}%`; }; // 获取涨跌幅颜色 const getChangeColor = (value) => { const num = parseFloat(value); if (isNaN(num) || num === 0) return 'gray.500'; return num > 0 ? 'red.500' : 'green.500'; }; // 获取涨跌幅数据(优先使用 quote,fallback 到 stock) const change = quote?.change ?? stock.daily_change ?? null; // 处理关联描述 const getRelationDesc = () => { const relationDesc = stock.relation_desc; if (!relationDesc) return '--'; if (typeof relationDesc === 'string') { return relationDesc; } else if (typeof relationDesc === 'object' && relationDesc.data && Array.isArray(relationDesc.data)) { // 新格式:{data: [{query_part: "...", sentences: "..."}]} return relationDesc.data .map(item => item.query_part || item.sentences || '') .filter(s => s) .join(';') || '--'; } return '--'; }; const relationText = getRelationDesc(); const maxLength = 50; // 收缩时显示的最大字符数 const needTruncate = relationText && relationText !== '--' && relationText.length > maxLength; return ( <> {/* 顶部:股票代码 + 名称 + 操作按钮(上下两行布局) */} {/* 第一行:股票代码 + 涨跌幅 + 操作按钮 */} {/* 左侧:代码 + 涨跌幅 */} {stock.stock_code} {formatChange(change)} {/* 右侧:操作按钮 */} {onWatchlistToggle && ( } onClick={handleWatchlistClick} aria-label={isInWatchlist ? '已关注' : '加自选'} title={isInWatchlist ? '已关注' : '加自选'} /> )} {/* 第二行:公司名称(彩色高亮) */} {stock.stock_name} {/* 分隔线 */} {/* 分时图 & K线图 - 左右布局 */} {/* 左侧:分时图 */} e.stopPropagation()}> 分时图 setIsModalOpen(true)} /> {/* 右侧:K线图 */} e.stopPropagation()}> 日K线 setIsModalOpen(true)} /> {/* 分隔线 */} {/* 关联描述 */} {relationText && relationText !== '--' && ( 关联描述: { if (needTruncate) { e.stopPropagation(); setIsDescExpanded(!isDescExpanded); } }} _hover={needTruncate ? { opacity: 0.8 } : {}} > {relationText} {needTruncate && ( )} {/* 合规提示 */} ⚠️ 以上关联描述由AI生成,仅供参考,不构成投资建议 )} {/* 股票详情弹窗 */} setIsModalOpen(false)} stock={stock} eventTime={eventTime} size="6xl" /> ); }; export default StockListItem;