// src/views/Community/components/StockDetailPanel.js import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react'; import { Drawer, Spin, Button, Alert } from 'antd'; import { CloseOutlined, LockOutlined, CrownOutlined } from '@ant-design/icons'; import { Tabs as AntdTabs } from 'antd'; import moment from 'moment'; // Services and Utils import { eventService } from '../../../services/eventService'; import { logger } from '../../../utils/logger'; import { getApiBase } from '../../../utils/apiConfig'; // Custom Hooks import { useSubscription } from '../../../hooks/useSubscription'; import { useEventStocks } from './StockDetailPanel/hooks/useEventStocks'; import { useWatchlist } from './StockDetailPanel/hooks/useWatchlist'; import { useStockMonitoring } from './StockDetailPanel/hooks/useStockMonitoring'; // Components import { RelatedStocksTab, LockedContent } from './StockDetailPanel/components'; import RelatedConcepts from '../../EventDetail/components/RelatedConcepts'; import HistoricalEvents from '../../EventDetail/components/HistoricalEvents'; import TransmissionChainAnalysis from '../../EventDetail/components/TransmissionChainAnalysis'; import EventDiscussionModal from './EventDiscussionModal'; import SubscriptionUpgradeModal from '../../../components/SubscriptionUpgradeModal'; import StockChartAntdModal from '../../../components/StockChart/StockChartAntdModal'; import RiskDisclaimer from '../../../components/RiskDisclaimer'; // Styles import './StockDetailPanel.css'; /** * 股票详情 Drawer 组件 * 显示事件相关的股票、概念、历史事件、传导链等信息 * * @param {boolean} visible - 是否显示 * @param {Object} event - 事件对象 * @param {Function} onClose - 关闭回调 */ function StockDetailPanel({ visible, event, onClose }) { logger.debug('StockDetailPanel', '组件加载', { visible, eventId: event?.id, eventTitle: event?.title }); // ==================== Hooks ==================== // 权限控制 const { hasFeatureAccess, getUpgradeRecommendation } = useSubscription(); // 事件数据管理 (Redux + Hooks) const { stocks, stocksWithQuotes, quotes, eventDetail, historicalEvents, chainAnalysis, expectationScore, loading, refreshAllData, refreshQuotes } = useEventStocks(event?.id, event?.start_time); // 自选股管理(只在 Drawer 可见时加载) const { watchlistSet, toggleWatchlist } = useWatchlist(visible); // 实时监控管理 const { isMonitoring, toggleMonitoring, manualRefresh: refreshMonitoring } = useStockMonitoring(stocks, event?.start_time); // ==================== Local State ==================== const [activeTab, setActiveTab] = useState('stocks'); const [searchText, setSearchText] = useState(''); const [filteredStocks, setFilteredStocks] = useState([]); const [fixedCharts, setFixedCharts] = useState([]); const [discussionModalVisible, setDiscussionModalVisible] = useState(false); const [discussionType, setDiscussionType] = useState('事件讨论'); const [upgradeModalOpen, setUpgradeModalOpen] = useState(false); const [upgradeFeature, setUpgradeFeature] = useState(''); // ==================== Effects ==================== // 过滤股票列表 useEffect(() => { if (!searchText.trim()) { setFilteredStocks(stocks); } else { const filtered = stocks.filter(stock => stock.stock_code.toLowerCase().includes(searchText.toLowerCase()) || stock.stock_name.toLowerCase().includes(searchText.toLowerCase()) ); setFilteredStocks(filtered); } }, [searchText, stocks]); // ==================== Event Handlers ==================== // 搜索处理 const handleSearch = useCallback((value) => { setSearchText(value); }, []); // 刷新数据 const handleRefresh = useCallback(() => { logger.debug('StockDetailPanel', '手动刷新数据'); refreshAllData(); refreshQuotes(); }, [refreshAllData, refreshQuotes]); // 切换监控 const handleMonitoringToggle = useCallback(() => { toggleMonitoring(); }, [toggleMonitoring]); // 自选股切换 const handleWatchlistToggle = useCallback(async (stockCode, isInWatchlist) => { const stockName = stocks.find(s => s.stock_code === stockCode)?.stock_name || ''; await toggleWatchlist(stockCode, stockName); }, [stocks, toggleWatchlist]); // 行点击 - 显示固定图表 const handleRowClick = useCallback((stock) => { setFixedCharts((prev) => { if (prev.find(item => item.stock.stock_code === stock.stock_code)) return prev; return [...prev, { stock, chartType: 'timeline' }]; }); }, []); // 移除固定图表 const handleUnfixChart = useCallback((stock) => { setFixedCharts((prev) => prev.filter(item => item.stock.stock_code !== stock.stock_code)); }, []); // 权限检查和升级提示 const handleUpgradeClick = useCallback((featureName) => { const recommendation = getUpgradeRecommendation(featureName); setUpgradeFeature(recommendation?.required || 'pro'); setUpgradeModalOpen(true); }, [getUpgradeRecommendation]); // 渲染锁定内容 const renderLockedContent = useCallback((featureName, description) => { const recommendation = getUpgradeRecommendation(featureName); const isProRequired = recommendation?.required === 'pro'; return ( handleUpgradeClick(featureName)} /> ); }, [getUpgradeRecommendation, handleUpgradeClick]); // 渲染固定图表 const renderFixedCharts = useMemo(() => { if (fixedCharts.length === 0) return null; const formattedEventTime = event?.start_time ? moment(event.start_time).format('YYYY-MM-DD HH:mm') : undefined; return fixedCharts.map(({ stock }, index) => (
handleUnfixChart(stock)} stock={stock} eventTime={formattedEventTime} fixed={true} width={800} />
)); }, [fixedCharts, event, handleUnfixChart]); // ==================== Tab Items ==================== const tabItems = useMemo(() => [ { key: 'stocks', label: ( 相关标的 {!hasFeatureAccess('related_stocks') && ( )} ), children: hasFeatureAccess('related_stocks') ? ( { setDiscussionType('事件讨论'); setDiscussionModalVisible(true); }} fixedChartsContent={renderFixedCharts} /> ) : renderLockedContent('related_stocks', '相关标的') }, { key: 'concepts', label: ( 相关概念 {!hasFeatureAccess('related_concepts') && ( )} ), children: hasFeatureAccess('related_concepts') ? ( ) : renderLockedContent('related_concepts', '相关概念') }, { key: 'historical', label: ( 历史事件对比 {!hasFeatureAccess('historical_events_full') && ( )} ), children: hasFeatureAccess('historical_events_full') ? ( ) : renderLockedContent('historical_events_full', '历史事件对比') }, { key: 'chain', label: ( 传导链分析 {!hasFeatureAccess('transmission_chain') && ( )} ), children: hasFeatureAccess('transmission_chain') ? ( ) : renderLockedContent('transmission_chain', '传导链分析') } ], [ hasFeatureAccess, filteredStocks, quotes, event, watchlistSet, searchText, loading, isMonitoring, eventDetail, historicalEvents, handleSearch, handleRefresh, handleMonitoringToggle, handleWatchlistToggle, handleRowClick, renderFixedCharts, renderLockedContent ]); // ==================== Render ==================== return ( <> {event?.title} } placement="right" width={900} open={visible} onClose={onClose} closable={false} className="stock-detail-panel" > {/* 风险提示 */}
{/* 事件讨论模态框 */} setDiscussionModalVisible(false)} eventId={event?.id} eventTitle={event?.title} discussionType={discussionType} /> {/* 订阅升级模态框 */} setUpgradeModalOpen(false)} requiredLevel={upgradeFeature} featureName={upgradeFeature === 'pro' ? '相关分析功能' : '传导链分析'} /> ); } export default StockDetailPanel;