diff --git a/src/components/ConceptStocksModal/index.tsx b/src/components/ConceptStocksModal/index.tsx index 2541cd7d..671e172a 100644 --- a/src/components/ConceptStocksModal/index.tsx +++ b/src/components/ConceptStocksModal/index.tsx @@ -26,15 +26,22 @@ import { FaTable } from 'react-icons/fa'; import marketService from '@services/marketService'; import { logger } from '@utils/logger'; -// 股票信息类型 +// 股票信息类型 - 兼容新旧API格式 interface StockInfo { - stock_code: string; - stock_name: string; + stock_code?: string; + stock_name?: string; + code?: string; // 新API格式 + name?: string; // 新API格式 reason?: string; change_pct?: number; [key: string]: unknown; } +// 获取股票代码(兼容新旧API) +const getStockCode = (stock: StockInfo): string => stock.code || stock.stock_code || ''; +// 获取股票名称(兼容新旧API) +const getStockName = (stock: StockInfo): string => stock.name || stock.stock_name || '未知'; + // 概念信息类型 export interface ConceptInfo { concept_id?: string; @@ -69,9 +76,12 @@ const ConceptStocksModal: React.FC = ({ const [stockMarketData, setStockMarketData] = useState>({}); const [loadingStockData, setLoadingStockData] = useState(false); - // 颜色主题 - const cardBg = useColorModeValue('white', '#1a1a1a'); - const hoverBg = useColorModeValue('gray.50', '#2a2a2a'); + // 深色主题颜色 + const cardBg = 'rgba(15, 23, 42, 0.95)'; + const hoverBg = 'whiteAlpha.100'; + const textColor = 'white'; + const subTextColor = 'whiteAlpha.700'; + const borderColor = 'whiteAlpha.100'; // 响应式配置 - 添加 fallback 避免首次渲染时返回 undefined 导致弹窗异常 const isMobile = useBreakpointValue({ base: true, md: false }, { fallback: 'md' }); @@ -91,13 +101,14 @@ const ConceptStocksModal: React.FC = ({ for (let i = 0; i < stocks.length; i += batchSize) { const batch = stocks.slice(i, i + batchSize); const promises = batch.map(async (stock) => { - if (!stock.stock_code) return null; - const seccode = stock.stock_code.substring(0, 6); + const stockCode = getStockCode(stock); + if (!stockCode) return null; + const seccode = stockCode.substring(0, 6); try { const response = await marketService.getTradeData(seccode, 1); if (response.success && response.data?.length > 0) { const latestData = response.data[response.data.length - 1]; - return { stock_code: stock.stock_code, ...latestData }; + return { stock_code: stockCode, ...latestData }; } } catch (error) { logger.warn('ConceptStocksModal', '获取股票行情失败', { stockCode: seccode }); @@ -168,16 +179,18 @@ const ConceptStocksModal: React.FC = ({ - - - - - + + + + + {stocks.map((stock, idx) => { - const marketData = stockMarketData[stock.stock_code]; + const stockCode = getStockCode(stock); + const stockName = getStockName(stock); + const marketData = stockMarketData[stockCode]; const changePercent = marketData?.change_percent; return ( @@ -185,15 +198,15 @@ const ConceptStocksModal: React.FC = ({ key={idx} _hover={{ bg: hoverBg }} cursor="pointer" - onClick={() => handleStockClick(stock.stock_code)} + onClick={() => handleStockClick(stockCode)} > - - - + - diff --git a/src/views/Concept/ConceptTimelineModal.js b/src/views/Concept/ConceptTimelineModal.js index f002838a..63e8c0a4 100644 --- a/src/views/Concept/ConceptTimelineModal.js +++ b/src/views/Concept/ConceptTimelineModal.js @@ -608,10 +608,20 @@ const ConceptTimelineModal = ({ scrollBehavior="inside" isCentered > - - + + {conceptName} - 历史时间轴 - 最近100天 - - + 最近100天 + + 🔥 Max版功能 @@ -671,29 +680,29 @@ const ConceptTimelineModal = ({ {loading ? (
- - 正在加载时间轴数据... + + 正在加载时间轴数据...
) : timelineData.length > 0 ? ( @@ -715,83 +724,79 @@ const ConceptTimelineModal = ({ spacing={{ base: 1, md: 2 }} px={{ base: 2, md: 4 }} py={{ base: 1, md: 2 }} - bg="purple.50" + bg="whiteAlpha.100" borderRadius="lg" border="1px solid" - borderColor="purple.200" - boxShadow="sm" + borderColor="purple.500" flexShrink={0} > - 📰 新闻 + 📰 新闻 - 📊 研报 + 📊 研报 - - 上涨 + + 上涨 - - 下跌 + + 下跌 🔥 - 涨3%+ + 涨3%+ {/* FullCalendar 日历组件 */} - + 暂无历史数据 - + 该概念在最近100天内没有相关事件记录 @@ -941,45 +967,43 @@ const ConceptTimelineModal = ({ size="4xl" scrollBehavior="inside" > - - + + - + {formatDateDisplay(selectedDate)} {selectedDateData.price && ( {getPriceInfo(selectedDateData.price).icon && ( @@ -996,14 +1020,13 @@ const ConceptTimelineModal = ({ {selectedDateData.price.stock_count && ( - 📊 统计股票: - {selectedDateData.price.stock_count} 只 + 📊 统计股票: + {selectedDateData.price.stock_count} 只 )} @@ -1012,7 +1035,7 @@ const ConceptTimelineModal = ({ - + {selectedDateData.events && selectedDateData.events.length > 0 ? ( {/* 统计卡片 */} @@ -1020,35 +1043,33 @@ const ConceptTimelineModal = ({ - - + + {selectedDateData.events.filter(e => e.type === 'news').length} - 条新闻 + 条新闻 - - + + {selectedDateData.events.filter(e => e.type === 'report').length} - 篇研报 + 篇研报 @@ -1059,58 +1080,38 @@ const ConceptTimelineModal = ({ {event.type === 'news' ? '📰 新闻' : '📊 研报'} {event.publisher && ( {event.title} @@ -1156,7 +1157,7 @@ const ConceptTimelineModal = ({ @@ -1166,8 +1167,8 @@ const ConceptTimelineModal = ({ {event.time && ( - - + + {formatDateTime(event.time)} @@ -1225,24 +1226,24 @@ const ConceptTimelineModal = ({
- + 当日无新闻或研报 {selectedDateData.price && ( - + 仅有涨跌幅数据 )} @@ -1253,20 +1254,20 @@ const ConceptTimelineModal = ({ )} - @@ -1366,22 +1368,22 @@ const ConceptTimelineModal = ({ size="4xl" scrollBehavior="inside" > - - - + + + - {selectedNews?.title} - + {selectedNews?.title} + {selectedNews?.source && ( {selectedNews.source === 'zsxq' ? '知识星球' : selectedNews.source} )} {selectedNews?.time && ( - {formatDateTime(selectedNews.time)} + {formatDateTime(selectedNews.time)} )} @@ -1390,38 +1392,39 @@ const ConceptTimelineModal = ({ {selectedNews?.content || '暂无内容'} - + {/* zsxq来源不显示查看原文按钮 */} {selectedNews?.url && selectedNews?.source !== 'zsxq' && ( )} - diff --git a/src/views/Concept/components/ConceptStatsPanel.js b/src/views/Concept/components/ConceptStatsPanel.js index 68a93935..8c81a55a 100644 --- a/src/views/Concept/components/ConceptStatsPanel.js +++ b/src/views/Concept/components/ConceptStatsPanel.js @@ -73,9 +73,10 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { const [useCustomRange, setUseCustomRange] = useState(false); const toast = useToast(); - const bg = useColorModeValue('white', 'gray.800'); - const cardBg = useColorModeValue('gray.50', 'gray.700'); - const borderColor = useColorModeValue('gray.200', 'gray.600'); + // 深色主题颜色(固定使用深色模式) + const bg = 'rgba(15, 23, 42, 0.8)'; + const cardBg = 'rgba(15, 23, 42, 0.6)'; + const borderColor = 'whiteAlpha.100'; // 获取统计数据 const fetchStatsData = async (days = timeRange, startDate = null, endDate = null) => { @@ -250,21 +251,21 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { return 'gray.500'; }; - // 统计卡片组件 - 美化版 + // 统计卡片组件 - 深色主题版 const StatsCard = ({ title, icon, color, data, renderItem, isLoading }) => ( {isLoading ? ( {[1, 2, 3, 4, 5].map((i) => ( - + - + - - + + - + ))} @@ -275,15 +276,15 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { width: '4px', }, '&::-webkit-scrollbar-track': { - background: '#f1f1f1', + background: 'rgba(255,255,255,0.05)', borderRadius: '10px', }, '&::-webkit-scrollbar-thumb': { - background: '#c1c1c1', + background: 'rgba(255,255,255,0.2)', borderRadius: '10px', }, '&::-webkit-scrollbar-thumb:hover': { - background: '#a8a8a8', + background: 'rgba(255,255,255,0.3)', }, }} > @@ -309,14 +310,14 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { align="center" p={3} borderRadius="xl" - bg={index < 3 ? 'red.50' : 'gray.50'} + bg={index < 3 ? 'rgba(239, 68, 68, 0.15)' : 'whiteAlpha.50'} border="1px solid" - borderColor={index < 3 ? 'red.100' : 'gray.200'} + borderColor={index < 3 ? 'red.500' : 'whiteAlpha.100'} _hover={{ transform: 'translateY(-1px)', shadow: 'md', cursor: 'pointer', - bg: index < 3 ? 'red.100' : 'gray.100' + bg: index < 3 ? 'rgba(239, 68, 68, 0.25)' : 'whiteAlpha.100' }} transition="all 0.2s" onClick={() => onConceptClick?.(null, item.name)} @@ -324,8 +325,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { { position="absolute" top="-8px" right="-8px" - color="yellow.500" + color="yellow.400" boxSize={3} /> )} - + {item.name} - + {item.stock_count}股 @@ -367,8 +368,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { { align="center" p={3} borderRadius="xl" - bg={index < 3 ? 'green.50' : 'gray.50'} + bg={index < 3 ? 'rgba(34, 197, 94, 0.15)' : 'whiteAlpha.50'} border="1px solid" - borderColor={index < 3 ? 'green.100' : 'gray.200'} + borderColor={index < 3 ? 'green.500' : 'whiteAlpha.100'} _hover={{ transform: 'translateY(-1px)', shadow: 'md', cursor: 'pointer', - bg: index < 3 ? 'green.100' : 'gray.100' + bg: index < 3 ? 'rgba(34, 197, 94, 0.25)' : 'whiteAlpha.100' }} transition="all 0.2s" onClick={() => onConceptClick?.(null, item.name)} > { {index + 1} - + {item.name} - + {item.stock_count}股 @@ -438,8 +439,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { { align="center" p={3} borderRadius="xl" - bg={index < 3 ? 'orange.50' : 'gray.50'} + bg={index < 3 ? 'rgba(251, 146, 60, 0.15)' : 'whiteAlpha.50'} border="1px solid" - borderColor={index < 3 ? 'orange.100' : 'gray.200'} + borderColor={index < 3 ? 'orange.500' : 'whiteAlpha.100'} _hover={{ transform: 'translateY(-1px)', shadow: 'md', cursor: 'pointer', - bg: index < 3 ? 'orange.100' : 'gray.100' + bg: index < 3 ? 'rgba(251, 146, 60, 0.25)' : 'whiteAlpha.100' }} transition="all 0.2s" onClick={() => onConceptClick?.(null, item.name)} @@ -478,8 +479,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { { position="absolute" top="-8px" right="-8px" - color="orange.500" + color="orange.400" boxSize={3} /> )} - + {item.name} - + {item.news_count} @@ -521,8 +522,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { { align="center" p={3} borderRadius="xl" - bg={index < 3 ? 'purple.50' : 'gray.50'} + bg={index < 3 ? 'rgba(168, 85, 247, 0.15)' : 'whiteAlpha.50'} border="1px solid" - borderColor={index < 3 ? 'purple.100' : 'gray.200'} + borderColor={index < 3 ? 'purple.500' : 'whiteAlpha.100'} _hover={{ transform: 'translateY(-1px)', shadow: 'md', cursor: 'pointer', - bg: index < 3 ? 'purple.100' : 'gray.100' + bg: index < 3 ? 'rgba(168, 85, 247, 0.25)' : 'whiteAlpha.100' }} transition="all 0.2s" onClick={() => onConceptClick?.(null, item.name)} @@ -561,8 +562,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { { position="absolute" top="-8px" right="-8px" - color="purple.500" + color="purple.400" boxSize={3} /> )} - + {item.name} - + 均幅 {formatChange(item.avg_change)} { align="center" p={3} borderRadius="xl" - bg={index < 3 ? 'cyan.50' : 'gray.50'} + bg={index < 3 ? 'rgba(34, 211, 238, 0.15)' : 'whiteAlpha.50'} border="1px solid" - borderColor={index < 3 ? 'cyan.100' : 'gray.200'} + borderColor={index < 3 ? 'cyan.500' : 'whiteAlpha.100'} _hover={{ transform: 'translateY(-1px)', shadow: 'md', cursor: 'pointer', - bg: index < 3 ? 'cyan.100' : 'gray.100' + bg: index < 3 ? 'rgba(34, 211, 238, 0.25)' : 'whiteAlpha.100' }} transition="all 0.2s" onClick={() => onConceptClick?.(null, item.name)} @@ -636,8 +637,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { { position="absolute" top="-8px" right="-8px" - color="cyan.500" + color="cyan.400" boxSize={3} /> )} - + {item.name} - + 累计 {formatChange(item.total_change)} { return ( - {/* 顶部标题卡片 */} + {/* 顶部标题卡片 - 深色玻璃态 */} {/* 背景装饰 */} { width="80px" height="80px" borderRadius="full" - bg="whiteAlpha.200" - filter="blur(10px)" + bg="purple.500" + opacity={0.2} + filter="blur(20px)" /> { width="60px" height="60px" borderRadius="full" - bg="whiteAlpha.100" - filter="blur(8px)" + bg="cyan.500" + opacity={0.15} + filter="blur(15px)" /> - - + + @@ -868,8 +874,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { - {/* 主内容卡片 */} - + {/* 主内容卡片 - 深色玻璃态 */} + { @@ -882,7 +888,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { size="sm" > { px={3} py={3} whiteSpace="nowrap" + color="whiteAlpha.700" _selected={{ bg: `${tab.color}.500`, color: 'white', @@ -917,7 +924,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => { bg: `${tab.color}.500`, } }} - _hover={{ bg: `${tab.color}.50` }} + _hover={{ bg: 'whiteAlpha.100', color: 'white' }} transition="all 0.2s" >
股票名称股票代码现价当日涨跌幅板块原因股票名称股票代码现价当日涨跌幅板块原因
- {stock.stock_name} + + {stockName} {stock.stock_code} + {stockCode} {loadingStockData ? ( - + ) : marketData?.close ? ( `¥${marketData.close.toFixed(2)}` ) : ( @@ -203,23 +216,24 @@ const ConceptStocksModal: React.FC = ({ 0 - ? 'red.500' + ? 'red.400' : changePercent && changePercent < 0 - ? 'green.500' - : 'gray.500' + ? 'green.400' + : 'whiteAlpha.500' } > {loadingStockData ? ( - + ) : changePercent !== undefined ? ( `${changePercent > 0 ? '+' : ''}${changePercent.toFixed(2)}%` ) : ( '-' )} + {stock.reason || '-'}