diff --git a/app.py b/app.py index 6dc494cc..1d32b55b 100755 --- a/app.py +++ b/app.py @@ -11036,7 +11036,6 @@ def get_events_by_mainline(): # 获取请求参数 recent_days = request.args.get('recent_days', 7, type=int) importance = request.args.get('importance', 'all') - limit_per_mainline = request.args.get('limit', 20, type=int) # 计算日期范围 since_date = datetime.now() - timedelta(days=recent_days) @@ -11106,8 +11105,8 @@ def get_events_by_mainline(): # 按时间倒序 query = query.order_by(Event.created_at.desc()) - # 获取事件(限制总数防止性能问题) - events = query.limit(500).all() + # 获取事件(提高限制以支持主线模式显示更多数据) + events = query.limit(2000).all() app.logger.info(f'[mainline] 查询到 {len(events)} 个事件') @@ -11220,12 +11219,12 @@ def get_events_by_mainline(): # ==================== 5. 整理返回数据 ==================== mainlines = [] for lv2_id, group in mainline_groups.items(): - # 按时间倒序,限制每组数量 + # 按时间倒序排列(不限制数量) group['events'] = sorted( group['events'], key=lambda x: x['created_at'] or '', reverse=True - )[:limit_per_mainline] + ) group['event_count'] = len(group['events']) mainlines.append(group) diff --git a/src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js b/src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js index 0095b01f..5a930114 100644 --- a/src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js +++ b/src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js @@ -1,5 +1,5 @@ // src/views/Community/components/DynamicNews/layouts/MainlineTimelineView.js -// 主线时间轴布局组件 - 按 lv2 概念分组展示事件(卡片式布局) +// 主线时间轴布局组件 - 按 lv2 概念分组展示事件(横向卡片布局) import React, { useState, @@ -22,11 +22,11 @@ import { IconButton, useColorModeValue, Tooltip, - Grid, + SimpleGrid, } from "@chakra-ui/react"; import { ChevronDownIcon, - ChevronRightIcon, + ChevronUpIcon, RepeatIcon, } from "@chakra-ui/icons"; import { FiTrendingUp, FiZap } from "react-icons/fi"; @@ -38,8 +38,9 @@ import { getApiBase } from "@utils/apiConfig"; * * 功能: * 1. 调用 /api/events/mainline 获取预分组数据 - * 2. 按 lv2 概念分组展示,卡片式布局 + 内部时间轴 + * 2. 按 lv2 概念分组展示,横向卡片布局 * 3. 按事件数量从多到少排序 + * 4. 深色背景风格,与列表模式统一 */ const MainlineTimelineViewComponent = forwardRef( ( @@ -51,7 +52,6 @@ const MainlineTimelineViewComponent = forwardRef( eventFollowStatus = {}, onToggleFollow, borderColor, - columnsPerRow = 3, }, ref ) => { @@ -61,18 +61,20 @@ const MainlineTimelineViewComponent = forwardRef( const [mainlineData, setMainlineData] = useState(null); const [expandedGroups, setExpandedGroups] = useState({}); - // 主题颜色 - 与列表模式统一的深色风格 + // 深色主题颜色 - 与列表模式统一 + const containerBg = useColorModeValue("gray.100", "gray.900"); const cardBg = useColorModeValue("white", "gray.800"); - const cardBorderColor = useColorModeValue("gray.200", "gray.600"); + const cardBorderColor = useColorModeValue("gray.200", "gray.700"); const headerBg = useColorModeValue("gray.50", "gray.750"); const headerHoverBg = useColorModeValue("gray.100", "gray.700"); const textColor = useColorModeValue("gray.800", "gray.100"); const secondaryTextColor = useColorModeValue("gray.600", "gray.400"); const timelineLineColor = useColorModeValue("blue.300", "blue.500"); const timelineDotBg = useColorModeValue("blue.500", "blue.400"); - const scrollbarTrackBg = useColorModeValue("#f1f1f1", "#2D3748"); - const scrollbarThumbBg = useColorModeValue("#888", "#4A5568"); - const scrollbarThumbHoverBg = useColorModeValue("#555", "#718096"); + const scrollbarTrackBg = useColorModeValue("#e2e8f0", "#1a202c"); + const scrollbarThumbBg = useColorModeValue("#a0aec0", "#4a5568"); + const scrollbarThumbHoverBg = useColorModeValue("#718096", "#718096"); + const statBarBg = useColorModeValue("gray.200", "gray.800"); // 根据主线类型获取配色 const getColorScheme = useCallback((lv2Name) => { @@ -189,10 +191,10 @@ const MainlineTimelineViewComponent = forwardRef( mainlines: sortedMainlines, }); - // 初始化展开状态(默认展开前5个) + // 初始化展开状态(默认全部折叠,方便一目了然对比) const initialExpanded = {}; - sortedMainlines.slice(0, 5).forEach((mainline) => { - initialExpanded[mainline.lv2_id] = true; + sortedMainlines.forEach((mainline) => { + initialExpanded[mainline.lv2_id] = false; }); setExpandedGroups(initialExpanded); } else { @@ -245,7 +247,7 @@ const MainlineTimelineViewComponent = forwardRef( // 渲染加载状态 if (loading) { return ( - +
@@ -259,7 +261,7 @@ const MainlineTimelineViewComponent = forwardRef( // 渲染错误状态 if (error) { return ( - +
加载失败: {error} @@ -278,7 +280,7 @@ const MainlineTimelineViewComponent = forwardRef( // 渲染空状态 if (!mainlineData?.mainlines?.length) { return ( - +
@@ -305,17 +307,15 @@ const MainlineTimelineViewComponent = forwardRef( overflowY="auto" h="100%" w="100%" - px={2} - py={2} + bg={containerBg} css={{ - "&::-webkit-scrollbar": { width: "6px" }, + "&::-webkit-scrollbar": { width: "8px" }, "&::-webkit-scrollbar-track": { background: scrollbarTrackBg, - borderRadius: "10px", }, "&::-webkit-scrollbar-thumb": { background: scrollbarThumbBg, - borderRadius: "10px", + borderRadius: "4px", }, "&::-webkit-scrollbar-thumb:hover": { background: scrollbarThumbHoverBg, @@ -323,32 +323,33 @@ const MainlineTimelineViewComponent = forwardRef( scrollBehavior: "smooth", }} > - {/* 顶部统计信息 */} + {/* 顶部统计栏 */} - - + + {mainline_count} 条主线 - {total_events} 个事件 + 共 {total_events} 个事件 {ungrouped_count > 0 && ( - - ({ungrouped_count} 个未归类) - + + {ungrouped_count} 个未归类 + )} @@ -356,17 +357,19 @@ const MainlineTimelineViewComponent = forwardRef( } - size="xs" + size="sm" variant="ghost" + colorScheme="gray" onClick={() => toggleAll(true)} aria-label="全部展开" /> } - size="xs" + icon={} + size="sm" variant="ghost" + colorScheme="gray" onClick={() => toggleAll(false)} aria-label="全部折叠" /> @@ -374,8 +377,9 @@ const MainlineTimelineViewComponent = forwardRef( } - size="xs" + size="sm" variant="ghost" + colorScheme="gray" onClick={fetchMainlineData} aria-label="刷新" /> @@ -383,57 +387,49 @@ const MainlineTimelineViewComponent = forwardRef( - {/* 主线卡片列表 */} - - {mainlines.map((mainline) => { - const colorScheme = getColorScheme(mainline.lv2_name); - const isExpanded = expandedGroups[mainline.lv2_id]; + {/* 主线卡片网格 - 横向布局 */} + + + {mainlines.map((mainline) => { + const colorScheme = getColorScheme(mainline.lv2_name); + const isExpanded = expandedGroups[mainline.lv2_id]; - return ( - - {/* 卡片头部 - 概念名称 */} - toggleGroup(mainline.lv2_id)} + return ( + - - - - - + {/* 卡片头部 */} + toggleGroup(mainline.lv2_id)} + _hover={{ bg: headerHoverBg }} + transition="all 0.15s" + > + + {mainline.lv2_name || "其他"} @@ -442,85 +438,112 @@ const MainlineTimelineViewComponent = forwardRef( fontSize="xs" borderRadius="full" px={2} + flexShrink={0} > - {mainline.event_count} 条 + {mainline.event_count} {mainline.lv1_name && ( - + {mainline.lv1_name} )} - - - - {/* 卡片内容 - 时间轴事件列表 */} - - - {/* 时间轴线 */} - + - {/* 事件列表 */} - - {mainline.events.map((event, eventIndex) => ( - - {/* 时间轴圆点 */} - - {/* 事件卡片 */} - { - onEventSelect?.(clickedEvent); - }} - onTitleClick={(e) => { - e.preventDefault(); - e.stopPropagation(); - onEventSelect?.(event); - }} - onToggleFollow={() => onToggleFollow?.(event.id)} - borderColor={borderColor} - /> - - ))} - - - - - ); - })} - + {/* 展开的事件列表 */} + + + {/* 时间轴线 */} + + + {/* 事件列表 */} + + {mainline.events.map((event, eventIndex) => ( + + {/* 时间轴圆点 */} + + {/* 事件卡片 */} + { + onEventSelect?.(clickedEvent); + }} + onTitleClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + onEventSelect?.(event); + }} + onToggleFollow={() => onToggleFollow?.(event.id)} + borderColor={borderColor} + compact + /> + + ))} + + + + + ); + })} + + ); }