微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡)


Posted in Javascript onJuly 25, 2019

需求:点击我们公司的微信公众号,从菜单栏中进入会员中心,如果是新会员则需绑定注册,注册完跳转到用户中心页面,然后给用户发会员卡,如果是老会员,如果以前没有的会员卡的,发一张会员卡给他,如果有,则不做任何处理。
实现:我的思路是这样的,进入会员中心,调用微信API接口,判断用户是否领过卡,若没有领取,则调用微信JS-JDK的addCard()接口。具体实现过程如下(用C#实现):

1创建会员卡

1) 先打开微信开发者文档,先调用创建会员卡接口,在文档的4.1 创建会员卡接口,直接用postman,详情见文档。

微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡)

创建的时候要特别注意”use_custom_code”: false,”bind_openid“:false两个字段

微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡) 

第一个为是否自定义code,第二个是否绑定openid,这个很重要,很重要,很重要!!!因为后面调用JS-JDK的addCard接口所需要的签名会根据这两个的值决定是否加入openid和code进行签名的生成(被坑了很久)。后面会详细说明这个签名,先一步步来,记住这两个参数一定要注意。按照这个文档说明,创建会员卡应该没有什么问题,对了, “sku”: { “quantity”: 50000000 }这个是库存,要添加一点库存。

2调用微信JS-SDK

1)引入微信js

<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

2)通过config接口注入权限验证配置

<script>
  $(function () {
  //判断是否已经领取会员卡
    $.ajax({
        url: '/User/ExitCard',
        type: 'GET',
        success: function (data) {
         if (data.Status == 1) 
         //1代表没有存在卡,0代表存在卡
            wxAddCard();
        }
      });
  }

 //微信添加卡券
    function wxAddCard() {

       //微信sdk config
      wx.config({
        debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: '', // 必填,公众号的唯一标识
        timestamp: '', // 必填,生成签名的时间戳
        nonceStr: '', // 必填,生成签名的随机串
        signature: '',// 必填,签名,见附录1
        jsApiList: ['onMenuShareTimeline',
          'onMenuShareAppMessage',
          'onMenuShareQQ',
          'onMenuShareWeibo',
          'onMenuShareQZone',
          'startRecord',
          'stopRecord',
          'onVoiceRecordEnd',
          'playVoice',
          'pauseVoice',
          'stopVoice',
          'onVoicePlayEnd',
          'uploadVoice',
          'downloadVoice',
          'chooseImage',
          'previewImage',
          'uploadImage',
          'downloadImage',
          'translateVoice',
          'getNetworkType',
          'openLocation',
          'getLocation',
          'hideOptionMenu',
          'showOptionMenu',
          'hideMenuItems',
          'showMenuItems',
          'hideAllNonBaseMenuItem',
          'showAllNonBaseMenuItem',
          'closeWindow',
          'scanQRCode',
          'chooseWXPay',
          'openProductSpecificView',
          'addCard',
          'chooseCard',
          'openCard'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
      });

        wx.ready(function () {
          wx.addCard({
            cardList: [{
              cardId: '',
              cardExt: '{"code":"","openid": "", "timestamp": "","nonce_str": "", "signature": ""}'
            }],
            success: function (res) {
              $.ajax({
                url: '/User/ActiveCard',
                type: 'GET',
                success: function (data) {
                  if (data.Status == 0)
                    alert("成功激活");
                }
              });
            },
            cancel: function (res) {
              alert(JSON.stringify(res))
            }
          });

        });

    }
 </script>

我这里是进入页面就调取接口看是否已经领卡,没有领卡,则调用微信接口,用户点击领取,然后调取激活接口,将会员卡激活,下面讲述签名的生成。

3)签名的配置

上一小节中的wx.config中appid为公众号的唯一标识,自己填自身微信公众号的,timestamp,nonceStr,signature三个签名其实就是为了加密吧。(以下代码都是用C#实现)
timestamp的生成:

/// <summary>
    /// 创建时间戳       ///本代码来自开源微信SDK项目:https://github.com/night-king/weixinSDK
    /// </summary>
    /// <returns></returns>
    public long CreatenTimestamp()
    {
      return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
    }

nonceStr的生成:

/// <summary>
    /// 创建随机字符串     ///本代码来自开源微信SDK项目:https://github.com/night-king/weixinSDK
    /// </summary>
    /// <returns></returns>
    public string CreatenNonce_str()
    {
      Random r = new Random();
      var sb = new StringBuilder();
      var length = strs.Length;
      for (int i = 0; i < 15; i++)
      {
        sb.Append(strs[r.Next(length - 1)]);
      }
      return sb.ToString();
    }

signature生成(这里是wx.config中的signature生成),signature签名的生成是由jsapi_ticket,noncestr,timestamp,url四个参数,先使用ASCII算法排序(其实就是看他们的字母顺序 j,n,t,u排序,如果首字母相等看第二位,以此类推),先等键进行排序,然后拼接例如jsapi_ticket=xxx&noncestr=&….我这里已经自己手动排序了,所以没实现ASCCII排序,排序完之后,使用sha1加密,代码如下:

/// <summary>
    /// 签名算法    ///本代码来自开源微信SDK项目:https://github.com/night-king/weixinSDK
    /// </summary>
    /// <param name="jsapi_ticket">jsapi_ticket</param>
    /// <param name="noncestr">随机字符串(必须与wx.config中的nonceStr相同)</param>
    /// <param name="timestamp">时间戳(必须与wx.config中的timestamp相同)</param>
    /// <param name="url">当前网页的URL,不包含#及其后面部分(必须是调用JS接口页面的完整URL)</param>
    /// <returns></returns>
    public string GetSignature(string jsapi_ticket, string noncestr, long timestamp, string url)
    {
      var string1Builder = new StringBuilder();
      string1Builder.Append("jsapi_ticket=").Append(jsapi_ticket).Append("&")
             .Append("noncestr=").Append(noncestr).Append("&")
             .Append("timestamp=").Append(timestamp).Append("&")
             .Append("url=").Append(url.IndexOf("#") >= 0 ? url.Substring(0, url.IndexOf("#")) : url);
      return ShaEncrypt.SHA1Encrypt(string1Builder.ToString()).ToLower();
    }
public static string SHA1Encrypt(string data)
    {
      //也给不了全部的代码,只需知道拼接后sha1加密 网上可以找到
      var hash = SHA1.Create();
      var encoder = new System.Text.ASCIIEncoding();
      var combined = encoder.GetBytes(data);
      var result = hash.ComputeHash(combined);

      StringBuilder strbul = new StringBuilder(40);
      for (int i = 0; i < result.Length; i++)
      {
        strbul.Append(result[i].ToString("x2"));//加密结果"x2"结果为32位,"x3"结果为48位,"x4"结果为64位

      }
      return strbul.ToString();
    }

返回wx.config所需要的四个参数appId,timestamp,nonceStr,signature。

没有意外的话可以成功,成功自动进入 wx.ready(function () {}中。

wx.addCard({
    cardList: [{
        cardId: '',//吧你前面创建会员卡成功返回的参数中的cardId写进去
        cardExt: '{"code":"","openid": "", "timestamp": "","nonce_str": "", "signature": ""}'
      }],
      success: function (res) {
        $.ajax({
          url: '/User/ActiveCard',
          type: 'GET',
          success: function (data) {
            if (data.Status == 0)
              alert("成功激活");
          }
        });
      },
      cancel: function (res) {
        alert(JSON.stringify(res))
      }
    });

cardExt的signature签名生成由你创建会员卡的时候设置的”use_custom_code”: false,”bind_openid“:false决定,当两个为false时,则吧 paramList.Add(code);paramList.Add(openId);注释掉,哪个为fasle,哪个就不要。
下面代码的api_ticket与上面的jsapi_ticket完全不同,不是同一个东西,我会最最下面放出他们获取的方法

//意思就是这里有几个参数,那么对应的上面的 paramList.Add();就要添加几个
//而这里的code和openid的填写与否取决与创建会员卡是填写的两个字段,上面已经提及
 cardExt: '{"code":"","openid": "", "timestamp": "","nonce_str": "", "signature": ""}'

意思就是这里有几个参数,那么对应的上面的 paramList.Add();就要添加几个,而这里的code和openid的填写与否取决与创建会员卡是填写的两个字段,上面已经提及


微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡)

3.下面贴上面后台接口主要的代码

1)/User/ExitCard(post微信接口,然后根据返回消息判断是否已经领取卡,领取则为true,未领取则为false)

public bool ExitCard(string openId, string token,string code, string cardId)//token为access_token code为自定义code号
//code我这里是自定义的会员卡号
// cardId为创建会员卡时微信返回的cardId
   {

   var data = new Hashtable();
   data.Add("openid", openId);
   data.Add("card_id", cardId);
   var res = HttpHelper.HttpComm(
   string.Format("https://api.weixin.qq.com/card/user/getcardlist?access_token={0}", token),
     "POST",
     JSONHelper.ToJson(data));
   var resObj = JSONHelper.FromJsonToAnonymousType(res,
     new
     {
       error_code = 0,
       errmsg = "ok",
       has_share_card = false,
       card_list = Enumerable.Repeat(new { card_id = string.Empty, code = string.Empty }, 1).ToList()
     });
   //var resObj = JSONHelper.FromJsonTo<Dictionary<string, object>>(res);
   //object info = new object();
   //var str = resObj.TryGetValue("card_list", out info);
   if (resObj.card_list.Count == 0 || resObj.card_list == null)
     return false;
   var temp = false;
   for (var i = 0; i < resObj.card_list.Count; i++)
   {
     if (resObj.card_list[i].code == code)
     {
       temp = true;
       break;
     }
   }
   return temp;
    }

2)/User/ActiveCard(激活会员卡)

//激活会员卡
    public Boolean ActiveCard(string accessToken,string bonus,string cardNo,string cardId)
    //bonus为用户积分 cardNo 卡号 cardId卡ID
    {

      var data = new Hashtable();
      data.Add("init_bonus", bonus);
      data.Add("membership_number", cardNo);
      data.Add("code", cardNo);//上面跟这个设置相同,自定义code放在微信会员卡卡上面
      data.Add("card_id", cardId);
      var res = HttpHelper.HttpComm(
      string.Format("https://api.weixin.qq.com/card/membercard/activate?access_token={0}", accessToken),
        "POST",
        JSONHelper.ToJson(data));
      var resObj = JSONHelper.FromJsonToAnonymousType(res,new { errcode = "0", errmsg = "ok" });
      if (resObj.errcode == "0")
        return true;//激活成功
      return false;
    }

上面的HttpHelper.HttpComm只是一种自己封装定义的http请求的工具类,

自己去实现发送post请求即可,就不贴出来了。

4)总结与心得

总体流程大概就是如上,我觉得已经够详细了,写这篇博客的理由就是网上关于微信这一块的知识有,但是没有很详细的,让刚接触的人不知道如何下手,虽说看文档可以看懂,但是微信官方文档有很多坑,往往在文档中一个小小的细节就让人搞个大半天,而且报的错误都比较笼统,所以就打算自己写一份比较详细的,一个呢自己总结一下经验,有助于自身成长,另一个为后来人铺路,让他们少走点弯路,往后有机会接微信其他接口,会吧流程继续贴出来,以供参考。

获取api_ticket的微信接口:这里写链接内容

也就是在下图目录下的13.1,当然也可以在第二张图上找到,都是一样的

微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡) 

微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡)

获取jsapi_ticket的微信接口在附录一,也就是目录下的16节

这里写链接内容

微信JS-SDK实现微信会员卡功能(给用户微信卡包里发送会员卡)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery 学习技巧总结
May 21 Javascript
IE与FireFox中的childNodes区别
Oct 20 Javascript
Extjs中TabPane如何嵌套在其他网页中实现思路及代码
Jan 27 Javascript
jquery实现的代替传统checkbox样式插件
Jun 19 Javascript
jQuery实现自动与手动切换的滚动新闻特效代码分享
Aug 27 Javascript
跟我学习javascript的函数调用和构造函数调用
Nov 16 Javascript
DIV随滚动条滚动而滚动的实现代码【推荐】
Apr 12 Javascript
Bootstrap modal 多弹窗之叠加引起的滚动条遮罩阴影问题
Feb 27 Javascript
Node.js 异步异常的处理与domain模块解析
May 10 Javascript
node错误处理与日志记录的实现
Dec 24 Javascript
快速解决element的autofocus失效问题
Sep 08 Javascript
Vue 401配合Vuex防止多次弹框的案例
Nov 11 Javascript
微信小程序实现收货地址左滑删除
Nov 18 #Javascript
jquery-ui 进度条功能示例【测试可用】
Jul 25 #jQuery
微信小程序实现左滑动删除效果
Mar 30 #Javascript
jquery ui 实现 tab标签功能示例【测试可用】
Jul 25 #jQuery
小程序实现左滑删除效果
Jul 25 #Javascript
微信公众号获取用户地理位置并列出附近的门店的示例代码
Jul 25 #Javascript
详解Vue.js和layui日期控件冲突问题解决办法
Jul 25 #Javascript
You might like
PHP 解决session死锁的方法
2013/06/20 PHP
php将mysql数据库整库导出生成sql文件的具体实现
2014/01/08 PHP
php实现的mongodb操作类
2015/05/28 PHP
js修改地址栏URL参数解决url参数问题
2012/12/15 Javascript
js自定义事件及事件交互原理概述(一)
2013/02/01 Javascript
对于this和$(this)的个人理解
2013/09/08 Javascript
jQuery实现鼠标单击网页文字后在文本框显示的方法
2015/05/06 Javascript
基于nodejs+express(4.x+)实现文件上传功能
2015/11/23 NodeJs
jQuery实现Table表格隔行变色及高亮显示当前选择行效果示例
2017/02/14 Javascript
如何使用Bootstrap创建表单
2017/03/29 Javascript
js实现适配不同的屏幕大小
2017/04/10 Javascript
JavaScript定时器setTimeout()和setInterval()详解
2017/08/18 Javascript
JavaScript数据结构之优先队列与循环队列实例详解
2017/10/27 Javascript
基于JavaScript实现五子棋游戏
2020/08/26 Javascript
JS计算距当前时间的时间差实例
2017/12/29 Javascript
koa2 用户注册、登录校验与加盐加密的实现方法
2019/07/22 Javascript
在layui tab控件中载入外部html页面的方法
2019/09/04 Javascript
Preload基础使用方法详解
2020/02/03 Javascript
实例讲解JavaScript 计时事件
2020/07/04 Javascript
[01:46]2020完美世界全国高校联赛秋季赛报名开启
2020/10/15 DOTA
python循环监控远程端口的方法
2015/03/14 Python
在Python中使用__slots__方法的详细教程
2015/04/28 Python
Python中查看文件名和文件路径
2017/03/31 Python
Python实现的旋转数组功能算法示例
2019/02/23 Python
YUV转为jpg图像的实现
2019/12/09 Python
keras model.fit 解决validation_spilt=num 的问题
2020/06/19 Python
Python项目实战之使用Django框架实现支付宝付款功能
2021/02/23 Python
美国真皮手袋品牌:GiGi New York
2017/03/10 全球购物
分别介绍一下Session Bean和Entity Bean
2015/03/13 面试题
Java语言程序设计测试题改错题部分
2014/07/22 面试题
运动会广播稿80字
2014/01/23 职场文书
项目合作协议书范本
2014/04/16 职场文书
html+css合并表格边框的示例代码
2021/03/31 HTML / CSS
python基础学习之生成器与文件系统知识总结
2021/05/25 Python
Pytest中skip skipif跳过用例详解
2021/06/30 Python
MySQL创建管理LIST分区
2022/04/13 MySQL