Files
evotraders/frontend/src/components/explain/ExplainEventsSection.jsx

158 lines
6.1 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.
import React from 'react';
import { formatDateTime } from '../../utils/formatters';
export default function ExplainEventsSection({
explainTimeline,
isOpen,
onToggle,
availableEventDates,
selectedEventDate,
onSelectEventDate,
eventCategoryCounts,
activeEventCategory,
onSelectEventCategory,
eventCategoryMeta,
visibleExplainEvents,
}) {
return (
<div className="section">
<div className="section-header">
<h2 className="section-title">关键事件时间线</h2>
<div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
<div style={{ fontSize: 11, color: '#666666' }}>
图上点击事件点可切换对应日期
</div>
<button
onClick={onToggle}
style={{
border: '1px solid #111111',
background: isOpen ? '#111111' : '#ffffff',
color: isOpen ? '#ffffff' : '#111111',
padding: '7px 10px',
fontFamily: 'inherit',
fontSize: 11,
fontWeight: 700,
cursor: 'pointer'
}}
>
{isOpen ? '收起关键事件' : `展开关键事件 ${explainTimeline.length}`}
</button>
</div>
</div>
{explainTimeline.length === 0 ? (
<div className="empty-state">当前还没有可以串起来看的关键事件</div>
) : !isOpen ? (
<div className="empty-state">关键事件默认收起需要时再展开查看和筛选</div>
) : (
<div style={{ display: 'grid', gap: 14 }}>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
{availableEventDates.map((dateKey) => {
const isActive = dateKey === selectedEventDate;
return (
<button
key={dateKey}
onClick={() => onSelectEventDate(dateKey)}
style={{
border: '1px solid #111111',
background: isActive ? '#111111' : '#ffffff',
color: isActive ? '#ffffff' : '#111111',
padding: '7px 10px',
fontFamily: 'inherit',
fontSize: 11,
fontWeight: 700,
cursor: 'pointer'
}}
>
{dateKey}
</button>
);
})}
</div>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
{Object.entries(eventCategoryMeta)
.filter(([key]) => (eventCategoryCounts[key] || 0) > 0 || key === 'all')
.map(([key, meta]) => {
const isActive = key === activeEventCategory;
return (
<button
key={key}
onClick={() => onSelectEventCategory(key)}
style={{
border: `1px solid ${meta.color}`,
background: isActive ? meta.color : '#ffffff',
color: isActive ? '#ffffff' : meta.color,
padding: '8px 10px',
fontFamily: 'inherit',
fontSize: 11,
fontWeight: 700,
cursor: 'pointer'
}}
>
{meta.label} {eventCategoryCounts[key] || 0}
</button>
);
})}
</div>
{visibleExplainEvents.length === 0 ? (
<div className="empty-state">当前日期下没有符合筛选条件的事件</div>
) : (
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(320px, 1fr))', gap: 16 }}>
{visibleExplainEvents.map((event) => {
const accent = event.tone === 'positive' ? '#00C853' : event.tone === 'negative' ? '#FF1744' : '#000000';
const categoryMeta = eventCategoryMeta[event.category] || eventCategoryMeta.other;
return (
<div
key={event.id}
style={{
border: '1px solid #000000',
background: '#ffffff',
padding: 14,
minHeight: 180
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, marginBottom: 8 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
<span style={{
display: 'inline-flex',
padding: '2px 6px',
border: `1px solid ${categoryMeta.color}`,
color: categoryMeta.color,
fontSize: 10,
fontWeight: 700
}}>
{categoryMeta.label}
</span>
<strong style={{ fontSize: 13 }}>{event.title}</strong>
</div>
<span style={{ fontSize: 10, color: '#666666', whiteSpace: 'nowrap' }}>
{formatDateTime(event.timestamp)}
</span>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
<span style={{
width: 8,
height: 8,
borderRadius: '50%',
background: accent
}} />
<span style={{ fontSize: 10, color: '#666666', textTransform: 'uppercase', letterSpacing: 0.6 }}>
{event.meta}
</span>
</div>
<div style={{ fontSize: 12, lineHeight: 1.7, color: '#000000', whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>
{event.body}
</div>
</div>
);
})}
</div>
)}
</div>
)}
</div>
);
}