Files
vf_react/src/components/Citation/CitationMark.js
2025-10-15 18:22:02 +08:00

141 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/components/Citation/CitationMark.js
import React, { useState } from 'react';
import { Popover, Typography, Space, Divider } from 'antd';
import { FileTextOutlined, UserOutlined, CalendarOutlined } from '@ant-design/icons';
const { Text } = Typography;
/**
* 引用标记组件 - 显示上标引用【1】【2】【3】
* 支持悬浮(桌面)和点击(移动)两种交互方式
*
* @param {Object} props
* @param {number} props.citationId - 引用 ID1, 2, 3...
* @param {Object} props.citation - 引用数据对象
* @param {string} props.citation.author - 作者
* @param {string} props.citation.report_title - 报告标题
* @param {string} props.citation.declare_date - 发布日期
* @param {string} props.citation.sentences - 摘要片段
*/
const CitationMark = ({ citationId, citation }) => {
const [popoverVisible, setPopoverVisible] = useState(false);
// 如果没有引用数据,不渲染
if (!citation) {
return null;
}
// 引用卡片内容
const citationContent = (
<div style={{ maxWidth: 350, padding: '8px 4px' }}>
{/* 作者 */}
<Space align="start" style={{ marginBottom: 8 }}>
<UserOutlined style={{ color: '#1890ff', marginTop: 4 }} />
<div>
<Text type="secondary" style={{ fontSize: 12 }}>作者</Text>
<br />
<Text strong style={{ fontSize: 13 }}>{citation.author}</Text>
</div>
</Space>
<Divider style={{ margin: '8px 0' }} />
{/* 报告标题 */}
<Space align="start" style={{ marginBottom: 8 }}>
<FileTextOutlined style={{ color: '#52c41a', marginTop: 4 }} />
<div>
<Text type="secondary" style={{ fontSize: 12 }}>报告标题</Text>
<br />
<Text strong style={{ fontSize: 13 }}>{citation.report_title}</Text>
</div>
</Space>
<Divider style={{ margin: '8px 0' }} />
{/* 发布日期 */}
<Space align="start" style={{ marginBottom: 8 }}>
<CalendarOutlined style={{ color: '#faad14', marginTop: 4 }} />
<div>
<Text type="secondary" style={{ fontSize: 12 }}>发布日期</Text>
<br />
<Text style={{ fontSize: 13 }}>{citation.declare_date}</Text>
</div>
</Space>
<Divider style={{ margin: '8px 0' }} />
{/* 摘要片段 */}
<div>
<Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
摘要片段
</Text>
<Text
style={{
fontSize: 13,
lineHeight: 1.6,
display: 'block',
color: '#595959'
}}
>
{citation.sentences}
</Text>
</div>
</div>
);
// 检测是否为移动设备
const isMobile = () => {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
);
};
// 移动端:仅点击触发
// 桌面端:悬浮 + 点击都触发
const triggerType = isMobile() ? 'click' : ['hover', 'click'];
return (
<Popover
content={citationContent}
title={`引用来源 [${citationId}]`}
trigger={triggerType}
placement="top"
overlayInnerStyle={{ maxWidth: 380 }}
open={popoverVisible}
onOpenChange={setPopoverVisible}
>
<sup
style={{
display: 'inline-block',
color: '#1890ff',
fontWeight: 'bold',
cursor: 'pointer',
padding: '0 2px',
fontSize: '0.85em',
userSelect: 'none',
transition: 'all 0.2s',
}}
onMouseEnter={(e) => {
if (!isMobile()) {
e.target.style.color = '#40a9ff';
e.target.style.textDecoration = 'underline';
}
}}
onMouseLeave={(e) => {
if (!isMobile()) {
e.target.style.color = '#1890ff';
e.target.style.textDecoration = 'none';
}
}}
onClick={() => {
setPopoverVisible(!popoverVisible);
}}
>
{citationId}
</sup>
</Popover>
);
};
export default CitationMark;