/** * 微信订阅消息工具 * 统一管理订阅消息的请求和状态 * * 订阅状态以服务端接口为准 */ const { api } = require('./request'); // 统一使用「每日记录提醒」模板,所有操作都通过这个模板通知 const SUBSCRIBE_TEMPLATES = { notify: 'tOaqM_Z6pNSih2pVpaUmP86MgwnDT5ZlwOqd0lgmXP8', }; // 防重复标记:同一会话中已请求过订阅,不再重复弹窗 let _requestedInSession = false; /** * 请求用户订阅指定模板 * @param {string|string[]} templateTypes - 模板类型或模板类型数组 * @returns {Promise} 订阅结果 { templateType: true/false } */ function requestSubscribe(templateTypes) { return new Promise((resolve, reject) => { if (!Array.isArray(templateTypes)) { templateTypes = [templateTypes]; } // 获取模板ID列表 const tmplIds = templateTypes .map(type => SUBSCRIBE_TEMPLATES[type]) .filter(id => id && id !== 'TEMPLATE_ID_'); if (tmplIds.length === 0) { console.warn('[subscribe] 模板ID未配置,请在微信小程序管理后台申请模板后更新'); resolve({}); return; } wx.requestSubscribeMessage({ tmplIds: tmplIds, success: (res) => { // 处理每个模板的授权结果 const results = {}; templateTypes.forEach((type) => { const tmplId = SUBSCRIBE_TEMPLATES[type]; const status = res[tmplId]; results[type] = status === 'accept'; }); // 将授权结果同步到后端 syncSubscribeResults(results); resolve(results); }, fail: (err) => { console.error('[subscribe] 请求订阅失败:', err); reject(err); } }); }); } /** * 将订阅结果同步到后端 */ function syncSubscribeResults(results) { Object.keys(results).forEach((type) => { const accepted = results[type]; const tmplId = SUBSCRIBE_TEMPLATES[type]; if (!tmplId || tmplId === 'TEMPLATE_ID_') return; if (accepted) { // 用户授权了,记录到后端,并同步本地标记 api.subscribeTemplate({ template_type: type, template_id: tmplId }).then(() => { wx.setStorageSync('subscribed_notify', true); }).catch((e) => { console.warn('[subscribe] 同步订阅状态到后端失败:', e); }); } // 用户拒绝时不做任何操作 }); } /** * 操作后静默请求订阅(无应用层弹窗) * * 优化策略: * 1. 同一会话中只弹窗一次(_requestedInSession 标记) * 2. 用户明确关闭通知(subscribed_notify=false)时才跳过 * 3. 如果用户没有伴侣,不弹窗 * * @param {string} scene - 触发场景(diary/photo/checkin/login) */ function requestSubscribeAfterAction(scene) { // 同一会话中已请求过,跳过 if (_requestedInSession) return; // 用户明确关闭了通知,不打扰 if (wx.getStorageSync('subscribed_notify') === false) return; // 检查是否有伴侣,没有伴侣不需要订阅 const coupleId = wx.getStorageSync('coupleId'); if (!coupleId) return; // 标记已请求,防止重复弹窗 _requestedInSession = true; // 延迟一点请求,避免干扰用户当前操作。 // 注意:微信订阅消息是一次性授权,每次操作后都应申请续订, // 用户勾选「总是保持以上选择」后这里会静默通过,不会反复弹窗。 setTimeout(() => { requestSubscribe('notify').catch(() => {}); }, 1500); } /** * 获取用户当前的订阅状态 * 从后端获取 * @param {boolean} forceRefresh - 保留旧调用参数 * @returns {Promise} 订阅状态 { template_type: true/false } */ async function getSubscribeStatus(forceRefresh = false) { try { const res = await api.mySubscribeTemplates(); const status = {}; Object.keys(SUBSCRIBE_TEMPLATES).forEach(type => { status[type] = !!res.templates[type]; }); return status; } catch (e) { return {}; } } module.exports = { requestSubscribe, requestSubscribeAfterAction, getSubscribeStatus };