评论

定时发送模板消息功能实现(云开发实现)。

云开发实现定时发送模板消息。

在准备开发这个功能之前,请确保你已经阅读过云开发文档和以下相关官方文档。

模板消息

获取AccessToken

发送模板消息

云函数定时触发器

我们来设定一个需求场景。以小程序【抽奖助手】为例,用户参与抽奖后,需要在开奖时间发送给用户开奖结果通知。这个通知采用模板消息形式下发。

先整理一下思路,实现这个功能我们需要哪些模块?

  1. 定时任务执行器。根据任务类型调用相应任务处理程序。
  2. 开奖任务处理程序,开奖后发送模板消息,通知用户结果。
  3. 云函数中调用 sendTemplateMessage 后端接口,发送模板消息。
  4. 周期获取AccessToken。请求后端接口需要用AccessToken,周期更新AccessToken,放入数据库中,随用随取。

模块实现

1.定时任务执行器

以云数据库形式实现。添加一个定时任务就是在该集合增加一条记录,移除同理。

记录字段设计:

timeingTask{
  _id:
  taskType: //任务类型,决定如何处理这个任务
  execTime: // 触发时间。到达这个时间开始执行。
  data:{}  // 必要数据
}

然后设置云函数周期执行。每分钟查询一次该定时任务数据库,是否有任务到达执行时间。如果有则根据类型进行处理,并在数据库中移除该任务。

const cloud = require('wx-server-sdk')
cloud.init({
  env: '你的云环境ID'
})
const db = cloud.database()

exports.main = async(event, context) => {
  const execTasks = []; // 待执行任务栈
  // 1.查询是否有定时任务。(timeingTask)集合是否有数据。
  let taskRes = await db.collection('timeingTask').limit(100).get()
  let tasks = taskRes.data;
  // 2.定时任务是否到达触发时间。只触发一次。
  let now = new Date();
  try {
    for (let i = 0; i < tasks.length; i++) {
      if (tasks[i].execTime <= now) { // 时间到
        execTasks.push(tasks[i]); // 存入待执行任务栈
        // 定时任务数据库中删除该任务
        await db.collection('timeingTask').doc(tasks[i]._id).remove()
      }
    }
  } catch (e) {
    console.error(e)
  }
  // 3.处理待执行任务
  for (let i = 0; i < execTasks.length; i++) {
    let task = execTasks[i];
    if (task.taskType == 1) { // 定时开奖任务
      const kaiJinag = require('kaiJiang.js')
      try {
        await kaiJinag.kai(task.data.activity_id)
      } catch(e) {
        console.error(e)
      }
    }
  }
}

使云函数每分钟执行的触发器代码:

{
  "triggers": [
    {
      "name": "timeingTaskExecutor",
      "type": "timer",
      "config": "0 */1 * * * * *"
    }
  ]
}

2.开奖任务处理程序 kaijiang.js


const cloud = require('wx-server-sdk')
const templateMessage = require('templateMessage.js')

const COLL_FIELD_NAME = 'publicField';
const FIELD_NAME = 'ACCESS_TOKEN'

const MSGID = '你的模板消息ID';

cloud.init({
  env: '你的云环境ID'
})
const db = cloud.database()

const kai = async activity_id => {

  // 根据活动id,获取参与用户信息,获取到用户的 openid 和 formid.

  // 开奖程序省略
  
  // 从数据库中获取AccessToken
  let tokenRes = await db.collection(COLL_FIELD_NAME).doc(FIELD_NAME).get();
  let token = tokenRes.data.token; // access_token
  
  let page = '点击模板消息,想要打开的小程序页面';
  let msgData = {
    "keyword1": {
      "value": activity.prizeName
    },
    "keyword2": {
      "value": "你参与的抽奖活动正在开奖,点击查看中奖名单"
    },
  };
  
    let openid = '用户openid';
    let formid = '用户formid';

    await templateMessage.sendTemplateMsg(token, MSGID, msgData, openid, formid, page);
}

module.exports = {
  kai: kai,
}

3.发送模板消息 templateMessage.js

封装在一个 js 文件里,传入必要参数调用即可。

const rp = require('request-promise');
const sendTemplateMsg = async (token, msgid, msgData, openid, formid, page) => {
  await rp({
    json: true,
    method: 'POST',
    uri: 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=' + token,
    body: {
      touser: openid,
      template_id: msgid,
      page: page,
      form_id: formid,
      data: msgData
    }
  }).then(res => {
  }).catch(err => {
    console.error(err)
  })
}
module.exports = {
  sendTemplateMsg: sendTemplateMsg,
}

4.周期获取AccessToken

使用云函数触发器,使云函数每小时请求一次AccessToken,并将AccessToken存入云数据库中。

const cloud = require('wx-server-sdk')
const rq = require('request-promise')
const APPID = '你的APPID';
const APPSECRET = '你的APPSECRET';
const COLLNAME = 'publicField';
const FIELDNAME = 'ACCESS_TOKEN'

cloud.init({
  env: '你的云环境ID'
})
const db = cloud.database()

exports.main = async(event, context) => {
  try {
    let res = await rq({
      method: 'GET',
      uri: "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + APPSECRET,
    });
    res = JSON.parse(res)

    let resUpdate = await db.collection(COLLNAME).doc(FIELDNAME).update({
      data: {
        token: res.access_token
      }
    })
  } catch (e) {
    console.error(e)
  }
}

使云函数一小时执行一次的触发器代码:

{
  "triggers": [
    {
      "name": "pollGetAccessToken",
      "type": "timer",
      "config": "0 0 */1 * * * *"
    }
  ]
}

这是我做的产品册小程序中的部分代码,目前项目还没有发布,发布后会开源出来。项目中用到了挺多开源组件,给我很大的帮助,希望我的分享也可以帮助到一些人。

有问题可以在公众号后台联系我,我看到都会回复的。

点赞 1
收藏
评论

3 个评论

  • 天生倔强
    天生倔强
    2021-03-17

    可是这样不是很消耗云资源吗,还有其他方法吗

    2021-03-17
    赞同
    回复
  • Hasaki
    Hasaki
    2019-03-19

    最核心的是如何偷偷摸摸收集form_id


    其余的都可以去参考文档了。


    2019-03-19
    赞同
    回复
  • 2019-03-17

    用户触发才能发送把。

    2019-03-17
    赞同
    回复 1
    • 2019-03-17

      以小程序【抽奖助手】为例,用户参与抽奖后,需要在开奖时间发送给用户开奖结果通知。

      用户参与抽奖”,这个动作获取formid

      2019-03-17
      回复
登录 后发表内容