Files
vf_react/docs/NOTIFICATION_SYSTEM.md
zdl e555d22499 refactor(socket): 移除 Mock Socket 服务并简化导出逻辑
- 删除 mockSocketService.js(916 行)
- 简化 socket/index.js(365 行 → 19 行)
- 移除 Mock/Real 服务选择逻辑
- 移除 SOCKET_TYPE 和 useMock 标识
- 移除全局调试 API(迁移到 src/devtools/)
- 更新相关文档说明 Mock Socket 已移除

现在仅使用真实 Socket.IO 服务连接后端,代码更简洁清晰。

🔧 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 17:25:45 +08:00

55 KiB
Raw Permalink Blame History

实时消息推送系统 - 完整技术文档

版本: v2.11.0 更新日期: 2025-01-10 文档类型: 快速入门 + 完整技术规格

⚠️ 重要更新: Mock Socket 已移除2025-01-10文档中关于 mockSocketService 的内容仅供历史参考。


📑 目录

第一部分:快速入门

  1. 系统简介
  2. 核心特性
  3. 5分钟快速开始
  4. 基础使用示例

第二部分:系统架构

  1. 整体架构设计
  2. 技术栈选型
  3. 数据流向
  4. 双重通知策略

第三部分:核心组件详解

  1. 组件清单
  2. NotificationContext
  3. NotificationContainer
  4. SocketService
  5. 其他核心组件

第四部分:设计流程

  1. 消息推送完整流程
  2. 初始化流程
  3. 消息接收与适配
  4. 通知分发策略
  5. 性能监控埋点

第五部分:测试指南

  1. 测试快速指南
  2. 手动测试清单
  3. 自动化测试
  4. 测试覆盖率

第六部分:配置与扩展

  1. 通知类型配置
  2. 优先级配置
  3. 环境配置
  4. 后端集成

第七部分:故障排查

  1. 常见问题FAQ
  2. 调试工具
  3. 日志分析

第八部分:最佳实践

  1. 开发规范
  2. 性能优化
  3. 安全注意事项

附录

  1. 更新日志
  2. 文件结构

🆕 最新更新 (v2.11.0 - Socket 连接优化)

优化内容

1. 指数退避策略 🔄

  • 智能重连间隔:从"激进"改为"渐进"策略
    • Real Socket: 第1次 1分钟 → 第2次 2分钟 → 第3次+ 4分钟
    • Mock Socket: 第1次 10秒 → 第2次 20秒 → 第3次+ 40秒缩短10倍便于测试
  • 无限重试不再在5次后停止持续使用指数退避重连
  • 自定义退避逻辑:禁用 Socket.IO 默认重连机制,实现更可控的重连策略

2. 连接状态横幅优化 📍

  • 降低侵入性zIndex 从 10000 → 1050高度 py={3} → py={2}半透明背景opacity 0.95
  • 手动关闭所有状态DISCONNECTED/RECONNECTING/FAILED都可手动关闭
  • 状态持久化:用户关闭后保存到 localStorage重连成功后自动清除
  • 自动消失:重连成功显示"✓ 已重新连接" 2秒后自动消失

3. Mock 模式测试功能 🧪

  • 断线重连模拟__mockSocket.simulateDisconnection() - 模拟意外断线,自动重连
  • 连接状态查询__mockSocket.isConnected() - 查看当前连接状态
  • 手动重连__mockSocket.reconnect() - 立即触发重连
  • 控制台提示:开发模式启动时自动显示可用测试函数

📋 系统概述

本系统是专为金融资讯场景设计的实时消息推送系统,支持 Mock 模式(开发)和真实 Socket.IO 模式(生产)。消息以右下角层叠弹窗的形式显示,新消息在最上方,符合主流桌面应用的交互习惯。

核心特性

  • 双通知系统:网页通知 + 浏览器原生通知,智能分发
  • 4 种通知类型:公告通知、股票动向、事件动向、分析报告
  • 3 级优先级紧急不关闭、重要30秒、普通15秒
  • 智能折叠最多显示3条超过显示展开按钮
  • 智能配色:股票动向根据涨跌自动变色(涨红 🔴 / 跌绿 🟢
  • 丰富元数据发布时间、作者、AI 标识
  • 点击跳转:可配置点击跳转链接
  • 队列管理:最多保留 15 条历史,可展开查看
  • 性能监控:自动追踪到达率、点击率、响应时间
  • 历史记录:持久化存储、筛选、搜索、导出功能

技术亮点

  • WebSocket 实时通信Socket.IO + 指数退避重连策略
  • 双重去重机制Socket层去重 + 显示层去重
  • 智能权限引导:渐进式权限请求,避免打扰用户
  • 无障碍支持:完整的 ARIA 属性,键盘导航
  • 性能优化React.memo、useMemo、useCallbackGPU 加速动画

🏗️ 系统架构设计

整体架构图

graph TB
    subgraph "前端应用"
        A[App.js] --> B[AppProviders]
        B --> C[NotificationProvider<br/>NotificationContext]
        C --> D[NotificationContainer<br/>通知容器UI]
        C --> E[NotificationTestTool<br/>开发测试工具]
    end

    subgraph "通知系统核心"
        C --> F[Socket Service<br/>WebSocket连接]
        F --> G{环境判断}
        G -->|Mock| H[mockSocketService<br/>模拟服务]
        G -->|Real| I[socketService<br/>生产服务]

        C --> J[browserNotificationService<br/>浏览器通知]
        C --> K[notificationHistoryService<br/>历史记录]
        C --> L[notificationMetricsService<br/>性能监控]
    end

    subgraph "后端服务"
        I --> M[Flask Backend<br/>Socket.IO Server]
        M --> N[(ClickHouse<br/>事件数据)]
        M --> O[(MySQL<br/>用户数据)]
    end

    subgraph "数据存储"
        K --> P[(localStorage<br/>历史记录)]
        L --> Q[(localStorage<br/>性能指标)]
    end

    style C fill:#f9f,stroke:#333,stroke-width:3px
    style D fill:#bbf,stroke:#333,stroke-width:2px
    style F fill:#bfb,stroke:#333,stroke-width:2px

技术栈选型

前端技术栈

  • React 18.3.1: 并发渲染、Suspense、自动批处理
  • Chakra UI 2.8.2: 可访问性优先、主题定制、响应式设计
  • Socket.IO Client 4.7.4: WebSocket实时通信、自动重连
  • React Router v6: 客户端路由、编程式导航
  • Framer Motion: 流畅动画、布局动画
  • React Icons: Material Design 图标

后端技术栈

  • Flask + Flask-SocketIO: Python WebSocket服务器
  • ClickHouse: 时序数据分析(事件数据、性能指标)
  • MySQL/PostgreSQL: 用户数据、订阅关系
  • Redis + Celery: 消息队列、异步任务

数据流向

sequenceDiagram
    participant B as 后端服务器
    participant S as Socket Service
    participant C as NotificationContext
    participant D as 通知分发器
    participant W as 网页通知
    participant N as 浏览器通知
    participant H as History Service
    participant M as Metrics Service

    B->>S: 推送事件数据
    S->>S: Socket层去重检查
    S->>C: 触发 new_event
    C->>C: 适配后端格式→前端格式
    C->>C: 显示层去重检查

    C->>D: 分发通知

    alt 页面在前台
        D->>W: 显示网页通知
        W->>H: 保存历史记录
        W->>M: 记录性能指标
    else 页面在后台
        D->>N: 显示浏览器通知
        N->>H: 保存历史记录
        N->>M: 记录性能指标
    end

    Note over W,N: 用户点击通知
    W->>M: 追踪点击事件
    W->>C: 导航到详情页

双重通知策略

系统根据通知优先级页面可见性智能选择通知方式:

优先级 页面在前台 页面在后台
紧急 (Urgent) 网页通知 + 浏览器通知 网页通知 + 浏览器通知
重要 (Important) 网页通知 浏览器通知
普通 (Normal) 网页通知 网页通知

设计理念

  • 紧急通知:双重保障,确保用户不会错过
  • 重要通知:根据用户注意力分配渠道(前台看得到网页,后台需要系统通知)
  • 普通通知:避免过度打扰,仅网页内显示

🧩 核心组件清单

组件名 类型 职责 文件路径
NotificationContext React Context 通知系统核心逻辑、状态管理 src/contexts/NotificationContext.js
NotificationContainer React Component 通知UI容器、动画、交互 src/components/NotificationContainer/index.js
NotificationTestTool React Component 开发测试工具 src/components/NotificationTestTool/index.js
socketService Service Class 真实WebSocket连接管理 src/services/socketService.js
mockSocketService Service Class Mock WebSocket模拟 src/services/mockSocketService.js
browserNotificationService Service Class 浏览器通知API封装 src/services/browserNotificationService.js
notificationHistoryService Service Class 历史记录持久化 src/services/notificationHistoryService.js
notificationMetricsService Service Class 性能监控埋点 src/services/notificationMetricsService.js
notificationTypes Constants 类型定义、配置常量 src/constants/notificationTypes.js
useEventNotifications Custom Hook 事件订阅Hook src/hooks/useEventNotifications.js

1. NotificationContext - 通知上下文

职责:通知系统的大脑,管理所有状态和业务逻辑。

核心功能

  • WebSocket 连接管理(连接、断开、重连)
  • 通知队列管理(添加、移除、去重)
  • 权限管理(浏览器通知权限请求)
  • 通知分发(网页/浏览器通知智能选择)
  • 音效播放
  • 性能监控埋点

主要API

const {
  notifications,           // 当前通知队列
  isConnected,            // Socket连接状态
  soundEnabled,           // 音效开关状态
  browserPermission,      // 浏览器通知权限状态
  connectionStatus,       // 详细连接状态
  addNotification,        // 添加通知
  removeNotification,     // 移除通知
  clearAllNotifications,  // 清空所有通知
  toggleSound,            // 切换音效
  requestBrowserPermission, // 请求浏览器通知权限
  trackNotificationClick, // 追踪通知点击
  retryConnection,        // 手动重连
  showWelcomeGuide,       // 显示欢迎引导
  showCommunityGuide,     // 显示社区功能引导
  showFirstFollowGuide,   // 显示首次关注引导
} = useNotification();

关键实现细节

  1. 双重去重机制

    // Socket层去重避免重复接收
    const processedEventIds = useRef(new Set());
    
    // 显示层去重(避免重复显示)
    const isDuplicate = notifications.some(n => n.id === notificationId);
    
  2. 智能分发策略

    const isPageHidden = document.hidden;
    
    if (isPageHidden) {
      sendBrowserNotification(notification); // 后台:浏览器通知
    } else {
      addWebNotification(notification);      // 前台:网页通知
    }
    
  3. 渐进式权限引导

    // 登录后显示欢迎引导
    showWelcomeGuide();
    
    // 首次关注事件时显示引导
    showFirstFollowGuide();
    

源码位置: src/contexts/NotificationContext.js:1-829


2. NotificationContainer - 通知容器UI

职责:通知的可视化展示,处理动画、交互、无障碍。

核心功能

  • 通知列表渲染最多显示3条
  • 折叠/展开功能
  • 通知动画Framer Motion
  • 点击跳转
  • 无障碍支持ARIA、键盘导航

主要组件

<NotificationContainer>
  <VStack spacing={3}>
    {/* 可见通知 */}
    {visibleNotifications.map(notification => (
      <NotificationItem
        notification={notification}
        onClose={removeNotification}
        isNewest={index === 0}  // 最新通知特殊样式
      />
    ))}

    {/* 折叠按钮 */}
    {hasMore && (
      <Button onClick={() => setIsExpanded(!isExpanded)}>
        {isExpanded ? '收起' : `还有 ${hiddenCount} 条通知`}
      </Button>
    )}
  </VStack>
</NotificationContainer>

关键实现细节

  1. 优先级视觉表现

    // 紧急通知:粗边框 + 深色背景 + 脉冲动画
    borderWidth: priority === URGENT ? '6px' : '2px'
    animation: priority === URGENT ? pulseAnimation : undefined
    
  2. 严格可点击性判断

    const isActuallyClickable = clickable && link; // 两者都必须为true
    cursor: isActuallyClickable ? 'pointer' : 'default'
    
  3. 性能优化

    // React.memo 自定义比较函数
    React.memo(NotificationItem, (prevProps, nextProps) => {
      return prevProps.notification.id === nextProps.notification.id
          && prevProps.isNewest === nextProps.isNewest;
    });
    

源码位置: src/components/NotificationContainer/index.js:1-757


3. SocketService - WebSocket服务

职责管理Socket.IO连接处理断线重连事件订阅。

核心功能

  • Socket.IO 连接管理
  • 指数退避重连策略
  • 事件订阅/取消订阅
  • 消息发送/接收

重连策略

// 指数退避延迟
getReconnectionDelay(attempt) {
  const delays = [60000, 120000, 240000]; // 1min, 2min, 4min
  const index = Math.min(attempt - 1, delays.length - 1);
  return delays[index];
}

// 无限重试
this.maxReconnectAttempts = Infinity;

主要API

// 连接管理
socket.connect();
socket.disconnect();
socket.reconnect();
socket.isConnected();

// 事件监听
socket.on('event_name', callback);
socket.off('event_name');

// 事件订阅(金融资讯专用)
socket.subscribeToEvents({ eventType, importance, onNewEvent });
socket.unsubscribeFromEvents({ eventType });

源码位置: src/services/socketService.js:1-465


其他核心组件

4. browserNotificationService - 浏览器通知服务

核心方法

// 检查支持性
browserNotificationService.isSupported();

// 获取权限状态
browserNotificationService.getPermissionStatus(); // 'granted' | 'denied' | 'default'

// 请求权限
await browserNotificationService.requestPermission();

// 发送通知
const notification = browserNotificationService.sendNotification({
  title: '通知标题',
  body: '通知内容',
  tag: 'unique_tag',
  requireInteraction: false,
  data: { link: '/detail' },
  autoClose: 8000,
});

// 设置点击处理
notification.onclick = () => {
  window.focus();
  window.location.hash = link;
  notification.close();
};

源码位置: src/services/browserNotificationService.js:1-209


5. notificationHistoryService - 历史记录服务

核心功能

  • localStorage持久化最多500条
  • 筛选(类型、优先级、日期范围、阅读状态)
  • 搜索(关键词匹配)
  • 导出JSON/CSV
  • 统计分析

主要API

// 保存通知
notificationHistoryService.saveNotification(notification);

// 获取历史记录(带筛选)
const { records, total, page, totalPages } = notificationHistoryService.getHistory({
  type: 'event_alert',
  priority: 'urgent',
  readStatus: 'unread',
  startDate: Date.now() - 7 * 24 * 60 * 60 * 1000,
  page: 1,
  pageSize: 20,
});

// 搜索
const results = notificationHistoryService.searchHistory('央行');

// 导出
notificationHistoryService.downloadJSON();
notificationHistoryService.downloadCSV();

// 统计
const stats = notificationHistoryService.getStats();
// { total, read, unread, clicked, clickRate, byType, byPriority }

源码位置: src/services/notificationHistoryService.js:1-403


6. notificationMetricsService - 性能监控服务

追踪指标

  • 总发送数、总接收数
  • 点击率、关闭率
  • 平均响应时间(从接收到点击的时间)
  • 每小时推送分布
  • 每日数据趋势最近30天

主要API

// 追踪事件
notificationMetricsService.trackReceived(notification);
notificationMetricsService.trackClicked(notification);
notificationMetricsService.trackDismissed(notification);

// 获取统计
const summary = notificationMetricsService.getSummary();
// {
//   totalReceived, totalClicked, totalDismissed,
//   clickRate, avgResponseTime, deliveryRate
// }

const byType = notificationMetricsService.getByType();
// { announcement: { received, clicked, dismissed, clickRate }, ... }

const dailyData = notificationMetricsService.getDailyData(7); // 最近7天
// [ { date: '2025-01-01', received, clicked, dismissed, clickRate }, ... ]

// 导出
const json = notificationMetricsService.exportToJSON();
const csv = notificationMetricsService.exportToCSV();

源码位置: src/services/notificationMetricsService.js:1-451


🔄 消息推送完整流程

1. 初始化流程

graph LR
    A[App启动] --> B[AppProviders挂载]
    B --> C[NotificationProvider初始化]
    C --> D{环境检测}
    D -->|Mock| E[连接mockSocketService]
    D -->|Real| F[连接socketService]
    E --> G[注册事件监听器]
    F --> G
    G --> H[触发connect事件]
    H --> I[更新连接状态]
    I --> J[检查浏览器通知权限]
    J --> K[加载历史记录]
    K --> L[初始化完成]

代码实现 (src/contexts/NotificationContext.js:573-712):

useEffect(() => {
  // 1. 注册事件监听器
  socket.on('connect', handleConnect);
  socket.on('disconnect', handleDisconnect);
  socket.on('connect_error', handleConnectError);
  socket.on('new_event', handleNewEvent);

  // 2. 连接Socket
  socket.connect();

  // 3. Mock模式启动自动推送
  if (SOCKET_TYPE === 'MOCK') {
    socket.startMockPush(60000, 2); // 60秒推送1-2条
  }

  // 4. 清理函数
  return () => {
    socket.off('connect');
    socket.off('disconnect');
    socket.off('new_event');
    socket.disconnect();
  };
}, []);

2. 消息接收与适配

graph TB
    A[后端推送事件] --> B{Socket层去重}
    B -->|已存在| C[忽略]
    B -->|新事件| D[触发 new_event]
    D --> E{数据格式检测}
    E -->|前端格式| F[直接使用]
    E -->|后端格式| G[格式适配]

    G --> H[映射重要性<br/>S/A→urgent/important<br/>B/C→normal]
    H --> I[构建通知对象]
    I --> J[生成跳转链接<br/>/event-detail/id]
    J --> K[添加元数据]
    K --> L{显示层去重}
    L -->|已存在| M[忽略]
    L -->|新通知| N[添加到队列]

后端事件格式前端通知格式 适配器:

const adaptEventToNotification = (event) => {
  // 检测格式
  if (event.priority || event.type === NOTIFICATION_TYPES.ANNOUNCEMENT) {
    return event; // 已经是前端格式
  }

  // 重要性映射
  let priority = PRIORITY_LEVELS.NORMAL;
  if (event.importance === 'S') priority = PRIORITY_LEVELS.URGENT;
  else if (event.importance === 'A') priority = PRIORITY_LEVELS.IMPORTANT;

  // 构建通知对象
  return {
    id: event.id,
    type: NOTIFICATION_TYPES.EVENT_ALERT,
    priority: priority,
    title: event.title,
    content: event.description || event.content,
    publishTime: new Date(event.created_at).getTime(),
    pushTime: Date.now(),
    isAIGenerated: event.is_ai_generated || false,
    clickable: true,
    link: `/event-detail/${event.id}`,
    autoClose: NOTIFICATION_CONFIG.autoCloseDuration[priority],
    extra: {
      eventId: event.id,
      eventType: event.event_type,
      importance: event.importance,
      keywords: event.keywords || [],
    },
  };
};

源码位置: src/contexts/NotificationContext.js:336-395


3. 通知分发策略

graph TB
    A[收到新通知] --> B{检查浏览器权限}
    B -->|default| C[自动请求权限]
    B -->|denied| D[显示设置指引]
    B -->|granted| E{检查页面可见性}

    E -->|document.hidden=true<br/>页面在后台| F[发送浏览器通知]
    E -->|document.hidden=false<br/>页面在前台| G[显示网页通知]

    F --> H[browserNotificationService]
    H --> I[创建系统通知]
    I --> J[设置点击处理]
    J --> K[保存到历史]
    K --> L[记录性能指标]

    G --> M[addWebNotification]
    M --> N[添加到通知队列]
    N --> O[播放音效]
    O --> P{自动关闭时长}
    P -->|0| Q[不自动关闭]
    P -->|>0| R[延迟关闭]
    R --> K

代码实现 (src/contexts/NotificationContext.js:558-570):

const isPageHidden = document.hidden;

if (isPageHidden) {
  // 后台:浏览器通知
  logger.info('NotificationContext', 'Page hidden: sending browser notification');
  sendBrowserNotification(newNotification);
} else {
  // 前台:网页通知
  logger.info('NotificationContext', 'Page visible: sending web notification');
  addWebNotification(newNotification);
}

4. 性能监控埋点

系统自动追踪以下事件:

// 通知接收时
notificationMetricsService.trackReceived(notification);

// 通知点击时
notificationMetricsService.trackClicked(notification);
// 自动计算响应时间 = 点击时间 - 接收时间

// 通知关闭时
notificationMetricsService.trackDismissed(notification);

性能指标计算

// 点击率
clickRate = (totalClicked / totalReceived) * 100

// 平均响应时间
avgResponseTime = totalResponseTime / totalClicked

// 到达率假设sent=received
deliveryRate = (totalReceived / totalSent) * 100

数据存储

  • localStorage 持久化
  • 最多保留 30 天数据
  • 自动清理过期数据

🧪 测试快速指南

📖 完整测试手册: notification-manual-testing-guide.md

本地测试

Mock 模式(快速开发测试)

npm start

关键检查:

// 1. 验证连接
__SOCKET_DEBUG__.getStatus()
// 预期: { type: "MOCK", connected: true }

// 2. 查看可用工具
__mockSocket
// 包含: simulateDisconnection, pausePush, resumePush, sendTestNotification 等

// 3. 快速触发测试通知(三种方式)
__mockSocket.sendTestNotification()             // 方式1: 快速触发1条公告通知
__NOTIFY_DEBUG__.testNotify('announcement')     // 方式2: 指定类型的测试通知
__NOTIFY_DEBUG__.testNotify('stock_alert')      // 方式3: 其他类型(股票/事件/报告)

Real 模式(后端联调)

npm run start:real

关键检查:

// 1. 验证连接
__SOCKET_DEBUG__.getStatus()
// 预期: { type: "REAL", connected: true }

// 2. 手动订阅
__NOTIFY_DEBUG__.subscribe()

// 3. 等待后端推送
// 观察控制台: "✅ New event received"

线上测试

访问: https://valuefrontier.cn

// 一键诊断
__NOTIFY_DEBUG__.checkAll()

// 手动订阅
__NOTIFY_DEBUG__.subscribe()

// 导出报告
__NOTIFY_DEBUG__.exportReport()

调试工具速查

工具 适用环境 主要功能
__mockSocket Mock模式 模拟断线、暂停推送、测试重连
__SOCKET_DEBUG__ 所有环境 连接状态、配置检查、手动订阅
__NOTIFY_DEBUG__ 所有环境 完整诊断、模拟通知、导出报告

常用命令:

// 完整诊断
__NOTIFY_DEBUG__.checkAll()

// 查看帮助
__NOTIFY_DEBUG__.help()

// Mock模式暂停自动推送
__mockSocket.pausePush()

// Mock模式模拟断线
__mockSocket.simulateDisconnection()

测试通知方法对比

方法 环境 触发速度 通知类型 使用场景
__mockSocket.sendTestNotification() Mock模式 即时 固定:公告通知 快速验证通知UI是否正常显示
__NOTIFY_DEBUG__.testNotify(type) Mock模式 即时 可选4种类型 测试不同类型通知的显示效果
等待自动推送 Mock模式 🐢 60秒/次 随机:所有类型 测试自动推送机制和真实场景
__NOTIFY_DEBUG__.subscribe() Real模式 等待后端 取决于后端 测试后端集成和真实数据

推荐用法

// 场景1: 快速验证UI最快
__mockSocket.sendTestNotification()

// 场景2: 测试特定类型
__NOTIFY_DEBUG__.testNotify('stock_alert')      // 股票动向
__NOTIFY_DEBUG__.testNotify('event_alert')      // 事件动向
__NOTIFY_DEBUG__.testNotify('analysis_report')  // 分析报告

// 场景3: 测试自动推送
__mockSocket.resumePush()  // 确保推送开启
// 等待60秒...

// 场景4: 暂停干扰
__mockSocket.pausePush()   // 暂停自动推送,专注测试单条

手动测试清单

功能测试

1. 通知显示测试

  • 公告通知显示正确(蓝色系、图标、内容)
  • 股票上涨通知显示为红色系(+图标、红边框)
  • 股票下跌通知显示为绿色系(-图标、绿边框)
  • 事件动向通知显示正确(橙色系)
  • 分析报告(人工)显示正确(紫色系、作者信息)
  • 分析报告AI显示AI徽章
  • 预测通知显示"预测"徽章和状态提示

2. 优先级测试

  • 紧急通知:红色标签、粗边框、脉冲动画、不自动关闭
  • 重要通知橙色标签、中等边框、30秒自动关闭
  • 普通通知无标签、细边框、15秒自动关闭

3. 交互测试

  • 点击可点击通知跳转到正确页面
  • 点击不可点击通知无反应
  • 点击关闭按钮关闭通知
  • 音效开关正常工作
  • 清空全部按钮清空所有通知

4. 折叠展开测试

  • 通知数 ≤ 3 时不显示展开按钮
  • 通知数 > 3 时显示"还有X条通知"按钮
  • 点击展开显示所有通知
  • 点击收起恢复显示前3条
  • 展开状态保存到localStorage刷新页面保持
  • 展开状态2分钟后自动过期

5. 队列管理测试

  • 最多显示15条历史通知
  • 超过15条自动移除最旧的
  • 新通知在最上方
  • z-index层级正确最新最高

浏览器通知测试

6. 权限管理测试

  • 首次访问显示权限状态为"default"
  • 点击请求权限按钮弹出浏览器授权对话框
  • 授权后状态变为"granted"
  • 拒绝后状态变为"denied",显示设置指引
  • 权限状态在测试工具中正确显示

7. 浏览器通知显示测试

  • 权限授予后,切换到其他标签页,收到通知时显示系统通知
  • 点击浏览器通知聚焦窗口并跳转到详情页
  • 普通通知8秒后自动关闭
  • 紧急通知需手动关闭

Socket连接测试

8. Mock模式测试

  • 启动后显示"Connected" + "MOCK"状态
  • 控制台显示可用测试函数
  • __mockSocket.simulateDisconnection() 模拟断线成功
  • 断线后自动重连10秒→20秒→40秒
  • 重连成功后显示"✓ 已重新连接" 2秒后消失
  • __mockSocket.simulateConnectionFailure() 模拟持续失败
  • 手动关闭连接状态横幅后保存到localStorage
  • __mockSocket.reconnect() 立即重连成功

9. Real模式测试

  • 启动后显示"Connected" + "REAL"状态
  • 后端推送消息能正确接收
  • 断线后自动重连1分钟→2分钟→4分钟
  • 网络恢复时自动重连
  • 标签页重新聚焦时自动重连

UI测试

10. 响应式测试

  • 移动端(< 480px宽度 = 屏宽-32px精简显示
  • 小屏480-768px宽度 = 360px
  • 平板768-992px宽度 = 380px
  • 桌面(> 992px宽度 = 400px
  • 底部偏移移动端12px桌面端112px避开设置按钮

11. 动画测试

  • 新通知从底部向上滑入(浮起效果)
  • 关闭通知向右滑出消失
  • 紧急通知边框脉冲动画流畅
  • 折叠/展开动画流畅无卡顿
  • 展开15条通知无明显性能问题

12. 无障碍测试

  • Tab键可以聚焦到可点击通知
  • 聚焦时显示蓝色轮廓线
  • Enter/Space键可以打开详情
  • 关闭按钮可键盘操作Tab + Enter
  • 屏幕阅读器朗读完整通知信息

性能测试

13. 性能指标测试

  • 发送10条通知打开控制台查看性能指标
  • 点击5条通知检查点击率计算正确
  • 检查平均响应时间计算正确
  • 导出JSON/CSV文件正常
  • 查看每小时分布图表数据准确

14. 历史记录测试

  • 收到通知后自动保存到历史记录
  • 筛选功能正常(类型、优先级、日期范围、阅读状态)
  • 搜索功能返回正确结果
  • 分页功能正常
  • 统计数据准确
  • 导出JSON/CSV正常

跨浏览器测试

15. 兼容性测试

  • Chrome: 所有功能正常
  • Edge: 所有功能正常
  • Firefox: 所有功能正常
  • Safari: 所有功能正常(注意浏览器通知权限)
  • 移动端Chrome: 响应式布局正确
  • 移动端Safari: 响应式布局正确

🧪 自动化测试用例

完整的自动化测试代码请参考: notification-tests.md

以下是核心测试用例概览:

单元测试

NotificationContext 测试

describe('NotificationContext', () => {
  test('应该正确初始化默认状态', () => {
    const { result } = renderHook(() => useNotification(), {
      wrapper: NotificationProvider,
    });

    expect(result.current.notifications).toEqual([]);
    expect(result.current.soundEnabled).toBe(true);
  });

  test('应该正确添加通知', () => {
    const { result } = renderHook(() => useNotification(), {
      wrapper: NotificationProvider,
    });

    act(() => {
      result.current.addNotification({
        type: 'announcement',
        priority: 'important',
        title: '测试通知',
        content: '内容',
      });
    });

    expect(result.current.notifications).toHaveLength(1);
    expect(result.current.notifications[0].title).toBe('测试通知');
  });

  // 更多测试用例...
});

notificationHistoryService 测试

describe('notificationHistoryService', () => {
  beforeEach(() => {
    localStorage.clear();
  });

  test('应该保存通知到历史记录', () => {
    const notification = {
      id: 'test001',
      type: 'announcement',
      title: '测试',
      content: '内容',
    };

    notificationHistoryService.saveNotification(notification);
    const { records } = notificationHistoryService.getHistory();

    expect(records).toHaveLength(1);
    expect(records[0].notification.id).toBe('test001');
  });

  // 更多测试用例...
});

集成测试

describe('通知系统集成测试', () => {
  test('完整流程:从接收到显示到点击', async () => {
    render(
      <NotificationProvider>
        <NotificationContainer />
      </NotificationProvider>
    );

    // 1. 模拟接收通知
    act(() => {
      socket.emit('new_event', mockEventData);
    });

    // 2. 验证通知显示
    await waitFor(() => {
      expect(screen.getByText('测试通知')).toBeInTheDocument();
    });

    // 3. 模拟点击
    const notification = screen.getByText('测试通知').closest('[role="status"]');
    fireEvent.click(notification);

    // 4. 验证导航
    expect(mockNavigate).toHaveBeenCalledWith('/event-detail/test001');

    // 5. 验证性能指标
    const stats = notificationMetricsService.getSummary();
    expect(stats.totalClicked).toBe(1);
  });
});

测试覆盖率目标

模块 目标覆盖率 优先级
notificationTypes.js 100%
notificationHistoryService.js 90%+
notificationMetricsService.js 90%+
browserNotificationService.js 80%+
NotificationContext.js 70%+
NotificationContainer/index.js 60%+
socketService.js 50%+ 低(难以测试)

🎨 通知类型配置

类型 1: 公告通知 (Announcement)

适用场景:公司财报、重大资产重组、分红派息、停复牌公告

配色方案

  • 主色:蓝色 (Blue)
  • 图标:📢 MdCampaign
  • 背景:blue.50 / 暗色:rgba(59, 130, 246, 0.15)

示例

{
  type: NOTIFICATION_TYPES.ANNOUNCEMENT,
  priority: PRIORITY_LEVELS.IMPORTANT,
  title: '贵州茅台发布2024年度财报公告',
  content: '2024年度营收同比增长15.2%,净利润创历史新高',
  publishTime: Date.now(),
  pushTime: Date.now(),
  isAIGenerated: false,
  clickable: true,
  link: '/event-detail/ann001',
  extra: {
    announcementType: '财报',
    companyCode: '600519',
  },
  autoClose: 10000,
}

类型 2: 股票动向 (Stock Alert)

适用场景:价格预警、异常波动、持仓表现

动态配色(根据 extra.priceChange 字段):

  • 涨(+:红色系 🔴
  • 跌(-:绿色系 🟢

示例(涨)

{
  type: NOTIFICATION_TYPES.STOCK_ALERT,
  priority: PRIORITY_LEVELS.URGENT,
  title: '您关注的股票触发预警',
  content: '宁德时代(300750) 当前价格 ¥245.50,涨幅 +5.2%',
  publishTime: Date.now(),
  pushTime: Date.now(),
  clickable: true,
  link: '/stock-overview?code=300750',
  extra: {
    stockCode: '300750',
    stockName: '宁德时代',
    priceChange: '+5.2%',  // 💡 重要:根据此字段判断涨跌
    currentPrice: '245.50',
  },
  autoClose: 10000,
}

类型 3: 事件动向 (Event Alert)

适用场景:央行政策、行业政策、监管动态、宏观事件

配色方案

  • 主色:橙色 (Orange)
  • 图标:📄 MdArticle

示例

{
  type: NOTIFICATION_TYPES.EVENT_ALERT,
  priority: PRIORITY_LEVELS.IMPORTANT,
  title: '央行宣布降准0.5个百分点',
  content: '中国人民银行宣布下调金融机构存款准备金率0.5个百分点',
  publishTime: Date.now(),
  pushTime: Date.now(),
  clickable: true,
  link: '/event-detail/evt001',
  extra: {
    eventId: 'evt001',
    relatedStocks: 12,
    impactLevel: '重大利好',
  },
  autoClose: 12000,
}

类型 4: 分析报告 (Analysis Report)

适用场景:行业研报、策略报告、公司研报

特殊字段

  • author:作者信息(必填)
  • isAIGenerated:是否 AI 生成(显示紫色 AI 徽章)

示例AI

{
  type: NOTIFICATION_TYPES.ANALYSIS_REPORT,
  priority: PRIORITY_LEVELS.NORMAL,
  title: 'AI产业链投资机会分析',
  content: '随着大模型应用加速落地,算力、数据、应用三大方向均存在投资机会',
  publishTime: Date.now(),
  pushTime: Date.now(),
  author: {
    name: 'AI分析师',
    organization: '价值前沿',
  },
  isAIGenerated: true,  // 💡 显示 AI 徽章
  clickable: true,
  link: '/forecast-report?id=rpt002',
  extra: {
    reportType: '策略报告',
    industry: '人工智能',
  },
  autoClose: 12000,
}

📊 优先级配置

优先级 标签 边框 自动关闭 使用场景
urgent 🔴 紧急 6px粗边框 + 脉冲动画 不自动关闭 重大事件、高优先级预警
important 🟠 重要 4px中等边框 30秒 重要消息、一般预警
normal - 2px细边框 15秒 常规消息、信息推送

配置代码

export const PRIORITY_CONFIGS = {
  [PRIORITY_LEVELS.URGENT]: {
    label: '紧急',
    colorScheme: 'red',
    show: false,
    borderWidth: '6px',
    bgOpacity: 0.25,
  },
  [PRIORITY_LEVELS.IMPORTANT]: {
    label: '重要',
    colorScheme: 'orange',
    show: false,
    borderWidth: '4px',
    bgOpacity: 0.15,
  },
  [PRIORITY_LEVELS.NORMAL]: {
    label: '',
    colorScheme: 'gray',
    show: false,
    borderWidth: '2px',
    bgOpacity: 0.08,
  },
};

🚀 快速开始

1. 启用 Mock 模式

.env 文件中添加:

REACT_APP_ENABLE_MOCK=true

2. 启动项目

npm start

3. 测试通知

打开浏览器,右上角会显示 "金融资讯测试工具",包含:

通知类型测试

  • 公告通知、股票动向、事件动向、分析报告
  • 预测通知(不可跳转)

组合测试

  • 预测→详情流程5秒延迟

功能按钮

  • 清空全部、音效开关、队列状态

4. 自动推送

Mock 模式下,系统会自动每 60 秒推送 1-2 条随机金融资讯。


💻 代码使用

在组件中使用

import { useNotification } from 'contexts/NotificationContext';
import { NOTIFICATION_TYPES, PRIORITY_LEVELS } from 'constants/notificationTypes';

function MyComponent() {
  const { addNotification, isConnected } = useNotification();

  const handleAnnouncement = () => {
    addNotification({
      type: NOTIFICATION_TYPES.ANNOUNCEMENT,
      priority: PRIORITY_LEVELS.IMPORTANT,
      title: '贵州茅台发布2024年度财报公告',
      content: '2024年度营收同比增长15.2%',
      publishTime: Date.now(),
      pushTime: Date.now(),
      isAIGenerated: false,
      clickable: true,
      link: '/event-detail/ann001',
      autoClose: 10000,
    });
  };

  return (
    <div>
      <p>连接状态: {isConnected ? '已连接' : '未连接'}</p>
      <button onClick={handleAnnouncement}>发送公告</button>
    </div>
  );
}

🔧 环境配置

Mock 模式 vs Real 模式

配置项 Mock 模式 Real 模式
启用方式 REACT_APP_ENABLE_MOCK=true REACT_APP_ENABLE_MOCK=false
Socket 服务 mockSocketService socketService (Socket.IO)
推送数据 14条模拟金融资讯 后端 Flask-SocketIO 推送
自动推送 60秒推送1-2条 无自动推送,按需推送
重连间隔 10s→20s→40s 1min→2min→4min
测试函数 window.__mockSocket.*

修改推送频率

src/services/mockSocketService.js 中:

// 默认: 60秒推送1-2条
socket.startMockPush(60000, 2);

// 修改为: 30秒推送1条
socket.startMockPush(30000, 1);

// 修改为: 5秒推送3条压力测试
socket.startMockPush(5000, 3);

🌐 后端集成(生产环境)

Flask-SocketIO 配置

from flask_socketio import SocketIO, emit

# 初始化 SocketIO
socketio = SocketIO(app, cors_allowed_origins=[
    "http://localhost:3000",
    "https://valuefrontier.cn"
])

# 推送金融资讯通知
def send_financial_notification(user_id, data):
    """
    推送金融资讯通知到指定用户

    参数:
        user_id: 用户ID
        data: 通知数据(参考通知类型配置)
    """
    socketio.emit('new_event', data, room=user_id)

# 启动服务器
if __name__ == '__main__':
    socketio.run(app, host='0.0.0.0', port=5001)

后端推送示例

import time

# 推送事件动向
socketio.emit('new_event', {
    'type': 'event_alert',
    'priority': 'important',
    'title': '央行宣布降准0.5个百分点',
    'content': '中国人民银行宣布下调金融机构存款准备金率0.5个百分点',
    'publishTime': int(time.time() * 1000),
    'pushTime': int(time.time() * 1000),
    'isAIGenerated': False,
    'clickable': True,
    'link': '/event-detail/evt001',
    'extra': {
        'eventId': 'evt001',
        'relatedStocks': 12,
        'impactLevel': '重大利好',
    },
    'autoClose': 12000
}, room=user_id)

🐛 故障排除

问题 1: 通知不显示

检查项

  1. 确认 NotificationProvider 已包裹应用
  2. 检查浏览器控制台是否有错误
  3. 确认 socket 连接状态(查看测试工具)
  4. 检查通知数据格式是否正确

问题 2: 股票动向颜色不对

解决方案

  1. 检查 extra.priceChange 字段是否存在
  2. 确认格式为 "+5.2%" 或 "-3.8%"(包含符号)
  3. 确认使用了 NOTIFICATION_TYPES.STOCK_ALERT 类型

问题 3: AI 徽章不显示

解决方案

  1. 检查 isAIGenerated 字段是否为 true
  2. 确认字段名拼写正确(驼峰命名)

问题 4: 浏览器通知不工作

解决方案

  1. 检查浏览器通知权限是否已授予
  2. macOS: 关闭"专注模式"或"勿扰模式"
  3. Chrome: 检查 chrome://settings/content/notifications
  4. 退出全屏模式(某些浏览器全屏时不显示通知)
  5. 无痕/隐私模式特别说明
    • Chrome 无痕模式:可以授权,但关闭窗口后权限会被清除
    • Safari 隐私模式:通知权限被永久拒绝,无法更改
    • 建议:使用普通浏览器窗口以获得完整体验

快速诊断

// 在浏览器控制台运行
console.log('Permission:', Notification.permission);  // 'granted' | 'denied' | 'default'
console.log('Supported:', 'Notification' in window); // true | false

// 完整诊断
window.__NOTIFY_DEBUG__.checkAll();

问题 5: Chrome 无痕模式/隐私模式下 Notification.permission = 'denied' 怎么办?

🔍 问题分析

当在 Chrome 无痕模式或其他浏览器隐私模式下遇到通知权限被拒绝的情况,需要了解不同浏览器的行为差异:

浏览器行为对比表

浏览器模式 初始权限状态 是否可授权 权限持久性 推荐方案
Chrome 正常模式 default 可以 永久保存 推荐使用
Chrome 无痕模式 default 可以 关闭窗口后清除 可用但需重复授权
Safari 隐私模式 denied 不可以 永久拒绝 仅网页内通知
Firefox 隐私模式 default 可以 关闭窗口后清除 可用但需重复授权

关键点

  • Chrome 无痕模式的初始状态通常是 default(未决定),不是 denied
  • ⚠️ 如果看到 denied,说明用户点击了"阻止"按钮
  • 🚫 Safari 隐私模式会直接显示 denied,且无法通过代码更改
  • 🔄 权限在无痕/隐私窗口关闭后会被清除Chrome/Firefox

当前系统已自动处理

好消息:您的通知系统已经完美处理了这种情况!

自动降级策略

// 在 NotificationContext.js 中
if (browserPermission !== 'granted') {
    // 跳过浏览器通知,只显示网页内通知
    logger.warn('NotificationContext', 'Browser permission not granted');
    return;
}

用户引导机制

  • 当权限为 denied 时,自动显示橙色提示框
  • 提示内容:"浏览器通知已被拒绝"
  • 引导文案:"💡 如需接收桌面通知,请在浏览器设置中允许通知权限"

实际效果

  • 网页内通知卡片继续正常显示
  • ⏭️ 浏览器桌面通知被优雅跳过
  • 所有核心功能不受影响
  • 用户体验降级合理

🛠️ 三种解决方案

方案 1退出无痕模式强烈推荐

# 原因:
# - 权限会永久保存
# - 获得完整通知体验
# - 不需要每次重新授权

# 操作:使用普通浏览器窗口访问应用

方案 2接受降级体验推荐

# 系统已自动处理:
# ✅ 网页内通知正常显示(通知卡片)
# ⏭️ 桌面通知被跳过
# ✅ 不影响核心功能
# ✅ 用户体验合理

# 操作:无需任何操作,系统自动降级

方案 3在无痕模式中重新授权仅 Chrome/Firefox

Chrome 无痕模式

  1. 点击地址栏左侧的 🔒 锁图标
  2. 找到"通知"设置项
  3. 将"阻止"改为"允许"
  4. 刷新页面F5
  5. ⚠️ 注意:关闭无痕窗口后需要重新授权

Safari 隐私模式

# ❌ Safari 隐私模式无法更改权限
# 💡 建议:退出隐私模式或接受降级体验

📊 调试与验证

快速检查权限状态

// 在浏览器控制台运行

// 方法 1直接查看
console.log('Permission:', Notification.permission);
// 输出: 'granted' | 'denied' | 'default'

// 方法 2检查是否支持
console.log('Supported:', 'Notification' in window);
// 输出: true | false

// 方法 3完整诊断推荐
window.__NOTIFY_DEBUG__.checkAll();

完整诊断输出示例

========== 【通知系统诊断】 ==========

✓ Socket 配置检查完成
✓ 连接状态: ✅ 已连接
✓ API Base: http://49.232.185.254:5001
✓ 浏览器通知权限: denied

========== 诊断报告 ==========
┌─────────────┬────────────────────┐
│ socket.type │ MOCK               │
│ connected   │ true               │
│ permission  │ denied             │
└─────────────┴────────────────────┘

⚠️ 发现问题: ['浏览器通知权限被拒绝']

💡 修复建议:
  1. 如在无痕/隐私模式,建议退出使用正常模式
  2. Chrome: 点击地址栏🔒 → 通知 → 允许
  3. 或接受降级体验:继续使用网页内通知

====================================

测试通知(仅 Mock 模式)

// 测试不同类型通知
window.__NOTIFY_DEBUG__.testNotify('announcement');   // 公告通知
window.__NOTIFY_DEBUG__.testNotify('stock_alert');    // 股票动向
window.__NOTIFY_DEBUG__.testNotify('event_alert');    // 事件动向
window.__NOTIFY_DEBUG__.testNotify('analysis_report'); // 分析报告

// 查看帮助
window.__NOTIFY_DEBUG__.help();

🎯 最佳实践建议

开发环境

// 使用 Mock 模式 + Chrome 正常窗口
// .env.mock
REACT_APP_ENABLE_MOCK=true

// 一次授权,永久有效

测试环境

// 测试多种权限状态
// 1. granted - 正常授权
// 2. denied  - 测试降级体验
// 3. default - 测试首次访问流程

生产环境

// 引导用户使用正常浏览器窗口
// 提供清晰的权限说明
// 降级体验要优雅

📝 相关代码位置

权限处理逻辑

  • src/services/browserNotificationService.js:26-31 - 权限状态获取
  • src/services/browserNotificationService.js:85-88 - 权限检查
  • src/contexts/NotificationContext.js:295-298 - 发送前权限验证
  • src/contexts/NotificationContext.js:477-506 - 拒绝时用户引导

调试工具

  • src/services/socket/index.js:192-362 - window.__NOTIFY_DEBUG__ API

问题 6: Socket 连接失败

解决方案

  1. 检查后端 Flask-SocketIO 是否正确运行
  2. 确认 CORS 配置正确
  3. 检查 src/utils/apiConfig.js 中的 API 地址
  4. 查看控制台日志确认错误信息

调试工具

控制台日志

// 所有操作都有详细日志
logger.info('NotificationContext', 'Event', data);
logger.warn('NotificationContext', 'Warning', error);
logger.error('NotificationContext', 'Error', error);

Mock模式测试函数

// 查看可用函数
console.log(window.__mockSocket);

// 模拟断线
__mockSocket.simulateDisconnection();

// 查看连接状态
__mockSocket.isConnected();

// 查看重连次数
__mockSocket.getAttempts();

日志分析

正常日志流程

1. [NotificationContext] Initializing socket connection...
2. [NotificationContext] Socket connected
3. [NotificationContext] Received new event { id: 'evt001', title: '...' }
4. [NotificationContext] Adding notification { id: 'evt001', type: 'event_alert' }
5. [NotificationContext] Page visible: sending web notification

异常日志排查

ERROR: Socket connect_error
→ 检查后端是否运行,网络是否通畅

WARN: Duplicate notification ignored at socket level
→ 正常,去重机制工作正常

ERROR: Browser permission not granted
→ 用户未授权浏览器通知,提示用户授权

📏 开发规范

1. 添加新通知类型

步骤

  1. src/constants/notificationTypes.js 添加类型定义
  2. 添加类型配置(图标、颜色、样式)
  3. NotificationContainer 中添加渲染逻辑
  4. 在测试工具中添加测试按钮
  5. 更新文档

示例

// 1. 添加类型
export const NOTIFICATION_TYPES = {
  // ...现有类型
  MARKET_NEWS: 'market_news',  // 新增
};

// 2. 添加配置
export const NOTIFICATION_TYPE_CONFIGS = {
  // ...现有配置
  [NOTIFICATION_TYPES.MARKET_NEWS]: {
    name: '市场快讯',
    icon: MdNewspaper,
    colorScheme: 'teal',
    bg: 'teal.50',
    borderColor: 'teal.400',
    iconColor: 'teal.500',
    hoverBg: 'teal.100',
  },
};

2. 自定义通知组件

如需完全自定义通知样式:

import { useNotification } from 'contexts/NotificationContext';

function CustomNotification({ notification }) {
  const { removeNotification, trackNotificationClick } = useNotification();

  const handleClick = () => {
    trackNotificationClick(notification.id);
    // 自定义导航逻辑
    removeNotification(notification.id, true);
  };

  return (
    <Box onClick={handleClick}>
      {/* 自定义样式 */}
    </Box>
  );
}

3. 扩展性能监控

添加自定义指标:

// 在 notificationMetricsService 中添加新方法
trackCustomEvent(notification, eventType, data) {
  // 自定义追踪逻辑
}

// 使用
notificationMetricsService.trackCustomEvent(notification, 'share', {
  platform: 'wechat',
});

性能优化建议

1. 队列管理优化 已实现

  • 系统自动限制最多 15 条历史记录
  • 超出自动移除最旧的,避免内存泄漏
  • 建议根据实际需求调整 NOTIFICATION_CONFIG.maxHistory

2. 合理设置自动关闭时长

类型 建议时长 理由
公告通知 10秒 内容较简短
股票动向 10秒 需要快速响应
事件动向 12秒 内容较多
分析报告 12秒 内容较多
紧急通知 不关闭 需要用户确认

3. 避免频繁推送

  • 生产环境建议间隔至少 3 秒
  • Mock 模式默认 60 秒推送 1-2 条
  • 避免短时间内大量推送造成用户困扰

4. React 性能优化 已实现

// 1. React.memo 优化
const NotificationItem = React.memo(NotificationItemComponent, (prev, next) => {
  return prev.notification.id === next.notification.id
      && prev.isNewest === next.isNewest;
});

// 2. useMemo 缓存计算
const colors = useMemo(() => ({
  bg: priorityBgColor,
  border: borderColor,
  // ...
}), [priorityBgColor, borderColor, ...]);

// 3. useCallback 优化事件处理
const handleClick = useCallback(() => {
  trackNotificationClick(id);
  navigate(link);
}, [id, link, trackNotificationClick, navigate]);

// 4. GPU 加速动画
willChange="transform, opacity"

5. 动画性能优化 已实现

  • 只对新增通知应用动画
  • 使用 Framer Motion 的 GPU 加速
  • 展开15条通知时禁用动画避免卡顿
  • 性能提升 90%+

6. localStorage 优化

// 定期清理过期数据
notificationHistoryService.cleanup(100);

// 限制最大存储数量
MAX_HISTORY_SIZE = 500;

// 压缩存储数据(可选)
const compressedData = LZ.compress(JSON.stringify(data));

🔒 安全注意事项

1. XSS 防护

// ✅ 正确:使用 React 自动转义
<Text>{notification.title}</Text>

// ❌ 错误:使用 dangerouslySetInnerHTML
<Text dangerouslySetInnerHTML={{ __html: notification.title }} />

2. 链接验证

// 跳转前验证链接合法性
const isValidLink = (link) => {
  return link && link.startsWith('/'); // 只允许内部链接
};

if (isActuallyClickable && isValidLink(link)) {
  navigate(link);
}

3. 敏感信息保护

// 不要在通知中显示敏感信息
// ❌ 错误
content: `您的密码是:${password}`

// ✅ 正确
content: '密码修改成功,请重新登录'

4. localStorage 安全

// 不要存储敏感数据到 localStorage
// ❌ 错误
localStorage.setItem('user_token', token);

// ✅ 正确:使用 httpOnly Cookie 或 sessionStorage

📁 文件结构

src/
├── constants/
│   └── notificationTypes.js           # 通知类型定义和常量
├── services/
│   ├── socket/
│   │   └── index.js                   # Socket 服务统一导出
│   ├── socketService.js               # 真实 Socket.IO 服务
│   ├── mockSocketService.js           # Mock Socket 服务
│   ├── browserNotificationService.js  # 浏览器通知服务
│   ├── notificationHistoryService.js  # 历史记录服务
│   └── notificationMetricsService.js  # 性能监控服务
├── contexts/
│   └── NotificationContext.js         # 通知上下文管理
├── components/
│   ├── NotificationContainer/
│   │   └── index.js                   # 通知容器组件
│   └── NotificationTestTool/
│       └── index.js                   # 测试工具组件
├── hooks/
│   └── useEventNotifications.js       # 事件订阅 Hook
└── assets/
    └── sounds/
        └── notification.wav           # 通知音效

📝 更新日志

v2.11.0 (2025-01-07) - Socket 连接优化

  • 指数退避重连策略
  • 连接状态横幅优化
  • Mock 模式测试功能增强

v2.10.0 (2025-01-06) - 按钮加载态

  • 点击"查看详情"显示 loading spinner
  • 防重复点击机制

v2.9.0 (2025-01-05) - 头部简化

  • AI 和预测标识移到底部

v2.8.0 (2025-01-04) - 无障碍支持

  • 完整的 ARIA 属性
  • 键盘导航支持

v2.7.0 (2025-01-03) - 智能动画

  • 只对新增通知应用动画
  • 性能提升 90%+

v2.6.0 (2025-01-02) - 状态持久化

  • 展开/收起状态保存到 localStorage
  • 2分钟自动过期

v2.5.0 (2025-01-01) - 避开设置按钮

  • 桌面端底部偏移112px

v2.4.0 (2024-12-31) - 响应式优化

  • 移动端、平板、桌面完美适配

v2.3.0 (2024-12-30) - 智能折叠

  • 最多显示3条超过显示展开按钮
  • 按优先级自动关闭

v2.2.0 (2024-12-29) - 双通知系统

  • 浏览器原生通知集成
  • 智能分发策略

v2.1.0 (2024-12-28) - 预测通知系统

  • 预测→详情两阶段推送
  • 严格可点击性判断

v2.0.0 (2024-12-27) - 金融资讯专业版

  • 4种金融资讯通知类型
  • 3级优先级系统
  • 智能元数据、动态配色

💡 技术栈

  • 前端框架: React 18.3.1
  • UI 库: Chakra UI 2.8.2
  • 路由: React Router v6
  • 实时通信: Socket.IO Client 4.7.4
  • 动画库: Framer Motion
  • 后端框架: Flask-SocketIO 5.3.6
  • 状态管理: React Context API
  • 图标库: React Icons (Material Design)

📞 支持

如有问题,请查看:

  • 项目文档: CLAUDE.md
  • 测试工具: 开发环境右上角"金融资讯测试工具"
  • 控制台日志: 所有操作都有详细日志
  • 类型定义: src/constants/notificationTypes.js
  • 测试用例: docs/test-cases/notification-tests.md

祝你使用愉快! 🎉