upload project

This commit is contained in:
unknown 2025-12-27 17:16:03 +08:00
commit 06961cae04
422 changed files with 110626 additions and 0 deletions

View file

@ -0,0 +1,598 @@
// 实时通知管理器 - 微信小程序专用
// 处理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;