Login.vue
handleSubmit (e) {
validateFields(validateFieldsKey, { force: true }, (err, values) => {
Login(loginParams) // 调用 src/store/modules/user.js中的actions中的Login方法
})
},
src/store/modules/user.js
Login ({ commit }, userInfo) {
return new Promise((resolve, reject) => {
login(userInfo).then(response => { // 调用 src/api/login.js中的login函数发送请求
const result = response.result
// 在 localStorage 中 存 ACCESS_TOKEN
storage.set(ACCESS_TOKEN, result.token, new Date().getTime() + 7 * 24 * 60 * 60 * 1000)
// 将 token 存到 state 中
commit('SET_TOKEN', result.token)
resolve()
}).catch(error => {
reject(error)
})
})
}
// login接口 Mock 返回的数据 [src/mock/services/auth.js]
const login = (options) => {
const body = getBody(options) // 请求时携带的参数数据
console.log('mock: body', body)
if (!username.includes(body.username) || !password.includes(body.password)) {
return builder({ isLogin: true }, '账户或密码错误', 401)
}
// 定义 mock 返回的数据
return builder({
'id': Mock.mock('@guid'),
'name': Mock.mock('@name'),
'username': 'admin',
'passwod': '',
'avatar': 'https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png',
'status': 1,
'telephone': '',
'lastLoginIp': '27.154.74.117',
'lastLoginTime': 1534837621348,
'creatorId': 'admin',
'createTime': 1497160610259,
'deleted': 0,
'roleId': 'admin',
'lang': 'zh-CN',
'toke': '4291d7da90057ec9aec4a71ea837f'
}, '', 200, { 'Custom-Header': Mock.mock('@guid') })
}
之后进行路由的跳转,在src/permission.js中定义了路由导航守卫
router.beforeEach((to, from, next) => {
// 如果to.meta.title存在且不为undefined, 就设置网页标签页标题
to.meta && typeof to.meta.title !== 'undefined' && setDocumentTitle(`${i18nRender(to.meta.title)} - ${domTitle}`)
const token = storage.get(ACCESS_TOKEN)
if (token) {
// 去往登录页则直接跳转到首页
if (to.path === loginRoutePath) {
next({ path: defaultRoutePath })
NProgress.done()
} else {
// 有token 但去的不是登录页
if (store.getters.roles.length === 0) {
// request login userInfo
store
.dispatch('GetInfo') // 调用 src/store/modules/user.js中的actions中的GetInfo方法
.then(res => {
// 调用 src/router/generator-routers.js中的 generatorDynamicRouter 函数
generatorDynamicRouter(token).then(routers => {
store.commit('SET_ROUTERS', routers) // 存到 state 中
// 根据roles权限生成可访问的路由表
// 动态添加可访问路由表
resetRouter() // 重置路由 防止退出重新登录或者token过期后页面未刷新,导致的路由重复添加
store.getters.addRouters.forEach(r => {
router.addRoute(r) // 添加到路由结构中
})
// 请求带有 redirect 重定向时,登录自动重定向到该地址
const redirect = decodeURIComponent(from.query.redirect || to.path)
if (to.path === redirect) {
// set the replace: true so the navigation will not leave a history record
next({ ...to, replace: true })
} else {
// 跳转到目的路由
next({ path: redirect })
}
})
})
.catch(() => {
notification.error({
message: '错误',
description: '请求用户信息失败,请重试'
})
// 失败时,获取用户信息失败时,调用登出,来清空历史保留信息
store.dispatch('Logout').then(() => {
next({ path: loginRoutePath, query: { redirect: to.fullPath } })
})
})
} else {
next()
}
}
} else {
if (allowList.includes(to.name)) {
// 在免登录名单,直接进入
next()
} else {
next({ path: loginRoutePath, query: { redirect: to.fullPath } })
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
}
}
})
src/store/modules/user.js
GetInfo ({ commit }) {
return new Promise((resolve, reject) => {
getInfo().then(response => { // 调用 src/api/login.js中的getInfo函数发送请求
// 对响应回来的数据处理, 并将有些信息存到 state 中
const result = response.result
if (result.role && result.role.permissions.length > 0) {
const role = result.role
role.permissions = result.role.permissions
// 提取汇总permissions数组中每一个元素的action
role.permissions.map(per => {
if (per.actionEntitySet != null && per.actionEntitySet.length > 0) {
const action = per.actionEntitySet.map(action => { return action.action })
per.actionList = action
}
})
// 汇总permissions数组中每一个元素的permissionId
role.permissionList = role.permissions.map(permission => { return permission.permissionId })
commit('SET_ROLES', result.role) // 存到 state 中
commit('SET_INFO', result) // 存到 state 中
} else {
reject(new Error('getInfo: roles must be a non-null array !'))
}
// 存到 state 中
commit('SET_NAME', { name: result.name, welcome: welcome() })
commit('SET_AVATAR', result.avatar)
resolve(response)
}).catch(error => {
reject(error)
})
})
},
getInfo接口返回的数据
const info = options => {
const userInfo = {
id: '4291d7da9005377ec9aec4a71ea837f',
name: '天野远子',
username: 'admin',
password: '',
avatar: '/avatar2.jpg',
status: 1,
telephone: '',
lastLoginIp: '27.154.74.117',
lastLoginTime: 1534837621348,
creatorId: 'admin',
createTime: 1497160610259,
merchantCode: 'TLif2btpzg079h15bk',
deleted: 0,
roleId: 'admin',
role: {}
}
// role
const roleObj = {
id: 'admin',
name: '管理员',
describe: '拥有所有权限',
status: 1,
creatorId: 'system',
createTime: 1497160610259,
deleted: 0,
permissions: [
{
roleId: 'admin',
permissionId: 'dashboard',
permissionName: '仪表盘',
actionEntitySet: [
{
action: 'add',
describe: '新增',
defaultCheck: false
},
{
action: 'update',
describe: '修改',
defaultCheck: false
},
{
action: 'delete',
describe: '删除',
defaultCheck: false
}
],
actionList: null,
dataAccess: null
}
]
}
userInfo.role = roleObj
return builder(userInfo)
}
src/router/generator-routers.js
export const generatorDynamicRouter = token => {
return new Promise((resolve, reject) => {
loginService
.getCurrentUserNav(token) // 调用 src/api/login.js中的getCurrentUserNav函数发送请求
.then(res => {
console.log('generatorDynamicRouter response:', res)
const { result } = res
const menuNav = []
const childrenNav = []
// 对 响应得到的数据进行加工处理, 生成路由表
listToTree(result, childrenNav, 0)
rootRouter.children = childrenNav
menuNav.push(rootRouter)
const routers = generator(menuNav)
routers.push(notFoundRouter) // 得到 路由表
resolve(routers)
})
.catch(err => {
reject(err)
})
})
}
getCurrentUserNav接口返回的数据
const userNav = options => {
const nav = [
// dashboard
{
name: 'dashboard',
parentId: 0,
id: 1,
meta: {
title: 'menu.dashboard',
icon: 'dashboard',
show: true
},
component: 'RouteView',
redirect: '/dashboard/workplace'
},
{
name: 'workplace',
parentId: 1,
id: 7,
meta: {
title: 'menu.dashboard.monitor',
show: true
},
component: 'Workplace'
},
{
name: 'monitor',
path: 'https://www.baidu.com/',
parentId: 1,
id: 3,
meta: {
title: 'menu.dashboard.workplace',
target: '_blank',
show: true
}
}
]
const json = builder(nav)
console.log('json', json)
return json
}
说白了,默认的这种方式,是通过后端返回的数据进行加工来动态生成路由的