feat: 添加合规
This commit is contained in:
@@ -149,11 +149,34 @@ const HistoricalEvents = ({
|
||||
return `${Math.floor(diffDays / 365)}年前`;
|
||||
};
|
||||
|
||||
// 处理关联描述字段的辅助函数
|
||||
const getRelationDesc = (relationDesc) => {
|
||||
// 处理空值
|
||||
if (!relationDesc) return '';
|
||||
|
||||
// 如果是字符串,直接返回
|
||||
if (typeof relationDesc === 'string') {
|
||||
return relationDesc;
|
||||
}
|
||||
|
||||
// 如果是对象且包含data数组
|
||||
if (typeof relationDesc === 'object' && relationDesc.data && Array.isArray(relationDesc.data)) {
|
||||
const firstItem = relationDesc.data[0];
|
||||
if (firstItem) {
|
||||
// 优先使用 query_part,其次使用 sentences
|
||||
return firstItem.query_part || firstItem.sentences || '';
|
||||
}
|
||||
}
|
||||
|
||||
// 其他情况返回空字符串
|
||||
return '';
|
||||
};
|
||||
|
||||
// 可展开的文本组件
|
||||
const ExpandableText = ({ text, maxLength = 20 }) => {
|
||||
const { isOpen, onToggle } = useDisclosure();
|
||||
const [shouldTruncate, setShouldTruncate] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (text && text.length > maxLength) {
|
||||
setShouldTruncate(true);
|
||||
@@ -161,22 +184,22 @@ const HistoricalEvents = ({
|
||||
setShouldTruncate(false);
|
||||
}
|
||||
}, [text, maxLength]);
|
||||
|
||||
|
||||
if (!text) return <Text fontSize="xs">--</Text>;
|
||||
|
||||
const displayText = shouldTruncate && !isOpen
|
||||
? text.substring(0, maxLength) + '...'
|
||||
|
||||
const displayText = shouldTruncate && !isOpen
|
||||
? text.substring(0, maxLength) + '...'
|
||||
: text;
|
||||
|
||||
|
||||
return (
|
||||
<VStack align="flex-start" spacing={1}>
|
||||
<Text fontSize="xs" noOfLines={isOpen ? undefined : 2} maxW="300px">
|
||||
{displayText}{text.includes('AI合成') ? '' : '(AI合成)'}
|
||||
</Text>
|
||||
{shouldTruncate && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant="link"
|
||||
<Button
|
||||
size="xs"
|
||||
variant="link"
|
||||
color="blue.500"
|
||||
onClick={onToggle}
|
||||
height="auto"
|
||||
@@ -444,13 +467,36 @@ const HistoricalEvents = ({
|
||||
// 股票列表子组件
|
||||
const StocksList = ({ stocks, eventTradingDate }) => {
|
||||
const textSecondary = useColorModeValue('gray.600', 'gray.400');
|
||||
|
||||
|
||||
// 处理股票代码,移除.SZ/.SH后缀
|
||||
const formatStockCode = (stockCode) => {
|
||||
if (!stockCode) return '';
|
||||
return stockCode.replace(/\.(SZ|SH)$/i, '');
|
||||
};
|
||||
|
||||
// 处理关联描述字段的辅助函数
|
||||
const getRelationDesc = (relationDesc) => {
|
||||
// 处理空值
|
||||
if (!relationDesc) return '';
|
||||
|
||||
// 如果是字符串,直接返回
|
||||
if (typeof relationDesc === 'string') {
|
||||
return relationDesc;
|
||||
}
|
||||
|
||||
// 如果是对象且包含data数组
|
||||
if (typeof relationDesc === 'object' && relationDesc.data && Array.isArray(relationDesc.data)) {
|
||||
const firstItem = relationDesc.data[0];
|
||||
if (firstItem) {
|
||||
// 优先使用 query_part,其次使用 sentences
|
||||
return firstItem.query_part || firstItem.sentences || '';
|
||||
}
|
||||
}
|
||||
|
||||
// 其他情况返回空字符串
|
||||
return '';
|
||||
};
|
||||
|
||||
if (!stocks || stocks.length === 0) {
|
||||
return (
|
||||
<Box textAlign="center" py={8} color={textSecondary}>
|
||||
@@ -527,7 +573,7 @@ const StocksList = ({ stocks, eventTradingDate }) => {
|
||||
<Td>
|
||||
<VStack align="flex-start" spacing={1}>
|
||||
<Text fontSize="xs" noOfLines={2} maxW="300px">
|
||||
{stock.relation_desc ? `${stock.relation_desc}(AI合成)` : '--'}
|
||||
{getRelationDesc(stock.relation_desc) ? `${getRelationDesc(stock.relation_desc)}(AI合成)` : '--'}
|
||||
</Text>
|
||||
</VStack>
|
||||
</Td>
|
||||
|
||||
@@ -65,6 +65,7 @@ import ReactECharts from 'echarts-for-react';
|
||||
import HomeNavbar from '../../../components/Navbars/HomeNavbar';
|
||||
|
||||
import { logger } from '../../../utils/logger';
|
||||
import { getApiBase } from '../../../utils/apiConfig';
|
||||
|
||||
// 板块关联TOP10数据计算
|
||||
function getSectorRelationTop10(sectorData) {
|
||||
@@ -177,7 +178,7 @@ function getTop10Sectors(chartData) {
|
||||
}
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
const API_BASE = isProduction ? "" : process.env.REACT_APP_API_URL;
|
||||
const API_BASE = getApiBase();
|
||||
// const API_BASE = 'http://49.232.185.254:5001'; // 改回5001端口,确保和后端一致
|
||||
|
||||
// 涨停分析服务
|
||||
|
||||
@@ -206,6 +206,28 @@ const RelatedStocks = ({
|
||||
return `股票${stock.stock_code.split('.')[0]}`;
|
||||
};
|
||||
|
||||
const getRelationDesc = (relationDesc) => {
|
||||
// 处理空值
|
||||
if (!relationDesc) return '--';
|
||||
|
||||
// 如果是字符串,直接返回
|
||||
if (typeof relationDesc === 'string') {
|
||||
return relationDesc;
|
||||
}
|
||||
|
||||
// 如果是对象且包含data数组
|
||||
if (typeof relationDesc === 'object' && relationDesc.data && Array.isArray(relationDesc.data)) {
|
||||
const firstItem = relationDesc.data[0];
|
||||
if (firstItem) {
|
||||
// 优先使用 query_part,其次使用 sentences
|
||||
return firstItem.query_part || firstItem.sentences || '--';
|
||||
}
|
||||
}
|
||||
|
||||
// 其他情况返回默认值
|
||||
return '--';
|
||||
};
|
||||
|
||||
// ==================== 数据处理 ====================
|
||||
const filteredAndSortedStocks = stocksData
|
||||
.filter(stock => {
|
||||
@@ -442,7 +464,7 @@ const RelatedStocks = ({
|
||||
{/* 关联描述 */}
|
||||
<Td maxW="200px">
|
||||
<Text fontSize="xs" noOfLines={2}>
|
||||
{stock.relation_desc || '--'}
|
||||
{getRelationDesc(stock.relation_desc)}
|
||||
</Text>
|
||||
</Td>
|
||||
|
||||
|
||||
@@ -405,6 +405,14 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
const modalBgColor = useColorModeValue('white', 'gray.800');
|
||||
const modalBorderColor = useColorModeValue('gray.200', 'gray.600');
|
||||
|
||||
// 关闭弹窗并清空状态
|
||||
const handleCloseModal = () => {
|
||||
setIsModalOpen(false);
|
||||
setSelectedNode(null);
|
||||
setNodeDetail(null);
|
||||
setTransmissionPath([]);
|
||||
};
|
||||
|
||||
// 延迟初始化图表,确保DOM容器准备好
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
@@ -771,9 +779,10 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
)}
|
||||
|
||||
{/* 节点详情弹窗 */}
|
||||
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} size="xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent maxH="80vh" bg={modalBgColor}>
|
||||
{isModalOpen && (
|
||||
<Modal isOpen={isModalOpen} onClose={handleCloseModal} size="xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent maxH="80vh" bg={modalBgColor}>
|
||||
<ModalHeader borderBottom="1px solid" borderColor={modalBorderColor}>
|
||||
<HStack justify="space-between">
|
||||
<Text>{selectedNode ? '节点详情' : '传导链分析'}</Text>
|
||||
@@ -845,9 +854,9 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
{selectedNode.extra?.description && (
|
||||
<Box>
|
||||
<Text fontWeight="bold" mb={2} color="blue.600">描述</Text>
|
||||
<Box
|
||||
fontSize="sm"
|
||||
color="gray.600"
|
||||
<Box
|
||||
fontSize="sm"
|
||||
color="gray.600"
|
||||
borderLeft="3px solid"
|
||||
borderColor="blue.200"
|
||||
pl={3}
|
||||
@@ -856,7 +865,19 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
borderRadius="md"
|
||||
fontStyle="italic"
|
||||
>
|
||||
{selectedNode.extra.description}(AI合成)
|
||||
{selectedNode.extra.description?.data ? (
|
||||
<>
|
||||
<CitedContent
|
||||
data={selectedNode.extra.description}
|
||||
title=""
|
||||
showAIBadge={false}
|
||||
containerStyle={{ backgroundColor: 'transparent', padding: 0, display: 'inline-block', verticalAlign: 'baseline' }}
|
||||
/>
|
||||
(AI合成)
|
||||
</>
|
||||
) : (
|
||||
`${selectedNode.extra.description}(AI合成)`
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
@@ -899,16 +920,17 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
<HStack justify="space-between" align="flex-start">
|
||||
<VStack align="stretch" spacing={1} flex={1}>
|
||||
<Text fontWeight="bold" fontSize="sm">{parent.name}</Text>
|
||||
{parent.transmission_mechanism_citation?.data ? (
|
||||
<Box fontSize="xs">
|
||||
{parent.transmission_mechanism?.data ? (
|
||||
<Text fontSize="xs">
|
||||
<Text as="span" fontWeight="bold">机制: </Text>
|
||||
<CitedContent
|
||||
data={parent.transmission_mechanism_citation.data}
|
||||
data={parent.transmission_mechanism}
|
||||
title=""
|
||||
showAIBadge={false}
|
||||
containerStyle={{ backgroundColor: 'transparent', padding: 0, display: 'inline' }}
|
||||
containerStyle={{ backgroundColor: 'transparent', padding: 0, display: 'inline-block', verticalAlign: 'baseline' }}
|
||||
/>
|
||||
</Box>
|
||||
(AI合成)
|
||||
</Text>
|
||||
) : parent.transmission_mechanism ? (
|
||||
<Text fontSize="xs" color="gray.600">
|
||||
机制: {parent.transmission_mechanism}(AI合成)
|
||||
@@ -950,15 +972,16 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
<VStack align="stretch" spacing={1} flex={1}>
|
||||
<Text fontWeight="bold" fontSize="sm">{child.name}</Text>
|
||||
{child.transmission_mechanism?.data ? (
|
||||
<Box fontSize="xs">
|
||||
<Text fontSize="xs">
|
||||
<Text as="span" fontWeight="bold">机制: </Text>
|
||||
<CitedContent
|
||||
data={child.transmission_mechanism.data}
|
||||
data={child.transmission_mechanism}
|
||||
title=""
|
||||
showAIBadge={false}
|
||||
containerStyle={{ backgroundColor: 'transparent', padding: 0, display: 'inline' }}
|
||||
containerStyle={{ backgroundColor: 'transparent', padding: 0, display: 'inline-block', verticalAlign: 'baseline' }}
|
||||
/>
|
||||
</Box>
|
||||
(AI合成)
|
||||
</Text>
|
||||
) : child.transmission_mechanism ? (
|
||||
<Text fontSize="xs" color="gray.600">
|
||||
机制: {child.transmission_mechanism}(AI合成)
|
||||
@@ -991,10 +1014,11 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter borderTop="1px solid" borderColor={modalBorderColor}>
|
||||
<Button onClick={() => setIsModalOpen(false)}>关闭</Button>
|
||||
<Button onClick={handleCloseModal}>关闭</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user