diff --git a/src/modules/system/domain/menu.go b/src/modules/system/domain/menu.go index f9b666a..6ad489e 100644 --- a/src/modules/system/domain/menu.go +++ b/src/modules/system/domain/menu.go @@ -12,6 +12,7 @@ type Menu struct { RouterName string `gorm:"not null" json:"routerName"` RouterAuth uint `gorm:"not null" json:"routerAuth"` RouterHidden uint `gorm:"not null" json:"routerHidden"` + RouterCache uint `gorm:"not null" json:"routerCache"` RouterComponentPath string `gorm:"not null" json:"routerComponentPath"` } diff --git a/web/src/main.js b/web/src/main.js index ba4047e..cb25209 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -8,9 +8,8 @@ import d2Admin from '@/plugin/d2admin' import store from '@/store/index' // 菜单和路由设置 -import router from './router' -import { frameInRoutes } from '@/router/routes' -import util from '@/libs/util' +import router, {constantRoutes} from './router' + import { uniqueId } from 'lodash' import api from '@/api' @@ -22,7 +21,7 @@ Vue.use(d2Admin) * @description https://github.com/d2-projects/d2-admin/issues/209 * @param {Array} menu 原始的菜单数据 */ -function supplementPath (menu) { +export function supplementPath (menu) { return menu.map(e => ({ ...e, path: e.path || uniqueId('d2-menu-empty-'), @@ -32,10 +31,13 @@ function supplementPath (menu) { })) } +/** + * 设置菜单 + * @returns {Promise<{path: string, icon: string, title: string}[]|[{path: string, icon: string, title: string}]>} + */ async function flushMenus () { let menuData = [{ path: '/index', title: '首页', icon: 'home' }] try { - console.log('========= 设置菜单 ======== ') const menuTree = await api.queryAllMenus({}) // 权限菜单 const d2adminMenus = [] @@ -79,11 +81,6 @@ async function flushMenus () { } } -async function flushRouter(){ - const menuTree = await api.queryAllMenus({}) - // 权限路由 -} - new Vue({ router, store, @@ -93,6 +90,7 @@ new Vue({ console.log('=========================== app created ===========================') const _this = this flushMenus().then((data) => { + console.log('=========================== app handle menu ===========================') // 设置顶栏菜单 _this.$store.commit('d2admin/menu/headerSet', supplementPath([])) // 设置侧边栏菜单 @@ -100,10 +98,7 @@ new Vue({ // 初始化菜单搜索功能 _this.$store.commit('d2admin/search/init', supplementPath(data)) }) - flushRouter().then((data) => { - // 处理路由 得到每一级的路由设置 - _this.$store.commit('d2admin/page/init', frameInRoutes) - }) + _this.$store.commit('d2admin/page/init', constantRoutes) }, mounted () { console.log('=========================== app mounted ===========================') diff --git a/web/src/router/index.js b/web/src/router/index.js index 50da5de..1f2bce1 100755 --- a/web/src/router/index.js +++ b/web/src/router/index.js @@ -7,9 +7,8 @@ import 'nprogress/nprogress.css' import store from '@/store/index' import util from '@/libs/util.js' - -// 路由数据 -import routes from './routes' +import layoutHeaderAside from '@/layout/header-aside' +import api from '@/api' // fix vue-router NavigationDuplicated const VueRouterPush = VueRouter.prototype.push @@ -23,47 +22,145 @@ VueRouter.prototype.replace = function replace (location) { Vue.use(VueRouter) -// 导出路由 在 main.js 里使用 -const router = new VueRouter({ +// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载 +const _import = require('@/libs/util.import.' + process.env.NODE_ENV) + +/** + * @description 创建在 layout 中显示的路由设置 + * @param {Array} routes 动态路由设置 + */ +export function createRoutesInLayout (routes = []) { + return [ + { + path: '/', + redirect: { name: 'index' }, + component: layoutHeaderAside, + children: [ + { path: 'index', name: 'index', meta: { title: '首页', auth: true }, component: _import('system/index') }, + { path: 'log', name: 'log', meta: { title: '前端日志', auth: true }, component: _import('system/log') }, + ...routes + ] + } + ] +} + +// 在 layout 之外显示的路由 +export const routesOutLayout = [ + // 刷新页面 + { path: '/refresh', name: 'refresh', component: _import('system/function/refresh'), hidden: true }, + // 页面重定向 + { path: '/redirect/:route*', name: 'redirect', component: _import('system/function/redirect'), hidden: true }, + // 登陆页面 + { path: '/login', name: 'login', component: _import('system/login'), hidden: true }, + // 未知页面 + { path: '*', name: '404', component: _import('system/error/404'), hidden: true } +] + +// 默认的路由 +export const constantRoutes = createRoutesInLayout().concat(routesOutLayout) + +/** + * @description 创建路由 + * @param {Array} routes 路由设置 + */ +const createRouter = (routes = []) => new VueRouter({ + scrollBehavior: () => ({ y: 0 }), routes }) +// 导出路由 在 main.js 里使用 +const router = createRouter(constantRoutes) + +/** + * @description 重新设置路由 + * @param {Array} routes 额外追加的路由 + */ +export function resetRouter (routes = []) { + router.matcher = createRouter(routes).matcher +} + +function buildRouter (menuItem) { + return { + path: menuItem.routerPath, + name: menuItem.routerName, + meta: { + title: menuItem.menuTitle, + auth: menuItem.routerAuth === 1, + hidden: menuItem.routerHidden === 1, + cache: menuItem.routerHidden === 1 + }, + component: _import(menuItem.routerComponentPath) + } +} +async function flushRouter () { + const menuTree = await api.queryAllMenus({}) + // 权限路由, 全是一级路由 + const routerData = [] + for (const menuItem of menuTree) { + const children = menuItem.children + if (children && children.length > 0) { + for (const childMenuItem of children) { + if (childMenuItem.routerPath && childMenuItem.routerComponentPath) { + routerData.push(buildRouter(childMenuItem)) + } + } + } + } + return routerData +} + /** * 路由拦截 * 权限验证 */ router.beforeEach(async (to, from, next) => { - // 确认已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201 - await store.dispatch('d2admin/page/isLoaded') - // 确认已经加载组件尺寸设置 https://github.com/d2-projects/d2-admin/issues/198 - await store.dispatch('d2admin/size/isLoaded') // 进度条 NProgress.start() - // 关闭搜索面板 - store.commit('d2admin/search/set', false) - // 验证当前路由所有的匹配中是否需要有登录验证的 - if (to.matched.some(r => r.meta.auth)) { - // 这里暂时将cookie里是否存有token作为验证是否登录的条件 - // 请根据自身业务需要修改 - const token = util.cookies.get('token') - if (token && token !== 'undefined') { - next() - } else { - // 没有登录的时候跳转到登录界面 - // 携带上登陆成功之后需要跳转的页面完整路径 - next({ - name: 'login', - query: { - redirect: to.fullPath - } + try { + // 关闭搜索面板 + store.commit('d2admin/search/set', false) + // 确认已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201 + await store.dispatch('d2admin/page/isLoaded') + // 确认已经加载组件尺寸设置 https://github.com/d2-projects/d2-admin/issues/198 + await store.dispatch('d2admin/size/isLoaded') + const isLoadRouter = util.cookies.get('isLoadRouter') + if (isLoadRouter !== 'true') { + console.log('=========================== app router loading ===========================') + // 加载动态路由 + resetRouter(constantRoutes) + flushRouter().then((data) => { + // 处理路由 得到每一级的路由设置 + const routers = [...constantRoutes] + routers[0].children = routers[0].children.concat(data) + store.commit('d2admin/page/init', routers) + util.cookies.set('isLoadRouter', 'true') }) - // https://github.com/d2-projects/d2-admin/issues/138 - NProgress.done() } - } else { - // 不需要身份校验 直接通过 - next() + // 验证当前路由所有的匹配中是否需要有登录验证的 + if (to.matched.some(r => r.meta.auth)) { + // 这里暂时将cookie里是否存有token作为验证是否登录的条件 + // 请根据自身业务需要修改 + const token = util.cookies.get('token') + if (token && token !== 'undefined') { + next() + } else { + // 没有登录的时候跳转到登录界面 + // 携带上登陆成功之后需要跳转的页面完整路径 + next({ + name: 'login', + query: { + redirect: to.fullPath + } + }) + } + } else { + // 不需要身份校验 直接通过 + next() + } + } catch (e) { + next(false) } + NProgress.done() }) router.afterEach(to => { diff --git a/web/src/router/routes.js b/web/src/router/routes.js deleted file mode 100644 index 7e3e934..0000000 --- a/web/src/router/routes.js +++ /dev/null @@ -1,113 +0,0 @@ -import layoutHeaderAside from '@/layout/header-aside' - -// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载 -const _import = require('@/libs/util.import.' + process.env.NODE_ENV) - -console.log('================= 刷新会导致路由重新加载') - -/** - * 在主框架内显示 - */ -const frameIn = [ - { - path: '/', - redirect: { name: 'index' }, - component: layoutHeaderAside, - children: [ - // 首页 - { - path: 'index', - name: 'index', - meta: { - auth: true - }, - component: _import('system/index') - }, - // 系统 前端日志 - { - path: 'log', - name: 'log', - meta: { - title: '前端日志', - auth: true - }, - component: _import('system/log') - }, - // 刷新页面 必须保留 - { - path: 'refresh', - name: 'refresh', - hidden: true, - component: _import('system/function/refresh') - }, - // 页面重定向 必须保留 - { - path: 'redirect/:route*', - name: 'redirect', - hidden: true, - component: _import('system/function/redirect') - }, - // 演示页面 - { - path: 'page1', - name: 'page1', - meta: { - title: '页面 1', - auth: true - }, - component: _import('demo/page1') - }, - { - path: 'page2', - name: 'page2', - meta: { - title: '页面 2', - auth: true - }, - component: _import('demo/page2') - }, - { - path: 'page3', - name: 'page3', - meta: { - title: '页面 3', - auth: true - }, - component: _import('demo/page3') - } - ] - } -] - -/** - * 在主框架之外显示 - */ -const frameOut = [ - // 登录 - { - path: '/login', - name: 'login', - component: _import('system/login') - } -] - -/** - * 错误页面 - */ -const errorPage = [ - { - path: '*', - name: '404', - component: _import('system/error/404') - } -] - -// 导出需要显示菜单的 -export const frameInRoutes = frameIn - -// 重新组织后导出 -export default [ - ...frameIn, - ...frameOut, - ...errorPage -] diff --git a/web/src/store/modules/d2admin/modules/page.js b/web/src/store/modules/d2admin/modules/page.js index a051450..71d2ffe 100644 --- a/web/src/store/modules/d2admin/modules/page.js +++ b/web/src/store/modules/d2admin/modules/page.js @@ -369,6 +369,7 @@ export default { state.current = fullPath }, /** + * 路由池 * @class pool * @description 保存 pool (候选池) * @param {Object} state state @@ -378,6 +379,7 @@ export default { const pool = [] const push = function (routes) { routes.forEach(route => { + console.log('=========================== app handle router ===========================', route) if (route.children && route.children.length > 0) { push(route.children) } else {