From 4a0194e26c4561f12fedd8d37fd9bbc29fd4edb5 Mon Sep 17 00:00:00 2001
From: zdl <3489966805@qq.com>
Date: Thu, 30 Oct 2025 12:15:55 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=E4=B8=BB=E7=BB=84?=
=?UTF-8?q?=E4=BB=B6=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=E2=94=82?=
=?UTF-8?q?=20=E2=94=82=20=E2=94=82=20=E2=94=82=20-=20=E2=9D=8C=20?=
=?UTF-8?q?=E7=A7=BB=E9=99=A4=20renderPriceChange=20=E5=87=BD=E6=95=B0?=
=?UTF-8?q?=EF=BC=8860=E8=A1=8C=EF=BC=89=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=E2=94=82=20?=
=?UTF-8?q?=E2=94=82=20=E2=94=82=20=E2=94=82=20-=20=E2=9D=8C=20=E7=A7=BB?=
=?UTF-8?q?=E9=99=A4=20renderCompactEvent=20=E5=87=BD=E6=95=B0=EF=BC=88200?=
=?UTF-8?q?=E8=A1=8C=EF=BC=89=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=E2=94=82=20=E2=94=82=20=E2=94=82?=
=?UTF-8?q?=20=E2=94=82=20-=20=E2=9D=8C=20=E7=A7=BB=E9=99=A4=20renderDetai?=
=?UTF-8?q?ledEvent=20=E5=87=BD=E6=95=B0=EF=BC=88300=E8=A1=8C=EF=BC=89=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=E2=94=82=20=E2=94=82=20=E2=94=82=20=E2=94=82=20-=20?=
=?UTF-8?q?=E2=9D=8C=20=E7=A7=BB=E9=99=A4=20expandedDescriptions=20state?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=E2=94=82=20=E2=94=82=20=E2=94=82?=
=?UTF-8?q?=20=E2=94=82=20-=20=E2=9D=8C=20=E7=B2=BE=E7=AE=80=20Chakra=20UI?=
=?UTF-8?q?=20=E5=AF=BC=E5=85=A5=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=E2=94=82=20=E2=94=82=20=E2=94=82=20?=
=?UTF-8?q?=E2=94=82=20-=20=E2=9C=85=20=E4=BD=BF=E7=94=A8=20EventCard=20?=
=?UTF-8?q?=E7=BB=84=E4=BB=B6=E7=BB=9F=E4=B8=80=E6=B8=B2=E6=9F=93=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?=
=?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=E2=94=82=20=E2=94=82=20?=
=?UTF-8?q?=E2=94=82=20=E2=94=82=20-=20=E2=9C=85=20=E4=BF=9D=E7=95=99?=
=?UTF-8?q?=E6=89=80=E6=9C=89=E4=B8=9A=E5=8A=A1=E9=80=BB=E8=BE=91=EF=BC=88?=
=?UTF-8?q?WebSocket=E3=80=81=E9=80=9A=E7=9F=A5=E3=80=81=E5=85=B3=E6=B3=A8?=
=?UTF-8?q?=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/Community/components/EventList.js | 634 +-------------------
1 file changed, 18 insertions(+), 616 deletions(-)
diff --git a/src/views/Community/components/EventList.js b/src/views/Community/components/EventList.js
index 9208c8de..2555548f 100644
--- a/src/views/Community/components/EventList.js
+++ b/src/views/Community/components/EventList.js
@@ -7,68 +7,28 @@ import {
Text,
Button,
Badge,
- Tag,
- TagLabel,
- TagLeftIcon,
Flex,
- Avatar,
- Tooltip,
- IconButton,
- Divider,
Container,
useColorModeValue,
- Circle,
- Stat,
- StatNumber,
- StatHelpText,
- StatArrow,
- ButtonGroup,
- Heading,
- SimpleGrid,
- Card,
- CardBody,
- Center,
- Link,
- Spacer,
Switch,
FormControl,
FormLabel,
useToast,
+ Center,
} from '@chakra-ui/react';
-import {
- ViewIcon,
- ChatIcon,
- StarIcon,
- TimeIcon,
- InfoIcon,
- WarningIcon,
- WarningTwoIcon,
- CheckCircleIcon,
- ArrowForwardIcon,
- ExternalLinkIcon,
- ViewOffIcon,
-} from '@chakra-ui/icons';
+import { InfoIcon } from '@chakra-ui/icons';
import { useNavigate } from 'react-router-dom';
-import moment from 'moment';
// 导入工具函数和常量
import { logger } from '../../../utils/logger';
import { getApiBase } from '../../../utils/apiConfig';
import { useEventNotifications } from '../../../hooks/useEventNotifications';
-import { getImportanceConfig, getAllImportanceLevels } from '../../../constants/importanceLevels';
import { browserNotificationService } from '../../../services/browserNotificationService';
import { useNotification } from '../../../contexts/NotificationContext';
+import { getImportanceConfig } from '../../../constants/importanceLevels';
-// 导入价格相关工具函数
-import {
- getPriceChangeColor,
- getPriceChangeBg,
- getPriceChangeBorderColor,
- PriceArrow,
-} from '../../../utils/priceFormatters';
-
-// 导入动画定义
-import { pulseAnimation } from '../../../constants/animations';
+// 导入子组件
+import EventCard from './EventCard';
// ========== 主组件 ==========
const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetail }) => {
@@ -78,7 +38,6 @@ const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetai
const [followingMap, setFollowingMap] = useState({});
const [followCountMap, setFollowCountMap] = useState({});
const [localEvents, setLocalEvents] = useState(events); // 用于实时更新的本地事件列表
- const [expandedDescriptions, setExpandedDescriptions] = useState({}); // 描述展开状态映射
// 从 NotificationContext 获取推送权限相关状态和方法
const { browserPermission, requestBrowserPermission } = useNotification();
@@ -265,67 +224,6 @@ const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetai
const linkColor = useColorModeValue('blue.600', 'blue.400');
const hoverBg = useColorModeValue('gray.50', 'gray.700');
- const renderPriceChange = (value, label) => {
- if (value === null || value === undefined) {
- return (
-
- {label}: --
-
- );
- }
-
- const absValue = Math.abs(value);
- const isPositive = value > 0;
-
- // 根据涨跌幅大小选择不同的颜色深浅
- let colorScheme = 'gray';
- let variant = 'solid';
-
- if (isPositive) {
- // 上涨用红色系
- if (absValue >= 3) {
- colorScheme = 'red';
- variant = 'solid'; // 深色
- } else if (absValue >= 1) {
- colorScheme = 'red';
- variant = 'subtle'; // 中等
- } else {
- colorScheme = 'red';
- variant = 'outline'; // 浅色
- }
- } else {
- // 下跌用绿色系
- if (absValue >= 3) {
- colorScheme = 'green';
- variant = 'solid'; // 深色
- } else if (absValue >= 1) {
- colorScheme = 'green';
- variant = 'subtle'; // 中等
- } else {
- colorScheme = 'green';
- variant = 'outline'; // 浅色
- }
- }
-
- const Icon = isPositive ? TriangleUpIcon : TriangleDownIcon;
-
- return (
-
-
-
- {label}: {isPositive ? '+' : ''}{value.toFixed(2)}%
-
-
- );
- };
const handleTitleClick = (e, event) => {
e.preventDefault();
@@ -349,511 +247,6 @@ const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetai
};
};
- // 精简模式的事件渲染(优化版:标题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 (
-
- {/* 左侧时间轴 - 动态样式 */}
-
- {/* 时间长方形卡片 */}
-
- {/* 日期 YYYY-MM-DD */}
-
- {moment(event.created_at).format('YYYY-MM-DD')}
-
- {/* 时间 HH:mm */}
-
- {moment(event.created_at).format('HH:mm')}
-
-
- {/* 时间轴竖线 */}
-
-
-
- {/* 右侧内容卡片 */}
- onEventClick(event)}
- mb={2}
- >
-
-
- {/* 第一行:标题(2行)+ 标签(内联)+ 按钮(右侧) */}
-
- {/* 标题区域:标题+标签(内联) */}
-
- handleTitleClick(e, event)}
- cursor="pointer"
- >
- {event.title}
-
- {' '}
- {/* 重要性标签 - 内联 */}
-
- {event.importance || 'C'}级
-
- {' '}
- {/* 涨跌幅标签 - 内联 */}
- {event.related_avg_chg != null && (
-
- 0 ? 'red' : 'green'}
- fontSize="xs"
- px={2}
- py={1}
- borderRadius="md"
- fontWeight="bold"
- display="inline-flex"
- alignItems="center"
- gap={1}
- verticalAlign="middle"
- >
-
- {event.related_avg_chg > 0 ? '+' : ''}{event.related_avg_chg.toFixed(2)}%
-
-
- )}
-
-
- {/* 操作按钮 - 固定右侧 */}
-
-
- }
- onClick={(e) => {
- e.stopPropagation();
- toggleFollow(event.id);
- }}
- >
- {isFollowing ? '已关注' : '关注'}
- {followerCount > 0 && `(${followerCount})`}
-
-
-
-
- {/* 第二行:统计数据(左) + 作者时间(右) */}
-
- {/* 左侧:统计数据 */}
-
-
-
-
- {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')}
-
-
-
-
-
-
-
- );
- };
-
- // 详细模式的事件渲染(原有的渲染方式,但修复了箭头颜色)
- const renderDetailedEvent = (event) => {
- const importance = getImportanceConfig(event.importance);
- const isFollowing = !!followingMap[event.id];
- const followerCount = followCountMap[event.id] ?? (event.follower_count || 0);
- const timelineStyle = getTimelineBoxStyle();
-
- return (
-
- {/* 左侧时间轴 - 动态样式 */}
-
- {/* 时间长方形卡片 */}
-
- {/* 日期 YYYY-MM-DD */}
-
- {moment(event.created_at).format('YYYY-MM-DD')}
-
- {/* 时间 HH:mm */}
-
- {moment(event.created_at).format('HH:mm')}
-
-
- {/* 时间轴竖线 */}
-
-
-
- {/* 事件卡片 */}
- onEventClick(event)}
- mb={3}
- >
-
-
- {/* 第一行:标题+优先级 | 统计+关注 */}
-
- {/* 左侧:标题 + 优先级标签 */}
-
-
- 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"
- >
-
-
- {event.importance || 'C'}级
-
-
-
-
- {/* 右侧:统计数据 + 关注按钮 */}
-
- {/* 统计数据 */}
-
-
-
-
- {event.view_count || 0}
-
-
-
-
-
- {event.post_count || 0}
-
-
-
-
-
- {followerCount}
-
-
-
-
- {/* 关注按钮 */}
- }
- onClick={(e) => {
- e.stopPropagation();
- toggleFollow(event.id);
- }}
- >
- {isFollowing ? '已关注' : '关注'}
-
-
-
-
- {/* 第二行:价格标签 | 时间+作者 */}
-
- {/* 左侧:价格标签 */}
-
- {/* 平均涨幅 - 始终显示,无数据时显示 -- */}
- 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 && (
-
- )}
-
- )}
-
-
-
-
- );
- };
-
// 分页组件
const Pagination = ({ current, total, pageSize, onChange }) => {
const totalPages = Math.ceil(total / pageSize);
@@ -1062,10 +455,19 @@ const EventList = ({ events, pagination, onPageChange, onEventClick, onViewDetai
{localEvents.map((event, index) => (
- {isCompactMode
- ? renderCompactEvent(event, index)
- : renderDetailedEvent(event)
- }
+
))}