diff --git a/src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js b/src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js
index 6b2adf23..cf6a7ef6 100644
--- a/src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js
+++ b/src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js
@@ -24,7 +24,9 @@ import {
Button,
} from "@chakra-ui/react";
import { ChevronDownIcon, ChevronUpIcon, RepeatIcon } from "@chakra-ui/icons";
-import { FiTrendingUp, FiZap } from "react-icons/fi";
+import { FiTrendingUp, FiZap, FiClock } from "react-icons/fi";
+import { FireOutlined } from "@ant-design/icons";
+import dayjs from "dayjs";
import { Select } from "antd";
import MiniEventCard from "../../EventCard/MiniEventCard";
import { getApiBase } from "@utils/apiConfig";
@@ -47,6 +49,122 @@ const COLORS = {
// 每次加载的事件数量
const EVENTS_PER_LOAD = 12;
+/**
+ * 格式化时间显示
+ */
+const formatEventTime = (dateStr) => {
+ if (!dateStr) return "";
+ const date = dayjs(dateStr);
+ const now = dayjs();
+ const isToday = date.isSame(now, "day");
+ const isYesterday = date.isSame(now.subtract(1, "day"), "day");
+
+ if (isToday) {
+ return date.format("HH:mm");
+ } else if (isYesterday) {
+ return `昨天 ${date.format("HH:mm")}`;
+ } else {
+ return date.format("MM-DD HH:mm");
+ }
+};
+
+/**
+ * 单个事件项组件 - 带时间轴
+ */
+const TimelineEventItem = React.memo(({ event, isSelected, onEventClick, isHot }) => {
+ const changePct = event.max_change_pct ?? event.change_pct;
+ const hasChange = changePct != null;
+ const isPositive = hasChange && changePct >= 0;
+
+ return (
+ onEventClick?.(event)}
+ _hover={{ bg: "rgba(255, 255, 255, 0.05)" }}
+ borderRadius="md"
+ transition="all 0.15s"
+ bg={isSelected ? "rgba(66, 153, 225, 0.15)" : "transparent"}
+ >
+ {/* 左侧时间轴 */}
+
+ {/* 时间显示 */}
+
+ {formatEventTime(event.created_at || event.event_time)}
+
+ {/* 时间轴线 */}
+
+ {/* 时间轴圆点 */}
+
+
+
+ {/* 右侧内容 */}
+
+
+ {/* HOT 标签 */}
+ {isHot && (
+
+
+ HOT
+
+ )}
+
+ {event.title}
+
+ {/* 涨跌幅 */}
+ {hasChange && (
+
+ {isPositive ? "+" : ""}
+ {changePct.toFixed(1)}%
+
+ )}
+
+
+
+ );
+});
+
+TimelineEventItem.displayName = "TimelineEventItem";
+
/**
* 单个主线卡片组件 - 支持懒加载
*/
@@ -70,6 +188,23 @@ const MainlineCard = React.memo(
}
}, [isExpanded]);
+ // 找出涨幅最大的事件(HOT 事件)
+ const hotEvent = useMemo(() => {
+ if (!mainline.events || mainline.events.length === 0) return null;
+ let maxChange = -Infinity;
+ let hot = null;
+ mainline.events.forEach((event) => {
+ const change = event.max_change_pct ?? event.change_pct ?? -Infinity;
+ if (change > maxChange) {
+ maxChange = change;
+ hot = event;
+ }
+ });
+ return hot;
+ }, [mainline.events]);
+
+ const hotEventId = hotEvent?.id;
+
// 当前显示的事件
const displayedEvents = useMemo(() => {
return mainline.events.slice(0, displayCount);
@@ -114,77 +249,135 @@ const MainlineCard = React.memo(
}}
>
{/* 卡片头部 */}
-
-
-
-
- {mainline.group_name || mainline.lv2_name || mainline.lv1_name || "其他"}
-
- {/* 涨跌幅显示 - 在概念名称旁边 */}
- {mainline.avg_change_pct != null && (
+
+ {/* 第一行:概念名称 + 涨跌幅 + 事件数 */}
+
+
+
= 0 ? "#fc8181" : "#68d391"}
+ fontSize="sm"
+ color={COLORS.textColor}
+ noOfLines={1}
+ flex={1}
+ >
+ {mainline.group_name || mainline.lv2_name || mainline.lv1_name || "其他"}
+
+ {/* 涨跌幅显示 - 在概念名称旁边 */}
+ {mainline.avg_change_pct != null && (
+ = 0 ? "#fc8181" : "#68d391"}
+ flexShrink={0}
+ >
+ {mainline.avg_change_pct >= 0 ? "+" : ""}
+ {mainline.avg_change_pct.toFixed(2)}%
+
+ )}
+
- {mainline.avg_change_pct >= 0 ? "+" : ""}
- {mainline.avg_change_pct.toFixed(2)}%
+ {mainline.event_count}
+
+
+ {/* 显示上级概念名称作为副标题 */}
+ {mainline.parent_name && (
+
+ {mainline.grandparent_name ? `${mainline.grandparent_name} > ` : ""}
+ {mainline.parent_name}
)}
-
- {mainline.event_count}
-
-
- {/* 显示上级概念名称作为副标题 */}
- {mainline.parent_name && (
-
- {mainline.grandparent_name ? `${mainline.grandparent_name} > ` : ""}
- {mainline.parent_name}
-
- )}
-
-
-
+
+
+
+
+ {/* HOT 事件展示区域 */}
+ {hotEvent && (
+ {
+ e.stopPropagation();
+ onEventSelect?.(hotEvent);
+ }}
+ _hover={{ bg: "rgba(245, 101, 101, 0.15)" }}
+ transition="all 0.15s"
+ >
+
+ {/* HOT 标签 */}
+
+
+ HOT
+
+ {/* HOT 事件标题 */}
+
+ {hotEvent.title}
+
+ {/* HOT 事件涨幅 */}
+ {(hotEvent.max_change_pct ?? hotEvent.change_pct) != null && (
+
+ +{(hotEvent.max_change_pct ?? hotEvent.change_pct).toFixed(1)}%
+
+ )}
+
+
+ )}
+
{/* 事件列表区域 */}
{isExpanded ? (
- {/* 事件列表 - 单列布局 */}
-
+ {/* 事件列表 - 带时间轴 */}
+
{displayedEvents.map((event) => (
-
))}
@@ -229,27 +423,20 @@ const MainlineCard = React.memo(
)}
) : (
- /* 折叠时显示简要信息 */
-
-
+ /* 折叠时显示简要信息 - 也带时间轴 */
+
+
{mainline.events.slice(0, 4).map((event) => (
- {
- e.stopPropagation();
- onEventSelect?.(event);
- }}
- >
- • {event.title}
-
+ event={event}
+ isSelected={selectedEvent?.id === event.id}
+ onEventClick={onEventSelect}
+ isHot={event.id === hotEventId}
+ />
))}
{mainline.events.length > 4 && (
-
+
... 还有 {mainline.events.length - 4} 条
)}