如何给未来的自己写信--小程序版

点我体验

效果展示

写信界面:

image.png

收信形式(微信-服务通知):
image.png

功能实现

订阅消息 + 云函数 + 触发器

小程序端订阅消息实现:
小程序端主要是获取订阅消息发送的权限。
为了避免每次发送都需要询问,可以引导用户勾选 不再询问。

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。

点我体验

猜你喜欢

转载自blog.csdn.net/weixin_44778151/article/details/122806085
今日推荐