143 lines
4.0 KiB
JavaScript
143 lines
4.0 KiB
JavaScript
/**
|
||
* 微信订阅消息工具
|
||
* 统一管理订阅消息的请求和状态
|
||
*
|
||
* 订阅状态以服务端接口为准
|
||
*/
|
||
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
|
||
};
|