154 lines
5.1 KiB
JavaScript
154 lines
5.1 KiB
JavaScript
// 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 - 引用 ID(1, 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: 320, padding: '8px 10px' }}>
|
||
{/* 报告标题 - 顶部突出显示 */}
|
||
<div style={{ marginBottom: 8 }}>
|
||
<Text
|
||
strong
|
||
style={{
|
||
fontSize: 14,
|
||
fontWeight: 600,
|
||
color: '#262626',
|
||
display: 'block',
|
||
lineHeight: 1.3
|
||
}}
|
||
>
|
||
{citation.report_title}
|
||
</Text>
|
||
</div>
|
||
|
||
{/* 作者和日期 - 左右分布 */}
|
||
<div style={{
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
marginBottom: 8,
|
||
paddingBottom: 8,
|
||
borderBottom: '1px solid #f0f0f0'
|
||
}}>
|
||
{/* 左侧:作者 */}
|
||
<Space size={4}>
|
||
<UserOutlined style={{ color: '#1890ff', fontSize: 12 }} />
|
||
<Text style={{ fontSize: 12, color: '#595959' }}>
|
||
{citation.author}
|
||
</Text>
|
||
</Space>
|
||
|
||
{/* 右侧:发布日期(重点标注) */}
|
||
<Space size={4}>
|
||
<CalendarOutlined style={{ color: '#fa8c16', fontSize: 12 }} />
|
||
<Text
|
||
strong
|
||
style={{
|
||
fontSize: 12,
|
||
fontWeight: 600,
|
||
color: '#fa8c16'
|
||
}}
|
||
>
|
||
{citation.declare_date}
|
||
</Text>
|
||
</Space>
|
||
</div>
|
||
|
||
{/* 摘要片段 */}
|
||
<div>
|
||
<Text type="secondary" style={{ fontSize: 11, display: 'block', marginBottom: 4 }}>
|
||
摘要片段
|
||
</Text>
|
||
<Text
|
||
style={{
|
||
fontSize: 12,
|
||
lineHeight: 1.5,
|
||
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: 340, padding: '8px' }}
|
||
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;
|