diff --git a/src/components/ParentView/index.vue b/src/components/ParentView/index.vue new file mode 100644 index 0000000..621cb5a --- /dev/null +++ b/src/components/ParentView/index.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/src/components/Hello.vue b/src/layout/index.vue similarity index 100% rename from src/components/Hello.vue rename to src/layout/index.vue diff --git a/src/main.js b/src/main.js index e4bf66f..064b8be 100644 --- a/src/main.js +++ b/src/main.js @@ -13,7 +13,7 @@ import 'element-ui/lib/theme-chalk/index.css' import VueHighlightJS from 'vue-highlightjs' import 'highlight.js/styles/atom-one-dark.css' // 加载路由 -import './router/index' +import './router/routers' //加载权限指令 import checkPer from '@/utils/permission' @@ -21,8 +21,6 @@ import checkPer from '@/utils/permission' -//加载路由 -Vue.use(router) // 加载代码高亮 Vue.use(VueHighlightJS) // 加载elementui diff --git a/src/router/index.js b/src/router/index.js index 1398245..ad73c34 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -7,9 +7,12 @@ import 'nprogress/nprogress.css' import { getToken } from '@/utils/auth' -// import { -// filterAsyncRouter -// } from '@/store/modules/permission' +import { + filterAsyncRouter +} from '@/store/modules/permission' +import { + buildMenus +} from '@/api/system/menu' @@ -22,18 +25,93 @@ const whiteList = ['/login'] //路由守卫,路由跳转前执行钩子函数 //to:目标路由对象 -//from:即将要离开的路由对象 -//next:执行效果依赖 +//from:当前路由 +//next:放行或重载 router.beforeEach((to, from, next) => { - //如果路由标题设置则显示配置标题和目标菜单标题 + // 如果路由标题设置则显示配置标题和目标菜单标题 if (to.meta.title) { document.title = to.meta.title + '-' + Config.title } + //加载效果 NProgress.start() - next(`/login?redirect=${to.fullPath}`) + //如果已登录过且要跳转的页面是登录页,执行下一次路由守卫 + if (getToken()) { + if (to.path === '/login') { + next({ + path: '/' + }) + NProgress.done() + } else { + //判断当前用户是否已拉取完用户信息 + if (store.getters.roles.length === 0) { + //拉取user_info + store.dispatch('GetInfo').then(() => { + //加载动态路由,拉取菜单 + loadMenus(next, to) + }).catch(() => { + store.dispatch('LogOut').then(() => { + //重新实例化路由对象 避免bug + location.reload() + }) + }) + } else if (store.getters.loadMenus) { + store.dispatch('updateLoadMenus') + loadMenus(next, to) + } else { + next() + } + } + } else { + //hsa no token + //在免登录白名单,直接进入 + if (whiteList.indexOf(to.path) !== -1) { + next() + } else { + //否则全部重定向到登录页面 + next(`/loginredirect=${to.fullPath}`) + NProgress.done() + } + } NProgress.done() }) -router.afterEach(()=>{ +export const loadMenus = (next, to) => { + + buildMenus().then(res => { + const sdata = JSON.parse(JSON.stringify(res)) + const rdata = JSON.parse(JSON.stringify(res)) + const sidebarRoutes = filterAsyncRouter() + }) + + rewriteRoutes.push({ + path: '*', + redirect: '/404', + hidden: true + }) + + //存储路由 + store.dispatch('GenerateRoutes', rewriteRoutes).then(() => { + /* + * 在addRoutes()之后第一次访问被添加的路由会白屏, + * 这是因为刚刚addRoutes()就立刻访问被添加的路由, + * 然而此时addRoutes()没有执行结束, + * 因而找不到刚刚被添加的路由导致白屏 + */ + router.addRoutes(rewriteRoutes) + /* + * 确保addRoutes()时动态添加的路由已经被完全加载上去 + * replace: true只是一个设置信息, + * 告诉VUE本次操作后, + * 不能通过浏览器后退按钮,返回前一个路由 + */ + next({ + ...to, + replace: true + }) + }) + store.dispatch('SetSidebarRouters', sidebarRoutes) +} + +router.afterEach(() => { NProgress.done() }) diff --git a/src/router/routers.js b/src/router/routers.js index 5f73203..7a685cc 100644 --- a/src/router/routers.js +++ b/src/router/routers.js @@ -1,5 +1,6 @@ import Vue from 'vue' import Router from 'vue-router' +import Config from '@/settings' //加载路由 @@ -28,8 +29,6 @@ export default new Router({ //修改路由,取消hash的注释改变部署模式 //mode:'hash', mode: 'history', - scrollBehavior: () => ({ - y: 0 - }), + scrollBehavior: () => ({ y: 0 }), routes: constantRouterMap }) diff --git a/src/settings.js b/src/settings.js index be219cc..6724201 100644 --- a/src/settings.js +++ b/src/settings.js @@ -16,4 +16,10 @@ module.exports = { //请求超时时间,毫秒(默认2分钟) timeout: 1200000, + //是否显示设置底部信息 + showFooter: true, + + //底部文字,支持html语法 + footerTxt:'© 2021 阅行客后台管理系统' + } diff --git a/src/store/modules/api.js b/src/store/modules/api.js new file mode 100644 index 0000000..02788ef --- /dev/null +++ b/src/store/modules/api.js @@ -0,0 +1,28 @@ +//适配Nginx反向代理 +const baseUrl = process.env.VUE_APP_BASE_API === '/' ? '' : process.env.VUE_APP_BASE_API + +//适配API路径 +const api = { + state: { + + //部署包上传 + //deployUploadApi: baseUrl + '/api/deploy/upload', + + //图片上传 + imagesUplaodApi: baseUrl + '/api/localStorage/pictures', + + //上传图像 + updateAvatarApi: baseUrl + '/api/users/updateAvatar', + + //文件上传 + fileUploadApi: baseUrl + '/api/localStorage', + + // swagger + swaggerApi: baseUrl + '/swagger-ui.html', + + //基础url + baseApi: baseUrl + } +} + +export default api diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js new file mode 100644 index 0000000..063253c --- /dev/null +++ b/src/store/modules/permission.js @@ -0,0 +1,86 @@ +import { constantRouterMap } from "@/router/routers"; +import Layout from '@/layout/index' +import ParentView from '@/components/ParentView' + +const permission = { + //存放状态 + state: { + routers: constantRouterMap, + addRouters: [], + sidebarRouters: [] + }, + //同步更改状态 + mutations: { + SET_ROUTERS: (state, routers) => { + state.addRouters = routers + state.routers = constantRouterMap.concat(routers) + }, + SET_SIDEBAR_ROUTERS: (state, routers) => { + state.sidebarRouters = constantRouterMap.concat(routers) + } + }, + //发送异步请求拿到数据 + actions: { + GenerateRoutes({ + commit + }, asyncRouter) { + commit('SET_ROUTERS', asyncRouter) + }, + SetSidebarRouters({ + commit + }, sidebarRouter) { + commit('SET_SIDEBAR_ROUTERS', sidebarRouter) + } + } + +} + +//遍历后台传来的路由字符串,转换为组件对象 +export const filterAsyncRouter = (routers, isRewrite = false) => { + return routers.filter(router => { + if (isRewrite && router.children) { + router.children = filterChildren(router.children) + } + if (router.component) { + if (router.component === 'Layout') { // Layout组件特殊处理 + router.component = Layout + } else if (router.component === 'ParentView') { + router.component = ParentView + } else { + const component = router.component + router.component = loadView(component) + } + } + if (router.children && router.children.length) { + router.children = filterAsyncRouter(router.children, router, isRewrite) + } + return true + }) +} + +function filterChildren(childrenMap) { + var children = [] + childrenMap.forEach((el, index) => { + if (el.children && el.children.length) { + if (el.component === 'ParentView') { + el.children.forEach(c => { + c.path = el.path + '/' + c.path + if (c.children && c.children.length) { + children = children.concat(filterChildren(c.children, c)) + return + } + children.push(c) + }) + return + } + } + children = children.concat(el) + }) + return children +} + +export const loadView = (view) => { + return (resolve) => require([`@/views/${view}`], resolve) +} + +export default permission diff --git a/src/utils/request.js b/src/utils/request.js index 4fab665..e4df359 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -7,7 +7,7 @@ import Config from '@/settings' import Cookies from "js-cookie" -//创建axios 实例 +//二次封装axios,创建axios 实例 const service = axios.create({ //api 的 base_url在.env.development有配置 baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '/', diff --git a/src/views/login.vue b/src/views/login.vue new file mode 100644 index 0000000..8d6593f --- /dev/null +++ b/src/views/login.vue @@ -0,0 +1,240 @@ + + + + +