小程序登录功能开发记录
前言
这里不再记录页面样式,只分析功能
点击登录按钮之后 – 登录成功跳转首页
1. main.vue 页面点击登录按钮,执行main.vue中定义的 submit() 方法
<!--main.vue-->
<view class="button" @click="submit('1')" :disabled="disabled"><text>登录</text></view>
// main.vue
import Config from '@/core/config'
const fileUrl = Config.get('fileUrl')
import {isMobile} from '@/utils/verify'
import store from '@/store'
import * as LoginApi from '@/api/login'
import * as CaptchaApi from '@/api/captcha'
import MpWeixinMobile from './mp-weixin-mobile'
async submit(loginType) {
const app = this
if (app.username.length == 0) {
app.$u.toast('请输入账号');
return;
}
if (app.password.length == 0) {
app.$u.toast('请输入密码');
return;
}
let wxCode = ""
// #ifdef MP-WEIXIN
wxCode = await this.getCode()
// #endif
uni.setStorageSync('openId',wxCode)
console.log("开始登录")
store.dispatch('Login', {
username: app.username,
password: app.password,
verifyCode: app.validCode,
loginType: loginType,
wxCode: wxCode
})
.then(res => {
console.log("登录成功",store.getters.firstPage)
if (app.remember == true) {
uni.setStorageSync('username', app.username);
uni.setStorageSync('password', app.password);
}
setTimeout(() => {
uni.reLaunch({
url: store.getters.firstPage
})
}, 500);
})
.catch(err => {
app.$toast(err.errMsg)
.finally(() => app.isLoading = false)
},
2. 收集登录信息后, submit()中调用 store.dispatch(‘Login’, {})
登录是通过 vuex ,页面中引入的 store (import store from '@/store'
)来执行的
// @/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import {
app,
user
} from './modules'
import getters from './getters'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
app,
user
},
state: {
},
mutations: {
},
actions: {
},
getters
})
import { app, user} from './modules'
// ./modules/user.js
import {
ACCESS_TOKEN,
USER_ID,
USER_INFO,
PERMISSIONS,
ROLES,
TAB_BAR_LIST,
FIRST_PAGE,
TENANT_LIST,
CURRENT_TENANT,
} from '@/store/mutation-types'
import storage from '@/utils/storage'
import * as LoginApi from '@/api/login'
import * as UserApi from '@/api/user'
import tabBar from '@/utils/tabbar.js'
import {
hasAnyRole,
} from '@/utils/util'
// 登陆成功后执行
const loginSuccess = (context, commit, {
token,
userId,
permissions,
roles,
user
}) => {
let tabBars = tabBar[0];
// 过期时间30天
const expiryTime = 30 * 86400
// 保存tokne和userId到缓存
storage.set(USER_ID, userId, expiryTime)
storage.set(USER_INFO, user, expiryTime)
storage.set(ACCESS_TOKEN, token, expiryTime)
storage.set(PERMISSIONS, permissions, expiryTime)
storage.set(ROLES, roles, expiryTime)
// 记录到store全局变量
commit('SET_TOKEN', token)
commit('SET_USER_ID', userId)
commit('SET_USER_INFO', user)
commit('SET_PERMISSIONS', permissions)
commit('SET_ROLES', roles)
//是否为代理商
// if (hasAnyRole(roles, ['PrimaryAgent']) === true) {
if (user.userType?.value === 'AGENT') {
tabBars = tabBar[1];
}
commit('SET_TAB_BAR_LIST', tabBars)
storage.set(TAB_BAR_LIST, tabBars, expiryTime)
storage.set(FIRST_PAGE, tabBars[0].pagePath, expiryTime)
commit('SET_FIRST_PAGE', tabBars[0].pagePath)
context.dispatch('CurrentUser')
.then(res => {
if (res) {
storage.set(TENANT_LIST, res.tenants, expiryTime)
commit('SET_TENANT_LIST', res.tenants)
//todo 默认第一个后期增加租户选择
storage.set(CURRENT_TENANT, res.tenants[0], expiryTime)
commit('SET_CURRENT_TENANT', res.tenants[0])
}
})
.catch(err => {})
}
const clearStorage = (commit) => {
// 删除缓存中的tokne和userId
storage.remove(USER_ID)
storage.remove(ACCESS_TOKEN)
storage.remove(PERMISSIONS)
storage.remove(ROLES)
storage.remove(TAB_BAR_LIST)
storage.remove(FIRST_PAGE)
storage.remove(USER_INFO)
//其他页面的缓存
storage.remove('checkDeviceList')
storage.remove('user')
// 记录到store全局变量
commit('SET_TOKEN', '')
commit('SET_USER_ID', null)
commit('SET_PERMISSIONS', [])
commit('SET_ROLES', [])
commit('SET_TAB_BAR_LIST', [])
commit('SET_FIRST_PAGE', '')
commit('SET_USER_INFO', {})
}
const user = {
state: {
// 用户认证token
token: '',
// 用户ID
userId: null,
roles: [],
permissions: [],
tabBarList: [],
firstPage: '',
userInfo: {},
tenantList: [],
currentTenant: {},
},
mutations: {
SET_TOKEN: (state, value) => {
state.token = value
},
SET_USER_ID: (state, value) => {
state.userId = value
},
SET_ROLES: (state, value) => {
state.roles = value
},
SET_PERMISSIONS: (state, value) => {
state.permissions = value
},
SET_TAB_BAR_LIST: (state, value) => {
state.tabBarList = value
},
SET_FIRST_PAGE: (state, value) => {
state.firstPage = value
},
SET_USER_INFO: (state, value) => {
state.userInfo = value
},
SET_TENANT_LIST: (state, value) => {
state.tenantList = value
},
SET_CURRENT_TENANT: (state, value) => {
state.currentTenant = value
}
},
actions: {
// 账户+密码登录
Login({
commit
}, data) {
return new Promise((resolve, reject) => {
LoginApi.login(data, {
isPrompt: false,
ignoreToken: true
})
.then(response => {
const result = response.result
loginSuccess(this, commit, result)
resolve(response)
})
.catch(reject)
})
},
// 手机号和验证码登录
LoginMobile({
commit
}, data) {
return new Promise((resolve, reject) => {
LoginApi.loginSms(data, {
isPrompt: false,
ignoreToken: true
})
.then(response => {
const result = response.result
loginSuccess(this, commit, result)
resolve(response)
})
.catch(reject)
})
},
// 微信小程序一键授权登录(获取用户基本信息)
LoginMpWx({
commit
}, data) {
return new Promise((resolve, reject) => {
LoginApi.loginMpWx(data, {
isPrompt: false,
ignoreToken: true
})
.then(response => {
const result = response.result
loginSuccess(this, commit, result)
resolve(response)
})
.catch(reject)
})
},
// 微信小程序一键授权登录(授权手机号)
LoginMpWxMobile({
commit
}, data) {
return new Promise((resolve, reject) => {
LoginApi.loginMpWxMobile(data, {
isPrompt: false,
ignoreToken: true
})
.then(response => {
const result = response.result
loginSuccess(this, commit, result)
resolve(response)
})
.catch(reject)
})
},
// 退出登录
Logout({
commit
}, data) {
return new Promise((resolve, reject) => {
LoginApi.logout(data, {
isPrompt: false,
ignoreToken: true
})
.then(response => {
const store = this
const result = response.result
if (store.getters.userId != '') {
clearStorage(commit)
resolve()
}
})
.catch(reject)
})
},
Clear({
commit
}, data) {
clearStorage(commit)
},
// 获得当前用户信息
CurrentUser({
commit
}, data) {
const store = this
return new Promise((resolve, reject) => {
UserApi.info()
.then(response => {
const result = response.result
resolve(result)
})
.catch(reject)
})
}
}
}
export default user
2.1 store.dispatch(‘Login’, {}) 调用的是 ./modules/user.js
中 actions
中的 Login()
// main.vue
store.dispatch('Login', {
username: app.username,
password: app.password,
verifyCode: app.validCode,
loginType: loginType,
wxCode: wxCode
}.then().catch()
执行的是 ./modules/user.js
中 actions
中的 Login()
// ~@/store/modules/user.js
Login({
commit
}, data) {
return new Promise((resolve, reject) => {
LoginApi.login(data, {
isPrompt: false,
ignoreToken: true
})
.then(response => {
const result = response.result
loginSuccess(this, commit, result)
resolve(response)
})
.catch(reject)
})
},
2.2. 在 ./modules/user.js
中 actions
中的 Login()
中发起请求
// ~@/store/modules/user.js
LoginApi.login(data, {
isPrompt: false,
ignoreToken: true
})
.then(response => {
const result = response.result
loginSuccess(this, commit, result)
resolve(response)
})
.catch(reject)
})
2.2.1 请求是通过 import * as LoginApi from '@/api/login'
导入的
// @/api/login/index.js
import request from '@/utils/request'
// api地址
const api = {
login: 'authorize/login',
logout: 'authorize/logout',
loginSms: 'authorize/loginSms',
loginMpWx: 'authorize/loginMpWx',
loginMpWxMobile: 'authorize/loginMpWxMobile',
}
// 用户登录(手机号+验证码) *账号密码登录
export function login(data, option) {
return request.post(api.login, data, option)
}
// @/utils/request/core/request.js
// post请求
post(url = '', data = {}, options = {}) {
return this.request({
method: "POST",
data: data,
url: url,
...options
});
}
2.2.2 请求成功后调用了 loginSuccess ()
这里分析一下都干了什么
// ~@/store/modules/user.js
// 登陆成功后执行
const loginSuccess = (context, commit, {
token,
userId,
permissions,
roles,
user
}) => {
let tabBars = tabBar[0];
// 过期时间30天
const expiryTime = 30 * 86400
// 保存tokne和userId到缓存
storage.set(USER_ID, userId, expiryTime)
storage.set(USER_INFO, user, expiryTime)
storage.set(ACCESS_TOKEN, token, expiryTime)
storage.set(PERMISSIONS, permissions, expiryTime)
storage.set(ROLES, roles, expiryTime)
// 记录到store全局变量
commit('SET_TOKEN', token)
commit('SET_USER_ID', userId)
commit('SET_USER_INFO', user)
commit('SET_PERMISSIONS', permissions)
commit('SET_ROLES', roles)
//是否为代理商
// if (hasAnyRole(roles, ['PrimaryAgent']) === true) {
if (user.userType?.value === 'AGENT') {
tabBars = tabBar[1];
}
commit('SET_TAB_BAR_LIST', tabBars)
storage.set(TAB_BAR_LIST, tabBars, expiryTime)
storage.set(FIRST_PAGE, tabBars[0].pagePath, expiryTime)
commit('SET_FIRST_PAGE', tabBars[0].pagePath)
context.dispatch('CurrentUser')
.then(res => {
if (res) {
storage.set(TENANT_LIST, res.tenants, expiryTime)
commit('SET_TENANT_LIST', res.tenants)
//todo 默认第一个后期增加租户选择
storage.set(CURRENT_TENANT, res.tenants[0], expiryTime)
commit('SET_CURRENT_TENANT', res.tenants[0])
}
})
.catch(err => {})
}
3. store.dispatch(‘Login’, {})执行成功的回调
// main.vue
store.dispatch('Login', {
username: app.username,
password: app.password,
verifyCode: app.validCode,
loginType: loginType,
wxCode: wxCode
})
.then(res => {
console.log("登录成功",store.getters.firstPage)
if (app.remember == true) {
uni.setStorageSync('username', app.username);
uni.setStorageSync('password', app.password);
}
setTimeout(() => {
uni.reLaunch({
url: store.getters.firstPage
})
}, 500);
})
.catch(err => {
app.$toast(err.errMsg)
// 跳转回原页面
// if (err.result.data.isBack) {
// setTimeout(() => app.onNavigateBack(1), 2000)
// }
})
.finally(() => app.isLoading = false)
跳转到首页
uni.reLaunch : 关闭所有页面,打开到应用内的某个页面。
// main.vue
uni.reLaunch({
url: store.getters.firstPage
})
首页的 URL 是从 store 当中获取的
OVER ~