要实现利用云开发定时推送模板消息,分为三个重点分别是

  1. 获取和储存fromid
  2. 周期获取AccessToken
  3. 定时执行推送方法

我们将三个重点一个一个来实现

具体实现出来的效果:用户在小程序中触发定时推送会在当天22点收到模板消息,若触发多次,例如7次,就会在之后7天每天的10点收到模板消息推送。

1.获取和储存formid

推送模板消息必不可少的是formid 首先我们需要在用户触发了定时发送模板消息的事件之后将fromid存储在云开发数据库中

(1)先在云函数数据库中建立新的数据集来存放所需数据,formid存储在data字段中

 timeingTask{
   _id:
   _openid:  //用户openid,根据需求也可以加入opengid
   taskType: //任务类型,可以通过设定不同的参数执行不同定时任务
   execTime: //执行时间,到达这个时间开始执行
   data:{}  // 其他所需数据,将formid放在作为参数放在里面
 }

(2)创建云函数saveFormID(云函数名称可自定)用于执行储存formid   

 index.js

 const cloud = require('wx-server-sdk')
 cloud.init()
 const db = cloud.database()

 exports.main = async(event, context) => {
   switch (event.action) {
     case 'saveFormID':
       {
         return saveFormID(event)
       }
     default:
       {
         return
       }
   }
 }
 async function saveFormID(event) {
   var s = await db.collection('timeingTask').where({
     _openid: event.userInfo.openId,
   }).orderBy('execTime', 'desc').get()//获取该用户是否有待执行的推送
   if (s.data.length == 0){//若不存在待执行推送,就新增一个当日的推送
     let time = new Date();
     time.setHours(14, 0, 0, 0)//设定推送时间,可根据需求调整
     return await db.collection('timeingTask').add({//将定时任务存入云函数数据库
       data: {
         data: {
           _openid: event.userInfo.openId,
           formId: event.formId,//将formid存入data中
         },
         execTime: time,
         taskType: "1",//可根据需求自定
         _openid: event.userInfo.openId,
       }
     })
   }else{//如果已存在任务就再最新的任务的基础上再新增一个下一天执行的任务
     let lastTime = new Date(s.data[0].execTime)//最后的任务的执行时间
     lastTime.setMilliseconds(lastTime.getMilliseconds() + (1 * 24 * 60 * 60 * 1000));
     var month = lastTime.getMonth() + 1;
     var day = lastTime.getDate();
     if (month < 10) {
       month = "0" + month;
     }
     if (day < 10) {
       day = "0" + day;
     }
     var val = lastTime.getFullYear() + "-" + month + "-" + day+" 14:00:00";
     let time = new Date(val)//设定任务推送时间,可根据需求调整
     return await db.collection('timeingTask').add({//将定时任务存入云函数数据库
       data: {
         data: {
           _openid: event.userInfo.openId,
           _opengid: event.openGid,
           formId: event.formId,
         },
         execTime: time,
         taskType: "1",
         _openid: event.userInfo.openId,
         _opengid: event.openGid,
       }
     })
   }
 }

2.周期获取AccessToken

再有了formid之后我们还需要AccessToken 来发送模板消息,由于AccessToken有效时间为两小时,所以我们需要定时的更新AccessToken,需要使用到云函数定时触发器

云函数定时触发器详情可查看 云函数定时触发器

(1)在云函数数据库中创建数据集来存放AccessToken

1 publicField{
2   _id:
3   time:  //AccessToken创建的时间
4   token: //AccessToken
5   type: //类型,可根据需求使用
6 }

(2)创建云函数GetAccess(云函数名称可自定)获取AccessToken    

index.js

 cloud = require('wx-server-sdk');
 const rq = require('request-promise')//通过npm引入request-promise包,可用可不用
 cloud.init()
 const db = cloud.database();
 const APPID = '你的APPID';
 const APPSECRET = '你的APPSECRET';
 const COLLNAME = 'publicField';//云函数数据库的数据集名
 const FIELDNAME = 'ACCESS_TOKEN'//数据type 
 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)//获取AccessToken
     let now = new Date();//当前时间
     let resUpdate = await db.collection(COLLNAME).where({
       type: FIELDNAME
     }).update({//存入云函数数据库
       data: {
         token: res.access_token,
         time: now,
       }
     })
   } catch (e) {
     console.error(e)
   }
 }

 (3)设置云函数定时器

为GetAccess云函数设置每小时运行一次的定时器  ,在云函数GetAccess目录下新建文件

config.json

{
  "triggers": [
    {
      "name": "myTimer",//触发器名字
      "type": "timer",//触发器类型
      "config": "0 0 */1 * * * *"//触发时间,当前为每小时触发
    }
  ]
}

之后在云函数处右键点击上传触发器,即可完成定时运行云函数

3.定时执行推送方法

accessToken和formid都有了之后我们就可以开始最重要的部分,也就是定时执行模板消息推送了

(1)新增云函数sendMessage(云函数名称可自定)

(2)在云函数下新建文件,用于封装发送模板消息的方法

templateMessage.js 

const rp = require('request-promise');//npm引用request-promise包,可用可不用
const sendTemplateMsg = async (token, msgid, msgData, openid, formid, page) => {
  console.log("发送数据", "token:", token, "msgid:", msgid, "msgData:", msgData, "openid:", openid, "formid:", formid,"page:" ,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 => {
    console.log("发送成功", res)
  }).catch(err => {
    console.error(err)
  })
}
module.exports = {
  sendTemplateMsg: sendTemplateMsg,
}

 (3)在云函数下新建文件 ,用于封装发送方法,来处理需要发送数据

 send.js   

const cloud = require('wx-server-sdk')
const templateMessage = require('templateMessage.js')//引入发送模板消息方法
const COLL_FIELD_NAME = 'publicField';//存放accessToken的数据集
const FIELD_NAME = 'ACCESS_TOKEN'//数据类型
const MSGID = '模板ID';//要发送的模板消息的模板ID
cloud.init()
const db = cloud.database()
const send = async data => {
  let openid = data._openid//获取用户openid
  let formid = data.formId//获取formid
  let tokenRes = await db.collection(COLL_FIELD_NAME).where({
    type: FIELD_NAME
  }).get()// 从数据库中获取AccessToken
  let token = tokenRes.data[0].token; // access_token
  let page = 'pages/homePage/homePage';//模板消息的打开页
  let msgData = {//根据需求自定模板消息的数据
    keyword1: {
      value: '*****',
    },
    keyword2: {
      value: "*****",
    },
    keyword3: {
      value: "*****",
    },
  };
  await templateMessage.sendTemplateMsg(token, MSGID, msgData, openid, formid, page);//调用发送模板消息方法
}
module.exports = {
  send: send,
}

(4)在云函数中获取数据库中的任务,并判断时间是否到达执行时间

index.js

const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
exports.main = async(event, context) => {
  const execTasks = []; //创建待执行任务栈
  // 1.获取数据库中待执行的定时任务
  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) { //执行发送方法
      console.log("send执行了", task.data)const send = require('send.js')//引入发送方法
      try {
        await send.send(task.data)//执行发送方法
      } catch (e) {
        console.error(e)
      }
    }
  }
}

 (5)为云函数sendMessage添加云函数定时器,每分钟执行

config.json

{
  "permissions": {
    "openapi": [//云函数调用发送模板消息的权限
      "wxacode.get",
      "templateMessage.send",
      "templateMessage.addTemplate",
      "templateMessage.deleteTemplate",
      "templateMessage.getTemplateList",
      "templateMessage.getTemplateLibraryById",
      "templateMessage.getTemplateLibraryList"
    ]
  },
  "triggers": [
    {
      "name": "myTimer",
      "type": "timer",
      "config": "0 */1 * * * * *"//每分钟执行
    }
  ]
}

注意要上传触发器。

以上便是利用云开发定时推送模板消息的实现过程。

实现思路参考于<<微信小程序,定时发送模板消息功能实现(云开发实现)>>

12-30 20:11