diff --git a/docs/ENHANCED_FEATURES_GUIDE.md b/docs/ENHANCED_FEATURES_GUIDE.md
deleted file mode 100644
index 9fc726a5..00000000
--- a/docs/ENHANCED_FEATURES_GUIDE.md
+++ /dev/null
@@ -1,626 +0,0 @@
-# 通知系统增强功能 - 使用指南
-
-## 📋 概述
-
-本指南介绍通知系统的三大增强功能:
-1. **智能桌面通知** - 自动请求权限,系统级通知
-2. **性能监控** - 追踪推送效果,数据驱动优化
-3. **历史记录** - 持久化存储,随时查询
-
----
-
-## 🎯 功能 1:智能桌面通知
-
-### 功能说明
-
-首次收到重要/紧急通知时,自动请求浏览器通知权限,确保用户不错过关键信息。
-
-### 工作原理
-
-```javascript
-// 在 NotificationContext 中的逻辑
-if (priority === URGENT || priority === IMPORTANT) {
- if (browserPermission === 'default' && !hasRequestedPermission) {
- // 首次遇到重要通知,自动请求权限
- await requestBrowserPermission();
- setHasRequestedPermission(true); // 避免重复请求
- }
-}
-```
-
-### 权限状态
-
-- **granted**: 已授权,可以发送桌面通知
-- **denied**: 已拒绝,无法发送桌面通知
-- **default**: 未请求,首次重要通知时会自动请求
-
-### 使用示例
-
-**自动触发**(推荐)
-```javascript
-// 无需任何代码,系统自动处理
-// 首次收到重要/紧急通知时会自动弹出权限请求
-```
-
-**手动请求**
-```javascript
-import { useNotification } from 'contexts/NotificationContext';
-
-function SettingsPage() {
- const { requestBrowserPermission, browserPermission } = useNotification();
-
- return (
-
-
当前状态: {browserPermission}
-
-
- );
-}
-```
-
-### 通知分发策略
-
-| 优先级 | 页面在前台 | 页面在后台 |
-|-------|----------|----------|
-| 紧急 | 桌面通知 + 网页通知 | 桌面通知 + 网页通知 |
-| 重要 | 网页通知 | 桌面通知 |
-| 普通 | 网页通知 | 网页通知 |
-
-### 测试步骤
-
-1. **清除已保存的权限状态**
- ```javascript
- localStorage.removeItem('browser_notification_requested');
- ```
-
-2. **刷新页面**
-
-3. **触发一个重要/紧急通知**
- - Mock 模式:等待自动推送
- - Real 模式:创建测试事件
-
-4. **观察权限请求弹窗**
- - 浏览器会弹出通知权限请求
- - 点击"允许"授权
-
-5. **验证桌面通知**
- - 切换到其他标签页
- - 收到重要通知时应该看到桌面通知
-
----
-
-## 📊 功能 2:性能监控
-
-### 功能说明
-
-追踪通知推送的各项指标,包括:
-- **到达率**: 发送 vs 接收
-- **点击率**: 点击 vs 接收
-- **响应时间**: 收到通知到点击的平均时间
-- **类型分布**: 各类型通知的数量和效果
-- **时段分布**: 每小时推送量
-
-### API 参考
-
-#### 获取汇总统计
-
-```javascript
-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' // 百分比
-}
-*/
-```
-
-#### 获取按类型统计
-
-```javascript
-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' }
-}
-*/
-```
-
-#### 获取按优先级统计
-
-```javascript
-const byPriority = notificationMetricsService.getByPriority();
-console.log(byPriority);
-/* 输出:
-{
- urgent: { sent: 10, received: 10, clicked: 9, dismissed: 1, clickRate: '90.00' },
- important: { sent: 40, received: 39, clicked: 25, dismissed: 14, clickRate: '64.10' },
- normal: { sent: 50, received: 49, clicked: 11, dismissed: 38, clickRate: '22.45' }
-}
-*/
-```
-
-#### 获取每日数据
-
-```javascript
-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' },
- ...
-]
-*/
-```
-
-#### 获取完整指标
-
-```javascript
-const allMetrics = notificationMetricsService.getAllMetrics();
-console.log(allMetrics);
-```
-
-#### 导出数据
-
-```javascript
-// 导出为 JSON
-const json = notificationMetricsService.exportToJSON();
-console.log(json);
-
-// 导出为 CSV
-const csv = notificationMetricsService.exportToCSV();
-console.log(csv);
-```
-
-#### 重置指标
-
-```javascript
-notificationMetricsService.reset();
-```
-
-### 在控制台查看实时指标
-
-打开浏览器控制台,执行:
-
-```javascript
-// 引入服务
-import { notificationMetricsService } from './services/notificationMetricsService.js';
-
-// 查看汇总
-console.table(notificationMetricsService.getSummary());
-
-// 查看按类型分布
-console.table(notificationMetricsService.getByType());
-
-// 查看最近 7 天数据
-console.table(notificationMetricsService.getDailyData(7));
-```
-
-### 监控埋点(自动)
-
-监控服务已自动集成到 `NotificationContext`,无需手动调用:
-
-- **trackReceived**: 收到通知时自动调用
-- **trackClicked**: 点击通知时自动调用
-- **trackDismissed**: 关闭通知时自动调用
-
-### 可视化展示(可选)
-
-你可以基于监控数据创建仪表板:
-
-```javascript
-import { notificationMetricsService } from 'services/notificationMetricsService';
-import { PieChart, LineChart } from 'recharts';
-
-function MetricsDashboard() {
- const summary = notificationMetricsService.getSummary();
- const dailyData = notificationMetricsService.getDailyData(7);
- const byType = notificationMetricsService.getByType();
-
- return (
-
- {/* 汇总卡片 */}
-
-
-
-
- {/* 类型分布饼图 */}
-
({
- name: type,
- value: data.received
- }))} />
-
- {/* 每日趋势折线图 */}
-
-
- );
-}
-```
-
----
-
-## 📜 功能 3:历史记录
-
-### 功能说明
-
-持久化存储所有接收到的通知,支持:
-- 查询和筛选
-- 搜索关键词
-- 标记已读/已点击
-- 批量删除
-- 导出(JSON/CSV)
-
-### API 参考
-
-#### 获取历史记录(支持筛选和分页)
-
-```javascript
-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 // 总页数
-}
-*/
-```
-
-#### 搜索历史记录
-
-```javascript
-const results = notificationHistoryService.searchHistory('降准');
-console.log(results); // 返回标题/内容中包含"降准"的所有记录
-```
-
-#### 标记已读/已点击
-
-```javascript
-// 标记已读
-notificationHistoryService.markAsRead('notification_id');
-
-// 标记已点击
-notificationHistoryService.markAsClicked('notification_id');
-```
-
-#### 删除记录
-
-```javascript
-// 删除单条
-notificationHistoryService.deleteRecord('notification_id');
-
-// 批量删除
-notificationHistoryService.deleteRecords(['id1', 'id2', 'id3']);
-
-// 清空所有
-notificationHistoryService.clearHistory();
-```
-
-#### 获取统计数据
-
-```javascript
-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
- }
-}
-*/
-```
-
-#### 导出历史记录
-
-```javascript
-// 导出为 JSON 字符串
-const json = notificationHistoryService.exportToJSON({
- type: 'event_alert' // 可选:只导出特定类型
-});
-
-// 导出为 CSV 字符串
-const csv = notificationHistoryService.exportToCSV();
-
-// 直接下载 JSON 文件
-notificationHistoryService.downloadJSON();
-
-// 直接下载 CSV 文件
-notificationHistoryService.downloadCSV();
-```
-
-### 在控制台使用
-
-打开浏览器控制台,执行:
-
-```javascript
-// 引入服务
-import { notificationHistoryService } from './services/notificationHistoryService.js';
-
-// 查看所有历史
-console.table(notificationHistoryService.getHistory().records);
-
-// 搜索
-const results = notificationHistoryService.searchHistory('央行');
-console.table(results);
-
-// 查看统计
-console.table(notificationHistoryService.getStats());
-
-// 导出并下载
-notificationHistoryService.downloadJSON();
-```
-
-### 数据结构
-
-每条历史记录包含:
-
-```javascript
-{
- id: 'notif_123', // 通知 ID
- notification: { // 完整通知对象
- type: 'event_alert',
- priority: 'urgent',
- title: '...',
- content: '...',
- ...
- },
- receivedAt: 1737459600000, // 接收时间戳
- readAt: 1737459650000, // 已读时间戳(null 表示未读)
- clickedAt: null, // 已点击时间戳(null 表示未点击)
-}
-```
-
-### 存储限制
-
-- **最大数量**: 500 条(超过后自动删除最旧的)
-- **存储位置**: localStorage
-- **容量估算**: 约 2-5MB(取决于通知内容长度)
-
----
-
-## 🔧 技术细节
-
-### 文件结构
-
-```
-src/
-├── services/
-│ ├── browserNotificationService.js [已存在] 浏览器通知服务
-│ ├── notificationMetricsService.js [新建] 性能监控服务
-│ └── notificationHistoryService.js [新建] 历史记录服务
-├── contexts/
-│ └── NotificationContext.js [修改] 集成所有功能
-└── components/
- └── NotificationContainer/
- └── index.js [修改] 添加点击追踪
-```
-
-### 修改清单
-
-| 文件 | 修改内容 | 状态 |
-|------|---------|------|
-| `NotificationContext.js` | 添加智能权限请求、监控埋点、历史保存 | ✅ 已完成 |
-| `NotificationContainer/index.js` | 添加点击追踪 | ✅ 已完成 |
-| `notificationMetricsService.js` | 性能监控服务 | ✅ 已创建 |
-| `notificationHistoryService.js` | 历史记录服务 | ✅ 已创建 |
-
-### 数据流
-
-```
-用户收到通知
- ↓
-NotificationContext.addWebNotification()
- ├─ notificationMetricsService.trackReceived() [监控埋点]
- ├─ notificationHistoryService.saveNotification() [历史保存]
- ├─ 首次重要通知 → requestBrowserPermission() [智能权限]
- └─ 显示网页通知或桌面通知
-
-用户点击通知
- ↓
-NotificationContainer.handleClick()
- ├─ notificationMetricsService.trackClicked() [监控埋点]
- ├─ notificationHistoryService.markAsClicked() [历史标记]
- └─ 跳转到目标页面
-
-用户关闭通知
- ↓
-NotificationContext.removeNotification()
- └─ notificationMetricsService.trackDismissed() [监控埋点]
-```
-
----
-
-## 🧪 测试步骤
-
-### 1. 测试智能桌面通知
-
-```bash
-# 1. 清除已保存的权限状态
-localStorage.removeItem('browser_notification_requested');
-
-# 2. 刷新页面
-
-# 3. 等待或触发一个重要/紧急通知
-
-# 4. 观察浏览器弹出权限请求
-
-# 5. 授权后验证桌面通知功能
-```
-
-### 2. 测试性能监控
-
-```javascript
-// 在控制台执行
-import { notificationMetricsService } from './services/notificationMetricsService.js';
-
-// 查看实时统计
-console.table(notificationMetricsService.getSummary());
-
-// 模拟推送几条通知,再次查看
-console.table(notificationMetricsService.getAllMetrics());
-
-// 导出数据
-console.log(notificationMetricsService.exportToJSON());
-```
-
-### 3. 测试历史记录
-
-```javascript
-// 在控制台执行
-import { notificationHistoryService } from './services/notificationHistoryService.js';
-
-// 查看历史
-console.table(notificationHistoryService.getHistory().records);
-
-// 搜索
-console.table(notificationHistoryService.searchHistory('降准'));
-
-// 查看统计
-console.table(notificationHistoryService.getStats());
-
-// 导出
-notificationHistoryService.downloadJSON();
-```
-
----
-
-## 📈 数据导出示例
-
-### 导出性能监控数据
-
-```javascript
-import { notificationMetricsService } from 'services/notificationMetricsService';
-
-// 导出 JSON
-const json = notificationMetricsService.exportToJSON();
-// 复制到剪贴板或保存
-
-// 导出 CSV
-const csv = notificationMetricsService.exportToCSV();
-// 可以在 Excel 中打开
-```
-
-### 导出历史记录
-
-```javascript
-import { notificationHistoryService } from 'services/notificationHistoryService';
-
-// 导出最近 7 天的事件动向通知
-const json = notificationHistoryService.exportToJSON({
- type: 'event_alert',
- startDate: Date.now() - 7 * 24 * 60 * 60 * 1000
-});
-
-// 直接下载为文件
-notificationHistoryService.downloadJSON({
- type: 'event_alert'
-});
-```
-
----
-
-## ⚠️ 注意事项
-
-### 1. localStorage 容量限制
-
-- 大多数浏览器限制为 5-10MB
-- 建议定期清理历史记录和监控数据
-- 使用导出功能备份数据
-
-### 2. 浏览器兼容性
-
-- **桌面通知**: 需要 HTTPS 或 localhost
-- **localStorage**: 所有现代浏览器支持
-- **权限请求**: 需要用户交互(不能自动授权)
-
-### 3. 隐私和数据安全
-
-- 所有数据存储在本地(localStorage)
-- 不会上传到服务器
-- 用户可以随时清空数据
-
-### 4. 性能影响
-
-- 监控埋点非常轻量,几乎无性能影响
-- 历史记录保存异步进行,不阻塞 UI
-- 数据查询在客户端完成,不增加服务器负担
-
----
-
-## 🎉 总结
-
-### 已实现的功能
-
-✅ **智能桌面通知**
-- 首次重要通知时自动请求权限
-- 智能分发策略(前台/后台)
-- localStorage 持久化权限状态
-
-✅ **性能监控**
-- 到达率、点击率、响应时间追踪
-- 按类型、优先级、时段统计
-- 数据导出(JSON/CSV)
-
-✅ **历史记录**
-- 持久化存储(最多 500 条)
-- 筛选、搜索、分页
-- 已读/已点击标记
-- 数据导出(JSON/CSV)
-
-### 未实现的功能(备份,待上线)
-
-⏸️ 历史记录页面 UI(代码已备份,随时可上线)
-⏸️ 监控仪表板 UI(可选,暂未实现)
-
-### 下一步建议
-
-1. **用户设置页面**: 允许用户自定义通知偏好
-2. **声音提示**: 为紧急通知添加音效
-3. **数据同步**: 将历史和监控数据同步到服务器
-4. **高级筛选**: 添加更多筛选维度(如关键词、股票代码等)
-
----
-
-**文档版本**: v1.0
-**最后更新**: 2025-01-21
-**维护者**: Claude Code
diff --git a/docs/NOTIFICATION_SYSTEM.md b/docs/NOTIFICATION_SYSTEM.md
index 224a7a4b..51f16a40 100644
--- a/docs/NOTIFICATION_SYSTEM.md
+++ b/docs/NOTIFICATION_SYSTEM.md
@@ -1,103 +1,83 @@
# 实时消息推送系统 - 完整技术文档
-> **版本**: v2.12.0
+> **版本**: v3.0.0
> **更新日期**: 2025-11-17
> **文档类型**: 用户指南 + 完整技术规格
>
-> ⚠️ **重要更新**:
-> - 测试工具已移除(2025-11-17):NotificationTestTool、window.__TEST_NOTIFICATION__、notificationDebugger
-> - 保留生产可用调试工具:window.__DEBUG__、window.browserNotificationService
+> 🎯 **重要说明**:
+> - 本文档已合并原 `ENHANCED_FEATURES_GUIDE.md` 的内容
+> - 所有 API 引用和代码示例已更新至最新版本
+> - 调试工具统一使用 `window.__DEBUG__`
---
## 📑 目录
-### 👤 第零部分:用户快速指南
-0. [连接状态查看](#-连接状态查看)
-1. [手动操作指南](#-手动操作指南)
-2. [常见问题解决](#-常见问题解决)
-3. [可用调试命令](#-可用调试命令)
+### 👤 第一部分:用户快速指南
+1. [连接状态查看](#-连接状态查看)
+2. [手动操作指南](#-手动操作指南)
+3. [常见问题解决](#-常见问题解决)
+4. [可用调试命令](#-可用调试命令)
-### 第一部分:快速入门(开发者)
-1. [系统简介](#-系统概述)
-2. [核心特性](#核心特性)
-3. [5分钟快速开始](#-快速开始)
-4. [基础使用示例](#-代码使用)
+### 🚀 第二部分:快速入门(开发者)
+5. [系统简介](#-系统概述)
+6. [核心特性](#核心特性)
+7. [5分钟快速开始](#-快速开始)
+8. [基础使用示例](#-代码使用)
-### 第二部分:系统架构
-5. [整体架构设计](#-系统架构设计)
-6. [技术栈选型](#-技术栈)
-7. [数据流向](#数据流向)
-8. [双重通知策略](#双重通知策略)
+### 🏗️ 第三部分:系统架构
+9. [整体架构设计](#-系统架构设计)
+10. [技术栈选型](#-技术栈)
+11. [数据流向](#数据流向)
+12. [双重通知策略](#双重通知策略)
-### 第三部分:核心组件详解
-9. [组件清单](#-核心组件清单)
-10. [NotificationContext](#1-notificationcontext---通知上下文)
-11. [NotificationContainer](#2-notificationcontainer---通知容器ui)
-12. [SocketService](#3-socketservice---websocket服务)
-13. [其他核心组件](#其他核心组件)
+### 🧩 第四部分:核心组件详解
+13. [组件清单](#-核心组件清单)
+14. [NotificationContext](#1-notificationcontext---通知上下文)
+15. [NotificationContainer](#2-notificationcontainer---通知容器ui)
+16. [SocketService](#3-socketservice---websocket服务)
+17. [其他核心组件](#其他核心组件)
-### 第四部分:设计流程
-14. [消息推送完整流程](#-消息推送完整流程)
-15. [初始化流程](#1-初始化流程)
-16. [消息接收与适配](#2-消息接收与适配)
-17. [通知分发策略](#3-通知分发策略)
-18. [性能监控埋点](#4-性能监控埋点)
+### 🔄 第五部分:设计流程
+18. [消息推送完整流程](#-消息推送完整流程)
+19. [初始化流程](#1-初始化流程)
+20. [消息接收与适配](#2-消息接收与适配)
+21. [通知分发策略](#3-通知分发策略)
+22. [性能监控埋点](#4-性能监控埋点)
-### 第五部分:测试指南
-19. [测试快速指南](#-测试快速指南)
-20. [手动测试清单](#-手动测试清单)
-21. [自动化测试](#-自动化测试用例)
-22. [测试覆盖率](#测试覆盖率目标)
-
-### 第六部分:配置与扩展
+### 🎨 第六部分:通知类型与配置
23. [通知类型配置](#-通知类型配置)
24. [优先级配置](#-优先级配置)
25. [环境配置](#环境配置)
-26. [后端集成](#-后端集成生产环境)
-### 第七部分:故障排查
-27. [常见问题FAQ](#-故障排除)
-28. [调试工具](#调试工具)
-29. [日志分析](#日志分析)
+### ✨ 第七部分:增强功能详解
+26. [智能桌面通知](#-功能-1智能桌面通知)
+27. [性能监控](#-功能-2性能监控)
+28. [历史记录](#-功能-3历史记录)
-### 第八部分:最佳实践
-30. [开发规范](#-开发规范)
-31. [性能优化](#-性能优化建议)
-32. [安全注意事项](#安全注意事项)
+### 🧪 第八部分:测试指南
+29. [测试快速指南](#-测试快速指南)
+30. [手动测试清单](#-手动测试清单)
+31. [自动化测试](#-自动化测试用例)
+
+### 🐛 第九部分:故障排查
+32. [常见问题FAQ](#-故障排除)
+33. [调试工具](#调试工具)
+34. [日志分析](#日志分析)
+
+### 📏 第十部分:最佳实践
+35. [开发规范](#-开发规范)
+36. [性能优化](#-性能优化建议)
+37. [安全注意事项](#安全注意事项)
### 附录
-33. [更新日志](#-更新日志)
-34. [文件结构](#-文件结构)
+38. [后端集成](#-后端集成生产环境)
+39. [更新日志](#-更新日志)
+40. [文件结构](#-文件结构)
---
-## 🆕 最新更新 (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()` - 立即触发重连
-- ✅ **控制台提示**:开发模式启动时自动显示可用测试函数
-
----
-
-## 👤 用户快速指南
+## 👤 第一部分:用户快速指南
> **适用人群**: 普通用户、测试人员、客服人员
> **阅读时间**: 5 分钟
@@ -293,29 +273,13 @@ __DEBUG__.clearAll()
__DEBUG__.help()
```
-#### **开发环境专用(Mock 模式)**
-
-仅在开发环境(`npm start`)可用:
-
-```javascript
-// 模拟断线(测试重连机制)
-__mockSocket.simulateDisconnection()
-
-// 查看连接状态
-__mockSocket.isConnected()
-
-// 手动重连
-__mockSocket.reconnect()
-
-// 发送测试通知
-__mockSocket.sendTestNotification()
-```
-
---
-## 📋 系统概述
+## 🚀 第二部分:快速入门(开发者)
-本系统是专为**金融资讯场景**设计的实时消息推送系统,支持 Mock 模式(开发)和真实 Socket.IO 模式(生产)。消息以右下角层叠弹窗的形式显示,**新消息在最上方**,符合主流桌面应用的交互习惯。
+### 📋 系统概述
+
+本系统是专为**金融资讯场景**设计的实时消息推送系统,基于 Socket.IO 实现 WebSocket 实时通信。消息以右下角层叠弹窗的形式显示,**新消息在最上方**,符合主流桌面应用的交互习惯。
### 核心特性
@@ -340,7 +304,74 @@ __mockSocket.sendTestNotification()
---
-## 🏗️ 系统架构设计
+### 🏃 快速开始
+
+#### 1. 启动项目
+
+```bash
+# 开发环境
+npm start
+
+# 或使用真实后端
+npm run start:real
+```
+
+#### 2. 验证连接
+
+打开浏览器控制台 (`F12` → `Console`),查看连接状态:
+
+```javascript
+// 查看 Socket 连接状态
+__DEBUG__.socket.getStatus()
+
+// 预期输出:
+// { connected: true, socketId: "...", reconnectAttempts: 0 }
+```
+
+#### 3. 测试通知
+
+等待后端推送通知,或使用后端 API 手动触发(参见[后端集成](#-后端集成生产环境))。
+
+---
+
+### 💻 代码使用
+
+#### 在组件中使用
+
+```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 ? '已连接' : '未连接'}
+
+
+ );
+}
+```
+
+---
+
+## 🏗️ 第三部分:系统架构
### 整体架构图
@@ -353,18 +384,14 @@ graph TB
end
subgraph "通知系统核心"
- C --> F[Socket Service
WebSocket连接]
- F --> G{环境判断}
- G -->|Mock| H[mockSocketService
模拟服务]
- G -->|Real| I[socketService
生产服务]
-
+ C --> F[socketService
Socket.IO连接]
C --> J[browserNotificationService
浏览器通知]
C --> K[notificationHistoryService
历史记录]
C --> L[notificationMetricsService
性能监控]
end
subgraph "后端服务"
- I --> M[Flask Backend
Socket.IO Server]
+ F --> M[Flask Backend
Socket.IO Server]
M --> N[(ClickHouse
事件数据)]
M --> O[(MySQL
用户数据)]
end
@@ -379,7 +406,7 @@ graph TB
style F fill:#bfb,stroke:#333,stroke-width:2px
```
-### 技术栈选型
+### 📚 技术栈
#### 前端技术栈
- **React 18.3.1**: 并发渲染、Suspense、自动批处理
@@ -448,14 +475,15 @@ sequenceDiagram
---
-## 🧩 核心组件清单
+## 🧩 第四部分:核心组件详解
+
+### 📦 核心组件清单
| 组件名 | 类型 | 职责 | 文件路径 |
|-------|------|------|---------|
| **NotificationContext** | React Context | 通知系统核心逻辑、状态管理 | `src/contexts/NotificationContext.js` |
| **NotificationContainer** | React Component | 通知UI容器、动画、交互 | `src/components/NotificationContainer/index.js` |
-| **socketService** | Service Class | 真实WebSocket连接管理 | `src/services/socketService.js` |
-| **mockSocketService** | Service Class | Mock WebSocket模拟 | `src/services/mockSocketService.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` |
@@ -528,7 +556,7 @@ const {
showFirstFollowGuide();
```
-**源码位置**: `src/contexts/NotificationContext.js:1-829`
+**源码位置**: `src/contexts/NotificationContext.js`
---
@@ -590,7 +618,7 @@ const {
});
```
-**源码位置**: `src/components/NotificationContainer/index.js:1-757`
+**源码位置**: `src/components/NotificationContainer/index.js`
---
@@ -634,7 +662,7 @@ socket.subscribeToEvents({ eventType, importance, onNewEvent });
socket.unsubscribeFromEvents({ eventType });
```
-**源码位置**: `src/services/socketService.js:1-465`
+**源码位置**: `src/services/socketService.js`
---
@@ -671,7 +699,7 @@ notification.onclick = () => {
};
```
-**源码位置**: `src/services/browserNotificationService.js:1-209`
+**源码位置**: `src/services/browserNotificationService.js`
---
@@ -711,7 +739,7 @@ const stats = notificationHistoryService.getStats();
// { total, read, unread, clicked, clickRate, byType, byPriority }
```
-**源码位置**: `src/services/notificationHistoryService.js:1-403`
+**源码位置**: `src/services/notificationHistoryService.js`
---
@@ -749,11 +777,13 @@ const json = notificationMetricsService.exportToJSON();
const csv = notificationMetricsService.exportToCSV();
```
-**源码位置**: `src/services/notificationMetricsService.js:1-451`
+**源码位置**: `src/services/notificationMetricsService.js`
---
-## 🔄 消息推送完整流程
+## 🔄 第五部分:设计流程
+
+### 📡 消息推送完整流程
### 1. 初始化流程
@@ -761,19 +791,16 @@ const csv = notificationMetricsService.exportToCSV();
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[初始化完成]
+ C --> D[连接socketService]
+ D --> E[注册事件监听器]
+ E --> F[触发connect事件]
+ F --> G[更新连接状态]
+ G --> H[检查浏览器通知权限]
+ H --> I[加载历史记录]
+ I --> J[初始化完成]
```
-**代码实现** (src/contexts/NotificationContext.js:573-712):
+**代码实现** (src/contexts/NotificationContext.js):
```javascript
useEffect(() => {
// 1. 注册事件监听器
@@ -785,12 +812,7 @@ useEffect(() => {
// 2. 连接Socket
socket.connect();
- // 3. Mock模式启动自动推送
- if (SOCKET_TYPE === 'MOCK') {
- socket.startMockPush(60000, 2); // 60秒推送1-2条
- }
-
- // 4. 清理函数
+ // 3. 清理函数
return () => {
socket.off('connect');
socket.off('disconnect');
@@ -859,7 +881,7 @@ const adaptEventToNotification = (event) => {
};
```
-**源码位置**: `src/contexts/NotificationContext.js:336-395`
+**源码位置**: `src/contexts/NotificationContext.js`
---
@@ -890,7 +912,7 @@ graph TB
R --> K
```
-**代码实现** (src/contexts/NotificationContext.js:558-570):
+**代码实现** (src/contexts/NotificationContext.js):
```javascript
const isPageHidden = document.hidden;
@@ -942,363 +964,9 @@ deliveryRate = (totalReceived / totalSent) * 100
---
-## 🧪 测试快速指南
+## 🎨 第六部分:通知类型与配置
-> 📖 **完整测试手册**: [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)
@@ -1426,7 +1094,7 @@ describe('通知系统集成测试', () => {
---
-## 📊 优先级配置
+### 📊 优先级配置
| 优先级 | 标签 | 边框 | 自动关闭 | 使用场景 |
|--------|------|------|---------|----------|
@@ -1463,126 +1131,939 @@ export const PRIORITY_CONFIGS = {
---
-## 🚀 快速开始
+### 环境配置
-### 1. 启用 Mock 模式
+### API 配置
-在 `.env` 文件中添加:
-```bash
-REACT_APP_ENABLE_MOCK=true
-```
-
-### 2. 启动项目
+在 `.env` 文件中配置后端地址:
```bash
-npm start
+# 开发环境
+REACT_APP_API_URL=http://49.232.185.254:5001
+
+# 生产环境
+REACT_APP_API_URL=
+# 空字符串表示使用相对路径
```
-### 3. 测试通知
+### Socket 连接配置
-打开浏览器控制台 (`F12` → `Console`),使用以下命令测试:
+Socket 服务会自动读取 `REACT_APP_API_URL` 并连接到后端:
-#### **Mock 模式测试**(开发环境)
```javascript
-// 发送测试通知
-__mockSocket.sendTestNotification()
+// src/services/socketService.js
+const API_BASE_URL = getApiBase();
-// 模拟断线重连
-__mockSocket.simulateDisconnection()
-
-// 查看连接状态
-__mockSocket.isConnected()
+this.socket = io(API_BASE_URL, {
+ transports: ['websocket', 'polling'],
+ reconnection: false, // 使用自定义重连策略
+ timeout: 20000,
+ withCredentials: true,
+});
```
-#### **通用测试命令**
-```javascript
-// 查看系统状态
-__DEBUG__.diagnose()
-
-// 查看连接状态
-__DEBUG__.socket.getStatus()
-
-// 查看通知权限
-window.browserNotificationService.getPermissionStatus()
-```
-
-### 4. 自动推送
-
-Mock 模式下,系统会自动每 60 秒推送 1-2 条随机金融资讯。
-
-查看更多测试命令,请参考本文档开头的 [用户快速指南](#-用户快速指南)。
-
---
-## 💻 代码使用
+## ✨ 第七部分:增强功能详解
-### 在组件中使用
+### 🔔 功能 1:智能桌面通知
+
+#### 功能说明
+
+首次收到重要/紧急通知时,自动请求浏览器通知权限,确保用户不错过关键信息。
+
+#### 工作原理
+```javascript
+// 在 NotificationContext 中的逻辑
+if (priority === URGENT || priority === IMPORTANT) {
+ if (browserPermission === 'default' && !hasRequestedPermission) {
+ // 首次遇到重要通知,自动请求权限
+ await requestBrowserPermission();
+ setHasRequestedPermission(true); // 避免重复请求
+ }
+}
+```
+
+#### 权限状态
+
+- **granted**: 已授权,可以发送桌面通知
+- **denied**: 已拒绝,无法发送桌面通知
+- **default**: 未请求,首次重要通知时会自动请求
+
+#### 使用示例
+
+**自动触发**(推荐)
+```javascript
+// 无需任何代码,系统自动处理
+// 首次收到重要/紧急通知时会自动弹出权限请求
+```
+
+**手动请求**
```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,
- });
- };
+function SettingsPage() {
+ const { requestBrowserPermission, browserPermission } = useNotification();
return (
-
连接状态: {isConnected ? '已连接' : '未连接'}
-
+
当前状态: {browserPermission}
+
);
}
```
+#### 通知分发策略
+
+| 优先级 | 页面在前台 | 页面在后台 |
+|-------|----------|----------|
+| 紧急 | 桌面通知 + 网页通知 | 桌面通知 + 网页通知 |
+| 重要 | 网页通知 | 桌面通知 |
+| 普通 | 网页通知 | 网页通知 |
+
---
-## 🔧 环境配置
+### 📊 功能 2:性能监控
-### 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.*` | 无 |
+追踪通知推送的各项指标,包括:
+- **到达率**: 发送 vs 接收
+- **点击率**: 点击 vs 接收
+- **响应时间**: 收到通知到点击的平均时间
+- **类型分布**: 各类型通知的数量和效果
+- **时段分布**: 每小时推送量
-### 修改推送频率
+#### API 参考
+
+##### 获取汇总统计
-在 `src/services/mockSocketService.js` 中:
```javascript
-// 默认: 60秒推送1-2条
-socket.startMockPush(60000, 2);
+import { notificationMetricsService } from 'services/notificationMetricsService';
-// 修改为: 30秒推送1条
-socket.startMockPush(30000, 1);
+const summary = notificationMetricsService.getSummary();
+console.log(summary);
+/* 输出:
+{
+ totalSent: 100,
+ totalReceived: 98,
+ totalClicked: 45,
+ totalDismissed: 53,
+ avgResponseTime: 5200, // 毫秒
+ clickRate: '45.92', // 百分比
+ deliveryRate: '98.00' // 百分比
+}
+*/
+```
-// 修改为: 5秒推送3条(压力测试)
-socket.startMockPush(5000, 3);
+##### 获取按类型统计
+
+```javascript
+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' }
+}
+*/
+```
+
+##### 获取每日数据
+
+```javascript
+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' },
+ ...
+]
+*/
+```
+
+##### 导出数据
+
+```javascript
+// 导出为 JSON
+const json = notificationMetricsService.exportToJSON();
+console.log(json);
+
+// 导出为 CSV
+const csv = notificationMetricsService.exportToCSV();
+console.log(csv);
+```
+
+#### 在控制台查看实时指标
+
+打开浏览器控制台,执行:
+
+```javascript
+// 查看汇总
+import { notificationMetricsService } from './services/notificationMetricsService.js';
+console.table(notificationMetricsService.getSummary());
+
+// 查看按类型分布
+console.table(notificationMetricsService.getByType());
+
+// 查看最近 7 天数据
+console.table(notificationMetricsService.getDailyData(7));
```
---
-## 🌐 后端集成(生产环境)
+### 📜 功能 3:历史记录
-### Flask-SocketIO 配置
+#### 功能说明
+
+持久化存储所有接收到的通知,支持:
+- 查询和筛选
+- 搜索关键词
+- 标记已读/已点击
+- 批量删除
+- 导出(JSON/CSV)
+
+#### API 参考
+
+##### 获取历史记录(支持筛选和分页)
+
+```javascript
+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 // 总页数
+}
+*/
+```
+
+##### 搜索历史记录
+
+```javascript
+const results = notificationHistoryService.searchHistory('降准');
+console.log(results); // 返回标题/内容中包含"降准"的所有记录
+```
+
+##### 标记已读/已点击
+
+```javascript
+// 标记已读
+notificationHistoryService.markAsRead('notification_id');
+
+// 标记已点击
+notificationHistoryService.markAsClicked('notification_id');
+```
+
+##### 删除记录
+
+```javascript
+// 删除单条
+notificationHistoryService.deleteRecord('notification_id');
+
+// 批量删除
+notificationHistoryService.deleteRecords(['id1', 'id2', 'id3']);
+
+// 清空所有
+notificationHistoryService.clearHistory();
+```
+
+##### 获取统计数据
+
+```javascript
+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
+ }
+}
+*/
+```
+
+##### 导出历史记录
+
+```javascript
+// 导出为 JSON 字符串
+const json = notificationHistoryService.exportToJSON({
+ type: 'event_alert' // 可选:只导出特定类型
+});
+
+// 导出为 CSV 字符串
+const csv = notificationHistoryService.exportToCSV();
+
+// 直接下载 JSON 文件
+notificationHistoryService.downloadJSON();
+
+// 直接下载 CSV 文件
+notificationHistoryService.downloadCSV();
+```
+
+#### 数据结构
+
+每条历史记录包含:
+
+```javascript
+{
+ id: 'notif_123', // 通知 ID
+ notification: { // 完整通知对象
+ type: 'event_alert',
+ priority: 'urgent',
+ title: '...',
+ content: '...',
+ ...
+ },
+ receivedAt: 1737459600000, // 接收时间戳
+ readAt: 1737459650000, // 已读时间戳(null 表示未读)
+ clickedAt: null, // 已点击时间戳(null 表示未点击)
+}
+```
+
+#### 存储限制
+
+- **最大数量**: 500 条(超过后自动删除最旧的)
+- **存储位置**: localStorage
+- **容量估算**: 约 2-5MB(取决于通知内容长度)
+
+---
+
+## 🧪 第八部分:测试指南
+
+### 🧪 测试快速指南
+
+#### 开发环境测试
+
+```bash
+# 启动开发服务器
+npm start
+```
+
+**关键检查**:
+```javascript
+// 1. 验证连接
+__DEBUG__.socket.getStatus()
+// 预期: { connected: true, socketId: "..." }
+
+// 2. 系统诊断
+__DEBUG__.diagnose()
+```
+
+#### 生产环境测试
+
+**访问**: https://valuefrontier.cn
+
+```javascript
+// 一键诊断
+__DEBUG__.diagnose()
+
+// 导出报告
+__DEBUG__.exportAll()
+```
+
+#### 调试工具速查
+
+| 工具 | 适用环境 | 主要功能 |
+|------|---------|---------|
+| `__DEBUG__.socket` | 所有环境 | 连接状态、配置检查、手动重连 |
+| `__DEBUG__.api` | 所有环境 | API 日志、错误追踪 |
+| `__DEBUG__` | 所有环境 | 完整诊断、导出报告、性能监控 |
+
+**常用命令**:
+```javascript
+// 完整诊断
+__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 测试
+```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);
+ });
+});
+```
+
+---
+
+## 🐛 第九部分:故障排查
+
+### 🔧 故障排除
+
+#### 问题 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 隐私模式:通知权限被永久拒绝,无法更改
+ - 建议:使用普通浏览器窗口以获得完整体验
+
+**快速诊断**:
+```javascript
+// 在浏览器控制台运行
+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. 查看控制台日志确认错误信息
+
+**使用调试工具**:
+```javascript
+// 查看连接状态
+__DEBUG__.socket.getStatus()
+
+// 查看错误日志
+__DEBUG__.socket.getLogs()
+
+// 手动重连
+__DEBUG__.socket.reconnect()
+```
+
+---
+
+### 调试工具
+
+#### window.__DEBUG__ - 主调试工具
+
+**可用命令**:
+```javascript
+// 系统诊断
+__DEBUG__.diagnose() // 检查所有系统状态
+__DEBUG__.printStats() // 打印所有统计信息
+__DEBUG__.performance() // 性能监控
+
+// 日志管理
+__DEBUG__.exportAll() // 导出所有日志
+__DEBUG__.clearAll() // 清空所有日志
+
+// 帮助信息
+__DEBUG__.help() // 显示帮助信息
+```
+
+#### window.__DEBUG__.socket - Socket 调试
+
+**可用命令**:
+```javascript
+// 连接管理
+__DEBUG__.socket.getStatus() // 获取连接状态
+__DEBUG__.socket.reconnect() // 手动重连
+
+// 日志管理
+__DEBUG__.socket.getLogs() // 获取所有 Socket 日志
+__DEBUG__.socket.clearLogs() // 清空日志
+__DEBUG__.socket.exportLogs() // 导出日志
+```
+
+#### window.__DEBUG__.api - API 调试
+
+**可用命令**:
+```javascript
+// 日志查询
+__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. 更新文档
+
+**示例**:
+```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 秒
+- 避免短时间内大量推送造成用户困扰
+
+#### 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;
+```
+
+---
+
+### 🔒 安全注意事项
+
+#### 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
+```
+
+---
+
+## 附录
+
+### 🌐 后端集成(生产环境)
+
+#### Flask-SocketIO 配置
```python
from flask_socketio import SocketIO, emit
@@ -1609,7 +2090,7 @@ if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5001)
```
-### 后端推送示例
+#### 后端推送示例
```python
import time
@@ -1636,474 +2117,44 @@ socketio.emit('new_event', {
---
-## 🐛 故障排除
+### 📝 更新日志
-### 问题 1: 通知不显示
+#### v3.0.0 (2025-11-17) - 文档合并与更新
+- ✅ 合并 ENHANCED_FEATURES_GUIDE.md 内容
+- ✅ 移除过时的 Mock 模式引用
+- ✅ 更新所有调试工具引用(统一使用 `window.__DEBUG__`)
+- ✅ 更新代码示例与最新代码一致
+- ✅ 完善增强功能文档(智能桌面通知、性能监控、历史记录)
+- ✅ 更新测试指南
-**检查项**:
-1. 确认 `NotificationProvider` 已包裹应用
-2. 检查浏览器控制台是否有错误
-3. 确认 socket 连接状态(使用 `__DEBUG__.socket.getStatus()`)
-4. 检查通知数据格式是否正确
+#### v2.11.0 (2025-01-07) - Socket 连接优化
+- ✅ 指数退避重连策略
+- ✅ 连接状态横幅优化
+- ✅ 手动关闭状态持久化
-### 问题 2: 股票动向颜色不对
+#### v2.10.0 (2025-01-06) - 按钮加载态
+- ✅ 点击"查看详情"显示 loading spinner
+- ✅ 防重复点击机制
-**解决方案**:
-1. 检查 `extra.priceChange` 字段是否存在
-2. 确认格式为 "+5.2%" 或 "-3.8%"(包含符号)
-3. 确认使用了 `NOTIFICATION_TYPES.STOCK_ALERT` 类型
+#### v2.9.0 (2025-01-05) - 头部简化
+- ✅ AI 和预测标识移到底部
-### 问题 3: AI 徽章不显示
+#### v2.8.0 (2025-01-04) - 无障碍支持
+- ✅ 完整的 ARIA 属性
+- ✅ 键盘导航支持
-**解决方案**:
-1. 检查 `isAIGenerated` 字段是否为 `true`
-2. 确认字段名拼写正确(驼峰命名)
+#### v2.7.0 (2025-01-03) - 智能动画
+- ✅ 只对新增通知应用动画
+- ✅ 性能提升 90%+
-### 问题 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
+#### v2.0.0 (2024-12-27) - 金融资讯专业版
+- ✅ 4种金融资讯通知类型
+- ✅ 3级优先级系统
+- ✅ 智能元数据、动态配色
---
-### 问题 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. 使用控制台命令测试(Mock 模式:`__mockSocket.sendTestNotification()`)
-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/
@@ -2112,8 +2163,7 @@ src/
├── services/
│ ├── socket/
│ │ └── index.js # Socket 服务统一导出
-│ ├── socketService.js # 真实 Socket.IO 服务
-│ ├── mockSocketService.js # Mock Socket 服务
+│ ├── socketService.js # Socket.IO 服务
│ ├── browserNotificationService.js # 浏览器通知服务
│ ├── notificationHistoryService.js # 历史记录服务
│ └── notificationMetricsService.js # 性能监控服务
@@ -2124,6 +2174,10 @@ src/
│ └── index.js # 通知容器组件
├── hooks/
│ └── useEventNotifications.js # 事件订阅 Hook
+├── devtools/
+│ ├── index.js # 调试工具统一入口
+│ ├── socketDebugger.js # Socket 调试工具
+│ └── apiDebugger.js # API 调试工具
└── assets/
└── sounds/
└── notification.wav # 通知音效
@@ -2131,74 +2185,10 @@ src/
---
-## 📝 更新日志
-
-### 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`
- **调试命令**: 浏览器控制台使用 `__DEBUG__.help()` 查看所有可用命令
- **控制台日志**: 所有操作都有详细日志