瀏覽代碼

perf: optimize settingDrawer code

vben 4 年之前
父節點
當前提交
4ff6b73c2b

+ 4 - 0
CHANGELOG.zh_CN.md

@@ -4,6 +4,10 @@
 
 - 表单项的`componentsProps`支持函数类型
 
+### ⚡ Performance Improvements
+
+- 优化 settingDrawer 代码
+
 ### 🐛 Bug Fixes
 
 - 修复多个富文本编辑器只显示一个

+ 1 - 2
index.html

@@ -30,8 +30,7 @@
       .app-loading {
         width: 100%;
         height: 100%;
-
-        /* background: #f0f2f5; */
+        background: #f0f2f5;
       }
 
       .app-loading .app-loading-wrap {

+ 1 - 1
mock/demo/table-demo.ts

@@ -11,7 +11,7 @@ const demoList = (() => {
       address: '@city()',
       name: '@cname()',
       'no|100000-10000000': 100000,
-      'status|1': ['正常', '启用', '停用'],
+      'status|1': ['normal', 'enable', 'disable'],
     });
   }
   return result;

+ 2 - 2
src/api/demo/error.ts

@@ -1,12 +1,12 @@
 import { defHttp } from '/@/utils/http/axios';
 
 enum Api {
-  // 该地址不存在
+  // The address does not exist
   Error = '/error',
 }
 
 /**
- * @description: 触发ajax错误
+ * @description: Trigger ajax error
  */
 export function fireErrorApi() {
   return defHttp.request({

+ 2 - 2
src/api/demo/model/tableModel.ts

@@ -1,6 +1,6 @@
 import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel';
 /**
- * @description: 请求列表接口参数
+ * @description: Request list interface parameters
  */
 export type DemoParams = BasicPageParams;
 
@@ -15,6 +15,6 @@ export interface DemoListItem {
 }
 
 /**
- * @description: 请求列表返回值
+ * @description: Request list return value
  */
 export type DemoListGetResultModel = BasicFetchResult<DemoListItem>;

+ 1 - 1
src/api/demo/table.ts

@@ -6,7 +6,7 @@ enum Api {
 }
 
 /**
- * @description: 获取示例列表值
+ * @description: Get sample list value
  */
 export function demoListApi(params: DemoParams) {
   return defHttp.request<DemoListGetResultModel>({

+ 0 - 1
src/components/Form/src/types/index.ts

@@ -89,7 +89,6 @@ export type ComponentType =
   | 'InputNumber'
   | 'InputCountDown'
   | 'Select'
-  | 'DictSelect'
   | 'SelectOptGroup'
   | 'SelectOption'
   | 'TreeSelect'

+ 2 - 1
src/components/Menu/src/BasicMenu.tsx

@@ -52,7 +52,8 @@ export default defineComponent({
       toRef(props, 'items'),
       toRef(props, 'flatItems'),
       toRef(props, 'isAppMenu'),
-      toRef(props, 'mode')
+      toRef(props, 'mode'),
+      toRef(props, 'accordion')
     );
 
     const getOpenKeys = computed(() => {

+ 4 - 0
src/components/Menu/src/props.ts

@@ -58,6 +58,10 @@ export const basicProps = {
     type: Boolean as PropType<boolean>,
     default: false,
   },
+  accordion: {
+    type: Boolean as PropType<boolean>,
+    default: true,
+  },
   beforeClickFn: {
     type: Function as PropType<Fn>,
     default: null,

+ 13 - 3
src/components/Menu/src/useOpenKeys.ts

@@ -6,21 +6,31 @@ import type { Ref } from 'vue';
 import { unref } from 'vue';
 import { menuStore } from '/@/store/modules/menu';
 import { getAllParentPath } from '/@/utils/helper/menuHelper';
+import { es6Unique } from '/@/utils';
 
 export function useOpenKeys(
   menuState: MenuState,
   menus: Ref<MenuType[]>,
   flatMenusRef: Ref<MenuType[]>,
   isAppMenu: Ref<boolean>,
-  mode: Ref<MenuModeEnum>
+  mode: Ref<MenuModeEnum>,
+  accordion: Ref<boolean>
 ) {
   /**
    * @description:设置展开
    */
   function setOpenKeys(menu: MenuType) {
     const flatMenus = unref(flatMenusRef);
-    menuState.openKeys = getAllParentPath(flatMenus, menu.path);
+    if (!unref(accordion)) {
+      menuState.openKeys = es6Unique([
+        ...menuState.openKeys,
+        ...getAllParentPath(flatMenus, menu.path),
+      ]);
+    } else {
+      menuState.openKeys = getAllParentPath(flatMenus, menu.path);
+    }
   }
+
   /**
    * @description:  重置值
    */
@@ -30,7 +40,7 @@ export function useOpenKeys(
   }
 
   function handleOpenChange(openKeys: string[]) {
-    if (unref(mode) === MenuModeEnum.HORIZONTAL) {
+    if (unref(mode) === MenuModeEnum.HORIZONTAL || !unref(accordion)) {
       menuState.openKeys = openKeys;
     } else {
       const rootSubMenuKeys: string[] = [];

+ 0 - 4
src/layouts/default/LayoutContent.tsx

@@ -2,11 +2,8 @@ import { defineComponent } from 'vue';
 import { Layout } from 'ant-design-vue';
 import { RouterView } from 'vue-router';
 
-// hooks
-
 import { ContentEnum } from '/@/enums/appEnum';
 import { appStore } from '/@/store/modules/app';
-// import PageLayout from '/@/layouts/page/index';
 export default defineComponent({
   name: 'DefaultLayoutContent',
   setup() {
@@ -17,7 +14,6 @@ export default defineComponent({
       return (
         <Layout.Content class={`layout-content ${wrapClass} `}>
           {() => <RouterView />}
-          {/* <PageLayout class={`layout-content ${wrapClass} `} /> */}
         </Layout.Content>
       );
     };

+ 16 - 14
src/layouts/default/LayoutMenu.tsx

@@ -55,27 +55,25 @@ export default defineComponent({
     },
   },
   setup(props) {
+    // Menu array
     const menusRef = ref<Menu[]>([]);
+    // flat menu array
     const flatMenusRef = ref<Menu[]>([]);
     const { currentRoute, push } = useRouter();
-    // const { addTab } = useTabs();
 
+    // get app config
     const getProjectConfigRef = computed(() => {
       return appStore.getProjectConfig;
     });
 
+    // get is Horizontal
     const getIsHorizontalRef = computed(() => {
       return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL;
     });
 
     const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
 
-    // watch(
-    //   () => menuStore.getCurrentTopSplitMenuPathState,
-    //   async (parentPath: string) => {
-    //     throttleHandleSplitLeftMenu(parentPath);
-    //   }
-    // );
+    // Route change split menu
     watch(
       [() => unref(currentRoute).path, () => props.splitType],
       async ([path, splitType]: [string, MenuSplitTyeEnum]) => {
@@ -88,23 +86,26 @@ export default defineComponent({
       }
     );
 
+    // Menu changes
     watch(
-      [() => permissionStore.getLastBuildMenuTimeState, permissionStore.getBackMenuListState],
+      [() => permissionStore.getLastBuildMenuTimeState, () => permissionStore.getBackMenuListState],
       () => {
         genMenus();
       }
     );
 
+    // split Menu changes
     watch([() => appStore.getProjectConfig.menuSetting.split], () => {
       if (props.splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
       genMenus();
     });
 
+    // Handle left menu split
     async function handleSplitLeftMenu(parentPath: string) {
       const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
       if (!isSplitMenu) return;
       const { splitType } = props;
-      // 菜单分割模式-left
+      // spilt mode left
       if (splitType === MenuSplitTyeEnum.LEFT) {
         const children = await getChildrenMenus(parentPath);
         if (!children) {
@@ -128,11 +129,11 @@ export default defineComponent({
       }
     }
 
+    // get menus
     async function genMenus() {
       const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
 
-      // 普通模式
-
+      // normal mode
       const { splitType } = props;
       if (splitType === MenuSplitTyeEnum.NONE || !isSplitMenu) {
         flatMenusRef.value = await getFlatMenus();
@@ -140,7 +141,7 @@ export default defineComponent({
         return;
       }
 
-      // 菜单分割模式-top
+      // split-top
       if (splitType === MenuSplitTyeEnum.TOP) {
         const parentPath = await getCurrentParentPath(unref(currentRoute).path);
         menuStore.commitCurrentTopSplitMenuPathState(parentPath);
@@ -156,12 +157,11 @@ export default defineComponent({
       const { path } = menu;
       if (path) {
         const { splitType } = props;
-        // 菜单分割模式-top
+        // split mode top
         if (splitType === MenuSplitTyeEnum.TOP) {
           menuStore.commitCurrentTopSplitMenuPathState(path);
         }
         push(path);
-        // addTab(path as PageEnum, true);
       }
     }
 
@@ -205,6 +205,7 @@ export default defineComponent({
           collapsed,
           collapsedShowTitle,
           collapsedShowSearch,
+          accordion,
         },
       } = unref(getProjectConfigRef);
 
@@ -227,6 +228,7 @@ export default defineComponent({
           onClickSearchInput={handleClickSearchInput}
           appendClass={props.splitType === MenuSplitTyeEnum.TOP}
           isTop={props.isTop}
+          accordion={accordion}
         >
           {{
             header: () =>

+ 1 - 5
src/layouts/default/LayoutSideBar.tsx

@@ -4,9 +4,6 @@ import { Layout } from 'ant-design-vue';
 import LayoutTrigger from './LayoutTrigger';
 import { menuStore } from '/@/store/modules/menu';
 
-// import darkMiniIMg from '/@/assets/images/sidebar/dark-mini.png';
-// import lightMiniImg from '/@/assets/images/sidebar/light-mini.png';
-// import lightImg from '/@/assets/images/sidebar/light.png';
 import { appStore } from '/@/store/modules/app';
 import { MenuModeEnum, MenuSplitTyeEnum, TriggerEnum } from '/@/enums/menuEnum';
 import { SIDE_BAR_MINI_WIDTH, SIDE_BAR_SHOW_TIT_MINI_WIDTH } from '/@/enums/appEnum';
@@ -44,7 +41,7 @@ export default defineComponent({
       initRef.value = true;
     }
 
-    // 菜单区域拖拽 - 鼠标移动
+    // Menu area drag and drop-mouse movement
     function handleMouseMove(ele: any, wrap: any, clientX: number) {
       document.onmousemove = function (innerE) {
         let iT = ele.left + ((innerE || event).clientX - clientX);
@@ -98,7 +95,6 @@ export default defineComponent({
       const side = unref(sideRef);
 
       const wrap = (side || {}).$el;
-      // const eleWidth = 6;
       ele &&
         (ele.onmousedown = (e: any) => {
           menuStore.commitDragStartState(true);

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

@@ -19,12 +19,11 @@ import './index.less';
 export default defineComponent({
   name: 'DefaultLayout',
   setup() {
-    // ! 在这里才注册全局组件
-    // ! 可以减少首屏代码体积
-    // default layout是在登录后才加载的。所以不会打包到首屏去
+    // ! Only register global components here
+    // ! Can reduce the size of the first screen code
+    // default layout It is loaded after login. So it won’t be packaged to the first screen
     registerGlobComp();
 
-    // 获取项目配置
     const { getFullContent } = useFullContent();
 
     const getProjectConfigRef = computed(() => {
@@ -56,8 +55,6 @@ export default defineComponent({
       return split || (show && mode !== MenuModeEnum.HORIZONTAL && !unref(getFullContent));
     });
 
-    // Get project configuration
-    // const { getFullContent } = useFullContent(currentRoute);
     function getTarget(): any {
       const {
         headerSetting: { fixed },

+ 73 - 319
src/layouts/default/setting/SettingDrawer.tsx

@@ -2,14 +2,7 @@ import { defineComponent, computed, unref, ref } from 'vue';
 import { BasicDrawer } from '/@/components/Drawer/index';
 import { Divider, Switch, Tooltip, InputNumber, Select } from 'ant-design-vue';
 import Button from '/@/components/Button/index.vue';
-import {
-  MenuModeEnum,
-  MenuTypeEnum,
-  MenuThemeEnum,
-  TopMenuAlignEnum,
-  TriggerEnum,
-} from '/@/enums/menuEnum';
-import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum';
+import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
 import { CopyOutlined, RedoOutlined, CheckOutlined } from '@ant-design/icons-vue';
 import { appStore } from '/@/store/modules/app';
 import { userStore } from '/@/store/modules/user';
@@ -24,70 +17,15 @@ import mixImg from '/@/assets/images/layout/menu-mix.svg';
 import sidebarImg from '/@/assets/images/layout/menu-sidebar.svg';
 import menuTopImg from '/@/assets/images/layout/menu-top.svg';
 import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
-
-const themeOptions = [
-  {
-    value: MenuThemeEnum.LIGHT,
-    label: '亮色',
-  },
-  {
-    value: MenuThemeEnum.DARK,
-    label: '暗色',
-  },
-];
-const contentModeOptions = [
-  {
-    value: ContentEnum.FULL,
-    label: '流式',
-  },
-  {
-    value: ContentEnum.FIXED,
-    label: '定宽',
-  },
-];
-const topMenuAlignOptions = [
-  {
-    value: TopMenuAlignEnum.CENTER,
-    label: '居中',
-  },
-  {
-    value: TopMenuAlignEnum.START,
-    label: '居左',
-  },
-  {
-    value: TopMenuAlignEnum.END,
-    label: '居右',
-  },
-];
-
-const menuTriggerOptions = [
-  {
-    value: TriggerEnum.NONE,
-    label: '不显示',
-  },
-  {
-    value: TriggerEnum.FOOTER,
-    label: '底部',
-  },
-  {
-    value: TriggerEnum.HEADER,
-    label: '顶部',
-  },
-];
-
-const routerTransitionOptions = [
-  RouterTransitionEnum.ZOOM_FADE,
-  RouterTransitionEnum.FADE,
-  RouterTransitionEnum.ZOOM_OUT,
-  RouterTransitionEnum.FADE_SIDE,
-  RouterTransitionEnum.FADE_BOTTOM,
-].map((item) => {
-  return {
-    label: item,
-    value: item,
-    key: item,
-  };
-});
+import { baseHandler } from './handler';
+import {
+  HandlerEnum,
+  themeOptions,
+  contentModeOptions,
+  topMenuAlignOptions,
+  menuTriggerOptions,
+  routerTransitionOptions,
+} from './const';
 
 interface SwitchOptions {
   config?: DeepPartial<ProjectConfig>;
@@ -139,6 +77,25 @@ export default defineComponent({
         });
     }
 
+    function handleResetSetting() {
+      try {
+        appStore.commitProjectConfigState(defaultSetting);
+        const { colorWeak, grayMode } = defaultSetting;
+        // updateTheme(themeColor);
+        updateColorWeak(colorWeak);
+        updateGrayMode(grayMode);
+        createMessage.success('重置成功!');
+      } catch (error) {
+        createMessage.error(error);
+      }
+    }
+
+    function handleClearAndRedo() {
+      localStorage.clear();
+      userStore.resumeAllState();
+      location.reload();
+    }
+
     function renderSidebar() {
       const {
         headerSetting: { theme: headerTheme },
@@ -175,7 +132,7 @@ export default defineComponent({
                 {{
                   default: () => (
                     <div
-                      onClick={baseHandler.bind(null, 'layout', {
+                      onClick={baseHandler.bind(null, HandlerEnum.CHANGE_LAYOUT, {
                         mode: mode,
                         type: ItemType,
                         split: unref(getIsHorizontalRef) ? false : undefined,
@@ -192,14 +149,14 @@ export default defineComponent({
         </div>,
         renderSwitchItem('分割菜单', {
           handler: (e) => {
-            baseHandler('splitMenu', e);
+            baseHandler(HandlerEnum.MENU_SPLIT, e);
           },
           def: split,
           disabled: !unref(getShowMenuRef) || type !== MenuTypeEnum.MIX,
         }),
         renderSelectItem('顶栏主题', {
           handler: (e) => {
-            baseHandler('headerMenu', e);
+            baseHandler(HandlerEnum.HEADER_THEME, e);
           },
           def: headerTheme,
           options: themeOptions,
@@ -207,7 +164,7 @@ export default defineComponent({
         }),
         renderSelectItem('菜单主题', {
           handler: (e) => {
-            baseHandler('menuTheme', e);
+            baseHandler(HandlerEnum.MENU_THEME, e);
           },
           def: menuTheme,
           options: themeOptions,
@@ -230,48 +187,49 @@ export default defineComponent({
           topMenuAlign,
           collapsedShowTitle,
           trigger,
+          accordion,
         } = {},
       } = appStore.getProjectConfig;
       return [
         renderSwitchItem('侧边菜单拖拽', {
           handler: (e) => {
-            baseHandler('hasDrag', e);
+            baseHandler(HandlerEnum.MENU_HAS_DRAG, e);
           },
           def: hasDrag,
           disabled: !unref(getShowMenuRef),
         }),
         renderSwitchItem('侧边菜单搜索', {
           handler: (e) => {
-            baseHandler('showSearch', e);
+            baseHandler(HandlerEnum.MENU_SHOW_SEARCH, e);
           },
           def: showSearch,
           disabled: !unref(getShowMenuRef),
         }),
+        renderSwitchItem('侧边菜单手风琴模式', {
+          handler: (e) => {
+            baseHandler(HandlerEnum.MENU_ACCORDION, e);
+          },
+          def: accordion,
+          disabled: !unref(getShowMenuRef),
+        }),
         renderSwitchItem('折叠菜单', {
           handler: (e) => {
-            baseHandler('collapsed', e);
+            baseHandler(HandlerEnum.MENU_COLLAPSED, e);
           },
           def: collapsed,
           disabled: !unref(getShowMenuRef),
         }),
         renderSwitchItem('折叠菜单显示名称', {
           handler: (e) => {
-            baseHandler('collapsedShowTitle', e);
+            baseHandler(HandlerEnum.MENU_COLLAPSED_SHOW_TITLE, e);
           },
           def: collapsedShowTitle,
           disabled: !unref(getShowMenuRef) || !collapsed,
         }),
 
-        renderSwitchItem('固定header', {
-          handler: (e) => {
-            baseHandler('headerFixed', e);
-          },
-          def: fixed,
-          disabled: !unref(getShowHeaderRef),
-        }),
         renderSelectItem('顶部菜单布局', {
           handler: (e) => {
-            baseHandler('topMenuAlign', e);
+            baseHandler(HandlerEnum.MENU_TOP_ALIGN, e);
           },
           def: topMenuAlign,
           options: topMenuAlignOptions,
@@ -279,14 +237,21 @@ export default defineComponent({
         }),
         renderSelectItem('菜单折叠按钮', {
           handler: (e) => {
-            baseHandler('menuTrigger', e);
+            baseHandler(HandlerEnum.MENU_TRIGGER, e);
           },
           def: trigger,
           options: menuTriggerOptions,
         }),
+        renderSwitchItem('固定header', {
+          handler: (e) => {
+            baseHandler(HandlerEnum.HEADER_FIXED, e);
+          },
+          def: fixed,
+          disabled: !unref(getShowHeaderRef),
+        }),
         renderSelectItem('内容区域宽度', {
           handler: (e) => {
-            baseHandler('contentMode', e);
+            baseHandler(HandlerEnum.CONTENT_MODE, e);
           },
           def: contentMode,
           options: contentModeOptions,
@@ -297,8 +262,8 @@ export default defineComponent({
             style="width:120px"
             size="small"
             min={0}
-            onChange={(e) => {
-              baseHandler('lockTime', e);
+            onChange={(e: any) => {
+              baseHandler(HandlerEnum.LOCK_TIME, e);
             }}
             defaultValue={appStore.getProjectConfig.lockTime}
             formatter={(value: string) => {
@@ -321,7 +286,7 @@ export default defineComponent({
             defaultValue={menuWidth}
             formatter={(value: string) => `${parseInt(value)}px`}
             onChange={(e: any) => {
-              baseHandler('menuWidth', e);
+              baseHandler(HandlerEnum.MENU_WIDTH, e);
             }}
           />
         </div>,
@@ -334,19 +299,19 @@ export default defineComponent({
         <>
           {renderSwitchItem('页面切换loading', {
             handler: (e) => {
-              baseHandler('openPageLoading', e);
+              baseHandler(HandlerEnum.OPEN_PAGE_LOADING, e);
             },
             def: openPageLoading,
           })}
           {renderSwitchItem('切换动画', {
             handler: (e) => {
-              baseHandler('openRouterTransition', e);
+              baseHandler(HandlerEnum.OPEN_ROUTE_TRANSITION, e);
             },
             def: openRouterTransition,
           })}
           {renderSelectItem('路由动画', {
             handler: (e) => {
-              baseHandler('routerTransition', e);
+              baseHandler(HandlerEnum.ROUTER_TRANSITION, e);
             },
             def: routerTransition,
             options: routerTransitionOptions,
@@ -370,289 +335,77 @@ export default defineComponent({
       return [
         renderSwitchItem('面包屑', {
           handler: (e) => {
-            baseHandler('showBreadCrumb', e);
+            baseHandler(HandlerEnum.SHOW_BREADCRUMB, e);
           },
           def: showBreadCrumb,
           disabled: !unref(getShowHeaderRef),
         }),
         renderSwitchItem('面包屑图标', {
           handler: (e) => {
-            baseHandler('showBreadCrumbIcon', e);
+            baseHandler(HandlerEnum.SHOW_BREADCRUMB_ICON, e);
           },
           def: showBreadCrumbIcon,
           disabled: !unref(getShowHeaderRef),
         }),
         renderSwitchItem('标签页', {
           handler: (e) => {
-            baseHandler('showMultiple', e);
+            baseHandler(HandlerEnum.TABS_SHOW, e);
           },
           def: showMultiple,
         }),
         renderSwitchItem('标签页快捷按钮', {
           handler: (e) => {
-            baseHandler('showQuick', e);
+            baseHandler(HandlerEnum.TABS_SHOW_QUICK, e);
           },
           def: showQuick,
           disabled: !unref(getShowTabsRef),
         }),
         renderSwitchItem('标签页图标', {
           handler: (e) => {
-            baseHandler('showTabIcon', e);
+            baseHandler(HandlerEnum.TABS_SHOW_ICON, e);
           },
           def: showTabIcon,
           disabled: !unref(getShowTabsRef),
         }),
         renderSwitchItem('左侧菜单', {
           handler: (e) => {
-            baseHandler('showSidebar', e);
+            baseHandler(HandlerEnum.MENU_SHOW_SIDEBAR, e);
           },
           def: showMenu,
           disabled: unref(getIsHorizontalRef),
         }),
         renderSwitchItem('顶栏', {
           handler: (e) => {
-            baseHandler('showHeader', e);
+            baseHandler(HandlerEnum.HEADER_SHOW, e);
           },
           def: showHeader,
         }),
         renderSwitchItem('Logo', {
           handler: (e) => {
-            baseHandler('showLogo', e);
+            baseHandler(HandlerEnum.SHOW_LOGO, e);
           },
           def: showLogo,
         }),
         renderSwitchItem('全屏内容', {
           handler: (e) => {
-            baseHandler('fullContent', e);
+            baseHandler(HandlerEnum.FULL_CONTENT, e);
           },
           def: fullContent,
         }),
         renderSwitchItem('灰色模式', {
           handler: (e) => {
-            baseHandler('grayMode', e);
+            baseHandler(HandlerEnum.GRAY_MODE, e);
           },
           def: grayMode,
         }),
         renderSwitchItem('色弱模式', {
           handler: (e) => {
-            baseHandler('colorWeak', e);
+            baseHandler(HandlerEnum.COLOR_WEAK, e);
           },
           def: colorWeak,
         }),
       ];
     }
-    function baseHandler(event: string, value: any) {
-      let config: DeepPartial<ProjectConfig> = {};
-      if (event === 'layout') {
-        const { mode, type, split } = value;
-        const splitOpt = split === undefined ? { split } : {};
-        let headerSetting = {};
-        if (type === MenuTypeEnum.TOP_MENU) {
-          headerSetting = {
-            theme: MenuThemeEnum.DARK,
-          };
-        }
-        config = {
-          menuSetting: {
-            mode,
-            type,
-            collapsed: false,
-            show: true,
-            ...splitOpt,
-          },
-          headerSetting,
-        };
-      }
-      if (event === 'hasDrag') {
-        config = {
-          menuSetting: {
-            hasDrag: value,
-          },
-        };
-      }
-      if (event === 'menuTrigger') {
-        config = {
-          menuSetting: {
-            trigger: value,
-          },
-        };
-      }
-      if (event === 'openPageLoading') {
-        config = {
-          openPageLoading: value,
-        };
-      }
-      if (event === 'topMenuAlign') {
-        config = {
-          menuSetting: {
-            topMenuAlign: value,
-          },
-        };
-      }
-      if (event === 'showBreadCrumb') {
-        config = {
-          showBreadCrumb: value,
-        };
-      }
-      if (event === 'showBreadCrumbIcon') {
-        config = {
-          showBreadCrumbIcon: value,
-        };
-      }
-      if (event === 'collapsed') {
-        config = {
-          menuSetting: {
-            collapsed: value,
-          },
-        };
-      }
-      if (event === 'menuWidth') {
-        config = {
-          menuSetting: {
-            menuWidth: value,
-          },
-        };
-      }
-      if (event === 'collapsedShowTitle') {
-        config = {
-          menuSetting: {
-            collapsedShowTitle: value,
-          },
-        };
-      }
-      if (event === 'lockTime') {
-        config = {
-          lockTime: value,
-        };
-      }
-      if (event === 'showQuick') {
-        config = {
-          multiTabsSetting: {
-            showQuick: value,
-          },
-        };
-      }
-      if (event === 'showTabIcon') {
-        config = {
-          multiTabsSetting: {
-            showIcon: value,
-          },
-        };
-      }
-      if (event === 'contentMode') {
-        config = {
-          contentMode: value,
-        };
-      }
-      if (event === 'menuTheme') {
-        config = {
-          menuSetting: {
-            theme: value,
-          },
-        };
-      }
-      if (event === 'splitMenu') {
-        config = {
-          menuSetting: {
-            split: value,
-          },
-        };
-      }
-      if (event === 'showMultiple') {
-        config = {
-          multiTabsSetting: {
-            show: value,
-          },
-        };
-      }
-      if (event === 'headerMenu') {
-        config = {
-          headerSetting: {
-            theme: value,
-          },
-        };
-      }
-      if (event === 'grayMode') {
-        config = {
-          grayMode: value,
-        };
-        updateGrayMode(value);
-      }
-      if (event === 'colorWeak') {
-        config = {
-          colorWeak: value,
-        };
-        updateColorWeak(value);
-      }
-      if (event === 'showLogo') {
-        config = {
-          showLogo: value,
-        };
-      }
-      if (event === 'showSearch') {
-        config = {
-          menuSetting: {
-            showSearch: value,
-          },
-        };
-      }
-      if (event === 'showSidebar') {
-        config = {
-          menuSetting: {
-            show: value,
-          },
-        };
-      }
-      if (event === 'openRouterTransition') {
-        config = {
-          openRouterTransition: value,
-        };
-      }
-      if (event === 'routerTransition') {
-        config = {
-          routerTransition: value,
-        };
-      }
-      if (event === 'headerFixed') {
-        config = {
-          headerSetting: {
-            fixed: value,
-          },
-        };
-      }
-      if (event === 'fullContent') {
-        config = {
-          fullContent: value,
-        };
-      }
-      if (event === 'showHeader') {
-        config = {
-          headerSetting: {
-            show: value,
-          },
-        };
-      }
-      appStore.commitProjectConfigState(config);
-    }
-
-    function handleResetSetting() {
-      try {
-        appStore.commitProjectConfigState(defaultSetting);
-        const { colorWeak, grayMode } = defaultSetting;
-        // updateTheme(themeColor);
-        updateColorWeak(colorWeak);
-        updateGrayMode(grayMode);
-        createMessage.success('重置成功!');
-      } catch (error) {
-        createMessage.error(error);
-      }
-    }
-
-    function handleClearAndRedo() {
-      localStorage.clear();
-      userStore.resumeAllState();
-      location.reload();
-    }
 
     function renderSelectItem(text: string, config?: SelectConfig) {
       const { handler, def, disabled = false, options } = config || {};
@@ -693,6 +446,7 @@ export default defineComponent({
         </div>
       );
     }
+
     return () => (
       <BasicDrawer {...attrs} title="项目配置" width={300} wrapClassName="setting-drawer">
         {{

+ 104 - 0
src/layouts/default/setting/const.ts

@@ -0,0 +1,104 @@
+import { ContentEnum, RouterTransitionEnum } from '/@/enums/appEnum';
+import { MenuThemeEnum, TopMenuAlignEnum, TriggerEnum } from '/@/enums/menuEnum';
+
+export enum HandlerEnum {
+  CHANGE_LAYOUT,
+  // menu
+  MENU_HAS_DRAG,
+  MENU_ACCORDION,
+  MENU_TRIGGER,
+  MENU_TOP_ALIGN,
+  MENU_COLLAPSED,
+  MENU_COLLAPSED_SHOW_TITLE,
+  MENU_WIDTH,
+  MENU_SHOW_SIDEBAR,
+  MENU_THEME,
+  MENU_SPLIT,
+  MENU_SHOW_SEARCH,
+
+  // header
+  HEADER_SHOW,
+  HEADER_THEME,
+  HEADER_FIXED,
+
+  TABS_SHOW_QUICK,
+  TABS_SHOW,
+  TABS_SHOW_ICON,
+
+  OPEN_PAGE_LOADING,
+  OPEN_ROUTE_TRANSITION,
+  ROUTER_TRANSITION,
+  LOCK_TIME,
+  FULL_CONTENT,
+  CONTENT_MODE,
+  SHOW_BREADCRUMB,
+  SHOW_BREADCRUMB_ICON,
+  GRAY_MODE,
+  COLOR_WEAK,
+  SHOW_LOGO,
+}
+
+export const themeOptions = [
+  {
+    value: MenuThemeEnum.LIGHT,
+    label: '亮色',
+  },
+  {
+    value: MenuThemeEnum.DARK,
+    label: '暗色',
+  },
+];
+
+export const contentModeOptions = [
+  {
+    value: ContentEnum.FULL,
+    label: '流式',
+  },
+  {
+    value: ContentEnum.FIXED,
+    label: '定宽',
+  },
+];
+
+export const topMenuAlignOptions = [
+  {
+    value: TopMenuAlignEnum.CENTER,
+    label: '居中',
+  },
+  {
+    value: TopMenuAlignEnum.START,
+    label: '居左',
+  },
+  {
+    value: TopMenuAlignEnum.END,
+    label: '居右',
+  },
+];
+
+export const menuTriggerOptions = [
+  {
+    value: TriggerEnum.NONE,
+    label: '不显示',
+  },
+  {
+    value: TriggerEnum.FOOTER,
+    label: '底部',
+  },
+  {
+    value: TriggerEnum.HEADER,
+    label: '顶部',
+  },
+];
+
+export const routerTransitionOptions = [
+  RouterTransitionEnum.ZOOM_FADE,
+  RouterTransitionEnum.FADE,
+  RouterTransitionEnum.ZOOM_OUT,
+  RouterTransitionEnum.FADE_SIDE,
+  RouterTransitionEnum.FADE_BOTTOM,
+].map((item) => {
+  return {
+    label: item,
+    value: item,
+  };
+});

+ 186 - 0
src/layouts/default/setting/handler.ts

@@ -0,0 +1,186 @@
+import { HandlerEnum } from './const';
+import { MenuThemeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
+import { updateColorWeak, updateGrayMode } from '/@/setup/theme';
+import { appStore } from '/@/store/modules/app';
+import { ProjectConfig } from '/@/types/config';
+
+export function baseHandler(event: HandlerEnum, value: any) {
+  const config = handler(event, value);
+  appStore.commitProjectConfigState(config);
+}
+
+export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConfig> {
+  switch (event) {
+    case HandlerEnum.CHANGE_LAYOUT:
+      const { mode, type, split } = value;
+      const splitOpt = split === undefined ? { split } : {};
+      let headerSetting = {};
+      if (type === MenuTypeEnum.TOP_MENU) {
+        headerSetting = {
+          theme: MenuThemeEnum.DARK,
+        };
+      }
+      return {
+        menuSetting: {
+          mode,
+          type,
+          collapsed: false,
+          show: true,
+          ...splitOpt,
+        },
+        headerSetting,
+      };
+
+    case HandlerEnum.MENU_HAS_DRAG:
+      return {
+        menuSetting: {
+          hasDrag: value,
+        },
+      };
+
+    case HandlerEnum.MENU_ACCORDION:
+      return {
+        menuSetting: {
+          accordion: value,
+        },
+      };
+    case HandlerEnum.MENU_TRIGGER:
+      return {
+        menuSetting: {
+          trigger: value,
+        },
+      };
+    case HandlerEnum.MENU_TOP_ALIGN:
+      return {
+        menuSetting: {
+          topMenuAlign: value,
+        },
+      };
+    case HandlerEnum.MENU_COLLAPSED:
+      return {
+        menuSetting: {
+          collapsed: value,
+        },
+      };
+    case HandlerEnum.MENU_WIDTH:
+      return {
+        menuSetting: {
+          menuWidth: value,
+        },
+      };
+    case HandlerEnum.MENU_COLLAPSED_SHOW_TITLE:
+      return {
+        menuSetting: {
+          collapsedShowTitle: value,
+        },
+      };
+    case HandlerEnum.MENU_SHOW_SIDEBAR:
+      return {
+        menuSetting: {
+          show: value,
+        },
+      };
+    case HandlerEnum.MENU_THEME:
+      return {
+        menuSetting: {
+          theme: value,
+        },
+      };
+    case HandlerEnum.MENU_SPLIT:
+      return {
+        menuSetting: {
+          split: value,
+        },
+      };
+    case HandlerEnum.MENU_SHOW_SEARCH:
+      return {
+        menuSetting: {
+          showSearch: value,
+        },
+      };
+    case HandlerEnum.OPEN_PAGE_LOADING:
+      return {
+        openPageLoading: value,
+      };
+    case HandlerEnum.OPEN_ROUTE_TRANSITION:
+      return {
+        openRouterTransition: value,
+      };
+    case HandlerEnum.ROUTER_TRANSITION:
+      return {
+        routerTransition: value,
+      };
+    case HandlerEnum.LOCK_TIME:
+      return {
+        lockTime: value,
+      };
+    case HandlerEnum.FULL_CONTENT:
+      return {
+        fullContent: value,
+      };
+    case HandlerEnum.CONTENT_MODE:
+      return {
+        contentMode: value,
+      };
+    case HandlerEnum.SHOW_BREADCRUMB:
+      return {
+        showBreadCrumb: value,
+      };
+    case HandlerEnum.SHOW_BREADCRUMB_ICON:
+      return {
+        showBreadCrumbIcon: value,
+      };
+    case HandlerEnum.GRAY_MODE:
+      updateGrayMode(value);
+      return {
+        grayMode: value,
+      };
+    case HandlerEnum.COLOR_WEAK:
+      updateColorWeak(value);
+      return {
+        colorWeak: value,
+      };
+    case HandlerEnum.SHOW_LOGO:
+      return {
+        showLogo: value,
+      };
+    case HandlerEnum.TABS_SHOW_QUICK:
+      return {
+        multiTabsSetting: {
+          showQuick: value,
+        },
+      };
+    case HandlerEnum.TABS_SHOW_QUICK:
+      return {
+        multiTabsSetting: {
+          showIcon: value,
+        },
+      };
+    case HandlerEnum.TABS_SHOW:
+      return {
+        multiTabsSetting: {
+          show: value,
+        },
+      };
+    case HandlerEnum.HEADER_THEME:
+      return {
+        headerSetting: {
+          theme: value,
+        },
+      };
+    case HandlerEnum.HEADER_FIXED:
+      return {
+        headerSetting: {
+          fixed: value,
+        },
+      };
+    case HandlerEnum.HEADER_SHOW:
+      return {
+        headerSetting: {
+          show: value,
+        },
+      };
+    default:
+      return {};
+  }
+}

+ 2 - 0
src/settings/projectSetting.ts

@@ -74,6 +74,8 @@ const setting: ProjectConfig = {
     collapsedShowSearch: false,
     // 折叠触发器的位置
     trigger: TriggerEnum.HEADER,
+    // 开启手风琴模式,只显示一个菜单
+    accordion: true,
   },
   // 消息配置
   messageSetting: {

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

@@ -24,6 +24,7 @@ export interface MenuSetting {
   topMenuAlign: 'start' | 'center' | 'end';
   collapsedShowSearch: boolean;
   trigger: TriggerEnum;
+  accordion: boolean;
 }
 
 export interface MultiTabsSetting {

+ 9 - 5
src/types/global.d.ts

@@ -30,12 +30,16 @@ declare type Indexable<T = any> = {
 
 declare type Hash<T> = Indexable<T>;
 
+// declare type DeepPartial<T> = {
+//   [P in keyof T]?: T[P] extends (infer U)[]
+//     ? RecursivePartial<U>[]
+//     : T[P] extends object
+//     ? RecursivePartial<T[P]>
+//     : T[P];
+// };
+
 declare type DeepPartial<T> = {
-  [P in keyof T]?: T[P] extends (infer U)[]
-    ? RecursivePartial<U>[]
-    : T[P] extends object
-    ? RecursivePartial<T[P]>
-    : T[P];
+  [P in keyof T]?: DeepPartial<T[P]>;
 };
 
 declare type SelectOptions = {

+ 3 - 3
src/useApp.ts

@@ -42,7 +42,7 @@ export function useThemeMode(mode: ThemeModeEnum) {
   };
 }
 
-// 初始化项目配置
+// Initial project configuration
 export function useInitAppConfigStore() {
   let projCfg: ProjectConfig = getLocal(PROJ_CFG_KEY) as ProjectConfig;
   if (!projCfg) {
@@ -78,12 +78,12 @@ export function useConfigProvider() {
   };
 }
 
-// 初始化网络监听
+// Initialize network monitoring
 export function useListenerNetWork() {
   const { listenNetWork } = appStore.getProjectConfig;
   if (!listenNetWork) return;
   const { replace } = useRouter();
-  // 检测网络状态
+  // Check network status
   useNetWork({
     onLineFn: () => {
       replace(PageEnum.BASE_HOME);

+ 16 - 19
src/views/dashboard/analysis/index.vue

@@ -1,42 +1,42 @@
 <template>
   <div class="analysis p-4">
-    <Row class="pl-2">
+    <a-row class="pl-2">
       <template v-for="item in growCardList" :key="item.title">
         <ACol :sm="24" :md="12" :lg="6">
           <GrowCard :info="item" />
         </ACol>
       </template>
-    </Row>
+    </a-row>
 
-    <Row>
-      <ACol :md="24" :lg="17" class="my-3">
+    <a-row>
+      <a-col :md="24" :lg="17" class="my-3">
         <CollapseContainer class="mr-3" title="产品成交额" :canExpan="false">
           <AnalysisLine />
         </CollapseContainer>
-        <Row class="mt-3">
-          <ACol :md="24" :lg="12" class="product-total">
+        <a-row class="mt-3">
+          <a-col :md="24" :lg="12" class="product-total">
             <CollapseContainer class="mr-3" title="产品成交额" :canExpan="false">
               <AnalysisPie />
             </CollapseContainer>
-          </ACol>
-          <ACol :md="24" :lg="12">
+          </a-col>
+          <a-col :md="24" :lg="12">
             <CollapseContainer class="mr-3" title="用户来源" :canExpan="false">
               <AnalysisBar />
             </CollapseContainer>
-          </ACol>
-        </Row>
-      </ACol>
-      <ACol :md="24" :lg="7">
+          </a-col>
+        </a-row>
+      </a-col>
+      <a-col :md="24" :lg="7">
         <CollapseContainer class="mt-3" title="项目进度" :canExpan="false">
           <template v-for="item in taskList" :key="item.title">
             <TaskCard :info="item" />
           </template>
         </CollapseContainer>
-      </ACol>
-    </Row>
-    <Row>
+      </a-col>
+    </a-row>
+    <a-row>
       <FlowAnalysis />
-    </Row>
+    </a-row>
   </div>
 </template>
 <script lang="ts">
@@ -48,14 +48,11 @@
   import AnalysisBar from './components/AnalysisBar.vue';
   import TaskCard from './components/TaskCard.vue';
   import FlowAnalysis from './components/FlowAnalysis';
-  import { Row, Col } from 'ant-design-vue';
   import { CollapseContainer } from '/@/components/Container/index';
 
   import { growCardList, taskList } from './data';
   export default defineComponent({
     components: {
-      Row,
-      ACol: Col,
       GrowCard,
       CollapseContainer,
       TrendLine,

+ 7 - 8
src/views/dashboard/workbench/index.vue

@@ -1,20 +1,19 @@
 <template>
-  <Row class="workbench p-4" :gutter="12">
-    <Col :md="24" :lg="17">
+  <a-row class="workbench p-4" :gutter="12">
+    <a-col :md="24" :lg="17">
       <ProdTotal class="mb-3" />
       <TodoList class="mb-3" />
       <NewsList class="mb-3" />
-    </Col>
-    <Col :md="24" :lg="7">
+    </a-col>
+    <a-col :md="24" :lg="7">
       <img src="/@/assets/images/dashboard/wokb/wokb.png" class="workbench__wokb-img mb-3" />
       <ShortCuts class="mb-3" />
       <Week class="mb-3" />
-    </Col>
-  </Row>
+    </a-col>
+  </a-row>
 </template>
 <script lang="ts">
   import { defineComponent } from 'vue';
-  import { Row, Col } from 'ant-design-vue';
   import ProdTotal from './components/ProdTotal.vue';
   import TodoList from './components/TodoList.vue';
   import Week from './components/Week.vue';
@@ -22,7 +21,7 @@
   import ShortCuts from './components/ShortCuts.vue';
 
   export default defineComponent({
-    components: { Row, Col, ProdTotal, TodoList, Week, ShortCuts, NewsList },
+    components: { ProdTotal, TodoList, Week, ShortCuts, NewsList },
     setup() {
       return {};
     },

+ 3 - 3
src/views/sys/login/Login.vue

@@ -168,7 +168,7 @@
       display: none;
       height: 100%;
       background: url(../../../assets/images/login/login-in.png) no-repeat;
-      background-position: 50% 30%;
+      background-position: 30% 30%;
       background-size: 80% 80%;
 
       .respond-to(xlarge, { display: block;});
@@ -194,9 +194,9 @@
         align-items: center;
         .respond-to(large, {
           width: 600px;
-          right: calc(50% - 300px);
+          right: calc(50% - 270px);
           });
-        .respond-to(xlarge, { width: 600px; right:0});
+        .respond-to(xlarge, { width: 540px; right:0});
       }
 
       &__content {

+ 1 - 1
vite.config.ts

@@ -34,7 +34,7 @@ const viteConfig: UserConfig = {
    * @default 'index.html'
    */
   // TODO build error
-  // entry: './public/index.html',
+  // entry: 'public/index.html',
   /**
    * port
    * @default '3000'