动态路由

This commit is contained in:
aoli.qu 2021-09-01 10:28:24 +08:00
parent ff40c9afa0
commit a665afac52
12 changed files with 167 additions and 308 deletions

View File

@ -9,7 +9,6 @@
<script> <script>
import { domTitle, setDocumentTitle } from '@/utils/domUtil' import { domTitle, setDocumentTitle } from '@/utils/domUtil'
import { i18nRender } from '@/locales' import { i18nRender } from '@/locales'
import { mapActions } from 'vuex'
export default { export default {
data () { data () {
@ -23,12 +22,6 @@ export default {
title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`)) title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`))
return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
} }
},
methods: {
...mapActions(['InitAccessToken'])
},
mounted () {
this.InitAccessToken()
} }
} }
</script> </script>

View File

@ -1,80 +1,40 @@
import request from '@/utils/request' import request from '@/utils/request'
const userApi = { const userApi = {
Login: '/auth/login', login: '/login',
Logout: '/auth/logout', logout: '/logout',
ForgePassword: '/auth/forge-password', getLoginUser: '/getLoginUser'
Register: '/auth/register',
twoStepCode: '/auth/2step-code',
SendSms: '/account/sms',
SendSmsErr: '/account/sms_err',
// get my info
UserInfo: '/user/info',
UserMenu: '/user/nav'
} }
/**
* login func
* parameter: {
* username: '',
* password: '',
* remember_me: true,
* captcha: '12345'
* }
* @param parameter
* @returns {*}
*/
export function login (parameter) { export function login (parameter) {
return request({ return request({
url: userApi.Login, url: userApi.login,
method: 'post', method: 'post',
data: parameter data: parameter
}) })
} }
export function getSmsCaptcha (parameter) { export function getLoginUser () {
return request({ return request({
url: userApi.SendSms, url: userApi.getLoginUser,
method: 'post', method: 'post',
data: parameter data: parameter
}) })
} }
export function getInfo () {
return request({
url: userApi.UserInfo,
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
}
export function getCurrentUserNav () {
return request({
url: userApi.UserMenu,
method: 'get'
})
}
export function logout () { export function logout () {
return request({ return request({
url: userApi.Logout, url: userApi.logout,
method: 'post', method: 'post',
headers: { headers: {
'Content-Type': 'application/json;charset=UTF-8' 'Content-Type': 'application/json;charset=UTF-8'
} }
}) })
} }
export function getSmsCaptcha (parameter) {
/** return axios({
* get user 2step code open? url: '/getSmsCaptcha',
* @param parameter {*} method: 'get',
*/ params: parameter
export function get2step (parameter) {
return request({
url: userApi.twoStepCode,
method: 'post',
data: parameter
}) })
} }

View File

@ -11,11 +11,10 @@
* storageOptions: {} - Vue-ls 插件配置项 (localStorage/sessionStorage) * storageOptions: {} - Vue-ls 插件配置项 (localStorage/sessionStorage)
* *
*/ */
export default { export default {
navTheme: 'dark', // theme for nav menu navTheme: 'light', // theme for nav menu
primaryColor: '#1890ff', // primary color of ant design primaryColor: '#1890ff', // primary color of ant design
layout: 'topmenu', // nav menu position: `sidemenu` or `topmenu` layout: 'sidemenu', // nav menu position: `sidemenu` or `topmenu`
contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu
fixedHeader: false, // sticky header fixedHeader: false, // sticky header
fixSiderbar: false, // sticky siderbar fixSiderbar: false, // sticky siderbar
@ -23,7 +22,7 @@ export default {
menu: { menu: {
locale: true locale: true
}, },
title: '系统后台', title: '安全培训平台',
pwa: false, pwa: false,
iconfontUrl: '', iconfontUrl: '',
production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true' production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true'

View File

@ -11,11 +11,9 @@
:i18nRender="i18nRender" :i18nRender="i18nRender"
v-bind="settings" v-bind="settings"
> >
<!-- <setting-drawer :settings="settings" @change="handleSettingChange" /> -->
<template v-slot:rightContentRender> <template v-slot:rightContentRender>
<right-content :top-menu="settings.layout === 'topmenu'" :is-mobile="isMobile" :theme="settings.theme" /> <right-content :top-menu="settings.layout === 'topmenu'" :is-mobile="isMobile" :theme="settings.theme" />
</template> </template>
<!-- <multi-tab></multi-tab> -->
<template v-slot:footerRender> <template v-slot:footerRender>
<global-footer /> <global-footer />
</template> </template>
@ -24,25 +22,20 @@
</template> </template>
<script> <script>
import { updateTheme } from '@ant-design-vue/pro-layout'
import { i18nRender } from '@/locales' import { i18nRender } from '@/locales'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { SIDEBAR_TYPE, TOGGLE_MOBILE_TYPE } from '@/store/mutation-types' import { SIDEBAR_TYPE, TOGGLE_MOBILE_TYPE } from '@/store/mutation-types'
import { asyncRouterMap } from '@/config/router.config.js'
import defaultSettings from '@/config/defaultSettings' import defaultSettings from '@/config/defaultSettings'
import RightContent from '@/components/GlobalHeader/RightContent' import RightContent from '@/components/GlobalHeader/RightContent'
import GlobalFooter from '@/components/GlobalFooter' import GlobalFooter from '@/components/GlobalFooter'
import MultiTab from '@/components/MultiTab'
import LogoSvg from '../assets/logo.svg?inline' import LogoSvg from '../assets/logo.svg?inline'
export default { export default {
name: 'BasicLayout', name: 'BasicLayout',
components: { components: {
// SettingDrawer,
RightContent, RightContent,
GlobalFooter, GlobalFooter
MultiTab
}, },
data () { data () {
return { return {
@ -63,13 +56,11 @@ export default {
fixedHeader: defaultSettings.fixedHeader, fixedHeader: defaultSettings.fixedHeader,
fixSiderbar: defaultSettings.fixSiderbar, fixSiderbar: defaultSettings.fixSiderbar,
colorWeak: defaultSettings.colorWeak, colorWeak: defaultSettings.colorWeak,
hideHintAlert: false, hideHintAlert: false,
hideCopyButton: false hideCopyButton: false
}, },
// //
query: {}, query: {},
// //
isMobile: false isMobile: false
} }
@ -81,9 +72,8 @@ export default {
}) })
}, },
created () { created () {
// const routes = this.mainMenu.find(item => item.path === '/') const routes = this.mainMenu.find(item => item.path === '/')
// this.menus = (routes && routes.children) || [] this.menus = (routes && routes.children) || []
this.menus = asyncRouterMap.find((item) => item.path === '/').children
// //
this.$watch('collapsed', () => { this.$watch('collapsed', () => {
this.$store.commit(SIDEBAR_TYPE, this.collapsed) this.$store.commit(SIDEBAR_TYPE, this.collapsed)
@ -102,12 +92,6 @@ export default {
}, 16) }, 16)
}) })
} }
// first update color
// TIPS: THEME COLOR HANDLER!! PLEASE CHECK THAT!!
if (process.env.NODE_ENV !== 'production' || process.env.VUE_APP_PREVIEW === 'true') {
updateTheme(this.settings.primaryColor)
}
}, },
methods: { methods: {
i18nRender, i18nRender,
@ -127,23 +111,6 @@ export default {
handleCollapse (val) { handleCollapse (val) {
this.collapsed = val this.collapsed = val
}, },
handleSettingChange ({ type, value }) {
console.log('type', type, value)
type && (this.settings[type] = value)
switch (type) {
case 'contentWidth':
this.settings[type] = value === 'Fixed'
break
case 'layout':
if (value === 'sidemenu') {
this.settings.contentWidth = false
} else {
this.settings.fixSiderbar = false
this.settings.contentWidth = true
}
break
}
},
logoRender () { logoRender () {
return <LogoSvg /> return <LogoSvg />
} }

View File

@ -15,7 +15,7 @@ const loginRoutePath = '/user/login'
const defaultRoutePath = '/dashboard/workplace' const defaultRoutePath = '/dashboard/workplace'
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
console.log("判断路由") debugger
NProgress.start() // start progress bar NProgress.start() // start progress bar
to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${i18nRender(to.meta.title)} - ${domTitle}`)) to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${i18nRender(to.meta.title)} - ${domTitle}`))
/* has token */ /* has token */
@ -24,16 +24,30 @@ router.beforeEach((to, from, next) => {
next({ path: defaultRoutePath }) next({ path: defaultRoutePath })
NProgress.done() NProgress.done()
} else { } else {
// check login user.roles is null
if (store.getters.roles.length === 0) { if (store.getters.roles.length === 0) {
// request login userInfo console.log('逻辑开始1 => src/permission.js')
store store
.dispatch('GetInfo') .dispatch('GetInfo')
.then(res => { .then(res => {
const roles = res.result && res.result.role console.log('流程3-获取个人信息返回 => src/permission.js ')
if (res.menus.length < 1) {
Modal.error({
title: '提示:',
content: '无菜单权限,请联系管理员',
okText: '确定',
onOk: () => {
store.dispatch('Logout').then(() => {
window.location.reload()
})
}
})
return
}
const antDesignMenus = res.menus
// generate dynamic router // generate dynamic router
store.dispatch('GenerateRoutes', { roles }).then(() => { console.log('流程4-从后端获取权限开始')
// 根据roles权限生成可访问的路由表 store.dispatch('GenerateRoutes', { antDesignMenus }).then(() => {
// 根据菜单权限生成可访问的路由表
// 动态添加可访问路由表 // 动态添加可访问路由表
router.addRoutes(store.getters.addRouters) router.addRoutes(store.getters.addRouters)
// 请求带有 redirect 重定向时,登录自动重定向到该地址 // 请求带有 redirect 重定向时,登录自动重定向到该地址
@ -48,11 +62,6 @@ router.beforeEach((to, from, next) => {
}) })
}) })
.catch(() => { .catch(() => {
notification.error({
message: '错误',
description: '请求用户信息失败,请重试'
})
// 失败时,获取用户信息失败时,调用登出,来清空历史保留信息
store.dispatch('Logout').then(() => { store.dispatch('Logout').then(() => {
next({ path: loginRoutePath, query: { redirect: to.fullPath } }) next({ path: loginRoutePath, query: { redirect: to.fullPath } })
}) })

View File

@ -1,5 +1,4 @@
// eslint-disable-next-line // eslint-disable-next-line
import * as loginService from '@/api/login'
// eslint-disable-next-line // eslint-disable-next-line
import { BasicLayout, BlankLayout, PageView, RouteView } from '@/layouts' import { BasicLayout, BlankLayout, PageView, RouteView } from '@/layouts'
@ -16,39 +15,6 @@ const constantRouterComponents = {
// 你需要动态引入的页面组件 // 你需要动态引入的页面组件
'Workplace': () => import('@/views/dashboard/Workplace'), 'Workplace': () => import('@/views/dashboard/Workplace'),
// form
'BasicForm': () => import('@/views/form/basicForm/Index'),
'StepForm': () => import('@/views/form/stepForm/StepForm'),
'AdvanceForm': () => import('@/views/form/advancedForm/AdvancedForm'),
// list
'TableList': () => import('@/views/list/TableList'),
'StandardList': () => import('@/views/list/StandardList'),
'CardList': () => import('@/views/list/CardList'),
'SearchLayout': () => import('@/views/list/search/SearchLayout'),
'SearchArticles': () => import('@/views/list/search/Article'),
'SearchProjects': () => import('@/views/list/search/Projects'),
'SearchApplications': () => import('@/views/list/search/Applications'),
'ProfileBasic': () => import('@/views/profile/basic/Index'),
'ProfileAdvanced': () => import('@/views/profile/advanced/Advanced'),
// result
'ResultSuccess': () => import(/* webpackChunkName: "result" */ '@/views/result/Success'),
'ResultFail': () => import(/* webpackChunkName: "result" */ '@/views/result/Error'),
// exception
'Exception403': () => import(/* webpackChunkName: "fail" */ '@/views/exception/403'),
'Exception404': () => import(/* webpackChunkName: "fail" */ '@/views/exception/404'),
'Exception500': () => import(/* webpackChunkName: "fail" */ '@/views/exception/500'),
// account
'AccountCenter': () => import('@/views/account/center/Index'),
'AccountSettings': () => import('@/views/account/settings/Index'),
'BaseSettings': () => import('@/views/account/settings/BaseSetting'),
'SecuritySettings': () => import('@/views/account/settings/Security'),
'CustomSettings': () => import('@/views/account/settings/Custom'),
'BindingSettings': () => import('@/views/account/settings/Binding'),
'NotificationSettings': () => import('@/views/account/settings/Notification')
} }
// 前端未找到页面路由(固定不用改) // 前端未找到页面路由(固定不用改)
@ -58,14 +24,10 @@ const notFoundRouter = {
// 根级菜单 // 根级菜单
const rootRouter = { const rootRouter = {
key: '', path: '/',
name: 'index', name: 'index',
path: '',
component: 'BasicLayout', component: 'BasicLayout',
redirect: '/dashboard', meta: { title: '首页' },
meta: {
title: '首页'
},
children: [] children: []
} }
@ -74,24 +36,26 @@ const rootRouter = {
* @param token * @param token
* @returns {Promise<Router>} * @returns {Promise<Router>}
*/ */
export const generatorDynamicRouter = (token) => { export const generatorDynamicRouter = (data) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
loginService.getCurrentUserNav(token).then(res => { console.log('流程5-后端返回的权限菜单generatorDynamicRouter')
const { result } = res console.log(data)
const resNav = data.antDesignMenus
const menuNav = [] const menuNav = []
const childrenNav = [] const childrenNav = []
// 后端数据, 根级树数组, 根级 PID // 后端数据, 根级树数组, 根级 PID
listToTree(result, childrenNav, 0) listToTree(resNav, childrenNav, 0)
rootRouter.children = childrenNav rootRouter.children = childrenNav
if (childrenNav.length > 0) {
rootRouter.redirect = childrenNav[0].path
}
menuNav.push(rootRouter) menuNav.push(rootRouter)
// console.log('menuNav', menuNav)
const routers = generator(menuNav) const routers = generator(menuNav)
routers.push(notFoundRouter) routers.push(notFoundRouter)
// console.log('routers', routers)
resolve(routers) resolve(routers)
}).catch(err => { }).catch(err => {
reject(err) // reject('加载菜单失败')
}) return Promise.reject(err)
}) })
} }

View File

@ -1,10 +1,10 @@
import Vue from 'vue' import Vue from 'vue'
import Router from 'vue-router' import Router from 'vue-router'
import { constantRouterMap, asyncRouterMap } from '@/config/router.config' import { constantRouterMap } from '@/config/router.config'
// hack router push callback // hack router push callback
const originalPush = Router.prototype.push const originalPush = Router.prototype.push
Router.prototype.push = function push(location, onResolve, onReject) { Router.prototype.push = function push (location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject) if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err) return originalPush.call(this, location).catch(err => err)
} }
@ -12,8 +12,7 @@ Router.prototype.push = function push(location, onResolve, onReject) {
Vue.use(Router) Vue.use(Router)
export default new Router({ export default new Router({
mode: 'hash', // history mode: 'history',
// base: process.env.BASE_URL, base: process.env.VUE_APP_PUBLIC_PATH,
scrollBehavior: () => ({ y: 0 }), routes: constantRouterMap
routes: constantRouterMap.concat(asyncRouterMap)
}) })

View File

@ -18,11 +18,14 @@ const permission = {
actions: { actions: {
GenerateRoutes ({ commit }, data) { GenerateRoutes ({ commit }, data) {
return new Promise(resolve => { return new Promise(resolve => {
const { token } = data console.log('动态生成路由:GenerateRoutes async-router 111')
generatorDynamicRouter(token).then(routers => { generatorDynamicRouter(data).then(routers => {
commit('SET_ROUTERS', routers) commit('SET_ROUTERS', routers)
resolve() resolve()
}) })
}).catch(err => {
// eslint-disable-next-line no-undef
reject(err)
}) })
} }
} }

View File

@ -8,16 +8,16 @@ import { asyncRouterMap, constantRouterMap } from '@/config/router.config'
* @returns {boolean} * @returns {boolean}
*/ */
function hasPermission (permission, route) { function hasPermission (permission, route) {
if (route.meta && route.meta.permission) { // if (route.meta && route.meta.permission) {
let flag = false // let flag = false
for (let i = 0, len = permission.length; i < len; i++) { // for (let i = 0, len = permission.length; i < len; i++) {
flag = route.meta.permission.includes(permission[i]) // flag = route.meta.permission.includes(permission[i])
if (flag) { // if (flag) {
return true // return true
} // }
} // }
return false // return false
} // }
return true return true
} }
@ -64,8 +64,10 @@ const permission = {
actions: { actions: {
GenerateRoutes ({ commit }, data) { GenerateRoutes ({ commit }, data) {
return new Promise(resolve => { return new Promise(resolve => {
console.log('src/store/下的permission.js')
const { roles } = data const { roles } = data
const accessedRouters = filterAsyncRouter(asyncRouterMap, roles) const accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
console.log('动态获取到的菜单列表:'+JSON.stringify(accessedRouters))
commit('SET_ROUTERS', accessedRouters) commit('SET_ROUTERS', accessedRouters)
resolve() resolve()
}) })

View File

@ -1,5 +1,5 @@
import storage from 'store' import storage from 'store'
import { userLogin, getInfo } from '@/api/security/user' import { login, getLoginUser, logout } from '@/api/login'
import { ACCESS_TOKEN } from '@/store/mutation-types' import { ACCESS_TOKEN } from '@/store/mutation-types'
import { welcome } from '@/utils/util' import { welcome } from '@/utils/util'
@ -10,6 +10,7 @@ const user = {
welcome: '', welcome: '',
avatar: '', avatar: '',
roles: [], roles: [],
buttons: [], // 按钮权限
info: {} info: {}
}, },
@ -29,6 +30,9 @@ const user = {
}, },
SET_INFO: (state, info) => { SET_INFO: (state, info) => {
state.info = info state.info = info
},
SET_BUTTONS: (state, buttons) => {
state.buttons = buttons
} }
}, },
@ -36,7 +40,7 @@ const user = {
// 登录 // 登录
Login ({ commit }, userInfo) { Login ({ commit }, userInfo) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
userLogin(userInfo).then(response => { login(userInfo).then(response => {
storage.set(ACCESS_TOKEN, response.token, 24 * 60 * 60 * 1000) storage.set(ACCESS_TOKEN, response.token, 24 * 60 * 60 * 1000)
commit('SET_TOKEN', response.token) commit('SET_TOKEN', response.token)
resolve() resolve()
@ -49,26 +53,23 @@ const user = {
// 获取用户信息 // 获取用户信息
GetInfo ({ commit }) { GetInfo ({ commit }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo().then(response => { getLoginUser().then(response => {
const result = response.result if (response.code === 200) {
if (result.role && result.role.permissions.length > 0) { const data = response.data
const role = result.role console.log('流程2-获取到个人信息 => user.js')
role.permissions = result.role.permissions console.log(data)
role.permissions.map(per => { commit('SET_ROLES', 1)
if (per.actionEntitySet != null && per.actionEntitySet.length > 0) { commit('SET_BUTTONS', data.permissions)
const action = per.actionEntitySet.map(action => { return action.action }) commit('SET_INFO', data)
per.actionList = action commit('SET_NAME', { name: data.userName, welcome: welcome() })
if (data.avatar != null) {
commit('SET_AVATAR', process.env.VUE_APP_API_BASE_URL + '/sysFileInfo/preview?id=' + data.avatar)
} }
}) resolve(data)
role.permissionList = role.permissions.map(permission => { return permission.permissionId })
commit('SET_ROLES', result.role)
commit('SET_INFO', result)
} else { } else {
reject(new Error('getInfo: roles must be a non-null array !')) // eslint-disable-next-line no-undef
reject(new Error(data.message))
} }
commit('SET_NAME', { name: result.name, welcome: welcome() })
commit('SET_AVATAR', result.avatar)
resolve(response)
}).catch(error => { }).catch(error => {
reject(error) reject(error)
}) })
@ -78,10 +79,15 @@ const user = {
// 登出 // 登出
Logout ({ commit, state }) { Logout ({ commit, state }) {
return new Promise((resolve) => { return new Promise((resolve) => {
logout(state.token).then(() => {
resolve()
}).catch(() => {
resolve()
}).finally(() => {
commit('SET_TOKEN', '') commit('SET_TOKEN', '')
commit('SET_ROLES', []) commit('SET_ROLES', [])
storage.remove(ACCESS_TOKEN) commit('SET_BUTTONS', [])
resolve() })
}) })
} }
} }

View File

@ -110,7 +110,8 @@ export default {
], ],
loadData: parameter => { loadData: parameter => {
return menuList(Object.assign(parameter, this.queryParam)).then((res) => { return menuList(Object.assign(parameter, this.queryParam)).then((res) => {
return res.data const menuList = listToTree(res.data, [], rootParentId)
return menuList
}) })
} }
} }
@ -133,8 +134,8 @@ export default {
}, },
methods: { methods: {
handleDel (record) { handleDel (record) {
menuDel({id: record.id, deleteReason: ""}).then((res) => { menuDel({ id: record.id, deleteReason: '' }).then((res) => {
if (res.code == 200) { if (res.code === 200) {
this.$message.success('删除成功') this.$message.success('删除成功')
this.$refs.table.refresh() this.$refs.table.refresh()
} else { } else {

View File

@ -1,33 +1,20 @@
<template> <template>
<div class="main"> <div class="main">
<a-form id="formLogin" class="user-layout-login" ref="formLogin" :form="form" @submit="handleSubmit"> <a-form-model ref="ruleForm" class="user-layout-login" :model="form" :rules="rules" @submit.prevent="handleSubmit">
<a-alert v-if="isLoginError" type="error" showIcon style="margin-bottom: 24px;" message="账户或密码错误18729260811/a123456789 )" /> <a-form-model-item>
<a-form-item> <a-input size="large" v-model="form.username" placeholder="请输入用户名">
<a-input size="large" type="text" placeholder="账户: 18729260811" v-decorator="[ <a-icon slot="prefix" type="user" style="color:rgba(0,0,0,.25)" />
'mobile',
{rules: [{ required: true, message: '请输入帐户名或邮箱地址' }], validateTrigger: 'change'}
]">
<a-icon slot="prefix" type="user" :style="{ color: 'rgba(0,0,0,.25)' }" />
</a-input> </a-input>
</a-form-item> </a-form-model-item>
<a-form-model-item>
<a-form-item> <a-input-password size="large" v-model="form.password" placeholder="请输入密码">
<a-input-password size="large" placeholder="密码: a123456789" v-decorator="[ <a-icon slot="prefix" type="lock" style="color:rgba(0,0,0,.25)" />
'password',
{rules: [{ required: true, message: '请输入密码' }], validateTrigger: 'blur'}
]">
<a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }" />
</a-input-password> </a-input-password>
</a-form-item> </a-form-model-item>
<a-form-item> <a-form-model-item>
<a-checkbox v-decorator="['rememberMe', { valuePropName: 'checked' }]">自动登录</a-checkbox> <a-button block type="primary" size="large" html-type="submit" :loading="loading">登录</a-button>
<router-link :to="{ name: 'recover', params: { user: 'aaa'} }" class="forge-password" style="float: right;">忘记密码</router-link> </a-form-model-item>
</a-form-item> </a-form-model>
<a-form-item style="margin-top:24px">
<a-button size="large" type="primary" htmlType="submit" class="login-button" :loading="state.loginBtn" :disabled="state.loginBtn">确定</a-button>
</a-form-item>
</a-form>
</div> </div>
</template> </template>
@ -36,53 +23,42 @@ import { mapActions } from 'vuex'
import { timeFix } from '@/utils/util' import { timeFix } from '@/utils/util'
export default { export default {
data() { data () {
return { return {
loginBtn: false, form: {
loginType: 0, username: 'admin',
isLoginError: false, password: 'daobang123'
form: this.$form.createForm(this), },
state: { rules: {
time: 60, username: [{ required: true, message: '请输入用户名' }],
loginBtn: false, password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
loginType: 0 },
} loading: false
} }
}, },
methods: { methods: {
...mapActions(['Login', 'Logout']), ...mapActions(['Login', 'Logout']),
handleSubmit(e) { handleSubmit () {
e.preventDefault() if (this.loading) {
const { return false
form: { validateFields }, }
state, this.loading = false
Login this.$refs.ruleForm.validate(valid => {
} = this const { form } = this
if (valid) {
state.loginBtn = true this.Login(form).then(() => {
this.loginSuccess()
const validateFieldsKey = ['mobile', 'password'] }, () => {
this.requestFailed()
validateFields(validateFieldsKey, { force: true }, (err, values) => {
if (!err) {
const loginParams = { ...values }
delete loginParams.username
loginParams[!state.loginType ? 'email' : 'username'] = values.username
loginParams.password = values.password
Login(loginParams)
.then((res) => this.loginSuccess(res))
.catch(err => this.requestFailed(err))
.finally(() => {
state.loginBtn = false
}) })
} else { } else {
setTimeout(() => { this.loading = false
state.loginBtn = false return false
}, 600)
} }
}) })
}, },
loginSuccess(res) { loginSuccess (res) {
this.loading = false
this.$router.push({ path: '/' }) this.$router.push({ path: '/' })
// 1 // 1
setTimeout(() => { setTimeout(() => {
@ -91,33 +67,13 @@ export default {
description: `${timeFix()},欢迎回来` description: `${timeFix()},欢迎回来`
}) })
}, 1000) }, 1000)
this.isLoginError = false
}, },
requestFailed() { requestFailed () {
this.isLoginError = true this.loading = false
} }
} }
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.user-layout-login {
label {
font-size: 14px;
}
.getCaptcha {
display: block;
width: 100%;
height: 40px;
}
.forge-password {
font-size: 14px;
}
button.login-button {
padding: 0 15px;
font-size: 16px;
height: 40px;
width: 100%;
}
}
</style> </style>