From 879358821d02d5e4575dfee0d189b9fee7f2e217 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Sun, 27 Aug 2023 09:03:39 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +--- README.zh-CN.md | 6 +--- mock/role/index.ts | 35 +++++++++++++++++-- src/api/login/index.ts | 2 +- .../src/components/InterfaceDisplay.vue | 13 +++++++ src/hooks/web/useStorage.ts | 29 +++++++++++---- src/locales/en.ts | 4 ++- src/locales/zh-CN.ts | 3 +- src/permission.ts | 21 +++-------- src/store/modules/app.ts | 16 ++++++--- src/store/modules/dict.ts | 34 ------------------ src/store/modules/permission.ts | 16 +++++---- src/utils/routerHelper.ts | 16 +++++---- src/views/Login/components/LoginForm.vue | 15 ++++---- 14 files changed, 118 insertions(+), 98 deletions(-) delete mode 100644 src/store/modules/dict.ts diff --git a/README.md b/README.md index 3d7ccbb3f..7bd0ee3f1 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,7 @@ If you need a basic template, please switch to the `mini` branch. `mini` simply - [vue-element-plus-admin](https://element-plus-admin.cn/) - Full version of the github site - [vue-element-plus-admin](https://kailong110120130.gitee.io/vue-element-plus-admin) - Full version of the gitee site -account: **admin/admin test/test** - -`admin` account is used to simulate the control permission of the server, and render whatever the server returns - -`test` account is used to simulate the front-end control authority. The server only returns the menu key to be displayed, and the front-end performs matching rendering +account: **admin/admin** Online examples do not apply to menu filtering by default, but directly use Static routing diff --git a/README.zh-CN.md b/README.zh-CN.md index 7bd843b37..e6dff6c3e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -31,11 +31,7 @@ vue-element-plus-admin 的定位是后台集成方案,不太适合当基础模 - [vue-element-plus-admin](https://element-plus-admin.cn/) - 完整版 github 站点 - [vue-element-plus-admin](https://kailong110120130.gitee.io/vue-element-plus-admin) - 完整版 gitee 站点 -帐号:**admin/admin test/test** - -`admin` 帐号用于模拟服务端控制权限,服务端返回什么就渲染什么 - -`test` 帐号用于模拟前端控制权限,服务端只返回需要显示的菜单 key,前端进行匹配渲染 +帐号:**admin/admin** 在线例子默认不适用菜单过滤,而是直接使用静态路由表 diff --git a/mock/role/index.ts b/mock/role/index.ts index 15d802ef2..b663613eb 100644 --- a/mock/role/index.ts +++ b/mock/role/index.ts @@ -1070,12 +1070,41 @@ export default [ url: '/role/list', method: 'get', timeout, - response: ({ query }) => { - const { roleName } = query + response: () => { + return { + data: { + code: code, + data: adminList + } + } + } + }, + { + url: '/role/table', + method: 'get', + timeout, + response: () => { + return { + data: { + code: code, + data: { + list: List, + total: 4 + } + } + } + } + }, + // 列表接口 + { + url: '/role/list2', + method: 'get', + timeout, + response: () => { return { data: { code: code, - data: roleName === 'admin' ? adminList : testList + data: testList } } } diff --git a/src/api/login/index.ts b/src/api/login/index.ts index ccddc3777..22bbaf860 100644 --- a/src/api/login/index.ts +++ b/src/api/login/index.ts @@ -30,5 +30,5 @@ export const getAdminRoleApi = ( } export const getTestRoleApi = (params: RoleParams): Promise> => { - return request.get({ url: '/role/list', params }) + return request.get({ url: '/role/list2', params }) } diff --git a/src/components/Setting/src/components/InterfaceDisplay.vue b/src/components/Setting/src/components/InterfaceDisplay.vue index 8e7d7799b..e8fbde6c0 100644 --- a/src/components/Setting/src/components/InterfaceDisplay.vue +++ b/src/components/Setting/src/components/InterfaceDisplay.vue @@ -115,6 +115,14 @@ const dynamicRouterChange = (show: boolean) => { appStore.setDynamicRouter(show) } +// 服务端动态路由 +const serverDynamicRouter = ref(appStore.getServerDynamicRouter) + +const serverDynamicRouterChange = (show: boolean) => { + ElMessage.info(t('setting.reExperienced')) + appStore.setServerDynamicRouter(show) +} + // 固定菜单 const fixedMenu = ref(appStore.getFixedMenu) @@ -206,6 +214,11 @@ watch( +
+ {{ t('setting.serverDynamicRouter') }} + +
+
{{ t('setting.fixedMenu') }} diff --git a/src/hooks/web/useStorage.ts b/src/hooks/web/useStorage.ts index cd077df7f..e33a6a567 100644 --- a/src/hooks/web/useStorage.ts +++ b/src/hooks/web/useStorage.ts @@ -1,15 +1,21 @@ -import { isArray, isObject } from '@/utils/is' +// 获取传入的值的类型 +const getValueType = (value: any) => { + const type = Object.prototype.toString.call(value) + return type.slice(8, -1) +} export const useStorage = (type: 'sessionStorage' | 'localStorage' = 'sessionStorage') => { const setStorage = (key: string, value: any) => { - window[type].setItem(key, isArray(value) || isObject(value) ? JSON.stringify(value) : value) + const valueType = getValueType(value) + window[type].setItem(key, JSON.stringify({ type: valueType, value })) } const getStorage = (key: string) => { const value = window[type].getItem(key) - try { - return JSON.parse(value || '') - } catch (error) { + if (value) { + const { value: val } = JSON.parse(value) + return val + } else { return value } } @@ -18,8 +24,17 @@ export const useStorage = (type: 'sessionStorage' | 'localStorage' = 'sessionSto window[type].removeItem(key) } - const clear = () => { - window[type].clear() + const clear = (excludes?: string[]) => { + // 获取排除项 + const keys = Object.keys(window[type]) + const defaultExcludes = ['dynamicRouter', 'serverDynamicRouter'] + const excludesArr = excludes ? [...excludes, ...defaultExcludes] : defaultExcludes + const excludesKeys = excludesArr ? keys.filter((key) => !excludesArr.includes(key)) : keys + // 排除项不清除 + excludesKeys.forEach((key) => { + window[type].removeItem(key) + }) + // window[type].clear() } return { diff --git a/src/locales/en.ts b/src/locales/en.ts index 1a791a976..990852e70 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -93,7 +93,9 @@ export default { footer: 'Footer', uniqueOpened: 'Unique opened', tagsViewIcon: 'Tags view icon', - dynamicRouter: 'Dynamic router', + // 开启动态路由 + dynamicRouter: 'Enable dynamic router', + serverDynamicRouter: 'Server dynamic router', reExperienced: 'Please exit the login experience again', fixedMenu: 'Fixed menu' }, diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 47e587e94..012b94d18 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -93,7 +93,8 @@ export default { footer: '页脚', uniqueOpened: '菜单手风琴', tagsViewIcon: '标签页图标', - dynamicRouter: '动态路由', + dynamicRouter: '开启动态路由', + serverDynamicRouter: '服务端动态路由', reExperienced: '请重新退出登录体验', fixedMenu: '固定菜单' }, diff --git a/src/permission.ts b/src/permission.ts index 92eebfb48..67d6ffa7b 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -5,16 +5,12 @@ import type { RouteRecordRaw } from 'vue-router' import { useTitle } from '@/hooks/web/useTitle' import { useNProgress } from '@/hooks/web/useNProgress' import { usePermissionStoreWithOut } from '@/store/modules/permission' -// import { useDictStoreWithOut } from '@/store/modules/dict' import { usePageLoading } from '@/hooks/web/usePageLoading' -// import { getDictApi } from '@/api/common' const permissionStore = usePermissionStoreWithOut() const appStore = useAppStoreWithOut() -// const dictStore = useDictStoreWithOut() - const { getStorage } = useStorage() const { start, done } = useNProgress() @@ -30,14 +26,6 @@ router.beforeEach(async (to, from, next) => { if (to.path === '/login') { next({ path: '/' }) } else { - // if (!dictStore.getIsSetDict) { - // // 获取所有字典 - // const res = await getDictApi() - // if (res) { - // dictStore.setDictObj(res.data) - // dictStore.setIsSetDict(true) - // } - // } if (permissionStore.getIsAddRouters) { next() return @@ -45,15 +33,14 @@ router.beforeEach(async (to, from, next) => { // 开发者可根据实际情况进行修改 const roleRouters = getStorage('roleRouters') || [] - const userInfo = getStorage(appStore.getUserInfo) // 是否使用动态路由 if (appStore.getDynamicRouter) { - userInfo.role === 'admin' - ? await permissionStore.generateRoutes('admin', roleRouters as AppCustomRouteRecordRaw[]) - : await permissionStore.generateRoutes('test', roleRouters as string[]) + appStore.serverDynamicRouter + ? await permissionStore.generateRoutes('server', roleRouters as AppCustomRouteRecordRaw[]) + : await permissionStore.generateRoutes('frontEnd', roleRouters as string[]) } else { - await permissionStore.generateRoutes('none') + await permissionStore.generateRoutes('static') } permissionStore.getAddRouters.forEach((route) => { diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index 56a824946..3247708ab 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -21,6 +21,7 @@ interface AppState { fixedHeader: boolean greyMode: boolean dynamicRouter: boolean + serverDynamicRouter: boolean pageLoading: boolean layout: LayoutType title: string @@ -42,7 +43,6 @@ export const useAppStore = defineStore('app', { mobile: false, // 是否是移动端 title: import.meta.env.VITE_APP_TITLE, // 标题 pageLoading: false, // 路由跳转loading - breadcrumb: true, // 面包屑 breadcrumbIcon: true, // 面包屑图标 collapse: false, // 折叠菜单 @@ -57,11 +57,12 @@ export const useAppStore = defineStore('app', { fixedHeader: true, // 固定toolheader footer: true, // 显示页脚 greyMode: false, // 是否开始灰色模式,用于特殊悼念日 - dynamicRouter: getStorage('dynamicRouter') || true, // 是否动态路由 - fixedMenu: getStorage('fixedMenu') || false, // 是否固定菜单 + dynamicRouter: getStorage('dynamicRouter'), // 是否动态路由 + serverDynamicRouter: getStorage('serverDynamicRouter'), // 是否服务端渲染动态路由 + fixedMenu: getStorage('fixedMenu'), // 是否固定菜单 layout: getStorage('layout') || 'classic', // layout布局 - isDark: getStorage('isDark') || false, // 是否是暗黑模式 + isDark: getStorage('isDark'), // 是否是暗黑模式 currentSize: getStorage('default') || 'default', // 组件尺寸 theme: getStorage('theme') || { // 主题色 @@ -138,6 +139,9 @@ export const useAppStore = defineStore('app', { getDynamicRouter(): boolean { return this.dynamicRouter }, + getServerDynamicRouter(): boolean { + return this.serverDynamicRouter + }, getFixedMenu(): boolean { return this.fixedMenu }, @@ -216,6 +220,10 @@ export const useAppStore = defineStore('app', { setStorage('dynamicRouter', dynamicRouter) this.dynamicRouter = dynamicRouter }, + setServerDynamicRouter(serverDynamicRouter: boolean) { + setStorage('serverDynamicRouter', serverDynamicRouter) + this.serverDynamicRouter = serverDynamicRouter + }, setFixedMenu(fixedMenu: boolean) { setStorage('fixedMenu', fixedMenu) this.fixedMenu = fixedMenu diff --git a/src/store/modules/dict.ts b/src/store/modules/dict.ts deleted file mode 100644 index 93dd46edf..000000000 --- a/src/store/modules/dict.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineStore } from 'pinia' -import { store } from '../index' - -export interface DictState { - isSetDict: boolean - dictObj: Recordable -} - -export const useDictStore = defineStore('dict', { - state: (): DictState => ({ - isSetDict: false, - dictObj: {} - }), - getters: { - getDictObj(): Recordable { - return this.dictObj - }, - getIsSetDict(): boolean { - return this.isSetDict - } - }, - actions: { - setDictObj(dictObj: Recordable) { - this.dictObj = dictObj - }, - setIsSetDict(isSetDict: boolean) { - this.isSetDict = isSetDict - } - } -}) - -export const useDictStoreWithOut = () => { - return useDictStore(store) -} diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index 63eb0dafa..48f5a851f 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -1,6 +1,10 @@ import { defineStore } from 'pinia' import { asyncRouterMap, constantRouterMap } from '@/router' -import { generateRoutesFn1, generateRoutesFn2, flatMultiLevelRoutes } from '@/utils/routerHelper' +import { + generateRoutesByFrontEnd, + generateRoutesByServer, + flatMultiLevelRoutes +} from '@/utils/routerHelper' import { store } from '../index' import { cloneDeep } from 'lodash-es' @@ -34,17 +38,17 @@ export const usePermissionStore = defineStore('permission', { }, actions: { generateRoutes( - type: 'admin' | 'test' | 'none', + type: 'server' | 'frontEnd' | 'static', routers?: AppCustomRouteRecordRaw[] | string[] ): Promise { return new Promise((resolve) => { let routerMap: AppRouteRecordRaw[] = [] - if (type === 'admin') { + if (type === 'server') { // 模拟后端过滤菜单 - routerMap = generateRoutesFn2(routers as AppCustomRouteRecordRaw[]) - } else if (type === 'test') { + routerMap = generateRoutesByServer(routers as AppCustomRouteRecordRaw[]) + } else if (type === 'frontEnd') { // 模拟前端过滤菜单 - routerMap = generateRoutesFn1(cloneDeep(asyncRouterMap), routers as string[]) + routerMap = generateRoutesByFrontEnd(cloneDeep(asyncRouterMap), routers as string[]) } else { // 直接读取静态路由表 routerMap = cloneDeep(asyncRouterMap) diff --git a/src/utils/routerHelper.ts b/src/utils/routerHelper.ts index 791e7603a..b4e7548ff 100644 --- a/src/utils/routerHelper.ts +++ b/src/utils/routerHelper.ts @@ -38,7 +38,7 @@ export const getRawRoute = (route: RouteLocationNormalized): RouteLocationNormal } // 前端控制路由生成 -export const generateRoutesFn1 = ( +export const generateRoutesByFrontEnd = ( routes: AppRouteRecordRaw[], keys: string[], basePath = '/' @@ -69,7 +69,7 @@ export const generateRoutesFn1 = ( if (isUrl(item) && (onlyOneChild === item || route.path === item)) { data = Object.assign({}, route) } else { - const routePath = onlyOneChild ?? pathResolve(basePath, route.path) + const routePath = (onlyOneChild ?? pathResolve(basePath, route.path)).trim() if (routePath === item || meta.followRoute === item) { data = Object.assign({}, route) } @@ -78,7 +78,11 @@ export const generateRoutesFn1 = ( // recursive child routes if (route.children && data) { - data.children = generateRoutesFn1(route.children, keys, pathResolve(basePath, data.path)) + data.children = generateRoutesByFrontEnd( + route.children, + keys, + pathResolve(basePath, data.path) + ) } if (data) { res.push(data as AppRouteRecordRaw) @@ -88,7 +92,7 @@ export const generateRoutesFn1 = ( } // 后端控制路由生成 -export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => { +export const generateRoutesByServer = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => { const res: AppRouteRecordRaw[] = [] for (const route of routes) { @@ -111,7 +115,7 @@ export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRe } // recursive child routes if (route.children) { - data.children = generateRoutesFn2(route.children) + data.children = generateRoutesByServer(route.children) } res.push(data as AppRouteRecordRaw) } @@ -121,7 +125,7 @@ export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRe export const pathResolve = (parentPath: string, path: string) => { if (isUrl(path)) return path const childPath = path.startsWith('/') || !path ? path : `/${path}` - return `${parentPath}${childPath}`.replace(/\/\//g, '/') + return `${parentPath}${childPath}`.replace(/\/\//g, '/').trim() } // 路由降级 diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index c6cc5307b..7c1262adc 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -220,7 +220,7 @@ const signIn = async () => { if (appStore.getDynamicRouter) { getRole() } else { - await permissionStore.generateRoutes('none').catch(() => {}) + await permissionStore.generateRoutes('static').catch(() => {}) permissionStore.getAddRouters.forEach((route) => { addRoute(route as RouteRecordRaw) // 动态添加可访问路由表 }) @@ -241,17 +241,16 @@ const getRole = async () => { const params = { roleName: formData.username } - // admin - 模拟后端过滤菜单 - // test - 模拟前端过滤菜单 const res = - formData.username === 'admin' ? await getAdminRoleApi(params) : await getTestRoleApi(params) + appStore.getDynamicRouter && appStore.getServerDynamicRouter + ? await getAdminRoleApi(params) + : await getTestRoleApi(params) if (res) { const routers = res.data || [] setStorage('roleRouters', routers) - - formData.username === 'admin' - ? await permissionStore.generateRoutes('admin', routers).catch(() => {}) - : await permissionStore.generateRoutes('test', routers).catch(() => {}) + appStore.getDynamicRouter && appStore.getServerDynamicRouter + ? await permissionStore.generateRoutes('server', routers).catch(() => {}) + : await permissionStore.generateRoutes('frontEnd', routers).catch(() => {}) permissionStore.getAddRouters.forEach((route) => { addRoute(route as RouteRecordRaw) // 动态添加可访问路由表