Browse Source

perf: perf menu

vben 4 years ago
parent
commit
88f4a3f02a

+ 14 - 7
src/components/Application/src/AppLocalePicker.vue

@@ -8,10 +8,10 @@
     :dropMenuList="localeList"
     :selectedKeys="selectedKeys"
     @menuEvent="handleMenuEvent"
-    overlayClassName="app-locale-picker-overlay"
+    :overlayClassName="`${prefixCls}-overlay`"
   >
-    <span class="app-local-picker">
-      <GlobalOutlined class="app-local-picker__icon" />
+    <span :class="prefixCls">
+      <GlobalOutlined :class="`${prefixCls}__icon`" />
       <span v-if="showText">{{ getLangText }}</span>
     </span>
   </Dropdown>
@@ -28,6 +28,7 @@
   import { LocaleType } from '/@/locales/types';
 
   import { propTypes } from '/@/utils/propTypes';
+  import { useDesign } from '/@/hooks/web/useDesign';
 
   export default defineComponent({
     name: 'AppLocalPicker',
@@ -39,9 +40,12 @@
       reload: propTypes.bool,
     },
     setup(props) {
-      const { localeList } = useLocaleSetting();
       const selectedKeys = ref<string[]>([]);
 
+      const { prefixCls } = useDesign('app-locale-picker');
+
+      const { localeList } = useLocaleSetting();
+
       const { changeLocale, getLang } = useLocale();
 
       const getLangText = computed(() => {
@@ -64,19 +68,22 @@
         toggleLocale(menu.event as string);
       }
 
-      return { localeList, handleMenuEvent, selectedKeys, getLangText };
+      return { localeList, handleMenuEvent, selectedKeys, getLangText, prefixCls };
     },
   });
 </script>
 
 <style lang="less" scoped>
-  :global(.app-locale-picker-overlay) {
+  @import (reference) '../../../design/index.less';
+  @prefix-cls: ~'@{namespace}-app-locale-picker';
+
+  :global(.@{prefix-cls}-overlay) {
     .ant-dropdown-menu-item {
       min-width: 160px;
     }
   }
 
-  .app-local-picker {
+  .@{prefix-cls} {
     display: flex;
     align-items: center;
     cursor: pointer;

+ 7 - 1
src/components/Basic/src/BasicArrow.vue

@@ -20,15 +20,17 @@
       expand: propTypes.bool,
       top: propTypes.bool,
       bottom: propTypes.bool,
+      inset: propTypes.bool,
     },
     setup(props) {
       const getClass = computed(() => {
-        const { expand, top, bottom } = props;
+        const { expand, top, bottom, inset } = props;
         return [
           'base-arrow',
           {
             'base-arrow__active': expand,
             top,
+            inset,
             bottom,
           },
         ];
@@ -47,6 +49,10 @@
     transition: all 0.3s ease 0.1s;
     transform-origin: center center;
 
+    &.inset {
+      line-height: 0px;
+    }
+
     &__active {
       transform: rotate(90deg);
     }

+ 140 - 134
src/components/Menu/src/BasicMenu.tsx

@@ -9,14 +9,15 @@ import {
   unref,
   reactive,
   watch,
-  onMounted,
-  ref,
   toRefs,
   ComputedRef,
+  ref,
+  CSSProperties,
 } from 'vue';
 import { Menu } from 'ant-design-vue';
 import MenuContent from './MenuContent';
 // import { ScrollContainer } from '/@/components/Container';
+// import { BasicArrow } from '/@/components/Basic';
 
 import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
 import { ThemeEnum } from '/@/enums/appEnum';
@@ -29,18 +30,20 @@ import { useRouter } from 'vue-router';
 import { isFunction } from '/@/utils/is';
 import { getSlot } from '/@/utils/helper/tsxHelper';
 import { menuHasChildren } from './helper';
-
 import { getCurrentParentPath } from '/@/router/menus';
 
 import { basicProps } from './props';
 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
 import { REDIRECT_NAME } from '/@/router/constant';
+import { tabStore } from '/@/store/modules/tab';
+import { useDesign } from '/@/hooks/web/useDesign';
 export default defineComponent({
   name: 'BasicMenu',
   props: basicProps,
   emits: ['menuClick'],
   setup(props, { slots, emit }) {
     const currentParentPath = ref('');
+    const isClickGo = ref(false);
 
     const menuState = reactive<MenuState>({
       defaultSelectedKeys: [],
@@ -51,170 +54,184 @@ export default defineComponent({
       collapsedOpenKeys: [],
     });
 
-    const { getCollapsed } = useMenuSetting();
+    const { prefixCls } = useDesign('basic-menu');
 
-    const { currentRoute } = useRouter();
+    const { items, mode, accordion } = toRefs(props);
+
+    const { getCollapsed, getIsHorizontal, getTopMenuAlign, getSplit } = useMenuSetting();
 
-    const { items, flatItems, mode, accordion } = toRefs(props);
+    const { currentRoute } = useRouter();
 
-    const { handleOpenChange, resetKeys, setOpenKeys } = useOpenKeys(
+    const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(
       menuState,
       items,
-      flatItems,
       mode,
       accordion
     );
 
-    const getOpenKeys = computed(() => {
-      return unref(getCollapsed) ? menuState.collapsedOpenKeys : menuState.openKeys;
+    const getMenuClass = computed(() => {
+      const { type } = props;
+      const { mode } = menuState;
+      return [
+        prefixCls,
+        `justify-${unref(getTopMenuAlign)}`,
+        {
+          [`${prefixCls}--hide-title`]: !unref(showTitle),
+          [`${prefixCls}--collapsed-show-title`]: props.collapsedShowTitle,
+          [`${prefixCls}__second`]:
+            !props.isHorizontal && appStore.getProjectConfig.menuSetting.split,
+          [`${prefixCls}__sidebar-hor`]:
+            type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL,
+        },
+      ];
     });
 
-    // menu外层样式
-    const getMenuWrapStyle = computed((): any => {
-      const { showLogo } = props;
-      let offset = 0;
-
-      if (showLogo) {
-        offset += 46;
-      }
-      return {
-        height: `calc(100% - ${offset}px)`,
-        position: 'relative',
-        overflowY: 'auto',
-      };
-    });
+    const showTitle = computed(() => props.collapsedShowTitle && unref(getCollapsed));
 
-    // 是否透明化左侧一级菜单
-    const transparentMenuClass = computed(() => {
-      const { type } = props;
-      const { mode } = menuState;
-      const cls: string[] = [];
-      if (
-        (type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL) ||
-        props.appendClass
-      ) {
-        cls.push('basic-menu__sidebar-hor');
-      }
+    const getInlineCollapseOptions = computed(() => {
+      const isInline = props.mode === MenuModeEnum.INLINE;
 
-      if (!props.isHorizontal && appStore.getProjectConfig.menuSetting.split) {
-        cls.push('basic-menu__second');
+      const inlineCollapseOptions: { inlineCollapsed?: boolean } = {};
+      if (isInline) {
+        inlineCollapseOptions.inlineCollapsed = unref(getCollapsed);
       }
-      return cls;
+      return inlineCollapseOptions;
     });
 
-    const showTitle = computed(() => props.collapsedShowTitle && unref(getCollapsed));
+    const getWrapperStyle = computed(
+      (): CSSProperties => {
+        const isHorizontal = unref(getIsHorizontal);
+        return {
+          height: isHorizontal
+            ? `calc(100% + 1px)`
+            : `calc(100%  - ${props.showLogo ? '48px' : '0'})`,
+          overflowY: isHorizontal ? 'hidden' : 'auto',
+        };
+      }
+    );
 
     watch(
-      () => currentRoute.value.name,
-      (name: string) => {
-        if (name === REDIRECT_NAME) return;
+      () => tabStore.getCurrentTab,
+      () => {
+        if (unref(currentRoute).name === REDIRECT_NAME) return;
         handleMenuChange();
-        props.isHorizontal && appStore.getProjectConfig.menuSetting.split && getParentPath();
+        unref(getSplit) && getParentPath();
       }
     );
 
     watch(
       () => props.items,
       () => {
-        if (props.items) {
-          handleMenuChange();
-        }
+        handleMenuChange();
       },
       {
         immediate: true,
       }
     );
 
+    getParentPath();
+
     async function getParentPath() {
       const { appendClass } = props;
       if (!appendClass) return '';
       const parentPath = await getCurrentParentPath(unref(currentRoute).path);
+
       currentParentPath.value = parentPath;
     }
 
-    async function handleMenuClick(menu: MenuType) {
+    async function handleMenuClick({ key, keyPath }: { key: string; keyPath: string[] }) {
       const { beforeClickFn } = props;
       if (beforeClickFn && isFunction(beforeClickFn)) {
-        const flag = await beforeClickFn(menu);
+        const flag = await beforeClickFn(key);
         if (!flag) return;
       }
-      emit('menuClick', menu);
-      const { path } = menu;
-      menuState.selectedKeys = [path];
+      emit('menuClick', key);
+
+      isClickGo.value = true;
+      menuState.openKeys = keyPath;
+      menuState.selectedKeys = [key];
     }
 
     function handleMenuChange() {
-      const { flatItems } = props;
-      if (!unref(flatItems) || flatItems.length === 0) return;
-      const findMenu = flatItems.find((menu) => menu.path === unref(currentRoute).path);
-      if (findMenu) {
-        if (menuState.mode !== MenuModeEnum.HORIZONTAL) {
-          setOpenKeys(findMenu);
-        }
-        menuState.selectedKeys = [findMenu.path];
-      } else {
-        resetKeys();
+      if (unref(isClickGo)) {
+        isClickGo.value = false;
+        return;
       }
+      const path = unref(currentRoute).path;
+      if (menuState.mode !== MenuModeEnum.HORIZONTAL) {
+        setOpenKeys(path);
+      }
+      menuState.selectedKeys = [path];
     }
 
-    // render menu item
-    function renderMenuItem(menuList?: MenuType[], index = 1) {
-      if (!menuList) return;
+    // function renderExpandIcon({ key }: { key: string }) {
+    //   const isOpen = getOpenKeys.value.includes(key);
+    //   const collapsed = unref(getCollapsed);
+    //   return (
+    //     <BasicArrow
+    //       expand={isOpen}
+    //       bottom
+    //       inset
+    //       class={[
+    //         `${prefixCls}__expand-icon`,
+    //         {
+    //           [`${prefixCls}__expand-icon--collapsed`]: collapsed,
+    //         },
+    //       ]}
+    //     />
+    //   );
+    // }
+
+    function renderItem(menu: MenuType, level = 1) {
+      return !menuHasChildren(menu) ? renderMenuItem(menu, level) : renderSubMenu(menu, level);
+    }
+
+    function renderMenuItem(menu: MenuType, level: number) {
       const { appendClass } = props;
-      const levelCls = `basic-menu-item__level${index} ${menuState.theme} `;
-      return menuList.map((menu) => {
-        if (!menu) {
-          return null;
-        }
-
-        const isAppendActiveCls =
-          appendClass && index === 1 && menu.path === unref(currentParentPath);
-        // 没有子节点
-        if (!menuHasChildren(menu)) {
-          return (
-            <Menu.Item
-              key={menu.path}
-              class={`${levelCls}${isAppendActiveCls ? ' top-active-menu ' : ''}`}
-              onClick={handleMenuClick.bind(null, menu)}
-            >
-              {() => [
-                <MenuContent
-                  item={menu}
-                  level={index}
-                  isHorizontal={props.isHorizontal}
-                  showTitle={unref(showTitle)}
-                />,
-              ]}
-            </Menu.Item>
-          );
-        }
-        return (
-          <Menu.SubMenu key={menu.path} class={levelCls}>
-            {{
-              title: () => [
-                <MenuContent
-                  showTitle={unref(showTitle)}
-                  item={menu}
-                  level={index}
-                  isHorizontal={props.isHorizontal}
-                />,
-              ],
-              default: () => renderMenuItem(menu.children, index + 1),
-            }}
-          </Menu.SubMenu>
-        );
-      });
+      const isAppendActiveCls =
+        appendClass && level === 1 && menu.path === unref(currentParentPath);
+      const levelCls = [
+        `${prefixCls}-item__level${level}`,
+        ` ${menuState.theme} `,
+        {
+          'top-active-menu': isAppendActiveCls,
+        },
+      ];
+      return (
+        <Menu.Item key={menu.path} class={levelCls}>
+          {() => [
+            <MenuContent
+              item={menu}
+              showTitle={unref(showTitle)}
+              isHorizontal={props.isHorizontal}
+            />,
+          ]}
+        </Menu.Item>
+      );
+    }
+
+    function renderSubMenu(menu: MenuType, level: number) {
+      const levelCls = `${prefixCls}-item__level${level} ${menuState.theme} `;
+      return (
+        <Menu.SubMenu key={menu.path} class={levelCls}>
+          {{
+            title: () => [
+              <MenuContent
+                showTitle={unref(showTitle)}
+                item={menu}
+                isHorizontal={props.isHorizontal}
+              />,
+            ],
+            // expandIcon: renderExpandIcon,
+            default: () => (menu.children || []).map((item) => renderItem(item, level + 1)),
+          }}
+        </Menu.SubMenu>
+      );
     }
 
     function renderMenu() {
-      const isInline = props.mode === MenuModeEnum.INLINE;
       const { selectedKeys, defaultSelectedKeys, mode, theme } = menuState;
 
-      const inlineCollapsedObj = isInline
-        ? {
-            inlineCollapsed: unref(getCollapsed),
-          }
-        : {};
       return (
         <Menu
           selectedKeys={selectedKeys}
@@ -224,36 +241,25 @@ export default defineComponent({
           inlineIndent={props.inlineIndent}
           theme={unref(theme)}
           onOpenChange={handleOpenChange}
-          class={[
-            'basic-menu',
-            props.collapsedShowTitle && 'collapsed-show-title',
-            ...unref(transparentMenuClass),
-          ]}
-          {...inlineCollapsedObj}
+          class={unref(getMenuClass)}
+          onClick={handleMenuClick}
+          {...unref(getInlineCollapseOptions)}
         >
           {{
-            default: () => renderMenuItem(props.items, 1),
+            default: () => unref(items).map((item) => renderItem(item)),
           }}
         </Menu>
       );
     }
 
-    onMounted(async () => {
-      getParentPath();
-    });
-
     return () => {
-      const { mode } = props;
-      return mode === MenuModeEnum.HORIZONTAL ? (
-        renderMenu()
-      ) : (
-        <section class={[`basic-menu-wrap`, !unref(showTitle) && 'hide-title']}>
-          {getSlot(slots, 'header')}
-
-          <section style={unref(getMenuWrapStyle)} class="basic-menu__content">
+      return (
+        <>
+          {!unref(getIsHorizontal) && getSlot(slots, 'header')}
+          <div class={`${prefixCls}-wrapper`} style={unref(getWrapperStyle)}>
             {renderMenu()}
-          </section>
-        </section>
+          </div>
+        </>
       );
     };
   },

+ 0 - 11
src/components/Menu/src/BasicMenu.vue

@@ -1,11 +0,0 @@
-<template>
-  <div> </div>
-</template>
-<script lang="ts">
-  import { defineComponent } from 'vue';
-  export default defineComponent({
-    setup() {
-      return {};
-    },
-  });
-</script>

+ 35 - 20
src/components/Menu/src/MenuContent.tsx

@@ -1,9 +1,13 @@
 import type { Menu as MenuType } from '/@/router/types';
-import { computed, PropType, unref } from 'vue';
+import type { PropType } from 'vue';
+import { computed, unref } from 'vue';
 
 import { defineComponent } from 'vue';
 import Icon from '/@/components/Icon/index';
 import { useI18n } from '/@/hooks/web/useI18n';
+import { useDesign } from '/@/hooks/web/useDesign';
+
+const { t } = useI18n();
 
 export default defineComponent({
   name: 'MenuContent',
@@ -12,12 +16,10 @@ export default defineComponent({
       type: Object as PropType<MenuType>,
       default: null,
     },
-
     showTitle: {
       type: Boolean as PropType<boolean>,
       default: true,
     },
-
     level: {
       type: Number as PropType<number>,
       default: 0,
@@ -28,13 +30,32 @@ export default defineComponent({
     },
   },
   setup(props) {
-    const { t } = useI18n();
+    const { prefixCls } = useDesign('basic-menu');
 
     const getI18nName = computed(() => t(props.item?.name));
+
+    const getTagClass = computed(() => {
+      const { item } = props;
+      const { tag = {} } = item || {};
+      const { dot, type = 'error' } = tag;
+      return [
+        `${prefixCls}__tag`,
+        type,
+        {
+          dot,
+        },
+      ];
+    });
+
+    const getNameClass = computed(() => {
+      const { showTitle } = props;
+      return { [`${prefixCls}--show-title`]: showTitle, [`${prefixCls}__name`]: !showTitle };
+    });
+
     /**
      * @description: 渲染图标
      */
-    function renderIcon(icon: string) {
+    function renderIcon(icon?: string) {
       return icon ? <Icon icon={icon} size={18} class="menu-item-icon" /> : null;
     }
 
@@ -45,36 +66,30 @@ export default defineComponent({
       const { tag } = item;
       if (!tag) return null;
 
-      const { dot, content, type = 'error' } = tag;
+      const { dot, content } = tag;
       if (!dot && !content) return null;
-      const cls = ['basic-menu__tag'];
-
-      dot && cls.push('dot');
-      type && cls.push(type);
 
-      return <span class={cls}>{dot ? '' : content}</span>;
+      return <span class={unref(getTagClass)}>{dot ? '' : content}</span>;
     }
 
     return () => {
-      if (!props.item) {
+      const { item } = props;
+      if (!item) {
         return null;
       }
-      const { showTitle } = props;
-      const { icon } = props.item;
+      const { icon } = item;
       const name = unref(getI18nName);
 
-      const cls = showTitle ? ['show-title'] : ['basic-menu__name'];
-
       return (
-        <>
-          {renderIcon(icon!)}
+        <span class={`${prefixCls}__content-wrapper`}>
+          {renderIcon(icon)}
           {
-            <span class={[cls]}>
+            <span class={unref(getNameClass)}>
               {name}
               {renderTag()}
             </span>
           }
-        </>
+        </span>
       );
     };
   },

+ 119 - 126
src/components/Menu/src/index.less

@@ -1,5 +1,7 @@
 @import (reference) '../../../design/index.less';
 
+@basic-menu-prefix-cls: ~'@{namespace}-basic-menu';
+
 .active-style() {
   color: @white;
   background: linear-gradient(
@@ -16,21 +18,48 @@
   }
 }
 
-.basic-menu {
+.@{basic-menu-prefix-cls} {
   width: 100%;
 
-  &-wrap {
-    height: 100%;
-  }
+  // &__expand-icon {
+  //   position: absolute;
+  //   top: calc(50% - 6px);
+  //   right: 16px;
+  //   width: 10px;
+  //   transform-origin: none;
+
+  //   span[role='img'] {
+  //     margin-right: 0;
+  //     font-size: 11px;
+  //   }
+
+  //   &--collapsed {
+  //     opacity: 0;
+  //   }
+  // }
 
   //  collapsed show title start
-  .show-title {
+  &--show-title {
     max-width: unset !important;
     opacity: 1 !important;
   }
 
-  &.collapsed-show-title.ant-menu-inline-collapsed {
-    .basic-menu-item__level1 {
+  &--hide-title {
+    &.ant-menu-inline-collapsed > .ant-menu-item,
+    &.ant-menu-inline-collapsed > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,
+    &.ant-menu-inline-collapsed
+      > .ant-menu-item-group
+      > .ant-menu-item-group-list
+      > .ant-menu-submenu
+      > .ant-menu-submenu-title,
+    &.ant-menu-inline-collapsed > .ant-menu-submenu > .ant-menu-submenu-title {
+      padding-right: 20px !important;
+      padding-left: 20px !important;
+    }
+  }
+
+  &--collapsed-show-title.ant-menu-inline-collapsed {
+    .@{basic-menu-prefix-cls}-item__level1 {
       padding: 2px 0;
     }
 
@@ -47,14 +76,23 @@
     & > li > .ant-menu-submenu-title {
       line-height: 24px;
     }
+    .@{basic-menu-prefix-cls}__content-wrapper {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      flex-direction: column;
+      .@{basic-menu-prefix-cls}--show-title {
+        line-height: 30px;
+      }
+    }
   }
 
-  .ant-menu-item {
-    transition: unset;
-  }
+  // .ant-menu-item {
+  //   transition: unset;
+  // }
 
   // scrollbar -s tart
-  &__content {
+  &-wrapper {
     /* 滚动槽 */
     &::-webkit-scrollbar {
       width: 5px;
@@ -75,8 +113,20 @@
       background: @border-color-dark;
     }
   }
+
   // scrollbar  end
 
+  &-item__level1.light {
+    &.top-active-menu {
+      top: 0 !important;
+    }
+
+    &.top-active-menu:not(.ant-menu-item-selected) {
+      color: @primary-color;
+      border-bottom: 3px solid @primary-color;
+    }
+  }
+
   &__sidebar-hor {
     // overflow: hidden;
 
@@ -85,20 +135,13 @@
       border: 0;
       align-items: center;
 
-      .basic-menu-item__level1 {
+      .@{basic-menu-prefix-cls}-item__level1 {
         margin-right: 2px;
       }
 
       &.ant-menu-light {
-        .basic-menu-item__level1 {
-          &.top-active-menu {
-            color: @primary-color;
-            border-bottom: 3px solid @primary-color;
-          }
-        }
-
         .ant-menu-item {
-          &.basic-menu-item__level1 {
+          &.@{basic-menu-prefix-cls}-item__level1 {
             height: @header-height;
             line-height: @header-height;
           }
@@ -155,7 +198,7 @@
           background: @top-menu-active-bg-color;
         }
 
-        .basic-menu-item__level1 {
+        .@{basic-menu-prefix-cls}-item__level1 {
           background: transparent;
 
           &.top-active-menu {
@@ -172,7 +215,7 @@
 
         .ant-menu-item,
         .ant-menu-submenu {
-          &.basic-menu-item__level1,
+          &.@{basic-menu-prefix-cls}-item__level1,
           .ant-menu-submenu-title {
             height: @header-height;
             line-height: @header-height;
@@ -182,17 +225,17 @@
     }
   }
 
-  &:not(.basic-menu__sidebar-hor).ant-menu-inline-collapsed {
-    .basic-menu-item__level1 {
+  &:not(.@{basic-menu-prefix-cls}__sidebar-hor).ant-menu-inline-collapsed {
+    .@{basic-menu-prefix-cls}-item__level1 {
       > div {
         align-items: center;
       }
     }
   }
 
-  &.ant-menu-dark:not(.basic-menu__sidebar-hor):not(.basic-menu__second) {
+  &.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor):not(.@{basic-menu-prefix-cls}__second) {
     // Reset menu item row height
-    .ant-menu-item:not(.basic-menu-item__level1),
+    .ant-menu-item:not(.@{basic-menu-prefix-cls}-item__level1),
     .ant-menu-sub.ant-menu-inline > .ant-menu-item,
     .ant-menu-sub.ant-menu-inline > .ant-menu-submenu > .ant-menu-submenu-title {
       height: @app-menu-item-height;
@@ -200,28 +243,28 @@
       line-height: @app-menu-item-height;
     }
 
-    .ant-menu-item.basic-menu-item__level1 {
+    .ant-menu-item.@{basic-menu-prefix-cls}-item__level1 {
       height: @app-menu-item-height;
       line-height: @app-menu-item-height;
     }
   }
 
   // 层级样式
-  &.ant-menu-dark:not(.basic-menu__sidebar-hor) {
-    overflow-x: hidden;
+  &.ant-menu-dark:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
+    overflow: hidden;
     background: @sider-dark-bg-color;
     .active-menu-style();
 
-    .menu-item-icon.app-iconify {
-      display: inline-block !important;
-    }
+    // .menu-item-icon.app-iconify {
+    //   display: inline-block !important;
+    // }
 
-    .ant-menu-item.ant-menu-item-selected.basic-menu-menu-item__level1,
-    .ant-menu-submenu-selected.basic-menu-menu-item__level1 {
+    .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
+    .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
       color: @white;
     }
 
-    .basic-menu-item__level1 {
+    .@{basic-menu-prefix-cls}-item__level1 {
       background-color: @sider-dark-bg-color;
 
       > .ant-menu-sub > li {
@@ -229,12 +272,12 @@
       }
     }
 
-    .basic-menu-item__level2:not(.ant-menu-item-selected),
+    .@{basic-menu-prefix-cls}-item__level2:not(.ant-menu-item-selected),
     .ant-menu-sub {
       background-color: @sider-dark-lighten-1-bg-color;
     }
 
-    .basic-menu-item__level3:not(.ant-menu-item-selected) {
+    .@{basic-menu-prefix-cls}-item__level3:not(.ant-menu-item-selected) {
       background-color: @sider-dark-lighten-2-bg-color;
 
       .ant-menu-item {
@@ -257,35 +300,26 @@
     }
   }
 
-  &.ant-menu-light:not(.basic-menu__sidebar-hor) {
-    overflow-x: hidden;
+  &.ant-menu-light:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
+    overflow: hidden;
     border-right: none;
 
-    .menu-item-icon.app-iconify {
-      display: inline-block !important;
-    }
-
-    // .ant-menu-item-selected {
-    //   background: fade(@primary-color, 18%);
+    // .menu-item-icon.app-iconify {
+    //   display: inline-block !important;
     // }
 
-    .ant-menu-item.ant-menu-item-selected.basic-menu-menu-item__level1,
-    .ant-menu-submenu-selected.basic-menu-menu-item__level1 {
+    .ant-menu-item.ant-menu-item-selected.@{basic-menu-prefix-cls}-menu-item__level1,
+    .ant-menu-submenu-selected.@{basic-menu-prefix-cls}-menu-item__level1 {
       color: @primary-color;
     }
   }
 
-  // 关键字的颜色
-  &__keyword {
-    color: lighten(@primary-color, 20%);
-  }
-
   // 激活的子菜单样式
   .ant-menu-item.ant-menu-item-selected {
     position: relative;
   }
 
-  &.basic-menu__second.ant-menu-inline-collapsed:not(.basic-menu__sidebar-hor) {
+  &.@{basic-menu-prefix-cls}__second.ant-menu-inline-collapsed:not(.@{basic-menu-prefix-cls}__sidebar-hor) {
     // Reset menu item row height
     .ant-menu-item,
     .ant-menu-sub.ant-menu-inline > .ant-menu-item,
@@ -298,26 +332,40 @@
       align-items: center;
     }
   }
-}
+  .@{basic-menu-prefix-cls}__tag {
+    position: absolute;
+    top: calc(50% - 8px);
+    right: 30px;
+    display: inline-block;
+    padding: 2px 4px;
+    margin-right: 4px;
+    font-size: 12px;
+    line-height: 14px;
+    color: #fff;
+    border-radius: 2px;
+
+    &.dot {
+      top: calc(50% - 4px);
+      width: 8px;
+      height: 8px;
+      padding: 0;
+      border-radius: 50%;
+    }
 
-// 触发器样式
-.ant-layout-sider {
-  &-dark {
-    .ant-layout-sider-trigger {
-      color: darken(@white, 25%);
-      background: @trigger-dark-bg-color;
+    &.primary {
+      background: @primary-color;
+    }
 
-      &:hover {
-        color: @white;
-        background: @trigger-dark-hover-bg-color;
-      }
+    &.error {
+      background: @error-color;
+    }
+
+    &.success {
+      background: @success-color;
     }
-  }
 
-  &-light {
-    .ant-layout-sider-trigger {
-      color: @text-color-base;
-      border-top: 1px solid @border-color-light;
+    &.warn {
+      background: @warning-color;
     }
   }
 }
@@ -332,71 +380,16 @@
   }
 }
 
-.hide-title {
-  .ant-menu-inline-collapsed > .ant-menu-item,
-  .ant-menu-inline-collapsed > .ant-menu-item-group > .ant-menu-item-group-list > .ant-menu-item,
-  .ant-menu-inline-collapsed
-    > .ant-menu-item-group
-    > .ant-menu-item-group-list
-    > .ant-menu-submenu
-    > .ant-menu-submenu-title,
-  .ant-menu-inline-collapsed > .ant-menu-submenu > .ant-menu-submenu-title {
-    padding-right: 20px !important;
-    padding-left: 20px !important;
-  }
-
-  .ant-menu-inline-collapsed {
-    .basic-menu-item__level1 {
-      display: flex;
-      justify-content: center;
-    }
-  }
-}
 // collapsed show title end
 .ant-menu-item,
 .ant-menu-submenu-title {
-  > .basic-menu__name {
+  > .@{basic-menu-prefix-cls}__name {
     width: 100%;
 
-    .basic-menu__tag {
+    .@{basic-menu-prefix-cls}__tag {
       float: right;
       margin-top: @app-menu-item-height / 2;
       transform: translate(0%, -50%);
     }
   }
 }
-
-.basic-menu__tag {
-  display: inline-block;
-  padding: 2px 4px;
-  margin-right: 4px;
-  font-size: 12px;
-  line-height: 14px;
-  color: #fff;
-  border-radius: 2px;
-
-  &.dot {
-    width: 8px;
-    height: 8px;
-    padding: 0;
-    margin-top: 21px !important;
-    margin-bottom: 2px;
-    border-radius: 50%;
-  }
-
-  &.primary {
-    background: @primary-color;
-  }
-
-  &.error {
-    background: @error-color;
-  }
-
-  &.success {
-    background: @success-color;
-  }
-
-  &.warn {
-    background: @warning-color;
-  }
-}

+ 6 - 10
src/components/Menu/src/props.ts

@@ -8,14 +8,11 @@ export const basicProps = {
     type: Array as PropType<Menu[]>,
     default: () => [],
   },
-  flatItems: {
-    type: Array as PropType<Menu[]>,
-    default: () => [],
-  },
   appendClass: {
     type: Boolean as PropType<boolean>,
     default: false,
   },
+
   collapsedShowTitle: {
     type: Boolean as PropType<boolean>,
     default: false,
@@ -31,6 +28,10 @@ export const basicProps = {
     type: String as PropType<MenuModeEnum>,
     default: MenuModeEnum.INLINE,
   },
+  showLogo: {
+    type: Boolean as PropType<boolean>,
+    default: false,
+  },
   type: {
     type: String as PropType<MenuTypeEnum>,
     default: MenuTypeEnum.MIX,
@@ -39,10 +40,6 @@ export const basicProps = {
     type: String as PropType<string>,
     default: ThemeEnum.DARK,
   },
-  showLogo: {
-    type: Boolean as PropType<boolean>,
-    default: false,
-  },
   inlineCollapsed: {
     type: Boolean as PropType<boolean>,
     default: false,
@@ -57,7 +54,6 @@ export const basicProps = {
     default: true,
   },
   beforeClickFn: {
-    type: Function as PropType<Fn>,
-    default: null,
+    type: Function as PropType<(key: string) => Promise<boolean>>,
   },
 };

+ 12 - 11
src/components/Menu/src/useOpenKeys.ts

@@ -1,34 +1,35 @@
 import { MenuModeEnum } from '/@/enums/menuEnum';
 import type { Menu as MenuType } from '/@/router/types';
 import type { MenuState } from './types';
-import type { Ref } from 'vue';
+
+import { computed, Ref, toRaw } from 'vue';
 
 import { unref } from 'vue';
-import { getAllParentPath } from '/@/router/helper/menuHelper';
 import { es6Unique } from '/@/utils';
 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
+import { getAllParentPath } from '/@/router/helper/menuHelper';
 
 export function useOpenKeys(
   menuState: MenuState,
   menus: Ref<MenuType[]>,
-  flatMenusRef: Ref<MenuType[]>,
   mode: Ref<MenuModeEnum>,
   accordion: Ref<boolean>
 ) {
   const { getCollapsed } = useMenuSetting();
 
-  function setOpenKeys(menu: MenuType) {
-    const flatMenus = unref(flatMenusRef);
+  function setOpenKeys(path: string) {
+    const menuList = toRaw(menus.value);
     if (!unref(accordion)) {
-      menuState.openKeys = es6Unique([
-        ...menuState.openKeys,
-        ...getAllParentPath(flatMenus, menu.path),
-      ]);
+      menuState.openKeys = es6Unique([...menuState.openKeys, ...getAllParentPath(menuList, path)]);
     } else {
-      menuState.openKeys = getAllParentPath(flatMenus, menu.path);
+      menuState.openKeys = getAllParentPath(menuList, path);
     }
   }
 
+  const getOpenKeys = computed(() => {
+    return unref(getCollapsed) ? menuState.collapsedOpenKeys : menuState.openKeys;
+  });
+
   /**
    * @description:  重置值
    */
@@ -59,5 +60,5 @@ export function useOpenKeys(
       }
     }
   }
-  return { setOpenKeys, resetKeys, handleOpenChange };
+  return { setOpenKeys, resetKeys, getOpenKeys, handleOpenChange };
 }

+ 51 - 51
src/hooks/setting/useHeaderSetting.ts

@@ -11,76 +11,76 @@ import { useFullContent } from '/@/hooks/web/useFullContent';
 
 import { MenuModeEnum } from '/@/enums/menuEnum';
 
-export function useHeaderSetting() {
-  const { getFullContent } = useFullContent();
-  const { getShowMultipleTab } = useMultipleTabSetting();
-  const {
-    getMenuMode,
-    getSplit,
-    getShowHeaderTrigger,
-    getIsSidebarType,
-    getIsTopMenu,
-  } = useMenuSetting();
-  const { getShowBreadCrumb, getShowLogo } = useRootSetting();
+const { getFullContent } = useFullContent();
+const { getShowMultipleTab } = useMultipleTabSetting();
+const {
+  getMenuMode,
+  getSplit,
+  getShowHeaderTrigger,
+  getIsSidebarType,
+  getIsTopMenu,
+} = useMenuSetting();
+const { getShowBreadCrumb, getShowLogo } = useRootSetting();
 
-  const getShowMixHeaderRef = computed(() => !unref(getIsSidebarType) && unref(getShowHeader));
+const getShowMixHeaderRef = computed(() => !unref(getIsSidebarType) && unref(getShowHeader));
 
-  const getShowFullHeaderRef = computed(() => {
-    return (
-      !unref(getFullContent) &&
-      unref(getShowMixHeaderRef) &&
-      unref(getShowHeader) &&
-      !unref(getIsTopMenu)
-    );
-  });
+const getShowFullHeaderRef = computed(() => {
+  return (
+    !unref(getFullContent) &&
+    unref(getShowMixHeaderRef) &&
+    unref(getShowHeader) &&
+    !unref(getIsTopMenu)
+  );
+});
 
-  const getShowInsetHeaderRef = computed(() => {
-    const need = !unref(getFullContent) && unref(getShowHeader);
-    return (need && !unref(getShowMixHeaderRef)) || (need && unref(getIsTopMenu));
-  });
+const getShowInsetHeaderRef = computed(() => {
+  const need = !unref(getFullContent) && unref(getShowHeader);
+  return (need && !unref(getShowMixHeaderRef)) || (need && unref(getIsTopMenu));
+});
 
-  // Get header configuration
-  const getHeaderSetting = computed(() => appStore.getProjectConfig.headerSetting);
+// Get header configuration
+const getHeaderSetting = computed(() => appStore.getProjectConfig.headerSetting);
 
-  const getShowDoc = computed(() => unref(getHeaderSetting).showDoc);
+const getShowDoc = computed(() => unref(getHeaderSetting).showDoc);
 
-  const getHeaderTheme = computed(() => unref(getHeaderSetting).theme);
+const getHeaderTheme = computed(() => unref(getHeaderSetting).theme);
 
-  const getShowHeader = computed(() => unref(getHeaderSetting).show);
+const getShowHeader = computed(() => unref(getHeaderSetting).show);
 
-  const getFixed = computed(() => unref(getHeaderSetting).fixed);
+const getFixed = computed(() => unref(getHeaderSetting).fixed);
 
-  const getHeaderBgColor = computed(() => unref(getHeaderSetting).bgColor);
+const getHeaderBgColor = computed(() => unref(getHeaderSetting).bgColor);
 
-  const getShowRedo = computed(() => unref(getHeaderSetting).showRedo && unref(getShowMultipleTab));
+const getShowRedo = computed(() => unref(getHeaderSetting).showRedo && unref(getShowMultipleTab));
 
-  const getUseLockPage = computed(() => unref(getHeaderSetting).useLockPage);
+const getUseLockPage = computed(() => unref(getHeaderSetting).useLockPage);
 
-  const getShowFullScreen = computed(() => unref(getHeaderSetting).showFullScreen);
+const getShowFullScreen = computed(() => unref(getHeaderSetting).showFullScreen);
 
-  const getShowNotice = computed(() => unref(getHeaderSetting).showNotice);
+const getShowNotice = computed(() => unref(getHeaderSetting).showNotice);
 
-  const getUnFixedAndFull = computed(() => !unref(getFixed) && !unref(getShowFullHeaderRef));
+const getUnFixedAndFull = computed(() => !unref(getFixed) && !unref(getShowFullHeaderRef));
 
-  const getShowBread = computed(() => {
-    return (
-      unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && unref(getShowBreadCrumb) && !unref(getSplit)
-    );
-  });
+const getShowBread = computed(() => {
+  return (
+    unref(getMenuMode) !== MenuModeEnum.HORIZONTAL && unref(getShowBreadCrumb) && !unref(getSplit)
+  );
+});
 
-  const getShowHeaderLogo = computed(() => {
-    return unref(getShowLogo) && !unref(getIsSidebarType);
-  });
+const getShowHeaderLogo = computed(() => {
+  return unref(getShowLogo) && !unref(getIsSidebarType);
+});
 
-  const getShowContent = computed(() => {
-    return unref(getShowBread) || unref(getShowHeaderTrigger);
-  });
+const getShowContent = computed(() => {
+  return unref(getShowBread) || unref(getShowHeaderTrigger);
+});
 
-  // Set header configuration
-  function setHeaderSetting(headerSetting: Partial<HeaderSetting>): void {
-    appStore.commitProjectConfigState({ headerSetting });
-  }
+// Set header configuration
+function setHeaderSetting(headerSetting: Partial<HeaderSetting>): void {
+  appStore.commitProjectConfigState({ headerSetting });
+}
 
+export function useHeaderSetting() {
   return {
     setHeaderSetting,
 

+ 14 - 14
src/hooks/setting/useLocaleSetting.ts

@@ -6,26 +6,26 @@ import { appStore } from '/@/store/modules/app';
 import getProjectSetting from '/@/settings/projectSetting';
 import { localeList } from '/@/locales';
 
-export function useLocaleSetting() {
-  // Get locale configuration
-  const getLocale = computed(() => appStore.getProjectConfig.locale || getProjectSetting.locale);
+// Get locale configuration
+const getLocale = computed(() => appStore.getProjectConfig.locale || getProjectSetting.locale);
 
-  // get current language
-  const getLang = computed(() => unref(getLocale).lang);
+// get current language
+const getLang = computed(() => unref(getLocale).lang);
 
-  // get Available Locales
-  const getAvailableLocales = computed((): string[] => unref(getLocale).availableLocales);
+// get Available Locales
+const getAvailableLocales = computed((): string[] => unref(getLocale).availableLocales);
 
-  // get Fallback Locales
-  const getFallbackLocale = computed((): string => unref(getLocale).fallback);
+// get Fallback Locales
+const getFallbackLocale = computed((): string => unref(getLocale).fallback);
 
-  const getShowLocale = computed(() => unref(getLocale).show);
+const getShowLocale = computed(() => unref(getLocale).show);
 
-  // Set locale configuration
-  function setLocale(locale: Partial<LocaleSetting>): void {
-    appStore.commitProjectConfigState({ locale });
-  }
+// Set locale configuration
+function setLocale(locale: Partial<LocaleSetting>): void {
+  appStore.commitProjectConfigState({ locale });
+}
 
+export function useLocaleSetting() {
   return {
     getLocale,
     getLang,

+ 56 - 56
src/hooks/setting/useMenuSetting.ts

@@ -7,89 +7,89 @@ import { appStore } from '/@/store/modules/app';
 import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
 import { MenuModeEnum, MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum';
 
-export function useMenuSetting() {
-  // Get menu configuration
-  const getMenuSetting = computed(() => appStore.getProjectConfig.menuSetting);
+// Get menu configuration
+const getMenuSetting = computed(() => appStore.getProjectConfig.menuSetting);
 
-  const getCollapsed = computed(() => unref(getMenuSetting).collapsed);
+const getCollapsed = computed(() => unref(getMenuSetting).collapsed);
 
-  const getMenuType = computed(() => unref(getMenuSetting).type);
+const getMenuType = computed(() => unref(getMenuSetting).type);
 
-  const getMenuMode = computed(() => unref(getMenuSetting).mode);
+const getMenuMode = computed(() => unref(getMenuSetting).mode);
 
-  const getMenuFixed = computed(() => unref(getMenuSetting).fixed);
+const getMenuFixed = computed(() => unref(getMenuSetting).fixed);
 
-  const getShowMenu = computed(() => unref(getMenuSetting).show);
+const getShowMenu = computed(() => unref(getMenuSetting).show);
 
-  const getMenuHidden = computed(() => unref(getMenuSetting).hidden);
+const getMenuHidden = computed(() => unref(getMenuSetting).hidden);
 
-  const getMenuWidth = computed(() => unref(getMenuSetting).menuWidth);
+const getMenuWidth = computed(() => unref(getMenuSetting).menuWidth);
 
-  const getTrigger = computed(() => unref(getMenuSetting).trigger);
+const getTrigger = computed(() => unref(getMenuSetting).trigger);
 
-  const getMenuTheme = computed(() => unref(getMenuSetting).theme);
+const getMenuTheme = computed(() => unref(getMenuSetting).theme);
 
-  const getSplit = computed(() => unref(getMenuSetting).split);
+const getSplit = computed(() => unref(getMenuSetting).split);
 
-  const getMenuBgColor = computed(() => unref(getMenuSetting).bgColor);
+const getMenuBgColor = computed(() => unref(getMenuSetting).bgColor);
 
-  const getCanDrag = computed(() => unref(getMenuSetting).canDrag);
+const getCanDrag = computed(() => unref(getMenuSetting).canDrag);
 
-  const getAccordion = computed(() => unref(getMenuSetting).accordion);
+const getAccordion = computed(() => unref(getMenuSetting).accordion);
 
-  const getCollapsedShowTitle = computed(() => unref(getMenuSetting).collapsedShowTitle);
+const getCollapsedShowTitle = computed(() => unref(getMenuSetting).collapsedShowTitle);
 
-  const getTopMenuAlign = computed(() => unref(getMenuSetting).topMenuAlign);
+const getTopMenuAlign = computed(() => unref(getMenuSetting).topMenuAlign);
 
-  const getIsSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDEBAR);
+const getIsSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDEBAR);
 
-  const getIsTopMenu = computed(() => unref(getMenuType) === MenuTypeEnum.TOP_MENU);
+const getIsTopMenu = computed(() => unref(getMenuType) === MenuTypeEnum.TOP_MENU);
 
-  const getShowTopMenu = computed(() => {
-    return unref(getMenuMode) === MenuModeEnum.HORIZONTAL || unref(getSplit);
-  });
+const getShowTopMenu = computed(() => {
+  return unref(getMenuMode) === MenuModeEnum.HORIZONTAL || unref(getSplit);
+});
 
-  const getShowHeaderTrigger = computed(() => {
-    if (
-      unref(getMenuType) === MenuTypeEnum.TOP_MENU ||
-      !unref(getShowMenu) ||
-      !unref(getMenuHidden)
-    ) {
-      return false;
-    }
+const getShowHeaderTrigger = computed(() => {
+  if (
+    unref(getMenuType) === MenuTypeEnum.TOP_MENU ||
+    !unref(getShowMenu) ||
+    !unref(getMenuHidden)
+  ) {
+    return false;
+  }
 
-    return unref(getTrigger) === TriggerEnum.HEADER;
-  });
+  return unref(getTrigger) === TriggerEnum.HEADER;
+});
 
-  const getIsHorizontal = computed(() => {
-    return unref(getMenuMode) === MenuModeEnum.HORIZONTAL;
-  });
+const getIsHorizontal = computed(() => {
+  return unref(getMenuMode) === MenuModeEnum.HORIZONTAL;
+});
 
-  const getRealWidth = computed(() => {
-    return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth);
-  });
+const getRealWidth = computed(() => {
+  return unref(getCollapsed) ? unref(getMiniWidthNumber) : unref(getMenuWidth);
+});
 
-  const getMiniWidthNumber = computed(() => {
-    const { collapsedShowTitle } = unref(getMenuSetting);
-    return collapsedShowTitle ? SIDE_BAR_SHOW_TIT_MINI_WIDTH : SIDE_BAR_MINI_WIDTH;
-  });
+const getMiniWidthNumber = computed(() => {
+  const { collapsedShowTitle } = unref(getMenuSetting);
+  return collapsedShowTitle ? SIDE_BAR_SHOW_TIT_MINI_WIDTH : SIDE_BAR_MINI_WIDTH;
+});
 
-  const getCalcContentWidth = computed(() => {
-    const width = unref(getIsTopMenu) || !unref(getShowMenu) ? 0 : unref(getRealWidth);
-    return `calc(100% - ${unref(width)}px)`;
-  });
+const getCalcContentWidth = computed(() => {
+  const width = unref(getIsTopMenu) || !unref(getShowMenu) ? 0 : unref(getRealWidth);
+  return `calc(100% - ${unref(width)}px)`;
+});
 
-  // Set menu configuration
-  function setMenuSetting(menuSetting: Partial<MenuSetting>): void {
-    appStore.commitProjectConfigState({ menuSetting });
-  }
+// Set menu configuration
+function setMenuSetting(menuSetting: Partial<MenuSetting>): void {
+  appStore.commitProjectConfigState({ menuSetting });
+}
 
-  function toggleCollapsed() {
-    setMenuSetting({
-      collapsed: !unref(getCollapsed),
-    });
-  }
+function toggleCollapsed() {
+  setMenuSetting({
+    collapsed: !unref(getCollapsed),
+  });
+}
 
+export function useMenuSetting() {
   return {
     setMenuSetting,
 

+ 7 - 7
src/hooks/setting/useMultipleTabSetting.ts

@@ -4,17 +4,17 @@ import { computed, unref } from 'vue';
 
 import { appStore } from '/@/store/modules/app';
 
-export function useMultipleTabSetting() {
-  const getMultipleTabSetting = computed(() => appStore.getProjectConfig.multiTabsSetting);
+const getMultipleTabSetting = computed(() => appStore.getProjectConfig.multiTabsSetting);
 
-  const getShowMultipleTab = computed(() => unref(getMultipleTabSetting).show);
+const getShowMultipleTab = computed(() => unref(getMultipleTabSetting).show);
 
-  const getShowQuick = computed(() => unref(getMultipleTabSetting).showQuick);
+const getShowQuick = computed(() => unref(getMultipleTabSetting).showQuick);
 
-  function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) {
-    appStore.commitProjectConfigState({ multiTabsSetting });
-  }
+function setMultipleTabSetting(multiTabsSetting: Partial<MultiTabsSetting>) {
+  appStore.commitProjectConfigState({ multiTabsSetting });
+}
 
+export function useMultipleTabSetting() {
   return {
     setMultipleTabSetting,
 

+ 24 - 23
src/hooks/setting/useRootSetting.ts

@@ -9,47 +9,48 @@ type RootSetting = Omit<
   ProjectConfig,
   'locale' | 'headerSetting' | 'menuSetting' | 'multiTabsSetting'
 >;
-export function useRootSetting() {
-  const getRootSetting = computed((): RootSetting => appStore.getProjectConfig);
 
-  const getPageLoading = computed(() => appStore.getPageLoading);
+const getRootSetting = computed((): RootSetting => appStore.getProjectConfig);
+
+const getPageLoading = computed(() => appStore.getPageLoading);
 
-  const getOpenKeepAlive = computed(() => unref(getRootSetting).openKeepAlive);
+const getOpenKeepAlive = computed(() => unref(getRootSetting).openKeepAlive);
 
-  const getCanEmbedIFramePage = computed(() => unref(getRootSetting).canEmbedIFramePage);
+const getCanEmbedIFramePage = computed(() => unref(getRootSetting).canEmbedIFramePage);
 
-  const getPermissionMode = computed(() => unref(getRootSetting).permissionMode);
+const getPermissionMode = computed(() => unref(getRootSetting).permissionMode);
 
-  const getShowLogo = computed(() => unref(getRootSetting).showLogo);
+const getShowLogo = computed(() => unref(getRootSetting).showLogo);
 
-  const getContentMode = computed(() => unref(getRootSetting).contentMode);
+const getContentMode = computed(() => unref(getRootSetting).contentMode);
 
-  const getUseOpenBackTop = computed(() => unref(getRootSetting).useOpenBackTop);
+const getUseOpenBackTop = computed(() => unref(getRootSetting).useOpenBackTop);
 
-  const getShowSettingButton = computed(() => unref(getRootSetting).showSettingButton);
+const getShowSettingButton = computed(() => unref(getRootSetting).showSettingButton);
 
-  const getUseErrorHandle = computed(() => unref(getRootSetting).useErrorHandle);
+const getUseErrorHandle = computed(() => unref(getRootSetting).useErrorHandle);
 
-  const getShowFooter = computed(() => unref(getRootSetting).showFooter);
+const getShowFooter = computed(() => unref(getRootSetting).showFooter);
 
-  const getShowBreadCrumb = computed(() => unref(getRootSetting).showBreadCrumb);
+const getShowBreadCrumb = computed(() => unref(getRootSetting).showBreadCrumb);
 
-  const getShowBreadCrumbIcon = computed(() => unref(getRootSetting).showBreadCrumbIcon);
+const getShowBreadCrumbIcon = computed(() => unref(getRootSetting).showBreadCrumbIcon);
 
-  const getFullContent = computed(() => unref(getRootSetting).fullContent);
+const getFullContent = computed(() => unref(getRootSetting).fullContent);
 
-  const getColorWeak = computed(() => unref(getRootSetting).colorWeak);
+const getColorWeak = computed(() => unref(getRootSetting).colorWeak);
 
-  const getGrayMode = computed(() => unref(getRootSetting).grayMode);
+const getGrayMode = computed(() => unref(getRootSetting).grayMode);
 
-  const getLayoutContentMode = computed(() =>
-    unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
-  );
+const getLayoutContentMode = computed(() =>
+  unref(getRootSetting).contentMode === ContentEnum.FULL ? ContentEnum.FULL : ContentEnum.FIXED
+);
 
-  function setRootSetting(setting: Partial<RootSetting>) {
-    appStore.commitProjectConfigState(setting);
-  }
+function setRootSetting(setting: Partial<RootSetting>) {
+  appStore.commitProjectConfigState(setting);
+}
 
+export function useRootSetting() {
   return {
     setRootSetting,
 

+ 11 - 11
src/hooks/setting/useTransitionSetting.ts

@@ -4,23 +4,23 @@ import { computed, unref } from 'vue';
 
 import { appStore } from '/@/store/modules/app';
 
-export function useTransitionSetting() {
-  const getTransitionSetting = computed(() => appStore.getProjectConfig.transitionSetting);
+const getTransitionSetting = computed(() => appStore.getProjectConfig.transitionSetting);
 
-  const getEnableTransition = computed(() => unref(getTransitionSetting)?.enable);
+const getEnableTransition = computed(() => unref(getTransitionSetting)?.enable);
 
-  const getOpenNProgress = computed(() => unref(getTransitionSetting)?.openNProgress);
+const getOpenNProgress = computed(() => unref(getTransitionSetting)?.openNProgress);
 
-  const getOpenPageLoading = computed((): boolean => {
-    return !!unref(getTransitionSetting)?.openPageLoading;
-  });
+const getOpenPageLoading = computed((): boolean => {
+  return !!unref(getTransitionSetting)?.openPageLoading;
+});
 
-  const getBasicTransition = computed(() => unref(getTransitionSetting)?.basicTransition);
+const getBasicTransition = computed(() => unref(getTransitionSetting)?.basicTransition);
 
-  function setTransitionSetting(transitionSetting: Partial<TransitionSetting>) {
-    appStore.commitProjectConfigState({ transitionSetting });
-  }
+function setTransitionSetting(transitionSetting: Partial<TransitionSetting>) {
+  appStore.commitProjectConfigState({ transitionSetting });
+}
 
+export function useTransitionSetting() {
   return {
     setTransitionSetting,
 

+ 10 - 7
src/hooks/web/useDesign.ts

@@ -1,18 +1,21 @@
 import { useAppProviderContext } from '/@/components/Application';
-import { computed } from 'vue';
-// import { useCssModule, reactive } from 'vue';
+// import { computed } from 'vue';
+// import { lowerFirst } from 'lodash-es';
 export function useDesign(scope: string) {
   const values = useAppProviderContext();
-  // const style = cssModule ? useCssModule() : {};
+  // const $style = cssModule ? useCssModule() : {};
 
+  // const style: Record<string, string> = {};
   // if (cssModule) {
-  //   Object.keys(style).forEach((key) => {
-  //     const moduleCls = style[key];
-  //     style[key] = `${cls}-${moduleCls}`;
+  //   Object.keys($style).forEach((key) => {
+  //     // const moduleCls = $style[key];
+  //     const k = key.replace(new RegExp(`^${values.prefixCls}-?`, 'ig'), '');
+  //     style[lowerFirst(k)] = $style[key];
   //   });
   // }
   return {
-    prefixCls: computed(() => `${values.prefixCls}-${scope}`),
+    // prefixCls: computed(() => `${values.prefixCls}-${scope}`),
+    prefixCls: `${values.prefixCls}-${scope}`,
     prefixVar: values.prefixCls,
     // style,
   };

+ 2 - 2
src/hooks/web/useFullContent.ts

@@ -2,12 +2,12 @@ import { computed, unref } from 'vue';
 
 import { appStore } from '/@/store/modules/app';
 
-import { useRouter } from 'vue-router';
+import router from '/@/router';
 /**
  * @description: Full screen display content
  */
 export const useFullContent = () => {
-  const { currentRoute } = useRouter();
+  const { currentRoute } = router;
 
   // Whether to display the content in full screen without displaying the menu
   const getFullContent = computed(() => {

+ 0 - 2
src/hooks/web/usePage.ts

@@ -1,4 +1,3 @@
-import { appStore } from '/@/store/modules/app';
 import type { RouteLocationRaw } from 'vue-router';
 
 import { PageEnum } from '/@/enums/pageEnum';
@@ -11,7 +10,6 @@ export type RouteLocationRawEx = Omit<RouteLocationRaw, 'path'> & { path: PageEn
 
 function handleError(e: Error) {
   console.error(e);
-  appStore.commitPageLoadingState(false);
 }
 
 // page switch

+ 2 - 8
src/layouts/default/header/LayoutHeader.tsx

@@ -80,13 +80,7 @@ export default defineComponent({
     const { refreshPage } = useTabs();
     const { t } = useI18n();
 
-    const {
-      getShowTopMenu,
-      getShowHeaderTrigger,
-      getSplit,
-      getTopMenuAlign,
-      getIsHorizontal,
-    } = useMenuSetting();
+    const { getShowTopMenu, getShowHeaderTrigger, getSplit, getIsHorizontal } = useMenuSetting();
 
     const { getShowLocale } = useLocaleSetting();
     const { getUseErrorHandle, getShowBreadCrumbIcon } = useRootSetting();
@@ -184,7 +178,7 @@ export default defineComponent({
               {/* <div class={[`layout-header__menu `]}> */}
               <LayoutMenu
                 isHorizontal={true}
-                class={`justify-${unref(getTopMenuAlign)}`}
+                // class={`justify-${unref(getTopMenuAlign)}`}
                 theme={unref(getHeaderTheme)}
                 splitType={unref(getSplitType)}
                 menuMode={unref(getMenuMode)}

+ 3 - 2
src/layouts/default/header/LayoutMultipleHeader.tsx

@@ -21,7 +21,7 @@ export default defineComponent({
 
     const injectValue = useLayoutContext();
 
-    const { getCalcContentWidth } = useMenuSetting();
+    const { getCalcContentWidth, getSplit } = useMenuSetting();
 
     const {
       getFixed,
@@ -56,7 +56,8 @@ export default defineComponent({
       (): CSSProperties => {
         const style: CSSProperties = {};
         if (unref(getFixed)) {
-          style.width = unref(injectValue.isMobile) ? '100%' : unref(getCalcContentWidth);
+          style.width =
+            unref(injectValue.isMobile) || unref(getSplit) ? '100%' : unref(getCalcContentWidth);
         }
         if (unref(getShowFullHeaderRef)) {
           style.top = `${unref(fullHeaderHeightRef)}px`;

+ 16 - 29
src/layouts/default/menu/index.tsx

@@ -1,21 +1,21 @@
 import './index.less';
 
 import { PropType, toRef } from 'vue';
-import type { Menu } from '/@/router/types';
 
 import { computed, defineComponent, unref } from 'vue';
-import { BasicMenu } from '/@/components/Menu/index';
+import { BasicMenu } from '/@/components/Menu';
 import { AppLogo } from '/@/components/Application';
 
 import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
 
 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-import { useRootSetting } from '/@/hooks/setting/useRootSetting';
 
 import { useGo } from '/@/hooks/web/usePage';
 import { useSplitMenu } from './useLayoutMenu';
 import { openWindow } from '/@/utils';
 import { propTypes } from '/@/utils/propTypes';
+import { isUrl } from '/@/utils/is';
+import { useRootSetting } from '/@/hooks/setting/useRootSetting';
 
 export default defineComponent({
   name: 'LayoutMenu',
@@ -38,56 +38,46 @@ export default defineComponent({
     const go = useGo();
 
     const {
-      setMenuSetting,
       getMenuMode,
       getMenuType,
       getCollapsedShowTitle,
-      getIsSidebarType,
       getMenuTheme,
       getCollapsed,
       getAccordion,
+      getIsSidebarType,
     } = useMenuSetting();
-
     const { getShowLogo } = useRootSetting();
 
-    const { flatMenusRef, menusRef } = useSplitMenu(toRef(props, 'splitType'));
-
-    const showLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType));
+    const { menusRef } = useSplitMenu(toRef(props, 'splitType'));
 
     const getComputedMenuMode = computed(() => props.menuMode || unref(getMenuMode));
 
     const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme));
-
+    const showLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType));
     const appendClass = computed(() => props.splitType === MenuSplitTyeEnum.TOP);
-
     /**
      * click menu
      * @param menu
      */
-    function handleMenuClick(menu: Menu) {
-      go(menu.path);
+    function handleMenuClick(path: string) {
+      go(path);
     }
 
     /**
      * before click menu
      * @param menu
      */
-    async function beforeMenuClickFn(menu: Menu) {
-      const { meta: { externalLink } = {} } = menu;
-
-      if (externalLink) {
-        openWindow(externalLink);
-        return false;
+    async function beforeMenuClickFn(path: string) {
+      if (!isUrl(path)) {
+        return true;
       }
-      return true;
-    }
-
-    function handleClickSearchInput() {
-      unref(getCollapsed) && setMenuSetting({ collapsed: false });
+      openWindow(path);
+      return false;
     }
 
     function renderHeader() {
       if (!unref(showLogo)) return null;
+
       return (
         <AppLogo
           showTitle={!unref(getCollapsed)}
@@ -100,20 +90,17 @@ export default defineComponent({
     return () => {
       return (
         <BasicMenu
-          class="layout-menu"
           beforeClickFn={beforeMenuClickFn}
           isHorizontal={props.isHorizontal}
-          appendClass={unref(appendClass)}
           type={unref(getMenuType)}
           mode={unref(getComputedMenuMode)}
           collapsedShowTitle={unref(getCollapsedShowTitle)}
           theme={unref(getComputedMenuTheme)}
-          showLogo={unref(showLogo)}
           items={unref(menusRef)}
-          flatItems={unref(flatMenusRef)}
           accordion={unref(getAccordion)}
           onMenuClick={handleMenuClick}
-          onClickSearchInput={handleClickSearchInput}
+          appendClass={unref(appendClass)}
+          showLogo={unref(showLogo)}
         >
           {{
             header: () => renderHeader(),

+ 2 - 41
src/layouts/default/menu/useLayoutMenu.ts

@@ -8,24 +8,12 @@ import { MenuSplitTyeEnum } from '/@/enums/menuEnum';
 import { useThrottle } from '/@/hooks/core/useThrottle';
 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
 
-import {
-  getChildrenMenus,
-  getCurrentParentPath,
-  getFlatChildrenMenus,
-  getFlatMenus,
-  getMenus,
-  getShallowMenus,
-} from '/@/router/menus';
+import { getChildrenMenus, getCurrentParentPath, getMenus, getShallowMenus } from '/@/router/menus';
 import { permissionStore } from '/@/store/modules/permission';
-// import { useI18n } from '/@/hooks/web/useI18n';
-// import { cloneDeep } from 'lodash-es';
 
-// const { t } = useI18n();
 export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
   // Menu array
   const menusRef = ref<Menu[]>([]);
-  // flat menu array
-  const flatMenusRef = ref<Menu[]>([]);
 
   const { currentRoute } = useRouter();
 
@@ -45,14 +33,6 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
     return unref(splitType) === MenuSplitTyeEnum.NONE || !unref(getSplit);
   });
 
-  // const getI18nFlatMenus = computed(() => {
-  //   return setI18nName(flatMenusRef.value, true, false);
-  // });
-
-  // const getI18nMenus = computed(() => {
-  //   return setI18nName(menusRef.value, true, true);
-  // });
-
   watch(
     [() => unref(currentRoute).path, () => unref(splitType)],
     async ([path]: [string, MenuSplitTyeEnum]) => {
@@ -83,20 +63,6 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
     genMenus();
   });
 
-  // function setI18nName(list: Menu[], clone = false, deep = true) {
-  //   const menus = clone ? cloneDeep(list) : list;
-  //   const arr: Menu[] = [];
-  //   menus.forEach((item) => {
-  //     if (!item.name.includes('.')) return;
-  //     item.name = t(item.name);
-
-  //     if (item.children && deep) {
-  //       setI18nName(item.children, false, deep);
-  //     }
-  //   });
-  //   return menus;
-  // }
-
   // Handle left menu split
   async function handleSplitLeftMenu(parentPath: string) {
     if (unref(splitLeft)) return;
@@ -105,14 +71,11 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
     const children = await getChildrenMenus(parentPath);
     if (!children) {
       setMenuSetting({ hidden: false });
-      flatMenusRef.value = [];
       menusRef.value = [];
       return;
     }
 
-    const flatChildren = await getFlatChildrenMenus(children);
     setMenuSetting({ hidden: true });
-    flatMenusRef.value = flatChildren;
     menusRef.value = children;
   }
 
@@ -120,7 +83,6 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
   async function genMenus() {
     // normal mode
     if (unref(normalType)) {
-      flatMenusRef.value = await getFlatMenus();
       menusRef.value = await getMenus();
       return;
     }
@@ -129,11 +91,10 @@ export function useSplitMenu(splitType: Ref<MenuSplitTyeEnum>) {
     if (unref(spiltTop)) {
       const shallowMenus = await getShallowMenus();
 
-      flatMenusRef.value = shallowMenus;
       menusRef.value = shallowMenus;
       return;
     }
   }
 
-  return { flatMenusRef, menusRef };
+  return { menusRef };
 }

+ 19 - 4
src/layouts/default/sider/index.less

@@ -12,10 +12,25 @@
 
   &.ant-layout-sider-dark {
     background: @sider-dark-bg-color;
+
+    .ant-layout-sider-trigger {
+      color: darken(@white, 25%);
+      background: @trigger-dark-bg-color;
+
+      &:hover {
+        color: @white;
+        background: @trigger-dark-hover-bg-color;
+      }
+    }
   }
 
   &:not(.ant-layout-sider-dark) {
     box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
+
+    .ant-layout-sider-trigger {
+      color: @text-color-base;
+      border-top: 1px solid @border-color-light;
+    }
   }
 
   .ant-layout-sider-zero-width-trigger {
@@ -43,9 +58,9 @@
       box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.15);
     }
   }
-}
 
-.ant-layout-sider-trigger {
-  height: 36px;
-  line-height: 36px;
+  & .ant-layout-sider-trigger {
+    height: 36px;
+    line-height: 36px;
+  }
 }

+ 2 - 2
src/layouts/default/sider/index.tsx

@@ -100,7 +100,7 @@ export default defineComponent({
           flex: `0 0 ${width}`,
           maxWidth: width,
           minWidth: width,
-          transition: 'all 0.2s',
+          transition: 'all 0.15s',
         };
       }
     );
@@ -126,7 +126,7 @@ export default defineComponent({
           )}
           <Layout.Sider
             ref={sideRef}
-            breakpoint="md"
+            breakpoint="lg"
             collapsible
             class={unref(getSiderClass)}
             style={unref(getSiderStyle)}

+ 5 - 0
src/utils/is.ts

@@ -79,3 +79,8 @@ export const isMobile = (): boolean => {
     /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
   );
 };
+
+export const isUrl = (path: string): boolean => {
+  const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
+  return reg.test(path);
+};