feat: 添加合规内容
This commit is contained in:
@@ -5,6 +5,7 @@ import ReactECharts from 'echarts-for-react';
|
|||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { stockService } from '../../services/eventService';
|
import { stockService } from '../../services/eventService';
|
||||||
|
import CitedContent from '../Citation/CitedContent';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
@@ -524,12 +525,21 @@ const StockChartAntdModal = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 关联描述 */}
|
{/* 关联描述 */}
|
||||||
{stock?.relation_desc && (
|
{stock?.relation_desc?.data ? (
|
||||||
|
// 使用引用组件(带研报来源)
|
||||||
|
<CitedContent
|
||||||
|
data={stock.relation_desc.data}
|
||||||
|
title="关联描述"
|
||||||
|
showAIBadge={true}
|
||||||
|
containerStyle={{ marginTop: 16 }}
|
||||||
|
/>
|
||||||
|
) : stock?.relation_desc ? (
|
||||||
|
// 降级显示(无引用数据)
|
||||||
<div style={{ marginTop: 16, padding: 16, backgroundColor: '#f5f5f5', borderRadius: 6 }}>
|
<div style={{ marginTop: 16, padding: 16, backgroundColor: '#f5f5f5', borderRadius: 6 }}>
|
||||||
<Text strong style={{ display: 'block', marginBottom: 8 }}>关联描述:</Text>
|
<Text strong style={{ display: 'block', marginBottom: 8 }}>关联描述:</Text>
|
||||||
<Text>{stock.relation_desc}(AI合成)</Text>
|
<Text>{stock.relation_desc}(AI合成)</Text>
|
||||||
</div>
|
</div>
|
||||||
)}
|
) : null}
|
||||||
|
|
||||||
{/* 调试信息 */}
|
{/* 调试信息 */}
|
||||||
{process.env.NODE_ENV === 'development' && chartData && (
|
{process.env.NODE_ENV === 'development' && chartData && (
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from 'antd';
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
StarFilled, StarOutlined, CalendarOutlined, LinkOutlined, StockOutlined,
|
StarFilled, StarOutlined, CalendarOutlined, LinkOutlined, StockOutlined,
|
||||||
TagsOutlined, ClockCircleOutlined, InfoCircleOutlined, LockOutlined
|
TagsOutlined, ClockCircleOutlined, InfoCircleOutlined, LockOutlined, RobotOutlined
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
@@ -14,6 +14,8 @@ import { eventService, stockService } from '../../../services/eventService';
|
|||||||
import StockChartAntdModal from '../../../components/StockChart/StockChartAntdModal';
|
import StockChartAntdModal from '../../../components/StockChart/StockChartAntdModal';
|
||||||
import { useSubscription } from '../../../hooks/useSubscription';
|
import { useSubscription } from '../../../hooks/useSubscription';
|
||||||
import SubscriptionUpgradeModal from '../../../components/SubscriptionUpgradeModal';
|
import SubscriptionUpgradeModal from '../../../components/SubscriptionUpgradeModal';
|
||||||
|
import CitationMark from '../../../components/Citation/CitationMark';
|
||||||
|
import { processCitationData } from '../../../utils/citationUtils';
|
||||||
import './InvestmentCalendar.css';
|
import './InvestmentCalendar.css';
|
||||||
|
|
||||||
const { TabPane } = Tabs;
|
const { TabPane } = Tabs;
|
||||||
@@ -474,26 +476,95 @@ const InvestmentCalendar = () => {
|
|||||||
const stockCode = record[0];
|
const stockCode = record[0];
|
||||||
const isExpanded = expandedReasons[stockCode] || false;
|
const isExpanded = expandedReasons[stockCode] || false;
|
||||||
const shouldTruncate = reason && reason.length > 100;
|
const shouldTruncate = reason && reason.length > 100;
|
||||||
|
|
||||||
const toggleExpanded = () => {
|
const toggleExpanded = () => {
|
||||||
setExpandedReasons(prev => ({
|
setExpandedReasons(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[stockCode]: !prev[stockCode]
|
[stockCode]: !prev[stockCode]
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 检查是否有引用数据(可能在 record.reason_citation 或 record[4])
|
||||||
|
const citationData = record.reason;
|
||||||
|
const hasCitation = citationData && citationData.data && Array.isArray(citationData.data);
|
||||||
|
|
||||||
|
if (hasCitation) {
|
||||||
|
// 使用引用组件,支持展开/收起
|
||||||
|
const processed = processCitationData(citationData);
|
||||||
|
|
||||||
|
if (processed) {
|
||||||
|
// 计算所有段落的总长度
|
||||||
|
const totalLength = processed.segments.reduce((sum, seg) => sum + seg.text.length, 0);
|
||||||
|
const shouldTruncate = totalLength > 100;
|
||||||
|
|
||||||
|
// 确定要显示的段落
|
||||||
|
let displaySegments = processed.segments;
|
||||||
|
if (shouldTruncate && !isExpanded) {
|
||||||
|
// 需要截断:计算应该显示到哪个段落
|
||||||
|
let charCount = 0;
|
||||||
|
displaySegments = [];
|
||||||
|
for (const seg of processed.segments) {
|
||||||
|
if (charCount + seg.text.length <= 100) {
|
||||||
|
// 完整显示这个段落
|
||||||
|
displaySegments.push(seg);
|
||||||
|
charCount += seg.text.length;
|
||||||
|
} else {
|
||||||
|
// 截断这个段落
|
||||||
|
const remainingChars = 100 - charCount;
|
||||||
|
if (remainingChars > 0) {
|
||||||
|
const truncatedText = seg.text.substring(0, remainingChars) + '...';
|
||||||
|
displaySegments.push({ ...seg, text: truncatedText });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{ lineHeight: '1.6' }}>
|
||||||
|
{displaySegments.map((segment, index) => (
|
||||||
|
<React.Fragment key={segment.citationId}>
|
||||||
|
<Text>{segment.text}</Text>
|
||||||
|
<CitationMark
|
||||||
|
citationId={segment.citationId}
|
||||||
|
citation={processed.citations[segment.citationId]}
|
||||||
|
/>
|
||||||
|
{index < displaySegments.length - 1 && <Text>,</Text>}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{shouldTruncate && (
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
onClick={toggleExpanded}
|
||||||
|
style={{ padding: 0, marginLeft: 4 }}
|
||||||
|
>
|
||||||
|
({isExpanded ? '收起' : '展开'})
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<div style={{ marginTop: 4 }}>
|
||||||
|
<Text type="secondary" style={{ fontSize: '12px' }}>(AI合成)</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 降级显示:纯文本 + 展开/收起
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Text>
|
<Text>
|
||||||
{isExpanded || !shouldTruncate
|
{isExpanded || !shouldTruncate
|
||||||
? reason
|
? reason
|
||||||
: `${reason?.slice(0, 100)}...`
|
: `${reason?.slice(0, 100)}...`
|
||||||
}
|
}
|
||||||
</Text>
|
</Text>
|
||||||
{shouldTruncate && (
|
{shouldTruncate && (
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={toggleExpanded}
|
onClick={toggleExpanded}
|
||||||
style={{ padding: 0, marginLeft: 4 }}
|
style={{ padding: 0, marginLeft: 4 }}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
import { InfoIcon, ViewIcon } from '@chakra-ui/icons';
|
import { InfoIcon, ViewIcon } from '@chakra-ui/icons';
|
||||||
import ReactECharts from 'echarts-for-react';
|
import ReactECharts from 'echarts-for-react';
|
||||||
import { eventService } from '../../../services/eventService';
|
import { eventService } from '../../../services/eventService';
|
||||||
|
import CitedContent from '../../../components/Citation/CitedContent';
|
||||||
|
|
||||||
// 节点样式配置 - 完全复刻Flask版本
|
// 节点样式配置 - 完全复刻Flask版本
|
||||||
const NODE_STYLES = {
|
const NODE_STYLES = {
|
||||||
@@ -896,11 +897,21 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
|||||||
<HStack justify="space-between" align="flex-start">
|
<HStack justify="space-between" align="flex-start">
|
||||||
<VStack align="stretch" spacing={1} flex={1}>
|
<VStack align="stretch" spacing={1} flex={1}>
|
||||||
<Text fontWeight="bold" fontSize="sm">{parent.name}</Text>
|
<Text fontWeight="bold" fontSize="sm">{parent.name}</Text>
|
||||||
{parent.transmission_mechanism && (
|
{parent.transmission_mechanism_citation?.data ? (
|
||||||
|
<Box fontSize="xs">
|
||||||
|
<Text as="span" fontWeight="bold">机制: </Text>
|
||||||
|
<CitedContent
|
||||||
|
data={parent.transmission_mechanism_citation.data}
|
||||||
|
title=""
|
||||||
|
showAIBadge={false}
|
||||||
|
containerStyle={{ backgroundColor: 'transparent', padding: 0, display: 'inline' }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
) : parent.transmission_mechanism ? (
|
||||||
<Text fontSize="xs" color="gray.600">
|
<Text fontSize="xs" color="gray.600">
|
||||||
机制: {parent.transmission_mechanism}(AI合成)
|
机制: {parent.transmission_mechanism}(AI合成)
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
) : null}
|
||||||
</VStack>
|
</VStack>
|
||||||
<HStack spacing={2}>
|
<HStack spacing={2}>
|
||||||
<Badge colorScheme={parent.direction === 'positive' ? 'green' : parent.direction === 'negative' ? 'red' : 'gray'} size="sm">
|
<Badge colorScheme={parent.direction === 'positive' ? 'green' : parent.direction === 'negative' ? 'red' : 'gray'} size="sm">
|
||||||
@@ -936,11 +947,21 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
|||||||
<HStack justify="space-between" align="flex-start">
|
<HStack justify="space-between" align="flex-start">
|
||||||
<VStack align="stretch" spacing={1} flex={1}>
|
<VStack align="stretch" spacing={1} flex={1}>
|
||||||
<Text fontWeight="bold" fontSize="sm">{child.name}</Text>
|
<Text fontWeight="bold" fontSize="sm">{child.name}</Text>
|
||||||
{child.transmission_mechanism && (
|
{child.transmission_mechanism?.data ? (
|
||||||
|
<Box fontSize="xs">
|
||||||
|
<Text as="span" fontWeight="bold">机制: </Text>
|
||||||
|
<CitedContent
|
||||||
|
data={child.transmission_mechanism.data}
|
||||||
|
title=""
|
||||||
|
showAIBadge={false}
|
||||||
|
containerStyle={{ backgroundColor: 'transparent', padding: 0, display: 'inline' }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
) : child.transmission_mechanism ? (
|
||||||
<Text fontSize="xs" color="gray.600">
|
<Text fontSize="xs" color="gray.600">
|
||||||
机制: {child.transmission_mechanism}(AI合成)
|
机制: {child.transmission_mechanism}(AI合成)
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
) : null}
|
||||||
</VStack>
|
</VStack>
|
||||||
<HStack spacing={2}>
|
<HStack spacing={2}>
|
||||||
<Badge colorScheme={child.direction === 'positive' ? 'green' : child.direction === 'negative' ? 'red' : 'gray'} size="sm">
|
<Badge colorScheme={child.direction === 'positive' ? 'green' : child.direction === 'negative' ? 'red' : 'gray'} size="sm">
|
||||||
|
|||||||
Reference in New Issue
Block a user