扫码功能和后端研究了好久,看了很多文章,不太符合我们的需求
还好写出来了,就把逻辑整理了一下
用的是微信扫码(公众号)

需求是这样的:点击下图微信扫码,然后出现二维码,微信扫一扫跳转到h5页面,(如果微信没有绑定过就跳转绑定表单页面,填写表单成功后显示绑定成功,同时pc端登录成功,如果绑定过就跳转登录成功,同时pc端登录成功)

第一步:
申请一个服务号,注意不是订阅号,订阅号没有授权的功能。网上很多教怎么申请的,这里就不说怎么申请的了
现在我们就拿到了appid还有域名

第二步:
点击微信的小图标,调用后端的接口得到uuid,同时开一个定时器检查uuid扫码状态,写到这里,前端的pc端逻辑就写完了(扫码确定后端会返回token)生成二维码

  1. 点击小图标获取uuid,前端拼接字符串 生成二维码
    下载依赖 npm install qrcodejs2 --save
    然后组件里引用 import QRCode from “qrcodejs2”;
  2. 同时写一个定时器检查扫码状态,后端返回是过期的话显示二维码过期,点击刷新,同时清除定时器;后端返回已经登录状态就把传给前端的token放入缓存,同时路由跳转到主页,清除定时器
  3. 这里的token就是每次axios请求头里带着去访问后端接口的令牌,如果有疑问可以去看我之前权限管理动态路由的博客

下面是我的代码

js部分

<script>
import QRCode from "qrcodejs2";
export default {
  data() {
    return {
      uuid: "",
      timer: null,
      baseUrl: process.env.VUE_APP_BASEURL,
      needUpdate: false,
      hasScan: false,
      hasSuccess: false,
    };
  },
  methods: {
    //点击刷新
    update() {
      this.$refs.qrCodeContainer.innerHTML = "";
      this.needUpdate = false;
      this.getUuid();
      this.timer = setInterval(() => {
        this.checkUuid();
      }, 1000);
    },
    //生成二维码
    bindQRCode() {
      new QRCode(this.$refs.qrCodeContainer, {
      //这里很重要,在网上看了这里都是微信重定向的地址,我们的需求实现不了,其实是后端的地址!!!!!!给后端去判断重定向
      //https://open.weixin.qq.com/connect/qrconnectappid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect  就是这一串,这里重定向的地址就是h5页面
      
        text: this.baseUrl + "/acl/wx/wxScan/?uuid=" + this.uuid,
        width: 140,
        height: 140,
        colorDark: "#333333", //二维码颜色
        colorLight: "#ffffff", //二维码背景色
        correctLevel: QRCode.CorrectLevel.L, //容错率,L/M/H
      });
    },
    //得到uuid
    getUuid() {
      this.$api.getUUID().then((res) => {
        if (res.success) {
          this.uuid = res.data.uuid;
          this.bindQRCode();
        }
      });
    },
    //检查uuid状态
    checkUuid() {
      this.$api.checkUUID({ UUID: this.uuid }).then((res) => {
        if (res.data.ret === "3") {
          clearInterval(this.timer);
          this.hasSuccess = true;
          this.$ls.set("token", res.data.token);
          if (this.$ls.get("token")) {
            //路由跳转
            this.$router.push({ name: "main" });
          }
        } else if (res.data.ret === "2") {
          clearInterval(this.timer);
          this.needUpdate = true;
        } else if (res.data.ret === "1") {
          clearInterval(this.timer);
          this.hasScan = true;
        }
      });
    },
  },
  mounted() {
    this.getUuid();
    this.timer = setInterval(() => {
      this.checkUuid();
    }, 1000);
  },
  destroyed() {
    clearInterval(this.timer);
  },
  //在页面离开时做的操作
  beforeRouteLeave(to, from, next) {
    this.$destroy();
    next();
  },
};
</script>

html部分

<h3>扫码登录</h3>
        <div class="qrcode-container-total d-f a-c j-c">
        
        <!--前端生成二维码,需要给二维码一个容器  -->
        
          <div class="qrcode-container" ref="qrCodeContainer"></div>
          <div class="qrcode-phone">
            <img src="@/assets/img/scan-phone.png" alt="" />
          </div>
        </div>
        <div class="dust d-f f-d a-c j-c" v-if="needUpdate">
          <h4>二维码已失效</h4>
          <a-button type="primary" @click="update"> 点击刷新 </a-button>
        </div>
        <div class="dust d-f f-d a-c j-c" v-if="hasScan">
          <h4>已扫描</h4>
          <h4>请在手机上确认登录</h4>
        </div>
        <div class="dust d-f f-d a-c j-c" v-if="hasSuccess">
          <h4>登录成功,跳转中…</h4>
        </div>
        <p>请使用 微信扫一扫 扫描二维码登录</p>
        <a class="ReturnLogin" @click="goLogin">返回登录</a>
      </div>

第三步:
h5页面的逻辑,这里就没什么了,就是表单验证掉接口然后tab切换
唯一要注意的是要把uuid带着传给后端

<template>
  <div>
    <div class="container-bind-wechat" v-if="bindWechat">
      <div class="title d-f j-c">
        <p>绑定手机号</p>
      </div>
      <div class="logo d-f f-d a-c">
        <div class="logo-box d-f j-c a-c">
          <img src="@/assets/img/logo.png" alt="" />
        </div>
        <p>小牛后台管理系统</p>
      </div>
      <div class="ipt">
        <a-input placeholder="请输入手机号" class="phone" v-model="phone" />
        <a-input placeholder="请输入验证码" class="code" v-model="code" />
        <div class="send-code">
          <a-divider type="vertical" />
          <a-button @click="sendVerifyCode" v-if="isSend">获取验证码</a-button>
          <a-button v-if="!isSend" disabled>{{ count }}s</a-button>
        </div>
        <div class="tooltip d-f a-c j-c" v-if="visible">手机号格式错误~</div>
        <div class="tooltip d-f a-c j-c" v-if="visibleToo">该手机号还没被注册过~</div>
        <div class="tooltip d-f a-c j-c" v-if="visibleThird">请勾选复选框~</div>
        <div class="tooltip d-f a-c j-c" v-if="visibleFifth">验证码格式错误~</div>
      </div>
      <div class="checkbox">
        <a-checkbox :checked="checkAgree" @change="handleChange"> 同意 </a-checkbox>
        <a class="login-service" href="" target="_blank"
          >《服务协议》</a
        >
        <a class="login-policy" href="" target="_blank"
          >《统一登录隐私政策》</a
        >
      </div>
      <a-button type="primary" class="login-submit" @click="bindAndLogin">
        绑定并登录
      </a-button>
    </div>
    <div class="container-bind-success" v-if="bindSuccess">
      <div class="title d-f j-c">
        <p>绑定成功</p>
      </div>
      <div class="success d-f f-d a-c">
        <div class="success-box d-f j-c a-c">
          <img src="@/assets/img/bind-success.png" alt="" />
        </div>
        <p>恭喜您微信和手机号绑定成功</p>
        <span>请使用微信扫码登录或手机号登录</span>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      phone: null,
      code: null,
      uuid: "",
      checkAgree: true,
      count: 30,
      isSend: true,
      timer: null,
      visible: false,
      visibleToo: false,
      visibleThird: false,
      visibleFifth: false,
      bindWechat: true,
      bindSuccess: false,
      bindFailure: false,
    };
  },
  methods: {
    //复选框状态改变
    handleChange(e) {
      this.checkAgree = e.target.checked;
    },
    //发送验证码
    sendVerifyCode() {
      if (this.validatePhone(this.phone)) {
        const TIME_COUNT = 60;
        if (!this.timer) {
          this.count = TIME_COUNT;
          this.isSend = false;
          //验证手机号已经注册过
          this.$api.isExist({ phone: this.phone }).then((res) => {
            // console.log(res)
            if (res.success) {
              //发送短信验证码
              this.$api
                .sendSmsCode({
                  phone: this.phone,
                  smsCodeType: 6,
                })
                .then((res) => {
                  // console.log(res)
                  return;
                });
            } else {
              this.visibleToo = true;
              this.phone = null;
              setTimeout(() => {
                this.visibleToo = false;
              }, 3000);
            }
          });
          this.timer = setInterval(() => {
            if (this.count > 0 && this.count <= TIME_COUNT) {
              this.count--;
            } else {
              this.isSend = true;
              clearInterval(this.timer);
              this.timer = null;
            }
          }, 1000);
        }
      }
    },
    validatePhone(value) {
      let phone = /^[1][3,4,5,6,7,8,9][0-9]{9}$/;
      if (!phone.test(value)) {
        this.visible = true;
        setTimeout(() => {
          this.visible = false;
        }, 3000);
        return false;
      } else {
        return true;
      }
    },
    validateCode(value) {
      let code = /^[0-9]{4}$/;
      if (!code.test(value)) {
        this.visibleFifth = true;
        setTimeout(() => {
          this.visibleFifth = false;
        }, 3000);
        return false;
      } else {
        return true;
      }
    },
    getUuid(url) {
      let num = url.indexOf("?");
      let str = url.substr(num + 1);
      let arr = str.split("&");
      let kv = [];
      arr.forEach((r) => {
        let n = r.indexOf("=");
        let k = r.substring(0, n);
        let v = r.substr(n + 1);
        let obj = {};
        obj[k] = v;
        kv.push(obj);
      });
      return kv;
    },
    //绑定并登录
    bindAndLogin() {
      if (this.validatePhone(this.phone) && this.validateCode(this.code)) {
        if (this.checkAgree) {
          this.$api
            .bindAndLogin({
              phone: this.phone,
              code: this.code,
              uuid: this.uuid,
            })
            .then((res) => {
              if (res.success) {
                this.bindWechat = false;
                this.bindSuccess = true;
              } else {
                this.bindWechat = false;
                this.bindFailure = true;
              }
            });
        } else {
          this.visibleThird = true;
          setTimeout(() => {
            this.visibleThird = false;
          }, 2000);
        }
      }
    },
  },
  created() {
    let url = location.href;
    let arr = this.getUuid(url);
    let obj = arr.find((r) => r.uuid);
    if (obj != undefined) {
      this.uuid = obj.uuid;
    }
  },
  destroyed() {
    clearInterval(this.timer);
  },
  //在页面离开时做的操作
  beforeRouteLeave(to, from, next) {
    this.$destroy();
    next();
  },
};
</script>

新手小白,写的不好,欢迎留言

Logo

前往低代码交流专区

更多推荐