使用场景
小程序里,只能是用户发起form请求,才能被动收到1次或3次通知,比如支付,发货的通知,因此有客户下单,作为管理员收不到消息推送的,必须要时不时地看一下web后台订单管理很不方便,于是借道服务号的模板消息,向指定用户(即管理员)推送来单了的消息。本文的初衷就是为了解决这个无奈的。
解题思路
1.在小程序后台生成一个二维码,带着appid的参数,生成链接地址,例如 2.扫一扫拿到上述的参数进入服务号体系,取得操作人即web后台管理员的openid 3.将openid与appid相关联 4.小程序中有用户在就向公众号暴露的发起推送指令,例如 5.公众号接收到指令向管理员的openid推送订单模板信息
步骤
一、创建了数据库,使用express-generator脚手架生成应用
1.服务号api体系 1.1 bind (appid),其中appid由二维码参数得到,其中openid进入服务号时自然获得 1.2 pushMessage (appid,templateid,data) 2.小程序api体系 1.1 payment回调成功,即用户付款成功之后,向服务号api调用pushMessage接口
小程序web后台代码
1.创建二维码
这里使用一个第三方module,qr-image
详情用法如下
var {bindUrl} = require('../utils/config'); var qr = require('qr-image'); try { var img = qr.image(bindUrl, {size :5}); res.writeHead(200, {'Content-Type': 'image/png'}); img.pipe(res); } catch (e) { res.writeHead(414, {'Content-Type': 'text/html'}); res.end('414 Request-URI Too Large
'); }
服务号代码
1.公众号管理后台绑定可信域名
2.请求服务号网页授权登录接口
文档地址:
3.代码描述
router.get('/auth', function(req, res) { var REDIRECT_URI = encodeURI(req.protocol + '://' + req.headers.host + req.originalUrl.replace(req.url, '') + '/code'); console.log(REDIRECT_URI); var obj = { appid: mp.APPID, redirect_uri: REDIRECT_URI, response_type: 'code', scope: 'snsapi_userinfo', state: req.query.appid }; var param = querystring.stringify(obj); var url = `https://open.weixin.qq.com/connect/oauth2/authorize?${param}`; console.log(url); res.redirect(url);});router.get('/code', function(req, res) { console.log("req.query"); console.log(req.query.code); var obj = { appid: mp.APPID, secret: mp.SECRET, code: req.query.code, grant_type: 'authorization_code' }; var appid = req.query.state; var param = querystring.stringify(obj); var url = `https://api.weixin.qq.com/sns/oauth2/access_token?${param}`; request(url, function(error, response, body) { console.log('error:', error); // Print the error if one occurred console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received console.log('body:', body); // Print the HTML for the Google homepage. if (!body.errcode) { var data = JSON.parse(body); console.log(data); data = _.extend(data, {appid: appid}); // 获取粉丝信息 var infoUrl = `https://api.weixin.qq.com/sns/userinfo?access_token=${data.access_token}&openid=${data.openid}&lang=zh_CN`; request(infoUrl, function (error, response, body) { console.log(infoUrl) console.log(body) data = _.extend(data, JSON.parse(body)); // 判断是否已经存在 Customer.findOneAndUpdate(_.pick(data, 'openid appid'), data, {upsert: true}, (err, result) => { if (err) { console.log(err); } res.render('success'); }); }); } });});
以上代码共完成了3部分操作:1.请求code,2.取出用户openId,3.绑定openId与小程序appid
3.小程序有用户下单支付向服务器请求推送模块消息
首先,创建服务号的模板消息,注意,这里并不是小程序的模板消息。
依然获得了data格式如下
{
{first.DATA}}订单编号:{
{keyword1.DATA}}客户昵称:{
{keyword2.DATA}}订单价格:{
{keyword3.DATA}}订单标题:{
{keyword4.DATA}}订单截止时间:{
{keyword5.DATA}}{
{remark.DATA}}接下来,在服务号创建被暴露一个message/push接口,供用户支付成功被调用
// 推送消息router.post('/push', function(req, res) { // 使用querystring来格式化query字符串 var url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${mp.APPID}&secret=${mp.SECRET}`; console.log(url); request(url, function(error, response, body) { var access_token = JSON.parse(body).access_token; // 请求模板消息接口 var messageUrl = `https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=${access_token}`; // 通过appid反查openid Customer.findOne({ appid: req.body.appid }, (err, customer) => { if (err) { console.log(err); } // 用户id var openid = customer.openid; // var data = { "touser": openid, "template_id": "8_Vlmaf3EpW4fu-u94yTwHUurQWsymvdBxM-lsHZBTM", "url": req.body.url, "data": { "first": { "value": "来新订单了", "color": "#173177" }, "keyword1": { "value": req.body.title, "color": "#173177" }, "keyword2": { "value": moment.full(req.body.createdAt), "color": "#173177" }, "keyword3": { "value": req.body.address, "color": "#173177" }, "keyword4": { "value": req.body.nickname, "color": "#173177" }, "keyword5": { "value": "已支付", "color": "#173177" }, "remark": { "value": "请登录后台查看", "color": "#173177" } } }; request({ url: messageUrl, method: "POST", json: true, body: data }, function(error, response, body) { console.log('error:', error); // Print the error if one occurred console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received console.log('body:', body); // Print the HTML for the Google homepage. } ); }); }); res.send('push message success');});
顺带提一句,querystring这个第三方module很好用,将对象转成?name=huangxj&age=30这样的字符串
结尾
经过这样的操作,就完成了借道服务号完成向小程序管理员推送消息的任务。以上思路来自于Bmob的消息推送机制,还有粉丝【是我没跑】的提点。
另辟蹊径
以上是通过软方式解决,还有一种是通过市面上云打印机的硬方案,用户下单,直接给打印推单子,机子直接吐小票,更要干脆利落。