新增前端订阅模块,收敛模板 ID 到唯一来源
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ const storage = require('../../utils/storage')
|
||||
const dateUtils = require('../../utils/date')
|
||||
const sync = require('../../utils/sync')
|
||||
const lunar = require('../../utils/lunar')
|
||||
const subscribe = require('../../utils/subscribe')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -373,7 +374,7 @@ Page({
|
||||
requestSubscribe() {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.requestSubscribeMessage({
|
||||
tmplIds: ['6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw'],
|
||||
tmplIds: [subscribe.TEMPLATE_ID],
|
||||
success: (res) => {
|
||||
console.log('订阅消息授权结果:', res)
|
||||
resolve(res)
|
||||
|
||||
+6
-1
@@ -72,4 +72,9 @@ function person(action, data) {
|
||||
return request({ url: '/api/person', data: { action, data } })
|
||||
}
|
||||
|
||||
module.exports = { request, login, anniversary, person, BASE_URL }
|
||||
// 订阅额度:grant 上报授权,get 查询余额与风险
|
||||
function subscribe(action, data) {
|
||||
return request({ url: '/api/subscribe', data: { action, data } })
|
||||
}
|
||||
|
||||
module.exports = { request, login, anniversary, person, subscribe, BASE_URL }
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 订阅消息统一入口
|
||||
*
|
||||
* ⚠️ 最重要的约束:wx.requestSubscribeMessage 和 wx.openSetting 必须由真实点击手势
|
||||
* 直接触发(基础库 2.8.2+),且调用前不能有 await 等异步操作,否则手势上下文丢失、
|
||||
* 调用必然失败(报 fail can only be invoked by user TAP gesture)。
|
||||
* 所以本模块的 requestAndReport 必须在 bindtap 处理函数里同步调用,
|
||||
* 用户状态要提前用 getStatus 查好缓存起来,不能现查现用。
|
||||
*/
|
||||
|
||||
const sync = require('./sync')
|
||||
|
||||
const TEMPLATE_ID = '6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw'
|
||||
|
||||
/**
|
||||
* 查询用户当前的订阅设置状态
|
||||
* itemSettings 只包含用户勾选过「总是保持以上选择」的模板,据此可判断调用会不会弹窗。
|
||||
* @returns {Promise<string>}
|
||||
* silent — 已长期同意,调用不弹窗,可在任意点击上搭车静默补额度
|
||||
* willPrompt — 没勾过,调用会弹窗,只在用户主动点击时才调
|
||||
* rejected — 已长期拒绝或被封禁,再调也没用,需引导去设置页
|
||||
* mainSwitchOff — 通知总开关关闭,需引导去设置页
|
||||
* unknown — 查询失败,按 willPrompt 保守处理
|
||||
*/
|
||||
function getStatus() {
|
||||
return new Promise((resolve) => {
|
||||
wx.getSetting({
|
||||
withSubscriptions: true,
|
||||
success: (res) => {
|
||||
const s = res.subscriptionsSetting || {}
|
||||
if (s.mainSwitch === false) return resolve('mainSwitchOff')
|
||||
const item = s.itemSettings && s.itemSettings[TEMPLATE_ID]
|
||||
if (item === 'accept') return resolve('silent')
|
||||
if (item === 'reject' || item === 'ban') return resolve('rejected')
|
||||
resolve('willPrompt')
|
||||
},
|
||||
fail: () => resolve('unknown')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求订阅并把新增额度上报后端
|
||||
* 必须在 tap handler 中同步调用(本函数第一条语句就是 wx.requestSubscribeMessage)
|
||||
* @returns {Promise<boolean>} 用户是否同意
|
||||
*/
|
||||
function requestAndReport() {
|
||||
return new Promise((resolve) => {
|
||||
wx.requestSubscribeMessage({
|
||||
tmplIds: [TEMPLATE_ID],
|
||||
success: (res) => {
|
||||
const accepted = res[TEMPLATE_ID] === 'accept'
|
||||
if (!accepted) return resolve(false)
|
||||
// 走同步队列上报:失败会自动入队,下次启动 flush。
|
||||
// 不能静默吞掉——用户已经同意、微信侧额度确实 +1 了,我们漏记会导致余额低估,
|
||||
// 进而白白跳过本可以发出去的提醒。
|
||||
sync.syncOrEnqueue({ kind: 'subscribe', action: 'grant', data: { count: 1 } })
|
||||
.then(() => resolve(true))
|
||||
},
|
||||
fail: (err) => {
|
||||
console.warn('[subscribe] 订阅失败', err)
|
||||
resolve(false)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { TEMPLATE_ID, getStatus, requestAndReport }
|
||||
@@ -24,6 +24,7 @@ function enqueue(item) {
|
||||
async function dispatch(item) {
|
||||
if (item.kind === 'person') return api.person(item.action, item.data)
|
||||
if (item.kind === 'anniversary') return api.anniversary(item.action, item.data)
|
||||
if (item.kind === 'subscribe') return api.subscribe(item.action, item.data)
|
||||
throw new Error('unknown sync kind: ' + item.kind)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user