1. 程式人生 > >小程式傳送模版訊息之 nodejs 實現

小程式傳送模版訊息之 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 在使用過之後會失效,需要重新獲取。


在這裡插入圖片描述