miniprogramme/utils/notification-manager.js
2025-09-12 16:08:17 +08:00

592 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 实时通知管理器 - 微信小程序专用
// 处理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;
console.log('🔔 初始化通知管理器...');
try {
// 加载通知设置
await this.loadNotificationSettings();
// 注册WebSocket消息处理器
this.registerWebSocketHandlers();
// 注册小程序生命周期事件
this.registerAppLifecycleEvents();
// 初始化未读计数
await this.loadUnreadCounts();
this.isInitialized = true;
console.log('✅ 通知管理器初始化完成');
} catch (error) {
console.error('❌ 通知管理器初始化失败:', error);
}
}
// 注册WebSocket消息处理器
registerWebSocketHandlers() {
// 新消息通知
wsManager.on('message', (data) => {
this.handleWebSocketMessage(data);
});
// 连接状态变化
wsManager.on('connected', () => {
console.log('🔔 WebSocket连接成功开始接收通知');
this.syncOfflineMessages();
});
wsManager.on('disconnected', () => {
console.log('🔔 WebSocket连接断开切换到离线模式');
});
}
// 处理WebSocket消息
async handleWebSocketMessage(data) {
try {
const message = typeof data === 'string' ? JSON.parse(data) : data;
console.log('📨 收到WebSocket消息:', message.type);
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:
console.log('🔔 未知消息类型:', message.type);
}
// 触发自定义事件
this.triggerEvent('message_received', message);
} catch (error) {
console.error('❌ 处理WebSocket消息失败:', error);
}
}
// 处理新消息
async handleNewMessage(messageData) {
console.log('💬 收到新消息:', 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) {
console.log('👥 收到好友请求:', 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) {
console.log('✅ 好友请求被接受:', acceptData);
// 显示通知
await this.showNotification({
type: 'friend_accepted',
title: '好友请求已接受',
content: `${acceptData.friendName} 已接受您的好友请求`,
data: acceptData
});
// 触发页面更新
this.triggerEvent('friend_accepted', acceptData);
}
// 处理系统通知
async handleSystemNotice(noticeData) {
console.log('📢 收到系统通知:', 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) {
console.log('👁️ 消息已读:', 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()) {
console.log('🔇 当前为静默时间,跳过通知');
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) {
// 微信小程序没有原生的本地通知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) {
console.log('🔔 没有对应的订阅消息模板');
return;
}
// 这里需要调用后端API发送订阅消息
// 因为订阅消息需要在服务端发送
console.log('📤 请求发送订阅消息:', {
templateId,
notification
});
// 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;
if (totalUnread > 0) {
wx.setTabBarBadge({
index: 1, // 消息页面的索引
text: totalUnread > 99 ? '99+' : totalUnread.toString()
});
} else {
wx.removeTabBarBadge({
index: 1
});
}
} catch (error) {
console.error('❌ 更新tabBar徽章失败:', error);
}
}
// 同步离线消息
async syncOfflineMessages() {
try {
console.log('🔄 同步离线消息...');
// 获取最后同步时间
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) {
console.log(`📥 收到 ${response.data.messages.length} 条离线消息`);
// 处理离线消息
for (const message of response.data.messages) {
await this.handleNewMessage(message);
}
// 更新同步时间
wx.setStorageSync('lastMessageSyncTime', Date.now());
}
} catch (error) {
console.error('❌ 同步离线消息失败:', error);
}
}
// 注册小程序生命周期事件
registerAppLifecycleEvents() {
// 监听小程序显示
wx.onAppShow(() => {
console.log('🔔 小程序显示,检查未读消息');
this.syncOfflineMessages();
});
// 监听小程序隐藏
wx.onAppHide(() => {
console.log('🔔 小程序隐藏,保存状态');
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();
}
}
// 获取未读计数
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
});
});
console.log('📝 订阅消息权限请求结果:', result);
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;