// 实时通知管理器 - 微信小程序专用 // 处理WebSocket消息、本地通知、订阅消息等 const wsManager = require('./websocket-manager-v2.js'); /** * 微信小程序实时通知管理器 * 功能: * 1. WebSocket消息处理和分发 * 2. 本地通知提醒 * 3. 订阅消息管理 * 4. 消息状态同步 * 5. 离线消息处理 */ class NotificationManager { constructor() { this.isInitialized = false; this.messageHandlers = new Map(); this.notificationQueue = []; this.unreadCounts = { messages: 0, friends: 0, system: 0 }; // 订阅消息模板ID(需要在微信公众平台配置) this.subscribeTemplates = { newMessage: 'template_id_for_new_message', friendRequest: 'template_id_for_friend_request', systemNotice: 'template_id_for_system_notice' }; // 通知设置 this.notificationSettings = { sound: true, vibrate: true, showBadge: true, quietHours: { enabled: false, start: '22:00', end: '08:00' } }; this.init(); } // 初始化通知管理器 async init() { if (this.isInitialized) return; try { // 加载通知设置 await this.loadNotificationSettings(); // 注册WebSocket消息处理器 this.registerWebSocketHandlers(); // 注册小程序生命周期事件 this.registerAppLifecycleEvents(); // 初始化未读计数 await this.loadUnreadCounts(); this.isInitialized = true; } catch (error) { console.error('❌ 通知管理器初始化失败:', error); } } // 注册WebSocket消息处理器 registerWebSocketHandlers() { // 新消息通知 wsManager.on('message', (data) => { this.handleWebSocketMessage(data); }); // 连接状态变化 wsManager.on('connected', () => { this.syncOfflineMessages(); }); wsManager.on('disconnected', () => { }); } // 处理WebSocket消息 async handleWebSocketMessage(data) { try { const message = typeof data === 'string' ? JSON.parse(data) : data; switch (message.type) { case 'new_message': await this.handleNewMessage(message.data); break; case 'friend_request': await this.handleFriendRequest(message.data); break; case 'friend_accepted': await this.handleFriendAccepted(message.data); break; case 'system_notice': await this.handleSystemNotice(message.data); break; case 'message_read': await this.handleMessageRead(message.data); break; case 'user_online': await this.handleUserOnline(message.data); break; case 'user_offline': await this.handleUserOffline(message.data); break; default: } // 触发自定义事件 this.triggerEvent('message_received', message); } catch (error) { console.error('❌ 处理WebSocket消息失败:', error); } } // 处理新消息 async handleNewMessage(messageData) { // 更新未读计数 this.unreadCounts.messages++; await this.saveUnreadCounts(); // 显示通知 await this.showNotification({ type: 'new_message', title: messageData.senderName || '新消息', content: this.formatMessageContent(messageData), data: messageData }); // 触发页面更新 this.triggerEvent('new_message', messageData); // 更新tabBar徽章 this.updateTabBarBadge(); } // 处理好友请求 async handleFriendRequest(requestData) { // 更新未读计数 this.unreadCounts.friends++; await this.saveUnreadCounts(); // 显示通知 await this.showNotification({ type: 'friend_request', title: '新的好友请求', content: `${requestData.senderName} 请求添加您为好友`, data: requestData }); // 触发页面更新 this.triggerEvent('friend_request', requestData); // 更新tabBar徽章 this.updateTabBarBadge(); } // 处理好友请求被接受 async handleFriendAccepted(acceptData) { // 显示通知 await this.showNotification({ type: 'friend_accepted', title: '好友请求已接受', content: `${acceptData.friendName} 已接受您的好友请求`, data: acceptData }); // 触发页面更新 this.triggerEvent('friend_accepted', acceptData); } // 处理系统通知 async handleSystemNotice(noticeData) { // 更新未读计数 this.unreadCounts.system++; await this.saveUnreadCounts(); // 显示通知 await this.showNotification({ type: 'system_notice', title: '系统通知', content: noticeData.content, data: noticeData }); // 触发页面更新 this.triggerEvent('system_notice', noticeData); } // 处理消息已读 async handleMessageRead(readData) { // 更新未读计数 if (readData.count && this.unreadCounts.messages >= readData.count) { this.unreadCounts.messages -= readData.count; await this.saveUnreadCounts(); this.updateTabBarBadge(); } // 触发页面更新 this.triggerEvent('message_read', readData); } // 显示通知 async showNotification(notification) { try { // 检查是否在静默时间 if (this.isInQuietHours()) { return; } // 检查应用状态 const appState = this.getAppState(); if (appState === 'foreground') { // 前台显示本地通知 await this.showLocalNotification(notification); } else { // 后台尝试发送订阅消息 await this.sendSubscribeMessage(notification); } // 播放提示音 if (this.notificationSettings.sound) { this.playNotificationSound(); } // 震动提醒 if (this.notificationSettings.vibrate) { this.vibrateDevice(); } } catch (error) { console.error('❌ 显示通知失败:', error); } } // 显示本地通知(前台) async showLocalNotification(notification) { // 只对已登录用户显示通知 const app = getApp(); const isLoggedIn = app?.globalData?.isLoggedIn || false; if (!isLoggedIn) return; // 微信小程序没有原生的本地通知API // 这里使用自定义的通知组件或Toast wx.showToast({ title: notification.content, icon: 'none', duration: 3000 }); // 如果有自定义通知组件,可以在这里调用 // this.triggerEvent('show_custom_notification', notification); } // 发送订阅消息(后台) async sendSubscribeMessage(notification) { try { // 检查是否有订阅权限 const templateId = this.getTemplateId(notification.type); if (!templateId) { return; } // 这里需要调用后端API发送订阅消息 // 因为订阅消息需要在服务端发送 // TODO: 调用后端API发送订阅消息 } catch (error) { console.error('❌ 发送订阅消息失败:', error); } } // 格式化消息内容 formatMessageContent(messageData) { switch (messageData.msgType) { case 0: // 文本消息 return messageData.content; case 1: // 图片消息 return '[图片]'; case 2: // 语音消息 return '[语音]'; case 3: // 视频消息 return '[视频]'; case 4: // 文件消息 return '[文件]'; default: return '[消息]'; } } // 获取模板ID getTemplateId(notificationType) { return this.subscribeTemplates[notificationType]; } // 检查是否在静默时间 isInQuietHours() { if (!this.notificationSettings.quietHours.enabled) { return false; } const now = new Date(); const currentTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`; const { start, end } = this.notificationSettings.quietHours; if (start <= end) { return currentTime >= start && currentTime <= end; } else { return currentTime >= start || currentTime <= end; } } // 获取应用状态 getAppState() { // 微信小程序中可以通过页面栈判断应用状态 const pages = getCurrentPages(); return pages.length > 0 ? 'foreground' : 'background'; } // 播放提示音 playNotificationSound() { try { // 微信小程序播放系统提示音 wx.createInnerAudioContext().play(); } catch (error) { console.error('❌ 播放提示音失败:', error); } } // 震动设备 vibrateDevice() { try { wx.vibrateShort({ type: 'medium' }); } catch (error) { console.error('❌ 震动失败:', error); } } // 更新tabBar徽章 updateTabBarBadge() { try { const totalUnread = this.unreadCounts.messages + this.unreadCounts.friends + this.unreadCounts.system; // 原生tabBar角标(兜底,部分机型自定义tabBar仍可用该API显示消息数) if (totalUnread > 0) { wx.setTabBarBadge({ index: 1, text: totalUnread > 99 ? '99+' : totalUnread.toString() }); } else { wx.removeTabBarBadge({ index: 1 }); } // 自定义tabBar同步:优先显示各自分类的数量 const pages = getCurrentPages(); const cur = pages[pages.length - 1]; if (cur && typeof cur.getTabBar === 'function') { const tb = cur.getTabBar && cur.getTabBar(); if (tb && typeof tb.setFriendsBadge === 'function' && typeof tb.setMessagesBadge === 'function') { tb.setFriendsBadge(this.unreadCounts.friends || 0); tb.setMessagesBadge(this.unreadCounts.messages || 0); } } } catch (error) { console.error('❌ 更新tabBar徽章失败:', error); } } // 同步离线消息 async syncOfflineMessages() { try { // 获取最后同步时间 const lastSyncTime = wx.getStorageSync('lastMessageSyncTime') || 0; // 调用API获取离线消息 const apiClient = require('./api-client.js'); const response = await apiClient.request({ url: '/api/v1/messages/offline', method: 'GET', data: { since: lastSyncTime } }); if (response.success && response.data.messages) { // 处理离线消息 for (const message of response.data.messages) { await this.handleNewMessage(message); } // 更新同步时间 wx.setStorageSync('lastMessageSyncTime', Date.now()); } } catch (error) { console.error('❌ 同步离线消息失败:', error); } } // 注册小程序生命周期事件 registerAppLifecycleEvents() { // 监听小程序显示 wx.onAppShow(() => { this.syncOfflineMessages(); }); // 监听小程序隐藏 wx.onAppHide(() => { this.saveUnreadCounts(); }); } // 加载通知设置 async loadNotificationSettings() { try { const settings = wx.getStorageSync('notificationSettings'); if (settings) { this.notificationSettings = { ...this.notificationSettings, ...settings }; } } catch (error) { console.error('❌ 加载通知设置失败:', error); } } // 保存通知设置 async saveNotificationSettings() { try { wx.setStorageSync('notificationSettings', this.notificationSettings); } catch (error) { console.error('❌ 保存通知设置失败:', error); } } // 加载未读计数 async loadUnreadCounts() { try { const counts = wx.getStorageSync('unreadCounts'); if (counts) { this.unreadCounts = { ...this.unreadCounts, ...counts }; this.updateTabBarBadge(); } } catch (error) { console.error('❌ 加载未读计数失败:', error); } } // 保存未读计数 async saveUnreadCounts() { try { wx.setStorageSync('unreadCounts', this.unreadCounts); } catch (error) { console.error('❌ 保存未读计数失败:', error); } } // 清除未读计数 async clearUnreadCount(type) { if (this.unreadCounts[type] !== undefined) { this.unreadCounts[type] = 0; await this.saveUnreadCounts(); this.updateTabBarBadge(); } } // 显式设置未读计数(用于以服务端真实数量为准时校准) async setUnreadCount(type, value) { if (this.unreadCounts[type] === undefined) return; const v = Math.max(0, Number(value) || 0); this.unreadCounts[type] = v; await this.saveUnreadCounts(); this.updateTabBarBadge(); } async setFriendsUnreadCount(value) { return this.setUnreadCount('friends', value); } async setMessagesUnreadCount(value) { return this.setUnreadCount('messages', value); } // 获取未读计数 getUnreadCount(type) { return this.unreadCounts[type] || 0; } // 获取总未读计数 getTotalUnreadCount() { return Object.values(this.unreadCounts).reduce((total, count) => total + count, 0); } // 更新通知设置 updateNotificationSettings(settings) { this.notificationSettings = { ...this.notificationSettings, ...settings }; this.saveNotificationSettings(); } // 请求订阅消息权限 async requestSubscribeMessage(templateIds) { try { const result = await new Promise((resolve, reject) => { wx.requestSubscribeMessage({ tmplIds: Array.isArray(templateIds) ? templateIds : [templateIds], success: resolve, fail: reject }); }); return result; } catch (error) { console.error('❌ 请求订阅消息权限失败:', error); return null; } } // 事件处理器 eventHandlers = new Map(); // 注册事件监听器 on(event, handler) { if (!this.eventHandlers.has(event)) { this.eventHandlers.set(event, []); } this.eventHandlers.get(event).push(handler); } // 移除事件监听器 off(event, handler) { const handlers = this.eventHandlers.get(event); if (handlers) { const index = handlers.indexOf(handler); if (index > -1) { handlers.splice(index, 1); } } } // 触发事件 triggerEvent(event, data) { const handlers = this.eventHandlers.get(event); if (handlers) { handlers.forEach(handler => { try { handler(data); } catch (error) { console.error(`❌ 事件处理器错误 [${event}]:`, error); } }); } } // 获取通知管理器状态 getStatus() { return { isInitialized: this.isInitialized, unreadCounts: { ...this.unreadCounts }, notificationSettings: { ...this.notificationSettings }, totalUnread: this.getTotalUnreadCount() }; } // 重置通知管理器 reset() { this.unreadCounts = { messages: 0, friends: 0, system: 0 }; this.saveUnreadCounts(); this.updateTabBarBadge(); this.eventHandlers.clear(); } } // 创建全局实例 const notificationManager = new NotificationManager(); module.exports = notificationManager;