Files
past-go/weapp/utils/subscribe.js
T
2026-10-07 09:28:43 +08:00

143 lines
4.0 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.
/**
* 微信订阅消息工具
* 统一管理订阅消息的请求和状态
*
* 订阅状态以服务端接口为准
*/
const { api } = require('./request');
// 统一使用「每日记录提醒」模板,所有操作都通过这个模板通知
const SUBSCRIBE_TEMPLATES = {
notify: 'tOaqM_Z6pNSih2pVpaUmP86MgwnDT5ZlwOqd0lgmXP8',
};
// 防重复标记:同一会话中已请求过订阅,不再重复弹窗
let _requestedInSession = false;
/**
* 请求用户订阅指定模板
* @param {string|string[]} templateTypes - 模板类型或模板类型数组
* @returns {Promise<object>} 订阅结果 { 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<object>} 订阅状态 { 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
};