miniprogramme/utils/subscribe-message-manager.js

441 lines
12 KiB
JavaScript
Raw Normal View History

2025-09-12 16:08:17 +08:00
// 订阅消息管理器 - 微信小程序专用
// 处理订阅消息的申请、管理和发送
/**
* 微信小程序订阅消息管理器
* 功能
* 1. 管理订阅消息模板
* 2. 请求用户订阅权限
* 3. 检查订阅状态
* 4. 智能订阅策略
* 5. 订阅数据统计
*/
class SubscribeMessageManager {
constructor() {
this.isInitialized = false;
// 订阅消息模板配置
this.templates = {
// 新消息通知
newMessage: {
id: 'template_id_for_new_message', // 需要在微信公众平台配置
name: '新消息通知',
description: '当您收到新消息时通知您',
keywords: ['发送人', '消息内容', '发送时间'],
required: false,
category: 'message'
},
// 好友请求通知
friendRequest: {
id: 'template_id_for_friend_request',
name: '好友请求通知',
description: '当有人申请添加您为好友时通知您',
keywords: ['申请人', '申请时间', '验证消息'],
required: false,
category: 'social'
},
// 系统通知
systemNotice: {
id: 'template_id_for_system_notice',
name: '系统通知',
description: '重要的系统消息和公告',
keywords: ['通知类型', '通知内容', '通知时间'],
required: true,
category: 'system'
},
// 群聊消息
groupMessage: {
id: 'template_id_for_group_message',
name: '群聊消息通知',
description: '当群聊中有新消息时通知您',
keywords: ['群名称', '发送人', '消息内容'],
required: false,
category: 'message'
},
// 活动提醒
activityReminder: {
id: 'template_id_for_activity_reminder',
name: '活动提醒',
description: '重要活动和事件提醒',
keywords: ['活动名称', '活动时间', '活动地点'],
required: false,
category: 'reminder'
}
};
// 订阅状态缓存
this.subscriptionStatus = new Map();
// 订阅策略配置
this.subscriptionStrategy = {
// 自动请求订阅的场景
autoRequestScenes: [
'first_message_received',
'first_friend_request',
'important_system_notice'
],
// 批量请求的最大数量
maxBatchRequest: 3,
// 请求间隔(毫秒)
requestInterval: 24 * 60 * 60 * 1000, // 24小时
// 最大请求次数
maxRequestTimes: 3
};
this.init();
}
// 初始化订阅消息管理器
async init() {
if (this.isInitialized) return;
console.log('📝 初始化订阅消息管理器...');
try {
// 加载订阅状态
await this.loadSubscriptionStatus();
// 检查模板配置
this.validateTemplateConfig();
this.isInitialized = true;
console.log('✅ 订阅消息管理器初始化完成');
} catch (error) {
console.error('❌ 订阅消息管理器初始化失败:', error);
}
}
// 请求订阅消息权限
async requestSubscription(templateKeys, options = {}) {
try {
console.log('📝 请求订阅消息权限:', templateKeys);
// 验证模板键
const validTemplateKeys = this.validateTemplateKeys(templateKeys);
if (validTemplateKeys.length === 0) {
throw new Error('没有有效的模板键');
}
// 获取模板ID
const templateIds = validTemplateKeys.map(key => this.templates[key].id);
// 检查请求频率限制
if (!this.canRequestSubscription(templateKeys)) {
console.log('⏰ 请求频率受限,跳过订阅请求');
return { success: false, reason: 'rate_limited' };
}
// 发起订阅请求
const result = await this.makeSubscriptionRequest(templateIds, options);
// 更新订阅状态
await this.updateSubscriptionStatus(validTemplateKeys, result);
// 记录请求历史
this.recordSubscriptionRequest(validTemplateKeys);
return result;
} catch (error) {
console.error('❌ 请求订阅消息权限失败:', error);
return { success: false, error: error.message };
}
}
// 发起订阅请求
async makeSubscriptionRequest(templateIds, options = {}) {
return new Promise((resolve) => {
wx.requestSubscribeMessage({
tmplIds: templateIds,
success: (res) => {
console.log('📝 订阅请求成功:', res);
resolve({
success: true,
result: res,
acceptedCount: this.countAcceptedSubscriptions(res)
});
},
fail: (error) => {
console.error('❌ 订阅请求失败:', error);
resolve({
success: false,
error: error.errMsg || '订阅请求失败'
});
}
});
});
}
// 统计接受的订阅数量
countAcceptedSubscriptions(result) {
let count = 0;
for (const templateId in result) {
if (result[templateId] === 'accept') {
count++;
}
}
return count;
}
// 智能订阅策略
async smartSubscriptionRequest(scene, context = {}) {
try {
console.log('🧠 智能订阅策略:', scene);
// 检查是否需要自动请求
if (!this.subscriptionStrategy.autoRequestScenes.includes(scene)) {
console.log('📝 当前场景不需要自动请求订阅');
return;
}
// 根据场景选择合适的模板
const templateKeys = this.getTemplatesForScene(scene);
if (templateKeys.length === 0) {
console.log('📝 当前场景没有对应的模板');
return;
}
// 过滤已订阅的模板
const unsubscribedTemplates = templateKeys.filter(key =>
!this.isSubscribed(key)
);
if (unsubscribedTemplates.length === 0) {
console.log('📝 所有相关模板都已订阅');
return;
}
// 限制批量请求数量
const templatesToRequest = unsubscribedTemplates.slice(
0,
this.subscriptionStrategy.maxBatchRequest
);
// 显示友好的订阅引导
const shouldRequest = await this.showSubscriptionGuide(scene, templatesToRequest);
if (!shouldRequest) {
console.log('📝 用户取消订阅请求');
return;
}
// 发起订阅请求
return await this.requestSubscription(templatesToRequest, { scene });
} catch (error) {
console.error('❌ 智能订阅策略执行失败:', error);
}
}
// 根据场景获取模板
getTemplatesForScene(scene) {
switch (scene) {
case 'first_message_received':
return ['newMessage', 'groupMessage'];
case 'first_friend_request':
return ['friendRequest'];
case 'important_system_notice':
return ['systemNotice'];
default:
return [];
}
}
// 显示订阅引导
async showSubscriptionGuide(scene, templateKeys) {
const templateNames = templateKeys.map(key => this.templates[key].name);
return new Promise((resolve) => {
wx.showModal({
title: '消息通知',
content: `为了及时通知您重要消息,建议开启以下通知:\n${templateNames.join('、')}`,
confirmText: '开启通知',
cancelText: '暂不开启',
success: (res) => {
resolve(res.confirm);
},
fail: () => {
resolve(false);
}
});
});
}
// 检查是否可以请求订阅
canRequestSubscription(templateKeys) {
const now = Date.now();
for (const key of templateKeys) {
const lastRequest = this.getLastRequestTime(key);
const requestCount = this.getRequestCount(key);
// 检查请求间隔
if (lastRequest && (now - lastRequest) < this.subscriptionStrategy.requestInterval) {
return false;
}
// 检查请求次数
if (requestCount >= this.subscriptionStrategy.maxRequestTimes) {
return false;
}
}
return true;
}
// 验证模板键
validateTemplateKeys(templateKeys) {
const keys = Array.isArray(templateKeys) ? templateKeys : [templateKeys];
return keys.filter(key => this.templates[key]);
}
// 验证模板配置
validateTemplateConfig() {
for (const [key, template] of Object.entries(this.templates)) {
if (!template.id || template.id.startsWith('template_id_')) {
console.warn(`⚠️ 模板 ${key} 的ID未配置或为占位符`);
}
}
}
// 检查订阅状态
isSubscribed(templateKey) {
return this.subscriptionStatus.get(templateKey) === 'accept';
}
// 获取所有订阅状态
getAllSubscriptionStatus() {
const status = {};
for (const key in this.templates) {
status[key] = {
template: this.templates[key],
subscribed: this.isSubscribed(key),
lastRequest: this.getLastRequestTime(key),
requestCount: this.getRequestCount(key)
};
}
return status;
}
// 更新订阅状态
async updateSubscriptionStatus(templateKeys, result) {
if (!result.success || !result.result) return;
for (const key of templateKeys) {
const templateId = this.templates[key].id;
const status = result.result[templateId];
if (status) {
this.subscriptionStatus.set(key, status);
}
}
await this.saveSubscriptionStatus();
}
// 记录请求历史
recordSubscriptionRequest(templateKeys) {
const now = Date.now();
const requestHistory = this.getRequestHistory();
for (const key of templateKeys) {
if (!requestHistory[key]) {
requestHistory[key] = { times: [], count: 0 };
}
requestHistory[key].times.push(now);
requestHistory[key].count++;
}
this.saveRequestHistory(requestHistory);
}
// 获取请求历史
getRequestHistory() {
try {
return wx.getStorageSync('subscriptionRequestHistory') || {};
} catch (error) {
console.error('❌ 获取请求历史失败:', error);
return {};
}
}
// 保存请求历史
saveRequestHistory(history) {
try {
wx.setStorageSync('subscriptionRequestHistory', history);
} catch (error) {
console.error('❌ 保存请求历史失败:', error);
}
}
// 获取最后请求时间
getLastRequestTime(templateKey) {
const history = this.getRequestHistory();
const keyHistory = history[templateKey];
if (keyHistory && keyHistory.times.length > 0) {
return Math.max(...keyHistory.times);
}
return null;
}
// 获取请求次数
getRequestCount(templateKey) {
const history = this.getRequestHistory();
return history[templateKey]?.count || 0;
}
// 加载订阅状态
async loadSubscriptionStatus() {
try {
const status = wx.getStorageSync('subscriptionStatus') || {};
this.subscriptionStatus = new Map(Object.entries(status));
} catch (error) {
console.error('❌ 加载订阅状态失败:', error);
}
}
// 保存订阅状态
async saveSubscriptionStatus() {
try {
const status = Object.fromEntries(this.subscriptionStatus);
wx.setStorageSync('subscriptionStatus', status);
} catch (error) {
console.error('❌ 保存订阅状态失败:', error);
}
}
// 获取管理器状态
getStatus() {
return {
isInitialized: this.isInitialized,
templates: this.templates,
subscriptionStatus: Object.fromEntries(this.subscriptionStatus),
strategy: this.subscriptionStrategy
};
}
// 重置订阅状态
reset() {
this.subscriptionStatus.clear();
this.saveSubscriptionStatus();
// 清除请求历史
try {
wx.removeStorageSync('subscriptionRequestHistory');
} catch (error) {
console.error('❌ 清除请求历史失败:', error);
}
}
}
// 创建全局实例
const subscribeMessageManager = new SubscribeMessageManager();
module.exports = subscribeMessageManager;