mirror of https://github.com/halo-dev/halo-admin
Support reset password.
parent
4da73491b9
commit
600f9d682e
|
@ -59,6 +59,22 @@ adminApi.refreshToken = refreshToken => {
|
|||
})
|
||||
}
|
||||
|
||||
adminApi.sendResetCode = param => {
|
||||
return service({
|
||||
url: `${baseUrl}/password/code`,
|
||||
data: param,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
adminApi.resetPassword = param => {
|
||||
return service({
|
||||
url: `${baseUrl}/password/reset`,
|
||||
data: param,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
adminApi.updateAdminAssets = () => {
|
||||
return service({
|
||||
url: `${baseUrl}/halo-admin`,
|
||||
|
|
|
@ -218,6 +218,12 @@ export const constantRouterMap = [
|
|||
meta: { title: '安装向导' },
|
||||
component: () => import('@/views/system/Installation')
|
||||
},
|
||||
{
|
||||
path: '/password/reset',
|
||||
name: 'ResetPassword',
|
||||
meta: { title: '重置密码' },
|
||||
component: () => import('@/views/user/ResetPassword')
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
name: 'NotFound',
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
import Vue from 'vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
|
||||
import {
|
||||
setDocumentTitle,
|
||||
domTitle
|
||||
} from '@/utils/domUtil'
|
||||
|
||||
import NProgress from 'nprogress' // progress bar
|
||||
import 'nprogress/nprogress.css' // progress bar style
|
||||
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
NProgress.configure({
|
||||
showSpinner: false
|
||||
}) // NProgress Configuration
|
||||
|
||||
const whiteList = ['Login', 'Install', 'NotFound'] // no redirect whitelist
|
||||
const whiteList = ['Login', 'Install', 'NotFound', 'ResetPassword'] // no redirect whitelist
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
NProgress.start()
|
||||
|
@ -16,7 +21,9 @@ router.beforeEach((to, from, next) => {
|
|||
Vue.$log.debug('Token', store.getters.token)
|
||||
if (store.getters.token) {
|
||||
if (to.name === 'Login') {
|
||||
next({ name: 'Dashboard' })
|
||||
next({
|
||||
name: 'Dashboard'
|
||||
})
|
||||
NProgress.done()
|
||||
return
|
||||
}
|
||||
|
@ -35,6 +42,11 @@ router.beforeEach((to, from, next) => {
|
|||
return
|
||||
}
|
||||
|
||||
next({ name: 'Login', query: { redirect: to.fullPath } })
|
||||
next({
|
||||
name: 'Login',
|
||||
query: {
|
||||
redirect: to.fullPath
|
||||
}
|
||||
})
|
||||
NProgress.done()
|
||||
})
|
||||
|
|
|
@ -8,7 +8,7 @@ import router from '@/router'
|
|||
import { isObject } from './util'
|
||||
|
||||
const service = axios.create({
|
||||
timeout: 5000,
|
||||
timeout: 8000,
|
||||
withCredentials: true
|
||||
})
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div class="loginLogo animated fadeInUp">
|
||||
<div class="container-wrapper">
|
||||
<div class="halo-logo animated fadeInUp">
|
||||
<span>Halo</span>
|
||||
</div>
|
||||
<div class="loginBody animated">
|
||||
<div class="animated">
|
||||
<a-form
|
||||
layout="vertical"
|
||||
@keyup.enter.native="handleLogin"
|
||||
|
@ -39,17 +39,27 @@
|
|||
/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-row>
|
||||
<a-form-item
|
||||
class="animated fadeInUp"
|
||||
:style="{'animation-delay': '0.3s'}"
|
||||
>
|
||||
<a-button
|
||||
type="primary"
|
||||
:block="true"
|
||||
@click="handleLogin"
|
||||
class="animated fadeInUp"
|
||||
:style="{'animation-delay': '0.3s'}"
|
||||
>登录</a-button>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
|
||||
<a-row>
|
||||
<router-link :to="{ name:'ResetPassword' }">
|
||||
<a
|
||||
class="tip animated fadeInRight"
|
||||
v-if="resetPasswordButton"
|
||||
href="javascript:void(0);"
|
||||
>
|
||||
找回密码
|
||||
</a>
|
||||
</router-link>
|
||||
<a
|
||||
@click="handleApiModifyModalOpen"
|
||||
class="tip animated fadeInUp"
|
||||
|
@ -92,12 +102,21 @@ export default {
|
|||
password: null,
|
||||
apiModifyVisible: false,
|
||||
defaultApiBefore: window.location.protocol + '//',
|
||||
apiUrl: window.location.host
|
||||
apiUrl: window.location.host,
|
||||
resetPasswordButton: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ defaultApiUrl: 'apiUrl' })
|
||||
},
|
||||
created() {
|
||||
const _this = this
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.keyCode === 72 && e.altKey && e.shiftKey) {
|
||||
_this.toggleHidden()
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['login', 'loadUser', 'loadOptions']),
|
||||
...mapMutations({
|
||||
|
@ -144,49 +163,53 @@ export default {
|
|||
handleApiUrlRestore() {
|
||||
this.restoreApiUrl()
|
||||
this.apiUrl = this.defaultApiUrl
|
||||
},
|
||||
toggleHidden() {
|
||||
this.resetPasswordButton = !this.resetPasswordButton
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scope>
|
||||
<style lang="less">
|
||||
body {
|
||||
height: 100%;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.container {
|
||||
background: #f7f7f7;
|
||||
|
||||
.container-wrapper {
|
||||
background: #ffffff;
|
||||
position: absolute;
|
||||
border-radius: 5px;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
margin: -160px 0 0 -160px;
|
||||
width: 320px;
|
||||
padding: 16px 32px 32px 32px;
|
||||
padding: 18px 28px 28px 28px;
|
||||
box-shadow: -4px 7px 46px 2px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.halo-logo {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
span {
|
||||
vertical-align: text-bottom;
|
||||
font-size: 38px;
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
color: #1790fe;
|
||||
background-image: linear-gradient(-20deg, #6e45e2 0%, #88d3ce 100%);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
small {
|
||||
margin-left: 5px;
|
||||
font-size: 35%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tip {
|
||||
cursor: pointer;
|
||||
margin-top: .5rem;
|
||||
margin-left: 0.5rem;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.loginLogo {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.loginLogo span {
|
||||
vertical-align: text-bottom;
|
||||
font-size: 36px;
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
color: #1790fe;
|
||||
background-image: -webkit-gradient(
|
||||
linear,
|
||||
37.219838% 34.532506%,
|
||||
36.425669% 93.178216%,
|
||||
from(#36c8f5),
|
||||
to(#1790fe),
|
||||
color-stop(0.37, #1790fe)
|
||||
);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,248 @@
|
|||
<template>
|
||||
<div class="container-wrapper">
|
||||
<div class="halo-logo animated fadeInUp">
|
||||
<span>Halo<small>重置密码</small></span>
|
||||
</div>
|
||||
<div class="animated">
|
||||
<a-form layout="vertical">
|
||||
<a-form-item
|
||||
class="animated fadeInUp"
|
||||
:style="{'animation-delay': '0.1s'}"
|
||||
>
|
||||
<a-input
|
||||
placeholder="用户名"
|
||||
v-model="resetParam.username"
|
||||
>
|
||||
<a-icon
|
||||
slot="prefix"
|
||||
type="user"
|
||||
style="color: rgba(0,0,0,.25)"
|
||||
/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="animated fadeInUp"
|
||||
:style="{'animation-delay': '0.2s'}"
|
||||
>
|
||||
<a-input
|
||||
placeholder="邮箱"
|
||||
v-model="resetParam.email"
|
||||
>
|
||||
<a-icon
|
||||
slot="prefix"
|
||||
type="mail"
|
||||
style="color: rgba(0,0,0,.25)"
|
||||
/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
class="animated fadeInUp"
|
||||
:style="{'animation-delay': '0.3s'}"
|
||||
>
|
||||
<a-input
|
||||
v-model="resetParam.code"
|
||||
type="password"
|
||||
placeholder="验证码"
|
||||
>
|
||||
<a-icon
|
||||
slot="prefix"
|
||||
type="safety-certificate"
|
||||
style="color: rgba(0,0,0,.25)"
|
||||
/>
|
||||
<a
|
||||
href="javascript:void(0);"
|
||||
slot="addonAfter"
|
||||
@click="handleSendCode"
|
||||
>
|
||||
获取
|
||||
</a>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="animated fadeInUp"
|
||||
:style="{'animation-delay': '0.4s'}"
|
||||
>
|
||||
<a-input
|
||||
v-model="resetParam.password"
|
||||
type="password"
|
||||
placeholder="新密码"
|
||||
>
|
||||
<a-icon
|
||||
slot="prefix"
|
||||
type="lock"
|
||||
style="color: rgba(0,0,0,.25)"
|
||||
/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="animated fadeInUp"
|
||||
:style="{'animation-delay': '0.5s'}"
|
||||
>
|
||||
<a-input
|
||||
v-model="resetParam.confirmPassword"
|
||||
type="password"
|
||||
placeholder="确认密码"
|
||||
>
|
||||
<a-icon
|
||||
slot="prefix"
|
||||
type="lock"
|
||||
style="color: rgba(0,0,0,.25)"
|
||||
/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
class="animated fadeInUp"
|
||||
:style="{'animation-delay': '0.6s'}"
|
||||
>
|
||||
<a-button
|
||||
type="primary"
|
||||
:block="true"
|
||||
@click="handleResetPassword"
|
||||
>重置密码</a-button>
|
||||
</a-form-item>
|
||||
|
||||
<a-row>
|
||||
<router-link :to="{ name:'Login' }">
|
||||
<a
|
||||
class="tip animated fadeInUp"
|
||||
:style="{'animation-delay': '0.7s'}"
|
||||
>
|
||||
返回登陆
|
||||
</a>
|
||||
</router-link>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import adminApi from '@/api/admin'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
resetParam: {
|
||||
username: '',
|
||||
email: '',
|
||||
code: '',
|
||||
password: '',
|
||||
confirmPassword: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSendCode() {
|
||||
if (!this.resetParam.username) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '用户名不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.resetParam.email) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '邮箱不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
adminApi.sendResetCode(this.resetParam).then(response => {
|
||||
this.$message.info('邮件发送成功,五分钟内有效')
|
||||
})
|
||||
},
|
||||
handleResetPassword() {
|
||||
if (!this.resetParam.username) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '用户名不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.resetParam.email) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '邮箱不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.resetParam.code) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '验证码不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.resetParam.password) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '新密码不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.resetParam.confirmPassword) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '确认密码不能为空!'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.resetParam.confirmPassword !== this.resetParam.password) {
|
||||
this.$notification['error']({
|
||||
message: '提示',
|
||||
description: '确认密码和新密码不匹配!'
|
||||
})
|
||||
return
|
||||
}
|
||||
adminApi.resetPassword(this.resetParam).then(response => {
|
||||
this.$message.info('密码重置成功!')
|
||||
this.$router.push({ name: 'Login' })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
body {
|
||||
height: 100%;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.container-wrapper {
|
||||
background: #ffffff;
|
||||
position: absolute;
|
||||
border-radius: 5px;
|
||||
top: 45%;
|
||||
left: 50%;
|
||||
margin: -160px 0 0 -160px;
|
||||
width: 320px;
|
||||
padding: 18px 28px 28px 28px;
|
||||
box-shadow: -4px 7px 46px 2px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.halo-logo {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
span {
|
||||
vertical-align: text-bottom;
|
||||
font-size: 38px;
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
color: #1790fe;
|
||||
background-image: linear-gradient(-20deg, #6e45e2 0%, #88d3ce 100%);
|
||||
-webkit-text-fill-color: transparent;
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
small {
|
||||
margin-left: 5px;
|
||||
font-size: 35%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tip {
|
||||
cursor: pointer;
|
||||
margin-left: 0.5rem;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue