From 806b72542ffeaec2170ad41d588b3530e218cc11 Mon Sep 17 00:00:00 2001 From: 321zhangjvzhi Date: Wed, 24 Apr 2024 17:25:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eslintrc/.eslintrc-auto-import.json | 3 +- package.json | 1 + src/api/user.ts | 1 + src/hooks/use-permission.ts | 27 ++++++-- src/permission.ts | 58 ++++++++-------- src/router/index.ts | 11 ++- src/router/modules/basic-demo.ts | 100 ---------------------------- src/router/modules/charts.ts | 42 ------------ src/router/modules/directive.ts | 48 ------------- src/router/modules/excel.ts | 23 ------- src/router/modules/guid.ts | 14 ---- src/router/modules/other.ts | 35 ---------- src/router/modules/rich-text.ts | 17 ----- src/router/modules/table.ts | 23 ------- src/views/mqtt/index.vue | 99 +++++++++++++++++++++++++++ typings/auto-imports.d.ts | 1 + 16 files changed, 163 insertions(+), 340 deletions(-) delete mode 100644 src/router/modules/basic-demo.ts delete mode 100644 src/router/modules/charts.ts delete mode 100644 src/router/modules/directive.ts delete mode 100644 src/router/modules/excel.ts delete mode 100644 src/router/modules/guid.ts delete mode 100644 src/router/modules/other.ts delete mode 100644 src/router/modules/rich-text.ts delete mode 100644 src/router/modules/table.ts create mode 100644 src/views/mqtt/index.vue diff --git a/eslintrc/.eslintrc-auto-import.json b/eslintrc/.eslintrc-auto-import.json index f8acbd2..08cb463 100644 --- a/eslintrc/.eslintrc-auto-import.json +++ b/eslintrc/.eslintrc-auto-import.json @@ -114,6 +114,7 @@ "Ref": true, "VNode": true, "WritableComputedRef": true, - "toValue": true + "toValue": true, + "filterRouters": true } } diff --git a/package.json b/package.json index f346008..948b36a 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "js-error-collection": "^1.0.8", "mitt": "3.0.1", "moment-mini": "2.29.4", + "mqtt": "^5.5.0", "nprogress": "0.2.0", "only-allow": "^1.2.1", "path-browserify": "^1.0.1", diff --git a/src/api/user.ts b/src/api/user.ts index eb882b0..c6e055e 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -19,6 +19,7 @@ export interface IUserRole { roleId: number roleName: string roleType: string + type: string } export async function getMyInfo(): Promise { diff --git a/src/hooks/use-permission.ts b/src/hooks/use-permission.ts index 4e07779..25693bf 100644 --- a/src/hooks/use-permission.ts +++ b/src/hooks/use-permission.ts @@ -1,22 +1,36 @@ -import NProgress from 'nprogress' -import type { RouteRecordName } from 'vue-router' -import Layout from '@/layout/default/index.vue' import router, { asyncRoutes, constantRoutes } from '@/router' -import 'nprogress/nprogress.css' import { useBasicStore } from '@/store/basic' +import NProgress from 'nprogress' +import 'nprogress/nprogress.css' +import type { RouteRecordName } from 'vue-router' import { isArray } from 'xe-utils' +import type { RouterTypes } from '~/basic' + +export function filterRouters< + T extends { + meta?: { roles?: string[] } + children?: T[] + } +>(menuList: T[], role: string) { + const out = menuList.filter((it) => it.meta?.roles?.includes(role) ?? true) + for (const t of out) { + if (t.children) filterRouters(t.children, role) + } + menuList.length = 0 + menuList.push(...out) +} //从数据库设置文本路由 export function setRouterFromDatabase(menuList) { const basicStore = useBasicStore() - const accessRoutes = menuList + const accessRoutes: RouterTypes = menuList // @ts-ignore const views = import.meta.glob('../views/**/*.vue') as Record Promise> function scanRouter(items: any[]) { for (const item of items) { - if (item.component === 'Layout') item.component = async () => Layout + if (item.component === 'Layout') item.component = () => import('@/layout/default/index.vue') else if (typeof item.component === 'string') { let url: string = item.component if (url.startsWith('@/')) { @@ -39,6 +53,7 @@ export function setRouterFromDatabase(menuList) { } scanRouter(accessRoutes) + accessRoutes.forEach((route) => router.addRoute(route)) asyncRoutes.forEach((item) => router.addRoute(item)) basicStore.setFilterAsyncRoutes(accessRoutes) diff --git a/src/permission.ts b/src/permission.ts index 139baea..ee4043b 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -1,13 +1,12 @@ -import router from '@/router' -import { progressClose, progressStart, setRouterFromDatabase } from '@/hooks/use-permission' +import router, { roleRoutes } from '@/router' +import { filterRouters, progressClose, progressStart, setRouterFromDatabase } from '@/hooks/use-permission' import { useBasicStore } from '@/store/basic' import { getMyInfo, getMyRole } from '@/api/user' import { langTitle } from '@/hooks/use-common' -import { getRouterList } from '@/api/router' //路由进入前拦截 //to:将要进入的页面 vue-router4.0 不推荐使用next() -const whiteList = ['/login', '/404', '/401', '/500'] // no redirect whitelist +const whiteList = ['/mqtt', '/login', '/404', '/401', '/500'] // no redirect whitelist router.beforeEach(async (to) => { progressStart() document.title = langTitle(to.meta?.title) // i18 page title @@ -15,34 +14,35 @@ router.beforeEach(async (to) => { if (to.path === '/500') { return true } + if (to.path === '/login') { + return true + } //1.判断token if (basicStore.token) { - if (to.path === '/login') { - return '/' - } else { - //2.判断是否获取用户信息 - if (!basicStore.getUserInfo) { - try { - const [userData, userRole] = await Promise.all([getMyInfo(), getMyRole()]) - const routes = await getRouterList({ roleId: userRole.roleId }) - //3.动态路由权限筛选 - setRouterFromDatabase(routes) - //4.保存用户信息到store - basicStore.setUserInfo({ - userInfo: userData, - roles: [userRole.roleType], - codes: [userRole.roleId] - }) - //5.再次执行路由跳转 - return { ...to, replace: true } - } catch (e) { - console.error(`route permission error${e}`) - progressClose() - return `/500?redirect=${to.path}` - } - } else { - return true + //2.判断是否获取用户信息 + if (!basicStore.getUserInfo) { + try { + const [userData, userRole] = await Promise.all([getMyInfo(), getMyRole()]) + //3.保存用户信息到store + basicStore.setUserInfo({ + userInfo: userData, + roles: [userRole.roleType], + codes: [userRole.roleId] + }) + //const routes = await getRouterList({ roleId: userRole.roleId }) + const routes = roleRoutes + filterRouters(routes as any, userRole.type) + //4.动态路由权限筛选 + setRouterFromDatabase(routes) + //5.再次执行路由跳转 + return { ...to, replace: true } + } catch (e) { + console.error(`route permission error${e}`) + progressClose() + return `/500?redirect=${to.path}` } + } else { + return true } } else { if (!whiteList.includes(to.path)) { diff --git a/src/router/index.ts b/src/router/index.ts index 5834a94..29d307a 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,5 +1,5 @@ import { createRouter, createWebHistory } from 'vue-router' -import type { RouterTypes } from '~/basic' +import type { BootstrapIcons, RouterTypes } from '~/basic' import settings from '@/settings' import { userRoute } from '@/router/modules/user' const Layout = () => import('@/layout/default/index.vue') @@ -39,11 +39,18 @@ export const constantRoutes: RouterTypes = [ } ] }, + { + path: '/mqtt', + name: 'MQTT', + component: () => import('@/views/mqtt/index.vue'), + //using el svg icon, the elSvgIcon first when at the same time using elSvgIcon and icon + meta: { title: 'MQTT', icon: 'list' as BootstrapIcons, affix: true } + }, userRoute ] //角色和code数组动态路由 -export const roleCodeRoutes: RouterTypes = [] +export const roleRoutes: RouterTypes = [] /** * asyncRoutes * the routes that need to be dynamically loaded based on user roles diff --git a/src/router/modules/basic-demo.ts b/src/router/modules/basic-demo.ts deleted file mode 100644 index 5468595..0000000 --- a/src/router/modules/basic-demo.ts +++ /dev/null @@ -1,100 +0,0 @@ -import Layout from '@/layout/default/index.vue' -const BasicDemo = { - path: '/basic-demo', - component: Layout, - meta: { title: 'Basic Demo', icon: 'eye-open' }, - alwaysShow: true, - children: [ - { - path: 'hook', - component: () => import('@/views/basic-demo/hook/index.vue'), - name: 'Hook', - meta: { title: 'Hook' } - }, - { - path: 'pinia', - component: () => import('@/views/basic-demo/pinia/index.vue'), - name: 'Pinia', - meta: { title: 'Pinia' } - }, - { - path: 'mock', - component: () => import('@/views/basic-demo/mock/index.vue'), - name: 'Mock', - meta: { title: 'Mock' } - }, - { - path: 'svg-icon', - component: () => import('@/views/basic-demo/svg-icon/index.vue'), - name: 'SvgIcon', - meta: { title: 'Svg Icon' } - }, - { - path: 'parent-children', - component: () => import('@/views/basic-demo/parent-children/index.vue'), - name: 'Parent', - meta: { title: 'Parent Children' } - }, - { - path: 'second-keep-alive', - component: () => import('@/views/basic-demo/keep-alive/index.vue'), - name: 'SecondKeepAlive', - //cachePage: cachePage when page enter, default false - //leaveRmCachePage: remove cachePage when page leave, default false - meta: { title: 'Second KeepAlive', cachePage: true, leaveRmCachePage: false } - }, - { - path: 'second-child', - name: 'SecondChild', - hidden: true, - component: () => import('@/views/basic-demo/keep-alive/second-child.vue'), - meta: { title: 'SecondChild', cachePage: true, activeMenu: '/basic-demo/second-keep-alive' } - }, - { - path: 'third-child', - name: 'ThirdChild', - hidden: true, - component: () => import('@/views/basic-demo/keep-alive/third-child.vue'), - meta: { title: 'ThirdChild', cachePage: true, activeMenu: '/basic-demo/second-keep-alive' } - }, - //tab-keep-alive - { - path: 'tab-keep-alive', - component: () => import('@/views/basic-demo/keep-alive/tab-keep-alive.vue'), - name: 'TabKeepAlive', - //closeTabRmCache: remove cachePage when tabs close, default false - meta: { title: 'Tab KeepAlive', cachePage: true, closeTabRmCache: true } - }, - //third-keep-alive - { - path: 'third-keep-alive', - name: 'ThirdKeepAlive', - component: () => import('@/views/basic-demo/keep-alive/third-keep-alive.vue'), - //注:移除父容器页面缓存会把子页面一起移除了 - meta: { title: 'Third KeepAlive', cachePage: true, leaveRmCachePage: false }, - alwaysShow: true, - children: [ - { - path: 'second-children', - name: 'SecondChildren', - component: () => import('@/views/basic-demo/keep-alive/third-children/SecondChildren.vue'), - meta: { title: 'SecondChild', cachePage: true, leaveRmCachePage: true } - }, - { - path: 'third-children', - name: 'ThirdChildren', - component: () => import('@/views/basic-demo/keep-alive/third-children/ThirdChildren.vue'), - meta: { title: 'ThirdChild', cachePage: true, leaveRmCachePage: false } - } - ] - }, - { - path: 'worker', - component: () => import('@/views/basic-demo/worker/index.vue'), - name: 'Worker', - meta: { title: 'Worker' } - } - ] -} - -export default BasicDemo diff --git a/src/router/modules/charts.ts b/src/router/modules/charts.ts deleted file mode 100644 index b7a88da..0000000 --- a/src/router/modules/charts.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** When your routing table is too long, you can split it into small modules**/ - -import Layout from '@/layout/default/index.vue' - -const chartsRouter = { - path: '/charts', - component: Layout, - redirect: 'noRedirect', - name: 'Charts', - meta: { - title: 'Charts', - icon: 'chart' - }, - children: [ - { - path: 'keyboard', - component: () => import('@/views/charts/keyboard.vue'), - name: 'KeyboardChart', - meta: { title: 'Keyboard Chart', noCache: true } - }, - { - path: 'line', - component: () => import('@/views/charts/line.vue'), - name: 'LineChart', - meta: { title: 'Line Chart', noCache: true } - }, - { - path: 'mix-chart', - component: () => import('@/views/charts/mix-chart.vue'), - name: 'MixChart', - meta: { title: 'Mix Chart', noCache: true } - }, - { - path: 'echarts-demo', - component: () => import('@/views/charts/echarts-demo.vue'), - name: 'EchartsDemo', - meta: { title: 'Echarts Demo', noCache: true } - } - ] -} - -export default chartsRouter diff --git a/src/router/modules/directive.ts b/src/router/modules/directive.ts deleted file mode 100644 index d9d86c0..0000000 --- a/src/router/modules/directive.ts +++ /dev/null @@ -1,48 +0,0 @@ -import Layout from '@/layout/default/index.vue' - -const directive = { - path: '/directive', - component: Layout, - meta: { title: 'Directive', icon: 'education' }, - alwaysShow: true, - children: [ - { - path: 'copy', - component: () => import('@/views/directive/copy.vue'), - name: 'copy', - meta: { title: 'v-copy' } - }, - { - path: 'debounce', - component: () => import('@/views/directive/debounce.vue'), - name: 'debounce', - meta: { title: 'v-debounce' } - }, - { - path: 'longpress', - component: () => import('@/views/directive/longpress.vue'), - name: 'longpress', - meta: { title: 'v-longpress' } - }, - { - path: 'watermark', - component: () => import('@/views/directive/watermark.vue'), - name: 'watermark', - meta: { title: 'v-watermark' } - }, - { - path: 'waves', - component: () => import('@/views/directive/waves.vue'), - name: 'waves', - meta: { title: 'v-waves' } - }, - { - path: 'clickoutside', - component: () => import('@/views/directive/clickoutside.vue'), - name: 'clickoutside', - meta: { title: 'v-clickoutside' } - } - ] -} - -export default directive diff --git a/src/router/modules/excel.ts b/src/router/modules/excel.ts deleted file mode 100644 index c3ad98c..0000000 --- a/src/router/modules/excel.ts +++ /dev/null @@ -1,23 +0,0 @@ -import Layout from '@/layout/default/index.vue' -const excel = { - path: '/excel', - component: Layout, - meta: { title: 'EXCEL', icon: 'excel' }, - alwaysShow: true, - children: [ - { - path: 'exportExcel', - component: () => import('@/views/excel/exportExcel.vue'), - name: 'exportExcel', - meta: { title: 'exportExcel' } - }, - { - path: 'importExcel', - component: () => import('@/views/excel/importExcel.vue'), - name: 'importExcel', - meta: { title: 'importExcel' } - } - ] -} - -export default excel diff --git a/src/router/modules/guid.ts b/src/router/modules/guid.ts deleted file mode 100644 index fbe296a..0000000 --- a/src/router/modules/guid.ts +++ /dev/null @@ -1,14 +0,0 @@ -import Layout from '@/layout/default/index.vue' -const guid = { - path: '/guide', - component: Layout, - children: [ - { - path: 'index', - component: () => import('@/views/guide/index.vue'), - name: 'Guide', - meta: { title: 'Guide', icon: 'guide' } - } - ] -} -export default guid diff --git a/src/router/modules/other.ts b/src/router/modules/other.ts deleted file mode 100644 index 1d546f9..0000000 --- a/src/router/modules/other.ts +++ /dev/null @@ -1,35 +0,0 @@ -import Layout from '@/layout/default/index.vue' -const other = { - path: '/other', - component: Layout, - meta: { title: 'Other', icon: 'eye-open' }, - alwaysShow: true, - children: [ - { - path: 'count-to', - component: () => import('@/views/other/count-to.vue'), - name: 'CountTo', - meta: { title: 'CountTo' } - }, - { - path: 'd3', - component: () => import('@/views/other/d3/index.vue'), - name: 'd3', - meta: { title: 'd3' } - }, - { - path: 'drag-pane', - component: () => import('@/views/other/drag-pane.vue'), - name: 'DragPane', - meta: { title: 'DragPane' } - }, - { - path: 'signboard', - component: () => import('@/views/other/signboard/index.vue'), - name: 'signboard', - meta: { title: 'signboard' } - } - ] -} - -export default other diff --git a/src/router/modules/rich-text.ts b/src/router/modules/rich-text.ts deleted file mode 100644 index d0a1af2..0000000 --- a/src/router/modules/rich-text.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Layout from '@/layout/default/index.vue' -const richText = { - path: '/rich-text', - component: Layout, - meta: { title: 'Rich Text', icon: 'clipboard' }, - alwaysShow: true, - children: [ - { - path: 'tinymce', - name: 'Tinymce', - component: () => import('@/views/rich-text/TinymceExample.vue'), - meta: { title: 'Tinymce', icon: 'nested' } - } - ] -} - -export default richText diff --git a/src/router/modules/table.ts b/src/router/modules/table.ts deleted file mode 100644 index 77244b3..0000000 --- a/src/router/modules/table.ts +++ /dev/null @@ -1,23 +0,0 @@ -import Layout from '@/layout/default/index.vue' -const table = { - path: '/table', - component: Layout, - meta: { title: 'Table', icon: 'table' }, - alwaysShow: true, - children: [ - { - path: 'dynamic-table', - name: 'DynamicTable', - component: () => import('@/views/table/dynamic-table.vue'), - meta: { title: 'Dynamic Table', icon: 'nested' } - }, - { - path: 'vxe-table', - name: 'VxeTable', - component: () => import('@/views/table/vxe-table.vue'), - meta: { title: 'Vxe Table', icon: 'nested' } - } - ] -} - -export default table diff --git a/src/views/mqtt/index.vue b/src/views/mqtt/index.vue new file mode 100644 index 0000000..2b91608 --- /dev/null +++ b/src/views/mqtt/index.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/typings/auto-imports.d.ts b/typings/auto-imports.d.ts index 3938be7..a88966c 100644 --- a/typings/auto-imports.d.ts +++ b/typings/auto-imports.d.ts @@ -27,6 +27,7 @@ declare global { const elLoading: typeof import('../src/hooks/use-element')['elLoading'] const elMessage: typeof import('../src/hooks/use-element')['elMessage'] const elNotify: typeof import('../src/hooks/use-element')['elNotify'] + const filterRouters: typeof import('../src/hooks/use-permission')['filterRouters'] const freshRouter: typeof import('../src/hooks/use-permission')['freshRouter'] const getCurrentInstance: typeof import('vue')['getCurrentInstance'] const getCurrentScope: typeof import('vue')['getCurrentScope']