微信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 相关文章推荐
javascript 实用的文字链提示框效果
Jun 30 Javascript
js改变文章字体大小的实例代码
Nov 27 Javascript
JavaScript事件委托用法分析
Jan 24 Javascript
javascript鼠标滑动评分控件完整实例
May 13 Javascript
AngularJS基础教程之简单介绍
Sep 27 Javascript
jQuery Mobile 触摸事件实例
Jun 04 Javascript
使用jQuery5分钟快速搞定双色表格的简单实例
Aug 08 Javascript
onmouseover事件和onmouseout事件全面理解
Aug 15 Javascript
AngularJS实现使用路由切换视图的方法
Jan 24 Javascript
jquery+css实现侧边导航栏效果
Jun 12 jQuery
Angular.js组件之input mask对input输入进行格式化详解
Jul 10 Javascript
使用node.js对音视频文件加密的实例代码
Aug 30 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学习 计数器实例代码
2008/06/15 PHP
php中smarty变量修饰用法实例分析
2015/06/11 PHP
PHP全局使用Laravel辅助函数dd
2019/12/26 PHP
document.all与WEB标准
2020/05/13 Javascript
jQuery动态地获取系统时间实现代码
2013/05/24 Javascript
cookie.js 加载顺序问题怎么才有效
2013/07/31 Javascript
关于onchange事件在IE和FF下的表现及解决方法
2014/03/08 Javascript
实现高性能JavaScript之执行与加载
2016/01/30 Javascript
jQuery+Pdo编写login登陆界面
2016/08/01 Javascript
Angularjs中三种数据的绑定策略(“@”,“=”,“&amp;”)
2016/12/23 Javascript
vue实现一个移动端屏蔽滑动的遮罩层实例
2017/06/08 Javascript
详解Angular4中路由Router类的跳转navigate
2017/06/09 Javascript
使用Vue自定义指令实现Select组件
2018/05/24 Javascript
Vue实现textarea固定输入行数与添加下划线样式的思路详解
2018/06/28 Javascript
仿ElementUI实现一个Form表单的实现代码
2019/04/23 Javascript
node实现socket链接与GPRS进行通信的方法
2019/05/20 Javascript
ES2020 已定稿,真实场景案例分析
2020/05/25 Javascript
JavaScript React如何修改默认端口号方法详解
2020/07/28 Javascript
Javascript基于OOP实实现探测器功能代码实例
2020/08/26 Javascript
npm ci命令的基本使用方法
2020/09/20 Javascript
vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能
2020/11/16 Javascript
一行JavaScript代码如何实现瀑布流布局
2020/12/11 Javascript
Python写的创建文件夹自定义函数mkdir()
2014/08/25 Python
Python+tkinter模拟“记住我”自动登录实例代码
2018/01/16 Python
Python深度优先算法生成迷宫
2018/01/22 Python
Python读取视频的两种方法(imageio和cv2)
2018/04/15 Python
python 用下标截取字符串的实例
2018/12/25 Python
解决Pytorch自定义层出现多Variable共享内存错误问题
2020/06/28 Python
Python爬虫之Selenium多窗口切换的实现
2020/12/04 Python
HTML5实现的图片无限加载的瀑布流效果另带边框圆角阴影
2014/03/07 HTML / CSS
异步传递消息系统的作用
2016/05/01 面试题
说好普通话圆梦你我他演讲稿
2014/09/21 职场文书
可怜妈妈观后感
2015/06/09 职场文书
运动员入场前导词
2015/07/20 职场文书
工作会议简报
2015/07/20 职场文书
Python实现位图分割的效果
2021/11/20 Python