From e671cba3b06e89a6866a922f64d7be5425d92734 Mon Sep 17 00:00:00 2001 From: Revantant Date: Thu, 11 Jul 2019 14:45:58 +0800 Subject: [PATCH 1/6] feat add routes mock --- mock/index.js | 6 +- mock/{role/index.js => role.js} | 17 +- mock/role/routes.js | 525 -------------------------------- mock/route.js | 37 +++ src/api/route.js | 8 + src/main.js | 6 +- src/store/modules/permission.js | 38 ++- src/styles/sidebar.scss | 1 + vue.config.js | 7 +- 9 files changed, 87 insertions(+), 558 deletions(-) rename mock/{role/index.js => role.js} (80%) delete mode 100644 mock/role/routes.js create mode 100644 mock/route.js create mode 100644 src/api/route.js diff --git a/mock/index.js b/mock/index.js index 6907e861..7b3e6788 100644 --- a/mock/index.js +++ b/mock/index.js @@ -3,6 +3,7 @@ import { param2Obj } from '../src/utils' import user from './user' import role from './role' +import route from './route' import article from './article' import search from './remote-search' @@ -10,7 +11,8 @@ const mocks = [ ...user, ...role, ...article, - ...search + ...search, + ...route ] // for front mock @@ -45,7 +47,7 @@ export function mockXHR() { } else { result = respond } - return Mock.mock(result) + return result } } diff --git a/mock/role/index.js b/mock/role.js similarity index 80% rename from mock/role/index.js rename to mock/role.js index 39148076..0e382993 100644 --- a/mock/role/index.js +++ b/mock/role.js @@ -1,8 +1,5 @@ import Mock from 'mockjs' -import { deepClone } from '../../src/utils/index.js' -import { asyncRoutes, constantRoutes } from './routes.js' - -const routes = deepClone([...constantRoutes, ...asyncRoutes]) +import { routes } from './route' const roles = [ { @@ -36,18 +33,6 @@ const roles = [ ] export default [ - // mock get all routes form server - { - url: '/routes', - type: 'get', - response: _ => { - return { - code: 20000, - data: routes - } - } - }, - // mock get all roles form server { url: '/roles', diff --git a/mock/role/routes.js b/mock/role/routes.js deleted file mode 100644 index d718919c..00000000 --- a/mock/role/routes.js +++ /dev/null @@ -1,525 +0,0 @@ -// Just a mock data - -export const constantRoutes = [ - { - path: '/redirect', - component: 'layout/Layout', - hidden: true, - children: [ - { - path: '/redirect/:path*', - component: 'views/redirect/index' - } - ] - }, - { - path: '/login', - component: 'views/login/index', - hidden: true - }, - { - path: '/auth-redirect', - component: 'views/login/auth-redirect', - hidden: true - }, - { - path: '/404', - component: 'views/error-page/404', - hidden: true - }, - { - path: '/401', - component: 'views/error-page/401', - hidden: true - }, - { - path: '', - component: 'layout/Layout', - redirect: 'dashboard', - children: [ - { - path: 'dashboard', - component: 'views/dashboard/index', - name: 'Dashboard', - meta: { title: 'Dashboard', icon: 'dashboard', affix: true } - } - ] - }, - { - path: '/documentation', - component: 'layout/Layout', - children: [ - { - path: 'index', - component: 'views/documentation/index', - name: 'Documentation', - meta: { title: 'Documentation', icon: 'documentation', affix: true } - } - ] - }, - { - path: '/guide', - component: 'layout/Layout', - redirect: '/guide/index', - children: [ - { - path: 'index', - component: 'views/guide/index', - name: 'Guide', - meta: { title: 'Guide', icon: 'guide', noCache: true } - } - ] - } -] - -export const asyncRoutes = [ - { - path: '/permission', - component: 'layout/Layout', - redirect: '/permission/index', - alwaysShow: true, - meta: { - title: 'Permission', - icon: 'lock', - roles: ['admin', 'editor'] - }, - children: [ - { - path: 'page', - component: 'views/permission/page', - name: 'PagePermission', - meta: { - title: 'Page Permission', - roles: ['admin'] - } - }, - { - path: 'directive', - component: 'views/permission/directive', - name: 'DirectivePermission', - meta: { - title: 'Directive Permission' - } - }, - { - path: 'role', - component: 'views/permission/role', - name: 'RolePermission', - meta: { - title: 'Role Permission', - roles: ['admin'] - } - } - ] - }, - - { - path: '/icon', - component: 'layout/Layout', - children: [ - { - path: 'index', - component: 'views/icons/index', - name: 'Icons', - meta: { title: 'Icons', icon: 'icon', noCache: true } - } - ] - }, - - { - path: '/components', - component: 'layout/Layout', - redirect: 'noRedirect', - name: 'ComponentDemo', - meta: { - title: 'Components', - icon: 'component' - }, - children: [ - { - path: 'tinymce', - component: 'views/components-demo/tinymce', - name: 'TinymceDemo', - meta: { title: 'Tinymce' } - }, - { - path: 'markdown', - component: 'views/components-demo/markdown', - name: 'MarkdownDemo', - meta: { title: 'Markdown' } - }, - { - path: 'json-editor', - component: 'views/components-demo/json-editor', - name: 'JsonEditorDemo', - meta: { title: 'Json Editor' } - }, - { - path: 'split-pane', - component: 'views/components-demo/split-pane', - name: 'SplitpaneDemo', - meta: { title: 'SplitPane' } - }, - { - path: 'avatar-upload', - component: 'views/components-demo/avatar-upload', - name: 'AvatarUploadDemo', - meta: { title: 'Avatar Upload' } - }, - { - path: 'dropzone', - component: 'views/components-demo/dropzone', - name: 'DropzoneDemo', - meta: { title: 'Dropzone' } - }, - { - path: 'sticky', - component: 'views/components-demo/sticky', - name: 'StickyDemo', - meta: { title: 'Sticky' } - }, - { - path: 'count-to', - component: 'views/components-demo/count-to', - name: 'CountToDemo', - meta: { title: 'Count To' } - }, - { - path: 'mixin', - component: 'views/components-demo/mixin', - name: 'ComponentMixinDemo', - meta: { title: 'componentMixin' } - }, - { - path: 'back-to-top', - component: 'views/components-demo/back-to-top', - name: 'BackToTopDemo', - meta: { title: 'Back To Top' } - }, - { - path: 'drag-dialog', - component: 'views/components-demo/drag-dialog', - name: 'DragDialogDemo', - meta: { title: 'Drag Dialog' } - }, - { - path: 'drag-select', - component: 'views/components-demo/drag-select', - name: 'DragSelectDemo', - meta: { title: 'Drag Select' } - }, - { - path: 'dnd-list', - component: 'views/components-demo/dnd-list', - name: 'DndListDemo', - meta: { title: 'Dnd List' } - }, - { - path: 'drag-kanban', - component: 'views/components-demo/drag-kanban', - name: 'DragKanbanDemo', - meta: { title: 'Drag Kanban' } - } - ] - }, - { - path: '/charts', - component: 'layout/Layout', - redirect: 'noRedirect', - name: 'Charts', - meta: { - title: 'Charts', - icon: 'chart' - }, - children: [ - { - path: 'keyboard', - component: 'views/charts/keyboard', - name: 'KeyboardChart', - meta: { title: 'Keyboard Chart', noCache: true } - }, - { - path: 'line', - component: 'views/charts/line', - name: 'LineChart', - meta: { title: 'Line Chart', noCache: true } - }, - { - path: 'mixchart', - component: 'views/charts/mixChart', - name: 'MixChart', - meta: { title: 'Mix Chart', noCache: true } - } - ] - }, - { - path: '/nested', - component: 'layout/Layout', - redirect: '/nested/menu1/menu1-1', - name: 'Nested', - meta: { - title: 'Nested', - icon: 'nested' - }, - children: [ - { - path: 'menu1', - component: 'views/nested/menu1/index', - name: 'Menu1', - meta: { title: 'Menu1' }, - redirect: '/nested/menu1/menu1-1', - children: [ - { - path: 'menu1-1', - component: 'views/nested/menu1/menu1-1', - name: 'Menu1-1', - meta: { title: 'Menu1-1' } - }, - { - path: 'menu1-2', - component: 'views/nested/menu1/menu1-2', - name: 'Menu1-2', - redirect: '/nested/menu1/menu1-2/menu1-2-1', - meta: { title: 'Menu1-2' }, - children: [ - { - path: 'menu1-2-1', - component: 'views/nested/menu1/menu1-2/menu1-2-1', - name: 'Menu1-2-1', - meta: { title: 'Menu1-2-1' } - }, - { - path: 'menu1-2-2', - component: 'views/nested/menu1/menu1-2/menu1-2-2', - name: 'Menu1-2-2', - meta: { title: 'Menu1-2-2' } - } - ] - }, - { - path: 'menu1-3', - component: 'views/nested/menu1/menu1-3', - name: 'Menu1-3', - meta: { title: 'Menu1-3' } - } - ] - }, - { - path: 'menu2', - name: 'Menu2', - component: 'views/nested/menu2/index', - meta: { title: 'Menu2' } - } - ] - }, - - { - path: '/example', - component: 'layout/Layout', - redirect: '/example/list', - name: 'Example', - meta: { - title: 'Example', - icon: 'example' - }, - children: [ - { - path: 'create', - component: 'views/example/create', - name: 'CreateArticle', - meta: { title: 'Create Article', icon: 'edit' } - }, - { - path: 'edit/:id(\\d+)', - component: 'views/example/edit', - name: 'EditArticle', - meta: { title: 'Edit Article', noCache: true }, - hidden: true - }, - { - path: 'list', - component: 'views/example/list', - name: 'ArticleList', - meta: { title: 'Article List', icon: 'list' } - } - ] - }, - - { - path: '/tab', - component: 'layout/Layout', - children: [ - { - path: 'index', - component: 'views/tab/index', - name: 'Tab', - meta: { title: 'Tab', icon: 'tab' } - } - ] - }, - - { - path: '/error', - component: 'layout/Layout', - redirect: 'noRedirect', - name: 'ErrorPages', - meta: { - title: 'Error Pages', - icon: '404' - }, - children: [ - { - path: '401', - component: 'views/error-page/401', - name: 'Page401', - meta: { title: 'Page 401', noCache: true } - }, - { - path: '404', - component: 'views/error-page/404', - name: 'Page404', - meta: { title: 'Page 404', noCache: true } - } - ] - }, - - { - path: '/error-log', - component: 'layout/Layout', - redirect: 'noRedirect', - children: [ - { - path: 'log', - component: 'views/error-log/index', - name: 'ErrorLog', - meta: { title: 'Error Log', icon: 'bug' } - } - ] - }, - - { - path: '/excel', - component: 'layout/Layout', - redirect: '/excel/export-excel', - name: 'Excel', - meta: { - title: 'Excel', - icon: 'excel' - }, - children: [ - { - path: 'export-excel', - component: 'views/excel/export-excel', - name: 'ExportExcel', - meta: { title: 'Export Excel' } - }, - { - path: 'export-selected-excel', - component: 'views/excel/select-excel', - name: 'SelectExcel', - meta: { title: 'Select Excel' } - }, - { - path: 'export-merge-header', - component: 'views/excel/merge-header', - name: 'MergeHeader', - meta: { title: 'Merge Header' } - }, - { - path: 'upload-excel', - component: 'views/excel/upload-excel', - name: 'UploadExcel', - meta: { title: 'Upload Excel' } - } - ] - }, - - { - path: '/zip', - component: 'layout/Layout', - redirect: '/zip/download', - alwaysShow: true, - meta: { title: 'Zip', icon: 'zip' }, - children: [ - { - path: 'download', - component: 'views/zip/index', - name: 'ExportZip', - meta: { title: 'Export Zip' } - } - ] - }, - - { - path: '/pdf', - component: 'layout/Layout', - redirect: '/pdf/index', - children: [ - { - path: 'index', - component: 'views/pdf/index', - name: 'PDF', - meta: { title: 'PDF', icon: 'pdf' } - } - ] - }, - { - path: '/pdf/download', - component: 'views/pdf/download', - hidden: true - }, - - { - path: '/theme', - component: 'layout/Layout', - redirect: 'noRedirect', - children: [ - { - path: 'index', - component: 'views/theme/index', - name: 'Theme', - meta: { title: 'Theme', icon: 'theme' } - } - ] - }, - - { - path: '/clipboard', - component: 'layout/Layout', - redirect: 'noRedirect', - children: [ - { - path: 'index', - component: 'views/clipboard/index', - name: 'ClipboardDemo', - meta: { title: 'Clipboard Demo', icon: 'clipboard' } - } - ] - }, - - { - path: '/i18n', - component: 'layout/Layout', - children: [ - { - path: 'index', - component: 'views/i18n-demo/index', - name: 'I18n', - meta: { title: 'I18n', icon: 'international' } - } - ] - }, - - { - path: 'external-link', - component: 'layout/Layout', - children: [ - { - path: 'https://github.com/PanJiaChen/vue-element-admin', - meta: { title: 'External Link', icon: 'link' } - } - ] - }, - - { path: '*', redirect: '/404', hidden: true } -] diff --git a/mock/route.js b/mock/route.js new file mode 100644 index 00000000..d36c6fcc --- /dev/null +++ b/mock/route.js @@ -0,0 +1,37 @@ +// Just a mock data +import { asyncRoutes } from '../src/router' + +// 将asyncRoutes的componet转换为路径字符串,以便导入数据库 +const mapAsyncRoutes = asyncRoutes => { + return asyncRoutes.map(route => { + const tmp = { ...route } + if (tmp.component) { + if (tmp.component.__file) { + tmp.component = tmp.component.__file.slice(4) + } else if (tmp.component instanceof Function) { + tmp.component = /\/\*\!.*\*\//.exec(String(tmp.component))[0].split(' ')[1].slice(2) + } + console.log(tmp.component) + } + if (tmp.children && tmp.children.length) { + tmp.children = mapAsyncRoutes(tmp.children) + } + return tmp + }) +} +const asyncRoutesMap = mapAsyncRoutes(asyncRoutes) + +export { asyncRoutesMap as routes } +export default [ + // mock get all routes form server + { + url: '/routes', + type: 'get', + response: _ => { + return { + code: 20000, + data: asyncRoutesMap + } + } + } +] diff --git a/src/api/route.js b/src/api/route.js new file mode 100644 index 00000000..8cd35e69 --- /dev/null +++ b/src/api/route.js @@ -0,0 +1,8 @@ +import request from '@/utils/request' + +export function getRoutes() { + return request({ + url: '/routes', + method: 'get' + }) +} diff --git a/src/main.js b/src/main.js index ef07f389..6ad980e6 100644 --- a/src/main.js +++ b/src/main.js @@ -28,9 +28,9 @@ import * as filters from './filters' // global filters * please remove it before going online! ! ! */ import { mockXHR } from '../mock' -if (process.env.NODE_ENV === 'production') { - mockXHR() -} +// if (process.env.NODE_ENV === 'production') { +mockXHR() +// } Vue.use(Element, { size: Cookies.get('size') || 'medium' // set element-ui default size diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js index aeb5ee53..b01435cc 100644 --- a/src/store/modules/permission.js +++ b/src/store/modules/permission.js @@ -1,5 +1,6 @@ -import { asyncRoutes, constantRoutes } from '@/router' - +import { constantRoutes } from '@/router' +import { getRoutes } from '@/api/route' +// const _import = path => import('@/views/' + path) /** * Use meta.role to determine if the current user has permission * @param roles @@ -18,6 +19,21 @@ function hasPermission(roles, route) { * @param routes asyncRoutes * @param roles */ + +export function mapAsyncRoutes(routes) { + return routes.map(route => { + const tmp = { ...route } + if (typeof tmp.component === 'string') { + const path = tmp.component + tmp.component = () => import(`@/${path}`) + } + if (tmp.children && tmp.children.length) { + tmp.children = mapAsyncRoutes(tmp.children) + } + return tmp + }) +} + export function filterAsyncRoutes(routes, roles) { const res = [] @@ -50,13 +66,17 @@ const actions = { generateRoutes({ commit }, roles) { return new Promise(resolve => { let accessedRoutes - if (roles.includes('admin')) { - accessedRoutes = asyncRoutes || [] - } else { - accessedRoutes = filterAsyncRoutes(asyncRoutes, roles) - } - commit('SET_ROUTES', accessedRoutes) - resolve(accessedRoutes) + getRoutes().then(res => { + const asyncRoutes = res.data + if (roles.includes('admin')) { + accessedRoutes = mapAsyncRoutes(asyncRoutes || []) + } else { + accessedRoutes = mapAsyncRoutes(filterAsyncRoutes(asyncRoutes, roles)) + debugger + } + commit('SET_ROUTES', accessedRoutes) + resolve(accessedRoutes) + }) }) } } diff --git a/src/styles/sidebar.scss b/src/styles/sidebar.scss index 3dad4c39..4d6f2a0a 100644 --- a/src/styles/sidebar.scss +++ b/src/styles/sidebar.scss @@ -1,3 +1,4 @@ +@import "./variables.scss"; #app { .main-container { diff --git a/vue.config.js b/vue.config.js index 4a5cd438..de0e042d 100644 --- a/vue.config.js +++ b/vue.config.js @@ -43,8 +43,9 @@ module.exports = { ['^' + process.env.VUE_APP_BASE_API]: '' } } - }, - after: require('./mock/mock-server.js') + } + // 如果启用mock-server需要为node配置一下webpack中@的alias + // after: require('./mock/mock-server.js') }, configureWebpack: { // provide the app's title in webpack's name field, so that @@ -101,7 +102,7 @@ module.exports = { .plugin('ScriptExtHtmlWebpackPlugin') .after('html') .use('script-ext-html-webpack-plugin', [{ - // `runtime` must same as runtimeChunk name. default is `runtime` + // `runtime` must same as runtimeChunk name. default is `runtime` inline: /runtime\..*\.js$/ }]) .end() From 55a2deace8176231a3957aa2ead0b2631d0c870f Mon Sep 17 00:00:00 2001 From: Revantant Date: Thu, 11 Jul 2019 15:50:53 +0800 Subject: [PATCH 2/6] feat import routes --- mock/route.js | 10 +++++++ src/api/route.js | 8 ++++++ src/router/index.js | 9 +++++++ src/views/permission/route.vue | 49 ++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 src/views/permission/route.vue diff --git a/mock/route.js b/mock/route.js index d36c6fcc..38cd2e97 100644 --- a/mock/route.js +++ b/mock/route.js @@ -33,5 +33,15 @@ export default [ data: asyncRoutesMap } } + }, + { + url: '/routes', + type: 'put', + response: _ => { + return { + code: 20000, + data: {} + } + } } ] diff --git a/src/api/route.js b/src/api/route.js index 8cd35e69..9891b64d 100644 --- a/src/api/route.js +++ b/src/api/route.js @@ -6,3 +6,11 @@ export function getRoutes() { method: 'get' }) } + +export function importRoutes(data) { + return request({ + url: '/routes', + method: 'put', + data + }) +} diff --git a/src/router/index.js b/src/router/index.js index fbe8ad25..559de4fd 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -167,6 +167,15 @@ export const asyncRoutes = [ title: 'Role Permission', roles: ['admin'] } + }, + { + path: 'path', + component: () => import('@/views/permission/route'), + name: 'Route', + meta: { + title: 'Route', + roles: ['admin'] + } } ] }, diff --git a/src/views/permission/route.vue b/src/views/permission/route.vue new file mode 100644 index 00000000..8909b6f0 --- /dev/null +++ b/src/views/permission/route.vue @@ -0,0 +1,49 @@ + + + + From 13f597b3ddc02f864c9a08ffb64f920fa2aa50b1 Mon Sep 17 00:00:00 2001 From: Revantant Date: Mon, 15 Jul 2019 18:12:03 +0800 Subject: [PATCH 3/6] fix allow route management only in dev env --- src/router/index.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/router/index.js b/src/router/index.js index 559de4fd..ed9929e4 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -167,15 +167,6 @@ export const asyncRoutes = [ title: 'Role Permission', roles: ['admin'] } - }, - { - path: 'path', - component: () => import('@/views/permission/route'), - name: 'Route', - meta: { - title: 'Route', - roles: ['admin'] - } } ] }, @@ -404,6 +395,26 @@ const createRouter = () => new Router({ const router = createRouter() +if (process.env.NODE_ENV === 'development') { + router.addRoutes([ + { + path: '/', + component: Layout, + redirect: '/dashboard', + children: [ + { + path: 'route', + component: () => import('@/views/permission/route'), + name: 'Route', + meta: { + title: 'Route', + roles: ['admin'] + } + } + ] + }]) +} + // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465 export function resetRouter() { const newRouter = createRouter() From 6082739de298c698f5bad0033493996d01af2bef Mon Sep 17 00:00:00 2001 From: Revantant Date: Wed, 17 Jul 2019 16:13:49 +0800 Subject: [PATCH 4/6] fix importRoutes api --- src/views/permission/route.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/permission/route.vue b/src/views/permission/route.vue index 8909b6f0..2c5ddbba 100644 --- a/src/views/permission/route.vue +++ b/src/views/permission/route.vue @@ -35,7 +35,7 @@ export default { }) }, handleImport() { - Route.importRoutes(routes).then(res => { + Route.importRoutes({ routes }).then(res => { this.$message({ type: 'success', message: 'Import Success' From 40e6ec5b6a2b2fcfebe14c95115cedcd47bcf9b3 Mon Sep 17 00:00:00 2001 From: Revantant Date: Wed, 17 Jul 2019 16:54:28 +0800 Subject: [PATCH 5/6] revoke --- mock/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mock/index.js b/mock/index.js index 7b3e6788..1b3b6173 100644 --- a/mock/index.js +++ b/mock/index.js @@ -47,7 +47,7 @@ export function mockXHR() { } else { result = respond } - return result + return Mock.mock(result) } } From ea153c1a54f8c9b8ba553b7f21cb41e77d919453 Mon Sep 17 00:00:00 2001 From: Revantant Date: Wed, 17 Jul 2019 16:55:08 +0800 Subject: [PATCH 6/6] fix row key duplicate --- mock/route.js | 10 +++++++++- src/views/permission/route.vue | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mock/route.js b/mock/route.js index 38cd2e97..1934ec47 100644 --- a/mock/route.js +++ b/mock/route.js @@ -19,6 +19,14 @@ const mapAsyncRoutes = asyncRoutes => { return tmp }) } +const mapRouteId = routes => { + return routes.map(route => { + const tmp = { ...route } + tmp.id = Math.random() + tmp.children && tmp.children.length && (tmp.children = mapRouteId(tmp.children)) + return tmp + }) +} const asyncRoutesMap = mapAsyncRoutes(asyncRoutes) export { asyncRoutesMap as routes } @@ -30,7 +38,7 @@ export default [ response: _ => { return { code: 20000, - data: asyncRoutesMap + data: mapRouteId(asyncRoutesMap) } } }, diff --git a/src/views/permission/route.vue b/src/views/permission/route.vue index 2c5ddbba..577df344 100644 --- a/src/views/permission/route.vue +++ b/src/views/permission/route.vue @@ -2,7 +2,7 @@
Import Routes - +