diff --git a/NOTIFICATION_SYSTEM.md b/NOTIFICATION_SYSTEM.md index c1210635..964e857b 100644 --- a/NOTIFICATION_SYSTEM.md +++ b/NOTIFICATION_SYSTEM.md @@ -1,15 +1,60 @@ # 实时消息推送系统使用指南 -## 🆕 最新更新 (v1.1.0) +## 🆕 最新更新 (v2.3.0 - 通知体验优化) -- ✅ **新消息置顶展示**:采用行业标准,新消息显示在最上方 -- ✅ **智能队列管理**:最多同时显示 5 条消息,超出自动移除最旧的 -- ✅ **视觉层次优化**:最新消息更强的阴影和边框高亮效果 -- ✅ **测试工具增强**:实时显示队列状态,新增"测试最大限制"功能 +- ✅ **按优先级区分自动关闭**:紧急通知不自动关闭,重要30秒,普通15秒 +- ✅ **简单折叠机制**:最多显示3条通知,超过显示"还有X条"展开按钮 +- ✅ **推送频率优化**:60秒推送1-2条(随机),更符合真实金融场景 +- ✅ **历史保留增加**:从5条增加到15条,支持查看更多历史通知 +- ✅ **集中配置管理**:所有配置统一在 `NOTIFICATION_CONFIG` 中管理 + +--- + +### v2.2.0 更新回顾 + +- ✅ **浏览器原生通知**:支持系统级通知,即使标签页在后台也能收到 +- ✅ **智能分发策略**:根据优先级和页面状态智能选择通知方式 + - 紧急(urgent)→ 浏览器通知 + 网页通知(双重保障) + - 重要(important)→ 后台=浏览器,前台=网页 + - 普通(normal)→ 仅网页通知 +- ✅ **权限管理**:测试工具显示权限状态,一键请求授权 +- ✅ **点击跳转**:浏览器通知点击聚焦窗口并跳转详情 + +--- + +### v2.1.0 更新回顾 + +- ✅ **预测通知系统**:支持预测→详情两阶段推送,解决详情延迟生成问题 +- ✅ **严格可点击性**:只有真正可跳转的通知才显示"查看详情"和 hover 效果 +- ✅ **视觉区分优化**:预测通知显示灰色"预测"徽章和状态提示 +- ✅ **测试工具增强**:新增预测通知测试和预测→详情流程测试(5秒延迟) +- ✅ **新增字段**:isPrediction、statusHint、relatedPredictionId + +--- + +### v2.0.0 更新回顾 + +- ✅ **通知类型重构**:4 种金融资讯通知类型(公告、股票、事件、分析) +- ✅ **优先级系统**:紧急、重要、普通三级优先级,带视觉标签 +- ✅ **智能元数据**:发布时间、作者信息、AI 生成标识 +- ✅ **动态配色**:股票动向根据涨跌自动变色(红涨绿跌) +- ✅ **点击交互**:支持点击跳转到详情页面,带视觉反馈 +- ✅ **统一设计**:所有通知宽度统一为 400px ## 📋 系统概述 -本系统实现了完整的实时消息推送功能,支持 Mock 模式(开发)和真实 Socket.IO 模式(生产)。消息以右下角层叠弹窗的形式显示,**新消息在最上方**,符合主流桌面应用的交互习惯。 +本系统是专为**金融资讯场景**设计的实时消息推送系统,支持 Mock 模式(开发)和真实 Socket.IO 模式(生产)。消息以右下角层叠弹窗的形式显示,**新消息在最上方**,符合主流桌面应用的交互习惯。 + +### 核心特性 + +- **双通知系统**:网页通知 + 浏览器原生通知,智能分发 +- **4 种通知类型**:公告通知、股票动向、事件动向、分析报告 +- **3 级优先级**:紧急(不关闭)、重要(30秒)、普通(15秒)🆕 +- **智能折叠**:最多显示3条,超过显示展开按钮 🆕 +- **智能配色**:股票动向根据涨跌自动变色(涨红 🔴 / 跌绿 🟢) +- **丰富元数据**:发布时间、作者、AI 标识 +- **点击跳转**:可配置点击跳转链接 +- **队列管理**:最多保留 15 条历史,可展开查看 🆕 --- @@ -17,34 +62,90 @@ ### ✅ 已实现功能 -1. **实时推送** - - WebSocket (Socket.IO) 连接 - - Mock 模式自动定期推送(开发环境) - - 支持多种消息类型(成功、错误、警告、信息) +1. **4 种通知类型** + - **公告通知** (Announcement):财报、重组、分红等公司公告 + - **股票动向** (Stock Alert):价格预警、异常波动、持仓表现 + - **事件动向** (Event Alert):政策变化、行业事件、宏观消息 + - **分析报告** (Analysis Report):行业研报、策略报告、公司研报 -2. **UI 展示** +2. **3 级优先级系统** + - **紧急** (Urgent):红色标签,用于重大事件和高优先级预警 + - **重要** (Important):橙色标签,用于重要消息和一般预警 + - **普通** (Normal):无标签,用于常规消息和信息推送 + +3. **智能元数据展示** + - **发布时间**:智能格式化(刚刚、X分钟前、今天 HH:mm、昨天 HH:mm、MM-DD HH:mm) + - **作者信息**:仅分析报告显示,格式为"作者 - 机构" + - **AI 标识**:紫色 AI 徽章,标识 AI 生成的内容 + +4. **动态配色方案** + - **股票动向**:根据 `priceChange` 字段自动判断 + - 涨(+):红色系(icon、border、bg、hover) + - 跌(-):绿色系 + - **其他类型**:固定配色(蓝、橙、紫) + +5. **预测通知系统** 🆕 + - **预测通知**:事件预测结果,详情未就绪(不可跳转) + - **详情通知**:完整报告已生成(可跳转查看) + - **视觉区分**: + - 预测通知:灰色"预测"徽章 + "详细报告生成中..." 状态提示 + - 详情通知:优先级徽章 + "查看详情" 提示 + - **典型场景**:先推送预测(T+0秒),延迟推送详情(T+5分钟) + +6. **点击交互** + - **可点击通知**:鼠标悬停变化、点击跳转到详情页 + - **不可点击通知**:静态展示,无交互效果 + - **视觉提示**:"📂 查看详情" 提示文本 + - **严格判断**:只有 `clickable=true` 且 `link` 存在才可点击 + +7. **UI 展示** - 右下角固定定位 + - **统一宽度 400px** - **新消息在最上方**(符合行业标准) + - **从底部向上滑入动画**(浮起效果) - 层叠显示最多 5 条消息 - 智能队列管理:超出自动移除最旧消息 - 视觉层次:最新消息更突出(更强阴影、边框高亮) - - 自动关闭(可配置时长) + - 自动关闭(可配置时长,默认 10-12 秒) - 手动关闭按钮 - - 流畅的进入/退出动画(从右侧滑入) + - 流畅的进入/退出动画 -3. **音效提示** +8. **音效提示** - 新消息音效播放 - 可开关音效 -4. **开发工具** - - 右上角测试工具面板(仅开发环境) - - 手动触发测试通知(4种类型) - - 层叠效果测试(4条消息) - - 最大限制测试(6条→5条) - - **实时队列状态显示**(当前消息数 / 5) - - 连接状态显示 - - 音效开关 - - 测试计数统计 +9. **浏览器原生通知系统** 🆕 + - **系统级通知**:显示在操作系统通知中心(Windows/macOS) + - **后台可见**:即使标签页不在前台也能收到通知 + - **智能分发策略**: + - **紧急通知(URGENT)**:浏览器通知 + 网页通知(双重保障) + - **重要通知(IMPORTANT)**:后台=浏览器通知,前台=网页通知 + - **普通通知(NORMAL)**:仅网页通知 + - **权限管理**:自动请求权限,状态实时显示 + - **点击跳转**:点击浏览器通知聚焦窗口并跳转详情 + - **防重复**:相同类型通知自动替换旧通知 + - **自动关闭**:普通通知 8 秒自动关闭,紧急通知需手动关闭 + +10. **开发工具增强** + - 右上角测试工具面板(仅开发环境) + - **浏览器权限管理** 🆕: + - 显示权限状态(已授权/未授权/已拒绝) + - 一键请求权限按钮 + - 权限状态实时更新 + - **9 种测试场景**: + - 公告通知 + - 股票上涨 / 股票下跌 + - 事件动向 + - 分析报告 / AI 报告 + - 预测通知(不可跳转) + - **3 种组合测试**: + - 层叠测试(4 种类型) + - 优先级测试(3 个级别) + - 预测→详情流程(5秒延迟) + - **实时队列状态**:当前消息数 / 5 + - 连接状态显示 + - 音效开关 + - 测试计数统计 --- @@ -52,21 +153,258 @@ ``` src/ +├── constants/ +│ └── notificationTypes.js # 通知类型定义和常量 🆕 ├── services/ │ ├── socket/ -│ │ └── index.js # Socket 服务统一导出 -│ ├── socketService.js # 真实 Socket.IO 服务 -│ └── mockSocketService.js # Mock Socket 服务 +│ │ └── index.js # Socket 服务统一导出 +│ ├── socketService.js # 真实 Socket.IO 服务 +│ └── mockSocketService.js # Mock Socket 服务(含 14 条金融资讯数据)🔄 ├── contexts/ -│ └── NotificationContext.js # 通知上下文管理 +│ └── NotificationContext.js # 通知上下文管理 ├── components/ │ ├── NotificationContainer/ -│ │ └── index.js # 通知容器组件 +│ │ └── index.js # 通知容器组件(完全重写)🔄 │ └── NotificationTestTool/ -│ └── index.js # 测试工具组件 +│ └── index.js # 测试工具组件(升级 8 种测试)🔄 └── assets/ └── sounds/ - └── notification.wav # 通知音效 + └── notification.wav # 通知音效 +``` + +**图例**:🆕 新增 | 🔄 重构 + +--- + +## 🎨 通知类型配置 + +### 类型 1: 公告通知 (Announcement) + +**适用场景**:公司财报、重大资产重组、分红派息、停复牌公告等 + +**配色方案**: +- 主色:蓝色 (Blue) +- 图标:📢 MdCampaign +- 背景:`blue.50` +- 边框:`blue.400` +- 图标色:`blue.500` +- 悬停:`blue.100` + +**示例数据**: +```javascript +{ + type: NOTIFICATION_TYPES.ANNOUNCEMENT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '贵州茅台发布2024年度财报公告', + content: '2024年度营收同比增长15.2%,净利润创历史新高,董事会建议每10股派息180元', + publishTime: 1711611000000, + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/event-detail/ann001', + extra: { + announcementType: '财报', + companyCode: '600519', + companyName: '贵州茅台', + }, + autoClose: 10000, +} +``` + +--- + +### 类型 2: 股票动向 (Stock Alert) + +**适用场景**:价格预警、异常波动、持仓表现、目标价触达 + +**配色方案**:**动态配色**(根据 `priceChange` 字段) +- **涨(+)**: + - 主色:红色 (Red) + - 图标:📈 MdTrendingUp + - 背景:`red.50` + - 边框:`red.400` + - 图标色:`red.500` + - 悬停:`red.100` +- **跌(-)**: + - 主色:绿色 (Green) + - 图标:📉 MdTrendingDown + - 背景:`green.50` + - 边框:`green.400` + - 图标色:`green.500` + - 悬停:`green.100` + +**示例数据(涨)**: +```javascript +{ + type: NOTIFICATION_TYPES.STOCK_ALERT, + priority: PRIORITY_LEVELS.URGENT, + title: '您关注的股票触发预警', + content: '宁德时代(300750) 当前价格 ¥245.50,盘中涨幅达 +5.2%,已触达您设置的目标价位', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/stock-overview?code=300750', + extra: { + stockCode: '300750', + stockName: '宁德时代', + priceChange: '+5.2%', // 💡 重要:根据此字段判断涨跌 + currentPrice: '245.50', + triggerType: '目标价', + }, + autoClose: 10000, +} +``` + +**示例数据(跌)**: +```javascript +{ + type: NOTIFICATION_TYPES.STOCK_ALERT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '您关注的股票异常波动', + content: '比亚迪(002594) 5分钟内跌幅达 -3.8%,当前价格 ¥198.20,建议关注', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/stock-overview?code=002594', + extra: { + stockCode: '002594', + stockName: '比亚迪', + priceChange: '-3.8%', // 💡 负数:使用绿色配色 + currentPrice: '198.20', + triggerType: '异常波动', + }, + autoClose: 10000, +} +``` + +--- + +### 类型 3: 事件动向 (Event Alert) + +**适用场景**:央行政策、行业政策、监管动态、宏观事件 + +**配色方案**: +- 主色:橙色 (Orange) +- 图标:📄 MdArticle +- 背景:`orange.50` +- 边框:`orange.400` +- 图标色:`orange.500` +- 悬停:`orange.100` + +**示例数据**: +```javascript +{ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '央行宣布降准0.5个百分点', + content: '中国人民银行宣布下调金融机构存款准备金率0.5个百分点,释放长期资金约1万亿元,利好股市', + publishTime: 1711590000000, + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/event-detail/evt001', + extra: { + eventId: 'evt001', + relatedStocks: 12, + impactLevel: '重大利好', + sectors: ['银行', '地产', '基建'], + }, + autoClose: 12000, +} +``` + +--- + +### 类型 4: 分析报告 (Analysis Report) + +**适用场景**:行业研报、策略报告、公司研报、市场分析 + +**配色方案**: +- 主色:紫色 (Purple) +- 图标:📊 MdAssessment +- 背景:`purple.50` +- 边框:`purple.400` +- 图标色:`purple.500` +- 悬停:`purple.100` + +**特殊字段**: +- `author`:作者信息(必填,包含 `name` 和 `organization`) +- `isAIGenerated`:是否 AI 生成(显示紫色 AI 徽章) + +**示例数据(人工)**: +```javascript +{ + type: NOTIFICATION_TYPES.ANALYSIS_REPORT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '医药行业深度报告:创新药迎来政策拐点', + content: 'CXO板块持续受益于全球创新药研发外包需求,建议关注药明康德、凯莱英等龙头企业', + publishTime: 1711584000000, + pushTime: Date.now(), + author: { + name: '李明', + organization: '中信证券', + }, + isAIGenerated: false, // 人工报告 + clickable: true, + link: '/forecast-report?id=rpt001', + extra: { + reportType: '行业研报', + industry: '医药', + rating: '强烈推荐', + }, + autoClose: 12000, +} +``` + +**示例数据(AI)**: +```javascript +{ + type: NOTIFICATION_TYPES.ANALYSIS_REPORT, + priority: PRIORITY_LEVELS.NORMAL, + title: 'AI产业链投资机会分析', + content: '随着大模型应用加速落地,算力、数据、应用三大方向均存在投资机会,重点关注海光信息、寒武纪', + publishTime: 1711582200000, + pushTime: Date.now(), + author: { + name: 'AI分析师', + organization: '价值前沿', + }, + isAIGenerated: true, // 💡 AI 生成:显示紫色 AI 徽章 + clickable: true, + link: '/forecast-report?id=rpt002', + extra: { + reportType: '策略报告', + industry: '人工智能', + rating: '推荐', + }, + autoClose: 12000, +} +``` + +--- + +## 📊 优先级配置 + +| 优先级 | 级别 | 颜色主题 | 标签显示 | 使用场景 | +|--------|------|---------|---------|----------| +| **Urgent** | 紧急 | 🔴 Red | ✅ 显示"紧急" | 重大事件、高优先级预警、异常波动 | +| **Important** | 重要 | 🟠 Orange | ✅ 显示"重要" | 重要消息、一般预警、关键公告 | +| **Normal** | 普通 | ⚪ Gray | ❌ 不显示 | 常规消息、信息推送、日常报告 | + +**代码使用**: +```javascript +import { PRIORITY_LEVELS } from '../constants/notificationTypes'; + +// 紧急消息 +priority: PRIORITY_LEVELS.URGENT + +// 重要消息 +priority: PRIORITY_LEVELS.IMPORTANT + +// 普通消息 +priority: PRIORITY_LEVELS.NORMAL ``` --- @@ -81,40 +419,54 @@ src/ 用户视角(右下角): 第1条消息到达: -┌────────────────────┐ -│ 🔔 买入成功 🆕 │ ← 从右侧滑入 -└────────────────────┘ +┌────────────────────────────────────────┐ +│ 📢 贵州茅台发布财报 🆕 [重要] │ ↑ 从底部向上滑入(浮起) +│ 2024年度营收同比增长15.2%... │ 宽度 400px +│ 📅 15分钟前 │ +└────────────────────────────────────────┘ 第2条消息到达: -┌────────────────────┐ -│ 🔔 价格预警 🆕 │ ← 新消息(最上方) -├────────────────────┤ -│ 🔔 买入成功 │ ← 旧消息向下平移 -└────────────────────┘ +┌────────────────────────────────────────┐ +│ 📈 宁德时代触发预警 🆕 [紧急] │ ↑ 新消息(最上方,从下浮起) +│ 当前价格 ¥245.50,涨幅 +5.2% │ 红色系(涨) +│ 📅 刚刚 | 📂 查看详情 │ +├────────────────────────────────────────┤ +│ 📢 贵州茅台发布财报 [重要] │ ↑ 旧消息同时向上推动 +│ 2024年度营收同比增长15.2%... │ +│ 📅 16分钟前 │ +└────────────────────────────────────────┘ 第6条消息到达(超过5条限制): -┌────────────────────┐ -│ 🔔 第6条 🆕 │ ← 最新 -├────────────────────┤ -│ 🔔 第5条 │ -├────────────────────┤ -│ 🔔 第4条 │ -├────────────────────┤ -│ 🔔 第3条 │ -├────────────────────┤ -│ 🔔 第2条 │ ← 最旧(仍显示) -└────────────────────┘ +┌────────────────────────────────────────┐ +│ 📊 AI产业链投资机会 🆕 [AI] │ ↑ 最新(从底部滑入) +│ 👤 AI分析师 - 价值前沿 │ 紫色系 + AI 徽章 +│ 📅 刚刚 | 📂 查看详情 │ +├────────────────────────────────────────┤ +│ 📈 宁德时代触发预警 [紧急] │ ↑ 向上推 +├────────────────────────────────────────┤ +│ 📢 贵州茅台发布财报 [重要] │ ↑ 向上推 +├────────────────────────────────────────┤ +│ 📄 央行宣布降准 [重要] │ ↑ 向上推 +├────────────────────────────────────────┤ +│ 📊 医药行业深度报告 │ ↑ 最旧(仍显示) +└────────────────────────────────────────┘ ↓ 自动移除 -│ 第1条(已移除) │ +│ 第1条(已移除) │ ``` ### 关键特性 +- **统一宽度 400px**:所有通知宽度一致,整齐美观 - **最新消息固定位置**:始终在右下角的顶部,便于快速注意 - **自动队列管理**:最多保留 5 条,超出自动移除最旧的 -- **视觉区分**:最新消息有更强的阴影(2xl vs lg)和边框高亮 +- **视觉区分**: + - 最新消息:boxShadow='2xl' + 边框高亮(4 个边) + - 其他消息:boxShadow='lg' + 左边框 - **z-index 层级**:最新消息层级最高(9999),依次递减 - **间距优化**:消息之间 12px 间距(spacing={3}) +- **点击反馈**: + - 可点击:cursor=pointer,hover 时上移 2px + 阴影增强 + - 不可点击:cursor=default,无 hover 效果 --- @@ -138,19 +490,31 @@ npm start ### 3. 测试通知 -打开浏览器,右上角会显示 **"通知测试工具"**,点击展开后可以: +打开浏览器,右上角会显示 **"金融资讯测试工具"**,点击展开后可以: -- **单条测试**:测试不同类型的通知(成功、错误、警告、信息) -- **层叠测试**:一次发送 4 条消息,测试层叠效果 -- **最大限制测试**:发送 6 条消息,验证只保留最新 5 条 +#### 通知类型测试(9 种场景) +- **公告通知**:测试蓝色系公告通知 +- **股票上涨**:测试红色系股票涨幅预警 +- **股票下跌**:测试绿色系股票跌幅预警 +- **事件动向**:测试橙色系事件通知 +- **分析报告**:测试紫色系人工研报 +- **AI 报告**:测试紫色系 AI 研报(带 AI 徽章) +- **预测通知**:测试灰色系预测通知(不可跳转)🆕 + +#### 组合测试(3 种) +- **层叠测试(4种类型)**:一次发送 4 条不同类型消息,测试层叠效果 +- **优先级测试(3个级别)**:测试紧急、重要、普通三个优先级 +- **预测→详情流程**:先推送预测(不可跳转),5秒后推送详情(可跳转)🆕 + +#### 功能按钮 +- **清空全部**:一键清空所有通知 +- **音效开关**:切换音效开关 - **队列状态**:实时显示当前队列中的消息数量(X / 5) -- **音效控制**:切换音效开关 -- **清空功能**:一键清空所有通知 - **连接状态**:查看 Socket 连接状态和服务类型(MOCK/REAL) ### 4. 自动推送 -在 Mock 模式下,系统会自动每 20 秒推送 1-2 条随机消息,用于测试层叠效果。 +在 Mock 模式下,系统会自动每 15 秒推送 1-2 条随机金融资讯,用于测试层叠效果。 --- @@ -160,40 +524,232 @@ npm start ```javascript import { useNotification } from 'contexts/NotificationContext'; +import { NOTIFICATION_TYPES, PRIORITY_LEVELS } from 'constants/notificationTypes'; function MyComponent() { const { addNotification, isConnected } = useNotification(); - const handleTradeSuccess = () => { + // 示例 1: 公告通知 + const handleAnnouncement = () => { addNotification({ - type: 'trade_alert', - severity: 'success', - title: '买入成功', - message: '您的订单已成功执行:买入 贵州茅台(600519) 100股', - autoClose: 8000, // 8秒后自动关闭 + 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: 股票动向(涨) + const handleStockAlert = () => { + addNotification({ + type: NOTIFICATION_TYPES.STOCK_ALERT, + priority: PRIORITY_LEVELS.URGENT, + title: '您关注的股票触发预警', + content: '宁德时代(300750) 当前价格 ¥245.50,盘中涨幅达 +5.2%', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/stock-overview?code=300750', + extra: { + stockCode: '300750', + stockName: '宁德时代', + priceChange: '+5.2%', // 💡 涨:使用红色配色 + currentPrice: '245.50', + }, + autoClose: 10000, + }); + }; + + // 示例 3: 事件动向 + const handleEventAlert = () => { + addNotification({ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '央行宣布降准0.5个百分点', + content: '中国人民银行宣布下调金融机构存款准备金率0.5个百分点', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/event-detail/evt001', + extra: { + eventId: 'evt001', + relatedStocks: 12, + impactLevel: '重大利好', + }, + autoClose: 12000, + }); + }; + + // 示例 4: 分析报告(AI) + const handleAnalysisReport = () => { + addNotification({ + 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, + }); + }; + + // 示例 5: 预测通知(不可跳转)🆕 + const handlePrediction = () => { + addNotification({ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.NORMAL, + title: '【预测】央行可能宣布降准政策', + content: '基于最新宏观数据分析,预计央行将在本周宣布降准0.5个百分点', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: true, + clickable: false, // ❌ 不可点击 + link: null, + extra: { + isPrediction: true, // 💡 显示"预测"徽章 + statusHint: '详细报告生成中...', // 💡 状态提示 + }, + autoClose: 15000, + }); + }; + + // 示例 6: 预测→详情流程 🆕 + const handlePredictionFlow = () => { + // 阶段 1: 推送预测 + addNotification({ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.NORMAL, + title: '【预测】新能源补贴政策或将延期', + content: '根据政策趋势分析,财政部可能宣布新能源汽车购置补贴政策延长至2025年底', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: true, + clickable: false, + link: null, + extra: { + isPrediction: true, + statusHint: '详细报告生成中...', + relatedPredictionId: 'pred_001', + }, + autoClose: 15000, + }); + + // 阶段 2: 5分钟后推送详情(实际业务中由后端触发) + setTimeout(() => { + addNotification({ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '新能源补贴政策延期至2025年底', + content: '财政部宣布新能源汽车购置补贴政策延长至2025年底,涉及比亚迪、理想汽车等5家龙头企业', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, // ✅ 可点击 + link: '/event-detail/evt001', + extra: { + isPrediction: false, + relatedPredictionId: 'pred_001', // 关联原预测 + }, + autoClose: 12000, + }); + }, 300000); // 300000ms = 5分钟 + }; + return (

连接状态: {isConnected ? '已连接' : '未连接'}

- + + + + + +
); } ``` -### 消息格式 +### 消息格式(v2.0.0) ```javascript { - type: 'trade_alert', // 消息类型 - severity: 'info', // 'success' | 'error' | 'warning' | 'info' - title: '通知标题', // 主标题 - message: '详细消息内容', // 详细内容 - timestamp: Date.now(), // 时间戳(自动生成) - autoClose: 8000, // 自动关闭时长(毫秒),0 或 false 表示不自动关闭 - id: 'unique_id' // 唯一ID(自动生成) + // 必填字段 + type: 'announcement' | 'stock_alert' | 'event_alert' | 'analysis_report', + priority: 'urgent' | 'important' | 'normal', + title: '通知标题', + content: '详细消息内容', + + // 时间字段 + publishTime: 1711611000000, // 发布时间(毫秒时间戳) + pushTime: Date.now(), // 推送时间(毫秒时间戳) + + // 元数据 + isAIGenerated: false, // 是否 AI 生成(显示 AI 徽章) + clickable: true, // 是否可点击 + link: '/event-detail/ann001', // 点击跳转链接 + + // 作者信息(仅 analysis_report 需要) + author: { + name: '李明', + organization: '中信证券', + }, + + // 额外信息(自定义,根据类型不同) + extra: { + // announcement + announcementType: '财报', + companyCode: '600519', + + // stock_alert + stockCode: '300750', + priceChange: '+5.2%', // 💡 重要:涨跌判断依据 + currentPrice: '245.50', + + // event_alert + eventId: 'evt001', + relatedStocks: 12, + impactLevel: '重大利好', + + // analysis_report + reportType: '行业研报', + industry: '医药', + rating: '强烈推荐', + + // 🆕 预测通知专用字段 + isPrediction: true, // 是否为预测通知(显示"预测"徽章) + statusHint: '详细报告生成中...', // 状态提示文字(可选) + relatedPredictionId: 'pred_001', // 关联预测ID(用于追溯,可选) + }, + + // 自动关闭 + autoClose: 10000, // 毫秒,0 或 false 表示不自动关闭 + + // 自动生成字段(无需手动设置) + id: 'unique_id', // 自动生成 + timestamp: Date.now(), // 自动生成 } ``` @@ -206,19 +762,91 @@ function MyComponent() { 在 `src/services/mockSocketService.js` 中可以配置: ```javascript -// 修改模拟数据 -const mockTradeAlerts = [ +// 修改模拟数据(14 条金融资讯) +const mockFinancialNews = [ + // 3 条公告通知 { - severity: 'success', - title: '自定义标题', - message: '自定义消息', - autoClose: 8000, + type: NOTIFICATION_TYPES.ANNOUNCEMENT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '贵州茅台发布2024年度财报公告', + content: '2024年度营收同比增长15.2%,净利润创历史新高...', + // ... + }, + + // 3 条股票动向 + { + type: NOTIFICATION_TYPES.STOCK_ALERT, + priority: PRIORITY_LEVELS.URGENT, + title: '您关注的股票触发预警', + content: '宁德时代(300750) 当前价格 ¥245.50,涨幅 +5.2%...', + extra: { + priceChange: '+5.2%', // 红色(涨) + }, + // ... + }, + + // 3 条事件动向 + { + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '央行宣布降准0.5个百分点', + // ... + }, + + // 4 条分析报告(2 条人工 + 2 条 AI) + { + type: NOTIFICATION_TYPES.ANALYSIS_REPORT, + priority: PRIORITY_LEVELS.IMPORTANT, + author: { + name: '李明', + organization: '中信证券', + }, + isAIGenerated: false, + // ... + }, + { + type: NOTIFICATION_TYPES.ANALYSIS_REPORT, + author: { + name: 'AI分析师', + organization: '价值前沿', + }, + isAIGenerated: true, // AI 徽章 + // ... }, - // 添加更多... ]; // 调整推送频率 -socket.startMockPush(20000, 2); // 每20秒推送1-2条 +socket.startMockPush(15000, 1); // 每15秒推送1条 +``` + +### 通知类型常量配置 + +在 `src/constants/notificationTypes.js` 中可以修改: + +```javascript +// 修改类型配色 +export const NOTIFICATION_TYPE_CONFIGS = { + [NOTIFICATION_TYPES.ANNOUNCEMENT]: { + name: '公告通知', + icon: MdCampaign, + colorScheme: 'blue', // 修改颜色主题 + bg: 'blue.50', + borderColor: 'blue.400', + iconColor: 'blue.500', + hoverBg: 'blue.100', + }, + // ... +}; + +// 修改优先级标签 +export const PRIORITY_CONFIGS = { + [PRIORITY_LEVELS.URGENT]: { + label: '紧急', + colorScheme: 'red', + show: true, + }, + // ... +}; ``` ### NotificationContext 配置 @@ -241,6 +869,12 @@ audioRef.current.volume = 0.5; // 0.0 - 1.0 在 `src/components/NotificationContainer/index.js` 中: ```javascript +// 调整通知宽度(默认 400px) + // 修改为其他数值 + +// 调整动画方向 + // bottom=从下向上, right=从右向左 + // 调整消息间距 // 3 = 12px, 4 = 16px, 2 = 8px @@ -276,10 +910,14 @@ socketio = SocketIO(app, cors_allowed_origins=[ def handle_connect(): print(f'Client connected: {request.sid}') -# 推送交易通知 -def send_trade_notification(user_id, data): +# 推送金融资讯通知 +def send_financial_notification(user_id, data): """ - 推送交易通知到指定用户 + 推送金融资讯通知到指定用户 + + 参数: + user_id: 用户ID + data: 通知数据(参考 v2.0.0 消息格式) """ emit('trade_notification', data, room=user_id) @@ -291,49 +929,88 @@ if __name__ == '__main__': ### 2. 后端推送示例 ```python -# 交易成功后推送通知 +import time + +# 示例 1: 公告通知 socketio.emit('trade_notification', { - 'type': 'trade_alert', - 'severity': 'success', - 'title': '买入成功', - 'message': f'买入 {stock_name}({stock_code}) {quantity}股', - 'timestamp': int(time.time() * 1000), - 'autoClose': 8000 -}, room=user_id) -``` - ---- - -## 🎨 自定义样式 - -### 修改通知位置 - -在 `src/components/NotificationContainer/index.js`: - -```javascript - -``` - -### 修改通知颜色 - -在 `src/components/NotificationContainer/index.js` 中的 `NOTIFICATION_STYLES`: - -```javascript -const NOTIFICATION_STYLES = { - success: { - icon: MdCheckCircle, - colorScheme: 'green', // 修改颜色主题 - bg: 'green.50', - borderColor: 'green.400', - iconColor: 'green.500', + 'type': 'announcement', + 'priority': 'important', + 'title': '贵州茅台发布2024年度财报公告', + 'content': '2024年度营收同比增长15.2%,净利润创历史新高', + 'publishTime': int(time.time() * 1000), + 'pushTime': int(time.time() * 1000), + 'isAIGenerated': False, + 'clickable': True, + 'link': '/event-detail/ann001', + 'extra': { + 'announcementType': '财报', + 'companyCode': '600519', + 'companyName': '贵州茅台', }, - // ... -}; + 'autoClose': 10000 +}, room=user_id) + +# 示例 2: 股票动向(涨) +socketio.emit('trade_notification', { + 'type': 'stock_alert', + 'priority': 'urgent', + 'title': '您关注的股票触发预警', + 'content': f'宁德时代(300750) 当前价格 ¥{current_price},涨幅 +{change_percent}%', + 'publishTime': int(time.time() * 1000), + 'pushTime': int(time.time() * 1000), + 'isAIGenerated': False, + 'clickable': True, + 'link': '/stock-overview?code=300750', + 'extra': { + 'stockCode': '300750', + 'stockName': '宁德时代', + 'priceChange': f'+{change_percent}%', # 涨:红色 + 'currentPrice': str(current_price), + }, + 'autoClose': 10000 +}, room=user_id) + +# 示例 3: 事件动向 +socketio.emit('trade_notification', { + '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) + +# 示例 4: 分析报告(AI) +socketio.emit('trade_notification', { + 'type': 'analysis_report', + 'priority': 'normal', + 'title': 'AI产业链投资机会分析', + 'content': '随着大模型应用加速落地,算力、数据、应用三大方向均存在投资机会', + 'publishTime': int(time.time() * 1000), + 'pushTime': int(time.time() * 1000), + 'author': { + 'name': 'AI分析师', + 'organization': '价值前沿', + }, + 'isAIGenerated': True, # AI 徽章 + 'clickable': True, + 'link': '/forecast-report?id=rpt002', + 'extra': { + 'reportType': '策略报告', + 'industry': '人工智能', + 'rating': '推荐', + }, + 'autoClose': 12000 +}, room=user_id) ``` --- @@ -346,22 +1023,43 @@ const NOTIFICATION_STYLES = { 1. 确认 `NotificationProvider` 已包裹应用 2. 检查浏览器控制台是否有错误 3. 确认 socket 连接状态(查看测试工具) +4. 检查通知数据格式是否正确(参考 v2.0.0 消息格式) -### 问题 2: 音效不播放 +### 问题 2: 股票动向颜色不对 + +**解决方案:** +1. 检查 `extra.priceChange` 字段是否存在 +2. 确认 `priceChange` 格式为 "+5.2%" 或 "-3.8%"(包含符号) +3. 确认使用了 `NOTIFICATION_TYPES.STOCK_ALERT` 类型 + +### 问题 3: AI 徽章不显示 + +**解决方案:** +1. 检查 `isAIGenerated` 字段是否为 `true` +2. 确认字段名拼写正确(驼峰命名) + +### 问题 4: 点击跳转不工作 + +**解决方案:** +1. 检查 `clickable` 字段是否为 `true` +2. 确认 `link` 字段存在且格式正确 +3. 检查路由配置是否正确 + +### 问题 5: 音效不播放 **解决方案:** 1. 检查浏览器是否允许自动播放音频 2. 确认音效开关已打开 3. 检查音频文件路径是否正确 -### 问题 3: Mock 推送不工作 +### 问题 6: Mock 推送不工作 **检查项:** 1. 确认 `.env` 中设置了 `REACT_APP_ENABLE_MOCK=true` 2. 查看控制台日志确认 Mock 服务已启动 3. 检查 `startMockPush` 是否被调用 -### 问题 4: Socket 连接失败 +### 问题 7: Socket 连接失败 **解决方案:** 1. 检查后端 Flask-SocketIO 是否正确运行 @@ -378,17 +1076,27 @@ const NOTIFICATION_STYLES = { - 建议根据实际需求调整 `maxNotifications` 值 2. **合理设置自动关闭时长** - - 建议 5-10 秒(默认 8 秒) + - 公告通知:10 秒 + - 股票动向:10 秒 + - 事件动向:12 秒(内容较多) + - 分析报告:12 秒(内容较多) - 重要消息可设置更长时间或 `autoClose: false` 3. **避免频繁推送** - 生产环境建议间隔至少 3 秒 + - Mock 模式默认 15 秒推送 1 条 - 避免短时间内大量推送造成用户困扰 4. **视觉性能优化** ✅ 已实现 - 使用 Chakra UI 的优化动画(Slide、ScaleFade) - z-index 合理分配,避免层叠问题 - 间距适中(12px),不会过于紧密 + - 统一宽度(400px),避免布局抖动 + +5. **点击交互优化** ✅ 已实现 + - 使用 React Router `navigate` 实现客户端路由 + - 点击事件冒泡控制(关闭按钮 `stopPropagation`) + - 悬停反馈平滑过渡(`transition: all 0.2s`) --- @@ -396,17 +1104,201 @@ const NOTIFICATION_STYLES = { 可以考虑添加的功能: -1. ✨ 通知历史记录 -2. ✨ 通知分类过滤 -3. ✨ 通知优先级 +1. ✨ 通知历史记录(带时间线展示) +2. ✨ 通知分类过滤(按类型、优先级筛选) +3. ✨ 通知优先级排序(紧急消息置顶) 4. ✨ 通知持久化(存储到 localStorage) -5. ✨ 通知点击交互(跳转到相关页面) -6. ✨ 用户偏好设置(通知类型开关) +5. ✨ 通知点击跳转动画(页面过渡效果) +6. ✨ 用户偏好设置(通知类型开关、免打扰模式) +7. ✨ 通知分组(同一股票的多条通知合并显示) +8. ✨ 桌面通知集成(Web Notifications API) +9. ✨ 通知搜索功能(历史记录搜索) +10. ✨ 通知统计分析(每日推送量、类型分布) --- ## 📝 更新日志 +### v2.2.0 (2025-01-21) - 双通知系统 🆕 + +**新增功能:** +- ✅ **浏览器原生通知**:集成 Web Notifications API + - 系统级通知,显示在操作系统通知中心 + - 即使标签页在后台也能收到通知 + - 点击通知聚焦窗口并跳转详情 + +- ✅ **智能分发策略**:根据优先级和页面状态自动选择通知方式 + - **紧急(URGENT)**:浏览器通知 + 网页通知(双重保障) + - **重要(IMPORTANT)**:页面在后台=浏览器通知,在前台=网页通知 + - **普通(NORMAL)**:仅显示网页通知 + +- ✅ **权限管理系统**: + - 自动检测浏览器通知权限状态 + - 测试工具显示权限状态(已授权/未授权/已拒绝) + - 一键请求权限按钮 + - 权限被拒绝时显示提示信息 + +**技术实现:** +- 新增 `browserNotificationService.js` 浏览器通知服务 +- NotificationContext 集成智能分发逻辑 +- 使用 `document.hidden` 检测页面状态 +- 浏览器通知点击使用 `window.location.hash` 跳转 + +**文件变更:** +- 新增:`src/services/browserNotificationService.js` +- 修改:`src/contexts/NotificationContext.js` +- 修改:`src/components/NotificationTestTool/index.js` + +**测试工具更新:** +- 顶部 Badge 显示浏览器权限状态 +- 新增"浏览器通知"测试区域 +- 请求权限按钮(未授权时显示) +- 权限状态实时说明 + +--- + +### v2.1.0 (2025-01-21) - 预测通知系统 + +**新增功能:** +- ✅ **预测通知系统**:支持预测→详情两阶段推送 + - 预测通知:不可跳转,显示"预测"徽章和状态提示 + - 详情通知:可跳转,显示"查看详情"提示 + - 典型场景:先推送预测(T+0),延迟推送详情(T+5分钟) + +- ✅ **严格可点击性判断**: + - 只有 `clickable=true` 且 `link` 存在才可点击 + - 不可点击通知:cursor=default,无 hover 效果,不显示"查看详情" + +- ✅ **新增字段**: + - `extra.isPrediction`:是否为预测通知(显示"预测"徽章) + - `extra.statusHint`:状态提示文字(如"详细报告生成中...") + - `extra.relatedPredictionId`:关联预测 ID(用于追溯) + +- ✅ **测试工具增强**: + - 新增"预测通知"测试按钮 + - 新增"预测→详情流程"测试(5秒延迟) + - Mock 数据新增 2 条预测通知示例 + +- ✅ **视觉优化**: + - 预测通知:灰色"预测"徽章 + - 状态提示:灰色小字 + 时钟图标(MdSchedule) + - 不可点击通知无 hover 效果 + +**技术细节:** +- 新增 `NOTIFICATION_STATUS` 常量(PREDICTION/READY) +- NotificationContainer 严格判断 `isActuallyClickable = clickable && link` +- 导入 MdSchedule 图标用于状态提示 + +**文档更新:** +- 新增预测通知使用场景说明 +- 新增预测→详情流程代码示例 +- 更新测试工具说明(9 种测试 + 3 种组合) + +--- + +### v2.0.0 (2025-01-21) - 金融资讯专业版 + +**重大重构:** +- ✅ **通知类型系统**:从 4 种通用类型(成功/错误/警告/信息)重构为 4 种金融资讯类型 + - 公告通知 (Announcement) - 蓝色系 + - 股票动向 (Stock Alert) - 红绿系(动态) + - 事件动向 (Event Alert) - 橙色系 + - 分析报告 (Analysis Report) - 紫色系 + +- ✅ **优先级系统**:新增 3 级优先级 + - 紧急 (Urgent) - 红色标签 + - 重要 (Important) - 橙色标签 + - 普通 (Normal) - 无标签 + +- ✅ **智能元数据**: + - 发布时间(智能格式化:刚刚、X分钟前、今天 HH:mm、昨天 HH:mm) + - 作者信息(仅分析报告,格式:作者 - 机构) + - AI 生成标识(紫色 AI 徽章) + +- ✅ **动态配色方案**: + - 股票动向根据 `priceChange` 自动判断涨跌 + - 涨(+):红色系(icon、border、bg、hover) + - 跌(-):绿色系 + +- ✅ **点击交互**: + - 支持点击跳转到详情页(React Router) + - 可配置 `clickable` 和 `link` + - 悬停视觉反馈(上移 2px + 阴影增强) + - "📂 查看详情" 提示文本 + +- ✅ **统一设计**: + - 所有通知宽度统一为 400px + - 内容超长自动截断(noOfLines) + - 响应式布局优化 + +- ✅ **Mock 数据升级**: + - 14 条金融资讯模拟数据 + - 3 条公告通知 + 3 条股票动向 + 3 条事件动向 + 4 条分析报告(2 条 AI) + - 真实场景数据(贵州茅台、宁德时代、比亚迪、央行政策等) + +- ✅ **测试工具升级**: + - 8 种单独测试:公告、股票上涨/下跌、事件、分析/AI 报告 + - 2 种组合测试:层叠测试(4 种类型)、优先级测试(3 个级别) + - 类型特定图标和配色 + - UI 分组优化(Divider) + +- ✅ **文件结构优化**: + - 新增 `src/constants/notificationTypes.js` 统一管理类型定义 + - `NotificationContainer/index.js` 完全重写 + - `NotificationTestTool/index.js` 完全重写 + - `mockSocketService.js` Mock 数据重构 + +**技术细节:** +- 使用 React Router `useNavigate` 实现点击跳转 +- 动态类型配置(getIcon、getColorScheme、getBg 等函数) +- 条件渲染优化(优先级标签、AI 徽章、作者信息、点击提示) +- 时间格式化辅助函数(formatNotificationTime) + +**破坏性变更:** +- ⚠️ 消息格式完全改变(从 severity 改为 type + priority) +- ⚠️ 移除了通用的 success/error/warning/info 类型 +- ⚠️ 新增必填字段:`type`、`priority`、`publishTime` +- ⚠️ 分析报告必须包含 `author` 字段 +- ⚠️ 股票动向需要 `extra.priceChange` 字段用于动态配色 + +**迁移指南:** +```javascript +// 旧版本(v1.x) +addNotification({ + type: 'trade_alert', + severity: 'success', // ❌ 移除 + title: '买入成功', + message: '...', // ❌ 改为 content +}) + +// 新版本(v2.0) +addNotification({ + type: NOTIFICATION_TYPES.ANNOUNCEMENT, // ✅ 新的类型系统 + priority: PRIORITY_LEVELS.IMPORTANT, // ✅ 新增优先级 + title: '买入成功', + content: '...', // ✅ message 改为 content + publishTime: Date.now(), // ✅ 新增发布时间 + pushTime: Date.now(), + isAIGenerated: false, // ✅ 新增 AI 标识 + clickable: true, // ✅ 新增点击配置 + link: '/event-detail/001', // ✅ 新增跳转链接 + extra: { ... }, // ✅ 新增额外信息 + autoClose: 10000, +}) +``` + +--- + +### v1.1.1 (2025-01-21) - 动画优化版 + +- ✅ **动画方向优化**:从"从右向左滑入"改为"**从底部向上滑入**" + - 更符合"通知浮起"的物理隐喻 + - 视觉效果更自然,与"堆叠"概念一致 + - 代码修改:`direction="right"` → `direction="bottom"` +- ✅ **文档更新**:同步更新动画说明和可视化图示 + +--- + ### v1.1.0 (2025-01-21) - 交互优化版 - ✅ **新消息置顶展示**(行业标准,参考 Windows/macOS/Slack) @@ -422,6 +1314,8 @@ const NOTIFICATION_STYLES = { - 队列满时红色提示 - ✅ **文档完善**:添加展示逻辑说明、配置指南 +--- + ### v1.0.0 (2025-01-20) - 初始版本 - ✅ 实现基础通知系统 @@ -437,9 +1331,11 @@ const NOTIFICATION_STYLES = { - **前端框架**: React 18.3.1 - **UI 库**: Chakra UI 2.8.2 +- **路由**: React Router v6 - **实时通信**: Socket.IO Client 4.7.4 - **后端框架**: Flask-SocketIO 5.3.6 - **状态管理**: React Context API +- **图标库**: React Icons (Material Design) --- @@ -447,8 +1343,9 @@ const NOTIFICATION_STYLES = { 如有问题,请查看: - 项目文档: `CLAUDE.md` -- 测试工具: 开发环境右上角 +- 测试工具: 开发环境右上角"金融资讯测试工具" - 控制台日志: 所有操作都有详细日志 +- 类型定义: `src/constants/notificationTypes.js` --- diff --git a/src/components/NotificationContainer/index.js b/src/components/NotificationContainer/index.js index 3c2a962c..777aeb8c 100644 --- a/src/components/NotificationContainer/index.js +++ b/src/components/NotificationContainer/index.js @@ -1,9 +1,10 @@ // src/components/NotificationContainer/index.js /** - * 通知容器组件 - 右下角层叠显示实时通知 + * 金融资讯通知容器组件 - 右下角层叠显示实时通知 */ -import React from 'react'; +import React, { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import { Box, VStack, @@ -11,56 +12,69 @@ import { Text, IconButton, Icon, + Badge, + Button, useColorModeValue, Slide, ScaleFade, } from '@chakra-ui/react'; -import { MdClose, MdCheckCircle, MdError, MdWarning, MdInfo } from 'react-icons/md'; +import { MdClose, MdOpenInNew, MdSchedule, MdExpandMore, MdExpandLess } from 'react-icons/md'; import { useNotification } from '../../contexts/NotificationContext'; - -// 通知类型对应的图标和颜色 -const NOTIFICATION_STYLES = { - success: { - icon: MdCheckCircle, - colorScheme: 'green', - bg: 'green.50', - borderColor: 'green.400', - iconColor: 'green.500', - }, - error: { - icon: MdError, - colorScheme: 'red', - bg: 'red.50', - borderColor: 'red.400', - iconColor: 'red.500', - }, - warning: { - icon: MdWarning, - colorScheme: 'orange', - bg: 'orange.50', - borderColor: 'orange.400', - iconColor: 'orange.500', - }, - info: { - icon: MdInfo, - colorScheme: 'blue', - bg: 'blue.50', - borderColor: 'blue.400', - iconColor: 'blue.500', - }, -}; +import { + NOTIFICATION_TYPE_CONFIGS, + NOTIFICATION_TYPES, + PRIORITY_CONFIGS, + NOTIFICATION_CONFIG, + formatNotificationTime, +} from '../../constants/notificationTypes'; /** * 单个通知项组件 */ const NotificationItem = ({ notification, onClose, isNewest = false }) => { - const { id, severity = 'info', title, message } = notification; - const style = NOTIFICATION_STYLES[severity] || NOTIFICATION_STYLES.info; + const navigate = useNavigate(); + const { id, type, priority, title, content, isAIGenerated, clickable, link, author, publishTime, pushTime, extra } = notification; - const bgColor = useColorModeValue(style.bg, `${style.colorScheme}.900`); - const borderColor = useColorModeValue(style.borderColor, `${style.colorScheme}.500`); + // 严格判断可点击性:只有 clickable=true 且 link 存在才可点击 + const isActuallyClickable = clickable && link; + + // 判断是否为预测通知 + const isPrediction = extra?.isPrediction; + + // 获取类型配置 + let typeConfig = NOTIFICATION_TYPE_CONFIGS[type] || NOTIFICATION_TYPE_CONFIGS[NOTIFICATION_TYPES.EVENT_ALERT]; + + // 股票动向需要根据涨跌动态配置 + if (type === NOTIFICATION_TYPES.STOCK_ALERT && extra?.priceChange) { + const priceChange = extra.priceChange; + typeConfig = { + ...typeConfig, + icon: typeConfig.getIcon(priceChange), + colorScheme: typeConfig.getColorScheme(priceChange), + bg: typeConfig.getBg(priceChange), + borderColor: typeConfig.getBorderColor(priceChange), + iconColor: typeConfig.getIconColor(priceChange), + hoverBg: typeConfig.getHoverBg(priceChange), + }; + } + + // 获取优先级配置 + const priorityConfig = PRIORITY_CONFIGS[priority] || PRIORITY_CONFIGS.normal; + + const bgColor = useColorModeValue(typeConfig.bg, `${typeConfig.colorScheme}.900`); + const borderColor = useColorModeValue(typeConfig.borderColor, `${typeConfig.colorScheme}.500`); const textColor = useColorModeValue('gray.800', 'white'); const subTextColor = useColorModeValue('gray.600', 'gray.300'); + const metaTextColor = useColorModeValue('gray.500', 'gray.400'); + const hoverBg = typeConfig.hoverBg; + const closeButtonHoverBg = useColorModeValue(`${typeConfig.colorScheme}.200`, `${typeConfig.colorScheme}.700`); + + // 点击处理(只有真正可点击时才执行) + const handleClick = () => { + if (isActuallyClickable) { + navigate(link); + } + }; return ( @@ -69,72 +83,160 @@ const NotificationItem = ({ notification, onClose, isNewest = false }) => { borderLeft="4px solid" borderColor={borderColor} borderRadius="md" - boxShadow={isNewest ? '2xl' : 'lg'} // 最新消息更强的阴影 + boxShadow={isNewest ? '2xl' : 'lg'} p={4} - minW="350px" - maxW="450px" + w="400px" // 统一宽度 position="relative" - _hover={{ + cursor={isActuallyClickable ? 'pointer' : 'default'} // 严格判断 + onClick={isActuallyClickable ? handleClick : undefined} // 严格判断 + _hover={isActuallyClickable ? { boxShadow: 'xl', - transform: 'translateX(-4px)', - }} + transform: 'translateY(-2px)', + bg: hoverBg, + } : {}} // 不可点击时无 hover 效果 transition="all 0.2s" - // 最新消息添加微妙的高亮边框 {...(isNewest && { borderRight: '1px solid', borderRightColor: borderColor, borderTop: '1px solid', - borderTopColor: useColorModeValue(`${style.colorScheme}.100`, `${style.colorScheme}.700`), + borderTopColor: useColorModeValue(`${typeConfig.colorScheme}.100`, `${typeConfig.colorScheme}.700`), })} > - - {/* 图标 */} + {/* 头部区域:图标 + 标题 + 优先级 + AI标识 */} + + {/* 类型图标 */} - {/* 内容 */} - - + {title} + + + {/* 优先级标签 */} + {priorityConfig.show && ( + - {title} - - {message && ( - - {message} - - )} - + {priorityConfig.label} + + )} + + {/* 预测标识 */} + {isPrediction && ( + + 预测 + + )} + + {/* AI 生成标识 */} + {isAIGenerated && ( + + AI + + )} {/* 关闭按钮 */} } - size="sm" + size="xs" variant="ghost" - colorScheme={style.colorScheme} + colorScheme={typeConfig.colorScheme} aria-label="关闭通知" - onClick={() => onClose(id)} - position="absolute" - top={2} - right={2} + onClick={(e) => { + e.stopPropagation(); + onClose(id); + }} + flexShrink={0} _hover={{ - bg: useColorModeValue(`${style.colorScheme}.100`, `${style.colorScheme}.800`), + bg: closeButtonHoverBg, }} /> + + {/* 内容区域 */} + + {content} + + + {/* 底部元数据区域 */} + + {/* 作者信息(仅分析报告) */} + {author && ( + + 👤 + {author.name} - {author.organization} + | + + )} + + {/* 时间信息 */} + + 📅 + + {publishTime && formatNotificationTime(publishTime)} + {!publishTime && pushTime && formatNotificationTime(pushTime)} + + + + {/* 状态提示(仅预测通知) */} + {extra?.statusHint && ( + <> + | + + + {extra.statusHint} + + + )} + + {/* 可点击提示(仅真正可点击的通知) */} + {isActuallyClickable && ( + <> + | + + + 查看详情 + + + )} + ); @@ -145,12 +247,24 @@ const NotificationItem = ({ notification, onClose, isNewest = false }) => { */ const NotificationContainer = () => { const { notifications, removeNotification } = useNotification(); + const [isExpanded, setIsExpanded] = useState(false); // 如果没有通知,不渲染 if (notifications.length === 0) { return null; } + // 根据展开状态决定显示的通知 + const maxVisible = NOTIFICATION_CONFIG.maxVisible; + const hasMore = notifications.length > maxVisible; + const visibleNotifications = isExpanded ? notifications : notifications.slice(0, maxVisible); + const hiddenCount = notifications.length - maxVisible; + + // 颜色配置 + const collapseBg = useColorModeValue('gray.100', 'gray.700'); + const collapseHoverBg = useColorModeValue('gray.200', 'gray.600'); + const collapseTextColor = useColorModeValue('gray.700', 'gray.200'); + return ( { align="flex-end" pointerEvents="auto" > - {notifications.map((notification, index) => ( + {visibleNotifications.map((notification, index) => ( { /> ))} + + {/* 折叠/展开按钮 */} + {hasMore && ( + + + + )} ); diff --git a/src/components/NotificationTestTool/index.js b/src/components/NotificationTestTool/index.js index 3aa75741..cbec0cd5 100644 --- a/src/components/NotificationTestTool/index.js +++ b/src/components/NotificationTestTool/index.js @@ -1,7 +1,7 @@ // src/components/NotificationTestTool/index.js /** - * 通知测试工具 - 仅在开发环境显示 - * 用于手动测试通知功能 + * 金融资讯通知测试工具 - 仅在开发环境显示 + * 用于手动测试4种通知类型 */ import React, { useState } from 'react'; @@ -15,87 +15,299 @@ import { Collapse, useDisclosure, Badge, + Divider, } from '@chakra-ui/react'; -import { MdNotifications, MdClose, MdVolumeOff, MdVolumeUp } from 'react-icons/md'; +import { MdNotifications, MdClose, MdVolumeOff, MdVolumeUp, MdCampaign, MdTrendingUp, MdArticle, MdAssessment } from 'react-icons/md'; import { useNotification } from '../../contexts/NotificationContext'; import { SOCKET_TYPE } from '../../services/socket'; +import { NOTIFICATION_TYPES, PRIORITY_LEVELS } from '../../constants/notificationTypes'; const NotificationTestTool = () => { const { isOpen, onToggle } = useDisclosure(); - const { addNotification, soundEnabled, toggleSound, isConnected, clearAllNotifications, notifications } = useNotification(); + const { addNotification, soundEnabled, toggleSound, isConnected, clearAllNotifications, notifications, browserPermission, requestBrowserPermission } = useNotification(); const [testCount, setTestCount] = useState(0); + // 浏览器权限状态标签 + const getPermissionLabel = () => { + switch (browserPermission) { + case 'granted': + return '已授权'; + case 'denied': + return '已拒绝'; + case 'default': + return '未授权'; + default: + return '不支持'; + } + }; + + const getPermissionColor = () => { + switch (browserPermission) { + case 'granted': + return 'green'; + case 'denied': + return 'red'; + case 'default': + return 'gray'; + default: + return 'gray'; + } + }; + + // 请求浏览器权限 + const handleRequestPermission = async () => { + await requestBrowserPermission(); + }; + // 只在开发环境显示 if (process.env.NODE_ENV !== 'development') { return null; } - const testNotifications = [ - { - severity: 'success', - title: '买入成功', - message: '您的订单已成功执行:买入 贵州茅台(600519) 100股', - }, - { - severity: 'error', - title: '委托失败', - message: '卖出订单失败:资金不足', - }, - { - severity: 'warning', - title: '价格预警', - message: '您关注的股票已触达预设价格', - }, - { - severity: 'info', - title: '持仓提醒', - message: '您持有的股票今日涨幅达 5.2%', - }, - ]; - - const handleTestNotification = (index) => { - const notif = testNotifications[index]; + // 公告通知测试数据 + const testAnnouncement = () => { addNotification({ - ...notif, - type: 'trade_alert', - autoClose: 8000, + type: NOTIFICATION_TYPES.ANNOUNCEMENT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '【测试】贵州茅台发布2024年度财报公告', + content: '2024年度营收同比增长15.2%,净利润创历史新高,董事会建议每10股派息180元', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/event-detail/test001', + extra: { + announcementType: '财报', + companyCode: '600519', + companyName: '贵州茅台', + }, + autoClose: 10000, }); setTestCount(prev => prev + 1); }; - const handleMultipleNotifications = () => { - testNotifications.forEach((notif, index) => { - setTimeout(() => { - addNotification({ - ...notif, - type: 'trade_alert', - autoClose: 10000, - }); - }, index * 600); + // 股票动向测试数据(涨) + const testStockAlertUp = () => { + addNotification({ + type: NOTIFICATION_TYPES.STOCK_ALERT, + priority: PRIORITY_LEVELS.URGENT, + title: '【测试】您关注的股票触发预警', + content: '宁德时代(300750) 当前价格 ¥245.50,盘中涨幅达 +5.2%,已触达您设置的目标价位', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/stock-overview?code=300750', + extra: { + stockCode: '300750', + stockName: '宁德时代', + priceChange: '+5.2%', + currentPrice: '245.50', + }, + autoClose: 10000, }); - setTestCount(prev => prev + testNotifications.length); + setTestCount(prev => prev + 1); }; - const handleMaxLimitTest = () => { - // 测试最大限制:快速发送6条,验证只保留最新5条 - for (let i = 1; i <= 6; i++) { + // 股票动向测试数据(跌) + const testStockAlertDown = () => { + addNotification({ + type: NOTIFICATION_TYPES.STOCK_ALERT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '【测试】您关注的股票异常波动', + content: '比亚迪(002594) 5分钟内跌幅达 -3.8%,当前价格 ¥198.20,建议关注', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/stock-overview?code=002594', + extra: { + stockCode: '002594', + stockName: '比亚迪', + priceChange: '-3.8%', + currentPrice: '198.20', + }, + autoClose: 10000, + }); + setTestCount(prev => prev + 1); + }; + + // 事件动向测试数据 + const testEventAlert = () => { + addNotification({ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '【测试】央行宣布降准0.5个百分点', + content: '中国人民银行宣布下调金融机构存款准备金率0.5个百分点,释放长期资金约1万亿元,利好股市', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, + link: '/event-detail/test003', + extra: { + eventId: 'test003', + relatedStocks: 12, + impactLevel: '重大利好', + }, + autoClose: 12000, + }); + setTestCount(prev => prev + 1); + }; + + // 分析报告测试数据(非AI) + const testAnalysisReport = () => { + addNotification({ + type: NOTIFICATION_TYPES.ANALYSIS_REPORT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '【测试】医药行业深度报告:创新药迎来政策拐点', + content: 'CXO板块持续受益于全球创新药研发外包需求,建议关注药明康德、凯莱英等龙头企业', + publishTime: Date.now(), + pushTime: Date.now(), + author: { + name: '李明', + organization: '中信证券', + }, + isAIGenerated: false, + clickable: true, + link: '/forecast-report?id=test004', + extra: { + reportType: '行业研报', + industry: '医药', + }, + autoClose: 12000, + }); + setTestCount(prev => prev + 1); + }; + + // AI分析报告测试数据 + const testAIReport = () => { + addNotification({ + type: NOTIFICATION_TYPES.ANALYSIS_REPORT, + priority: PRIORITY_LEVELS.NORMAL, + title: '【测试】AI产业链投资机会分析', + content: '随着大模型应用加速落地,算力、数据、应用三大方向均存在投资机会,重点关注海光信息、寒武纪', + publishTime: Date.now(), + pushTime: Date.now(), + author: { + name: 'AI分析师', + organization: '价值前沿', + }, + isAIGenerated: true, + clickable: true, + link: '/forecast-report?id=test005', + extra: { + reportType: '策略报告', + industry: '人工智能', + }, + autoClose: 12000, + }); + setTestCount(prev => prev + 1); + }; + + // 预测通知测试数据(不可跳转) + const testPrediction = () => { + addNotification({ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.NORMAL, + title: '【测试】【预测】央行可能宣布降准政策', + content: '基于最新宏观数据分析,预计央行将在本周宣布降准0.5个百分点,释放长期资金', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: true, + clickable: false, // ❌ 不可点击 + link: null, + extra: { + isPrediction: true, + statusHint: '详细报告生成中...', + }, + autoClose: 15000, + }); + setTestCount(prev => prev + 1); + }; + + // 预测→详情流程测试(先推预测,5秒后推详情) + const testPredictionFlow = () => { + // 阶段 1: 推送预测 + addNotification({ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.NORMAL, + title: '【测试】【预测】新能源汽车补贴政策将延期', + content: '根据政策趋势分析,预计财政部将宣布新能源汽车购置补贴政策延长至2025年底', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: true, + clickable: false, + link: null, + extra: { + isPrediction: true, + statusHint: '详细报告生成中...', + relatedPredictionId: 'pred_test_001', + }, + autoClose: 15000, + }); + setTestCount(prev => prev + 1); + + // 阶段 2: 5秒后推送详情 + setTimeout(() => { + addNotification({ + type: NOTIFICATION_TYPES.EVENT_ALERT, + priority: PRIORITY_LEVELS.IMPORTANT, + title: '【测试】新能源汽车补贴政策延期至2025年底', + content: '财政部宣布新能源汽车购置补贴政策延长至2025年底,涉及比亚迪、理想汽车等5家龙头企业', + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: true, // ✅ 可点击 + link: '/event-detail/test_pred_001', + extra: { + isPrediction: false, + relatedPredictionId: 'pred_test_001', + eventId: 'test_pred_001', + relatedStocks: 5, + impactLevel: '重大利好', + }, + autoClose: 12000, + }); + setTestCount(prev => prev + 1); + }, 5000); + }; + + // 测试全部类型(层叠效果) + const testAllTypes = () => { + const tests = [testAnnouncement, testStockAlertUp, testEventAlert, testAnalysisReport]; + tests.forEach((test, index) => { + setTimeout(() => test(), index * 600); + }); + }; + + // 测试优先级 + const testPriority = () => { + [ + { priority: PRIORITY_LEVELS.URGENT, label: '紧急' }, + { priority: PRIORITY_LEVELS.IMPORTANT, label: '重要' }, + { priority: PRIORITY_LEVELS.NORMAL, label: '普通' }, + ].forEach((item, index) => { setTimeout(() => { addNotification({ - severity: i % 2 === 0 ? 'success' : 'info', - title: `测试消息 #${i}`, - message: `这是第 ${i} 条测试消息(共6条,应只保留最新5条)`, - type: 'trade_alert', - autoClose: 12000, + type: NOTIFICATION_TYPES.ANNOUNCEMENT, + priority: item.priority, + title: `【测试】${item.label}优先级通知`, + content: `这是一条${item.label}优先级的测试通知,用于验证优先级标签显示`, + publishTime: Date.now(), + pushTime: Date.now(), + isAIGenerated: false, + clickable: false, + autoClose: 10000, }); - }, i * 400); - } - setTestCount(prev => prev + 6); + setTestCount(prev => prev + 1); + }, index * 600); + }); }; return ( { > - 通知测试工具 + 金融资讯测试工具 {isConnected ? 'Connected' : 'Disconnected'} @@ -122,6 +334,9 @@ const NotificationTestTool = () => { {SOCKET_TYPE} + + 浏览器: {getPermissionLabel()} + : } size="xs" @@ -133,60 +348,151 @@ const NotificationTestTool = () => { {/* 工具面板 */} - - - 点击按钮测试不同类型的通知 + + + 通知类型测试 - {/* 测试按钮 */} - - - - - - + {/* 公告通知 */} + {/* 股票动向 */} + + + + + + {/* 事件动向 */} + {/* 分析报告 */} + + + AI + + + + {/* 预测通知 */} + + + + + + 组合测试 + + + {/* 层叠测试 */} + + + {/* 优先级测试 */} + {/* 预测→详情流程测试 */} + + + + + + 浏览器通知 + + + {/* 请求权限按钮 */} + {browserPermission !== 'granted' && ( + + )} + + {/* 浏览器通知状态说明 */} + {browserPermission === 'granted' && ( + + ✅ 浏览器通知已启用 + + )} + {browserPermission === 'denied' && ( + + ❌ 请在浏览器设置中允许通知 + + )} + + + {/* 功能按钮 */}