- 集成node-notifier实现跨平台系统通知 - AI响应完成时自动弹出Windows Toast通知 - 支持通知防抖机制,避免频繁弹窗 - 添加通知配置项:启用/禁用、声音、超时时间 - 移除VS Code内置弹窗,仅在系统通知失败时作为备用
912 lines
23 KiB
Markdown
912 lines
23 KiB
Markdown
# IC Coder 系统通知功能实现方案
|
||
|
||
## 目录
|
||
|
||
- [1. 需求背景](#1-需求背景)
|
||
- [2. 技术方案对比](#2-技术方案对比)
|
||
- [3. 推荐方案详解](#3-推荐方案详解)
|
||
- [4. 实现步骤](#4-实现步骤)
|
||
- [5. API 设计](#5-api-设计)
|
||
- [6. 配置选项](#6-配置选项)
|
||
- [7. 测试方案](#7-测试方案)
|
||
- [8. 注意事项](#8-注意事项)
|
||
- [9. 常见问题](#9-常见问题)
|
||
|
||
---
|
||
|
||
## 1. 需求背景
|
||
|
||
### 1.1 问题描述
|
||
|
||
当前 IC Coder 插件使用 VS Code 内置的通知 API (`vscode.window.showInformationMessage`) 来提示用户任务完成。这种方式存在以下问题:
|
||
|
||
- **可见性问题**: 用户切换到其他应用时,无法看到 VS Code 内部的通知
|
||
- **错过通知**: 长时间运行的任务(如 iverilog 仿真)完成时,用户可能已经离开 VS Code
|
||
- **用户体验**: 需要用户主动回到 VS Code 才能知道任务状态
|
||
|
||
### 1.2 目标
|
||
|
||
实现系统级通知功能,使得:
|
||
|
||
1. 用户在任何应用中都能收到任务完成通知
|
||
2. 通知显示在操作系统的通知中心(Windows Action Center / macOS Notification Center / Linux notify-send)
|
||
3. 支持自定义通知内容、图标、声音
|
||
4. 用户可以配置是否启用系统通知
|
||
|
||
---
|
||
|
||
## 2. 技术方案对比
|
||
|
||
### 2.1 方案一:node-notifier(推荐)
|
||
|
||
**描述**: 使用 `node-notifier` 库,封装了各平台的原生通知 API
|
||
|
||
**优点**:
|
||
- ✅ 跨平台支持(Windows/macOS/Linux)
|
||
- ✅ API 简单易用
|
||
- ✅ 支持自定义图标、声音、操作按钮
|
||
- ✅ 活跃维护,社区支持良好
|
||
- ✅ 支持通知点击回调
|
||
|
||
**缺点**:
|
||
- ❌ 需要添加额外依赖(~500KB)
|
||
- ❌ 首次使用需要用户授权
|
||
|
||
**适用场景**: 需要跨平台支持的生产环境
|
||
|
||
---
|
||
|
||
### 2.2 方案二:Windows PowerShell Toast 通知
|
||
|
||
**描述**: 使用 PowerShell 脚本调用 Windows 10/11 的 Toast 通知 API
|
||
|
||
**优点**:
|
||
- ✅ 无需额外依赖
|
||
- ✅ 支持丰富的 Toast 样式(按钮、输入框等)
|
||
- ✅ 与 Windows 系统深度集成
|
||
|
||
**缺点**:
|
||
- ❌ 仅支持 Windows 10/11
|
||
- ❌ 需要执行 PowerShell 脚本,可能有安全限制
|
||
- ❌ 实现复杂度较高
|
||
|
||
**适用场景**: 仅针对 Windows 平台的专用功能
|
||
|
||
---
|
||
|
||
### 2.3 方案三:Electron Notification API
|
||
|
||
**描述**: 使用 Electron 的 `Notification` API(VS Code 基于 Electron)
|
||
|
||
**优点**:
|
||
- ✅ 无需额外依赖
|
||
- ✅ 跨平台支持
|
||
- ✅ API 简洁
|
||
|
||
**缺点**:
|
||
- ❌ VS Code 扩展 API 未直接暴露 Electron API
|
||
- ❌ 需要通过 `@vscode/webview-ui-toolkit` 或其他方式间接调用
|
||
- ❌ 可能存在兼容性问题
|
||
|
||
**适用场景**: 理论可行,但实际受限于 VS Code 扩展沙箱
|
||
|
||
---
|
||
|
||
### 2.4 方案四:结合 VS Code 通知 + 系统通知
|
||
|
||
**描述**: 同时使用 VS Code 内置通知和系统通知
|
||
|
||
**优点**:
|
||
- ✅ 双重保障,覆盖所有场景
|
||
- ✅ 用户在 VS Code 内外都能看到
|
||
|
||
**缺点**:
|
||
- ❌ 可能显得冗余
|
||
- ❌ 需要处理两种通知的协调逻辑
|
||
|
||
**适用场景**: 对通知可靠性要求极高的场景
|
||
|
||
---
|
||
|
||
### 2.5 方案对比表
|
||
|
||
| 方案 | 跨平台 | 依赖大小 | 实现难度 | 用户体验 | 推荐度 |
|
||
|------|--------|----------|----------|----------|--------|
|
||
| node-notifier | ✅ | ~500KB | ⭐ 低 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||
| PowerShell Toast | ❌ Windows Only | 0 | ⭐⭐⭐ 高 | ⭐⭐⭐⭐ | ⭐⭐ |
|
||
| Electron API | ✅ | 0 | ⭐⭐⭐⭐ 很高 | ⭐⭐⭐ | ⭐ |
|
||
| 双重通知 | ✅ | ~500KB | ⭐⭐ 中 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
|
||
|
||
---
|
||
|
||
## 3. 推荐方案详解
|
||
|
||
### 3.1 选择 node-notifier 的理由
|
||
|
||
1. **成熟稳定**: 被广泛使用(npm 周下载量 > 200 万)
|
||
2. **跨平台**: 自动适配不同操作系统的通知机制
|
||
3. **功能丰富**: 支持图标、声音、操作按钮、回调
|
||
4. **易于集成**: 与 VS Code 扩展开发无缝集成
|
||
|
||
### 3.2 node-notifier 工作原理
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ IC Coder Extension │
|
||
│ ┌────────────────────────────────────────────────────────┐ │
|
||
│ │ notificationService.ts │ │
|
||
│ │ ┌──────────────────────────────────────────────────┐ │ │
|
||
│ │ │ sendSystemNotification(title, message, options) │ │ │
|
||
│ │ └──────────────────┬───────────────────────────────┘ │ │
|
||
│ └────────────────────┼──────────────────────────────────┘ │
|
||
└────────────────────────┼─────────────────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────┐
|
||
│ node-notifier │
|
||
│ (跨平台适配层) │
|
||
└──────────┬───────────┘
|
||
│
|
||
┌───────────────┼───────────────┐
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌─────────┐ ┌──────────┐ ┌──────────┐
|
||
│ Windows │ │ macOS │ │ Linux │
|
||
│ Toast │ │ NSUser │ │ notify- │
|
||
│ Notif. │ │ Notif. │ │ send │
|
||
└─────────┘ └──────────┘ └──────────┘
|
||
```
|
||
|
||
### 3.3 各平台通知效果
|
||
|
||
#### Windows 10/11
|
||
- 显示在右下角 Action Center
|
||
- 支持应用图标、标题、消息、操作按钮
|
||
- 可以播放系统声音
|
||
- 通知历史保存在通知中心
|
||
|
||
#### macOS
|
||
- 显示在右上角 Notification Center
|
||
- 支持应用图标、标题、副标题、消息
|
||
- 可以播放系统声音
|
||
- 支持回复和操作按钮
|
||
|
||
#### Linux
|
||
- 使用 `notify-send` 或 `libnotify`
|
||
- 显示位置取决于桌面环境(GNOME/KDE/XFCE)
|
||
- 支持图标、标题、消息、紧急程度
|
||
|
||
---
|
||
|
||
## 4. 实现步骤
|
||
|
||
### 4.1 安装依赖
|
||
|
||
```bash
|
||
# 安装 node-notifier
|
||
pnpm add node-notifier
|
||
|
||
# 安装类型定义
|
||
pnpm add -D @types/node-notifier
|
||
```
|
||
|
||
### 4.2 创建通知服务模块
|
||
|
||
创建 `src/services/notificationService.ts`
|
||
|
||
```typescript
|
||
import * as notifier from 'node-notifier';
|
||
import * as path from 'path';
|
||
import * as vscode from 'vscode';
|
||
|
||
/**
|
||
* 通知类型枚举
|
||
*/
|
||
export enum NotificationType {
|
||
INFO = 'info',
|
||
SUCCESS = 'success',
|
||
WARNING = 'warning',
|
||
ERROR = 'error'
|
||
}
|
||
|
||
/**
|
||
* 通知选项接口
|
||
*/
|
||
export interface NotificationOptions {
|
||
/** 通知标题 */
|
||
title: string;
|
||
/** 通知消息 */
|
||
message: string;
|
||
/** 通知类型 */
|
||
type?: NotificationType;
|
||
/** 是否播放声音 */
|
||
sound?: boolean;
|
||
/** 超时时间(秒),0 表示不自动消失 */
|
||
timeout?: number;
|
||
/** 自定义图标路径 */
|
||
icon?: string;
|
||
/** 点击通知时的回调 */
|
||
onClick?: () => void;
|
||
}
|
||
|
||
/**
|
||
* 系统通知服务类
|
||
*/
|
||
export class NotificationService {
|
||
private static instance: NotificationService;
|
||
private readonly extensionPath: string;
|
||
private readonly iconPath: string;
|
||
|
||
private constructor(context: vscode.ExtensionContext) {
|
||
this.extensionPath = context.extensionPath;
|
||
this.iconPath = path.join(this.extensionPath, 'resources', 'icon.png');
|
||
}
|
||
|
||
/**
|
||
* 获取单例实例
|
||
*/
|
||
public static getInstance(context?: vscode.ExtensionContext): NotificationService {
|
||
if (!NotificationService.instance && context) {
|
||
NotificationService.instance = new NotificationService(context);
|
||
}
|
||
return NotificationService.instance;
|
||
}
|
||
|
||
/**
|
||
* 检查是否启用系统通知
|
||
*/
|
||
private isSystemNotificationEnabled(): boolean {
|
||
const config = vscode.workspace.getConfiguration('ic-coder');
|
||
return config.get<boolean>('enableSystemNotification', true);
|
||
}
|
||
|
||
/**
|
||
* 发送系统通知
|
||
*/
|
||
public sendNotification(options: NotificationOptions): void {
|
||
// 检查用户配置
|
||
if (!this.isSystemNotificationEnabled()) {
|
||
console.log('[NotificationService] 系统通知已禁用');
|
||
return;
|
||
}
|
||
|
||
const {
|
||
title,
|
||
message,
|
||
type = NotificationType.INFO,
|
||
sound = true,
|
||
timeout = 10,
|
||
icon,
|
||
onClick
|
||
} = options;
|
||
|
||
// 准备通知参数
|
||
const notificationConfig: notifier.Notification = {
|
||
title: title,
|
||
message: message,
|
||
icon: icon || this.iconPath,
|
||
sound: sound,
|
||
wait: false,
|
||
timeout: timeout,
|
||
appID: 'IC Coder' // Windows 10/11 需要
|
||
};
|
||
|
||
// 发送通知
|
||
notifier.notify(notificationConfig, (err, response, metadata) => {
|
||
if (err) {
|
||
console.error('[NotificationService] 通知发送失败:', err);
|
||
// 降级到 VS Code 内置通知
|
||
this.fallbackToVSCodeNotification(title, message, type);
|
||
return;
|
||
}
|
||
|
||
console.log('[NotificationService] 通知已发送:', response, metadata);
|
||
});
|
||
|
||
// 监听通知点击事件
|
||
if (onClick) {
|
||
notifier.on('click', (notifierObject, options, event) => {
|
||
onClick();
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 降级到 VS Code 内置通知
|
||
*/
|
||
private fallbackToVSCodeNotification(
|
||
title: string,
|
||
message: string,
|
||
type: NotificationType
|
||
): void {
|
||
const fullMessage = `${title}: ${message}`;
|
||
|
||
switch (type) {
|
||
case NotificationType.ERROR:
|
||
vscode.window.showErrorMessage(fullMessage);
|
||
break;
|
||
case NotificationType.WARNING:
|
||
vscode.window.showWarningMessage(fullMessage);
|
||
break;
|
||
case NotificationType.SUCCESS:
|
||
case NotificationType.INFO:
|
||
default:
|
||
vscode.window.showInformationMessage(fullMessage);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送成功通知
|
||
*/
|
||
public success(title: string, message: string, onClick?: () => void): void {
|
||
this.sendNotification({
|
||
title,
|
||
message,
|
||
type: NotificationType.SUCCESS,
|
||
sound: true,
|
||
timeout: 10,
|
||
onClick
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 发送错误通知
|
||
*/
|
||
public error(title: string, message: string, onClick?: () => void): void {
|
||
this.sendNotification({
|
||
title,
|
||
message,
|
||
type: NotificationType.ERROR,
|
||
sound: true,
|
||
timeout: 15,
|
||
onClick
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 发送警告通知
|
||
*/
|
||
public warning(title: string, message: string, onClick?: () => void): void {
|
||
this.sendNotification({
|
||
title,
|
||
message,
|
||
type: NotificationType.WARNING,
|
||
sound: true,
|
||
timeout: 10,
|
||
onClick
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 发送信息通知
|
||
*/
|
||
public info(title: string, message: string, onClick?: () => void): void {
|
||
this.sendNotification({
|
||
title,
|
||
message,
|
||
type: NotificationType.INFO,
|
||
sound: false,
|
||
timeout: 8,
|
||
onClick
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.3 在扩展入口初始化服务
|
||
|
||
修改 `src/extension.ts`
|
||
|
||
```typescript
|
||
import { NotificationService } from './services/notificationService';
|
||
|
||
export function activate(context: vscode.ExtensionContext) {
|
||
// 初始化通知服务
|
||
const notificationService = NotificationService.getInstance(context);
|
||
|
||
// ... 其他初始化代码
|
||
}
|
||
```
|
||
|
||
### 4.4 在消息处理器中使用
|
||
|
||
修改 `src/utils/messageHandler.ts`
|
||
|
||
```typescript
|
||
import { NotificationService } from '../services/notificationService';
|
||
|
||
// 在适当的位置添加通知
|
||
export async function handleMessage(message: any, panel: vscode.WebviewPanel) {
|
||
const notificationService = NotificationService.getInstance();
|
||
|
||
// 示例:iverilog 仿真完成
|
||
if (message.type === 'simulationComplete') {
|
||
notificationService.success(
|
||
'IC Coder - 仿真完成',
|
||
'iverilog 仿真已成功完成,VCD 文件已生成',
|
||
() => {
|
||
// 点击通知时聚焦到 VS Code
|
||
vscode.window.showTextDocument(vscode.window.activeTextEditor!.document);
|
||
}
|
||
);
|
||
}
|
||
|
||
// 示例:仿真失败
|
||
if (message.type === 'simulationError') {
|
||
notificationService.error(
|
||
'IC Coder - 仿真失败',
|
||
`仿真过程中发生错误: ${message.error}`,
|
||
() => {
|
||
// 点击通知时打开输出面板
|
||
panel.reveal();
|
||
}
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.5 添加配置项
|
||
|
||
修改 `package.json`
|
||
|
||
```json
|
||
{
|
||
"contributes": {
|
||
"configuration": {
|
||
"title": "IC Coder",
|
||
"properties": {
|
||
"ic-coder.enableSystemNotification": {
|
||
"type": "boolean",
|
||
"default": true,
|
||
"description": "启用系统级通知(任务完成时显示操作系统通知)"
|
||
},
|
||
"ic-coder.notificationSound": {
|
||
"type": "boolean",
|
||
"default": true,
|
||
"description": "通知时播放系统声音"
|
||
},
|
||
"ic-coder.notificationTimeout": {
|
||
"type": "number",
|
||
"default": 10,
|
||
"minimum": 0,
|
||
"maximum": 60,
|
||
"description": "通知自动消失时间(秒),0 表示不自动消失"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. API 设计
|
||
|
||
### 5.1 核心 API
|
||
|
||
#### `NotificationService.getInstance(context?)`
|
||
|
||
获取通知服务单例实例
|
||
|
||
**参数**:
|
||
- `context` (可选): `vscode.ExtensionContext` - 扩展上下文,首次调用时必须提供
|
||
|
||
**返回**: `NotificationService` 实例
|
||
|
||
**示例**:
|
||
```typescript
|
||
const notificationService = NotificationService.getInstance(context);
|
||
```
|
||
|
||
---
|
||
|
||
#### `sendNotification(options)`
|
||
|
||
发送自定义通知
|
||
|
||
**参数**:
|
||
- `options`: `NotificationOptions` - 通知选项对象
|
||
|
||
**返回**: `void`
|
||
|
||
**示例**:
|
||
```typescript
|
||
notificationService.sendNotification({
|
||
title: 'IC Coder',
|
||
message: '任务已完成',
|
||
type: NotificationType.SUCCESS,
|
||
sound: true,
|
||
timeout: 10,
|
||
onClick: () => {
|
||
console.log('用户点击了通知');
|
||
}
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
#### `success(title, message, onClick?)`
|
||
|
||
发送成功通知(快捷方法)
|
||
|
||
**参数**:
|
||
- `title`: `string` - 通知标题
|
||
- `message`: `string` - 通知消息
|
||
- `onClick` (可选): `() => void` - 点击回调
|
||
|
||
**示例**:
|
||
```typescript
|
||
notificationService.success(
|
||
'IC Coder',
|
||
'VCD 文件生成成功',
|
||
() => panel.reveal()
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
#### `error(title, message, onClick?)`
|
||
|
||
发送错误通知(快捷方法)
|
||
|
||
**参数**:
|
||
- `title`: `string` - 通知标题
|
||
- `message`: `string` - 通知消息
|
||
- `onClick` (可选): `() => void` - 点击回调
|
||
|
||
**示例**:
|
||
```typescript
|
||
notificationService.error(
|
||
'IC Coder',
|
||
'编译失败: 语法错误',
|
||
() => vscode.commands.executeCommand('workbench.action.showErrorsWarnings')
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
#### `warning(title, message, onClick?)`
|
||
|
||
发送警告通知(快捷方法)
|
||
|
||
---
|
||
|
||
#### `info(title, message, onClick?)`
|
||
|
||
发送信息通知(快捷方法)
|
||
|
||
---
|
||
|
||
### 5.2 类型定义
|
||
|
||
```typescript
|
||
enum NotificationType {
|
||
INFO = 'info',
|
||
SUCCESS = 'success',
|
||
WARNING = 'warning',
|
||
ERROR = 'error'
|
||
}
|
||
|
||
interface NotificationOptions {
|
||
title: string;
|
||
message: string;
|
||
type?: NotificationType;
|
||
sound?: boolean;
|
||
timeout?: number;
|
||
icon?: string;
|
||
onClick?: () => void;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 配置选项
|
||
|
||
### 6.1 用户配置项
|
||
|
||
| 配置项 | 类型 | 默认值 | 说明 |
|
||
|--------|------|--------|------|
|
||
| `ic-coder.enableSystemNotification` | `boolean` | `true` | 是否启用系统通知 |
|
||
| `ic-coder.notificationSound` | `boolean` | `true` | 是否播放通知声音 |
|
||
| `ic-coder.notificationTimeout` | `number` | `10` | 通知自动消失时间(秒) |
|
||
|
||
### 6.2 配置方式
|
||
|
||
#### 方式 1: VS Code 设置界面
|
||
|
||
1. 打开 VS Code 设置 (`Ctrl+,` / `Cmd+,`)
|
||
2. 搜索 "IC Coder"
|
||
3. 找到 "Enable System Notification" 选项
|
||
4. 勾选或取消勾选
|
||
|
||
#### 方式 2: settings.json
|
||
|
||
```json
|
||
{
|
||
"ic-coder.enableSystemNotification": true,
|
||
"ic-coder.notificationSound": true,
|
||
"ic-coder.notificationTimeout": 10
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 测试方案
|
||
|
||
### 7.1 单元测试
|
||
|
||
创建 `src/test/suite/notificationService.test.ts`
|
||
|
||
```typescript
|
||
import * as assert from 'assert';
|
||
import * as vscode from 'vscode';
|
||
import { NotificationService, NotificationType } from '../../services/notificationService';
|
||
|
||
suite('NotificationService Test Suite', () => {
|
||
let notificationService: NotificationService;
|
||
|
||
suiteSetup(() => {
|
||
const context = {
|
||
extensionPath: __dirname
|
||
} as vscode.ExtensionContext;
|
||
notificationService = NotificationService.getInstance(context);
|
||
});
|
||
|
||
test('应该成功创建单例实例', () => {
|
||
const instance1 = NotificationService.getInstance();
|
||
const instance2 = NotificationService.getInstance();
|
||
assert.strictEqual(instance1, instance2);
|
||
});
|
||
|
||
test('应该发送成功通知', (done) => {
|
||
notificationService.success('测试标题', '测试消息');
|
||
setTimeout(() => done(), 1000);
|
||
});
|
||
});
|
||
```
|
||
|
||
### 7.2 手动测试清单
|
||
|
||
#### Windows 测试
|
||
- [ ] 通知显示在 Action Center
|
||
- [ ] 点击通知能够聚焦到 VS Code
|
||
- [ ] 通知声音正常播放
|
||
- [ ] 通知图标正确显示
|
||
- [ ] 通知在设定时间后自动消失
|
||
- [ ] 禁用系统通知后不再显示
|
||
|
||
---
|
||
|
||
## 8. 注意事项
|
||
|
||
### 8.1 权限问题
|
||
|
||
**Windows**:
|
||
- 首次使用时,Windows 可能会弹出权限请求
|
||
- 用户需要在"设置 > 系统 > 通知和操作"中允许应用通知
|
||
|
||
**macOS**:
|
||
- 需要在"系统偏好设置 > 通知"中允许 VS Code 发送通知
|
||
|
||
**Linux**:
|
||
- 需要安装 `libnotify-bin` 包
|
||
- 不同桌面环境的通知样式可能不同
|
||
|
||
### 8.2 通知频率控制
|
||
|
||
为避免通知轰炸,建议实现防抖机制:
|
||
|
||
```typescript
|
||
export class NotificationService {
|
||
private lastNotificationTime: Map<string, number> = new Map();
|
||
private readonly DEBOUNCE_INTERVAL = 3000; // 3 秒
|
||
|
||
private shouldSendNotification(key: string): boolean {
|
||
const now = Date.now();
|
||
const lastTime = this.lastNotificationTime.get(key) || 0;
|
||
|
||
if (now - lastTime < this.DEBOUNCE_INTERVAL) {
|
||
return false;
|
||
}
|
||
|
||
this.lastNotificationTime.set(key, now);
|
||
return true;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.3 错误处理
|
||
|
||
通知发送失败时,自动降级到 VS Code 内置通知。
|
||
|
||
### 8.4 安全考虑
|
||
|
||
- **不要在通知中显示敏感信息**(如 token、密码)
|
||
- **验证通知内容**,防止 XSS 攻击
|
||
- **限制通知频率**,防止滥用
|
||
|
||
---
|
||
|
||
## 9. 常见问题
|
||
|
||
### 9.1 通知不显示
|
||
|
||
**问题**: 调用通知 API 后,系统没有显示通知
|
||
|
||
**可能原因**:
|
||
1. 用户禁用了系统通知权限
|
||
2. 操作系统的"勿扰模式"已启用
|
||
3. `node-notifier` 安装失败或版本不兼容
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 添加调试日志
|
||
notifier.notify(notificationConfig, (err, response, metadata) => {
|
||
if (err) {
|
||
console.error('[NotificationService] 错误:', err);
|
||
} else {
|
||
console.log('[NotificationService] 响应:', response);
|
||
}
|
||
});
|
||
```
|
||
|
||
### 9.2 通知点击回调不触发
|
||
|
||
**问题**: 点击通知后,`onClick` 回调没有执行
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 设置 wait: true
|
||
const notificationConfig: notifier.Notification = {
|
||
title: title,
|
||
message: message,
|
||
wait: true, // 等待用户交互
|
||
};
|
||
```
|
||
|
||
### 9.3 通知图标不显示
|
||
|
||
**问题**: 通知显示时没有自定义图标
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
import * as fs from 'fs';
|
||
|
||
// 检查图标是否存在
|
||
if (!fs.existsSync(this.iconPath)) {
|
||
console.warn(`图标文件不存在: ${this.iconPath}`);
|
||
this.iconPath = ''; // 使用系统默认图标
|
||
}
|
||
```
|
||
|
||
### 9.4 Linux 上通知不工作
|
||
|
||
**问题**: 在 Linux 系统上通知无法显示
|
||
|
||
**解决方案**:
|
||
```bash
|
||
# Ubuntu/Debian
|
||
sudo apt-get install libnotify-bin
|
||
|
||
# Fedora/RHEL
|
||
sudo dnf install libnotify
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 最佳实践
|
||
|
||
### 10.1 通知时机
|
||
|
||
**推荐发送通知的场景**:
|
||
- ✅ 长时间运行的任务完成(> 10 秒)
|
||
- ✅ 后台任务完成(用户可能已切换到其他应用)
|
||
- ✅ 发生错误需要用户关注
|
||
- ✅ 重要状态变更
|
||
|
||
**不推荐发送通知的场景**:
|
||
- ❌ 即时完成的操作(< 3 秒)
|
||
- ❌ 用户主动触发且立即完成的操作
|
||
- ❌ 频繁发生的事件(如自动保存)
|
||
- ❌ 调试信息或日志
|
||
|
||
### 10.2 通知内容
|
||
|
||
**标题**:
|
||
- 简洁明了,不超过 20 个字符
|
||
- 包含应用名称(如 "IC Coder - 仿真完成")
|
||
- 使用动作完成时态("已完成" 而不是 "完成中")
|
||
|
||
**消息**:
|
||
- 提供具体信息,不超过 100 个字符
|
||
- 包含关键细节(如文件名、错误类型)
|
||
- 避免技术术语,使用用户友好的语言
|
||
|
||
**示例**:
|
||
```typescript
|
||
// ✅ 好的通知
|
||
notificationService.success(
|
||
'IC Coder - 仿真完成',
|
||
'testbench.v 仿真成功,VCD 文件已生成'
|
||
);
|
||
|
||
// ❌ 不好的通知
|
||
notificationService.success('完成', '操作已完成');
|
||
```
|
||
|
||
### 10.3 通知优先级
|
||
|
||
根据重要性设置不同的通知类型和超时时间:
|
||
|
||
```typescript
|
||
// 高优先级:错误(15 秒)
|
||
notificationService.error(
|
||
'IC Coder - 编译失败',
|
||
'发现 3 个语法错误,请检查代码'
|
||
);
|
||
|
||
// 中优先级:警告(10 秒)
|
||
notificationService.warning(
|
||
'IC Coder - 警告',
|
||
'仿真时间过长,可能存在死循环'
|
||
);
|
||
|
||
// 低优先级:信息(8 秒,无声音)
|
||
notificationService.info(
|
||
'IC Coder - 提示',
|
||
'已自动保存工作区'
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 性能指标
|
||
|
||
### 11.1 预期性能
|
||
|
||
| 指标 | 目标值 | 说明 |
|
||
|------|--------|------|
|
||
| 通知发送延迟 | < 100ms | 从调用到系统显示 |
|
||
| 内存占用 | < 5MB | 通知服务常驻内存 |
|
||
| CPU 占用 | < 1% | 空闲时 CPU 使用率 |
|
||
| 包体积增加 | ~500KB | node-notifier 依赖 |
|
||
|
||
---
|
||
|
||
## 12. 参考资料
|
||
|
||
### 12.1 官方文档
|
||
|
||
- [node-notifier GitHub](https://github.com/mikaelbr/node-notifier)
|
||
- [VS Code Extension API](https://code.visualstudio.com/api)
|
||
- [Windows Toast Notifications](https://docs.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-notifications-overview)
|
||
|
||
### 12.2 相关文章
|
||
|
||
- [Best Practices for Desktop Notifications](https://web.dev/notifications/)
|
||
- [Designing Better Notifications](https://uxdesign.cc/designing-better-notifications-36ba9c0b3e0e)
|
||
|
||
---
|
||
|
||
## 13. 总结
|
||
|
||
本文档详细介绍了在 IC Coder 插件中实现系统级通知功能的完整方案,包括:
|
||
|
||
✅ **技术选型**: 选择 `node-notifier` 作为跨平台通知解决方案
|
||
✅ **架构设计**: 单例模式的通知服务类,支持多种通知类型
|
||
✅ **实现细节**: 完整的代码示例和配置说明
|
||
✅ **测试方案**: 单元测试、集成测试和手动测试清单
|
||
✅ **最佳实践**: 通知时机、内容设计和用户体验优化
|
||
✅ **故障排查**: 常见问题和解决方案
|
||
|
||
通过实现系统级通知,IC Coder 插件能够在用户切换到其他应用时仍然及时通知任务状态,显著提升用户体验。
|
||
|
||
---
|
||
|
||
**文档版本**: v1.0
|
||
**最后更新**: 2026-01-26
|
||
**作者**: IC Coder Team
|
||
**许可**: MIT License
|
||
|