diff --git a/.env b/.env
index fdd62d5cc..1545fae6c 100644
--- a/.env
+++ b/.env
@@ -6,3 +6,7 @@ VITE_GLOB_APP_TITLE = Vben Admin
# spa shortname
VITE_GLOB_APP_SHORT_NAME = vue_vben_admin_2x
+
+# Menu generation mode BACK|ROLE
+# Need to delete LocalStorage after modification
+VITE_GEN_MENU_MODE=ROLE
diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md
index cdaa80d46..6dcc2b4b1 100644
--- a/CHANGELOG.zh_CN.md
+++ b/CHANGELOG.zh_CN.md
@@ -8,6 +8,10 @@
- openModal 和 openDrawer 第二个参数可以代替`transferModalData`传参到内部
- 带参路由可以被缓存
+### ✨ Refactor
+
+- 重构由后台生成菜单的逻辑
+
### ⚡ Performance Improvements
- 菜单性能继续优化,更流畅
diff --git a/build/vite/plugin/dynamicImport/index.ts b/build/vite/plugin/dynamicImport/index.ts
new file mode 100644
index 000000000..6b0b92ce3
--- /dev/null
+++ b/build/vite/plugin/dynamicImport/index.ts
@@ -0,0 +1,55 @@
+// Used to import all files under `src/views`
+
+// The built-in dynamic import of vite cannot meet the needs of importing all files under views
+
+import glob from 'glob';
+import { Transform } from 'vite/dist/node/transform.js';
+
+function getPath(path: string) {
+ const lastIndex = path.lastIndexOf('.');
+ if (lastIndex !== -1) {
+ path = path.substring(0, lastIndex);
+ }
+ return path.replace('src/views', '');
+}
+
+const dynamicImportTransform = function (env: any = {}): Transform {
+ return {
+ test({ path }) {
+ // Only convert the file
+ return path.includes('/src/utils/helper/dynamicImport.ts');
+ },
+ transform({ code }) {
+ const { VITE_GEN_MENU_MODE = '' } = env;
+ if (VITE_GEN_MENU_MODE !== 'BACK') {
+ return code;
+ }
+ // if (!isBuild) return code;
+ // Only convert the dir
+ try {
+ const files = glob.sync('src/views/**/**.{vue,tsx}', { cwd: process.cwd() });
+
+ const _code = `
+ export default function (id) {
+ switch (id) {
+ ${files
+
+ .map((p) =>
+ ` case '${getPath(p)}': return () => import('${p
+ .replace('src/views', '/@/views')
+ .replace(/\/\//g, '/')}');`.replace('.tsx', '')
+ )
+ .join('\n ')}
+ default: return Promise.reject(new Error("Unknown variable dynamic import: " + id));
+ }
+ }\n\n
+ `;
+ return _code;
+ } catch (error) {
+ console.error(error);
+ return code;
+ }
+ },
+ };
+};
+export default dynamicImportTransform;
diff --git a/mock/sys/menu.ts b/mock/sys/menu.ts
index 2f9623258..82930c542 100644
--- a/mock/sys/menu.ts
+++ b/mock/sys/menu.ts
@@ -16,7 +16,7 @@ const dashboardRoute = {
{
path: '/welcome',
name: 'Welcome',
- component: '/dashboard/welcome/index.vue',
+ component: '/dashboard/welcome/index',
meta: {
title: '欢迎页',
affix: true,
@@ -34,28 +34,28 @@ const frontRoute = {
children: [
{
path: 'page',
- component: '/demo/permission/front/index.vue',
+ component: '/demo/permission/front/index',
meta: {
title: '页面权限',
},
},
{
path: 'btn',
- component: '/demo/permission/front/Btn.vue',
+ component: '/demo/permission/front/Btn',
meta: {
title: '按钮权限',
},
},
{
path: 'auth-pageA',
- component: '/demo/permission/front/AuthPageA.vue',
+ component: '/demo/permission/front/AuthPageA',
meta: {
title: '权限测试页A',
},
},
{
path: 'auth-pageB',
- component: '/demo/permission/front/AuthPageB.vue',
+ component: '/demo/permission/front/AuthPageB',
meta: {
title: '权限测试页B',
},
@@ -71,14 +71,14 @@ const backRoute = {
children: [
{
path: 'page',
- component: 'demo/permission/back/index.vue',
+ component: '/demo/permission/back/index',
meta: {
title: '页面权限',
},
},
{
path: 'btn',
- component: '/demo/permission/back/Btn.vue',
+ component: '/demo/permission/back/Btn',
meta: {
title: '按钮权限',
},
diff --git a/src/layouts/default/index.tsx b/src/layouts/default/index.tsx
index a4b112627..3116e096f 100644
--- a/src/layouts/default/index.tsx
+++ b/src/layouts/default/index.tsx
@@ -107,7 +107,9 @@ export default defineComponent({
unref(showHeaderRef) && }
{showTabs && !unref(getFullContent) && (
-
+
+ {() => }
+
)}
{useOpenBackTop && }
diff --git a/src/settings/projectSetting.ts b/src/settings/projectSetting.ts
index ff08bb3fc..2ca2ea448 100644
--- a/src/settings/projectSetting.ts
+++ b/src/settings/projectSetting.ts
@@ -1,15 +1,16 @@
import type { ProjectConfig } from '/@/types/config';
import { MenuTypeEnum, MenuThemeEnum, MenuModeEnum, TriggerEnum } from '/@/enums/menuEnum';
-import { ContentEnum, PermissionModeEnum, RouterTransitionEnum } from '/@/enums/appEnum';
+import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum';
import { primaryColor } from '../../build/config/lessModifyVars';
-import { isProdMode } from '/@/utils/env';
+import { isProdMode, getRoleMode } from '/@/utils/env';
+
// ! You need to clear the browser cache after the change
const setting: ProjectConfig = {
// Whether to show the configuration button
showSettingButton: true,
// 权限模式
- permissionMode: PermissionModeEnum.ROLE,
+ permissionMode: getRoleMode(),
// 网站灰色模式,用于可能悼念的日期开启
grayMode: false,
// 色弱模式
diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts
index 3b50634eb..4f3e95780 100644
--- a/src/store/modules/permission.ts
+++ b/src/store/modules/permission.ts
@@ -19,7 +19,7 @@ import { genRouteModule, transformObjToRoute } from '/@/utils/helper/routeHelper
import { transformRouteToMenu } from '/@/utils/helper/menuHelper';
import { useMessage } from '/@/hooks/web/useMessage';
-import { warn } from '/@/utils/log';
+// import { warn } from '/@/utils/log';
const { createMessage } = useMessage();
const NAME = 'permission';
@@ -99,9 +99,9 @@ class Permission extends VuexModule {
});
// this.commitRoutesState(routes);
// Background permissions
- warn(
- `当前权限模式为:${PermissionModeEnum.ROLE},请将src/store/modules/permission.ts内的后台菜单获取函数注释,如果已注释可以忽略此信息!`
- );
+ // warn(
+ // `当前权限模式为:${PermissionModeEnum.ROLE},请将src/store/modules/permission.ts内的后台菜单获取函数注释,如果已注释可以忽略此信息!`
+ // );
// 如果确定不需要做后台动态权限,请将下面整个判断注释
} else if (permissionMode === PermissionModeEnum.BACK) {
const messageKey = 'loadMenu';
diff --git a/src/utils/env.ts b/src/utils/env.ts
index 58818a72c..a14a6f31f 100644
--- a/src/utils/env.ts
+++ b/src/utils/env.ts
@@ -1,3 +1,4 @@
+import { PermissionModeEnum } from '../enums/appEnum';
import type { GlobEnvConfig } from '/@/types/config';
export const getGlobEnvConfig = (): GlobEnvConfig => {
@@ -46,3 +47,14 @@ export const isProdMode = (): boolean => import.meta.env.PROD;
* @example:
*/
export const isUseMock = (): boolean => import.meta.env.VITE_USE_MOCK === 'true';
+
+/**
+ * @description: 获取菜单生成方式
+ * @param {type}
+ * @returns:
+ * @example:
+ */
+export const getRoleMode = (): PermissionModeEnum =>
+ import.meta.env.VITE_GEN_MENU_MODE === PermissionModeEnum.ROLE
+ ? PermissionModeEnum.ROLE
+ : PermissionModeEnum.BACK;
diff --git a/src/utils/helper/dynamicImport.ts b/src/utils/helper/dynamicImport.ts
new file mode 100644
index 000000000..34e5b08af
--- /dev/null
+++ b/src/utils/helper/dynamicImport.ts
@@ -0,0 +1,4 @@
+export default function (id: string) {
+ const dynamicImportModule: any = id;
+ return dynamicImportModule;
+}
diff --git a/src/utils/helper/routeHelper.ts b/src/utils/helper/routeHelper.ts
index eab722a11..274f03415 100644
--- a/src/utils/helper/routeHelper.ts
+++ b/src/utils/helper/routeHelper.ts
@@ -6,6 +6,8 @@ import { tabStore } from '/@/store/modules/tab';
import { createRouter, createWebHashHistory } from 'vue-router';
import { toRaw } from 'vue';
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+// import { isDevMode } from '/@/utils/env';
+import dynamicImport from './dynamicImport';
let currentTo: RouteLocationNormalized | null = null;
@@ -45,12 +47,12 @@ export function genRouteModule(moduleList: AppRouteModule[]) {
// TODO 错误写法
function asyncImportRoute(routes: AppRouteRecordRaw[]) {
routes.forEach((item) => {
- let { component } = item;
+ const { component } = item;
const { children } = item;
if (component) {
- component = component.replace(/^\//, '');
- item.component = () => import(`/@/views/${component}`);
+ item.component = dynamicImport(component);
}
+
children && asyncImportRoute(children);
});
}
diff --git a/vite.config.ts b/vite.config.ts
index 679c90ae0..39a6b5cd8 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -5,6 +5,7 @@ import { resolve } from 'path';
import { modifyVars } from './build/config/lessModifyVars';
import { createProxy } from './build/vite/proxy';
import globbyTransform from './build/vite/plugin/context/transform';
+import dynamicImportTransform from './build/vite/plugin/dynamicImport/index';
import { isDevFn, loadEnv } from './build/utils';
@@ -134,5 +135,5 @@ const viteConfig: UserConfig = {
export default {
...viteConfig,
- transforms: [globbyTransform(viteConfig)],
+ transforms: [globbyTransform(viteConfig), dynamicImportTransform(viteEnv)],
} as UserConfig;