main.js 引入 router
import router from './router'
new Vue({
router,
i18n,
created: bootstrap,
render: h => h(App)
}).$mount('#app')
router - index.js new Router
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import { constantRouterMap } from '@/config/router.config'
const createRouter = () => new Router({
mode: 'history',
base: "booking",
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
})
const router = createRouter()
export default router
配置基础路由
import { UserLayout} from '@/layouts'
export const constantRouterMap = [
{
component: UserLayout,
path: '/',
redirect: '/Login',
children: [{
path: '/Login',
name:"Login",
component: () => import('@/views/Home/Login')
},
{
path: '/404',
name:"404",
component: () => import('@/views/exception/404'),
},
]
},
]
路由处理 - permission.js
import router from '@/router'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
import TokenCache from '@/utils/cache/TokenCache'
import OperatorCache from '@/utils/cache/OperatorCache'
import { initRouter } from '@/utils/routerUtil'
import defaultSettings from '@/config/defaultSettings'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['Login'] // no redirect whitelist
router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
// 已授权
if (TokenCache.getToken()) {
OperatorCache.init(() => {
if (to.path === '/Home/Login') {
next({ path: '/' })
NProgress.done()
} else {
initRouter(to, from, next).then(() => {
const redirect = decodeURIComponent(from.query.redirect || to.path)
//桌面特殊处理
if (to.path == defaultSettings.desktopPath || to.path == '/404') {
next()
} else {
if (to.path === redirect) {
next()
} else {
// 跳转到目的路由
next({ path: redirect })
}
}
})
}
})
} else {
if (whiteList.includes(to.name)) {
// 在免登录白名单,直接进入
next()
} else {
next({ path: '/', query: { redirect: to.fullPath } })
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
}
}
})
router.afterEach(() => {
NProgress.done() // finish progress bar
})
路由接口
import router from '@/router'
import { Axios } from '@/utils/plugin/axios-plugin'
import { BasicLayout, PageView } from '@/layouts'
import ProcessHelper from '@/utils/helper/ProcessHelper'
import defaultSettings from '@/config/defaultSettings'
import i18n from '../../config/i18n'
var uuid = require('node-uuid')
let inited = false
let addRouter = []
export const getAddRouter = () => {
return addRouter
}
// 前端未找到页面路由(固定不用改)
const notFoundRouter = {
path: '*',
redirect: '/404',
hidden: true
}
// 开发模式额外路由
const devRouter = [
{
title: '开发',
icon: 'code',
children: [
{
path: '/Base_Manage/Base_DbLink/List',
title: '数据库连接'
}
]
},
]
//初始化
export const initRouter = (to, from, next) => {
return new Promise((res, rej) => {
if (inited) {
res()
} else {
generatorDynamicRouter().then(dynamicRouter => {
router.addRoutes(dynamicRouter)
addRouter = dynamicRouter
inited = true
//路由缓存
localStorage.setItem('routers',dynamicRouter);
next({ ...to, replace: true })
})
}
})
}
/**
* 获取路由菜单信息
* @returns {Promise<any>}
*/
const generatorDynamicRouter = () => {
return new Promise((resolve, reject) => {
// ajax
getRouterByUser().then(res => {
let allRouters = []
//首页根路由
let rootRouter = {
// 路由地址 动态拼接生成如 /dashboard/workplace
path: '/',
redirect: defaultSettings.desktopPath,
// 路由名称,建议唯一
name: uuid.v4(),
// 该路由对应页面的 组件
component: BasicLayout,
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
meta: { title: '首页' },
children: []
}
allRouters.push(rootRouter)
if (!ProcessHelper.isProduction()) {
res.push(...devRouter)
}
//格式化路由
rootRouter.children = generator(res)
allRouters.push(notFoundRouter)
//返回组装后的路由
resolve(allRouters)
})
.catch(err => {
reject(err)
})
})
}
/**
* 获取后端路由
* @returns {Promise}
*/
const getRouterByUser = () => {
return new Promise((resolve, reject) => {
Axios.post('/Home/GetMenu', {}).then(resJson => {
if (resJson.Success) {
resolve(resJson.Data)
}
})
})
}
/**
* 格式化 后端 结构信息并递归生成层级路由表
*
* @param routerMap
* @param parent
* @returns {*}
*/
const generator = (routerMap, parent) => {
return routerMap.map(item => {
let hasChildren = item.children && item.children.length > 0
let component = {}
if (hasChildren) {
component = PageView
} else if (item.path) {
component = () => import(`@/views${item.path.replace(new RegExp(/\/\:.*$/), '')}`)
}
let currentRouter = {
path: '',
// 路由名称,建议唯一
name: uuid.v4(),
// 该路由对应页面的 组件
component: component,
// meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
// 这里添加了国际化
meta: { title: i18n.t(`menu.${item.Lan_id}`), icon: item.icon || undefined }
}
//有子菜单
if (hasChildren) {
currentRouter.path = `/${uuid.v4()}`
} else if (item.path) {
//页面
currentRouter.path = item.path
currentRouter.path = currentRouter.path.replace('//', '/')
}
// 重定向
item.redirect && (currentRouter.redirect = item.redirect)
// 是否有子菜单,并递归处理
if (hasChildren) {
// Recursion
currentRouter.children = generator(item.children, currentRouter)
}
return currentRouter
})
}
BasicLayout.vue的渲染
<template>
<a-layout :class="['layout', device]">
<!-- SideMenu -->
<a-drawer
v-if="isMobile()"
placement="left"
:wrapClassName="`drawer-sider ${navTheme}`"
:closable="false"
:visible="collapsed"
@close="drawerClose"
>
<side-menu
mode="inline"
:menus="menus"
:theme="navTheme"
:collapsed="false"
:collapsible="true"
@menuSelect="menuSelect"
></side-menu>
</a-drawer>
<side-menu
v-else-if="isSideMenu()"
mode="inline"
:menus="menus"
:theme="navTheme"
:collapsed="collapsed"
:collapsible="true"
></side-menu>
<a-layout
:class="[layoutMode, `content-width-${contentWidth}`]"
:style="{ paddingLeft: contentPaddingLeft, minHeight: '100vh' }"
>
<!-- layout header -->
<global-header
:mode="layoutMode"
:menus="menus"
:theme="navTheme"
:collapsed="collapsed"
:device="device"
@toggle="toggle"
/>
<!-- layout content -->
<a-layout-content
:style="{ height: '100%', margin: '24px 24px 0', paddingTop: fixedHeader ? '64px' : '0' }"
>
<multi-tab v-if="multiTab"></multi-tab>
<transition name="page-transition">
<!-- <route-view /> -->
<div class="content">
<div class="page-header-index-wide">
<slot>
<!-- keep-alive -->
<keep-alive v-if="multiTab">
<router-view ref="content" />
</keep-alive>
<router-view v-else ref="content" />
</slot>
</div>
</div>
</transition>
</a-layout-content>
<!-- layout footer -->
<!-- <a-layout-footer>
<global-footer />
</a-layout-footer>-->
<!-- Setting Drawer (show in development mode) -->
<!-- <setting-drawer v-if="!production"></setting-drawer> -->
</a-layout>
</a-layout>
</template>
<script>
import { triggerWindowResizeEvent } from '@/utils/util'
import { mapState, mapActions } from 'vuex'
import { mixin, mixinDevice } from '@/utils/mixin'
import config from '@/config/defaultSettings'
import RouteView from './RouteView'
import MultiTab from '@/components/MultiTab'
import SideMenu from '@/components/Menu/SideMenu'
import GlobalHeader from '@/components/GlobalHeader'
import GlobalFooter from '@/components/GlobalFooter'
// import SettingDrawer from '@/components/SettingDrawer'
import { getAddRouter } from '@/utils/routerUtil'
export default {
name: 'BasicLayout',
mixins: [mixin, mixinDevice],
components: {
RouteView,
MultiTab,
SideMenu,
GlobalHeader,
GlobalFooter
// SettingDrawer
},
data() {
return {
production: config.production,
collapsed: false,
menus: []
}
},
computed: {
...mapState({
// 动态主路由
mainMenu: state => getAddRouter()
}),
contentPaddingLeft() {
if (!this.fixSidebar || this.isMobile()) {
return '0'
}
if (this.sidebarOpened) {
return '220px'
}
return '80px'
}
},
watch: {
sidebarOpened(val) {
this.collapsed = !val
}
},
created() {
//menus赋值
this.menus = this.mainMenu.find(item => item.path === '/').children
this.collapsed = !this.sidebarOpened
},
mounted() {
const userAgent = navigator.userAgent
if (userAgent.indexOf('Edge') > -1) {
this.$nextTick(() => {
this.collapsed = !this.collapsed
setTimeout(() => {
this.collapsed = !this.collapsed
}, 16)
})
}
}
}
</script>