如何用开发者账号开通权限以及配置路径等都是后端实现的,我这里主要讲前端要做的工作
首先是登录页,原先已经有输入账号和密码的常规登录模式,现在加一个微信的图标,点击后切换为登录页,效果如下
一、因为是在一个页面上切换,所以原登录的模块和微信扫码页用变量控制切换,重点看微信扫码,
<template>
<div class="mainWrapper">
<div v-show="passwordLoginFlag" class="main">
(正常登录的逻辑,此处省略。。。。。)
<a-row class="user-layout-login wxlogin">
<a-col :span="10">社交账号登录</a-col>
<a-col :span="8" @click="getqrcode()">
<img src="@/assets/icons/icon_wx.png" alt="" /><span class="wxpay">微信</span>
</a-col>
</a-row>
</div>
<div v-show="wxLoginFlag">
<div class="wx_dialog_toiast">
<div class="wx_dialog_dl">微信登录</div>
<div id="qrcode" class="qr-code"></div>
<div class="wx_dialog_sm">请使用微信扫描二维码登录"xxx"</div>
<div class="wx_dialog_success" v-if="successFlag">登录成功</div>
</div>
</div>
<wx-login-modules ref="wxLoginModules" />
</div>
</template>
(备注:新建这篇文章的时候是早上,一直到下午四点多我才解决了一个问题然后重新回来编辑,这个问题会在文章中体现,只想说真的是气到无语的一个小错,耽误了我四五个小时,也是提醒大家一定要注意细节!!)
1、安装
控制台--npm install qrcodejs2 --save
页面引入--import QRCode from 'qrcodejs2
2、先有个容器承载二维码,其他的都是样式,
<div id="qrcode" class="qr-code"></div>
3、点击微信调用方法,调接口res.data是后端设置好的二维码地址,其实就是微信文档上要求的格式,如下图
import {
getWxappid, getWeixinlogin } from '@/api/login.js'
import {
mapState } from 'vuex'
data() {
return {
form: this.$form.createForm(this),
psdVisible: false,
state: {
time: 60,
loginBtn: false,
},
passwordLoginFlag: true,
wxLoginFlag: false,
successFlag: false,
settimer: 150,
}
},
computed: {
...mapState({
token: (state) => state.user.token,
}),
},
getqrcode() {
this.passwordLoginFlag= false//控制密码登录页面隐藏
this.wxLoginFlag= true//控制微信扫码页面显示
getWxappid().then((res) => {
//获取二维码的接口
let qrcode = new QRCode('qrcode', {
width: 190,
height: 190,
text: res.data, // 二维码地址
colorDark: '#000',
colorLight: '#fff',
})
getWeixinlogin().then((res) => {
//扫码后登录的接口
=>authorization_flag字段有三个状态,-1未响应要轮循调用接口不断刷新二维码,0登录成功直接跳转,1登录失败跳到短信验证页去绑定手机号
if (res && res.code == 0) {
if (res.authorization_flag == -1) {
const vm = this
let timer = setInterval(function () {
//设定时器开始循环
vm.settimer--
vm.recirleLogin(timer)//重复调用接口
if (vm.settimer == 0) {
clearInterval(timer)
vm.settimer = 150
}
}, 2000)
} else if (res.authorization_flag == 0) {
//字段为0的时候,后端会返回token,代表登录成功,可以直接跳到登录后的首页,所以一定要有token
this.successFlag = true
this.$ls.set('Access-Token', res.data.token, 12 * 60 * 60 * 1000)//保存token第一步,存到localstroage中,项目里使用了vue.ls插件封装了一下localstorage,我在最下面延申了一下,可以看看
this.$store.commit('SET_TOKEN', res.data.token)//保存token第二步,保存到vuex中,保存token一般都是本地存储+vuex双存
this.$router.replace({
name: 'portal' })//跳到登录后的首页
} else {
//字段为1代表未绑定,跳到绑定手机页
this.successFlag = true
this.$router.push({
name: 'wx-bingingtel' })
}
} else {
//如果状态码不是0,代表出现了错误,提示一下错误,重新调一下接口
this.$message.error(res.msg)
this.qrcode()
}
})
})
},
recirleLogin(timer) {
这里是当状态为0的时候,定时器调用接口走这里,代表用户一直没有扫码。如果用户扫码了就会走1或者0里面的代码,逻辑和上面是一样的,我有点懒,应该封装一下,重复调用的。
getWeixinlogin().then((res) => {
if (res.authorization_flag == 1) {
this.successFlag = true
this.wxLoginFlag= false
clearInterval(timer)
this.$router.push({
name: 'wx-bingingtel' })
} else if (res.authorization_flag == 0) {
this.successFlag = true
clearInterval(timer)
this.$ls.set('Access-Token', res.data.token, 12 * 60 * 60 * 1000)//今天花四五个小时才解决的问题就是这个token,明明获取到了,但是登录后一直没有用户信息。原因在于我写的是Access_Token或ACCESS_TOKEN,这就是要注意的细节之处,为了这个花这么久,真不值啊。。。。
this.$store.commit('SET_TOKEN', res.data.token)
this.$router.replace({
name: 'portal' })
}
})
},
处理token
在store文件夹下新建a.js文件
export const ACCESS_TOKEN = 'Access-Token' //还有其他导出,和本文无关,所以只重点突出token的过程
在vuex文件夹的modules文件夹中新建b.js
import Vue from 'vue'
import {
ACCESS_TOKEN } from '@/store/a.js'
const user = {
state: {
token: '',
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
},
actions: {
}
export default user
form表单验证的代码就不贴了,太多了。主要贴一下获取验证码的方法和登录的方法
<a-button
class="getCaptcha"
type="primary"
:disabled="state.smsSendBtnDisable || state.smsSendBtn"
@click.stop.prevent="getCaptcha"
v-text="(!state.smsSendBtn && '获取验证码') || state.time + ' s'"
/>
<a-button
size="large"
type="primary"
htmlType="submit"
class="login-button"
:loading="submitDisabel"
:disabled="submitDisabel"
>
登录
</a-button>
import {
mapActions } from 'vuex'
data() {
return {
isLoginError: false,
formLayout: 'horizontal',
form: this.$form.createForm(this),
state: {
time: 60,
smsSendBtnDisable: true,
smsSendBtn: false,
passwordIsVisible: false,
passwordLevel: 0,
passwordLevelChecked: false,
percent: 10,
progressColor: '#FF0000',
},
submitDisabel: false,
}
// 获取验证码
getCaptcha(e) {
e.preventDefault()
const {
form: {
validateFields },
state,
$notification,
} = this
validateFields(['mobile'], {
force: true }, (err, values) => {
if (!err) {
state.smsSendBtn = true
const interval = window.setInterval(() => {
//设置定时器,点击获取验证码开始倒计时60秒并置灰按钮
if (state.time-- <= 0) {
state.time = 60
state.smsSendBtn = false
window.clearInterval(interval)
}
}, 1000)
getSmsCaptchaTop({
phoneNumber: values.mobile })
.then((res) => {
if (res && res.code == 0) {
$notification['success']({
message: '提示',
description: res.msg,
duration: 5,
})
} else {
$notification['warning']({
message: '提示',
description: res.msg,
duration: 5,
})
}
})
.catch((err) => {
clearInterval(interval)
state.time = 60
state.smsSendBtn = false
this.requestFailed(err)
})
}
})
},
requestFailed(err) {
this.$notification['error']({
message: '错误',
description: ((err.response || {
}).data || {
}).message || err.msg || '请求出现错误,请稍后再试',
duration: 4,
})
},
...mapActions(['wxLogin']),
handleSubmit(e) {
e.preventDefault()
const {
form: {
validateFields },
state,
wxLogin,
$message,
$router,
} = this
validateFields({
force: true }, (err, values) => {
if (!err) {
state.passwordLevelChecked = false
this.submitDisabel = true
wxLogin({
loginName: values.mobile,
agreementReadFlag: values.agree ? 1 : 0,
verifyCode: values.captcha,
})
.then((res) => this.loginSuccess(res) )
.catch((err) => {
this.submitDisabel = false
this.requestFailed(err)
}).finally(()=>{
setTimeout(()=>{
state.loginBtn = false
},600)
})
}
})
},
loginSuccess(res) {
if (res.code === 0) {
this.$router.replace({
name: 'portal' }, () => {
this.$notification.success({
message: '欢迎',
})
})
// this.isLoginError = false
} else {
this.requestFailed(res)
}
},
注意:wxLogin方法是封装在vuex的b.js文件中的,正常引入接口,然后在antion中定义方法
import {
getWxbind } from '@/api/login'
actions: {
// 微信登录
wxLogin({
commit }, userInfo) {
return new Promise((resolve, reject) => {
getWxbind(userInfo)
.then(response => {
const result = response
Vue.ls.set(ACCESS_TOKEN, result.data.token, 12 * 60 * 60 * 1000)//注意这里是ACCESS_TOKEN
commit('SET_TOKEN', result.data.token)
resolve(response)
})
.catch(error => {
reject(error)
})
})
},
}
vue-ls插件延申点:
npm install vue-ls --save
main.js中:
import VueStorage from 'vue-ls'
新建new.js中写入以下代码,然后引入到vuex的js文件中
export default {
primaryColor: '#48B8FF', // primary color of ant design
navTheme: 'dark', // theme for nav menu
layout: 'sidemenu', // nav menu position: sidemenu or topmenu
contentWidth: 'Fixed', // layout of content: Fluid or Fixed, only works when layout is topmenu
fixedHeader: false, // sticky header
fixSiderbar: true, // sticky siderbar
autoHideHeader: false, // auto hide header
colorWeak: false,
multiTab: false,
storageOptions: {
namespace: 'pro__', // key prefix
name: 'ls', // name variable Vue.[ls] or this.[$ls],
storage: 'local' // storage name session, local, memory
}
}