# 实时消息推送系统 - 完整技术文档
> **版本**: v2.11.0
> **更新日期**: 2025-01-07
> **文档类型**: 快速入门 + 完整技术规格
---
## 📑 目录
### 第一部分:快速入门
1. [系统简介](#-系统概述)
2. [核心特性](#核心特性)
3. [5分钟快速开始](#-快速开始)
4. [基础使用示例](#-代码使用)
### 第二部分:系统架构
5. [整体架构设计](#-系统架构设计)
6. [技术栈选型](#-技术栈)
7. [数据流向](#数据流向)
8. [双重通知策略](#双重通知策略)
### 第三部分:核心组件详解
9. [组件清单](#-核心组件清单)
10. [NotificationContext](#1-notificationcontext---通知上下文)
11. [NotificationContainer](#2-notificationcontainer---通知容器ui)
12. [SocketService](#3-socketservice---websocket服务)
13. [其他核心组件](#其他核心组件)
### 第四部分:设计流程
14. [消息推送完整流程](#-消息推送完整流程)
15. [初始化流程](#1-初始化流程)
16. [消息接收与适配](#2-消息接收与适配)
17. [通知分发策略](#3-通知分发策略)
18. [性能监控埋点](#4-性能监控埋点)
### 第五部分:测试指南
19. [测试快速指南](#-测试快速指南)
20. [手动测试清单](#-手动测试清单)
21. [自动化测试](#-自动化测试用例)
22. [测试覆盖率](#测试覆盖率目标)
### 第六部分:配置与扩展
23. [通知类型配置](#-通知类型配置)
24. [优先级配置](#-优先级配置)
25. [环境配置](#环境配置)
26. [后端集成](#-后端集成生产环境)
### 第七部分:故障排查
27. [常见问题FAQ](#-故障排除)
28. [调试工具](#调试工具)
29. [日志分析](#日志分析)
### 第八部分:最佳实践
30. [开发规范](#-开发规范)
31. [性能优化](#-性能优化建议)
32. [安全注意事项](#安全注意事项)
### 附录
33. [更新日志](#-更新日志)
34. [文件结构](#-文件结构)
---
## 🆕 最新更新 (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、useCallback,GPU 加速动画
---
## 🏗️ 系统架构设计
### 整体架构图
```mermaid
graph TB
subgraph "前端应用"
A[App.js] --> B[AppProviders]
B --> C[NotificationProvider
NotificationContext]
C --> D[NotificationContainer
通知容器UI]
C --> E[NotificationTestTool
开发测试工具]
end
subgraph "通知系统核心"
C --> F[Socket Service
WebSocket连接]
F --> G{环境判断}
G -->|Mock| H[mockSocketService
模拟服务]
G -->|Real| I[socketService
生产服务]
C --> J[browserNotificationService
浏览器通知]
C --> K[notificationHistoryService
历史记录]
C --> L[notificationMetricsService
性能监控]
end
subgraph "后端服务"
I --> M[Flask Backend
Socket.IO Server]
M --> N[(ClickHouse
事件数据)]
M --> O[(MySQL
用户数据)]
end
subgraph "数据存储"
K --> P[(localStorage
历史记录)]
L --> Q[(localStorage
性能指标)]
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**: 消息队列、异步任务
### 数据流向
```mermaid
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**:
```javascript
const {
notifications, // 当前通知队列
isConnected, // Socket连接状态
soundEnabled, // 音效开关状态
browserPermission, // 浏览器通知权限状态
connectionStatus, // 详细连接状态
addNotification, // 添加通知
removeNotification, // 移除通知
clearAllNotifications, // 清空所有通知
toggleSound, // 切换音效
requestBrowserPermission, // 请求浏览器通知权限
trackNotificationClick, // 追踪通知点击
retryConnection, // 手动重连
showWelcomeGuide, // 显示欢迎引导
showCommunityGuide, // 显示社区功能引导
showFirstFollowGuide, // 显示首次关注引导
} = useNotification();
```
**关键实现细节**:
1. **双重去重机制**:
```javascript
// Socket层去重(避免重复接收)
const processedEventIds = useRef(new Set());
// 显示层去重(避免重复显示)
const isDuplicate = notifications.some(n => n.id === notificationId);
```
2. **智能分发策略**:
```javascript
const isPageHidden = document.hidden;
if (isPageHidden) {
sendBrowserNotification(notification); // 后台:浏览器通知
} else {
addWebNotification(notification); // 前台:网页通知
}
```
3. **渐进式权限引导**:
```javascript
// 登录后显示欢迎引导
showWelcomeGuide();
// 首次关注事件时显示引导
showFirstFollowGuide();
```
**源码位置**: `src/contexts/NotificationContext.js:1-829`
---
### 2. NotificationContainer - 通知容器UI
**职责**:通知的可视化展示,处理动画、交互、无障碍。
**核心功能**:
- 通知列表渲染(最多显示3条)
- 折叠/展开功能
- 通知动画(Framer Motion)
- 点击跳转
- 无障碍支持(ARIA、键盘导航)
**主要组件**:
```jsx
{/* 可见通知 */}
{visibleNotifications.map(notification => (
))}
{/* 折叠按钮 */}
{hasMore && (
)}
```
**关键实现细节**:
1. **优先级视觉表现**:
```javascript
// 紧急通知:粗边框 + 深色背景 + 脉冲动画
borderWidth: priority === URGENT ? '6px' : '2px'
animation: priority === URGENT ? pulseAnimation : undefined
```
2. **严格可点击性判断**:
```javascript
const isActuallyClickable = clickable && link; // 两者都必须为true
cursor: isActuallyClickable ? 'pointer' : 'default'
```
3. **性能优化**:
```javascript
// 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 连接管理
- 指数退避重连策略
- 事件订阅/取消订阅
- 消息发送/接收
**重连策略**:
```javascript
// 指数退避延迟
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**:
```javascript
// 连接管理
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 - 浏览器通知服务
**核心方法**:
```javascript
// 检查支持性
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**:
```javascript
// 保存通知
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**:
```javascript
// 追踪事件
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. 初始化流程
```mermaid
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):
```javascript
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. 消息接收与适配
```mermaid
graph TB
A[后端推送事件] --> B{Socket层去重}
B -->|已存在| C[忽略]
B -->|新事件| D[触发 new_event]
D --> E{数据格式检测}
E -->|前端格式| F[直接使用]
E -->|后端格式| G[格式适配]
G --> H[映射重要性
S/A→urgent/important
B/C→normal]
H --> I[构建通知对象]
I --> J[生成跳转链接
/event-detail/id]
J --> K[添加元数据]
K --> L{显示层去重}
L -->|已存在| M[忽略]
L -->|新通知| N[添加到队列]
```
**后端事件格式** → **前端通知格式** 适配器:
```javascript
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. 通知分发策略
```mermaid
graph TB
A[收到新通知] --> B{检查浏览器权限}
B -->|default| C[自动请求权限]
B -->|denied| D[显示设置指引]
B -->|granted| E{检查页面可见性}
E -->|document.hidden=true
页面在后台| F[发送浏览器通知]
E -->|document.hidden=false
页面在前台| 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):
```javascript
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. 性能监控埋点
系统自动追踪以下事件:
```javascript
// 通知接收时
notificationMetricsService.trackReceived(notification);
// 通知点击时
notificationMetricsService.trackClicked(notification);
// 自动计算响应时间 = 点击时间 - 接收时间
// 通知关闭时
notificationMetricsService.trackDismissed(notification);
```
**性能指标计算**:
```javascript
// 点击率
clickRate = (totalClicked / totalReceived) * 100
// 平均响应时间
avgResponseTime = totalResponseTime / totalClicked
// 到达率(假设sent=received)
deliveryRate = (totalReceived / totalSent) * 100
```
**数据存储**:
- localStorage 持久化
- 最多保留 30 天数据
- 自动清理过期数据
---
## 🧪 测试快速指南
> 📖 **完整测试手册**: [notification-manual-testing-guide.md](./test-cases/notification-manual-testing-guide.md)
### 本地测试
#### Mock 模式(快速开发测试)
```bash
npm start
```
**关键检查**:
```javascript
// 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 模式(后端联调)
```bash
npm run start:real
```
**关键检查**:
```javascript
// 1. 验证连接
__SOCKET_DEBUG__.getStatus()
// 预期: { type: "REAL", connected: true }
// 2. 手动订阅
__NOTIFY_DEBUG__.subscribe()
// 3. 等待后端推送
// 观察控制台: "✅ New event received"
```
### 线上测试
**访问**: https://valuefrontier.cn
```javascript
// 一键诊断
__NOTIFY_DEBUG__.checkAll()
// 手动订阅
__NOTIFY_DEBUG__.subscribe()
// 导出报告
__NOTIFY_DEBUG__.exportReport()
```
### 调试工具速查
| 工具 | 适用环境 | 主要功能 |
|------|---------|---------|
| `__mockSocket` | Mock模式 | 模拟断线、暂停推送、测试重连 |
| `__SOCKET_DEBUG__` | 所有环境 | 连接状态、配置检查、手动订阅 |
| `__NOTIFY_DEBUG__` | 所有环境 | 完整诊断、模拟通知、导出报告 |
**常用命令**:
```javascript
// 完整诊断
__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模式 | ⏳ 等待后端 | 取决于后端 | 测试后端集成和真实数据 |
**推荐用法**:
```javascript
// 场景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](./test-cases/notification-tests.md)**
以下是核心测试用例概览:
### 单元测试
#### NotificationContext 测试
```javascript
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 测试
```javascript
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');
});
// 更多测试用例...
});
```
### 集成测试
```javascript
describe('通知系统集成测试', () => {
test('完整流程:从接收到显示到点击', async () => {
render(
);
// 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)`
**示例**:
```javascript
{
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` 字段):
- **涨(+)**:红色系 🔴
- **跌(-)**:绿色系 🟢
**示例(涨)**:
```javascript
{
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
**示例**:
```javascript
{
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)**:
```javascript
{
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秒 | 常规消息、信息推送 |
**配置代码**:
```javascript
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` 文件中添加:
```bash
REACT_APP_ENABLE_MOCK=true
```
### 2. 启动项目
```bash
npm start
```
### 3. 测试通知
打开浏览器,右上角会显示 **"金融资讯测试工具"**,包含:
#### 通知类型测试
- 公告通知、股票动向、事件动向、分析报告
- 预测通知(不可跳转)
#### 组合测试
- 预测→详情流程(5秒延迟)
#### 功能按钮
- 清空全部、音效开关、队列状态
### 4. 自动推送
Mock 模式下,系统会自动每 60 秒推送 1-2 条随机金融资讯。
---
## 💻 代码使用
### 在组件中使用
```javascript
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 (
连接状态: {isConnected ? '已连接' : '未连接'}
);
}
```
---
## 🔧 环境配置
### 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` 中:
```javascript
// 默认: 60秒推送1-2条
socket.startMockPush(60000, 2);
// 修改为: 30秒推送1条
socket.startMockPush(30000, 1);
// 修改为: 5秒推送3条(压力测试)
socket.startMockPush(5000, 3);
```
---
## 🌐 后端集成(生产环境)
### Flask-SocketIO 配置
```python
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)
```
### 后端推送示例
```python
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 隐私模式:通知权限被永久拒绝,无法更改
- 建议:使用普通浏览器窗口以获得完整体验
**快速诊断**:
```javascript
// 在浏览器控制台运行
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)
#### ✅ 当前系统已自动处理
**好消息**:您的通知系统已经完美处理了这种情况!
**自动降级策略**:
```javascript
// 在 NotificationContext.js 中
if (browserPermission !== 'granted') {
// 跳过浏览器通知,只显示网页内通知
logger.warn('NotificationContext', 'Browser permission not granted');
return;
}
```
**用户引导机制**:
- 当权限为 `denied` 时,自动显示橙色提示框
- 提示内容:"浏览器通知已被拒绝"
- 引导文案:"💡 如需接收桌面通知,请在浏览器设置中允许通知权限"
**实际效果**:
- ✅ 网页内通知卡片继续正常显示
- ⏭️ 浏览器桌面通知被优雅跳过
- ✅ 所有核心功能不受影响
- ✅ 用户体验降级合理
#### 🛠️ 三种解决方案
**方案 1:退出无痕模式(强烈推荐)**
```bash
# 原因:
# - 权限会永久保存
# - 获得完整通知体验
# - 不需要每次重新授权
# 操作:使用普通浏览器窗口访问应用
```
**方案 2:接受降级体验(推荐)**
```bash
# 系统已自动处理:
# ✅ 网页内通知正常显示(通知卡片)
# ⏭️ 桌面通知被跳过
# ✅ 不影响核心功能
# ✅ 用户体验合理
# 操作:无需任何操作,系统自动降级
```
**方案 3:在无痕模式中重新授权(仅 Chrome/Firefox)**
**Chrome 无痕模式**:
1. 点击地址栏左侧的 🔒 锁图标
2. 找到"通知"设置项
3. 将"阻止"改为"允许"
4. 刷新页面(F5)
5. ⚠️ **注意**:关闭无痕窗口后需要重新授权
**Safari 隐私模式**:
```bash
# ❌ Safari 隐私模式无法更改权限
# 💡 建议:退出隐私模式或接受降级体验
```
#### 📊 调试与验证
**快速检查权限状态**:
```javascript
// 在浏览器控制台运行
// 方法 1:直接查看
console.log('Permission:', Notification.permission);
// 输出: 'granted' | 'denied' | 'default'
// 方法 2:检查是否支持
console.log('Supported:', 'Notification' in window);
// 输出: true | false
// 方法 3:完整诊断(推荐)
window.__NOTIFY_DEBUG__.checkAll();
```
**完整诊断输出示例**:
```bash
========== 【通知系统诊断】 ==========
✓ Socket 配置检查完成
✓ 连接状态: ✅ 已连接
✓ API Base: http://49.232.185.254:5001
✓ 浏览器通知权限: denied
========== 诊断报告 ==========
┌─────────────┬────────────────────┐
│ socket.type │ MOCK │
│ connected │ true │
│ permission │ denied │
└─────────────┴────────────────────┘
⚠️ 发现问题: ['浏览器通知权限被拒绝']
💡 修复建议:
1. 如在无痕/隐私模式,建议退出使用正常模式
2. Chrome: 点击地址栏🔒 → 通知 → 允许
3. 或接受降级体验:继续使用网页内通知
====================================
```
**测试通知(仅 Mock 模式)**:
```javascript
// 测试不同类型通知
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();
```
#### 🎯 最佳实践建议
**开发环境**:
```javascript
// 使用 Mock 模式 + Chrome 正常窗口
// .env.mock
REACT_APP_ENABLE_MOCK=true
// 一次授权,永久有效
```
**测试环境**:
```javascript
// 测试多种权限状态
// 1. granted - 正常授权
// 2. denied - 测试降级体验
// 3. default - 测试首次访问流程
```
**生产环境**:
```javascript
// 引导用户使用正常浏览器窗口
// 提供清晰的权限说明
// 降级体验要优雅
```
#### 📝 相关代码位置
**权限处理逻辑**:
- `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. 查看控制台日志确认错误信息
### 调试工具
**控制台日志**:
```javascript
// 所有操作都有详细日志
logger.info('NotificationContext', 'Event', data);
logger.warn('NotificationContext', 'Warning', error);
logger.error('NotificationContext', 'Error', error);
```
**Mock模式测试函数**:
```javascript
// 查看可用函数
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. 更新文档
**示例**:
```javascript
// 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. 自定义通知组件
如需完全自定义通知样式:
```javascript
import { useNotification } from 'contexts/NotificationContext';
function CustomNotification({ notification }) {
const { removeNotification, trackNotificationClick } = useNotification();
const handleClick = () => {
trackNotificationClick(notification.id);
// 自定义导航逻辑
removeNotification(notification.id, true);
};
return (
{/* 自定义样式 */}
);
}
```
### 3. 扩展性能监控
添加自定义指标:
```javascript
// 在 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 性能优化 ✅ 已实现
```javascript
// 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 优化
```javascript
// 定期清理过期数据
notificationHistoryService.cleanup(100);
// 限制最大存储数量
MAX_HISTORY_SIZE = 500;
// 压缩存储数据(可选)
const compressedData = LZ.compress(JSON.stringify(data));
```
---
## 🔒 安全注意事项
### 1. XSS 防护
```javascript
// ✅ 正确:使用 React 自动转义
{notification.title}
// ❌ 错误:使用 dangerouslySetInnerHTML
```
### 2. 链接验证
```javascript
// 跳转前验证链接合法性
const isValidLink = (link) => {
return link && link.startsWith('/'); // 只允许内部链接
};
if (isActuallyClickable && isValidLink(link)) {
navigate(link);
}
```
### 3. 敏感信息保护
```javascript
// 不要在通知中显示敏感信息
// ❌ 错误
content: `您的密码是:${password}`
// ✅ 正确
content: '密码修改成功,请重新登录'
```
### 4. localStorage 安全
```javascript
// 不要存储敏感数据到 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`
---
**祝你使用愉快!** 🎉