// src/views/Community/components/DynamicNewsDetail/DynamicNewsDetailPanel.js
// 动态新闻详情面板主组件(组装所有子组件)
import React, { useState, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
Card,
CardBody,
VStack,
Text,
Spinner,
Center,
useColorModeValue,
useToast,
} from '@chakra-ui/react';
import { getImportanceConfig } from '../../../../constants/importanceLevels';
import { eventService } from '../../../../services/eventService';
import { useEventStocks } from '../StockDetailPanel/hooks/useEventStocks';
import { toggleEventFollow, selectEventFollowStatus } from '../../../../store/slices/communityDataSlice';
import EventHeaderInfo from './EventHeaderInfo';
import EventDescriptionSection from './EventDescriptionSection';
import RelatedConceptsSection from './RelatedConceptsSection';
import RelatedStocksSection from './RelatedStocksSection';
import CollapsibleSection from './CollapsibleSection';
import HistoricalEvents from '../../../EventDetail/components/HistoricalEvents';
import TransmissionChainAnalysis from '../../../EventDetail/components/TransmissionChainAnalysis';
/**
* 动态新闻详情面板主组件
* @param {Object} props
* @param {Object} props.event - 事件对象(包含详情数据)
*/
const DynamicNewsDetailPanel = ({ event }) => {
const dispatch = useDispatch();
const cardBg = useColorModeValue('white', 'gray.800');
const borderColor = useColorModeValue('gray.200', 'gray.700');
const textColor = useColorModeValue('gray.600', 'gray.400');
const toast = useToast();
// 从 Redux 读取关注状态
const eventFollowStatus = useSelector(selectEventFollowStatus);
const isFollowing = event?.id ? (eventFollowStatus[event.id]?.isFollowing || false) : false;
const followerCount = event?.id ? (eventFollowStatus[event.id]?.followerCount || event.follower_count || 0) : 0;
// 使用 Hook 获取实时数据
const {
stocks,
quotes,
eventDetail,
historicalEvents,
expectationScore,
loading
} = useEventStocks(event?.id, event?.created_at);
// 折叠状态管理
const [isStocksOpen, setIsStocksOpen] = useState(true);
const [isHistoricalOpen, setIsHistoricalOpen] = useState(true);
const [isTransmissionOpen, setIsTransmissionOpen] = useState(false);
// 自选股管理(使用 localStorage)
const [watchlistSet, setWatchlistSet] = useState(() => {
try {
const saved = localStorage.getItem('stock_watchlist');
return saved ? new Set(JSON.parse(saved)) : new Set();
} catch {
return new Set();
}
});
// 切换关注状态
const handleToggleFollow = useCallback(async () => {
if (!event?.id) return;
dispatch(toggleEventFollow(event.id));
}, [dispatch, event?.id]);
// 切换自选股
const handleWatchlistToggle = useCallback(async (stockCode, isInWatchlist) => {
try {
const newWatchlist = new Set(watchlistSet);
if (isInWatchlist) {
newWatchlist.delete(stockCode);
toast({
title: '已移除自选股',
status: 'info',
duration: 2000,
isClosable: true,
});
} else {
newWatchlist.add(stockCode);
toast({
title: '已添加至自选股',
status: 'success',
duration: 2000,
isClosable: true,
});
}
setWatchlistSet(newWatchlist);
localStorage.setItem('stock_watchlist', JSON.stringify(Array.from(newWatchlist)));
} catch (error) {
console.error('切换自选股失败:', error);
toast({
title: '操作失败',
description: error.message,
status: 'error',
duration: 3000,
isClosable: true,
});
}
}, [watchlistSet, toast]);
// 空状态
if (!event) {
return (
请选择一个事件查看详情
);
}
const importance = getImportanceConfig(event.importance);
return (
{/* 头部信息区 */}
{/* 事件描述 */}
{/* 相关概念 */}
{/* 相关股票(可折叠) */}
{loading.stocks || loading.quotes ? (
加载股票数据中...
) : (
setIsStocksOpen(!isStocksOpen)}
onWatchlistToggle={handleWatchlistToggle}
/>
)}
{/* 历史事件对比(可折叠) */}
setIsHistoricalOpen(!isHistoricalOpen)}
count={historicalEvents?.length || 0}
>
{loading.historicalEvents ? (
加载历史事件...
) : (
)}
{/* 传导链分析(可折叠) */}
setIsTransmissionOpen(!isTransmissionOpen)}
>
);
};
export default DynamicNewsDetailPanel;