小程序登录功能开发记录

时间:2022-11-05 07:53:13


前言

这里不再记录页面样式,只分析功能

点击登录按钮之后 – 登录成功跳转首页

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.jsactions 中的 Login()

// main.vue
	store.dispatch('Login', {
			username: app.username,
			password: app.password,
			verifyCode: app.validCode,
			loginType: loginType,
			wxCode: wxCode
		}.then().catch()

执行的是 ./modules/user.jsactions 中的 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.jsactions 中的 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 ~