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 = () => {
|
adminApi.updateAdminAssets = () => {
|
||||||
return service({
|
return service({
|
||||||
url: `${baseUrl}/halo-admin`,
|
url: `${baseUrl}/halo-admin`,
|
||||||
|
|
|
@ -218,6 +218,12 @@ export const constantRouterMap = [
|
||||||
meta: { title: '安装向导' },
|
meta: { title: '安装向导' },
|
||||||
component: () => import('@/views/system/Installation')
|
component: () => import('@/views/system/Installation')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/password/reset',
|
||||||
|
name: 'ResetPassword',
|
||||||
|
meta: { title: '重置密码' },
|
||||||
|
component: () => import('@/views/user/ResetPassword')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/404',
|
path: '/404',
|
||||||
name: 'NotFound',
|
name: 'NotFound',
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
|
import {
|
||||||
|
setDocumentTitle,
|
||||||
|
domTitle
|
||||||
|
} from '@/utils/domUtil'
|
||||||
|
|
||||||
import NProgress from 'nprogress' // progress bar
|
import NProgress from 'nprogress' // progress bar
|
||||||
import 'nprogress/nprogress.css' // progress bar style
|
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) => {
|
router.beforeEach((to, from, next) => {
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
|
@ -16,7 +21,9 @@ router.beforeEach((to, from, next) => {
|
||||||
Vue.$log.debug('Token', store.getters.token)
|
Vue.$log.debug('Token', store.getters.token)
|
||||||
if (store.getters.token) {
|
if (store.getters.token) {
|
||||||
if (to.name === 'Login') {
|
if (to.name === 'Login') {
|
||||||
next({ name: 'Dashboard' })
|
next({
|
||||||
|
name: 'Dashboard'
|
||||||
|
})
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -35,6 +42,11 @@ router.beforeEach((to, from, next) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
next({ name: 'Login', query: { redirect: to.fullPath } })
|
next({
|
||||||
|
name: 'Login',
|
||||||
|
query: {
|
||||||
|
redirect: to.fullPath
|
||||||
|
}
|
||||||
|
})
|
||||||
NProgress.done()
|
NProgress.done()
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,7 +8,7 @@ import router from '@/router'
|
||||||
import { isObject } from './util'
|
import { isObject } from './util'
|
||||||
|
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
timeout: 5000,
|
timeout: 8000,
|
||||||
withCredentials: true
|
withCredentials: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container-wrapper">
|
||||||
<div class="loginLogo animated fadeInUp">
|
<div class="halo-logo animated fadeInUp">
|
||||||
<span>Halo</span>
|
<span>Halo</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="loginBody animated">
|
<div class="animated">
|
||||||
<a-form
|
<a-form
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
@keyup.enter.native="handleLogin"
|
@keyup.enter.native="handleLogin"
|
||||||
|
@ -39,17 +39,27 @@
|
||||||
/>
|
/>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-row>
|
<a-form-item
|
||||||
|
class="animated fadeInUp"
|
||||||
|
:style="{'animation-delay': '0.3s'}"
|
||||||
|
>
|
||||||
<a-button
|
<a-button
|
||||||
type="primary"
|
type="primary"
|
||||||
:block="true"
|
:block="true"
|
||||||
@click="handleLogin"
|
@click="handleLogin"
|
||||||
class="animated fadeInUp"
|
|
||||||
:style="{'animation-delay': '0.3s'}"
|
|
||||||
>登录</a-button>
|
>登录</a-button>
|
||||||
</a-row>
|
</a-form-item>
|
||||||
|
|
||||||
<a-row>
|
<a-row>
|
||||||
|
<router-link :to="{ name:'ResetPassword' }">
|
||||||
|
<a
|
||||||
|
class="tip animated fadeInRight"
|
||||||
|
v-if="resetPasswordButton"
|
||||||
|
href="javascript:void(0);"
|
||||||
|
>
|
||||||
|
找回密码
|
||||||
|
</a>
|
||||||
|
</router-link>
|
||||||
<a
|
<a
|
||||||
@click="handleApiModifyModalOpen"
|
@click="handleApiModifyModalOpen"
|
||||||
class="tip animated fadeInUp"
|
class="tip animated fadeInUp"
|
||||||
|
@ -92,12 +102,21 @@ export default {
|
||||||
password: null,
|
password: null,
|
||||||
apiModifyVisible: false,
|
apiModifyVisible: false,
|
||||||
defaultApiBefore: window.location.protocol + '//',
|
defaultApiBefore: window.location.protocol + '//',
|
||||||
apiUrl: window.location.host
|
apiUrl: window.location.host,
|
||||||
|
resetPasswordButton: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({ defaultApiUrl: 'apiUrl' })
|
...mapGetters({ defaultApiUrl: 'apiUrl' })
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
const _this = this
|
||||||
|
document.addEventListener('keydown', function(e) {
|
||||||
|
if (e.keyCode === 72 && e.altKey && e.shiftKey) {
|
||||||
|
_this.toggleHidden()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['login', 'loadUser', 'loadOptions']),
|
...mapActions(['login', 'loadUser', 'loadOptions']),
|
||||||
...mapMutations({
|
...mapMutations({
|
||||||
|
@ -144,49 +163,53 @@ export default {
|
||||||
handleApiUrlRestore() {
|
handleApiUrlRestore() {
|
||||||
this.restoreApiUrl()
|
this.restoreApiUrl()
|
||||||
this.apiUrl = this.defaultApiUrl
|
this.apiUrl = this.defaultApiUrl
|
||||||
|
},
|
||||||
|
toggleHidden() {
|
||||||
|
this.resetPasswordButton = !this.resetPasswordButton
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scope>
|
<style lang="less">
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
.container {
|
|
||||||
background: #f7f7f7;
|
.container-wrapper {
|
||||||
|
background: #ffffff;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
border-radius: 5px;
|
||||||
top: 45%;
|
top: 45%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin: -160px 0 0 -160px;
|
margin: -160px 0 0 -160px;
|
||||||
width: 320px;
|
width: 320px;
|
||||||
padding: 16px 32px 32px 32px;
|
padding: 18px 28px 28px 28px;
|
||||||
box-shadow: -4px 7px 46px 2px rgba(0, 0, 0, 0.1);
|
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 {
|
.tip {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-top: .5rem;
|
margin-left: 0.5rem;
|
||||||
float: right;
|
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>
|
</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