微信小程序消息模板设计及实现

本文以微信小程序内置的两个模板:购买成功和评论回复提醒为例来阐述第三方微信小程序平台的设计。

小程序端

    微信用户支付成功后,微信服务通知中会收到支付成功服务提醒。见下图:

商家端

用户完成评价后,商家管理端可以查看评论。见下图:

商家进行回复:

商家回复微信小程序用户的评论后,微信用户在微信的服务通知会收到评价回复提醒,用户点开后可以查看回复的详情。

这些效果如何实现的呢? 

 1 首先介绍表设计

 1.1 服务评价及留言表设计

  这张表关键字段是订单ID(order_id)、服务评价留言(msg)、商家管理员后台回复信息(reply_msg)及商家管理员的帐号ID(admin_id) 。 一个订单服务只可被评价一次和回复一次。

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 小程序消息模板设置表

 描述商家小程序与小程序模板的关联关系。一个小程序可以设置多个消息模板。

component_appid: 微信第三方平台应用appid;

authorizer_appid: 商家小程序appid;

business_type: 业务枚举字典,如:购买成功(buy_success)和评价回复(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 前端设计

2.1 小程序端提交评价

 小程序端订单服务评价设计。 源码参考:

<van-action-sheet show="{{ commentShow }}" title="订单服务评价" 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="请输入留言"
      autosize="{maxHeight: 100, minHeight: 50}"
      input-class="textarea"
      border="{{ false }}" bind:change="msgChange"
    />

     <van-button type="info" size="small"  block bindtap="submitComment">提交评价</van-button>


  </van-cell-group>

效果如下: 

2.2 小程序端订阅消息模板

其中,tmplIds 是从表 《1.2 小程序消息模板设置表》中动态读取的小程序模板ID集合,用户在小程序上支付成功后,会提示微信用户是否订阅消息模板。

wx.requestSubscribeMessage({

         tmplIds: app.globalData.miniMsgTemplateIds,
         success (res) {
            console.log('--->接受订阅返回 :'+JSON.stringify(res));
         }
})

2.3  商家端设计

商家登录商家端后,进入订单评价界面。前面已介绍。

3 平台端

平台端可以对多个商家小程序进行统一管理。包括对各个商家小程序的消息模板进行管理设置。

平台管理员登录后,在授权小程序管理栏目打开授权小程序的管理页面。点操作栏的“小程序分类及消息模板设置”图标

从上图可以看出,商家小程序已选择了 “评论回复提醒”和“支付成功通知”两个模板消息。

可以查看具体的小程序分类中所有可以选择的消息模板。如下图:

  

点击“查看分类下的消息模板”后进入可以选择的消息模板列表,如下图:

小程序的模板要求比较严格,不是所有的消息模板可以使用,根据小程序的商家营业范围来界定。故要在小程序的分类下去选择消息模板。在上图的操作栏中,点“修改”图标,可以进入任意一个消息模板选择消息模板中使用的关键词,如下图:

选择好模板的关键词后点“确定”按钮进行保存, 这样就保存了商家小程序与消息模板的关联关系。,这样消息模板就在平台端配置好了。

商家的小程序在用户触发相关的动作后就用平台自动就会向用户发送小程序模板消息。

参考代码如下:

 平台向微信用户发送模板消息(服务通知消息)是异步的, 下面仅给出关键逻辑。

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("评论记录不存在{}", id);
        return ;
    }
    OrderComment  oc = ocOp.get();

    Optional<Order> orderOp = orderRepository.findById(oc.getOrder_id());

    if ( orderOp == null || !orderOp.isPresent()) {
        log.error("评论记录不存在{}", 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 , //业务方的对象
 *     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("购买记录不存在{}", 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("--->发送信息业务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 , //业务方的对象
 *     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);





}

第三方平台发送微信小程序消息的通用逻辑:

/**
 * 通用发送小程序模板消息
 *  @param body: 公共的部分协议
 *
 *  {
 *     msg_type: XX ,
 *     omponent_appid: XX,
 *     authorizer_appid: XX,
 *     template_id: XX,
 *     touser: XX,
 *     data: JSON , //业务方的对象
 *     miniprogram_state: "formal",
 *     lang: "zh_CN"
 *
 *  }
 * @param bizData:  业务部分协议
 * @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("消息类型必传");
    }

    if (!MiniMsgTypeEnum.isValid(msg_type)) {

        throw new Exception("消息类型不合法");
    }

    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("--->发送模板消息 body {}", body); // body {touser=ojM8n5G69FSxiF8Cu1aBefp_3c04, miniprogram_state=formal, template_id=FNyV8MnOhDZ9KCQ8QWBy2KMZ2i5oj3n0auwrYf-4cV4, lang=zh_CN}

    body.put("data", bizData );


    log.info("--->发送模板消息完整业务协议 body {}", body); // body {touser=ojM8n5G69FSxiF8Cu1aBefp_3c04, miniprogram_state=formal, template_id=FNyV8MnOhDZ9KCQ8QWBy2KMZ2i5oj3n0auwrYf-4cV4, lang=zh_CN}

    String response = doPostStr(url, body);
    log.info("----> 发送模板消息返回 response {}", response);

    JSONObject res =  JSONObject.parseObject(response);

    Integer status = res.getInteger("errcode");
    if (status != null && status.intValue() == 0) {

        log.info("-->>模板消息成功发送<<-----");
    } else {

        throw new Exception(res.getString("errmsg"));

    }


}

详细的设计请参见:

https://github.com/alanjiang/mini-wechat-doc

也可参考这篇文章

小程序消息订阅和回复新功能上线

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值