Files
vf_react/docs/NOTIFICATION_SYSTEM.md
zdl 678eb6838e docs: 合并并更新通知系统文档至 v3.0.0
主要更新:
- 合并 ENHANCED_FEATURES_GUIDE.md 到 NOTIFICATION_SYSTEM.md
- 移除过时的 Mock 模式和测试工具引用
- 更新所有调试工具为 window.__DEBUG__
- 完善增强功能文档(智能桌面通知、性能监控、历史记录)
- 重新组织文档结构为 10 个清晰的部分
- 更新所有代码示例与最新代码保持一致

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 18:40:05 +08:00

56 KiB
Raw Permalink Blame History

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

版本: v3.0.0 更新日期: 2025-11-17 文档类型: 用户指南 + 完整技术规格

🎯 重要说明:

  • 本文档已合并原 ENHANCED_FEATURES_GUIDE.md 的内容
  • 所有 API 引用和代码示例已更新至最新版本
  • 调试工具统一使用 window.__DEBUG__

📑 目录

👤 第一部分:用户快速指南

  1. 连接状态查看
  2. 手动操作指南
  3. 常见问题解决
  4. 可用调试命令

🚀 第二部分:快速入门(开发者)

  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. 环境配置

第七部分:增强功能详解

  1. 智能桌面通知
  2. 性能监控
  3. 历史记录

🧪 第八部分:测试指南

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

🐛 第九部分:故障排查

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

📏 第十部分:最佳实践

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

附录

  1. 后端集成
  2. 更新日志
  3. 文件结构

👤 第一部分:用户快速指南

适用人群: 普通用户、测试人员、客服人员 阅读时间: 5 分钟

🔌 连接状态查看

方法 1: 页面顶部状态横幅

当系统出现连接问题时,页面顶部会显示状态横幅:

状态 显示内容 颜色 说明
已连接 无横幅 - 正常工作,无需操作
⚠️ 断开连接 "⚠️ 连接已断开" 橙色 正在尝试重连
🔄 重连中 "🔄 正在重连... (第 X 次)" 蓝色 自动重连进行中
连接失败 " 连接失败,请检查网络" 红色 需要手动干预
✓ 已重连 "✓ 已重新连接" 绿色 重连成功2秒后自动消失

操作:

  • 横幅可手动关闭(点击 ✕ 按钮)
  • 关闭后会记住状态,重连成功后自动清除

方法 2: 浏览器控制台查看

  1. F12 打开开发者工具
  2. 切换到 Console 标签
  3. 输入以下命令:
// 查看连接状态
__DEBUG__.socket.getStatus()

// 输出示例:
{
  connected: true,
  socketId: "abc123...",
  reconnectAttempts: 0
}

🔧 手动操作指南

1. 手动重连

当连接失败时,可以手动触发重连:

浏览器控制台 (F12Console):

// 手动重连
__DEBUG__.socket.reconnect()

刷新页面(最简单):

  • Ctrl+R (Windows) 或 Cmd+R (Mac)
  • 或点击浏览器刷新按钮

2. 查看连接日志

// 查看最近的 Socket 日志
__DEBUG__.socket.getLogs()

// 导出所有日志到文件
__DEBUG__.exportAll()

3. 检查浏览器通知权限

// 查看通知权限状态
window.browserNotificationService.getPermissionStatus()

// 返回值:
// "granted"  - 已授权
// "denied"   - 已拒绝
// "default"  - 未询问

如何授予权限:

  1. 点击浏览器地址栏左侧的🔒图标
  2. 找到"通知"设置
  3. 选择"允许"

🆘 常见问题解决

问题 1: 收不到通知

可能原因:

  • 浏览器通知权限未授予
  • Socket 连接断开
  • 浏览器标签页处于后台(网页通知需要标签页在前台)

解决步骤:

  1. 检查连接状态(参见上面"连接状态查看"
  2. 检查通知权限:
    window.browserNotificationService.getPermissionStatus()
    
  3. 如果是 "denied",需要在浏览器设置中允许通知
  4. 如果是 "default",刷新页面会自动请求权限

问题 2: 连接一直断开

排查步骤:

  1. 检查网络连接:打开其他网站,确认网络正常
  2. 查看重连次数
    __DEBUG__.socket.getStatus()
    
  3. 查看错误日志
    __DEBUG__.socket.getLogs()
    
  4. 手动重连
    __DEBUG__.socket.reconnect()
    
  5. 刷新页面Ctrl+RCmd+R

问题 3: 通知太多/太少

无法控制通知数量(由后端推送决定),但可以:

  • 清空所有通知: 点击通知容器右上角"清空全部"按钮
  • 关闭单个通知: 点击通知右上角 ✕ 按钮
  • 关闭音效: 点击通知容器右上角🔊图标

问题 4: 页面卡顿

可能原因: 通知历史过多

解决方法:

  1. 点击"清空全部"按钮清空历史通知
  2. 系统会自动限制最多显示 15 条通知
  3. 如仍卡顿,刷新页面

💻 可用调试命令

使用方法: 打开浏览器控制台 (F12Console),输入以下命令

Socket 连接调试

// 1. 查看连接状态
__DEBUG__.socket.getStatus()

// 2. 手动重连
__DEBUG__.socket.reconnect()

// 3. 查看 Socket 日志
__DEBUG__.socket.getLogs()

// 4. 导出 Socket 日志
__DEBUG__.socket.exportLogs()

通知权限调试

// 1. 查看权限状态
window.browserNotificationService.getPermissionStatus()
// 返回: "granted" | "denied" | "default"

// 2. 请求权限
window.browserNotificationService.requestPermission()

// 3. 检查是否支持通知
window.browserNotificationService.isSupported()
// 返回: true | false

综合调试

// 1. 系统诊断(检查所有状态)
__DEBUG__.diagnose()

// 2. 查看所有统计信息
__DEBUG__.printStats()

// 3. 导出所有日志
__DEBUG__.exportAll()

// 4. 清空所有日志
__DEBUG__.clearAll()

// 5. 显示帮助信息
__DEBUG__.help()

🚀 第二部分:快速入门(开发者)

📋 系统概述

本系统是专为金融资讯场景设计的实时消息推送系统,基于 Socket.IO 实现 WebSocket 实时通信。消息以右下角层叠弹窗的形式显示,新消息在最上方,符合主流桌面应用的交互习惯。

核心特性

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

技术亮点

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

🏃 快速开始

1. 启动项目

# 开发环境
npm start

# 或使用真实后端
npm run start:real

2. 验证连接

打开浏览器控制台 (F12Console),查看连接状态:

// 查看 Socket 连接状态
__DEBUG__.socket.getStatus()

// 预期输出:
// { connected: true, socketId: "...", reconnectAttempts: 0 }

3. 测试通知

等待后端推送通知,或使用后端 API 手动触发(参见后端集成)。


💻 代码使用

在组件中使用

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>
  );
}

🏗️ 第三部分:系统架构

整体架构图

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

    subgraph "通知系统核心"
        C --> F[socketService<br/>Socket.IO连接]
        C --> J[browserNotificationService<br/>浏览器通知]
        C --> K[notificationHistoryService<br/>历史记录]
        C --> L[notificationMetricsService<br/>性能监控]
    end

    subgraph "后端服务"
        F --> 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
socketService Service Class WebSocket连接管理 src/services/socketService.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


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


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


其他核心组件

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


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


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. 初始化流程

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

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

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. 清理函数
  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


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):

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 天数据
  • 自动清理过期数据

🎨 第六部分:通知类型与配置

🎯 通知类型配置

类型 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,
  },
};

环境配置

API 配置

.env 文件中配置后端地址:

# 开发环境
REACT_APP_API_URL=http://49.232.185.254:5001

# 生产环境
REACT_APP_API_URL=
# 空字符串表示使用相对路径

Socket 连接配置

Socket 服务会自动读取 REACT_APP_API_URL 并连接到后端:

// src/services/socketService.js
const API_BASE_URL = getApiBase();

this.socket = io(API_BASE_URL, {
  transports: ['websocket', 'polling'],
  reconnection: false, // 使用自定义重连策略
  timeout: 20000,
  withCredentials: true,
});

第七部分:增强功能详解

🔔 功能 1智能桌面通知

功能说明

首次收到重要/紧急通知时,自动请求浏览器通知权限,确保用户不错过关键信息。

工作原理

// 在 NotificationContext 中的逻辑
if (priority === URGENT || priority === IMPORTANT) {
  if (browserPermission === 'default' && !hasRequestedPermission) {
    // 首次遇到重要通知,自动请求权限
    await requestBrowserPermission();
    setHasRequestedPermission(true); // 避免重复请求
  }
}

权限状态

  • granted: 已授权,可以发送桌面通知
  • denied: 已拒绝,无法发送桌面通知
  • default: 未请求,首次重要通知时会自动请求

使用示例

自动触发(推荐)

// 无需任何代码,系统自动处理
// 首次收到重要/紧急通知时会自动弹出权限请求

手动请求

import { useNotification } from 'contexts/NotificationContext';

function SettingsPage() {
  const { requestBrowserPermission, browserPermission } = useNotification();

  return (
    <div>
      <p>当前状态: {browserPermission}</p>
      <button onClick={requestBrowserPermission}>
        开启桌面通知
      </button>
    </div>
  );
}

通知分发策略

优先级 页面在前台 页面在后台
紧急 桌面通知 + 网页通知 桌面通知 + 网页通知
重要 网页通知 桌面通知
普通 网页通知 网页通知

📊 功能 2性能监控

功能说明

追踪通知推送的各项指标,包括:

  • 到达率: 发送 vs 接收
  • 点击率: 点击 vs 接收
  • 响应时间: 收到通知到点击的平均时间
  • 类型分布: 各类型通知的数量和效果
  • 时段分布: 每小时推送量

API 参考

获取汇总统计
import { notificationMetricsService } from 'services/notificationMetricsService';

const summary = notificationMetricsService.getSummary();
console.log(summary);
/* 输出:
{
  totalSent: 100,
  totalReceived: 98,
  totalClicked: 45,
  totalDismissed: 53,
  avgResponseTime: 5200, // 毫秒
  clickRate: '45.92',    // 百分比
  deliveryRate: '98.00'  // 百分比
}
*/
获取按类型统计
const byType = notificationMetricsService.getByType();
console.log(byType);
/* 输出:
{
  announcement: { sent: 20, received: 20, clicked: 15, dismissed: 5, clickRate: '75.00' },
  stock_alert: { sent: 30, received: 30, clicked: 20, dismissed: 10, clickRate: '66.67' },
  event_alert: { sent: 40, received: 38, clicked: 10, dismissed: 28, clickRate: '26.32' },
  analysis_report: { sent: 10, received: 10, clicked: 0, dismissed: 10, clickRate: '0.00' }
}
*/
获取每日数据
const dailyData = notificationMetricsService.getDailyData(7); // 最近 7 天
console.log(dailyData);
/* 输出:
[
  { date: '2025-01-15', sent: 15, received: 14, clicked: 6, dismissed: 8, clickRate: '42.86' },
  { date: '2025-01-16', sent: 20, received: 20, clicked: 10, dismissed: 10, clickRate: '50.00' },
  ...
]
*/
导出数据
// 导出为 JSON
const json = notificationMetricsService.exportToJSON();
console.log(json);

// 导出为 CSV
const csv = notificationMetricsService.exportToCSV();
console.log(csv);

在控制台查看实时指标

打开浏览器控制台,执行:

// 查看汇总
import { notificationMetricsService } from './services/notificationMetricsService.js';
console.table(notificationMetricsService.getSummary());

// 查看按类型分布
console.table(notificationMetricsService.getByType());

// 查看最近 7 天数据
console.table(notificationMetricsService.getDailyData(7));

📜 功能 3历史记录

功能说明

持久化存储所有接收到的通知,支持:

  • 查询和筛选
  • 搜索关键词
  • 标记已读/已点击
  • 批量删除
  • 导出JSON/CSV

API 参考

获取历史记录(支持筛选和分页)
import { notificationHistoryService } from 'services/notificationHistoryService';

const result = notificationHistoryService.getHistory({
  type: 'event_alert',      // 可选:筛选类型
  priority: 'urgent',       // 可选:筛选优先级
  readStatus: 'unread',     // 可选:'read' | 'unread' | 'all'
  startDate: Date.now() - 7 * 24 * 60 * 60 * 1000, // 可选:开始日期
  endDate: Date.now(),      // 可选:结束日期
  page: 1,                  // 页码
  pageSize: 20,             // 每页数量
});

console.log(result);
/* 输出:
{
  records: [...],   // 当前页的记录
  total: 150,       // 总记录数
  page: 1,          // 当前页
  pageSize: 20,     // 每页数量
  totalPages: 8     // 总页数
}
*/
搜索历史记录
const results = notificationHistoryService.searchHistory('降准');
console.log(results); // 返回标题/内容中包含"降准"的所有记录
标记已读/已点击
// 标记已读
notificationHistoryService.markAsRead('notification_id');

// 标记已点击
notificationHistoryService.markAsClicked('notification_id');
删除记录
// 删除单条
notificationHistoryService.deleteRecord('notification_id');

// 批量删除
notificationHistoryService.deleteRecords(['id1', 'id2', 'id3']);

// 清空所有
notificationHistoryService.clearHistory();
获取统计数据
const stats = notificationHistoryService.getStats();
console.log(stats);
/* 输出:
{
  total: 500,           // 总记录数
  read: 320,            // 已读数
  unread: 180,          // 未读数
  clicked: 150,         // 已点击数
  clickRate: '30.00',   // 点击率
  byType: {             // 按类型统计
    announcement: 100,
    stock_alert: 150,
    event_alert: 200,
    analysis_report: 50
  },
  byPriority: {         // 按优先级统计
    urgent: 50,
    important: 200,
    normal: 250
  }
}
*/
导出历史记录
// 导出为 JSON 字符串
const json = notificationHistoryService.exportToJSON({
  type: 'event_alert'  // 可选:只导出特定类型
});

// 导出为 CSV 字符串
const csv = notificationHistoryService.exportToCSV();

// 直接下载 JSON 文件
notificationHistoryService.downloadJSON();

// 直接下载 CSV 文件
notificationHistoryService.downloadCSV();

数据结构

每条历史记录包含:

{
  id: 'notif_123',           // 通知 ID
  notification: {            // 完整通知对象
    type: 'event_alert',
    priority: 'urgent',
    title: '...',
    content: '...',
    ...
  },
  receivedAt: 1737459600000, // 接收时间戳
  readAt: 1737459650000,     // 已读时间戳null 表示未读)
  clickedAt: null,           // 已点击时间戳null 表示未点击)
}

存储限制

  • 最大数量: 500 条(超过后自动删除最旧的)
  • 存储位置: localStorage
  • 容量估算: 约 2-5MB取决于通知内容长度

🧪 第八部分:测试指南

🧪 测试快速指南

开发环境测试

# 启动开发服务器
npm start

关键检查:

// 1. 验证连接
__DEBUG__.socket.getStatus()
// 预期: { connected: true, socketId: "..." }

// 2. 系统诊断
__DEBUG__.diagnose()

生产环境测试

访问: https://valuefrontier.cn

// 一键诊断
__DEBUG__.diagnose()

// 导出报告
__DEBUG__.exportAll()

调试工具速查

工具 适用环境 主要功能
__DEBUG__.socket 所有环境 连接状态、配置检查、手动重连
__DEBUG__.api 所有环境 API 日志、错误追踪
__DEBUG__ 所有环境 完整诊断、导出报告、性能监控

常用命令:

// 完整诊断
__DEBUG__.diagnose()

// 查看帮助
__DEBUG__.help()

// 查看连接状态
__DEBUG__.socket.getStatus()

// 手动重连
__DEBUG__.socket.reconnect()

手动测试清单

功能测试

1. 通知显示测试
  • 公告通知显示正确(蓝色系、图标、内容)
  • 股票上涨通知显示为红色系(+图标、红边框)
  • 股票下跌通知显示为绿色系(-图标、绿边框)
  • 事件动向通知显示正确(橙色系)
  • 分析报告(人工)显示正确(紫色系、作者信息)
  • 分析报告AI显示AI徽章
2. 优先级测试
  • 紧急通知:红色标签、粗边框、脉冲动画、不自动关闭
  • 重要通知橙色标签、中等边框、30秒自动关闭
  • 普通通知无标签、细边框、15秒自动关闭
3. 交互测试
  • 点击可点击通知跳转到正确页面
  • 点击不可点击通知无反应
  • 点击关闭按钮关闭通知
  • 音效开关正常工作
  • 清空全部按钮清空所有通知
4. 折叠展开测试
  • 通知数 ≤ 3 时不显示展开按钮
  • 通知数 > 3 时显示"还有X条通知"按钮
  • 点击展开显示所有通知
  • 点击收起恢复显示前3条
5. 队列管理测试
  • 最多显示15条历史通知
  • 超过15条自动移除最旧的
  • 新通知在最上方
  • z-index层级正确最新最高

浏览器通知测试

6. 权限管理测试
  • 首次访问显示权限状态为"default"
  • 点击请求权限按钮弹出浏览器授权对话框
  • 授权后状态变为"granted"
  • 拒绝后状态变为"denied",显示设置指引
7. 浏览器通知显示测试
  • 权限授予后,切换到其他标签页,收到通知时显示系统通知
  • 点击浏览器通知聚焦窗口并跳转到详情页
  • 普通通知8秒后自动关闭
  • 紧急通知需手动关闭

Socket连接测试

8. 连接测试
  • 启动后显示"Connected"状态
  • 后端推送消息能正确接收
  • 断线后自动重连1分钟→2分钟→4分钟
  • 网络恢复时自动重连
  • 标签页重新聚焦时自动重连
  • 重连成功后显示"✓ 已重新连接" 2秒后消失

UI测试

9. 响应式测试
  • 移动端(< 480px宽度 = 屏宽-32px精简显示
  • 小屏480-768px宽度 = 360px
  • 平板768-992px宽度 = 380px
  • 桌面(> 992px宽度 = 400px
10. 动画测试
  • 新通知从底部向上滑入(浮起效果)
  • 关闭通知向右滑出消失
  • 紧急通知边框脉冲动画流畅
  • 折叠/展开动画流畅无卡顿
11. 无障碍测试
  • Tab键可以聚焦到可点击通知
  • 聚焦时显示蓝色轮廓线
  • Enter/Space键可以打开详情
  • 关闭按钮可键盘操作Tab + Enter

性能测试

12. 性能指标测试
  • 发送10条通知打开控制台查看性能指标
  • 点击5条通知检查点击率计算正确
  • 检查平均响应时间计算正确
  • 导出JSON/CSV文件正常
13. 历史记录测试
  • 收到通知后自动保存到历史记录
  • 筛选功能正常(类型、优先级、日期范围、阅读状态)
  • 搜索功能返回正确结果
  • 分页功能正常
  • 统计数据准确
  • 导出JSON/CSV正常

跨浏览器测试

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

🧪 自动化测试用例

单元测试

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);
  });
});

🐛 第九部分:故障排查

🔧 故障排除

问题 1: 通知不显示

检查项

  1. 确认 NotificationProvider 已包裹应用
  2. 检查浏览器控制台是否有错误
  3. 确认 socket 连接状态(使用 __DEBUG__.socket.getStatus()
  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

// 完整诊断
__DEBUG__.diagnose();

问题 5: Socket 连接失败

解决方案

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

使用调试工具

// 查看连接状态
__DEBUG__.socket.getStatus()

// 查看错误日志
__DEBUG__.socket.getLogs()

// 手动重连
__DEBUG__.socket.reconnect()

调试工具

window.DEBUG - 主调试工具

可用命令

// 系统诊断
__DEBUG__.diagnose()          // 检查所有系统状态
__DEBUG__.printStats()        // 打印所有统计信息
__DEBUG__.performance()       // 性能监控

// 日志管理
__DEBUG__.exportAll()         // 导出所有日志
__DEBUG__.clearAll()          // 清空所有日志

// 帮助信息
__DEBUG__.help()              // 显示帮助信息

window.DEBUG.socket - Socket 调试

可用命令

// 连接管理
__DEBUG__.socket.getStatus()     // 获取连接状态
__DEBUG__.socket.reconnect()     // 手动重连

// 日志管理
__DEBUG__.socket.getLogs()       // 获取所有 Socket 日志
__DEBUG__.socket.clearLogs()     // 清空日志
__DEBUG__.socket.exportLogs()    // 导出日志

window.DEBUG.api - API 调试

可用命令

// 日志查询
__DEBUG__.api.getLogs()              // 获取所有 API 日志
__DEBUG__.api.getRecentErrors()      // 获取最近的错误

// 测试请求
__DEBUG__.api.testRequest('GET', '/api/endpoint')

// 日志管理
__DEBUG__.api.exportLogs()           // 导出日志
__DEBUG__.api.clearLogs()            // 清空日志

日志分析

正常日志流程

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 秒
  • 避免短时间内大量推送造成用户困扰

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;

🔒 安全注意事项

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

附录

🌐 后端集成(生产环境)

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)

📝 更新日志

v3.0.0 (2025-11-17) - 文档合并与更新

  • 合并 ENHANCED_FEATURES_GUIDE.md 内容
  • 移除过时的 Mock 模式引用
  • 更新所有调试工具引用(统一使用 window.__DEBUG__
  • 更新代码示例与最新代码一致
  • 完善增强功能文档(智能桌面通知、性能监控、历史记录)
  • 更新测试指南

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

  • 指数退避重连策略
  • 连接状态横幅优化
  • 手动关闭状态持久化

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.0.0 (2024-12-27) - 金融资讯专业版

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

📁 文件结构

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

📞 支持

如有问题,请查看:

  • 用户快速指南: 本文档开头的用户快速指南
  • 项目文档: CLAUDE.md
  • 调试命令: 浏览器控制台使用 __DEBUG__.help() 查看所有可用命令
  • 控制台日志: 所有操作都有详细日志
  • 类型定义: src/constants/notificationTypes.js

祝你使用愉快! 🎉