小程序发送模版消息之 nodejs 实现

功能分析

现需要实现一个用户报名成功通知到功能,管理员在后台审核之后,会通过用户的申请,同时发送小程序报名成功的模版消息到用户的微信上。

首先需要分析一下微信发送模版消息的接口

//模版消息的结构
let opts = {
                touser: param.openid, //目标用户的openid
                template_id: template_id, //模版消息的id,需要在小程序管理配置获得
                form_id: param.formId,//当前用户通过表单提交行为获得的formId 有效期7天
                data: {
                    "keyword1": {
                        "value": '值1',
                        "color": "#1d1d1d"
                    },
                    "keyword2": {
                        "value": 值2,
                        "color": "#1d1d1d"
                    }
                }
            }


//发送小程序模版消息的请求
let data = {
                method: 'POST',
                //请求接口 需要一个生成有效期为两小时的 accessToken,见下方代码
                url: `https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=${accessToken}`,
                //将模版消息的结构字符画
                body: JSON.stringify(opts),
                header: {
                    'content-type': 'application/json' // 默认值
                }
            }
//请求获取临时 AccessToken 的 Promise函数
const request = require('request');

const fetchAccessTokenReq = new Promise((resolve, reject) => {
        let APPID = '你的小程序appid';
        let secret = '你的小程序appsecret';
        let url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${secret}`

        request.get(url, (err, response, data) => {
            if (err) {
                resolve(false);
            } else {
                let AccessToken = JSON.parse(data);
                resolve(AccessToken);
            }
        })
    })

表单收集

假设活动字段设计为如下

const bookingrecord = mongoose.Schema({
    activity_id: String, //用户请求的参加活动的id
    activity_content: Object, //活动对象
    openid: String, //参加用户的openid
    submit: Object,// 提交表单
    isAllow: Boolean, //是否已经同意
    formId:String //表单id 也可以为单个用户保存
})

在小程序的form 表单中间通过 submit 提交获取到 formid,通过 post请求提交并保存到数据库

// 在page 的 form 表单中收集
<form class='section' bindsubmit="bindFromSubmit" report-submit='true' report-submit='true'>
  <text class='fontbold'>活动报名</text>
  <text class='col'>* 真实姓名</text>
  <input placeholder='真实姓名' data-key='realName' name=''></input>
  <text class='col'>*  联系方式</text>
  <input placeholder='可以联系到你的方式 微信/手机' data-key='contact'' name=''></input>
  <text class='col'>* 备注</text>
  <textarea placeholder='备注' data-key='remark'/ name=''>
  <button class='main' form-type='submit' hover-class='none' wx:if='{{submit.realName && submit.contact && submit.remark}}'>提交报名</button>
  <button class='default' hover-class='none' wx:else>不可提交</button>
</form>
// submit.js
 bindFromSubmit: function(e) {
    let formId = e.detail.formId;
  }

这样就能为每一个用户申请的报名记录记录一个 formId,同时也应该尽可能多的为单个用户保存,以防其他需求。


使用Promise整合请求

当管理员通过申请者的申请时,会将单条申请记录的字段更新,然后发送一条模版消息到用户的微信上,假设 formid 有效的情况下,使用 promise 依次处理请求,我尽量将代码写的浅显易懂。

// 通过报名申请并向报名者发送小程序模版消息
router.post('/api/allowApplyAndSendTemplateMsg', (req, res) => {
    let _body = req.body;
    let template_id = `模版id`; //模版消息的id

    // 数据库操作
    const updataCurrentOjbectAllow = new Promise((resolve, reject) => {
        db.bookingrecord.updateOne({ '_id': object._id }, { $set: { 'isAllow': true } }).exec((err, doc) => {
            if (err) {
                resolve(false)
            } else {
                resolve(true);
            }
        })
    })

    // 获取token
    const fetchAccessTokenReq = new Promise((resolve, reject) => {
        const APPID = 'appid';
        const secret = 'secret';
        const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${secret}`

        request.get(url, (err, response, data) => {
            if (err) {
                resolve(false)
            } else {
                let AccessToken = JSON.parse(data);
                resolve(AccessToken);
            }
        })
    })

    // promise all
    Promise.all([updataCurrentOjbectAllow, fetchAccessTokenReq]).then((response) => {
        let db_options_res = response[0];
        let accessToken = response[1].access_token;

        sendTemplateMessage(object, db_options_res, accessToken).then(_res => {
            if (_res) {
                return res.json({
                    code: 1,
                    msg: '发送成功',
                    result: 'send template message success'
                })
            }
        }).catch(err => {
            // 错误处理
        })

    }).catch((err) => {
    	// 错误处理
    })

    const sendTemplateMessage = (param, dbres, accessToken) => {
        return new Promise((resolve, reject) => {
            if (!dbres) {
                return res.json({
                    code: 0,
                    msg: '数据库写入失败',
                    result: 'db updata fail'
                })
            }

            let opts = {
                touser: param.openid,
                template_id: template_id,
                form_id: param.formId,
                data: {
                    "keyword1": {
                        "value": '说明2',
                        "color": "#1d1d1d"
                    },
                    "keyword7": {
                        "value": '说明2',
                        "color": "#1d1d1d"
                    }
                }
            }

            let data = {
                method: 'POST',
                url: `https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=${accessToken}`,
                body: JSON.stringify(opts),
                header: {
                    'content-type': 'application/json' // 默认值
                }
            }

            request(data, function(error, response, data) {
                let result = JSON.parse(data);
                if (result.errcode == '0' && result.errmsg === 'ok') {
                    resolve(result)
                } else {
                    reject(result)
                }
            });
        })
    }
})

其他问题 ⚠️

accessToken 在使用过之后会失效,需要重新获取。
小程序发送模版消息之 nodejs 实现


小程序发送模版消息之 nodejs 实现