本文以微信小程序內(nèi)置的兩個(gè)模板:購(gòu)買(mǎi)成功和評(píng)論回復(fù)提醒為例來(lái)闡述第三方微信小程序平臺(tái)的設(shè)計(jì)。
小程序端
? ? 微信用戶支付成功后,微信服務(wù)通知中會(huì)收到支付成功服務(wù)提醒。見(jiàn)下圖:
商家端
用戶完成評(píng)價(jià)后,商家管理端可以查看評(píng)論。見(jiàn)下圖:
商家進(jìn)行回復(fù):
商家回復(fù)微信小程序用戶的評(píng)論后,微信用戶在微信的服務(wù)通知會(huì)收到評(píng)價(jià)回復(fù)提醒,用戶點(diǎn)開(kāi)后可以查看回復(fù)的詳情。
這些效果如何實(shí)現(xiàn)的呢??
?1 首先介紹表設(shè)計(jì)
?1.1 服務(wù)評(píng)價(jià)及留言表設(shè)計(jì)
? 這張表關(guān)鍵字段是訂單ID(order_id)、服務(wù)評(píng)價(jià)留言(msg)、商家管理員后臺(tái)回復(fù)信息(reply_msg)及商家管理員的帳號(hào)ID(admin_id) 。 一個(gè)訂單服務(wù)只可被評(píng)價(jià)一次和回復(fù)一次。
CREATE TABLE `t_order_comment` (
? `id` bigint NOT NULL,
? `stars` smallint DEFAULT '0',
? `order_id` bigint NOT NULL,
? `msg` varchar(200) DEFAULT NULL,
? `openid` varchar(64) NOT NULL,
? `submit_time` datetime DEFAULT NULL,
? `reply_time` datetime DEFAULT NULL,
? `reply_msg` varchar(200) DEFAULT NULL,
? `admin_id` bigint DEFAULT NULL,
? PRIMARY KEY (`id`),
? UNIQUE KEY `uniq_order_id` (`order_id`),
? KEY `index_openid` (`openid`),
? KEY `index_adminid` (`admin_id`)
) ;
1.2 小程序消息模板設(shè)置表
?描述商家小程序與小程序模板的關(guān)聯(lián)關(guān)系。一個(gè)小程序可以設(shè)置多個(gè)消息模板。
component_appid: 微信第三方平臺(tái)應(yīng)用appid;
authorizer_appid: 商家小程序appid;
business_type: 業(yè)務(wù)枚舉字典,如:購(gòu)買(mǎi)成功(buy_success)和評(píng)價(jià)回復(fù)(order_comment_reply);
msg_template_id: 微信小程序的模板ID?
CREATE TABLE `t_mini_msg_set` (
? `id` bigint NOT NULL,
? `component_appid` varchar(64) NOT NULL,
? `authorizer_appid` varchar(64) NOT NULL,
? `business_type` varchar(32) NOT NULL,
? `business_type_des` varchar(64) DEFAULT NULL,
? `msg_template_id` varchar(64) NOT NULL,
? PRIMARY KEY (`id`),
? UNIQUE KEY `component_appid_msg_template_id` (`component_appid`,`authorizer_appid`,`msg_template_id`)
) ;
2 前端設(shè)計(jì)
2.1 小程序端提交評(píng)價(jià)
?小程序端訂單服務(wù)評(píng)價(jià)設(shè)計(jì)。 源碼參考:
<van-action-sheet show="{{ commentShow }}" title="訂單服務(wù)評(píng)價(jià)" bind:close="onMsgClose"> <view style="height: 160px"> <van-cell-group> <van-rate value="{{ stars }}" bind:change="onStarsChange" /> <van-field value="{{ msg }}" label="留言建議 " type="textarea" placeholder="請(qǐng)輸入留言" autosize="{maxHeight: 100, minHeight: 50}" input-class="textarea" border="{{ false }}" bind:change="msgChange" /> <van-button type="info" size="small" block bindtap="submitComment">提交評(píng)價(jià)</van-button> </van-cell-group>
效果如下:?
2.2 小程序端訂閱消息模板
其中,tmplIds 是從表 《1.2 小程序消息模板設(shè)置表》中動(dòng)態(tài)讀取的小程序模板ID集合,用戶在小程序上支付成功后,會(huì)提示微信用戶是否訂閱消息模板。
wx.requestSubscribeMessage({ tmplIds: app.globalData.miniMsgTemplateIds, success (res) { console.log('--->接受訂閱返回 :'+JSON.stringify(res)); } })
2.3? 商家端設(shè)計(jì)
商家登錄商家端后,進(jìn)入訂單評(píng)價(jià)界面。前面已介紹。
3 平臺(tái)端
平臺(tái)端可以對(duì)多個(gè)商家小程序進(jìn)行統(tǒng)一管理。包括對(duì)各個(gè)商家小程序的消息模板進(jìn)行管理設(shè)置。
平臺(tái)管理員登錄后,在授權(quán)小程序管理欄目打開(kāi)授權(quán)小程序的管理頁(yè)面。點(diǎn)操作欄的“小程序分類(lèi)及消息模板設(shè)置”圖標(biāo)
從上圖可以看出,商家小程序已選擇了 “評(píng)論回復(fù)提醒”和“支付成功通知”兩個(gè)模板消息。
可以查看具體的小程序分類(lèi)中所有可以選擇的消息模板。如下圖:
??
點(diǎn)擊“查看分類(lèi)下的消息模板”后進(jìn)入可以選擇的消息模板列表,如下圖:
小程序的模板要求比較嚴(yán)格,不是所有的消息模板可以使用,根據(jù)小程序的商家營(yíng)業(yè)范圍來(lái)界定。故要在小程序的分類(lèi)下去選擇消息模板。在上圖的操作欄中,點(diǎn)“修改”圖標(biāo),可以進(jìn)入任意一個(gè)消息模板選擇消息模板中使用的關(guān)鍵詞,如下圖:
選擇好模板的關(guān)鍵詞后點(diǎn)“確定”按鈕進(jìn)行保存, 這樣就保存了商家小程序與消息模板的關(guān)聯(lián)關(guān)系。,這樣消息模板就在平臺(tái)端配置好了。
商家的小程序在用戶觸發(fā)相關(guān)的動(dòng)作后就用平臺(tái)自動(dòng)就會(huì)向用戶發(fā)送小程序模板消息。
參考代碼如下:
?平臺(tái)向微信用戶發(fā)送模板消息(服務(wù)通知消息)是異步的, 下面僅給出關(guān)鍵邏輯。
public void handleSQSOrderCommentReply( JSONObject body) throws Exception { Long id = body.getLong("id"); Optional<OrderComment> ocOp = orderCommentRepository.findById(id); if (ocOp == null || !ocOp.isPresent()) { log.error("評(píng)論記錄不存在{}", id); return ; } OrderComment oc = ocOp.get(); Optional<Order> orderOp = orderRepository.findById(oc.getOrder_id()); if ( orderOp == null || !orderOp.isPresent()) { log.error("評(píng)論記錄不存在{}", id); return ; } Order order = orderOp.get(); OrderCommentReply reply = new OrderCommentReply(); reply.setReply_msg(oc.getReply_msg()); reply.setReply_time(oc.getReply_time()); reply.setMsg(oc.getMsg()); JSONObject bizData = MiniMsgUtil.packageBizData(MiniMsgTypeEnum.comment_reply.getValue(), reply, OrderCommentReply.class); /* { * msg_type: XX , * component_appid: XX, * authorizer_appid: XX, * template_id: XX, * touser: XX, * data: JSON , //業(yè)務(wù)方的對(duì)象 * miniprogram_state: "formal", * lang: "zh_CN", page: /pages/orderdetail/orderdetail?order_status={{order.order_status}}&id={{order.id}}" } */ JSONObject reqBody = new JSONObject(); reqBody.put("msg_type", MiniMsgTypeEnum.comment_reply.getValue()); reqBody.put("component_appid", platAppId); reqBody.put("authorizer_appid", order.getAppid()); reqBody.put("touser", order.getMember_id()); reqBody.put("miniprogram_state", "formal"); reqBody.put("lang", "zh_CN"); reqBody.put("page", "/pages/htabs/tabs?appid="+order.getAppid()+"&shopid="+order.getShopid()); log.info("---> component_app_id {} mini_appid {} ",platAppId, order.getAppid()); MiniMsgSet set = miniMsgSetRepository.findMiniMsgSetByBusinessType(platAppId,order.getAppid(), MiniMsgTypeEnum.comment_reply.getValue()); if (set == null) { log.error("未配置消息模板"); return ; } reqBody.put("template_id", set.getMsg_template_id()); wechatMiniTempMsgSendService.sendTemplateMsg(reqBody, bizData); } public void handleSQSBuySuccess( JSONObject body) throws Exception { Long order_id = body.getLong("order_id"); Optional<Order> orderOp = orderRepository.findById(order_id); if ( orderOp == null || !orderOp.isPresent()) { log.error("購(gòu)買(mǎi)記錄不存在{}", order_id); return ; } Order order = orderOp.get(); BuySuccess buy = new BuySuccess(); buy.setFinish_time(order.getFinish_time()); buy.setOrder_no(WechatTool.getOrderNo(order.getOrder_no())); buy.setProduct_name(order.getGoods_brief()); buy.setTotal_fee(String.valueOf(order.getTotal_fee())); JSONObject bizData = MiniMsgUtil.packageBizData(MiniMsgTypeEnum.buy_success.getValue(),buy, BuySuccess.class); log.info("--->發(fā)送信息業(yè)務(wù)JSON {}", bizData); log.info("---> component_appid {} miniId {}",order.getPlatform_appid(),order.getAppid() ); MiniMsgSet set = miniMsgSetRepository.findMiniMsgSetByBusinessType(order.getAppid(), MiniMsgTypeEnum.buy_success.getValue()); if (set == null) { log.error("未配置消息模板"); return ; } /* { * msg_type: XX , * component_appid: XX, * authorizer_appid: XX, * template_id: XX, * touser: XX, * data: JSON , //業(yè)務(wù)方的對(duì)象 * miniprogram_state: "formal", * lang: "zh_CN" } */ JSONObject reqBody = new JSONObject(); reqBody.put("msg_type", MiniMsgTypeEnum.buy_success.getValue()); reqBody.put("component_appid", platAppId); reqBody.put("authorizer_appid", order.getAppid()); reqBody.put("touser", order.getMember_id()); reqBody.put("miniprogram_state", "formal"); reqBody.put("lang", "zh_CN"); reqBody.put("template_id", set.getMsg_template_id()); reqBody.put("page", "/pages/htabs/tabs?appid="+order.getAppid()+"&shopid="+order.getShopid()); wechatMiniTempMsgSendService.sendTemplateMsg(reqBody, bizData); }
第三方平臺(tái)發(fā)送微信小程序消息的通用邏輯:
/** * 通用發(fā)送小程序模板消息 * @param body: 公共的部分協(xié)議 * * { * msg_type: XX , * omponent_appid: XX, * authorizer_appid: XX, * template_id: XX, * touser: XX, * data: JSON , //業(yè)務(wù)方的對(duì)象 * miniprogram_state: "formal", * lang: "zh_CN" * * } * @param bizData: 業(yè)務(wù)部分協(xié)議 * @return * @throws Exception * @ MiniMsgTypeEnum */ public void sendTemplateMsg(JSONObject body , JSONObject bizData) throws Exception { String msg_type = body.getString("msg_type"); if (StringUtils.isEmpty(msg_type)) { throw new Exception("消息類(lèi)型必傳"); } if (!MiniMsgTypeEnum.isValid(msg_type)) { throw new Exception("消息類(lèi)型不合法"); } String component_appid = body.getString("component_appid"); String authorizer_appid = body.getString("authorizer_appid"); PlatformGrant grant = getApiToken(component_appid, authorizer_appid); String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + grant.getAuthorizer_access_token(); body.remove("msg_type"); body.remove("component_appid"); body.remove("authorizer_appid"); log.info("--->發(fā)送模板消息 body {}", body); // body {touser=ojM8n5G69FSxiF8Cu1aBefp_3c04, miniprogram_state=formal, template_id=FNyV8MnOhDZ9KCQ8QWBy2KMZ2i5oj3n0auwrYf-4cV4, lang=zh_CN} body.put("data", bizData ); log.info("--->發(fā)送模板消息完整業(yè)務(wù)協(xié)議 body {}", body); // body {touser=ojM8n5G69FSxiF8Cu1aBefp_3c04, miniprogram_state=formal, template_id=FNyV8MnOhDZ9KCQ8QWBy2KMZ2i5oj3n0auwrYf-4cV4, lang=zh_CN} String response = doPostStr(url, body); log.info("----> 發(fā)送模板消息返回 response {}", response); JSONObject res = JSONObject.parseObject(response); Integer status = res.getInteger("errcode"); if (status != null && status.intValue() == 0) { log.info("-->>模板消息成功發(fā)送<<-----"); } else { throw new Exception(res.getString("errmsg")); } }
詳細(xì)的設(shè)計(jì)請(qǐng)參見(jiàn):
https://github.com/alanjiang/mini-wechat-doc
也可參考這篇文章文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-457757.html
小程序消息訂閱和回復(fù)新功能上線文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-457757.html
到了這里,關(guān)于微信小程序消息模板設(shè)計(jì)及實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!