import Vue from 'vue' import Router from 'vue-router' import store from '@/store' const HtTabsComponent = () => import('@/components/common/HtTabsComponent.vue') const TemplateComponent = () => import('@/components/common/TemplateComponent.vue') Vue.use(Router) // 通用路由 const constantRoutes = [ { path: '/401', name: '401', component: () => import('@/views/401'), meta: { single: true, anonymous: true, }, }, { path: '/login/:tenant', name: 'tenantLogin', props: true, component: () => import('@/views/Login.vue'), meta: { single: true, anonymous: true, }, }, { path: '/login', name: 'login', props: true, component: () => import('@/views/Login.vue'), meta: { single: true, anonymous: true, }, }, { path: '/resetPwdView', name: 'resetPwdView', props: true, component: () => import('@/views/ResetPwdView.vue'), meta: { single: true, anonymous: true, }, }, { path: '/', redirect: { name: 'home', }, }, { path: '/href/template/:alias', name: 'href', component: () => import('@/components/common/HtTabsComponentHref.vue'), }, { path: '/home', name: 'home', component: () => import('@/views/common/Home.vue'), meta: { isHome: true, }, }, { path: '/formPreview/:formId', name: 'formPreview', props: true, component: () => import('@/components/form/FormPreview.vue'), meta: { single: true, }, }, { path: '/approvalForm', name: 'approvalForm', props: true, component: () => import('@/views/flow/ApprovalForm.vue'), meta: { single: true, }, }, { path: '/reportManager/viewList', name: 'viewList', component: () => import('@/components/form/customView/ViewList.vue'), meta: { isHome: true, }, }, { path: '/reportManager/flowChartEdit', name: 'flowChartEdit', component: () => import('@/components/form/chart/FlowChartEdit.vue'), meta: { isHome: true, }, }, { path: '/demo', name: 'demo', component: HtTabsComponent, meta: { anonymous: true, }, }, { path: '/executeJobList/:jobName', name: 'executeJobList', component: HtTabsComponent, meta: { keepAlive: true, //页面跳转重新渲染 默认不渲染 }, }, { path: '/schedulerTriggerList/:jobName', name: 'schedulerTriggerList', component: HtTabsComponent, meta: { keepAlive: true, }, }, { path: '/portal/addColumn', name: 'addColumn', component: () => import('@/views/portal/AddColumn.vue'), meta: { noMargin: true, }, }, // { // path: '/sysModuleList', // name: 'sysModuleList', // component: () => import('@/views/system/generator/sysModuleList.vue'), // }, { path: '/templateMenu/:alias', name: 'templateMenu', component: TemplateComponent, meta: { keepAlive: true, //页面跳转重新渲染 默认不渲染 }, }, { path: '/matrixData/:matrixId', name: 'matrixData', component: () => import('@/views/uc/MatrixData.vue'), }, { path: '/datavPreview', name: 'datavPreview', component: () => import('@/components/portal/DatavDesignPreview.vue'), meta: { single: true, }, }, { path: '/datavShow/:alias/:key', name: 'datavShow', component: () => import('@/components/portal/DatavDesignPreview.vue'), }, { //表单列表预览-不显示菜单 path: '/templatePreview/:templateKey/:rkey', name: 'templatePreview', component: () => import('@/components/form/dataTemplate/TemplatePreview.vue'), meta: { single: true, }, }, { path: '/templatePreview/:templateKey/:parameterqQuerys/:rkey', name: 'templatePreview_withQuerys', component: () => import('@/components/form/dataTemplate/TemplatePreview.vue'), meta: { single: true, }, }, { //表单列表预览-显示菜单 path: '/templateShow/:templateKey/:rkey', name: 'templateShow', component: () => import('@/components/form/dataTemplate/TemplatePreview.vue'), }, { path: '/templateForm/:templateKey/:action/:data', name: 'templateForm_withDatas', component: () => import('@/components/form/dataTemplate/TemplateForm.vue'), meta: { //singleInherit: true, single: true, }, }, { path: '/templateForm/:templateKey/:action', name: 'templateForm', component: () => import('@/components/form/dataTemplate/TemplateForm.vue'), meta: { //singleInherit: true,//继承属性:是否继承上一个路由的single属性。 single: true, }, }, { //数据列表预览-不显示菜单 path: '/querySqlPreview/:sqlViewId', name: 'querySqlPreview', component: () => import('@/components/form/customView/QuerySqlPreview.vue'), meta: { single: true, }, }, { //数据列表预览-显示菜单 path: '/querySqlShow/:sqlViewId/:rkey', name: 'querySqlShow', component: () => import('@/components/form/customView/QuerySqlPreview.vue'), }, { path: '/applicationModule/appTagManager', name: 'appTagManager', component: () => import('@/views/portal/AppTagManager.vue'), }, { path: '/404', name: '404', component: () => import('@/views/404'), meta: { single: true, anonymous: true, }, }, { path: '/500', name: '500', component: () => import('@/views/500'), meta: { single: true, anonymous: true, }, }, { name: 'security', path: '/security', component: () => import('@/views/system/SecuritySetting.vue'), meta: { single: true, }, }, { name: 'loading', path: '/loading', component: () => import('@/views/Loading.vue'), meta: { single: true, anonymous: true, }, }, ] var router = new Router({ base: process.env.BASE_URL, mode: 'history', routes: constantRoutes, }) const ssoRedirect = () => { if (window.ssoConfig.mode == 'cas') { let service = window.location.href localStorage.setItem('service', service) window.location.href = window.ssoConfig.url + '?service=' + service } else if (window.ssoConfig.mode == 'oauth') { if (!window.ssoConfig.clientId) { throw 'oauth模式下必须提供clientId' } const service = window.location.href localStorage.setItem('service', service) window.location.href = `${window.ssoConfig.url}?response_type=code&client_id=${window.ssoConfig.clientId}&redirect_uri=${service}` } } const originalPush = Router.prototype.push Router.prototype.push = function push(location, onResolve, onReject) { if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject) return originalPush.call(this, location).catch((err) => err) } // 移除url后面的指定参数 const removeUrlParams = (params) => { const query = window.location.search.substring(1) if (!query) { return } const vars = query.split('&') const newVars = [] for (var i = 0; i < vars.length; i++) { var pair = vars[i].split('=') if (!params.includes(pair[0])) { newVars.push(vars[i]) } } setTimeout(() => { window.history.replaceState( null, null, `${window.location.pathname}${ newVars.length > 0 ? '?' : '' }${newVars.join('&')}` ) }, 500) } router.beforeEach((to, from, next) => { // 经过路由的页面跳转才展示主页,解决单点登录跳转页面闪现问题 to.meta.isRoute=true // 添加路由白名单 const routesWhiteList = [ '/login', '/404', '/401', '/500', 'tenantLogin', 'security', ] const previewRoute = ['templatePreview','querySqlPreview','formPreview'] if(previewRoute.includes(to.name)&&from.fullPath === '/'){ from.meta.single = true } if ( routesWhiteList.indexOf(to.path) !== -1 || routesWhiteList.indexOf(to.name) !== -1 ) { next() } else { //判断是否继承上一个路由的single属性 if (to.fullPath != from.fullPath) { if (to.meta && to.meta.singleInherit) { if (!window.opener || from.fullPath !== '/') { to.meta.single = from.meta.single || false } else { let href = window.opener.location.pathname let arr = href.split('/') if (arr.length > 2) { href = arr.slice(2).join('/') } let $router = require('./router.js').default let openerRoute = $router.matcher.match(href) if (openerRoute && openerRoute.meta) { to.meta.single = !!openerRoute.meta.single } } } } if (from.fullPath == '/' && sessionStorage.beforePath) { // 李天平更改,路由为/时,把beforePath设置为/home // const beforePath = sessionStorage.getItem('beforePath') const beforePath = '/home' let $router = require('./router.js').default let historyRoute = $router.matcher.match(beforePath) if (historyRoute.meta && historyRoute.meta.single === true) { to.meta.single = !!historyRoute.meta } if (sessionStorage.beforePath.includes('/login')) { to.meta.single = false } } if (from.fullPath != '/') { let url = new URL(window.context.manage + from.fullPath) // 直接从登录页面登录,会直接保存为login页面,重定向的地址不会进入,会导致上面的single统一被设置为false // 故提取地址中的重定向地址作为上一次页面 if (url.searchParams.has('redirect')) { sessionStorage.setItem( 'beforePath', decodeURIComponent(url.searchParams.get('redirect')) ) } else { sessionStorage.setItem('beforePath', from.fullPath) } } // 1.当前为单点登录模式,且要路由到login页面,则做单点登录重定向; if ( to.name == 'login' && window.ssoConfig.mode && window.ssoConfig.mode != 'jwt' ) { // 单点登录时如果已经携带了code或者ticket时,如果是/login路径需要跳转到默认页面(解决反复跳转的问题) if ( (window.ssoConfig.mode == 'cas' || window.ssoConfig.mode == 'oauth') && (to.query.code || to.query.ticket) ) { window.location.href = window.location.href.replace('/login', '') return } else { next({ path: '/loading'}) ssoRedirect() } } if (!to.matched || to.matched.length ==0 || // 没有匹配到路由,则该页面可能为动态注册的页面,需要登录校验 (to.matched.some((record) => !record.meta.anonymous) &&!store.state.login.currentUser) || // 不是匿名页面,并且没有登录,需要登录校验 (to.query && to.query.toManager == 'toManager') ) { if (to.query && to.query.toManager == 'toManager') { store.dispatch('login/cleanCurrentUser') } let ticket = to.query.token // 2.当前已经从单点页面重定向回来了,且在url地址中携带了ticket或code; if (window.ssoConfig.mode == 'cas') { ticket = to.query.ticket } else if (window.ssoConfig.mode == 'oauth') { ticket = to.query.code } store // 3.携带ticket做用户鉴权; .dispatch('login/validAndCompletedCurrent', ticket) .then(() => { // 初始化菜单 store.dispatch('menu/actionMenus').then(() => {}) store.dispatch('menu/actionMenuBookmark') removeUrlParams(["token", "toManager"]) next() }) .catch(() => { // 4.鉴权失败时根据当前模式重定向到对应页面。 store.dispatch('login/logoutAndCleanUp').then(() => { if ( window.ssoConfig.mode && window.ssoConfig.mode != 'jwt' && !ticket ) { next({ path: '/loading'}) ssoRedirect() } else if ( !window.ssoConfig.mode || window.ssoConfig.mode == 'jwt' ) { let account = '' if (store.state.login.currentUser) { account = store.state.login.currentUser.account } next({ path: localStorage.getItem(account + 'manageLoginRoutePath') || '/login', query: { redirect: to.fullPath, }, }) } else { next({path: '/500', replace: true}) } }) }) } else { next() } } }) // 默认注册的路由、登录页、租户登录页,404、500等 const defaultRegisterRouters = [ '/login', '/404', '/401', '/500', 'tenantLogin', 'security', ] // 路由解析前,先进行动态二级路由的注册处理 router.beforeResolve((to, from, next) => { if ( defaultRegisterRouters.includes(to.path) || defaultRegisterRouters.includes(to.name) ) { next() } else { // 如果注册过路由,则不进行注册 const registRouter = store.state.menu.registRouter if (registRouter) { next() } else { // 没有注册过路由,先调用同步方法获取菜单数据。 store .dispatch('menu/actionMenus') .then((data) => { let routePathList = [] // 将固定路由的path放入集合,如果注册的时候遇到相同的path,则不进行注册 constantRoutes.forEach((r) => { routePathList.push(r.path) }) // 注册路由 convertAndAddRoute( router, JSON.parse(JSON.stringify(data)), routePathList ) // 标记为已经注册过 store.dispatch('menu/actionRegistRouter') next({...to, replace: true}) }) .catch(() => { next() }) } } }) /** * 将菜单数据转化成vue路由,并且注册路由。 * @param {*} router vue的路由对象 * @param {*} menus 菜单数据 * @param {*} routePathList 已经注册过的路由path集合 */ const convertAndAddRoute = (router, menus, routePathList) => { for (let i = menus.length - 1; i >= 0; i--) { let route = menus[i] // 有下级菜单,则递归注册 if (route.children && route.children.length) { route.children = convertAndAddRoute(router, route.children, routePathList) } delete route.children // 根据菜单层级进行判断注册。管理端目前只注册2级菜单。1级菜单是目录,3级菜单是table页签展示。无需注册 if (route.path && (route.path.split('.').length == 5 || route.path.split('.').length == 6)) { route.name = route.alias route.path = '/' + route.alias delete route.alias // path相同的,则以先注册的为准 if (routePathList.includes(route.path)) { console.error(`存在相同的路由路径[${route.path}]`) } else { route.component = (resolve) => require(['@/components/common/HtTabsComponent.vue'], resolve) router.addRoute(route) routePathList.push(route.path) } } } } export default router