162 lines
5.6 KiB
JavaScript
162 lines
5.6 KiB
JavaScript
// src/components/Citation/CitedContent.js
|
||
import React from 'react';
|
||
import { Typography, Tag } from 'antd';
|
||
import { RobotOutlined } from '@ant-design/icons';
|
||
import CitationMark from './CitationMark';
|
||
import { processCitationData } from '../../utils/citationUtils';
|
||
import { logger } from '../../utils/logger';
|
||
|
||
const { Text } = Typography;
|
||
|
||
/**
|
||
* 带引用标注的内容组件(块级模式)
|
||
* 展示拼接的文本,每句话后显示上标引用【1】【2】【3】
|
||
* 支持鼠标悬浮和点击查看引用来源
|
||
* AI 标识统一显示在右上角,不占用布局高度
|
||
*
|
||
* @param {Object} props
|
||
* @param {Object} props.data - API 返回的原始数据 { data: [...] }
|
||
* @param {string} props.title - 标题文本,默认 "AI 分析结果"
|
||
* @param {string} props.prefix - 内容前的前缀标签,如 "机制:"(可选)
|
||
* @param {Object} props.prefixStyle - 前缀标签的自定义样式(可选)
|
||
* @param {boolean} props.showAIBadge - 是否显示右上角 AI 标识,默认 true(可选)
|
||
* @param {Object} props.containerStyle - 容器额外样式(可选)
|
||
* @param {string} props.textColor - 文本颜色,默认自动判断背景色(可选)
|
||
* @param {string} props.titleColor - 标题颜色,默认继承 textColor(可选)
|
||
*
|
||
* @example
|
||
* <CitedContent
|
||
* data={apiData}
|
||
* title="关联描述"
|
||
* prefix="机制:"
|
||
* prefixStyle={{ color: '#666' }}
|
||
* showAIBadge={true}
|
||
* containerStyle={{ marginTop: 16 }}
|
||
* textColor="#E2E8F0"
|
||
* />
|
||
*/
|
||
const CitedContent = ({
|
||
data,
|
||
title = 'AI 分析结果',
|
||
prefix = '',
|
||
prefixStyle = {},
|
||
showAIBadge = true,
|
||
containerStyle = {},
|
||
textColor,
|
||
titleColor
|
||
}) => {
|
||
// 处理数据
|
||
const processed = processCitationData(data);
|
||
|
||
// 如果数据无效,不渲染
|
||
if (!processed) {
|
||
logger.warn('CitedContent', '无效数据,不渲染', {
|
||
hasData: !!data,
|
||
title
|
||
});
|
||
return null;
|
||
}
|
||
|
||
// 自动判断文本颜色:如果容器背景是深色,使用浅色文本
|
||
const bgColor = containerStyle.backgroundColor;
|
||
const isDarkBg = bgColor && (
|
||
bgColor.includes('rgba(0,0,0') ||
|
||
bgColor.includes('rgba(0, 0, 0') ||
|
||
bgColor === 'transparent' ||
|
||
bgColor.includes('#1A202C') ||
|
||
bgColor.includes('#171923')
|
||
);
|
||
|
||
const finalTextColor = textColor || (isDarkBg ? '#E2E8F0' : '#262626');
|
||
const finalTitleColor = titleColor || finalTextColor;
|
||
|
||
return (
|
||
<div
|
||
style={{
|
||
position: 'relative',
|
||
width: '100%',
|
||
backgroundColor: '#f5f5f5',
|
||
borderRadius: 6,
|
||
padding: 16,
|
||
paddingTop: title ? 16 : 20,
|
||
...containerStyle
|
||
}}
|
||
>
|
||
{/* 标题栏 */}
|
||
{title && (
|
||
<div style={{ marginBottom: 12 }}>
|
||
<Text strong style={{ fontSize: 14, color: finalTitleColor }}>
|
||
{title}
|
||
</Text>
|
||
</div>
|
||
)}
|
||
|
||
{/* 带引用的文本内容 */}
|
||
<div style={{ lineHeight: 1.8 }}>
|
||
{/* AI 标识 - 行内显示在文字前面 */}
|
||
{showAIBadge && (
|
||
<Tag
|
||
icon={<RobotOutlined />}
|
||
color="purple"
|
||
style={{
|
||
fontSize: 12,
|
||
padding: '2px 8px',
|
||
marginRight: 8,
|
||
verticalAlign: 'middle',
|
||
display: 'inline-flex',
|
||
}}
|
||
className="ai-badge-responsive"
|
||
>
|
||
AI合成
|
||
</Tag>
|
||
)}
|
||
{/* 前缀标签(如果有) */}
|
||
{prefix && (
|
||
<Text style={{
|
||
fontSize: 14,
|
||
fontWeight: 'bold',
|
||
display: 'inline',
|
||
marginRight: 4,
|
||
color: finalTextColor,
|
||
...prefixStyle
|
||
}}>
|
||
{prefix}
|
||
</Text>
|
||
)}
|
||
|
||
{processed.segments.map((segment, index) => (
|
||
<React.Fragment key={`segment-${segment.citationId}`}>
|
||
{/* 文本片段 */}
|
||
<Text style={{ fontSize: 14, display: 'inline', color: finalTextColor }}>
|
||
{segment.text}
|
||
</Text>
|
||
|
||
{/* 引用标记 */}
|
||
<CitationMark
|
||
citationId={segment.citationId}
|
||
citation={processed.citations[segment.citationId]}
|
||
/>
|
||
|
||
{/* 在片段之间添加逗号分隔符(最后一个不加) */}
|
||
{index < processed.segments.length - 1 && (
|
||
<Text style={{ fontSize: 14, display: 'inline', color: finalTextColor }}>,</Text>
|
||
)}
|
||
</React.Fragment>
|
||
))}
|
||
</div>
|
||
|
||
{/* 响应式样式 */}
|
||
<style jsx>{`
|
||
@media (max-width: 768px) {
|
||
.ai-badge-responsive {
|
||
font-size: 10px !important;
|
||
padding: 1px 6px !important;
|
||
}
|
||
}
|
||
`}</style>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default CitedContent;
|