From f0722560212afb866eed1b627c7c43da15e17019 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Mon, 27 Oct 2025 17:46:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(EventList):=20=E9=87=8D=E6=9E=84=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E5=92=8CUI=20-=20=E7=B2=BE=E7=AE=80/=E8=AF=A6?= =?UTF-8?q?=E7=BB=86=E6=A8=A1=E5=BC=8F=E4=BC=98=E5=8C=96=E3=80=81=E6=8E=A8?= =?UTF-8?q?=E9=80=81=E6=8E=A7=E5=88=B6=E3=80=81=E6=8F=8F=E8=BF=B0=E5=B1=95?= =?UTF-8?q?=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **主要变更**: 1. **渲染函数重构**: - 重写 renderCompactEvent:标题2行+标签内联+按钮右侧布局 - 重写 renderDetailedEvent:标题+优先级+统计+价格标签+时间作者 - 添加 getTimelineBoxStyle 函数统一时间轴样式 - renderCompactEvent 支持隔行变色(index % 2) 2. **顶部控制栏全面升级**: - 改为 sticky 定位,全宽白色背景 - 左侧占位,中间嵌入分页器,右侧控制按钮 - 新增桌面推送开关(使用 handlePushToggle) - WebSocket 状态简化为 🟢实时/🔴离线 - 精简模式切换改为 xs 尺寸 3. **描述展开/收起功能**: - 详细模式支持长描述(>120字符)展开/收起 - 使用 expandedDescriptions 状态管理 - noOfLines 动态切换 4. **统一时间格式**: - 所有时间显示统一为 YYYY-MM-DD HH:mm **效果**: - 精简模式更紧凑,信息密度更高 - 详细模式布局更清晰,价格标签更易读 - 顶部控制栏功能集中,操作更便捷 - 推送权限管理可视化 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/views/Community/components/EventList.js | 908 ++++++++++++-------- 1 file changed, 530 insertions(+), 378 deletions(-) diff --git a/src/views/Community/components/EventList.js b/src/views/Community/components/EventList.js index 9a2a4943..71a31750 100644 --- a/src/views/Community/components/EventList.js +++ b/src/views/Community/components/EventList.js @@ -413,124 +413,208 @@ const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetai navigate(`/event-detail/${eventId}`); }; - // 精简模式的事件渲染 - const renderCompactEvent = (event) => { + // 时间轴样式配置(固定使用轻量卡片样式) + const getTimelineBoxStyle = () => { + return { + bg: useColorModeValue('gray.50', 'gray.700'), + borderColor: useColorModeValue('gray.400', 'gray.500'), + borderWidth: '2px', + textColor: useColorModeValue('blue.600', 'blue.400'), + boxShadow: 'sm', + }; + }; + + // 精简模式的事件渲染(优化版:标题2行+标签内联+按钮右侧) + const renderCompactEvent = (event, index) => { const importance = getImportanceConfig(event.importance); const isFollowing = !!followingMap[event.id]; const followerCount = followCountMap[event.id] ?? (event.follower_count || 0); + const timelineStyle = getTimelineBoxStyle(); return ( - - {/* 时间线和重要性标记 */} - - + {/* 左侧时间轴 - 动态样式 */} + + {/* 时间长方形卡片 */} + - {event.importance || 'C'} - + {/* 日期 YYYY-MM-DD */} + + {moment(event.created_at).format('YYYY-MM-DD')} + + {/* 时间 HH:mm */} + + {moment(event.created_at).format('HH:mm')} + + + {/* 时间轴竖线 */} - {/* 精简事件卡片 */} + {/* 右侧内容卡片 */} onEventClick(event)} - mb={3} + mb={2} > - - - {/* 左侧:标题和时间 */} - - handleTitleClick(e, event)} - cursor="pointer" - noOfLines={1} - > - {event.title} - - - - {moment(event.created_at).format('MM-DD HH:mm')} - - {event.creator?.username || 'Anonymous'} - - - - {/* 右侧:涨跌幅指标 */} - - - + + {/* 第一行:标题(2行)+ 标签(内联)+ 按钮(右侧) */} + + {/* 标题区域:标题+标签(内联) */} + + handleTitleClick(e, event)} + cursor="pointer" + > + {event.title} + + {' '} + {/* 重要性标签 - 内联 */} + - - - + {' '} + {/* 涨跌幅标签 - 内联 */} + {event.related_avg_chg != null && ( + + 0 ? 'red' : 'green'} + fontSize="xs" + px={2} + py={1} + borderRadius="md" fontWeight="bold" - color={getPriceChangeColor(event.related_avg_chg)} + display="inline-flex" + alignItems="center" + gap={1} + verticalAlign="middle" > - {event.related_avg_chg != null - ? `${event.related_avg_chg > 0 ? '+' : ''}${event.related_avg_chg.toFixed(2)}%` - : '--'} - - - - + + {event.related_avg_chg > 0 ? '+' : ''}{event.related_avg_chg.toFixed(2)}% + + + )} + - - - - + {/* 操作按钮 - 固定右侧 */} + + + + + + + {/* 第二行:统计数据(左) + 作者时间(右) */} + + {/* 左侧:统计数据 */} + + + + + {event.view_count || 0} + + + + + + + {event.post_count || 0} + + + + + + + {followerCount} + + + + + {/* 右侧:作者 + 时间(统一格式 YYYY-MM-DD HH:mm) */} + + @{event.creator?.username || 'Anonymous'} + + + {moment(event.created_at).format('YYYY-MM-DD HH:mm')} + + + + @@ -542,28 +626,52 @@ const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetai const importance = getImportanceConfig(event.importance); const isFollowing = !!followingMap[event.id]; const followerCount = followCountMap[event.id] ?? (event.follower_count || 0); + const timelineStyle = getTimelineBoxStyle(); return ( - - {/* 时间线和重要性标记 */} - - + {/* 左侧时间轴 - 动态样式 */} + + {/* 时间长方形卡片 */} + - {event.importance || 'C'} - + {/* 日期 YYYY-MM-DD */} + + {moment(event.created_at).format('YYYY-MM-DD')} + + {/* 时间 HH:mm */} + + {moment(event.created_at).format('HH:mm')} + + + {/* 时间轴竖线 */} @@ -573,264 +681,122 @@ const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetai bg={cardBg} borderWidth="1px" borderColor={borderColor} - borderRadius="lg" + borderRadius="md" boxShadow="sm" _hover={{ - boxShadow: 'md', - transform: 'translateY(-2px)', + boxShadow: 'xl', + transform: 'translateY(-3px)', borderColor: importance.color, }} - transition="all 0.2s" + transition="all 0.3s ease" cursor="pointer" onClick={() => onEventClick(event)} - mb={4} + mb={3} > - - - {/* 标题和重要性标签 */} - - - handleTitleClick(e, event)} - cursor="pointer" + + + {/* 第一行:标题+优先级 | 统计+关注 */} + + {/* 左侧:标题 + 优先级标签 */} + + - {event.title} - - - - - 重要性等级说明 - - - {getAllImportanceLevels().map((level) => ( - - - - {level.level}级 - {level.description} - - - ))} - - } - placement="left" - hasArrow - bg="white" - color="gray.800" - fontSize="md" - p={3} - borderRadius="lg" - borderWidth="1px" - borderColor="gray.200" - boxShadow="lg" - > - handleTitleClick(e, event)} + cursor="pointer" + > + {event.title} + + + + + + 重要性等级说明 + + + {getAllImportanceLevels().map((level) => ( + + + + {level.level}级 + {level.description} + + + ))} + + } + placement="top" + hasArrow + bg="white" + color="gray.800" + fontSize="md" + p={3} + borderRadius="lg" + borderWidth="1px" + borderColor="gray.200" + boxShadow="lg" > - - {importance.label}优先级 - - - - - {/* 元信息 */} - - - - {moment(event.created_at).format('YYYY-MM-DD HH:mm')} - - - {event.creator?.username || 'Anonymous'} - - - {/* 描述 */} - - {event.description} - - - {/* 价格变化指标 */} - - - - - - - 平均 - - - {event.related_avg_chg != null ? ( - - - - {event.related_avg_chg > 0 ? '+' : ''}{event.related_avg_chg.toFixed(2)}% - - - ) : ( - -- - )} - - - - - - - - - - 最大 - - - {event.related_max_chg != null ? ( - - - - {event.related_max_chg > 0 ? '+' : ''}{event.related_max_chg.toFixed(2)}% - - - ) : ( - -- - )} - - - - - - - - - - 周 - - - {event.related_week_chg != null ? ( - - - - {event.related_week_chg > 0 ? '+' : ''}{event.related_week_chg.toFixed(2)}% - - - ) : ( - -- - )} - - - - - - - - - - {/* 统计信息和操作按钮 */} - - - - - - {event.view_count || 0} - - - - - - {event.post_count || 0} - - - - - - {followerCount} - + + {event.importance || 'C'}级 + - - - + {/* 右侧:统计数据 + 关注按钮 */} + + {/* 统计数据 */} + + + + + {event.view_count || 0} + + + + + + {event.post_count || 0} + + + + + + {followerCount} + + + + + {/* 关注按钮 */} - + + + {/* 第二行:价格标签 | 时间+作者 */} + + {/* 左侧:价格标签 */} + + {/* 平均涨幅 - 始终显示,无数据时显示 -- */} + 0 ? 'red' : event.related_avg_chg < 0 ? 'green' : 'gray') + : 'gray'} + fontSize="xs" + px={2} + py={0.5} + borderRadius="md" + cursor="pointer" + _hover={{ transform: 'scale(1.05)', boxShadow: 'md' }} + transition="all 0.2s" + > + + 平均 + + {event.related_avg_chg != null + ? `${event.related_avg_chg > 0 ? '+' : ''}${event.related_avg_chg.toFixed(2)}%` + : '--'} + + + + + {/* 最大涨幅 - 始终显示,无数据时显示 -- */} + 0 ? 'red' : event.related_max_chg < 0 ? 'green' : 'gray') + : 'gray'} + fontSize="xs" + px={2} + py={0.5} + borderRadius="md" + cursor="pointer" + _hover={{ transform: 'scale(1.05)', boxShadow: 'md' }} + transition="all 0.2s" + > + + 最大 + + {event.related_max_chg != null + ? `${event.related_max_chg > 0 ? '+' : ''}${event.related_max_chg.toFixed(2)}%` + : '--'} + + + + + {/* 周涨幅 - 始终显示,无数据时显示 -- */} + 0 ? 'red' : event.related_week_chg < 0 ? 'green' : 'gray') + : 'gray'} + fontSize="xs" + px={2} + py={0.5} + borderRadius="md" + cursor="pointer" + _hover={{ transform: 'scale(1.05)', boxShadow: 'md' }} + transition="all 0.2s" + > + + + {event.related_week_chg != null && } + + {event.related_week_chg != null + ? `${event.related_week_chg > 0 ? '+' : ''}${event.related_week_chg.toFixed(2)}%` + : '--'} + + + + + + {/* 右侧:时间 + 作者 */} + + + {moment(event.created_at).format('YYYY-MM-DD HH:mm')} + + + @{event.creator?.username || 'Anonymous'} + + + + {/* 第三行:描述文字 + 展开/收起 */} + {event.description && ( + + + {event.description} + + {event.description.length > 120 && ( + + )} + + )} @@ -946,47 +1028,117 @@ const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetai return ( - - {/* 顶部控制栏:连接状态 + 视图切换 */} - - {/* WebSocket 连接状态指示器 */} - - - {isConnected ? '🟢 实时推送已开启' : '🔴 实时推送未连接'} - - {isConnected && ( - - 新事件将自动推送 - + {/* 顶部控制栏:左空白 + 中间分页器 + 右侧控制(固定sticky) - 铺满全宽 */} + + + + {/* 左侧占位 */} + + + {/* 中间:分页器 */} + {pagination.total > 0 && localEvents.length > 0 ? ( + + + + 第 {pagination.current} / {Math.ceil(pagination.total / pagination.pageSize)} 页 + + + + 共 {pagination.total} 条 + + + ) : ( + )} - - {/* 视图切换控制 */} - - - 精简模式 - - setIsCompactMode(e.target.checked)} - colorScheme="blue" - /> - - + {/* 右侧:控制按钮 */} + + {/* WebSocket 连接状态 */} + + {isConnected ? '🟢 实时' : '🔴 离线'} + + {/* 桌面推送开关 */} + + + 推送 + + + + + + + {/* 视图切换控制 */} + + + 精简 + + setIsCompactMode(e.target.checked)} + colorScheme="blue" + /> + + + + + + + {/* 事件列表内容 */} + {localEvents.length > 0 ? ( {localEvents.map((event, index) => ( {isCompactMode - ? renderCompactEvent(event) + ? renderCompactEvent(event, index) : renderDetailedEvent(event) }