Quellcode durchsuchen

chore: detail optimization

vben vor 4 Jahren
Ursprung
Commit
31e2715e67

+ 4 - 4
build/script/updateHtml.ts

@@ -74,9 +74,7 @@ function injectCdnjs(html: string) {
 export async function runUpdateHtml() {
   const outDir = viteConfig.outDir || 'dist';
   const indexPath = getCwdPath(outDir, 'index.html');
-  if (!existsSync(`${indexPath}`)) {
-    return;
-  }
+  if (!existsSync(indexPath)) return;
   try {
     let processedHtml = '';
     const rawHtml = readFileSync(indexPath, 'utf-8');
@@ -92,7 +90,9 @@ export async function runUpdateHtml() {
     }
     if (minify) {
       const { enable, ...miniOpt } = minify;
-      processedHtml = HtmlMinifier.minify(processedHtml, miniOpt);
+      if (enable) {
+        processedHtml = HtmlMinifier.minify(processedHtml, miniOpt);
+      }
     }
 
     writeFileSync(indexPath, processedHtml);

+ 95 - 0
build/transform/require-context/index.ts

@@ -0,0 +1,95 @@
+// https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts
+
+// TODO 目前还不能监听文件新增及删除 内容已经改变,缓存问题?
+// 可以使用,先不打算集成
+import { join } from 'path';
+import { lstatSync } from 'fs';
+import glob from 'glob';
+import { createResolver, Resolver } from 'vite/dist/node/resolver.js';
+import { Transform } from 'vite/dist/node/transform.js';
+
+const modulesDir: string = join(process.cwd(), '/node_modules/');
+
+interface SharedConfig {
+  root?: string;
+  alias?: Record<string, string>;
+  resolvers?: Resolver[];
+}
+
+function template(template: string) {
+  return (data: { [x: string]: any }) => {
+    return template.replace(/#([^#]+)#/g, (_, g1) => data[g1] || g1);
+  };
+}
+
+const globbyTransform = function (config: SharedConfig): Transform {
+  const resolver = createResolver(
+    config.root || process.cwd(),
+    config.resolvers || [],
+    config.alias || {}
+  );
+  const cache = new Map();
+
+  const urlMap = new Map();
+  return {
+    test({ path }) {
+      const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
+      try {
+        return (
+          !filePath.startsWith(modulesDir) &&
+          /\.(vue|js|jsx|ts|tsx)$/.test(filePath) &&
+          lstatSync(filePath).isFile()
+        );
+      } catch {
+        return false;
+      }
+    },
+    transform({ code, path, isBuild }) {
+      let result = cache.get(path);
+      if (!result) {
+        const reg = /import\s+([\w\s{}*]+)\s+from\s+(['"])globby(\?path)?!([^'"]+)\2/g;
+        const lastImport = urlMap.get(path);
+        const match = code.match(reg);
+        if (lastImport && match) {
+          code = code.replace(lastImport, match[0]);
+        }
+        result = code.replace(reg, (_, g1, g2, g3, g4) => {
+          const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
+          // resolve path
+          const resolvedFilePath = g4.startsWith('.')
+            ? resolver.resolveRelativeRequest(filePath, g4)
+            : { pathname: resolver.requestToFile(g4) };
+          const files = glob.sync(resolvedFilePath.pathname, { dot: true });
+          let templateStr = 'import #name# from #file#'; // import default
+          let name = g1;
+          const m = g1.match(/\{\s*(\w+)(\s+as\s+(\w+))?\s*\}/); // import module
+          const m2 = g1.match(/\*\s+as\s+(\w+)/); // import * as all module
+          if (m) {
+            templateStr = `import { ${m[1]} as #name# } from #file#`;
+            name = m[3] || m[1];
+          } else if (m2) {
+            templateStr = 'import * as #name# from #file#';
+            name = m2[1];
+          }
+          const temRender = template(templateStr);
+
+          const groups: Array<string>[] = [];
+          const replaceFiles = files.map((f, i) => {
+            const file = g2 + resolver.fileToRequest(f) + g2;
+            groups.push([name + i, file]);
+            return temRender({ name: name + i, file });
+          });
+          urlMap.set(path, replaceFiles.join('\n'));
+          return (
+            replaceFiles.join('\n') +
+            (g3 ? '\n' + groups.map((v) => `${v[0]}._path = ${v[1]}`).join('\n') : '') +
+            `\nconst ${name} = { ${groups.map((v) => v[0]).join(',')} }\n`
+          );
+        });
+        if (isBuild) cache.set(path, result);
+      }
+      return result;
+    },
+  };
+};
+export default globbyTransform;

+ 8 - 12
build/utils.ts

@@ -124,28 +124,24 @@ export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.pr
   return envConfig;
 }
 
-export function successConsole(message: any) {
+function consoleFn(color: string, message: any) {
   console.log(
     chalk.blue.bold('****************  ') +
-      chalk.green.bold('✨ ' + message) +
+      (chalk as any)[color].bold(message) +
       chalk.blue.bold('  ****************')
   );
 }
 
+export function successConsole(message: any) {
+  consoleFn('green', '✨ ' + message);
+}
+
 export function errorConsole(message: any) {
-  console.log(
-    chalk.blue.bold('****************  ') +
-      chalk.red.bold('✨ ' + message) +
-      chalk.blue.bold('  ****************')
-  );
+  consoleFn('red', '✨ ' + message);
 }
 
 export function warnConsole(message: any) {
-  console.log(
-    chalk.blue.bold('****************  ') +
-      chalk.yellow.bold('✨ ' + message) +
-      chalk.blue.bold('  ****************')
-  );
+  consoleFn('yellow', '✨ ' + message);
 }
 
 export function getCwdPath(...dir: string[]) {

+ 4 - 1
src/components/CountTo/src/index.vue

@@ -5,7 +5,6 @@
 </template>
 <script lang="ts">
   import { defineComponent, reactive, computed, watch, onMounted, unref, toRef } from 'vue';
-
   import { countToProps } from './props';
   import { useRaf } from '/@/hooks/event/useRaf';
   import { isNumber } from '/@/utils/is';
@@ -37,12 +36,14 @@
         remaining: null,
         rAF: null,
       });
+
       onMounted(() => {
         if (props.autoplay) {
           start();
         }
         emit('mounted');
       });
+
       const getCountDown = computed(() => {
         return props.startVal > props.endVal;
       });
@@ -61,6 +62,7 @@
         state.paused = false;
         state.rAF = requestAnimationFrame(count);
       }
+
       function pauseResume() {
         if (state.paused) {
           resume();
@@ -70,6 +72,7 @@
           state.paused = true;
         }
       }
+
       function pause() {
         cancelAnimationFrame(state.rAF);
       }

+ 5 - 3
src/components/Menu/src/BasicMenu.tsx

@@ -7,7 +7,7 @@ import { Menu } from 'ant-design-vue';
 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
 import { menuStore } from '/@/store/modules/menu';
 import { getSlot } from '/@/utils/helper/tsxHelper';
-import { ScrollContainer } from '/@/components/Container/index';
+// import { ScrollContainer } from '/@/components/Container/index';
 import SearchInput from './SearchInput.vue';
 import './index.less';
 import { menuHasChildren } from './helper';
@@ -67,6 +67,7 @@ export default defineComponent({
       return {
         height: `calc(100% - ${offset}px)`,
         position: 'relative',
+        overflow: 'auto',
       };
     });
 
@@ -246,8 +247,9 @@ export default defineComponent({
             onClick={handleInputClick}
             collapsed={getCollapsedState}
           />
-          <section style={unref(getMenuWrapStyle)}>
-            <ScrollContainer>{() => renderMenu()}</ScrollContainer>
+          <section style={unref(getMenuWrapStyle)} class="basic-menu__wrap">
+            {renderMenu()}
+            {/* <ScrollContainer>{() => renderMenu()}</ScrollContainer> */}
           </section>
         </section>
       );

+ 31 - 3
src/components/Menu/src/index.less

@@ -14,6 +14,30 @@
 }
 
 .basic-menu {
+  &__wrap {
+    /* 滚动槽 */
+    &::-webkit-scrollbar {
+      width: 6px;
+      height: 6px;
+    }
+
+    // TODO 滚动条样式-待修改
+    &::-webkit-scrollbar-track {
+      background: rgba(0, 0, 0, 0);
+    }
+
+    /* 滚动条滑块 */
+    &::-webkit-scrollbar-thumb {
+      background: rgba(255, 255, 255, 0.3);
+      border-radius: 4px;
+      box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
+    }
+
+    ::-webkit-scrollbar-thumb:hover {
+      background: @border-color-dark;
+    }
+  }
+
   .ant-menu-submenu:first-of-type {
     margin-top: 4px;
   }
@@ -95,14 +119,14 @@
         .ant-menu-submenu-active,
         .ant-menu-submenu-title:hover {
           background: @top-menu-active-bg-color;
-          border-radius: 6px 6px 0 0;
+          // border-radius: 6px 6px 0 0;
         }
 
         .basic-menu-item__level1 {
           &.ant-menu-item-selected,
           &.ant-menu-submenu-selected {
             background: @top-menu-active-bg-color;
-            border-radius: 6px 6px 0 0;
+            // border-radius: 6px 6px 0 0;
           }
         }
 
@@ -148,6 +172,10 @@
     }
 
     .basic-menu-item__level1 {
+      > .ant-menu-sub > li {
+        background-color: @sub-menu-item-dark-bg-color;
+      }
+
       margin-bottom: 0;
 
       &.top-active-menu {
@@ -179,7 +207,7 @@
 
     .ant-menu-submenu-title {
       height: @app-menu-item-height;
-      margin: 0;
+      // margin: 0;
       line-height: @app-menu-item-height;
     }
   }

+ 1 - 1
src/design/var/index.less

@@ -18,4 +18,4 @@
 // app menu
 
 // left-menu
-@app-menu-item-height: 44px;
+@app-menu-item-height: 48px;

+ 10 - 5
src/hooks/web/useTabs.ts

@@ -1,10 +1,10 @@
-import type { AppRouteRecordRaw } from '/@/router/types.d';
 import { useTimeout } from '/@/hooks/core/useTimeout';
 import { PageEnum } from '/@/enums/pageEnum';
 import { TabItem, tabStore } from '/@/store/modules/tab';
 import { appStore } from '/@/store/modules/app';
 import router from '/@/router';
 import { ref } from 'vue';
+import { pathToRegexp } from 'path-to-regexp';
 
 const activeKeyRef = ref<string>('');
 
@@ -68,7 +68,11 @@ export function useTabs() {
   function getTo(path: string): any {
     const routes = router.getRoutes();
     const fn = (p: string): any => {
-      const to = routes.find((item) => item.path === p);
+      const to = routes.find((item) => {
+        if (item.path === '/:path(.*)*') return;
+        const regexp = pathToRegexp(item.path);
+        return regexp.test(p);
+      });
       if (!to) return '';
       if (!to.redirect) return to;
       if (to.redirect) {
@@ -88,12 +92,13 @@ export function useTabs() {
     resetCache: () => canIUseFn() && resetCache(),
     addTab: (path: PageEnum, goTo = false, replace = false) => {
       const to = getTo(path);
+
       if (!to) return;
       useTimeout(() => {
-        tabStore.addTabByPathAction((to as unknown) as AppRouteRecordRaw);
+        tabStore.addTabByPathAction();
       }, 0);
-      activeKeyRef.value = to.path;
-      goTo && replace ? router.replace : router.push(to.path);
+      activeKeyRef.value = path;
+      goTo && replace ? router.replace : router.push(path);
     },
     activeKeyRef,
   };

+ 5 - 0
src/layouts/default/index.tsx

@@ -82,10 +82,13 @@ export default defineComponent({
           {() => (
             <>
               {isLock && <LockPage />}
+
               {!unref(getFullContent) && unref(isShowMixHeaderRef) && unref(showHeaderRef) && (
                 <LayoutHeader />
               )}
+
               {showSettingButton && <SettingBtn />}
+
               <Layout>
                 {() => (
                   <>
@@ -102,7 +105,9 @@ export default defineComponent({
                               {() => <MultipleTabs />}
                             </Layout.Header>
                           )}
+
                           {useOpenBackTop && <BackTop target={getTarget} />}
+
                           <div class={[`default-layout__main`, fixedHeaderCls]}>
                             {openPageLoading && (
                               <FullLoading

+ 3 - 6
src/layouts/default/multitabs/index.tsx

@@ -9,6 +9,7 @@ import {
   // ref,
   unref,
   onMounted,
+  toRaw,
 } from 'vue';
 import { Tabs } from 'ant-design-vue';
 import TabContent from './TabContent';
@@ -73,11 +74,7 @@ export default defineComponent({
       routes &&
         routes.forEach((route) => {
           if (route.meta && route.meta.affix) {
-            tabs.push({
-              path: route.path,
-              name: route.name,
-              meta: { ...route.meta },
-            });
+            tabs.push(toRaw(route) as TabItem);
           }
         });
       return tabs;
@@ -114,7 +111,7 @@ export default defineComponent({
       };
       return (
         <span>
-          <TabContent {...tabContentProps} />
+          <TabContent {...(tabContentProps as any)} />
         </span>
       );
     }

+ 2 - 1
src/layouts/page/index.tsx

@@ -40,7 +40,8 @@ export default defineComponent({
           <RouterView>
             {{
               default: ({ Component, route }: { Component: any; route: RouteLocation }) => {
-                const name = route.meta.inTab ? ' ' : null;
+                // 已经位于tab内的不再显示动画
+                const name = route.meta.inTab ? 'fade' : null;
                 const Content = openCache ? (
                   <KeepAlive max={max} include={cacheTabs}>
                     <Component {...route.params} />

+ 4 - 2
src/router/guard/index.ts

@@ -7,7 +7,7 @@ import { createProgressGuard } from './progressGuard';
 import { createPermissionGuard } from './permissionGuard';
 import { createPageLoadingGuard } from './pageLoadingGuard';
 import { useSetting } from '/@/hooks/core/useSetting';
-import { getIsOpenTab } from '/@/utils/helper/routeHelper';
+import { getIsOpenTab, setCurrentTo } from '/@/utils/helper/routeHelper';
 
 const { projectSetting } = useSetting();
 export function createGuard(router: Router) {
@@ -17,7 +17,7 @@ export function createGuard(router: Router) {
     axiosCanceler = new AxiosCanceler();
   }
   router.beforeEach(async (to) => {
-    const isOpen = getIsOpenTab(to.path);
+    const isOpen = getIsOpenTab(to.fullPath);
     to.meta.inTab = isOpen;
     try {
       if (closeMessageOnSwitch) {
@@ -30,6 +30,8 @@ export function createGuard(router: Router) {
     } catch (error) {
       console.warn('basic guard error:' + error);
     }
+    setCurrentTo(to);
+    return true;
   });
   openNProgress && createProgressGuard(router);
   createPermissionGuard(router);

+ 10 - 2
src/router/guard/pageLoadingGuard.ts

@@ -2,6 +2,7 @@ import type { Router } from 'vue-router';
 import { tabStore } from '/@/store/modules/tab';
 import { appStore } from '/@/store/modules/app';
 import { userStore } from '/@/store/modules/user';
+import { getParams } from '/@/utils/helper/routeHelper';
 
 export function createPageLoadingGuard(router: Router) {
   let isFirstLoad = true;
@@ -29,9 +30,16 @@ export function createPageLoadingGuard(router: Router) {
     }
     return true;
   });
-  router.afterEach(async (to) => {
+  router.afterEach(async (to, from) => {
     const { openRouterTransition, openPageLoading } = appStore.getProjectConfig;
-    if ((!openRouterTransition && openPageLoading) || isFirstLoad || to.meta.afterCloseLoading) {
+    const realToPath = to.path.replace(getParams(to), '');
+    const realFormPath = from.path.replace(getParams(from), '');
+    if (
+      (!openRouterTransition && openPageLoading) ||
+      isFirstLoad ||
+      to.meta.afterCloseLoading ||
+      realToPath === realFormPath
+    ) {
       setTimeout(() => {
         appStore.commitPageLoadingState(false);
       }, 110);

+ 2 - 1
src/router/menus/index.ts

@@ -107,7 +107,8 @@ export async function getFlatChildrenMenus(children: Menu[]) {
 function basicFilter(routes: RouteRecordNormalized[]) {
   return (menu: Menu) => {
     const matchRoute = routes.find((route) => route.path === menu.path);
-    if (!matchRoute) return false;
+
+    if (!matchRoute) return true;
     menu.icon = menu.icon || matchRoute.meta.icon;
     menu.meta = matchRoute.meta;
     return true;

+ 14 - 0
src/router/menus/modules/demo/feat.ts

@@ -45,6 +45,20 @@ const menu: MenuModule = {
         path: '/full-screen',
         name: '全屏',
       },
+      {
+        path: '/testTab',
+        name: '带参Tab',
+        children: [
+          {
+            path: '/id1',
+            name: '带参tab1',
+          },
+          {
+            path: '/id2',
+            name: '带参tab2',
+          },
+        ],
+      },
     ],
   },
 };

+ 9 - 2
src/router/routes/index.ts

@@ -3,8 +3,6 @@ import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
 import { DEFAULT_LAYOUT_COMPONENT, PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant';
 import { genRouteModule } from '/@/utils/helper/routeHelper';
 
-import LoginRoute from './modules/sys';
-
 import dashboard from './modules/dashboard';
 
 // demo
@@ -48,5 +46,14 @@ export const RootRoute: AppRouteRecordRaw = {
   children: [],
 };
 
+export const LoginRoute: AppRouteRecordRaw = {
+  path: '/login',
+  name: 'Login',
+  component: () => import('/@/views/sys/login/Login.vue'),
+  meta: {
+    title: '登录',
+  },
+};
+
 // 基础路由 不用权限
 export const basicRoutes = [LoginRoute, RootRoute];

+ 8 - 0
src/router/routes/modules/demo/feat.ts

@@ -96,5 +96,13 @@ export default {
         title: '全屏',
       },
     },
+    {
+      path: '/testTab/:id',
+      name: 'TestTab',
+      component: () => import('/@/views/demo/feat/tab-params/index.vue'),
+      meta: {
+        title: 'Tab带参',
+      },
+    },
   ],
 } as AppRouteModule;

+ 0 - 12
src/router/routes/modules/sys.ts

@@ -1,12 +0,0 @@
-import type { AppRouteRecordRaw } from '/@/router/types';
-
-const routes: AppRouteRecordRaw = {
-  path: '/login',
-  name: 'Login',
-  component: () => import('/@/views/sys/login/Login.vue'),
-  meta: {
-    title: '登录',
-  },
-};
-
-export default routes;

+ 1 - 0
src/router/types.d.ts

@@ -39,6 +39,7 @@ export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
   components?: any;
   children?: AppRouteRecordRaw[];
   props?: any;
+  fullPath?: string;
 }
 
 export interface Menu {

+ 26 - 15
src/store/modules/tab.ts

@@ -11,6 +11,7 @@ import { appStore } from '/@/store/modules/app';
 import store from '/@/store';
 import router from '/@/router';
 import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
+import { getCurrentTo } from '/@/utils/helper/routeHelper';
 
 type CacheName = string | symbol | null | undefined;
 /**
@@ -18,7 +19,10 @@ type CacheName = string | symbol | null | undefined;
  */
 // declare namespace TabsStore {
 export interface TabItem {
-  path: string;
+  fullPath: string;
+  path?: string;
+  params?: any;
+  query?: any;
   name?: CacheName;
   meta?: RouteMeta;
 }
@@ -86,20 +90,21 @@ class Tab extends VuexModule {
    */
   @Mutation
   commitAddTab(route: AppRouteRecordRaw | TabItem): void {
-    const { path, name, meta } = route;
+    const { path, name, meta, fullPath, params, query } = route as TabItem;
     // 404  页面不需要添加tab
     if (path === PageEnum.ERROR_PAGE) {
       return;
     } else if ([REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)) {
       return;
     }
+
     // 已经存在的页面,不重复添加tab
     const hasTab = this.tabsState.some((tab) => {
-      return tab.path === path;
+      return tab.fullPath === fullPath;
     });
     if (hasTab) return;
 
-    this.tabsState.push({ path, name, meta });
+    this.tabsState.push({ path, fullPath, name, meta, params, query });
     if (unref(getOpenKeepAliveRef) && name) {
       const noKeepAlive = meta && meta.ignoreKeepAlive;
       const hasName = this.keepAliveTabsState.includes(name);
@@ -113,9 +118,9 @@ class Tab extends VuexModule {
   @Mutation
   commitCloseTab(route: AppRouteRecordRaw | TabItem): void {
     try {
-      const { path, name, meta: { affix } = {} } = route;
+      const { fullPath, name, meta: { affix } = {} } = route;
       if (affix) return;
-      const index = this.tabsState.findIndex((item) => item.path === path);
+      const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
       index !== -1 && this.tabsState.splice(index, 1);
 
       if (unref(getOpenKeepAliveRef) && name) {
@@ -153,7 +158,7 @@ class Tab extends VuexModule {
 
   @Mutation
   closeMultipleTab({ pathList, nameList }: { pathList: string[]; nameList: string[] }): void {
-    this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.path));
+    this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
     if (unref(getOpenKeepAliveRef) && nameList) {
       this.keepAliveTabsState = toRaw(this.keepAliveTabsState).filter(
         (item) => !nameList.includes(item as string)
@@ -172,7 +177,7 @@ class Tab extends VuexModule {
       for (const item of leftTabs) {
         const affix = item.meta ? item.meta.affix : false;
         if (!affix) {
-          pathList.push(item.path);
+          pathList.push(item.fullPath);
           nameList.push(item.name as string);
         }
       }
@@ -181,13 +186,19 @@ class Tab extends VuexModule {
   }
 
   @Action
-  addTabByPathAction(to: AppRouteRecordRaw): void {
-    to && this.commitAddTab((to as unknown) as AppRouteRecordRaw);
+  addTabByPathAction(): void {
+    const toRoute = getCurrentTo();
+    if (!toRoute) return;
+    const { meta } = toRoute;
+    if (meta && meta.affix) {
+      return;
+    }
+    this.commitAddTab((toRoute as unknown) as AppRouteRecordRaw);
   }
 
   @Action
   closeRightTabAction(route: AppRouteRecordRaw | TabItem): void {
-    const index = this.tabsState.findIndex((item) => item.path === route.path);
+    const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
 
     if (index >= 0 && index < this.tabsState.length - 1) {
       const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);
@@ -197,7 +208,7 @@ class Tab extends VuexModule {
       for (const item of rightTabs) {
         const affix = item.meta ? item.meta.affix : false;
         if (!affix) {
-          pathList.push(item.path);
+          pathList.push(item.fullPath);
           nameList.push(item.name as string);
         }
       }
@@ -207,16 +218,16 @@ class Tab extends VuexModule {
 
   @Action
   closeOtherTabAction(route: AppRouteRecordRaw | TabItem): void {
-    const closePathList = this.tabsState.map((item) => item.path);
+    const closePathList = this.tabsState.map((item) => item.fullPath);
     const pathList: string[] = [];
     const nameList: string[] = [];
     closePathList.forEach((path) => {
-      if (path !== route.path) {
+      if (path !== route.fullPath) {
         const closeItem = this.tabsState.find((item) => item.path === path);
         if (!closeItem) return;
         const affix = closeItem.meta ? closeItem.meta.affix : false;
         if (!affix) {
-          pathList.push(closeItem.path);
+          pathList.push(closeItem.fullPath);
           nameList.push(closeItem.name as string);
         }
       }

+ 3 - 1
src/types/source.d.ts

@@ -1,5 +1,7 @@
 declare module 'ant-design-vue/es/locale/zh_CN';
-declare module 'vue-draggable-resizable';
+declare module 'globby!/@/router/routes/modules/**/*.@(ts)';
+declare module 'globby!/@/router/menus/modules/**/*.@(ts)';
+
 declare const React: string;
 declare module '*.bmp' {
   const src: string;

+ 0 - 3
src/utils/eventHub.ts

@@ -16,9 +16,6 @@ class EventHub {
 
   emit(eventName: string, data?: any) {
     if (this.cache[eventName] === undefined) return;
-    console.log('======================');
-    console.log(this.cache, eventName);
-    console.log('======================');
     this.cache[eventName].forEach((fn) => fn(data));
   }
   off(eventName: string, fn: (data: any) => void) {

+ 2 - 2
src/utils/helper/menuHelper.ts

@@ -4,7 +4,6 @@ import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
 import { findPath, forEach, treeMap, treeToList } from './treeHelper';
 import { cloneDeep } from 'lodash-es';
 
-//
 export function getAllParentPath(treeData: any[], path: string) {
   const menuList = findPath(treeData, (n) => n.path === path) as Menu[];
   return (menuList || []).map((item) => item.path);
@@ -14,6 +13,7 @@ export function flatMenus(menus: Menu[]) {
   return treeToList(menus);
 }
 
+// 拼接父级路径
 function joinParentPath(list: any, node: any) {
   let allPaths = getAllParentPath(list, node.path);
 
@@ -26,7 +26,6 @@ function joinParentPath(list: any, node: any) {
       parentPath += /^\//.test(p) ? p : `/${p}`;
     });
   }
-
   node.path = `${parentPath}${/^\//.test(node.path) ? node.path : `/${node.path}`}`.replace(
     /\/\//g,
     '/'
@@ -34,6 +33,7 @@ function joinParentPath(list: any, node: any) {
   return node;
 }
 
+// 解析菜单模块
 export function transformMenuModule(menuModule: MenuModule): Menu {
   const { menu } = menuModule;
 

+ 26 - 1
src/utils/helper/routeHelper.ts

@@ -1,11 +1,23 @@
 import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
-import type { RouteRecordRaw } from 'vue-router';
+import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
 
 import { appStore } from '/@/store/modules/app';
 import { tabStore } from '/@/store/modules/tab';
 import { createRouter, createWebHashHistory } from 'vue-router';
 import { toRaw } from 'vue';
 import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
+
+let currentTo: RouteLocationNormalized | null = null;
+
+export function getCurrentTo() {
+  return currentTo;
+}
+
+export function setCurrentTo(to: RouteLocationNormalized) {
+  currentTo = to;
+}
+// 转化路由模块
+// 将多级转成2层。keepAlive问题
 export function genRouteModule(moduleList: AppRouteModule[]) {
   const ret: AppRouteRecordRaw[] = [];
   for (const routeMod of moduleList) {
@@ -27,6 +39,7 @@ export function genRouteModule(moduleList: AppRouteModule[]) {
   return ret as RouteRecordRaw[];
 }
 
+// 动态引入
 function asyncImportRoute(routes: AppRouteRecordRaw[]) {
   routes.forEach((item) => {
     const { component, children } = item;
@@ -37,6 +50,7 @@ function asyncImportRoute(routes: AppRouteRecordRaw[]) {
   });
 }
 
+// 将后台对象转成路由对象
 export function transformObjToRoute(routeList: AppRouteModule[]) {
   routeList.forEach((route) => {
     asyncImportRoute(route.routes);
@@ -48,6 +62,7 @@ export function transformObjToRoute(routeList: AppRouteModule[]) {
   return routeList;
 }
 
+//
 export function getIsOpenTab(toPath: string) {
   const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
 
@@ -57,3 +72,13 @@ export function getIsOpenTab(toPath: string) {
   }
   return false;
 }
+
+export function getParams(data: any = {}) {
+  const { params = {} } = data;
+  let ret = '';
+  Object.keys(params).forEach((key) => {
+    const p = params[key];
+    ret += `/${p}`;
+  });
+  return ret;
+}

+ 17 - 0
src/views/demo/feat/tab-params/index.vue

@@ -0,0 +1,17 @@
+<template>
+  <div class="p-4"> Current Param : {{ params }} </div>
+</template>
+<script lang="ts">
+  import { computed, defineComponent, unref } from 'vue';
+  import { useRouter } from 'vue-router';
+  export default defineComponent({
+    setup() {
+      const { currentRoute } = useRouter();
+      return {
+        params: computed(() => {
+          return unref(currentRoute).params;
+        }),
+      };
+    },
+  });
+</script>

+ 13 - 15
src/views/sys/redirect/index.vue

@@ -2,7 +2,7 @@
   <div />
 </template>
 <script lang="ts">
-  import { defineComponent, onBeforeMount, unref } from 'vue';
+  import { defineComponent, unref } from 'vue';
 
   import { appStore } from '/@/store/modules/app';
 
@@ -11,21 +11,19 @@
     name: 'Redirect',
     setup() {
       const { currentRoute, replace } = useRouter();
-      onBeforeMount(() => {
-        const { params, query } = unref(currentRoute);
-        const { path } = params;
-        const _path = Array.isArray(path) ? path.join('/') : path;
-        replace({
-          path: '/' + _path,
-          query,
-        });
-        const { openRouterTransition, openPageLoading } = appStore.getProjectConfig;
-        if (openRouterTransition && openPageLoading) {
-          setTimeout(() => {
-            appStore.setPageLoadingAction(false);
-          }, 0);
-        }
+      const { params, query } = unref(currentRoute);
+      const { path } = params;
+      const _path = Array.isArray(path) ? path.join('/') : path;
+      replace({
+        path: '/' + _path,
+        query,
       });
+      const { openRouterTransition, openPageLoading } = appStore.getProjectConfig;
+      if (openRouterTransition && openPageLoading) {
+        setTimeout(() => {
+          appStore.setPageLoadingAction(false);
+        }, 0);
+      }
       return {};
     },
   });

+ 1 - 1
vite.config.ts

@@ -71,7 +71,7 @@ const viteConfig: UserConfig = {
    *  boolean | 'terser' | 'esbuild'
    * @default 'terser'
    */
-  minify: isDevFn() ? false : 'terser',
+  minify: 'terser',
   /**
    * 基本公共路径
    * @default '/'