点我体验
效果展示
写信界面:
收信形式(微信-服务通知):
功能实现
订阅消息 + 云函数 + 触发器
小程序端订阅消息实现:
小程序端主要是获取订阅消息发送的权限。
为了避免每次发送都需要询问,可以引导用户勾选 不再询问。
onMailSubmit() {
// 如果已经授权订阅消息,直接插入数据到数据库
if (this.data.hasSub) {
return this.addDateSub()
}
let tmplId = app.globalData.settings.system.dateTemlIds
this.setData({
isSubMask: true // 添加遮罩层,引导用户点击不再询问
})
wx.requestSubscribeMessage({
tmplIds: [tmplId],
success: (res) => {
if (res[tmplId] === "accept") {
this.data.hasSub = true
this.addDateSub()
} else if (res[tmplId] === "reject") {
this.subReject() // 订阅消息失败,引导到设置允许
}
this.setData({
isSubMask: false
})
},
fail: (err) => {
this.subReject()
this.setData({
isSubMask: false
})
}
})
},
云函数部分实现:
存储信件数据是常规的 curd,这里就不放出来了。
这里的云函数是发送订阅消息的部分代码。
步骤大致为:获取该时段信件的数量 --> 分批获取所有信件数据(云函数每次最多获取一百条数据) --> 循环消息列表,发送订阅消息
const countResult = await db.collection('msg_subscribe')
.where({ sendTime, tmplId }).count()
const total = countResult.total
// 计算需分几次取
const batchTimes = Math.ceil(total / 100)
// 承载所有读操作的 promise 的数组
const tasks = []
for (let i = 0; i < batchTimes; i++) {
const promise = db.collection('msg_subscribe')
.where({ sendTime, tmplId }).skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()
tasks.push(promise)
}
if (tasks.length === 0) {
return 'no sub'
}
// 等待所有
const mq = (await Promise.all(tasks)).reduce((acc, cur) => {
return {
data: acc.data.concat(cur.data),
errMsg: acc.errMsg,
}
}).data
// 循环消息列表
const sendPromises = mq.map(async message => {
try {
let content = message.content.text
// 订阅消息文本长度不能超过 20 个字符
if (content.length > 20) {
content = content.substring(0, 17) + '...'
}
// 发送订阅消息
return await cloud.openapi.subscribeMessage.send({
touser: message.openid,
page: `pages/todo/timemail/timemail?_id=${message._id}`,
data: {
thing1: { value: content },
phrase2: { value: '待取' },
number3: { value: 1 },
time4: { value: message.sendTime },
time5: { value: message.updateTime }
},
templateId: tmplId,
});
} catch (e) {
return e;
}
});
return Promise.all(sendPromises);
触发器部分实现:
每个信件都有指定的送达时间,使用云开发需要用到触发器的辅助。
实现的方式:创建云函数 --> 设置触发器,每小时触发一次 --> 在 index 文件处理当前时间需要处理的任务。
// 触发器配置 cron 表达式,每到 xx:00:00 执行
{
"permissions": {
"openapi": []
},
"triggers": [
{
"name": "timedtask",
"type": "timer",
"config": "0 0 * * * * *"
}
]
}
// index 代码
exports.main = async (event, context) => {
let now = dayjs()
let hour = now.hour()
let minute = now.minute()
let time = now.format('HH:mm')
let promiseList = []
// 根据时间调用相应的处理逻辑,放到 Promise 里面执行
promiseList.push(dateSub.main(event, context))
if (hour % 6 === 0) { // 每 6 个小时拉取最新新闻消息
promiseList.push(getNews.main(event.context))
}
if (time === '05:00') { // 每天记录订阅消息派发
promiseList.push(signSub.main(event, context))
}
return await Promise.all(promiseList)
}
Q:为什么每小时才触发一次
A:云函数调用次数计费,用户量不大暂时设定为每小时检查一次信件,后继用户量多可以把时间精度调为 5 min。