bug修复:退出登录后再次登录不获取用户信息;增加锁屏页面;

This commit is contained in:
ZSEN 2021-04-24 13:39:10 +08:00
parent 939daa426c
commit e116897b7e
11 changed files with 276 additions and 103 deletions

View File

@ -40,13 +40,19 @@ export default [
method: 'post',
timeout: 1000,
statusCode: 200,
response: {
response: ({body}) => {
// 响应内容
return +body.password === 123456 ? {
code: 200,
message: '登录成功',
data: {
token: '@word(50, 100)', // @word()是mockjs的语法
refresh_token: '@word(50, 100)', // refresh_token是用来重新生成token的
},
}
} : {
code: 400,
message: '密码错误请输入123456',
}
},
},
{

View File

@ -0,0 +1,46 @@
<template>
<div class="userinfo">
<template v-if="!userinfo">
<i class="el-icon-user" />
<h3>admin</h3>
</template>
<template v-else>
<img class="avatar" :src="userinfo.avatar" />
<h3>{{ userinfo.name }}</h3>
</template>
</div>
</template>
<script>
import { defineComponent } from 'vue'
import { useUserinfo } from './hooks/useUserinfo'
export default defineComponent({
setup() {
const { userinfo } = useUserinfo()
return { userinfo }
},
})
</script>
<style lang="scss" scoped>
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
i {
font-size: 48px;
color: $mainColor;
}
h3 {
font-size: 14px;
font-weight: normal;
margin: 8px 0;
}
.avatar {
width: 64px;
height: 64px;
border-radius: 50%;
}
}
</style>

View File

@ -60,22 +60,14 @@
custom-class="lock-modal"
append-to-body
>
<div class="userinfo">
<template v-if="!userinfo">
<i class="el-icon-user" />
<h3>admin</h3>
</template>
<template v-else>
<img class="avatar" :src="userinfo.avatar" />
<h3>{{ userinfo.name }}</h3>
</template>
</div>
<Avatar />
<el-form :model="lockModel" :rules="lockRules" ref="lockForm">
<el-form-item label="锁屏密码" prop="password">
<el-input
type="password"
v-model.trim="lockModel.password"
autocomplete="off"
@keyup.enter="submitForm"
></el-input>
</el-form-item>
<el-form-item>
@ -94,16 +86,18 @@
<script>
import { defineComponent, reactive, ref } from 'vue'
import { useUserinfo } from './hooks/useUserinfo'
import Avatar from '@/components/Avatar/index.vue'
import { setItem } from '@/utils/storage'
import { AesEncryption } from '@/utils/encrypt'
import { useRouter } from 'vue-router'
export default defineComponent({
components: {
Avatar,
},
setup() {
const router = useRouter()
const dialogVisible = ref(false)
const { userinfo } = useUserinfo()
const lockForm = ref(null)
const lockModel = reactive({
password: '',
@ -123,13 +117,12 @@ export default defineComponent({
// localStorage
setItem('__VEA_SCREEN_LOCKED__', pwd)
//
router.push('/lock')
router.push('/lock?redirect=' + router.currentRoute.value.fullPath)
})
}
return {
dialogVisible,
userinfo,
lockForm,
lockModel,
lockRules,
@ -145,25 +138,6 @@ export default defineComponent({
}
</style>
<style lang="scss" scoped>
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
i {
font-size: 48px;
color: $mainColor;
}
h3 {
font-size: 14px;
font-weight: normal;
margin: 8px 0;
}
.avatar {
width: 64px;
height: 64px;
border-radius: 50%;
}
}
.submit-btn {
width: 100%;
}

View File

@ -70,7 +70,7 @@
import { defineComponent } from 'vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import { useUserinfo } from './hooks/useUserinfo'
import { useUserinfo } from '@/components/Avatar/hooks/useUserinfo'
import LockModal from './LockModal.vue'
export default defineComponent({
@ -86,9 +86,7 @@ export default defineComponent({
// 退
const logout = () => {
// token
store.commit('app/clearToken')
//
store.commit('account/clearUserinfo')
store.dispatch('app/clearToken')
//
store.dispatch('tags/delAllTags')
router.push('/login')

View File

@ -1,45 +0,0 @@
/*
* ::
* :;J7, :, ::;7:
* ,ivYi, , ;LLLFS:
* :iv7Yi :7ri;j5PL
* ,:ivYLvr ,ivrrirrY2X,
* :;r@Wwz.7r: :ivu@kexianli.
* :iL7::,:::iiirii:ii;::::,,irvF7rvvLujL7ur
* ri::,:,::i:iiiiiii:i:irrv177JX7rYXqZEkvv17
* ;i:, , ::::iirrririi:i:::iiir2XXvii;L8OGJr71i
* :,, ,,: ,::ir@mingyi.irii:i:::j1jri7ZBOS7ivv,
* ,::, ::rv77iiiriii:iii:i::,rvLq@huhao.Li
* ,, ,, ,:ir7ir::,:::i;ir:::i:i::rSGGYri712:
* ::: ,v7r:: ::rrv77:, ,, ,:i7rrii:::::, ir7ri7Lri
* , 2OBBOi,iiir;r:: ,irriiii::,, ,iv7Luur:
* ,, i78MBBi,:,:::,:, :7FSL: ,iriii:::i::,,:rLqXv::
* : iuMMP: :,:::,:ii;2GY7OBB0viiii:i:iii:i:::iJqL;::
* , ::::i ,,,,, ::LuBBu BBBBBErii:i:i:i:i:i:i:r77ii
* , : , ,,:::rruBZ1MBBqi, :,,,:::,::::::iiriri:
* , ,,,,::::i: @arqiao. ,:,, ,:::ii;i7:
* :, rjujLYLi ,,:::::,:::::::::,, ,:i,:,,,,,::i:iii
* :: BBBBBBBBB0, ,,::: , ,:::::: , ,,,, ,,:::::::
* i, , ,8BMMBBBBBBi ,,:,, ,,, , , , , , :,::ii::i::
* : iZMOMOMBBM2::::::::::,,,, ,,,,,,:,,,::::i:irr:i:::,
* i ,,:;u0MBMOG1L:::i:::::: ,,,::, ,,, ::::::i:i:iirii:i:i:
* : ,iuUuuXUkFu7i:iii:i:::, :,:,: ::::::::i:i:::::iirr7iiri::
* : :rk@Yizero.i:::::, ,:ii:::::::i:::::i::,::::iirrriiiri::,
* : 5BMBBBBBBSr:,::rv2kuii:::iii::,:i:,, , ,,:,:i@petermu.,
* , :r50EZ8MBBBBGOBBBZP7::::i::,:::::,: :,:,::i;rrririiii::
* :jujYY7LS0ujJL7r::,::i::,::::::::::::::iirirrrrrrr:ii:
* ,: :@kevensun.:,:,,,::::i:i:::::,,::::::iir;ii;7v77;ii;i,
* ,,, ,,:,::::::i:iiiii:i::::,, ::::iiiir@xingjief.r;7:i,
* , , ,,,:,,::::::::iiiiiiiiii:,:,:::::::::iiir;ri7vL77rrirri::
* :,, , ::::::::i:::i:::i:i::,,,,,:,::i:i:::iir;@Secbone.ii:::
*
* @Descripttion:
* @version:
* @Date: 2021-04-23 14:08:17
* @LastEditors: huzhushan@126.com
* @LastEditTime: 2021-04-23 14:08:18
* @Author: huzhushan@126.com
* @HomePage: https://huzhushan.gitee.io/vue3-element-admin
* @Github: https://github.com/huzhushan/vue3-element-admin
* @Donate: https://huzhushan.gitee.io/vue3-element-admin/donate/
*/

View File

@ -47,7 +47,7 @@ const getPageTitle = title => {
}
// 白名单里面是路由对象的name
const WhiteList = ['login', 'forbidden', 'server-error', 'not-found']
const WhiteList = ['login', 'forbidden', 'server-error', 'not-found', 'lock']
// vue-router4的路由守卫不再是通过next放行而是通过return返回true或false或者一个路由地址
router.beforeEach(async to => {
@ -65,11 +65,6 @@ router.beforeEach(async to => {
replace: true,
}
} else {
// 判断是否处于锁屏状态
if (to.name !== 'lock' && !!getItem('__VEA_SCREEN_LOCKED__')) {
return { name: 'lock', replace: true }
}
// 获取用户角色信息,根据角色判断权限
let userinfo = store.state.account.userinfo
if (!userinfo) {
@ -80,6 +75,18 @@ router.beforeEach(async to => {
return false
}
}
// 判断是否处于锁屏状态
if (to.name !== 'lock' && !!getItem('__VEA_SCREEN_LOCKED__')) {
return {
name: 'lock',
query: {
redirect: to.path,
},
replace: true,
}
}
// 如果没有权限跳转到403页面
if (
!!to.meta &&

View File

@ -48,5 +48,12 @@ export default {
state.device = device
},
},
actions: {},
actions: {
clearToken({ commit }) {
// 清除token
commit('clearToken')
// 清除用户信息
commit('account/clearUserinfo', '', { root: true })
},
},
}

View File

@ -69,7 +69,8 @@ service.interceptors.response.use(
// 校验是否有 refresh_token
const { authorization } = store.state.app
if (!authorization || !authorization.refresh_token) {
router.push('/login')
const redirect = encodeURIComponent(window.location.href)
router.push(`/login?redirect=${redirect}`)
// 代码不要往后执行了
return Promise.reject(error)
@ -97,9 +98,10 @@ service.interceptors.response.use(
} catch (err) {
// 如果获取失败,直接跳转 登录页
// console.log('请求刷新 token 失败', err)
router.push('/login')
const redirect = encodeURIComponent(window.location.href)
router.push(`/login?redirect=${redirect}`)
// 清除token
store.commit('app/clearToken')
store.dispatch('app/clearToken')
return Promise.reject(error)
}
}

View File

@ -47,9 +47,144 @@
<template>
<h1 class="title">
屏幕已锁定
<div class="unlock"><i class="el-icon-lock"></i>解锁</div>
<div class="unlock-btn" @click="handleUnlock">
<i class="el-icon-unlock"></i>解锁
</div>
</h1>
<div class="unlock-modal" v-show="showModal">
<Avatar class="userinfo-unlock" />
<el-form :model="lockModel" :rules="lockRules" ref="lockForm">
<el-form-item prop="password">
<el-input
type="password"
v-model.trim="lockModel.password"
autocomplete="off"
placeholder="请输入锁屏密码或登录密码"
@keyup.enter="submitForm"
>
<template #append>
<el-button
type="primary"
class="btn-unlock"
icon="el-icon-right"
@click="submitForm"
></el-button>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-button @click="cancel" type="text">取消</el-button>
<el-button @click="reLogin" type="text">重新登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { defineComponent, ref, reactive, getCurrentInstance } from 'vue'
import Avatar from '@/components/Avatar/index.vue'
import { getItem, removeItem } from '@/utils/storage'
import { AesEncryption } from '@/utils/encrypt'
import { useRoute, useRouter } from 'vue-router'
import { useStore } from 'vuex'
import { Login } from '@/api/login'
export default defineComponent({
components: {
Avatar,
},
setup() {
const { ctx } = getCurrentInstance()
const store = useStore()
const router = useRouter()
const route = useRoute()
const showModal = ref(false)
const lockForm = ref(null)
const lockModel = reactive({
password: '',
})
const checkPwd = async (rule, value, callback) => {
const encryption = new AesEncryption()
const cipher = getItem('__VEA_SCREEN_LOCKED__')
if (!cipher) {
return callback()
}
const pwd = encryption.decryptByAES(cipher)
if (pwd === value) {
return callback()
} else {
//
const { code } = await Login({
username: store.state.account.userinfo.name,
password: value,
})
if (+code === 200) {
return callback()
}
}
return callback(new Error(rule.message))
}
const lockRules = reactive({
password: [
{ required: true, message: '请输入锁屏密码' },
{
validator: checkPwd,
message: '密码错误',
trigger: 'none',
},
],
})
const handleUnlock = () => {
//
const { authorization } = store.state.app
if (authorization) {
showModal.value = true
//
!store.state.account.userinfo && store.dispatch('account/getUserinfo')
} else {
ctx.$message('您的账号已退出,请直接登录')
reLogin()
}
}
const submitForm = () => {
lockForm.value.validate(async valid => {
if (!valid) {
return false
}
//
removeItem('__VEA_SCREEN_LOCKED__')
router.push({ path: route.query.redirect || '/', replace: true })
})
}
const cancel = () => {
lockForm.value.resetFields()
showModal.value = false
}
const reLogin = () => {
removeItem('__VEA_SCREEN_LOCKED__')
router.push('/login?redirect=' + (route.query.redirect || '/'))
}
return {
showModal,
lockForm,
lockModel,
lockRules,
handleUnlock,
submitForm,
cancel,
reLogin,
}
},
})
</script>
<style lang="scss" scoped>
.title {
@ -59,7 +194,7 @@
margin: 0;
display: flex;
align-items: flex-end;
.unlock {
.unlock-btn {
color: #aaa;
font-size: 16px;
font-weight: normal;
@ -67,4 +202,37 @@
cursor: pointer;
}
}
.unlock-modal {
position: fixed;
z-index: 10;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(8px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
::v-deep(.el-input-group__append) {
background: $mainColor !important;
border-color: $mainColor !important;
}
.btn-unlock {
background: $mainColor !important;
color: #fff !important;
::v-deep(i) {
transform: scale(1.5);
}
}
}
.userinfo-unlock {
margin-bottom: 16px;
::v-deep(h3) {
color: #fff;
}
}
</style>

View File

@ -58,6 +58,7 @@ import {
import { Login } from '@/api/login'
import { useStore } from 'vuex'
import { useRouter, useRoute } from 'vue-router'
export default defineComponent({
name: 'login',
setup() {
@ -100,8 +101,17 @@ export default defineComponent({
message: '登录成功',
duration: 1000,
})
const targetPath = route.query.redirect
router.push(targetPath ? targetPath : '/')
const targetPath = decodeURIComponent(route.query.redirect)
if (targetPath.startsWith('http')) {
// url
window.location.href = targetPath
} else if (targetPath.startsWith('/')) {
//
router.push(targetPath)
} else {
router.push('/')
}
store.commit('app/setToken', data)
} else {
ctx.$message.error(message)