Browse Source

chore: 版本跟随vben更新

lanjianrong 4 years ago
parent
commit
e34ddc5ff8
46 changed files with 1488 additions and 1349 deletions
  1. 4 0
      package.json
  2. BIN
      public/favicon.ico
  3. 44 2
      src/api/sys/manager.ts
  4. 21 0
      src/api/sys/model/managerModel.ts
  5. 1 1
      src/api/sys/user.ts
  6. 0 8
      src/components/Excel/index.ts
  7. 0 58
      src/components/Excel/src/Export2Excel.ts
  8. 0 91
      src/components/Excel/src/ExportExcelModel.vue
  9. 0 126
      src/components/Excel/src/ImportExcel.vue
  10. 0 31
      src/components/Excel/src/types.ts
  11. 25 13
      src/layouts/default/content/useContentViewHeight.ts
  12. 25 23
      src/layouts/default/feature/index.vue
  13. 38 18
      src/layouts/default/footer/index.vue
  14. 56 72
      src/layouts/default/header/MultipleHeader.vue
  15. 73 73
      src/layouts/default/header/components/Breadcrumb.vue
  16. 36 31
      src/layouts/default/header/components/lock/LockModal.vue
  17. 39 42
      src/layouts/default/header/components/user-dropdown/index.vue
  18. 1 1
      src/layouts/default/header/index.less
  19. 54 71
      src/layouts/default/header/index.vue
  20. 35 22
      src/layouts/default/index.vue
  21. 58 64
      src/layouts/default/menu/index.vue
  22. 49 95
      src/layouts/default/setting/SettingDrawer.tsx
  23. 15 21
      src/layouts/default/setting/components/InputNumberItem.vue
  24. 20 21
      src/layouts/default/setting/components/SelectItem.vue
  25. 20 21
      src/layouts/default/setting/components/SwitchItem.vue
  26. 17 18
      src/layouts/default/setting/components/ThemeColorPicker.vue
  27. 15 15
      src/layouts/default/setting/components/TypePicker.vue
  28. 10 10
      src/layouts/default/setting/index.vue
  29. 45 51
      src/layouts/default/sider/LayoutSider.vue
  30. 116 131
      src/layouts/default/sider/MixSider.vue
  31. 52 55
      src/layouts/default/tabs/index.vue
  32. 41 41
      src/layouts/default/tabs/useMultipleTabs.ts
  33. 57 60
      src/layouts/default/tabs/useTabDropdown.ts
  34. 27 28
      src/layouts/iframe/useFrameKeepAlive.ts
  35. 2 2
      src/router/menus/modules/dashboard.ts
  36. 2 2
      src/router/menus/modules/manager.ts
  37. 4 4
      src/router/routes/modules/dashboard.ts
  38. 5 13
      src/router/routes/modules/manager.ts
  39. 2 2
      src/views/dashboard/project-detail/index.vue
  40. 0 0
      src/views/manager/permission/detail.vue
  41. 86 2
      src/views/manager/permission/index.vue
  42. 110 0
      src/views/manager/permission/tableData.tsx
  43. 1 1
      src/views/manager/user/detail/index.vue
  44. 1 1
      src/views/manager/user/list/index.vue
  45. 61 0
      src/views/sys/login/SessionTimeoutLogin.vue
  46. 220 8
      yarn.lock

+ 4 - 0
package.json

@@ -83,7 +83,11 @@
     "eslint": "^7.28.0",
     "eslint-config-prettier": "^8.3.0",
     "eslint-define-config": "^1.0.8",
+    "eslint-plugin-html": "^6.1.2",
+    "eslint-plugin-javascript": "^1.3.4",
+    "eslint-plugin-jsx": "^0.1.0",
     "eslint-plugin-prettier": "^3.4.0",
+    "eslint-plugin-typescript": "^0.14.0",
     "eslint-plugin-vue": "^7.10.0",
     "esno": "^0.7.1",
     "fs-extra": "^10.0.0",

BIN
public/favicon.ico


+ 44 - 2
src/api/sys/manager.ts

@@ -5,9 +5,19 @@ import { BasicPageParams } from '/@/api/model/baseModel'
 enum Api {
   GetManagerList = '/backstage/manager/list',
   GetManagerInfo = '/backstage/manager',
-  SaveManagerStatus = '/backstage/manager/enable'
+  SaveManagerStatus = '/backstage/manager/enable',
+  GetGroupList = '/backstage/group/list',
+  DeleteGroup = '/backstage/group/delete',
+  AddGroup = '/backstage/group/add',
+  UpdateGroup = 'backstage/group/update'
 }
-import { ManagerListGetResultModel, ManagerInfoGetResultModel } from './model/managerModel'
+import {
+  ManagerListGetResultModel,
+  ManagerInfoGetResultModel,
+  AddPermParams,
+  PermGroupListResultModel,
+  UpdatePermParams
+} from './model/managerModel'
 /**
  * @description 获取后台用户列表
  */
@@ -42,3 +52,35 @@ export function toggleManagerStatus(params: { id: string; canLogin: 0 | 1 }, mod
     }
   )
 }
+
+/** 获取权限列表 */
+export function getPermGroupList(params: BasicPageParams) {
+  return defHttp.get<PermGroupListResultModel>({
+    url: Api.GetGroupList,
+    params
+  })
+}
+
+/** 删除权限 */
+export function deletePermGroup(id: string) {
+  return defHttp.delete({
+    url: Api.DeleteGroup,
+    params: { id }
+  })
+}
+
+/** 新增权限组 */
+export function addPermGroup(params: AddPermParams) {
+  return defHttp.post({
+    url: Api.AddGroup,
+    params
+  })
+}
+
+/** 编辑权限组 */
+export function updatePermGroup(params: UpdatePermParams) {
+  return defHttp.post({
+    url: Api.UpdateGroup,
+    params
+  })
+}

+ 21 - 0
src/api/sys/model/managerModel.ts

@@ -9,6 +9,7 @@ export type ManagerItem = {
   telephone: string
   loginIp: string
   canLogin: number
+  isAdmin: number
   office: string
   category: string
   email: string
@@ -18,9 +19,29 @@ export type ManagerItem = {
   avatar: string
   createTime: string
 }
+export type AddPermParams = {
+  name: string
+  permission: string[]
+  remark?: string
+}
+
+export type PermGroupItem = {
+  id: string
+  name: string
+  remark: string
+  permission: string
+  createTime: string
+}
+export type UpdatePermParams = {
+  id: string
+  name: string
+  permission: string[]
+  remark?: string
+}
 
 /**
  * @description: Request list return value
  */
 export type ManagerListGetResultModel = BasicFetchResult<ManagerItem[]>
+export type PermGroupListResultModel = BasicFetchResult<PermGroupItem[]>
 export type ManagerInfoGetResultModel = ManagerItem

+ 1 - 1
src/api/sys/user.ts

@@ -14,7 +14,7 @@ enum Api {
   GetUserInfoById = '/login/project/name',
   GetPermCodeByUserId = '/getPermCodeByUserId',
   GetToken = '/login/project/name',
-  GetAccountGroupList = '/projectAccount/group'
+  GetAccountGroupList = '/backstage/account/group'
 }
 
 /**

+ 0 - 8
src/components/Excel/index.ts

@@ -1,8 +0,0 @@
-import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
-
-export const ImpExcel = createAsyncComponent(() => import('./src/ImportExcel.vue'));
-export const ExpExcelModel = createAsyncComponent(() => import('./src/ExportExcelModel.vue'));
-
-export * from './src/types';
-
-export { jsonToSheetXlsx, aoaToSheetXlsx } from './src/Export2Excel';

+ 0 - 58
src/components/Excel/src/Export2Excel.ts

@@ -1,58 +0,0 @@
-import xlsx from 'xlsx';
-import type { WorkBook } from 'xlsx';
-import type { JsonToSheet, AoAToSheet } from './types';
-
-const { utils, writeFile } = xlsx;
-
-const DEF_FILE_NAME = 'excel-list.xlsx';
-export function jsonToSheetXlsx<T = any>({
-  data,
-  header,
-  filename = DEF_FILE_NAME,
-  json2sheetOpts = {},
-  write2excelOpts = { bookType: 'xlsx' },
-}: JsonToSheet<T>) {
-  const arrData = [...data];
-  if (header) {
-    arrData.unshift(header);
-    json2sheetOpts.skipHeader = true;
-  }
-
-  const worksheet = utils.json_to_sheet(arrData, json2sheetOpts);
-
-  /* add worksheet to workbook */
-  const workbook: WorkBook = {
-    SheetNames: [filename],
-    Sheets: {
-      [filename]: worksheet,
-    },
-  };
-  /* output format determined by filename */
-  writeFile(workbook, filename, write2excelOpts);
-  /* at this point, out.xlsb will have been downloaded */
-}
-
-export function aoaToSheetXlsx<T = any>({
-  data,
-  header,
-  filename = DEF_FILE_NAME,
-  write2excelOpts = { bookType: 'xlsx' },
-}: AoAToSheet<T>) {
-  const arrData = [...data];
-  if (header) {
-    arrData.unshift(header);
-  }
-
-  const worksheet = utils.aoa_to_sheet(arrData);
-
-  /* add worksheet to workbook */
-  const workbook: WorkBook = {
-    SheetNames: [filename],
-    Sheets: {
-      [filename]: worksheet,
-    },
-  };
-  /* output format determined by filename */
-  writeFile(workbook, filename, write2excelOpts);
-  /* at this point, out.xlsb will have been downloaded */
-}

+ 0 - 91
src/components/Excel/src/ExportExcelModel.vue

@@ -1,91 +0,0 @@
-<template>
-  <BasicModal
-    v-bind="$attrs"
-    :title="t('component.excel.exportModalTitle')"
-    @ok="handleOk"
-    @register="registerModal"
-  >
-    <BasicForm
-      :labelWidth="100"
-      :schemas="schemas"
-      :showActionButtonGroup="false"
-      @register="registerForm"
-    />
-  </BasicModal>
-</template>
-<script lang="ts">
-  import type { ExportModalResult } from './types';
-  import { defineComponent } from 'vue';
-  import { BasicModal, useModalInner } from '/@/components/Modal';
-  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
-
-  import { useI18n } from '/@/hooks/web/useI18n';
-
-  const { t } = useI18n();
-
-  const schemas: FormSchema[] = [
-    {
-      field: 'filename',
-      component: 'Input',
-      label: t('component.excel.fileName'),
-      rules: [{ required: true }],
-    },
-    {
-      field: 'bookType',
-      component: 'Select',
-      label: t('component.excel.fileType'),
-      defaultValue: 'xlsx',
-      rules: [{ required: true }],
-      componentProps: {
-        options: [
-          {
-            label: 'xlsx',
-            value: 'xlsx',
-            key: 'xlsx',
-          },
-          {
-            label: 'html',
-            value: 'html',
-            key: 'html',
-          },
-          {
-            label: 'csv',
-            value: 'csv',
-            key: 'csv',
-          },
-          {
-            label: 'txt',
-            value: 'txt',
-            key: 'txt',
-          },
-        ],
-      },
-    },
-  ];
-  export default defineComponent({
-    components: { BasicModal, BasicForm },
-    emits: ['success', 'register'],
-    setup(_, { emit }) {
-      const [registerForm, { validateFields }] = useForm();
-      const [registerModal, { closeModal }] = useModalInner();
-
-      async function handleOk() {
-        const res = (await validateFields()) as ExportModalResult;
-        const { filename, bookType } = res;
-        emit('success', {
-          filename: `${filename.split('.').shift()}.${bookType}`,
-          bookType,
-        });
-        closeModal();
-      }
-
-      return {
-        schemas,
-        handleOk,
-        registerForm,
-        registerModal,
-        t,
-      };
-    },
-  });
-</script>

+ 0 - 126
src/components/Excel/src/ImportExcel.vue

@@ -1,126 +0,0 @@
-<template>
-  <div>
-    <input
-      ref="inputRef"
-      type="file"
-      v-show="false"
-      accept=".xlsx, .xls"
-      @change="handleInputClick"
-    />
-    <div @click="handleUpload">
-      <slot></slot>
-    </div>
-  </div>
-</template>
-<script lang="ts">
-  import { defineComponent, ref, unref } from 'vue';
-  import XLSX from 'xlsx';
-
-  import type { ExcelData } from './types';
-  export default defineComponent({
-    name: 'ImportExcel',
-    emits: ['success', 'error'],
-    setup(_, { emit }) {
-      const inputRef = ref<HTMLInputElement | null>(null);
-      const loadingRef = ref<Boolean>(false);
-
-      /**
-       * @description: 第一行作为头部
-       */
-      function getHeaderRow(sheet: XLSX.WorkSheet) {
-        if (!sheet || !sheet['!ref']) return [];
-        const headers: string[] = [];
-        // A3:B7=>{s:{c:0, r:2}, e:{c:1, r:6}}
-        const range = XLSX.utils.decode_range(sheet['!ref']);
-
-        const R = range.s.r;
-        /* start in the first row */
-        for (let C = range.s.c; C <= range.e.c; ++C) {
-          /* walk every column in the range */
-          const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })];
-          /* find the cell in the first row */
-          let hdr = 'UNKNOWN ' + C; // <-- replace with your desired default
-          if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
-          headers.push(hdr);
-        }
-        return headers;
-      }
-
-      /**
-       * @description: 获得excel数据
-       */
-      function getExcelData(workbook: XLSX.WorkBook) {
-        const excelData: ExcelData[] = [];
-        for (const sheetName of workbook.SheetNames) {
-          const worksheet = workbook.Sheets[sheetName];
-          const header: string[] = getHeaderRow(worksheet);
-          const results = XLSX.utils.sheet_to_json(worksheet);
-          excelData.push({
-            header,
-            results,
-            meta: {
-              sheetName,
-            },
-          });
-        }
-        return excelData;
-      }
-
-      /**
-       * @description: 读取excel数据
-       */
-      function readerData(rawFile: File) {
-        loadingRef.value = true;
-        return new Promise((resolve, reject) => {
-          const reader = new FileReader();
-          reader.onload = async (e) => {
-            try {
-              const data = e.target && e.target.result;
-              const workbook = XLSX.read(data, { type: 'array' });
-              // console.log(workbook);
-              /* DO SOMETHING WITH workbook HERE */
-              const excelData = getExcelData(workbook);
-              emit('success', excelData);
-              resolve('');
-            } catch (error) {
-              reject(error);
-              emit('error');
-            } finally {
-              loadingRef.value = false;
-            }
-          };
-          reader.readAsArrayBuffer(rawFile);
-        });
-      }
-
-      async function upload(rawFile: File) {
-        const inputRefDom = unref(inputRef);
-        if (inputRefDom) {
-          // fix can't select the same excel
-          inputRefDom.value = '';
-        }
-        await readerData(rawFile);
-      }
-
-      /**
-       * @description: 触发选择文件管理器
-       */
-      function handleInputClick(e: Event) {
-        const files = e && (e.target as HTMLInputElement).files;
-        const rawFile = files && files[0]; // only setting files[0]
-        if (!rawFile) return;
-        upload(rawFile);
-      }
-
-      /**
-       * @description: 点击上传按钮
-       */
-      function handleUpload() {
-        const inputRefDom = unref(inputRef);
-        inputRefDom && inputRefDom.click();
-      }
-
-      return { handleUpload, handleInputClick, inputRef };
-    },
-  });
-</script>

+ 0 - 31
src/components/Excel/src/types.ts

@@ -1,31 +0,0 @@
-import type { JSON2SheetOpts, WritingOptions, BookType } from 'xlsx';
-
-export interface ExcelData<T = any> {
-  header: string[];
-  results: T[];
-  meta: { sheetName: string };
-}
-
-// export interface ImportProps {
-//   beforeUpload: (file: File) => boolean;
-// }
-
-export interface JsonToSheet<T = any> {
-  data: T[];
-  header?: T;
-  filename?: string;
-  json2sheetOpts?: JSON2SheetOpts;
-  write2excelOpts?: WritingOptions;
-}
-
-export interface AoAToSheet<T = any> {
-  data: T[][];
-  header?: T[];
-  filename?: string;
-  write2excelOpts?: WritingOptions;
-}
-
-export interface ExportModalResult {
-  filename: string;
-  bookType: BookType;
-}

+ 25 - 13
src/layouts/default/content/useContentViewHeight.ts

@@ -1,30 +1,42 @@
-import { ref, computed, unref } from 'vue';
-import { createPageContext } from '/@/hooks/component/usePageContext';
-import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn';
-export const headerHeightRef = ref(0);
+import { ref, computed, unref } from 'vue'
+import { createPageContext } from '/@/hooks/component/usePageContext'
+import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'
+
+const headerHeightRef = ref(0)
+const footerHeightRef = ref(0)
+
+export function useLayoutHeight() {
+  function setHeaderHeight(val) {
+    headerHeightRef.value = val
+  }
+  function setFooterHeight(val) {
+    footerHeightRef.value = val
+  }
+  return { headerHeightRef, footerHeightRef, setHeaderHeight, setFooterHeight }
+}
 
 export function useContentViewHeight() {
-  const contentHeight = ref(window.innerHeight);
-  const pageHeight = ref(window.innerHeight);
+  const contentHeight = ref(window.innerHeight)
+  const pageHeight = ref(window.innerHeight)
   const getViewHeight = computed(() => {
-    return unref(contentHeight) - unref(headerHeightRef) || 0;
-  });
+    return unref(contentHeight) - unref(headerHeightRef) || 0
+  })
 
   useWindowSizeFn(
     () => {
-      contentHeight.value = window.innerHeight;
+      contentHeight.value = window.innerHeight
     },
     100,
     { immediate: true }
-  );
+  )
 
   async function setPageHeight(height: number) {
-    pageHeight.value = height;
+    pageHeight.value = height
   }
 
   createPageContext({
     contentHeight: getViewHeight,
     setPageHeight,
-    pageHeight,
-  });
+    pageHeight
+  })
 }

+ 25 - 23
src/layouts/default/feature/index.vue

@@ -1,58 +1,60 @@
 <script lang="ts">
-  import { defineComponent, computed, unref } from 'vue';
-  import { BackTop } from 'ant-design-vue';
+  import { defineComponent, computed, unref } from 'vue'
+  import { BackTop } from 'ant-design-vue'
 
-  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
-  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useRootSetting } from '/@/hooks/setting/useRootSetting'
+  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useUserStoreWidthOut } from '/@/store/modules/user'
 
-  import { SettingButtonPositionEnum } from '/@/enums/appEnum';
-  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+  import { SettingButtonPositionEnum } from '/@/enums/appEnum'
+  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'
 
+  import SessionTimeoutLogin from '/@/views/sys/login/SessionTimeoutLogin.vue'
   export default defineComponent({
     name: 'LayoutFeatures',
     components: {
       BackTop,
       LayoutLockPage: createAsyncComponent(() => import('/@/views/sys/lock/index.vue')),
       SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue')),
+      SessionTimeoutLogin
     },
     setup() {
-      const {
-        getUseOpenBackTop,
-        getShowSettingButton,
-        getSettingButtonPosition,
-        getFullContent,
-      } = useRootSetting();
+      const { getUseOpenBackTop, getShowSettingButton, getSettingButtonPosition, getFullContent } = useRootSetting()
+      const userStore = useUserStoreWidthOut()
+      const { prefixCls } = useDesign('setting-drawer-fearure')
+      const { getShowHeader } = useHeaderSetting()
 
-      const { prefixCls } = useDesign('setting-drawer-fearure');
-      const { getShowHeader } = useHeaderSetting();
+      const getIsSessionTimeout = computed(() => userStore.getSessionTimeout)
 
       const getIsFixedSettingDrawer = computed(() => {
         if (!unref(getShowSettingButton)) {
-          return false;
+          return false
         }
-        const settingButtonPosition = unref(getSettingButtonPosition);
+        const settingButtonPosition = unref(getSettingButtonPosition)
 
         if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
-          return !unref(getShowHeader) || unref(getFullContent);
+          return !unref(getShowHeader) || unref(getFullContent)
         }
-        return settingButtonPosition === SettingButtonPositionEnum.FIXED;
-      });
+        return settingButtonPosition === SettingButtonPositionEnum.FIXED
+      })
 
       return {
         getTarget: () => document.body,
         getUseOpenBackTop,
         getIsFixedSettingDrawer,
         prefixCls,
-      };
-    },
-  });
+        getIsSessionTimeout
+      }
+    }
+  })
 </script>
 
 <template>
   <LayoutLockPage />
   <BackTop v-if="getUseOpenBackTop" :target="getTarget" />
   <SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls" />
+  <SessionTimeoutLogin v-if="getIsSessionTimeout" />
 </template>
 
 <style lang="less">

+ 38 - 18
src/layouts/default/footer/index.vue

@@ -12,34 +12,54 @@
 </template>
 
 <script lang="ts">
-  import { computed, defineComponent, unref } from 'vue';
-  import { Layout } from 'ant-design-vue';
+  import { computed, defineComponent, unref, ref } from 'vue'
+  import { Layout } from 'ant-design-vue'
 
-  import { GithubFilled } from '@ant-design/icons-vue';
+  import { GithubFilled } from '@ant-design/icons-vue'
 
-  import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting';
-  import { openWindow } from '/@/utils';
+  import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting'
+  import { openWindow } from '/@/utils'
 
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
-  import { useRouter } from 'vue-router';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useI18n } from '/@/hooks/web/useI18n'
+  import { useRootSetting } from '/@/hooks/setting/useRootSetting'
+  import { useRouter } from 'vue-router'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useLayoutHeight } from '../content/useContentViewHeight'
 
   export default defineComponent({
     name: 'LayoutFooter',
     components: { Footer: Layout.Footer, GithubFilled },
     setup() {
-      const { t } = useI18n();
-      const { getShowFooter } = useRootSetting();
-      const { currentRoute } = useRouter();
-      const { prefixCls } = useDesign('layout-footer');
+      const { t } = useI18n()
+      const { getShowFooter } = useRootSetting()
+      const { currentRoute } = useRouter()
+      const { prefixCls } = useDesign('layout-footer')
+
+      const footerRef = ref<ComponentRef>(null)
+      const { setFooterHeight } = useLayoutHeight()
 
       const getShowLayoutFooter = computed(() => {
-        return unref(getShowFooter) && !unref(currentRoute).meta?.hiddenFooter;
-      });
-      return { getShowLayoutFooter, prefixCls, t, DOC_URL, GITHUB_URL, SITE_URL, openWindow };
-    },
-  });
+        if (unref(getShowFooter)) {
+          const footerEl = unref(footerRef)?.$el
+          setFooterHeight(footerEl?.offsetHeight || 0)
+        } else {
+          setFooterHeight(0)
+        }
+        return unref(getShowFooter) && !unref(currentRoute).meta?.hiddenFooter
+      })
+
+      return {
+        getShowLayoutFooter,
+        prefixCls,
+        t,
+        DOC_URL,
+        GITHUB_URL,
+        SITE_URL,
+        openWindow,
+        footerRef
+      }
+    }
+  })
 </script>
 <style lang="less" scoped>
   @prefix-cls: ~'@{namespace}-layout-footer';

+ 56 - 72
src/layouts/default/header/MultipleHeader.vue

@@ -6,94 +6,78 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, unref, computed, CSSProperties } from 'vue';
+  import { defineComponent, unref, computed, CSSProperties } from 'vue'
 
-  import LayoutHeader from './index.vue';
-  import MultipleTabs from '../tabs/index.vue';
+  import LayoutHeader from './index.vue'
+  import MultipleTabs from '../tabs/index.vue'
 
-  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { useFullContent } from '/@/hooks/web/useFullContent';
-  import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
-  import { useAppInject } from '/@/hooks/web/useAppInject';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { headerHeightRef } from '../content/useContentViewHeight';
+  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'
+  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'
+  import { useFullContent } from '/@/hooks/web/useFullContent'
+  import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'
+  import { useAppInject } from '/@/hooks/web/useAppInject'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useLayoutHeight } from '../content/useContentViewHeight'
 
-  const HEADER_HEIGHT = 48;
+  const HEADER_HEIGHT = 48
 
-  const TABS_HEIGHT = 32;
+  const TABS_HEIGHT = 32
   export default defineComponent({
     name: 'LayoutMultipleHeader',
     components: { LayoutHeader, MultipleTabs },
     setup() {
-      const { prefixCls } = useDesign('layout-multiple-header');
+      const { setHeaderHeight } = useLayoutHeight()
+      const { prefixCls } = useDesign('layout-multiple-header')
 
-      const { getCalcContentWidth, getSplit } = useMenuSetting();
-      const { getIsMobile } = useAppInject();
-      const {
-        getFixed,
-        getShowInsetHeaderRef,
-        getShowFullHeaderRef,
-        getHeaderTheme,
-        getShowHeader,
-      } = useHeaderSetting();
+      const { getCalcContentWidth, getSplit } = useMenuSetting()
+      const { getIsMobile } = useAppInject()
+      const { getFixed, getShowInsetHeaderRef, getShowFullHeaderRef, getHeaderTheme, getShowHeader } =
+        useHeaderSetting()
 
-      const { getFullContent } = useFullContent();
+      const { getFullContent } = useFullContent()
 
-      const { getShowMultipleTab } = useMultipleTabSetting();
+      const { getShowMultipleTab } = useMultipleTabSetting()
 
       const getShowTabs = computed(() => {
-        return unref(getShowMultipleTab) && !unref(getFullContent);
-      });
+        return unref(getShowMultipleTab) && !unref(getFullContent)
+      })
 
       const getIsShowPlaceholderDom = computed(() => {
-        return unref(getFixed) || unref(getShowFullHeaderRef);
-      });
-
-      const getWrapStyle = computed(
-        (): CSSProperties => {
-          const style: CSSProperties = {};
-          if (unref(getFixed)) {
-            style.width = unref(getIsMobile) ? '100%' : unref(getCalcContentWidth);
-          }
-          if (unref(getShowFullHeaderRef)) {
-            style.top = `${HEADER_HEIGHT}px`;
-          }
-          return style;
+        return unref(getFixed) || unref(getShowFullHeaderRef)
+      })
+
+      const getWrapStyle = computed((): CSSProperties => {
+        const style: CSSProperties = {}
+        if (unref(getFixed)) {
+          style.width = unref(getIsMobile) ? '100%' : unref(getCalcContentWidth)
+        }
+        if (unref(getShowFullHeaderRef)) {
+          style.top = `${HEADER_HEIGHT}px`
         }
-      );
+        return style
+      })
 
       const getIsFixed = computed(() => {
-        return unref(getFixed) || unref(getShowFullHeaderRef);
-      });
-
-      const getPlaceholderDomStyle = computed(
-        (): CSSProperties => {
-          let height = 0;
-          if (
-            (unref(getShowFullHeaderRef) || !unref(getSplit)) &&
-            unref(getShowHeader) &&
-            !unref(getFullContent)
-          ) {
-            height += HEADER_HEIGHT;
-          }
-          if (unref(getShowMultipleTab) && !unref(getFullContent)) {
-            height += TABS_HEIGHT;
-          }
-          headerHeightRef.value = height;
-          return {
-            height: `${height}px`,
-          };
+        return unref(getFixed) || unref(getShowFullHeaderRef)
+      })
+
+      const getPlaceholderDomStyle = computed((): CSSProperties => {
+        let height = 0
+        if ((unref(getShowFullHeaderRef) || !unref(getSplit)) && unref(getShowHeader) && !unref(getFullContent)) {
+          height += HEADER_HEIGHT
         }
-      );
+        if (unref(getShowMultipleTab) && !unref(getFullContent)) {
+          height += TABS_HEIGHT
+        }
+        setHeaderHeight(height)
+        return {
+          height: `${height}px`
+        }
+      })
 
       const getClass = computed(() => {
-        return [
-          prefixCls,
-          `${prefixCls}--${unref(getHeaderTheme)}`,
-          { [`${prefixCls}--fixed`]: unref(getIsFixed) },
-        ];
-      });
+        return [prefixCls, `${prefixCls}--${unref(getHeaderTheme)}`, { [`${prefixCls}--fixed`]: unref(getIsFixed) }]
+      })
 
       return {
         getClass,
@@ -103,10 +87,10 @@
         getWrapStyle,
         getIsShowPlaceholderDom,
         getShowTabs,
-        getShowInsetHeaderRef,
-      };
-    },
-  });
+        getShowInsetHeaderRef
+      }
+    }
+  })
 </script>
 <style lang="less" scoped>
   @prefix-cls: ~'@{namespace}-layout-multiple-header';
@@ -116,7 +100,7 @@
     flex: 0 0 auto;
 
     &--dark {
-      margin-left: 0;
+      margin-left: -1px;
     }
 
     &--fixed {

+ 73 - 73
src/layouts/default/header/components/Breadcrumb.vue

@@ -14,145 +14,145 @@
   </div>
 </template>
 <script lang="ts">
-  import type { RouteLocationMatched } from 'vue-router';
-  import type { Menu } from '/@/router/types';
+  import type { RouteLocationMatched } from 'vue-router'
+  import type { Menu } from '/@/router/types'
 
-  import { defineComponent, ref, watchEffect } from 'vue';
+  import { defineComponent, ref, watchEffect } from 'vue'
 
-  import { Breadcrumb } from 'ant-design-vue';
-  import Icon from '/@/components/Icon';
+  import { Breadcrumb } from 'ant-design-vue'
+  import Icon from '/@/components/Icon'
 
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
-  import { useGo } from '/@/hooks/web/usePage';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { useRouter } from 'vue-router';
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useRootSetting } from '/@/hooks/setting/useRootSetting'
+  import { useGo } from '/@/hooks/web/usePage'
+  import { useI18n } from '/@/hooks/web/useI18n'
+  import { useRouter } from 'vue-router'
 
-  import { propTypes } from '/@/utils/propTypes';
-  import { isString } from '/@/utils/is';
-  import { filter } from '/@/utils/helper/treeHelper';
-  import { getMenus } from '/@/router/menus';
+  import { propTypes } from '/@/utils/propTypes'
+  import { isString } from '/@/utils/is'
+  import { filter } from '/@/utils/helper/treeHelper'
+  import { getMenus } from '/@/router/menus'
 
-  import { REDIRECT_NAME } from '/@/router/constant';
-  import { getAllParentPath } from '/@/router/helper/menuHelper';
+  import { REDIRECT_NAME } from '/@/router/constant'
+  import { getAllParentPath } from '/@/router/helper/menuHelper'
 
   export default defineComponent({
     name: 'LayoutBreadcrumb',
     components: { Icon, [Breadcrumb.name]: Breadcrumb },
     props: {
-      theme: propTypes.oneOf(['dark', 'light']),
+      theme: propTypes.oneOf(['dark', 'light'])
     },
     setup() {
-      const routes = ref<RouteLocationMatched[]>([]);
-      const { currentRoute } = useRouter();
-      const { prefixCls } = useDesign('layout-breadcrumb');
-      const { getShowBreadCrumbIcon } = useRootSetting();
-      const go = useGo();
+      const routes = ref<RouteLocationMatched[]>([])
+      const { currentRoute } = useRouter()
+      const { prefixCls } = useDesign('layout-breadcrumb')
+      const { getShowBreadCrumbIcon } = useRootSetting()
+      const go = useGo()
 
-      const { t } = useI18n();
+      const { t } = useI18n()
       watchEffect(async () => {
-        if (currentRoute.value.name === REDIRECT_NAME) return;
-        const menus = await getMenus();
+        if (currentRoute.value.name === REDIRECT_NAME) return
+        const menus = await getMenus()
 
-        const routeMatched = currentRoute.value.matched;
-        const cur = routeMatched?.[routeMatched.length - 1];
-        let path = currentRoute.value.path;
+        const routeMatched = currentRoute.value.matched
+        const cur = routeMatched?.[routeMatched.length - 1]
+        let path = currentRoute.value.path
 
         if (cur && cur?.meta?.currentActiveMenu) {
-          path = cur.meta.currentActiveMenu as string;
+          path = cur.meta.currentActiveMenu as string
         }
 
-        const parent = getAllParentPath(menus, path);
-        const filterMenus = menus.filter((item) => item.path === parent[0]);
-        const matched = getMatched(filterMenus, parent) as any;
+        const parent = getAllParentPath(menus, path)
+        const filterMenus = menus.filter(item => item.path === parent[0])
+        const matched = getMatched(filterMenus, parent) as any
 
-        if (!matched || matched.length === 0) return;
+        if (!matched || matched.length === 0) return
 
-        const breadcrumbList = filterItem(matched);
+        const breadcrumbList = filterItem(matched)
 
         if (currentRoute.value.meta?.currentActiveMenu) {
-          breadcrumbList.push(({
+          breadcrumbList.push({
             ...currentRoute.value,
-            name: currentRoute.value.meta?.title || currentRoute.value.name,
-          } as unknown) as RouteLocationMatched);
+            name: currentRoute.value.meta?.title || currentRoute.value.name
+          } as unknown as RouteLocationMatched)
         }
-        routes.value = breadcrumbList;
-      });
+        routes.value = breadcrumbList
+      })
 
       function getMatched(menus: Menu[], parent: string[]) {
-        const metched: Menu[] = [];
-        menus.forEach((item) => {
+        const metched: Menu[] = []
+        menus.forEach(item => {
           if (parent.includes(item.path)) {
             metched.push({
               ...item,
-              name: item.meta?.title || item.name,
-            });
+              name: item.meta?.title || item.name
+            })
           }
           if (item.children?.length) {
-            metched.push(...getMatched(item.children, parent));
+            metched.push(...getMatched(item.children, parent))
           }
-        });
-        return metched;
+        })
+        return metched
       }
 
       function filterItem(list: RouteLocationMatched[]) {
-        let resultList = filter(list, (item) => {
-          const { meta, name } = item;
+        let resultList = filter(list, item => {
+          const { meta, name } = item
           if (!meta) {
-            return !!name;
+            return !!name
           }
-          const { title, hideBreadcrumb, hideMenu } = meta;
+          const { title, hideBreadcrumb, hideMenu } = meta
           if (!title || hideBreadcrumb || hideMenu) {
-            return false;
+            return false
           }
-          return true;
-        }).filter((item) => !item.meta?.hideBreadcrumb || !item.meta?.hideMenu);
+          return true
+        }).filter(item => !item.meta?.hideBreadcrumb || !item.meta?.hideMenu)
 
-        return resultList;
+        return resultList
       }
 
       function handleClick(route: RouteLocationMatched, paths: string[], e: Event) {
-        e?.preventDefault();
-        const { children, redirect, meta } = route;
+        e?.preventDefault()
+        const { children, redirect, meta } = route
 
         if (children?.length && !redirect) {
-          e?.stopPropagation();
-          return;
+          e?.stopPropagation()
+          return
         }
         if (meta?.carryParam) {
-          return;
+          return
         }
 
         if (redirect && isString(redirect)) {
-          go(redirect);
+          go(redirect)
         } else {
-          let goPath = '';
+          let goPath = ''
           if (paths.length === 1) {
-            goPath = paths[0];
+            goPath = paths[0]
           } else {
-            const ps = paths.slice(1);
-            const lastPath = ps.pop() || '';
-            goPath = `${lastPath}`;
+            const ps = paths.slice(1)
+            const lastPath = ps.pop() || ''
+            goPath = `${lastPath}`
           }
-          goPath = /^\//.test(goPath) ? goPath : `/${goPath}`;
-          go(goPath);
+          goPath = /^\//.test(goPath) ? goPath : `/${goPath}`
+          go(goPath)
         }
       }
 
       function hasRedirect(routes: RouteLocationMatched[], route: RouteLocationMatched) {
         if (routes.indexOf(route) === routes.length - 1) {
-          return false;
+          return false
         }
-        return true;
+        return true
       }
 
       function getIcon(route) {
-        return route.icon || route.meta?.icon;
+        return route.icon || route.meta?.icon
       }
 
-      return { routes, t, prefixCls, getIcon, getShowBreadCrumbIcon, handleClick, hasRedirect };
-    },
-  });
+      return { routes, t, prefixCls, getIcon, getShowBreadCrumbIcon, handleClick, hasRedirect }
+    }
+  })
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-layout-breadcrumb';

+ 36 - 31
src/layouts/default/header/components/lock/LockModal.vue

@@ -8,7 +8,7 @@
   >
     <div :class="`${prefixCls}__entry`">
       <div :class="`${prefixCls}__header`">
-        <img :src="headerImg" :class="`${prefixCls}__header-img`" />
+        <img :src="avatar" :class="`${prefixCls}__header-img`" />
         <p :class="`${prefixCls}__header-name`">
           {{ getRealName }}
         </p>
@@ -25,27 +25,27 @@
   </BasicModal>
 </template>
 <script lang="ts">
-  import { defineComponent, computed } from 'vue';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { BasicModal, useModalInner } from '/@/components/Modal/index';
-  import { BasicForm, useForm } from '/@/components/Form/index';
+  import { defineComponent, computed } from 'vue'
+  import { useI18n } from '/@/hooks/web/useI18n'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { BasicModal, useModalInner } from '/@/components/Modal/index'
+  import { BasicForm, useForm } from '/@/components/Form/index'
 
-  import { useUserStore } from '/@/store/modules/user';
-  import { useLockStore } from '/@/store/modules/lock';
-  import headerImg from '/@/assets/images/header.jpg';
+  import { useUserStore } from '/@/store/modules/user'
+  import { useLockStore } from '/@/store/modules/lock'
+  import headerImg from '/@/assets/images/header.jpg'
   export default defineComponent({
     name: 'LockModal',
     components: { BasicModal, BasicForm },
 
     setup() {
-      const { t } = useI18n();
-      const { prefixCls } = useDesign('header-lock-modal');
-      const userStore = useUserStore();
-      const lockStore = useLockStore();
+      const { t } = useI18n()
+      const { prefixCls } = useDesign('header-lock-modal')
+      const userStore = useUserStore()
+      const lockStore = useLockStore()
 
-      const getRealName = computed(() => userStore.getUserInfo?.realName);
-      const [register, { closeModal }] = useModalInner();
+      const getRealName = computed(() => userStore.getUserInfo?.realName)
+      const [register, { closeModal }] = useModalInner()
 
       const [registerForm, { validateFields, resetFields }] = useForm({
         showActionButtonGroup: false,
@@ -54,23 +54,28 @@
             field: 'password',
             label: t('layout.header.lockScreenPassword'),
             component: 'InputPassword',
-            required: true,
-          },
-        ],
-      });
+            required: true
+          }
+        ]
+      })
 
       async function handleLock() {
-        const values = (await validateFields()) as any;
-        const password: string | undefined = values.password;
-        closeModal();
+        const values = (await validateFields()) as any
+        const password: string | undefined = values.password
+        closeModal()
 
         lockStore.setLockInfo({
           isLock: true,
-          pwd: password,
-        });
-        await resetFields();
+          pwd: password
+        })
+        await resetFields()
       }
 
+      const avatar = computed(() => {
+        const { avatar } = userStore.getUserInfo
+        return avatar || headerImg
+      })
+
       return {
         t,
         prefixCls,
@@ -78,10 +83,10 @@
         register,
         registerForm,
         handleLock,
-        headerImg,
-      };
-    },
-  });
+        avatar
+      }
+    }
+  })
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-header-lock-modal';
@@ -89,8 +94,8 @@
   .@{prefix-cls} {
     &__entry {
       position: relative;
-      height: 240px;
-      padding: 130px 30px 60px 30px;
+      //height: 240px;
+      padding: 130px 30px 30px 30px;
       border-radius: 10px;
     }
 

+ 39 - 42
src/layouts/default/header/components/user-dropdown/index.vue

@@ -1,7 +1,7 @@
 <template>
   <Dropdown placement="bottomLeft" :overlayClassName="`${prefixCls}-dropdown-overlay`">
     <span :class="[prefixCls, `${prefixCls}--${theme}`]" class="flex">
-      <img :class="`${prefixCls}__header`" :src="headerImg" />
+      <img :class="`${prefixCls}__header`" :src="getUserInfo.avatar" />
       <span :class="`${prefixCls}__info hidden md:block`">
         <span :class="`${prefixCls}__name  `" class="truncate">
           {{ getUserInfo.realName }}
@@ -19,15 +19,12 @@
         />
         <MenuDivider v-if="getShowDoc" />
         <MenuItem
+          v-if="getUseLockPage"
           key="lock"
           :text="t('layout.header.tooltipLock')"
           icon="ion:lock-closed-outline"
         />
-        <MenuItem
-          key="logout"
-          :text="t('layout.header.dropdownItemLoginOut')"
-          icon="ion:power-outline"
-        />
+        <MenuItem key="logout" :text="t('layout.header.dropdownItemLoginOut')" icon="ion:power-outline" />
       </Menu>
     </template>
   </Dropdown>
@@ -35,25 +32,25 @@
 </template>
 <script lang="ts">
   // components
-  import { Dropdown, Menu } from 'ant-design-vue';
+  import { Dropdown, Menu } from 'ant-design-vue'
 
-  import { defineComponent, computed } from 'vue';
+  import { defineComponent, computed } from 'vue'
 
-  import { DOC_URL } from '/@/settings/siteSetting';
+  import { DOC_URL } from '/@/settings/siteSetting'
 
-  import { useUserStore } from '/@/store/modules/user';
-  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useModal } from '/@/components/Modal';
+  import { useUserStore } from '/@/store/modules/user'
+  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'
+  import { useI18n } from '/@/hooks/web/useI18n'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useModal } from '/@/components/Modal'
 
-  import headerImg from '/@/assets/images/header.jpg';
-  import { propTypes } from '/@/utils/propTypes';
-  import { openWindow } from '/@/utils';
+  import headerImg from '/@/assets/images/header.jpg'
+  import { propTypes } from '/@/utils/propTypes'
+  import { openWindow } from '/@/utils'
 
-  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'
 
-  type MenuEvent = 'logout' | 'doc' | 'lock';
+  type MenuEvent = 'logout' | 'doc' | 'lock'
 
   export default defineComponent({
     name: 'UserDropdown',
@@ -62,49 +59,49 @@
       Menu,
       MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')),
       MenuDivider: Menu.Divider,
-      LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')),
+      LockAction: createAsyncComponent(() => import('../lock/LockModal.vue'))
     },
     props: {
-      theme: propTypes.oneOf(['dark', 'light']),
+      theme: propTypes.oneOf(['dark', 'light'])
     },
     setup() {
-      const { prefixCls } = useDesign('header-user-dropdown');
-      const { t } = useI18n();
-      const { getShowDoc } = useHeaderSetting();
-      const userStore = useUserStore();
+      const { prefixCls } = useDesign('header-user-dropdown')
+      const { t } = useI18n()
+      const { getShowDoc, getUseLockPage } = useHeaderSetting()
+      const userStore = useUserStore()
 
       const getUserInfo = computed(() => {
-        const { realName = '', desc } = userStore.getUserInfo || {};
-        return { realName, desc };
-      });
+        const { realName = '', avatar, desc } = userStore.getUserInfo || {}
+        return { realName, avatar: avatar || headerImg, desc }
+      })
 
-      const [register, { openModal }] = useModal();
+      const [register, { openModal }] = useModal()
 
       function handleLock() {
-        openModal(true);
+        openModal(true)
       }
 
       //  login out
       function handleLoginOut() {
-        userStore.confirmLoginOut();
+        userStore.confirmLoginOut()
       }
 
       // open doc
       function openDoc() {
-        openWindow(DOC_URL);
+        openWindow(DOC_URL)
       }
 
       function handleMenuClick(e: { key: MenuEvent }) {
         switch (e.key) {
           case 'logout':
-            handleLoginOut();
-            break;
+            handleLoginOut()
+            break
           case 'doc':
-            openDoc();
-            break;
+            openDoc()
+            break
           case 'lock':
-            handleLock();
-            break;
+            handleLock()
+            break
         }
       }
 
@@ -114,11 +111,11 @@
         getUserInfo,
         handleMenuClick,
         getShowDoc,
-        headerImg,
         register,
-      };
-    },
-  });
+        getUseLockPage
+      }
+    }
+  })
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-header-user-dropdown';

+ 1 - 1
src/layouts/default/header/index.less

@@ -166,7 +166,7 @@
 
   &--dark {
     background-color: @header-dark-bg-color !important;
-    border-bottom: 1px solid @border-color-base;
+    // border-bottom: 1px solid @border-color-base;
     border-left: 1px solid @border-color-base;
     .@{header-prefix-cls}-logo {
       &:hover {

+ 54 - 71
src/layouts/default/header/index.vue

@@ -10,9 +10,7 @@
         :style="getLogoWidth"
       />
       <LayoutTrigger
-        v-if="
-          (getShowContent && getShowHeaderTrigger && !getSplit && !getIsMixSidebar) || getIsMobile
-        "
+        v-if="(getShowContent && getShowHeaderTrigger && !getSplit && !getIsMixSidebar) || getIsMobile"
         :theme="getHeaderTheme"
         :sider="false"
       />
@@ -22,18 +20,13 @@
 
     <!-- menu start -->
     <div :class="`${prefixCls}-menu`" v-if="getShowTopMenu && !getIsMobile">
-      <LayoutMenu
-        :isHorizontal="true"
-        :theme="getHeaderTheme"
-        :splitType="getSplitType"
-        :menuMode="getMenuMode"
-      />
+      <LayoutMenu :isHorizontal="true" :theme="getHeaderTheme" :splitType="getSplitType" :menuMode="getMenuMode" />
     </div>
     <!-- menu-end -->
 
     <!-- action  -->
     <div :class="`${prefixCls}-action`">
-      <AppSearch :class="`${prefixCls}-action__item `" />
+      <AppSearch :class="`${prefixCls}-action__item `" v-if="getShowSearch" />
 
       <ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" />
 
@@ -55,31 +48,31 @@
   </Header>
 </template>
 <script lang="ts">
-  import { defineComponent, unref, computed } from 'vue';
+  import { defineComponent, unref, computed } from 'vue'
 
-  import { propTypes } from '/@/utils/propTypes';
+  import { propTypes } from '/@/utils/propTypes'
 
-  import { Layout } from 'ant-design-vue';
-  import { AppLogo } from '/@/components/Application';
-  import LayoutMenu from '../menu/index.vue';
-  import LayoutTrigger from '../trigger/index.vue';
+  import { Layout } from 'ant-design-vue'
+  import { AppLogo } from '/@/components/Application'
+  import LayoutMenu from '../menu/index.vue'
+  import LayoutTrigger from '../trigger/index.vue'
 
-  import { AppSearch } from '/@/components/Application';
+  import { AppSearch } from '/@/components/Application'
 
-  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { useRootSetting } from '/@/hooks/setting/useRootSetting';
+  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'
+  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'
+  import { useRootSetting } from '/@/hooks/setting/useRootSetting'
 
-  import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
-  import { SettingButtonPositionEnum } from '/@/enums/appEnum';
-  import { AppLocalePicker } from '/@/components/Application';
+  import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'
+  import { SettingButtonPositionEnum } from '/@/enums/appEnum'
+  import { AppLocalePicker } from '/@/components/Application'
 
-  import { UserDropDown, LayoutBreadcrumb, FullScreen, Notify, ErrorAction } from './components';
-  import { useAppInject } from '/@/hooks/web/useAppInject';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { UserDropDown, LayoutBreadcrumb, FullScreen, Notify, ErrorAction } from './components'
+  import { useAppInject } from '/@/hooks/web/useAppInject'
+  import { useDesign } from '/@/hooks/web/useDesign'
 
-  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
-  import { useLocale } from '/@/locales/useLocale';
+  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'
+  import { useLocale } from '/@/locales/useLocale'
 
   export default defineComponent({
     name: 'LayoutHeader',
@@ -96,82 +89,72 @@
       AppSearch,
       ErrorAction,
       SettingDrawer: createAsyncComponent(() => import('/@/layouts/default/setting/index.vue'), {
-        loading: true,
-      }),
+        loading: true
+      })
     },
     props: {
-      fixed: propTypes.bool,
+      fixed: propTypes.bool
     },
     setup(props) {
-      const { prefixCls } = useDesign('layout-header');
-      const {
-        getShowTopMenu,
-        getShowHeaderTrigger,
-        getSplit,
-        getIsMixMode,
-        getMenuWidth,
-        getIsMixSidebar,
-      } = useMenuSetting();
-      const {
-        getUseErrorHandle,
-        getShowSettingButton,
-        getSettingButtonPosition,
-      } = useRootSetting();
+      const { prefixCls } = useDesign('layout-header')
+      const { getShowTopMenu, getShowHeaderTrigger, getSplit, getIsMixMode, getMenuWidth, getIsMixSidebar } =
+        useMenuSetting()
+      const { getUseErrorHandle, getShowSettingButton, getSettingButtonPosition } = useRootSetting()
 
       const {
         getHeaderTheme,
-        getUseLockPage,
         getShowFullScreen,
         getShowNotice,
         getShowContent,
         getShowBread,
         getShowHeaderLogo,
         getShowHeader,
-      } = useHeaderSetting();
+        getShowSearch
+      } = useHeaderSetting()
 
-      const { getShowLocalePicker } = useLocale();
+      const { getShowLocalePicker } = useLocale()
 
-      const { getIsMobile } = useAppInject();
+      const { getIsMobile } = useAppInject()
 
       const getHeaderClass = computed(() => {
-        const theme = unref(getHeaderTheme);
+        const theme = unref(getHeaderTheme)
         return [
           prefixCls,
           {
             [`${prefixCls}--fixed`]: props.fixed,
             [`${prefixCls}--mobile`]: unref(getIsMobile),
-            [`${prefixCls}--${theme}`]: theme,
-          },
-        ];
-      });
+            [`${prefixCls}--${theme}`]: theme
+          }
+        ]
+      })
 
       const getShowSetting = computed(() => {
         if (!unref(getShowSettingButton)) {
-          return false;
+          return false
         }
-        const settingButtonPosition = unref(getSettingButtonPosition);
+        const settingButtonPosition = unref(getSettingButtonPosition)
 
         if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
-          return unref(getShowHeader);
+          return unref(getShowHeader)
         }
-        return settingButtonPosition === SettingButtonPositionEnum.HEADER;
-      });
+        return settingButtonPosition === SettingButtonPositionEnum.HEADER
+      })
 
       const getLogoWidth = computed(() => {
         if (!unref(getIsMixMode) || unref(getIsMobile)) {
-          return {};
+          return {}
         }
-        const width = unref(getMenuWidth) < 180 ? 180 : unref(getMenuWidth);
-        return { width: `${width}px` };
-      });
+        const width = unref(getMenuWidth) < 180 ? 180 : unref(getMenuWidth)
+        return { width: `${width}px` }
+      })
 
       const getSplitType = computed(() => {
-        return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE;
-      });
+        return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE
+      })
 
       const getMenuMode = computed(() => {
-        return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null;
-      });
+        return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null
+      })
 
       return {
         prefixCls,
@@ -189,15 +172,15 @@
         getShowLocalePicker,
         getShowFullScreen,
         getShowNotice,
-        getUseLockPage,
         getUseErrorHandle,
         getLogoWidth,
         getIsMixSidebar,
         getShowSettingButton,
         getShowSetting,
-      };
-    },
-  });
+        getShowSearch
+      }
+    }
+  })
 </script>
 <style lang="less">
   @import './index.less';

+ 35 - 22
src/layouts/default/index.vue

@@ -1,8 +1,8 @@
 <template>
-  <Layout :class="prefixCls">
+  <Layout :class="prefixCls" v-bind="lockEvents">
     <LayoutFeatures />
     <LayoutHeader fixed v-if="getShowFullHeaderRef" />
-    <Layout :class="layoutClass">
+    <Layout :class="[layoutClass]">
       <LayoutSideBar v-if="getShowSidebar || getIsMobile" />
       <Layout :class="`${prefixCls}-main`">
         <LayoutMultipleHeader />
@@ -14,20 +14,21 @@
 </template>
 
 <script lang="ts">
-  import { defineComponent, computed, unref } from 'vue';
-  import { Layout } from 'ant-design-vue';
-  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
+  import { defineComponent, computed, unref } from 'vue'
+  import { Layout } from 'ant-design-vue'
+  import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'
 
-  import LayoutHeader from './header/index.vue';
-  import LayoutContent from './content/index.vue';
-  import LayoutSideBar from './sider/index.vue';
-  import LayoutMultipleHeader from './header/MultipleHeader.vue';
+  import LayoutHeader from './header/index.vue'
+  import LayoutContent from './content/index.vue'
+  import LayoutSideBar from './sider/index.vue'
+  import LayoutMultipleHeader from './header/MultipleHeader.vue'
 
-  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'
+  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useLockPage } from '/@/hooks/web/useLockPage'
 
-  import { useAppInject } from '/@/hooks/web/useAppInject';
+  import { useAppInject } from '/@/hooks/web/useAppInject'
 
   export default defineComponent({
     name: 'DefaultLayout',
@@ -38,14 +39,24 @@
       LayoutContent,
       LayoutSideBar,
       LayoutMultipleHeader,
-      Layout,
+      Layout
     },
     setup() {
-      const { prefixCls } = useDesign('default-layout');
-      const { getIsMobile } = useAppInject();
-      const { getShowFullHeaderRef } = useHeaderSetting();
-      const { getShowSidebar, getIsMixSidebar } = useMenuSetting();
-      const layoutClass = computed(() => ({ 'ant-layout-has-sider': unref(getIsMixSidebar) }));
+      const { prefixCls } = useDesign('default-layout')
+      const { getIsMobile } = useAppInject()
+      const { getShowFullHeaderRef } = useHeaderSetting()
+      const { getShowSidebar, getIsMixSidebar, getShowMenu } = useMenuSetting()
+
+      // Create a lock screen monitor
+      const lockEvents = useLockPage()
+
+      const layoutClass = computed(() => {
+        let cls: string[] = ['ant-layout']
+        if (unref(getIsMixSidebar) || unref(getShowMenu)) {
+          cls.push('ant-layout-has-sider')
+        }
+        return cls
+      })
 
       return {
         getShowFullHeaderRef,
@@ -54,9 +65,10 @@
         getIsMobile,
         getIsMixSidebar,
         layoutClass,
-      };
-    },
-  });
+        lockEvents
+      }
+    }
+  })
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-default-layout';
@@ -73,6 +85,7 @@
     }
 
     &-main {
+      width: 100%;
       margin-left: 1px;
     }
   }

+ 58 - 64
src/layouts/default/menu/index.vue

@@ -1,24 +1,24 @@
 <script lang="tsx">
-  import type { PropType, CSSProperties } from 'vue';
+  import type { PropType, CSSProperties } from 'vue'
 
-  import { computed, defineComponent, unref, toRef } from 'vue';
-  import { BasicMenu } from '/@/components/Menu';
-  import { SimpleMenu } from '/@/components/SimpleMenu';
-  import { AppLogo } from '/@/components/Application';
+  import { computed, defineComponent, unref, toRef } from 'vue'
+  import { BasicMenu } from '/@/components/Menu'
+  import { SimpleMenu } from '/@/components/SimpleMenu'
+  import { AppLogo } from '/@/components/Application'
 
-  import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
+  import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'
 
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { ScrollContainer } from '/@/components/Container';
+  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'
+  import { ScrollContainer } from '/@/components/Container'
 
-  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';
-  import { useAppInject } from '/@/hooks/web/useAppInject';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  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'
+  import { useAppInject } from '/@/hooks/web/useAppInject'
+  import { useDesign } from '/@/hooks/web/useDesign'
 
   export default defineComponent({
     name: 'LayoutMenu',
@@ -27,18 +27,18 @@
 
       splitType: {
         type: Number as PropType<MenuSplitTyeEnum>,
-        default: MenuSplitTyeEnum.NONE,
+        default: MenuSplitTyeEnum.NONE
       },
 
       isHorizontal: propTypes.bool,
       // menu Mode
       menuMode: {
         type: [String] as PropType<Nullable<MenuModeEnum>>,
-        default: '',
-      },
+        default: ''
+      }
     },
     setup(props) {
-      const go = useGo();
+      const go = useGo()
 
       const {
         getMenuMode,
@@ -49,23 +49,23 @@
         getAccordion,
         getIsHorizontal,
         getIsSidebarType,
-        getSplit,
-      } = useMenuSetting();
-      const { getShowLogo } = useRootSetting();
+        getSplit
+      } = useMenuSetting()
+      const { getShowLogo } = useRootSetting()
 
-      const { prefixCls } = useDesign('layout-menu');
+      const { prefixCls } = useDesign('layout-menu')
 
-      const { menusRef } = useSplitMenu(toRef(props, 'splitType'));
+      const { menusRef } = useSplitMenu(toRef(props, 'splitType'))
 
-      const { getIsMobile } = useAppInject();
+      const { getIsMobile } = useAppInject()
 
       const getComputedMenuMode = computed(() =>
         unref(getIsMobile) ? MenuModeEnum.INLINE : props.menuMode || unref(getMenuMode)
-      );
+      )
 
-      const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme));
+      const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme))
 
-      const getIsShowLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType));
+      const getIsShowLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType))
 
       const getUseScroll = computed(() => {
         return (
@@ -73,29 +73,27 @@
           (unref(getIsSidebarType) ||
             props.splitType === MenuSplitTyeEnum.LEFT ||
             props.splitType === MenuSplitTyeEnum.NONE)
-        );
-      });
-
-      const getWrapperStyle = computed(
-        (): CSSProperties => {
-          return {
-            height: `calc(100% - ${unref(getIsShowLogo) ? '48px' : '0px'})`,
-          };
+        )
+      })
+
+      const getWrapperStyle = computed((): CSSProperties => {
+        return {
+          height: `calc(100% - ${unref(getIsShowLogo) ? '48px' : '0px'})`
         }
-      );
+      })
 
       const getLogoClass = computed(() => {
         return [
           `${prefixCls}-logo`,
           unref(getComputedMenuTheme),
           {
-            [`${prefixCls}--mobile`]: unref(getIsMobile),
-          },
-        ];
-      });
+            [`${prefixCls}--mobile`]: unref(getIsMobile)
+          }
+        ]
+      })
 
       const getCommonProps = computed(() => {
-        const menus = unref(menusRef);
+        const menus = unref(menusRef)
         return {
           menus,
           beforeClickFn: beforeMenuClickFn,
@@ -104,16 +102,16 @@
           accordion: unref(getAccordion),
           collapse: unref(getCollapsed),
           collapsedShowTitle: unref(getCollapsedShowTitle),
-          onMenuClick: handleMenuClick,
-        };
-      });
+          onMenuClick: handleMenuClick
+        }
+      })
       /**
        * click menu
        * @param menu
        */
 
       function handleMenuClick(path: string) {
-        go(path);
+        go(path)
       }
 
       /**
@@ -122,28 +120,24 @@
        */
       async function beforeMenuClickFn(path: string) {
         if (!isUrl(path)) {
-          return true;
+          return true
         }
-        openWindow(path);
-        return false;
+        openWindow(path)
+        return false
       }
 
       function renderHeader() {
-        if (!unref(getIsShowLogo) && !unref(getIsMobile)) return null;
+        if (!unref(getIsShowLogo) && !unref(getIsMobile)) return null
 
         return (
-          <AppLogo
-            showTitle={!unref(getCollapsed)}
-            class={unref(getLogoClass)}
-            theme={unref(getComputedMenuTheme)}
-          />
-        );
+          <AppLogo showTitle={!unref(getCollapsed)} class={unref(getLogoClass)} theme={unref(getComputedMenuTheme)} />
+        )
       }
 
       function renderMenu() {
-        const { menus, ...menuProps } = unref(getCommonProps);
+        const { menus, ...menuProps } = unref(getCommonProps)
         // console.log(menus);
-        if (!menus || !menus.length) return null;
+        if (!menus || !menus.length) return null
         return !props.isHorizontal ? (
           <SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} />
         ) : (
@@ -155,7 +149,7 @@
             mode={unref(getComputedMenuMode)}
             items={menus}
           />
-        );
+        )
       }
 
       return () => {
@@ -168,10 +162,10 @@
               renderMenu()
             )}
           </>
-        );
-      };
-    },
-  });
+        )
+      }
+    }
+  })
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-layout-menu';

+ 49 - 95
src/layouts/default/setting/SettingDrawer.tsx

@@ -1,27 +1,20 @@
-import { defineComponent, computed, unref } from 'vue';
-import { BasicDrawer } from '/@/components/Drawer/index';
-import { Divider } from 'ant-design-vue';
-import {
-  TypePicker,
-  ThemeColorPicker,
-  SettingFooter,
-  SwitchItem,
-  SelectItem,
-  InputNumberItem,
-} from './components';
+import { defineComponent, computed, unref } from 'vue'
+import { BasicDrawer } from '/@/components/Drawer/index'
+import { Divider } from 'ant-design-vue'
+import { TypePicker, ThemeColorPicker, SettingFooter, SwitchItem, SelectItem, InputNumberItem } from './components'
 
-import { AppDarkModeToggle } from '/@/components/Application';
+import { AppDarkModeToggle } from '/@/components/Application'
 
-import { MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum';
+import { MenuTypeEnum, TriggerEnum } from '/@/enums/menuEnum'
 
-import { useRootSetting } from '/@/hooks/setting/useRootSetting';
-import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
-import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
-import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
-import { useI18n } from '/@/hooks/web/useI18n';
+import { useRootSetting } from '/@/hooks/setting/useRootSetting'
+import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'
+import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting'
+import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'
+import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'
+import { useI18n } from '/@/hooks/web/useI18n'
 
-import { baseHandler } from './handler';
+import { baseHandler } from './handler'
 
 import {
   HandlerEnum,
@@ -30,16 +23,12 @@ import {
   getMenuTriggerOptions,
   routerTransitionOptions,
   menuTypeList,
-  mixSidebarTriggerOptions,
-} from './enum';
+  mixSidebarTriggerOptions
+} from './enum'
 
-import {
-  HEADER_PRESET_BG_COLOR_LIST,
-  SIDE_BAR_BG_COLOR_LIST,
-  APP_PRESET_COLOR_LIST,
-} from '/@/settings/designSetting';
+import { HEADER_PRESET_BG_COLOR_LIST, SIDE_BAR_BG_COLOR_LIST, APP_PRESET_COLOR_LIST } from '/@/settings/designSetting'
 
-const { t } = useI18n();
+const { t } = useI18n()
 
 export default defineComponent({
   name: 'SettingDrawer',
@@ -55,15 +44,10 @@ export default defineComponent({
       getGrayMode,
       getLockTime,
       getShowDarkModeToggle,
-      getThemeColor,
-    } = useRootSetting();
+      getThemeColor
+    } = useRootSetting()
 
-    const {
-      getOpenPageLoading,
-      getBasicTransition,
-      getEnableTransition,
-      getOpenNProgress,
-    } = useTransitionSetting();
+    const { getOpenPageLoading, getBasicTransition, getEnableTransition, getOpenNProgress } = useTransitionSetting()
 
     const {
       getIsHorizontal,
@@ -83,21 +67,16 @@ export default defineComponent({
       getIsMixSidebar,
       getCloseMixSidebarOnChange,
       getMixSideTrigger,
-      getMixSideFixed,
-    } = useMenuSetting();
+      getMixSideFixed
+    } = useMenuSetting()
 
-    const {
-      getShowHeader,
-      getFixed: getHeaderFixed,
-      getHeaderBgColor,
-      getShowSearch,
-    } = useHeaderSetting();
+    const { getShowHeader, getFixed: getHeaderFixed, getHeaderBgColor, getShowSearch } = useHeaderSetting()
 
-    const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
+    const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting()
 
     const getShowMenuRef = computed(() => {
-      return unref(getShowMenu) && !unref(getIsHorizontal);
-    });
+      return unref(getShowMenu) && !unref(getIsHorizontal)
+    })
 
     function renderSidebar() {
       return (
@@ -108,13 +87,13 @@ export default defineComponent({
               baseHandler(HandlerEnum.CHANGE_LAYOUT, {
                 mode: item.mode,
                 type: item.type,
-                split: unref(getIsHorizontal) ? false : undefined,
-              });
+                split: unref(getIsHorizontal) ? false : undefined
+              })
             }}
             def={unref(getMenuType)}
           />
         </>
-      );
+      )
     }
 
     function renderHeaderTheme() {
@@ -124,7 +103,7 @@ export default defineComponent({
           def={unref(getHeaderBgColor)}
           event={HandlerEnum.HEADER_THEME}
         />
-      );
+      )
     }
 
     function renderSiderTheme() {
@@ -134,7 +113,7 @@ export default defineComponent({
           def={unref(getMenuBgColor)}
           event={HandlerEnum.MENU_THEME}
         />
-      );
+      )
     }
 
     function renderMainTheme() {
@@ -144,19 +123,19 @@ export default defineComponent({
           def={unref(getThemeColor)}
           event={HandlerEnum.CHANGE_THEME_COLOR}
         />
-      );
+      )
     }
 
     /**
      * @description:
      */
     function renderFeatures() {
-      let triggerDef = unref(getTrigger);
+      let triggerDef = unref(getTrigger)
 
-      const triggerOptions = getMenuTriggerOptions(unref(getSplit));
-      const some = triggerOptions.some((item) => item.value === triggerDef);
+      const triggerOptions = getMenuTriggerOptions(unref(getSplit))
+      const some = triggerOptions.some(item => item.value === triggerDef)
       if (!some) {
-        triggerDef = TriggerEnum.FOOTER;
+        triggerDef = TriggerEnum.FOOTER
       }
 
       return (
@@ -265,7 +244,7 @@ export default defineComponent({
             formatter={(value: string) => {
               return parseInt(value) === 0
                 ? `0(${t('layout.setting.notAutoScreenLock')})`
-                : `${value}${t('layout.setting.minute')}`;
+                : `${value}${t('layout.setting.minute')}`
             }}
           />
           <InputNumberItem
@@ -279,7 +258,7 @@ export default defineComponent({
             formatter={(value: string) => `${parseInt(value)}px`}
           />
         </>
-      );
+      )
     }
 
     function renderContent() {
@@ -299,11 +278,7 @@ export default defineComponent({
             disabled={!unref(getShowHeader)}
           />
 
-          <SwitchItem
-            title={t('layout.setting.tabs')}
-            event={HandlerEnum.TABS_SHOW}
-            def={unref(getShowMultipleTab)}
-          />
+          <SwitchItem title={t('layout.setting.tabs')} event={HandlerEnum.TABS_SHOW} def={unref(getShowMultipleTab)} />
 
           <SwitchItem
             title={t('layout.setting.tabsRedoBtn')}
@@ -332,41 +307,25 @@ export default defineComponent({
             disabled={unref(getIsHorizontal)}
           />
 
-          <SwitchItem
-            title={t('layout.setting.header')}
-            event={HandlerEnum.HEADER_SHOW}
-            def={unref(getShowHeader)}
-          />
+          <SwitchItem title={t('layout.setting.header')} event={HandlerEnum.HEADER_SHOW} def={unref(getShowHeader)} />
           <SwitchItem
             title="Logo"
             event={HandlerEnum.SHOW_LOGO}
             def={unref(getShowLogo)}
             disabled={unref(getIsMixSidebar)}
           />
-          <SwitchItem
-            title={t('layout.setting.footer')}
-            event={HandlerEnum.SHOW_FOOTER}
-            def={unref(getShowFooter)}
-          />
+          <SwitchItem title={t('layout.setting.footer')} event={HandlerEnum.SHOW_FOOTER} def={unref(getShowFooter)} />
           <SwitchItem
             title={t('layout.setting.fullContent')}
             event={HandlerEnum.FULL_CONTENT}
             def={unref(getFullContent)}
           />
 
-          <SwitchItem
-            title={t('layout.setting.grayMode')}
-            event={HandlerEnum.GRAY_MODE}
-            def={unref(getGrayMode)}
-          />
+          <SwitchItem title={t('layout.setting.grayMode')} event={HandlerEnum.GRAY_MODE} def={unref(getGrayMode)} />
 
-          <SwitchItem
-            title={t('layout.setting.colorWeak')}
-            event={HandlerEnum.COLOR_WEAK}
-            def={unref(getColorWeak)}
-          />
+          <SwitchItem title={t('layout.setting.colorWeak')} event={HandlerEnum.COLOR_WEAK} def={unref(getColorWeak)} />
         </>
-      );
+      )
     }
 
     function renderTransition() {
@@ -397,16 +356,11 @@ export default defineComponent({
             disabled={!unref(getEnableTransition)}
           />
         </>
-      );
+      )
     }
 
     return () => (
-      <BasicDrawer
-        {...attrs}
-        title={t('layout.setting.drawerTitle')}
-        width={330}
-        wrapClassName="setting-drawer"
-      >
+      <BasicDrawer {...attrs} title={t('layout.setting.drawerTitle')} width={330} wrapClassName="setting-drawer">
         {unref(getShowDarkModeToggle) && <Divider>{() => t('layout.setting.darkMode')}</Divider>}
         {unref(getShowDarkModeToggle) && <AppDarkModeToggle class="mx-auto" />}
         <Divider>{() => t('layout.setting.navMode')}</Divider>
@@ -426,6 +380,6 @@ export default defineComponent({
         <Divider />
         <SettingFooter />
       </BasicDrawer>
-    );
-  },
-});
+    )
+  }
+})

+ 15 - 21
src/layouts/default/setting/components/InputNumberItem.vue

@@ -1,46 +1,40 @@
 <template>
   <div :class="prefixCls">
     <span> {{ title }}</span>
-    <InputNumber
-      v-bind="$attrs"
-      size="small"
-      :class="`${prefixCls}-input-number`"
-      @change="handleChange"
-    />
+    <InputNumber v-bind="$attrs" size="small" :class="`${prefixCls}-input-number`" @change="handleChange" />
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, PropType } from 'vue';
+  import { defineComponent, PropType } from 'vue'
 
-  import { InputNumber } from 'ant-design-vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { baseHandler } from '../handler';
-  import { HandlerEnum } from '../enum';
+  import { InputNumber } from 'ant-design-vue'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { baseHandler } from '../handler'
+  import { HandlerEnum } from '../enum'
 
   export default defineComponent({
     name: 'InputNumberItem',
     components: { InputNumber },
     props: {
       event: {
-        type: Number as PropType<HandlerEnum>,
-        default: () => {},
+        type: Number as PropType<HandlerEnum>
       },
       title: {
-        type: String,
-      },
+        type: String
+      }
     },
     setup(props) {
-      const { prefixCls } = useDesign('setting-input-number-item');
+      const { prefixCls } = useDesign('setting-input-number-item')
 
       function handleChange(e: ChangeEvent) {
-        props.event && baseHandler(props.event, e);
+        props.event && baseHandler(props.event, e)
       }
       return {
         prefixCls,
-        handleChange,
-      };
-    },
-  });
+        handleChange
+      }
+    }
+  })
 </script>
 <style lang="less" scoped>
   @prefix-cls: ~'@{namespace}-setting-input-number-item';

+ 20 - 21
src/layouts/default/setting/components/SelectItem.vue

@@ -12,54 +12,53 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, PropType, computed } from 'vue';
+  import { defineComponent, PropType, computed } from 'vue'
 
-  import { Select } from 'ant-design-vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { baseHandler } from '../handler';
-  import { HandlerEnum } from '../enum';
+  import { Select } from 'ant-design-vue'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { baseHandler } from '../handler'
+  import { HandlerEnum } from '../enum'
 
   export default defineComponent({
     name: 'SelectItem',
     components: { Select },
     props: {
       event: {
-        type: Number as PropType<HandlerEnum>,
-        default: () => {},
+        type: Number as PropType<HandlerEnum>
       },
       disabled: {
-        type: Boolean,
+        type: Boolean
       },
       title: {
-        type: String,
+        type: String
       },
       def: {
-        type: [String, Number] as PropType<string | number>,
+        type: [String, Number] as PropType<string | number>
       },
       initValue: {
-        type: [String, Number] as PropType<string | number>,
+        type: [String, Number] as PropType<string | number>
       },
       options: {
         type: Array as PropType<LabelValueOptions>,
-        default: () => [],
-      },
+        default: () => []
+      }
     },
     setup(props) {
-      const { prefixCls } = useDesign('setting-select-item');
+      const { prefixCls } = useDesign('setting-select-item')
       const getBindValue = computed(() => {
-        return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {};
-      });
+        return props.def ? { value: props.def, defaultValue: props.initValue || props.def } : {}
+      })
 
       function handleChange(e: ChangeEvent) {
-        props.event && baseHandler(props.event, e);
+        props.event && baseHandler(props.event, e)
       }
       return {
         prefixCls,
         handleChange,
-        getBindValue,
-      };
-    },
-  });
+        getBindValue
+      }
+    }
+  })
 </script>
 <style lang="less" scoped>
   @prefix-cls: ~'@{namespace}-setting-select-item';

+ 20 - 21
src/layouts/default/setting/components/SwitchItem.vue

@@ -11,50 +11,49 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, PropType, computed } from 'vue';
+  import { defineComponent, PropType, computed } from 'vue'
 
-  import { Switch } from 'ant-design-vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { baseHandler } from '../handler';
-  import { HandlerEnum } from '../enum';
+  import { Switch } from 'ant-design-vue'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useI18n } from '/@/hooks/web/useI18n'
+  import { baseHandler } from '../handler'
+  import { HandlerEnum } from '../enum'
 
   export default defineComponent({
     name: 'SwitchItem',
     components: { Switch },
     props: {
       event: {
-        type: Number as PropType<HandlerEnum>,
-        default: () => {},
+        type: Number as PropType<HandlerEnum>
       },
       disabled: {
-        type: Boolean,
+        type: Boolean
       },
       title: {
-        type: String,
+        type: String
       },
       def: {
-        type: Boolean,
-      },
+        type: Boolean
+      }
     },
     setup(props) {
-      const { prefixCls } = useDesign('setting-switch-item');
-      const { t } = useI18n();
+      const { prefixCls } = useDesign('setting-switch-item')
+      const { t } = useI18n()
 
       const getBindValue = computed(() => {
-        return props.def ? { checked: props.def } : {};
-      });
+        return props.def ? { checked: props.def } : {}
+      })
       function handleChange(e: ChangeEvent) {
-        props.event && baseHandler(props.event, e);
+        props.event && baseHandler(props.event, e)
       }
       return {
         prefixCls,
         t,
         handleChange,
-        getBindValue,
-      };
-    },
-  });
+        getBindValue
+      }
+    }
+  })
 </script>
 <style lang="less" scoped>
   @prefix-cls: ~'@{namespace}-setting-switch-item';

+ 17 - 18
src/layouts/default/setting/components/ThemeColorPicker.vue

@@ -6,8 +6,8 @@
         :class="[
           `${prefixCls}__item`,
           {
-            [`${prefixCls}__item--active`]: def === color,
-          },
+            [`${prefixCls}__item--active`]: def === color
+          }
         ]"
         :style="{ background: color }"
       >
@@ -17,13 +17,13 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, PropType } from 'vue';
-  import { CheckOutlined } from '@ant-design/icons-vue';
+  import { defineComponent, PropType } from 'vue'
+  import { CheckOutlined } from '@ant-design/icons-vue'
 
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useDesign } from '/@/hooks/web/useDesign'
 
-  import { baseHandler } from '../handler';
-  import { HandlerEnum } from '../enum';
+  import { baseHandler } from '../handler'
+  import { HandlerEnum } from '../enum'
 
   export default defineComponent({
     name: 'ThemeColorPicker',
@@ -31,28 +31,27 @@
     props: {
       colorList: {
         type: Array as PropType<string[]>,
-        defualt: [],
+        defualt: []
       },
       event: {
-        type: Number as PropType<HandlerEnum>,
-        default: () => {},
+        type: Number as PropType<HandlerEnum>
       },
       def: {
-        type: String,
-      },
+        type: String
+      }
     },
     setup(props) {
-      const { prefixCls } = useDesign('setting-theme-picker');
+      const { prefixCls } = useDesign('setting-theme-picker')
 
       function handleClick(color: string) {
-        props.event && baseHandler(props.event, color);
+        props.event && baseHandler(props.event, color)
       }
       return {
         prefixCls,
-        handleClick,
-      };
-    },
-  });
+        handleClick
+      }
+    }
+  })
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-setting-theme-picker';

+ 15 - 15
src/layouts/default/setting/components/TypePicker.vue

@@ -8,8 +8,8 @@
             `${prefixCls}__item`,
             `${prefixCls}__item--${item.type}`,
             {
-              [`${prefixCls}__item--active`]: def === item.type,
-            },
+              [`${prefixCls}__item--active`]: def === item.type
+            }
           ]"
         >
           <div class="mix-sidebar"></div>
@@ -19,37 +19,37 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, PropType } from 'vue';
+  import { defineComponent, PropType } from 'vue'
 
-  import { Tooltip } from 'ant-design-vue';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { Tooltip } from 'ant-design-vue'
+  import { useDesign } from '/@/hooks/web/useDesign'
 
-  import { menuTypeList } from '../enum';
+  import { menuTypeList } from '../enum'
   export default defineComponent({
     name: 'MenuTypePicker',
     components: { Tooltip },
     props: {
       menuTypeList: {
         type: Array as PropType<typeof menuTypeList>,
-        defualt: () => [],
+        defualt: () => []
       },
       handler: {
         type: Function as PropType<Fn>,
-        default: () => {},
+        default: () => ({})
       },
       def: {
         type: String,
-        default: '',
-      },
+        default: ''
+      }
     },
     setup() {
-      const { prefixCls } = useDesign('setting-menu-type-picker');
+      const { prefixCls } = useDesign('setting-menu-type-picker')
 
       return {
-        prefixCls,
-      };
-    },
-  });
+        prefixCls
+      }
+    }
+  })
 </script>
 <style lang="less" scoped>
   @prefix-cls: ~'@{namespace}-setting-menu-type-picker';

+ 10 - 10
src/layouts/default/setting/index.vue

@@ -1,26 +1,26 @@
 <template>
-  <div @click="openDrawer">
+  <div @click="openDrawer(true)">
     <Icon icon="ion:settings-outline" />
     <SettingDrawer @register="register" />
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent } from 'vue';
-  import SettingDrawer from './SettingDrawer';
-  import Icon from '/@/components/Icon';
+  import { defineComponent } from 'vue'
+  import SettingDrawer from './SettingDrawer'
+  import Icon from '/@/components/Icon'
 
-  import { useDrawer } from '/@/components/Drawer';
+  import { useDrawer } from '/@/components/Drawer'
 
   export default defineComponent({
     name: 'SettingButton',
     components: { SettingDrawer, Icon },
     setup() {
-      const [register, { openDrawer }] = useDrawer();
+      const [register, { openDrawer }] = useDrawer()
 
       return {
         register,
-        openDrawer,
-      };
-    },
-  });
+        openDrawer
+      }
+    }
+  })
 </script>

+ 45 - 51
src/layouts/default/sider/LayoutSider.vue

@@ -1,9 +1,5 @@
 <template>
-  <div
-    v-if="getMenuFixed && !getIsMobile"
-    :style="getHiddenDomStyle"
-    v-show="showClassSideBarRef"
-  ></div>
+  <div v-if="getMenuFixed && !getIsMobile" :style="getHiddenDomStyle" v-show="showClassSideBarRef"></div>
   <Sider
     v-show="showClassSideBarRef"
     ref="sideRef"
@@ -25,26 +21,26 @@
   </Sider>
 </template>
 <script lang="ts">
-  import { computed, defineComponent, ref, unref, CSSProperties } from 'vue';
+  import { computed, defineComponent, ref, unref, CSSProperties } from 'vue'
 
-  import { Layout } from 'ant-design-vue';
-  import LayoutMenu from '../menu/index.vue';
-  import LayoutTrigger from '/@/layouts/default/trigger/index.vue';
+  import { Layout } from 'ant-design-vue'
+  import LayoutMenu from '../menu/index.vue'
+  import LayoutTrigger from '/@/layouts/default/trigger/index.vue'
 
-  import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum';
+  import { MenuModeEnum, MenuSplitTyeEnum } from '/@/enums/menuEnum'
 
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { useTrigger, useDragLine, useSiderEvent } from './useLayoutSider';
-  import { useAppInject } from '/@/hooks/web/useAppInject';
-  import { useDesign } from '/@/hooks/web/useDesign';
+  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'
+  import { useTrigger, useDragLine, useSiderEvent } from './useLayoutSider'
+  import { useAppInject } from '/@/hooks/web/useAppInject'
+  import { useDesign } from '/@/hooks/web/useDesign'
 
-  import DragBar from './DragBar.vue';
+  import DragBar from './DragBar.vue'
   export default defineComponent({
     name: 'LayoutSideBar',
     components: { Sider: Layout.Sider, LayoutMenu, DragBar, LayoutTrigger },
     setup() {
-      const dragBarRef = ref<ElRef>(null);
-      const sideRef = ref<ElRef>(null);
+      const dragBarRef = ref<ElRef>(null)
+      const sideRef = ref<ElRef>(null)
 
       const {
         getCollapsed,
@@ -54,54 +50,52 @@
         getRealWidth,
         getMenuHidden,
         getMenuFixed,
-        getIsMixMode,
-      } = useMenuSetting();
+        getIsMixMode
+      } = useMenuSetting()
 
-      const { prefixCls } = useDesign('layout-sideBar');
+      const { prefixCls } = useDesign('layout-sideBar')
 
-      const { getIsMobile } = useAppInject();
+      const { getIsMobile } = useAppInject()
 
-      const { getTriggerAttr, getShowTrigger } = useTrigger(getIsMobile);
+      const { getTriggerAttr, getShowTrigger } = useTrigger(getIsMobile)
 
-      useDragLine(sideRef, dragBarRef);
+      useDragLine(sideRef, dragBarRef)
 
-      const { getCollapsedWidth, onBreakpointChange } = useSiderEvent();
+      const { getCollapsedWidth, onBreakpointChange } = useSiderEvent()
 
       const getMode = computed(() => {
-        return unref(getSplit) ? MenuModeEnum.INLINE : null;
-      });
+        return unref(getSplit) ? MenuModeEnum.INLINE : null
+      })
 
       const getSplitType = computed(() => {
-        return unref(getSplit) ? MenuSplitTyeEnum.LEFT : MenuSplitTyeEnum.NONE;
-      });
+        return unref(getSplit) ? MenuSplitTyeEnum.LEFT : MenuSplitTyeEnum.NONE
+      })
 
       const showClassSideBarRef = computed(() => {
-        return unref(getSplit) ? !unref(getMenuHidden) : true;
-      });
+        return unref(getSplit) ? !unref(getMenuHidden) : true
+      })
 
       const getSiderClass = computed(() => {
         return [
           prefixCls,
           {
             [`${prefixCls}--fixed`]: unref(getMenuFixed),
-            [`${prefixCls}--mix`]: unref(getIsMixMode) && !unref(getIsMobile),
-          },
-        ];
-      });
-
-      const getHiddenDomStyle = computed(
-        (): CSSProperties => {
-          const width = `${unref(getRealWidth)}px`;
-          return {
-            width: width,
-            overflow: 'hidden',
-            flex: `0 0 ${width}`,
-            maxWidth: width,
-            minWidth: width,
-            transition: 'all 0.2s',
-          };
+            [`${prefixCls}--mix`]: unref(getIsMixMode) && !unref(getIsMobile)
+          }
+        ]
+      })
+
+      const getHiddenDomStyle = computed((): CSSProperties => {
+        const width = `${unref(getRealWidth)}px`
+        return {
+          width: width,
+          overflow: 'hidden',
+          flex: `0 0 ${width}`,
+          maxWidth: width,
+          minWidth: width,
+          transition: 'all 0.2s'
         }
-      );
+      })
 
       return {
         prefixCls,
@@ -120,10 +114,10 @@
         onBreakpointChange,
         getMode,
         getSplitType,
-        getShowTrigger,
-      };
-    },
-  });
+        getShowTrigger
+      }
+    }
+  })
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-layout-sideBar';

+ 116 - 131
src/layouts/default/sider/MixSider.vue

@@ -8,8 +8,8 @@
       getMenuTheme,
       {
         open: openMenu,
-        mini: getCollapsed,
-      },
+        mini: getCollapsed
+      }
     ]"
     v-bind="getMenuEvents"
   >
@@ -23,8 +23,8 @@
           :class="[
             `${prefixCls}-module__item `,
             {
-              [`${prefixCls}-module__item--active`]: item.path === activePath,
-            },
+              [`${prefixCls}-module__item--active`]: item.path === activePath
+            }
           ]"
           v-bind="getItemEvents(item)"
           v-for="item in menuModules"
@@ -49,8 +49,8 @@
         :class="[
           `${prefixCls}-menu-list__title`,
           {
-            show: openMenu,
-          },
+            show: openMenu
+          }
         ]"
       >
         <span class="text"> {{ title }}</span>
@@ -62,47 +62,38 @@
         />
       </div>
       <ScrollContainer :class="`${prefixCls}-menu-list__content`">
-        <SimpleMenu
-          :items="chilrenMenus"
-          :theme="getMenuTheme"
-          mixSider
-          @menuClick="handleMenuClick"
-        />
+        <SimpleMenu :items="chilrenMenus" :theme="getMenuTheme" mixSider @menuClick="handleMenuClick" />
       </ScrollContainer>
-      <div
-        v-show="getShowDragBar && openMenu"
-        :class="`${prefixCls}-drag-bar`"
-        ref="dragBarRef"
-      ></div>
+      <div v-show="getShowDragBar && openMenu" :class="`${prefixCls}-drag-bar`" ref="dragBarRef"></div>
     </div>
   </div>
 </template>
 <script lang="ts">
-  import type { Menu } from '/@/router/types';
-  import type { CSSProperties } from 'vue';
-  import type { RouteLocationNormalized } from 'vue-router';
+  import type { Menu } from '/@/router/types'
+  import type { CSSProperties } from 'vue'
+  import type { RouteLocationNormalized } from 'vue-router'
 
-  import { defineComponent, onMounted, ref, computed, unref } from 'vue';
+  import { defineComponent, onMounted, ref, computed, unref } from 'vue'
 
-  import { ScrollContainer } from '/@/components/Container';
-  import { SimpleMenuTag } from '/@/components/SimpleMenu';
-  import { Icon } from '/@/components/Icon';
-  import { AppLogo } from '/@/components/Application';
-  import Trigger from '../trigger/HeaderTrigger.vue';
+  import { ScrollContainer } from '/@/components/Container'
+  import { SimpleMenuTag } from '/@/components/SimpleMenu'
+  import { Icon } from '/@/components/Icon'
+  import { AppLogo } from '/@/components/Application'
+  import Trigger from '../trigger/HeaderTrigger.vue'
 
-  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
-  import { useDragLine } from './useLayoutSider';
-  import { useGlobSetting } from '/@/hooks/setting';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useI18n } from '/@/hooks/web/useI18n';
-  import { useGo } from '/@/hooks/web/usePage';
+  import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'
+  import { useDragLine } from './useLayoutSider'
+  import { useGlobSetting } from '/@/hooks/setting'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useI18n } from '/@/hooks/web/useI18n'
+  import { useGo } from '/@/hooks/web/usePage'
 
-  import { SIDE_BAR_SHOW_TIT_MINI_WIDTH, SIDE_BAR_MINI_WIDTH } from '/@/enums/appEnum';
+  import { SIDE_BAR_SHOW_TIT_MINI_WIDTH, SIDE_BAR_MINI_WIDTH } from '/@/enums/appEnum'
 
-  import clickOutside from '/@/directives/clickOutside';
-  import { getShallowMenus, getChildrenMenus, getCurrentParentPath } from '/@/router/menus';
-  import { listenerRouteChange } from '/@/logics/mitt/routeChange';
-  import { SimpleMenu } from '/@/components/SimpleMenu';
+  import clickOutside from '/@/directives/clickOutside'
+  import { getShallowMenus, getChildrenMenus, getCurrentParentPath } from '/@/router/menus'
+  import { listenerRouteChange } from '/@/logics/mitt/routeChange'
+  import { SimpleMenu } from '/@/components/SimpleMenu'
 
   export default defineComponent({
     name: 'LayoutMixSider',
@@ -112,23 +103,23 @@
       SimpleMenu,
       Icon,
       Trigger,
-      SimpleMenuTag,
+      SimpleMenuTag
     },
     directives: {
-      clickOutside,
+      clickOutside
     },
     setup() {
-      let menuModules = ref<Menu[]>([]);
-      const activePath = ref('');
-      const chilrenMenus = ref<Menu[]>([]);
-      const openMenu = ref(false);
-      const dragBarRef = ref<ElRef>(null);
-      const sideRef = ref<ElRef>(null);
-      const currentRoute = ref<Nullable<RouteLocationNormalized>>(null);
-
-      const { prefixCls } = useDesign('layout-mix-sider');
-      const go = useGo();
-      const { t } = useI18n();
+      let menuModules = ref<Menu[]>([])
+      const activePath = ref('')
+      const chilrenMenus = ref<Menu[]>([])
+      const openMenu = ref(false)
+      const dragBarRef = ref<ElRef>(null)
+      const sideRef = ref<ElRef>(null)
+      const currentRoute = ref<Nullable<RouteLocationNormalized>>(null)
+
+      const { prefixCls } = useDesign('layout-mix-sider')
+      const go = useGo()
+      const { t } = useI18n()
       const {
         getMenuWidth,
         getCanDrag,
@@ -140,170 +131,164 @@
         mixSideHasChildren,
         setMenuSetting,
         getIsMixSidebar,
-        getCollapsed,
-      } = useMenuSetting();
+        getCollapsed
+      } = useMenuSetting()
 
-      const { title } = useGlobSetting();
+      const { title } = useGlobSetting()
 
-      useDragLine(sideRef, dragBarRef, true);
+      useDragLine(sideRef, dragBarRef, true)
 
-      const getMenuStyle = computed(
-        (): CSSProperties => {
-          return {
-            width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
-            left: `${unref(getMixSideWidth)}px`,
-          };
+      const getMenuStyle = computed((): CSSProperties => {
+        return {
+          width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
+          left: `${unref(getMixSideWidth)}px`
         }
-      );
+      })
 
       const getIsFixed = computed(() => {
         /* eslint-disable-next-line */
-        mixSideHasChildren.value = unref(chilrenMenus).length > 0;
-        const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren);
+        mixSideHasChildren.value = unref(chilrenMenus).length > 0
+        const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren)
         if (isFixed) {
           /* eslint-disable-next-line */
-          openMenu.value = true;
+          openMenu.value = true
         }
-        return isFixed;
-      });
+        return isFixed
+      })
 
       const getMixSideWidth = computed(() => {
-        return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH;
-      });
-
-      const getDomStyle = computed(
-        (): CSSProperties => {
-          const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0;
-          const width = `${unref(getMixSideWidth) + fixedWidth}px`;
-          return getWrapCommonStyle(width);
-        }
-      );
+        return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH
+      })
 
-      const getWrapStyle = computed(
-        (): CSSProperties => {
-          const width = `${unref(getMixSideWidth)}px`;
-          return getWrapCommonStyle(width);
-        }
-      );
+      const getDomStyle = computed((): CSSProperties => {
+        const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0
+        const width = `${unref(getMixSideWidth) + fixedWidth}px`
+        return getWrapCommonStyle(width)
+      })
+
+      const getWrapStyle = computed((): CSSProperties => {
+        const width = `${unref(getMixSideWidth)}px`
+        return getWrapCommonStyle(width)
+      })
 
       const getMenuEvents = computed(() => {
         return !unref(getMixSideFixed)
           ? {
               onMouseleave: () => {
-                closeMenu();
-              },
+                closeMenu()
+              }
             }
-          : {};
-      });
+          : {}
+      })
 
-      const getShowDragBar = computed(() => unref(getCanDrag));
+      const getShowDragBar = computed(() => unref(getCanDrag))
 
       onMounted(async () => {
-        menuModules.value = await getShallowMenus();
-      });
+        menuModules.value = await getShallowMenus()
+      })
 
-      listenerRouteChange((route) => {
-        currentRoute.value = route;
-        setActive(true);
+      listenerRouteChange(route => {
+        currentRoute.value = route
+        setActive(true)
         if (unref(getCloseMixSidebarOnChange)) {
-          closeMenu();
+          closeMenu()
         }
-      });
+      })
 
       function getWrapCommonStyle(width: string): CSSProperties {
         return {
           width,
           maxWidth: width,
           minWidth: width,
-          flex: `0 0 ${width}`,
-        };
+          flex: `0 0 ${width}`
+        }
       }
 
       // Process module menu click
       async function hanldeModuleClick(path: string, hover = false) {
-        const children = await getChildrenMenus(path);
+        const children = await getChildrenMenus(path)
 
         if (unref(activePath) === path) {
           if (!hover) {
             if (!unref(openMenu)) {
-              openMenu.value = true;
+              openMenu.value = true
             } else {
-              closeMenu();
+              closeMenu()
             }
           }
           if (!unref(openMenu)) {
-            setActive();
+            setActive()
           }
         } else {
-          openMenu.value = true;
-          activePath.value = path;
+          openMenu.value = true
+          activePath.value = path
         }
 
         if (!children || children.length === 0) {
-          go(path);
-          chilrenMenus.value = [];
-          closeMenu();
-          return;
+          go(path)
+          chilrenMenus.value = []
+          closeMenu()
+          return
         }
-        chilrenMenus.value = children;
+        chilrenMenus.value = children
       }
 
       // Set the currently active menu and submenu
       async function setActive(setChildren = false) {
-        const path = currentRoute.value?.path;
-        if (!path) return;
-        const parentPath = await getCurrentParentPath(path);
-        activePath.value = parentPath;
+        const path = currentRoute.value?.path
+        if (!path) return
+        const parentPath = await getCurrentParentPath(path)
+        activePath.value = parentPath
         // hanldeModuleClick(parentPath);
         if (unref(getIsMixSidebar)) {
-          const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
-          const p = activeMenu?.path;
+          const activeMenu = unref(menuModules).find(item => item.path === unref(activePath))
+          const p = activeMenu?.path
           if (p) {
-            const children = await getChildrenMenus(p);
+            const children = await getChildrenMenus(p)
             if (setChildren) {
-              chilrenMenus.value = children;
+              chilrenMenus.value = children
 
               if (unref(getMixSideFixed)) {
-                openMenu.value = children.length > 0;
+                openMenu.value = children.length > 0
               }
             }
             if (children.length === 0) {
-              chilrenMenus.value = [];
+              chilrenMenus.value = []
             }
           }
         }
       }
 
       function handleMenuClick(path: string) {
-        go(path);
+        go(path)
       }
 
       function handleClickOutside() {
-        setActive(true);
-        closeMenu();
+        setActive(true)
+        closeMenu()
       }
 
       function getItemEvents(item: Menu) {
         if (unref(getMixSideTrigger) === 'hover') {
           return {
-            onMouseenter: () => hanldeModuleClick(item.path, true),
-          };
+            onMouseenter: () => hanldeModuleClick(item.path, true)
+          }
         }
         return {
-          onClick: () => hanldeModuleClick(item.path),
-        };
+          onClick: () => hanldeModuleClick(item.path)
+        }
       }
 
       function handleFixedMenu() {
         setMenuSetting({
-          mixSideFixed: !unref(getIsFixed),
-        });
+          mixSideFixed: !unref(getIsFixed)
+        })
       }
 
       // Close menu
       function closeMenu() {
         if (!unref(getIsFixed)) {
-          openMenu.value = false;
+          openMenu.value = false
         }
       }
 
@@ -329,10 +314,10 @@
         handleFixedMenu,
         getMixSideFixed,
         getWrapStyle,
-        getCollapsed,
-      };
-    },
-  });
+        getCollapsed
+      }
+    }
+  })
 </script>
 <style lang="less">
   @prefix-cls: ~'@{namespace}-layout-mix-sider';

+ 52 - 55
src/layouts/default/tabs/index.vue

@@ -27,28 +27,28 @@
   </div>
 </template>
 <script lang="ts">
-  import type { RouteLocationNormalized } from 'vue-router';
+  import type { RouteLocationNormalized } from 'vue-router'
 
-  import { defineComponent, computed, unref, ref } from 'vue';
+  import { defineComponent, computed, unref, ref } from 'vue'
 
-  import { Tabs } from 'ant-design-vue';
-  import TabContent from './components/TabContent.vue';
-  import FoldButton from './components/FoldButton.vue';
-  import TabRedo from './components/TabRedo.vue';
+  import { Tabs } from 'ant-design-vue'
+  import TabContent from './components/TabContent.vue'
+  import FoldButton from './components/FoldButton.vue'
+  import TabRedo from './components/TabRedo.vue'
 
-  import { useGo } from '/@/hooks/web/usePage';
+  import { useGo } from '/@/hooks/web/usePage'
 
-  import { useMultipleTabStore } from '/@/store/modules/multipleTab';
-  import { useUserStore } from '/@/store/modules/user';
+  import { useMultipleTabStore } from '/@/store/modules/multipleTab'
+  import { useUserStore } from '/@/store/modules/user'
 
-  import { initAffixTabs, useTabsDrag } from './useMultipleTabs';
-  import { useDesign } from '/@/hooks/web/useDesign';
-  import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
+  import { initAffixTabs, useTabsDrag } from './useMultipleTabs'
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'
 
-  import { REDIRECT_NAME } from '/@/router/constant';
-  import { listenerRouteChange } from '/@/logics/mitt/routeChange';
+  import { REDIRECT_NAME } from '/@/router/constant'
+  import { listenerRouteChange } from '/@/logics/mitt/routeChange'
 
-  import { useRouter } from 'vue-router';
+  import { useRouter } from 'vue-router'
 
   export default defineComponent({
     name: 'MultipleTabs',
@@ -57,75 +57,72 @@
       FoldButton,
       Tabs,
       TabPane: Tabs.TabPane,
-      TabContent,
+      TabContent
     },
     setup() {
-      const affixTextList = initAffixTabs();
-      const activeKeyRef = ref('');
+      const affixTextList = initAffixTabs()
+      const activeKeyRef = ref('')
 
-      useTabsDrag(affixTextList);
-      const tabStore = useMultipleTabStore();
-      const userStore = useUserStore();
-      const router = useRouter();
+      useTabsDrag(affixTextList)
+      const tabStore = useMultipleTabStore()
+      const userStore = useUserStore()
+      const router = useRouter()
 
-      const { prefixCls } = useDesign('multiple-tabs');
-      const go = useGo();
-      const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting();
+      const { prefixCls } = useDesign('multiple-tabs')
+      const go = useGo()
+      const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting()
 
       const getTabsState = computed(() => {
-        return tabStore.getTabList.filter((item) => !item.meta?.hideTab);
-      });
+        return tabStore.getTabList.filter(item => !item.meta?.hideTab)
+      })
 
-      const unClose = computed(() => unref(getTabsState).length === 1);
+      const unClose = computed(() => unref(getTabsState).length === 1)
 
       const getWrapClass = computed(() => {
         return [
           prefixCls,
           {
-            [`${prefixCls}--hide-close`]: unref(unClose),
-          },
-        ];
-      });
+            [`${prefixCls}--hide-close`]: unref(unClose)
+          }
+        ]
+      })
 
-      listenerRouteChange((route) => {
-        const { name } = route;
+      listenerRouteChange(route => {
+        const { name } = route
         if (name === REDIRECT_NAME || !route || !userStore.getToken) {
-          return;
+          return
         }
 
-        const { path, fullPath, meta = {} } = route;
-        const { currentActiveMenu, hideTab } = meta;
-        const isHide = !hideTab ? null : currentActiveMenu;
-        const p = isHide || fullPath || path;
+        const { path, fullPath, meta = {} } = route
+        const { currentActiveMenu, hideTab } = meta
+        const isHide = !hideTab ? null : currentActiveMenu
+        const p = isHide || fullPath || path
         if (activeKeyRef.value !== p) {
-          activeKeyRef.value = p as string;
+          activeKeyRef.value = p as string
         }
 
         if (isHide) {
-          const findParentRoute = router
-            .getRoutes()
-            .find((item) => item.path === currentActiveMenu);
+          const findParentRoute = router.getRoutes().find(item => item.path === currentActiveMenu)
 
-          findParentRoute &&
-            tabStore.addTab((findParentRoute as unknown) as RouteLocationNormalized);
+          findParentRoute && tabStore.addTab(findParentRoute as unknown as RouteLocationNormalized)
         } else {
-          tabStore.addTab(unref(route));
+          tabStore.addTab(unref(route))
         }
-      });
+      })
 
       function handleChange(activeKey: any) {
-        activeKeyRef.value = activeKey;
-        go(activeKey, false);
+        activeKeyRef.value = activeKey
+        go(activeKey, false)
       }
 
       // Close the current tab
       function handleEdit(targetKey: string) {
         // Added operation to hide, currently only use delete operation
         if (unref(unClose)) {
-          return;
+          return
         }
 
-        tabStore.closeTabByKey(targetKey, router);
+        tabStore.closeTabByKey(targetKey, router)
       }
       return {
         prefixCls,
@@ -137,10 +134,10 @@
         getTabsState,
         getShowQuick,
         getShowRedo,
-        getShowFold,
-      };
-    },
-  });
+        getShowFold
+      }
+    }
+  })
 </script>
 <style lang="less">
   @import './index.less';

+ 41 - 41
src/layouts/default/tabs/useMultipleTabs.ts

@@ -1,78 +1,78 @@
-import { toRaw, ref, nextTick } from 'vue';
-import type { RouteLocationNormalized } from 'vue-router';
-import { useDesign } from '/@/hooks/web/useDesign';
-import { useSortable } from '/@/hooks/web/useSortable';
-import { useMultipleTabStore } from '/@/store/modules/multipleTab';
-import { isNullAndUnDef } from '/@/utils/is';
-import projectSetting from '/@/settings/projectSetting';
-import { useRouter } from 'vue-router';
+import { toRaw, ref, nextTick } from 'vue'
+import type { RouteLocationNormalized } from 'vue-router'
+import { useDesign } from '/@/hooks/web/useDesign'
+import { useSortable } from '/@/hooks/web/useSortable'
+import { useMultipleTabStore } from '/@/store/modules/multipleTab'
+import { isNullAndUnDef } from '/@/utils/is'
+import projectSetting from '/@/settings/projectSetting'
+import { useRouter } from 'vue-router'
 
 export function initAffixTabs(): string[] {
-  const affixList = ref<RouteLocationNormalized[]>([]);
+  const affixList = ref<RouteLocationNormalized[]>([])
 
-  const tabStore = useMultipleTabStore();
-  const router = useRouter();
+  const tabStore = useMultipleTabStore()
+  const router = useRouter()
   /**
    * @description: Filter all fixed routes
    */
   function filterAffixTabs(routes: RouteLocationNormalized[]) {
-    const tabs: RouteLocationNormalized[] = [];
+    const tabs: RouteLocationNormalized[] = []
     routes &&
-      routes.forEach((route) => {
+      routes.forEach(route => {
         if (route.meta && route.meta.affix) {
-          tabs.push(toRaw(route));
+          tabs.push(toRaw(route))
         }
-      });
-    return tabs;
+      })
+    return tabs
   }
 
   /**
    * @description: Set fixed tabs
    */
   function addAffixTabs(): void {
-    const affixTabs = filterAffixTabs((router.getRoutes() as unknown) as RouteLocationNormalized[]);
-    affixList.value = affixTabs;
+    const affixTabs = filterAffixTabs(router.getRoutes() as unknown as RouteLocationNormalized[])
+    affixList.value = affixTabs
     for (const tab of affixTabs) {
-      tabStore.addTab(({
+      tabStore.addTab({
         meta: tab.meta,
         name: tab.name,
-        path: tab.path,
-      } as unknown) as RouteLocationNormalized);
+        path: tab.path
+      } as unknown as RouteLocationNormalized)
     }
   }
 
-  let isAddAffix = false;
+  let isAddAffix = false
 
   if (!isAddAffix) {
-    addAffixTabs();
-    isAddAffix = true;
+    addAffixTabs()
+    isAddAffix = true
   }
-  return affixList.value.map((item) => item.meta?.title).filter(Boolean) as string[];
+  return affixList.value.map(item => item.meta?.title).filter(Boolean) as string[]
 }
 
 export function useTabsDrag(affixTextList: string[]) {
-  const tabStore = useMultipleTabStore();
-  const { multiTabsSetting } = projectSetting;
-  const { prefixCls } = useDesign('multiple-tabs');
+  const tabStore = useMultipleTabStore()
+  const { multiTabsSetting } = projectSetting
+  const { prefixCls } = useDesign('multiple-tabs')
   nextTick(() => {
-    if (!multiTabsSetting.canDrag) return;
-    const el = document.querySelectorAll(`.${prefixCls} .ant-tabs-nav > div`)?.[0] as HTMLElement;
+    if (!multiTabsSetting.canDrag) return
+    const el = document.querySelectorAll(`.${prefixCls} .ant-tabs-nav > div`)?.[0] as HTMLElement
     const { initSortable } = useSortable(el, {
       filter: (e: ChangeEvent) => {
-        const text = e?.target?.innerText;
-        if (!text) return false;
-        return affixTextList.includes(text);
+        const text = e?.target?.innerText
+        if (!text) return false
+        return affixTextList.includes(text)
       },
-      onEnd: (evt) => {
-        const { oldIndex, newIndex } = evt;
+      onEnd: evt => {
+        const { oldIndex, newIndex } = evt
 
         if (isNullAndUnDef(oldIndex) || isNullAndUnDef(newIndex) || oldIndex === newIndex) {
-          return;
+          return
         }
 
-        tabStore.sortTabs(oldIndex, newIndex);
-      },
-    });
-    initSortable();
-  });
+        tabStore.sortTabs(oldIndex, newIndex)
+      }
+    })
+    initSortable()
+  })
 }

+ 57 - 60
src/layouts/default/tabs/useTabDropdown.ts

@@ -1,139 +1,136 @@
-import type { TabContentProps } from './types';
-import type { DropMenu } from '/@/components/Dropdown';
-import type { ComputedRef } from 'vue';
+import type { TabContentProps } from './types'
+import type { DropMenu } from '/@/components/Dropdown'
+import type { ComputedRef } from 'vue'
 
-import { computed, unref, reactive } from 'vue';
-import { MenuEventEnum } from './types';
-import { useMultipleTabStore } from '/@/store/modules/multipleTab';
-import { RouteLocationNormalized, useRouter } from 'vue-router';
-import { useTabs } from '/@/hooks/web/useTabs';
-import { useI18n } from '/@/hooks/web/useI18n';
+import { computed, unref, reactive } from 'vue'
+import { MenuEventEnum } from './types'
+import { useMultipleTabStore } from '/@/store/modules/multipleTab'
+import { RouteLocationNormalized, useRouter } from 'vue-router'
+import { useTabs } from '/@/hooks/web/useTabs'
+import { useI18n } from '/@/hooks/web/useI18n'
 
 export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: ComputedRef<boolean>) {
   const state = reactive({
     current: null as Nullable<RouteLocationNormalized>,
-    currentIndex: 0,
-  });
+    currentIndex: 0
+  })
 
-  const { t } = useI18n();
-  const tabStore = useMultipleTabStore();
-  const { currentRoute } = useRouter();
-  const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs();
+  const { t } = useI18n()
+  const tabStore = useMultipleTabStore()
+  const { currentRoute } = useRouter()
+  const { refreshPage, closeAll, close, closeLeft, closeOther, closeRight } = useTabs()
 
-  const getTargetTab = computed(
-    (): RouteLocationNormalized => {
-      return unref(getIsTabs) ? tabContentProps.tabItem : unref(currentRoute);
-    }
-  );
+  const getTargetTab = computed((): RouteLocationNormalized => {
+    return unref(getIsTabs) ? tabContentProps.tabItem : unref(currentRoute)
+  })
 
   /**
    * @description: drop-down list
    */
   const getDropMenuList = computed(() => {
     if (!unref(getTargetTab)) {
-      return;
+      return
     }
-    const { meta } = unref(getTargetTab);
-    const { path } = unref(currentRoute);
+    const { meta } = unref(getTargetTab)
+    const { path } = unref(currentRoute)
 
     // Refresh button
-    const curItem = state.current;
-    const index = state.currentIndex;
-    const refreshDisabled = curItem ? curItem.path !== path : true;
+    const curItem = state.current
+    const index = state.currentIndex
+    const refreshDisabled = curItem ? curItem.path !== path : true
     // Close left
-    const closeLeftDisabled = index === 0;
+    const closeLeftDisabled = index === 0
 
-    const disabled = tabStore.getTabList.length === 1;
+    const disabled = tabStore.getTabList.length === 1
 
     // Close right
-    const closeRightDisabled =
-      index === tabStore.getTabList.length - 1 && tabStore.getLastDragEndIndex >= 0;
+    const closeRightDisabled = index === tabStore.getTabList.length - 1 && tabStore.getLastDragEndIndex >= 0
     const dropMenuList: DropMenu[] = [
       {
         icon: 'ion:reload-sharp',
         event: MenuEventEnum.REFRESH_PAGE,
         text: t('layout.multipleTab.reload'),
-        disabled: refreshDisabled,
+        disabled: refreshDisabled
       },
       {
         icon: 'clarity:close-line',
         event: MenuEventEnum.CLOSE_CURRENT,
         text: t('layout.multipleTab.close'),
         disabled: !!meta?.affix || disabled,
-        divider: true,
+        divider: true
       },
       {
         icon: 'line-md:arrow-close-left',
         event: MenuEventEnum.CLOSE_LEFT,
         text: t('layout.multipleTab.closeLeft'),
         disabled: closeLeftDisabled,
-        divider: false,
+        divider: false
       },
       {
         icon: 'line-md:arrow-close-right',
         event: MenuEventEnum.CLOSE_RIGHT,
         text: t('layout.multipleTab.closeRight'),
         disabled: closeRightDisabled,
-        divider: true,
+        divider: true
       },
       {
         icon: 'dashicons:align-center',
         event: MenuEventEnum.CLOSE_OTHER,
         text: t('layout.multipleTab.closeOther'),
-        disabled: disabled,
+        disabled: disabled
       },
       {
         icon: 'clarity:minus-line',
         event: MenuEventEnum.CLOSE_ALL,
         text: t('layout.multipleTab.closeAll'),
-        disabled: disabled,
-      },
-    ];
+        disabled: disabled
+      }
+    ]
 
-    return dropMenuList;
-  });
+    return dropMenuList
+  })
 
   function handleContextMenu(tabItem: RouteLocationNormalized) {
     return (e: Event) => {
       if (!tabItem) {
-        return;
+        return
       }
-      e?.preventDefault();
-      const index = tabStore.getTabList.findIndex((tab) => tab.path === tabItem.path);
-      state.current = tabItem;
-      state.currentIndex = index;
-    };
+      e?.preventDefault()
+      const index = tabStore.getTabList.findIndex(tab => tab.path === tabItem.path)
+      state.current = tabItem
+      state.currentIndex = index
+    }
   }
 
   // Handle right click event
   function handleMenuEvent(menu: DropMenu): void {
-    const { event } = menu;
+    const { event } = menu
     switch (event) {
       case MenuEventEnum.REFRESH_PAGE:
         // refresh page
-        refreshPage();
-        break;
+        refreshPage()
+        break
       // Close current
       case MenuEventEnum.CLOSE_CURRENT:
-        close(tabContentProps.tabItem);
-        break;
+        close(tabContentProps.tabItem)
+        break
       // Close left
       case MenuEventEnum.CLOSE_LEFT:
-        closeLeft();
-        break;
+        closeLeft()
+        break
       // Close right
       case MenuEventEnum.CLOSE_RIGHT:
-        closeRight();
-        break;
+        closeRight()
+        break
       // Close other
       case MenuEventEnum.CLOSE_OTHER:
-        closeOther();
-        break;
+        closeOther()
+        break
       // Close all
       case MenuEventEnum.CLOSE_ALL:
-        closeAll();
-        break;
+        closeAll()
+        break
     }
   }
-  return { getDropMenuList, handleMenuEvent, handleContextMenu };
+  return { getDropMenuList, handleMenuEvent, handleContextMenu }
 }

+ 27 - 28
src/layouts/iframe/useFrameKeepAlive.ts

@@ -1,60 +1,59 @@
-import type { AppRouteRecordRaw } from '/@/router/types';
+import type { AppRouteRecordRaw } from '/@/router/types'
 
-import { computed, toRaw, unref } from 'vue';
+import { computed, toRaw, unref } from 'vue'
 
-import { useMultipleTabStore } from '/@/store/modules/multipleTab';
+import { useMultipleTabStore } from '/@/store/modules/multipleTab'
 
-import { uniqBy } from 'lodash-es';
+import { uniqBy } from 'lodash-es'
 
-import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
+import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'
 
-import { useRouter } from 'vue-router';
+import { useRouter } from 'vue-router'
 
 export function useFrameKeepAlive() {
-  const router = useRouter();
-  const { currentRoute } = router;
-  const { getShowMultipleTab } = useMultipleTabSetting();
-  const tabStore = useMultipleTabStore();
+  const router = useRouter()
+  const { currentRoute } = router
+  const { getShowMultipleTab } = useMultipleTabSetting()
+  const tabStore = useMultipleTabStore()
   const getFramePages = computed(() => {
-    const ret =
-      getAllFramePages((toRaw(router.getRoutes()) as unknown) as AppRouteRecordRaw[]) || [];
-    return ret;
-  });
+    const ret = getAllFramePages(toRaw(router.getRoutes()) as unknown as AppRouteRecordRaw[]) || []
+    return ret
+  })
 
   const getOpenTabList = computed((): string[] => {
     return tabStore.getTabList.reduce((prev: string[], next) => {
       if (next.meta && Reflect.has(next.meta, 'frameSrc')) {
-        prev.push(next.name as string);
+        prev.push(next.name as string)
       }
-      return prev;
-    }, []);
-  });
+      return prev
+    }, [])
+  })
 
   function getAllFramePages(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] {
-    let res: AppRouteRecordRaw[] = [];
+    let res: AppRouteRecordRaw[] = []
     for (const route of routes) {
-      const { meta: { frameSrc } = {}, children } = route;
+      const { meta: { frameSrc } = {}, children } = route
       if (frameSrc) {
-        res.push(route);
+        res.push(route)
       }
       if (children && children.length) {
-        res.push(...getAllFramePages(children));
+        res.push(...getAllFramePages(children))
       }
     }
-    res = uniqBy(res, 'name');
-    return res;
+    res = uniqBy(res, 'name')
+    return res
   }
 
   function showIframe(item: AppRouteRecordRaw) {
-    return item.name === unref(currentRoute).name;
+    return item.name === unref(currentRoute).name
   }
 
   function hasRenderFrame(name: string) {
     if (!unref(getShowMultipleTab)) {
-      return router.currentRoute.value.name === name;
+      return router.currentRoute.value.name === name
     }
-    return unref(getOpenTabList).includes(name);
+    return unref(getOpenTabList).includes(name)
   }
 
-  return { hasRenderFrame, getFramePages, showIframe, getAllFramePages };
+  return { hasRenderFrame, getFramePages, showIframe, getAllFramePages }
 }

+ 2 - 2
src/router/menus/modules/dashboard.ts

@@ -1,10 +1,10 @@
 import type { MenuModule } from '/@/router/types'
-import { t } from '/@/hooks/web/useI18n'
+// import { t } from '/@/hooks/web/useI18n'
 
 const menu: MenuModule = {
   orderNo: 10,
   menu: {
-    name: t('routes.dashboard.workbench'),
+    name: '项目',
     path: '/dashboard/main'
   }
 }

+ 2 - 2
src/router/menus/modules/manager.ts

@@ -8,11 +8,11 @@ const menu: MenuModule = {
     path: '/manager',
     children: [
       {
-        path: 'list',
+        path: 'staff-list',
         name: '用户列表'
       },
       {
-        path: 'permission',
+        path: 'perm-list',
         name: '权限组'
       }
     ]

+ 4 - 4
src/router/routes/modules/dashboard.ts

@@ -1,7 +1,7 @@
 import type { AppRouteModule } from '/@/router/types'
 
 import { LAYOUT } from '/@/router/constant'
-import { t } from '/@/hooks/web/useI18n'
+// import { t } from '/@/hooks/web/useI18n'
 
 const dashboard: AppRouteModule = {
   path: '/dashboard',
@@ -9,7 +9,7 @@ const dashboard: AppRouteModule = {
   component: LAYOUT,
   redirect: '/dashboard/main',
   meta: {
-    title: t('routes.dashboard.dashboard')
+    title: '项目'
   },
   children: [
     {
@@ -17,8 +17,8 @@ const dashboard: AppRouteModule = {
       name: 'Workbench',
       component: () => import('/@/views/dashboard/workbench/index.vue'),
       meta: {
-        icon: 'ion:grid-outline',
-        title: t('routes.dashboard.workbench')
+        icon: 'clarity:users-solid-badged',
+        title: '项目'
       }
     },
     {

+ 5 - 13
src/router/routes/modules/manager.ts

@@ -6,14 +6,14 @@ const manager: AppRouteModule = {
   path: '/manager',
   name: 'Manager',
   component: LAYOUT,
-  redirect: '/manager/list',
+  redirect: '/manager/staff-list',
   meta: {
     title: '后台用户',
     icon: 'fa-solid:user-cog'
   },
   children: [
     {
-      path: 'list',
+      path: 'staff-list',
       name: 'ManagerList',
       component: () => import('/@/views/manager/user/list/index.vue'),
       meta: {
@@ -21,7 +21,7 @@ const manager: AppRouteModule = {
       }
     },
     {
-      path: 'detail/:id',
+      path: 'staff-detail/:id',
       name: 'ManagerDetail',
       component: () => import('/@/views/manager/user/detail/index.vue'),
       meta: {
@@ -29,20 +29,12 @@ const manager: AppRouteModule = {
       }
     },
     {
-      path: 'permission',
-      name: 'PermissionList',
+      path: 'perm-list',
+      name: 'PermList',
       component: () => import('/@/views/manager/permission/index.vue'),
       meta: {
         title: '权限组'
       }
-    },
-    {
-      path: 'permission/detail/:id',
-      name: 'PermissionDetail',
-      component: () => import('/@/views/manager/permission/detail.vue'),
-      meta: {
-        title: '权限详情'
-      }
     }
   ]
 }

+ 2 - 2
src/views/dashboard/project-detail/index.vue

@@ -20,9 +20,9 @@
         <a-tab-pane key="2" tab="项目账号">
           <ProjectAccount :active-id="activeKey" :id="projectInfo?.id" :has-admin="hasAdmin" />
         </a-tab-pane>
-        <a-tab-pane key="3" tab="项目标段" />
+        <!-- <a-tab-pane key="3" tab="项目标段" />
         <a-tab-pane key="4" tab="办事处共享" />
-        <a-tab-pane key="5" tab="功能设置" />
+        <a-tab-pane key="5" tab="功能设置" /> -->
       </a-tabs>
     </div>
   </PageWrapper>

+ 0 - 0
src/views/manager/permission/detail.vue


+ 86 - 2
src/views/manager/permission/index.vue

@@ -1,2 +1,86 @@
-<template><div>11</div></template>
-<script lang="ts"></script>
+<template>
+  <div>
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button @click="showModalFn" class="ml-3"><PlusOutlined />新增权限组</a-button>
+      </template>
+    </BasicTable>
+    <BasicModal @register="registerModal" :title="modalTitle" @ok="modalConfirm">
+      <BasicForm @register="registerForm" ref="formElRef" />
+    </BasicModal>
+  </div>
+</template>
+<script lang="ts">
+  import { computed, defineComponent, nextTick, ref, toRaw } from 'vue'
+  import { BasicTable, useTable } from '/@/components/Table'
+  import { getTableColumns, getPermSchemas } from './tableData'
+  import { PlusOutlined } from '@ant-design/icons-vue'
+  import { addPermGroup, getPermGroupList, updatePermGroup } from '/@/api/sys/manager'
+  import { BasicForm, FormActionType, useForm } from '/@/components/Form'
+  import { BasicModal, useModal } from '/@/components/Modal'
+  import { PermGroupItem } from '/@/api/sys/model/managerModel'
+
+  export default defineComponent({
+    name: 'PermList',
+    components: {
+      BasicTable,
+      PlusOutlined,
+      BasicModal,
+      BasicForm
+    },
+    setup() {
+      const formElRef = ref<Nullable<FormActionType>>(null)
+      const modalType = ref<'create' | 'update'>('create')
+      const [registerModal, { openModal }] = useModal()
+      const [registerForm] = useForm({
+        schemas: getPermSchemas(),
+        showActionButtonGroup: false
+      })
+
+      function reloadTableData() {
+        return reload()
+      }
+
+      async function setFormInstanceValue(item: PermGroupItem) {
+        modalType.value = 'update'
+        openModal()
+        await nextTick()
+        formElRef.value?.setFieldsValue({ ...item })
+      }
+      const [registerTable, { reload }] = useTable({
+        api: getPermGroupList,
+        columns: getTableColumns(reloadTableData, (item: PermGroupItem) => setFormInstanceValue(item)),
+        showTableSetting: true,
+        canResize: true,
+        bordered: true
+      })
+
+      async function showModalFn() {
+        modalType.value = 'create'
+        openModal(true)
+        await nextTick()
+        formElRef.value?.resetFields()
+      }
+
+      function modalConfirm() {
+        formElRef.value?.validate().then(async values => {
+          try {
+            if (modalType.value === 'create') {
+              await addPermGroup(toRaw(values))
+            } else {
+              await updatePermGroup(toRaw(values))
+            }
+          } catch (error) {
+            return
+          } finally {
+            await reload()
+            openModal(false)
+          }
+        })
+      }
+
+      const modalTitle = computed(() => (modalType.value === 'create' ? '新增权限组' : '编辑权限组'))
+      return { formElRef, registerModal, registerForm, registerTable, showModalFn, modalConfirm, modalTitle }
+    }
+  })
+</script>

+ 110 - 0
src/views/manager/permission/tableData.tsx

@@ -0,0 +1,110 @@
+import { BasicColumn } from '/@/components/Table/src/types/table'
+import { Popconfirm } from 'ant-design-vue'
+import { Icon } from '/@/components/Icon/index'
+import { deletePermGroup } from '/@/api/sys/manager'
+import { computed } from 'vue'
+import { FormSchema } from '/@/components/Form'
+
+enum PermMap {
+  showProject = '项目',
+  showStaff = '用户列表',
+  showPermission = '权限组'
+}
+export function getTableColumns(fn1: () => Promise<void>, fn2: (item) => void): BasicColumn[] {
+  async function delConfirm(id: string) {
+    await deletePermGroup(id)
+    await fn1()
+  }
+  return [
+    {
+      dataIndex: 'Id',
+      title: 'ID',
+      width: '5%'
+    },
+    {
+      dataIndex: 'name',
+      title: '组名称',
+      width: '15%'
+    },
+    {
+      dataIndex: 'permission',
+      title: '拥有权限',
+      customRender: ({ record }) => {
+        const text = record.permission.reduce((prev, curr) => {
+          if (prev && PermMap[curr]) {
+            prev += '、'
+          }
+          if (PermMap[curr]) {
+            prev += PermMap[curr]
+          }
+          return prev
+        }, '')
+        return <span>{text}</span>
+      }
+    },
+    {
+      dataIndex: 'createTime',
+      title: '创建时间'
+    },
+    {
+      dataIndex: 'remark',
+      title: '备注'
+    },
+    {
+      dataIndex: 'opreate',
+      title: '操作',
+      customRender: ({ record }) => (
+        <div class="text-primary divide-x">
+          <span class="cursor-pointer mr-2" onClick={() => fn2(record)}>
+            <Icon icon="ant-design:edit-filled"></Icon>
+          </span>
+          <span class="pl-2">
+            <Popconfirm title="确定删除吗?" okText="确认" cancelText="取消" onConfirm={() => delConfirm(record.id)}>
+              <Icon icon="fluent:delete-20-filled" class="cursor-pointer"></Icon>
+            </Popconfirm>
+          </span>
+        </div>
+      )
+    }
+  ]
+}
+
+export function getPermSchemas() {
+  const schemas = computed<FormSchema[]>(() => [
+    {
+      field: 'id',
+      required: false,
+      component: 'Input',
+      label: 'ID',
+      show: false
+    },
+    {
+      field: 'name',
+      component: 'Input',
+      required: true,
+      componentProps: {
+        placeholder: '输入用户组名称'
+      },
+      label: '用户组名称'
+    },
+    {
+      field: 'permission',
+      component: 'CheckboxGroup',
+      required: true,
+      label: '权限设置',
+      componentProps: {
+        options: [
+          { label: '项目', value: 'showProject' },
+          { label: '用户列表', value: 'showStaff' },
+          { label: '权限组', value: 'showPermission' }
+        ]
+      }
+    },
+    {
+      field: 'remark',
+      component: 'InputTextArea',
+      label: '备注'
+    }
+  ])
+  return schemas
+}

+ 1 - 1
src/views/manager/user/detail/index.vue

@@ -47,7 +47,7 @@
   import { RadioChangeEvent } from 'ant-design-vue/lib/radio'
   import { useMessage } from '/@/hooks/web/useMessage'
   export default defineComponent({
-    name: 'UserDetail',
+    name: 'ManagerDetail',
     components: {
       PageWrapper,
       ARadioButton: Radio.Button,

+ 1 - 1
src/views/manager/user/list/index.vue

@@ -16,7 +16,7 @@
       const go = useGo()
       const [registerTable] = useTable({
         columns: getTableColumns((id: string) => go(`/manager/detail/${id}`)),
-        canResize: false,
+        canResize: true,
         api: getManagerList
       })
       return { registerTable }

+ 61 - 0
src/views/sys/login/SessionTimeoutLogin.vue

@@ -0,0 +1,61 @@
+<template>
+  <transition>
+    <div :class="prefixCls">
+      <Login sessionTimeout />
+    </div>
+  </transition>
+</template>
+<script lang="ts">
+  import { defineComponent, onBeforeUnmount, onMounted, ref } from 'vue'
+  import Login from './Login.vue'
+
+  import { useDesign } from '/@/hooks/web/useDesign'
+  import { useUserStore } from '/@/store/modules/user'
+  import { usePermissionStore } from '/@/store/modules/permission'
+  import { useAppStore } from '/@/store/modules/app'
+  import { PermissionModeEnum } from '/@/enums/appEnum'
+  export default defineComponent({
+    name: 'SessionTimeoutLogin',
+    components: { Login },
+    setup() {
+      const { prefixCls } = useDesign('st-login')
+      const userStore = useUserStore()
+      const permissionStore = usePermissionStore()
+      const appStore = useAppStore()
+      const userId = ref<Nullable<number | string>>(0)
+
+      const isBackMode = () => {
+        return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK
+      }
+
+      onMounted(() => {
+        // 记录当前的UserId
+        userId.value = userStore.getUserInfo?.userId
+        console.log('Mounted', userStore.getUserInfo)
+      })
+
+      onBeforeUnmount(() => {
+        if (userId.value && userId.value !== userStore.getUserInfo.userId) {
+          // 登录的不是同一个用户,刷新整个页面以便丢弃之前用户的页面状态
+          document.location.reload()
+        } else if (isBackMode() && permissionStore.getLastBuildMenuTime === 0) {
+          // 后台权限模式下,没有成功加载过菜单,就重新加载整个页面。这通常发生在会话过期后按F5刷新整个页面后载入了本模块这种场景
+          document.location.reload()
+        }
+      })
+
+      return { prefixCls }
+    }
+  })
+</script>
+<style lang="less" scoped>
+  @prefix-cls: ~'@{namespace}-st-login';
+
+  .@{prefix-cls} {
+    position: fixed;
+    z-index: 9999999;
+    width: 100%;
+    height: 100%;
+    background: @component-background;
+  }
+</style>

+ 220 - 8
yarn.lock

@@ -53,6 +53,13 @@
   dependencies:
     "@babel/highlight" "^7.12.13"
 
+"@babel/code-frame@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/code-frame/download/@babel/code-frame-7.14.5.tgz?cache=0&sync_timestamp=1623280394200&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
+  integrity sha1-I7CNdA6D9JxeWZRfvxtD6Au/Tts=
+  dependencies:
+    "@babel/highlight" "^7.14.5"
+
 "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.15", "@babel/compat-data@^7.13.8":
   version "7.13.15"
   resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4"
@@ -88,6 +95,15 @@
     jsesc "^2.5.1"
     source-map "^0.5.0"
 
+"@babel/generator@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/generator/download/@babel/generator-7.14.5.tgz?cache=0&sync_timestamp=1623280360946&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.14.5.tgz#848d7b9f031caca9d0cd0af01b063f226f52d785"
+  integrity sha1-hI17nwMcrKnQzQrwGwY/Im9S14U=
+  dependencies:
+    "@babel/types" "^7.14.5"
+    jsesc "^2.5.1"
+    source-map "^0.5.0"
+
 "@babel/helper-annotate-as-pure@^7.12.13":
   version "7.12.13"
   resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab"
@@ -162,6 +178,15 @@
     "@babel/template" "^7.12.13"
     "@babel/types" "^7.12.13"
 
+"@babel/helper-function-name@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/helper-function-name/download/@babel/helper-function-name-7.14.5.tgz?cache=0&sync_timestamp=1623280385237&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-function-name%2Fdownload%2F%40babel%2Fhelper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4"
+  integrity sha1-ieLEdJcvFdjiM7Uu6MSA4s/NUMQ=
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.14.5"
+    "@babel/template" "^7.14.5"
+    "@babel/types" "^7.14.5"
+
 "@babel/helper-get-function-arity@^7.12.13":
   version "7.12.13"
   resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583"
@@ -169,6 +194,13 @@
   dependencies:
     "@babel/types" "^7.12.13"
 
+"@babel/helper-get-function-arity@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.14.5.tgz?cache=0&sync_timestamp=1623280360950&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-get-function-arity%2Fdownload%2F%40babel%2Fhelper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815"
+  integrity sha1-Jfv6V5sJN+7h87gF7OTOOYxDGBU=
+  dependencies:
+    "@babel/types" "^7.14.5"
+
 "@babel/helper-hoist-variables@^7.13.0":
   version "7.13.0"
   resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz#5d5882e855b5c5eda91e0cadc26c6e7a2c8593d8"
@@ -177,6 +209,13 @@
     "@babel/traverse" "^7.13.0"
     "@babel/types" "^7.13.0"
 
+"@babel/helper-hoist-variables@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/helper-hoist-variables/download/@babel/helper-hoist-variables-7.14.5.tgz?cache=0&sync_timestamp=1623280361512&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-hoist-variables%2Fdownload%2F%40babel%2Fhelper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d"
+  integrity sha1-4N0nwzp45XfXyIhJFqPn7x98f40=
+  dependencies:
+    "@babel/types" "^7.14.5"
+
 "@babel/helper-member-expression-to-functions@^7.13.0", "@babel/helper-member-expression-to-functions@^7.13.12":
   version "7.13.12"
   resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72"
@@ -257,6 +296,13 @@
   dependencies:
     "@babel/types" "^7.12.13"
 
+"@babel/helper-split-export-declaration@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.14.5.tgz?cache=0&sync_timestamp=1623280365934&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-split-export-declaration%2Fdownload%2F%40babel%2Fhelper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a"
+  integrity sha1-IrI6VO9RwrdgXYUZMMGXbdC8aTo=
+  dependencies:
+    "@babel/types" "^7.14.5"
+
 "@babel/helper-validator-identifier@^7.12.11":
   version "7.12.11"
   resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
@@ -300,11 +346,25 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
+"@babel/highlight@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/highlight/download/@babel/highlight-7.14.5.tgz?cache=0&sync_timestamp=1623280393681&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhighlight%2Fdownload%2F%40babel%2Fhighlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
+  integrity sha1-aGGlLwOWZAUAH2qlNKAaJNmejNk=
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.14.5"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
 "@babel/parser@^7.12.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.15", "@babel/parser@^7.13.9":
   version "7.13.15"
   resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.13.15.tgz#8e66775fb523599acb6a289e12929fa5ab0954d8"
   integrity sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==
 
+"@babel/parser@^7.14.5", "@babel/parser@^7.7.0":
+  version "7.14.6"
+  resolved "https://registry.nlark.com/@babel/parser/download/@babel/parser-7.14.6.tgz#d85cc68ca3cac84eae384c06f032921f5227f4b2"
+  integrity sha1-2FzGjKPKyE6uOEwG8DKSH1In9LI=
+
 "@babel/parser@^7.6.0", "@babel/parser@^7.9.6":
   version "7.14.5"
   resolved "https://registry.nlark.com/@babel/parser/download/@babel/parser-7.14.5.tgz#4cd2f346261061b2518873ffecdf1612cb032829"
@@ -897,6 +957,15 @@
     "@babel/parser" "^7.12.13"
     "@babel/types" "^7.12.13"
 
+"@babel/template@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/template/download/@babel/template-7.14.5.tgz?cache=0&sync_timestamp=1623280386138&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftemplate%2Fdownload%2F%40babel%2Ftemplate-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
+  integrity sha1-qbydizM1T/blWpxg0RCSAKaJdPQ=
+  dependencies:
+    "@babel/code-frame" "^7.14.5"
+    "@babel/parser" "^7.14.5"
+    "@babel/types" "^7.14.5"
+
 "@babel/traverse@^7.0.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.15":
   version "7.13.15"
   resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.15.tgz#c38bf7679334ddd4028e8e1f7b3aa5019f0dada7"
@@ -911,6 +980,21 @@
     debug "^4.1.0"
     globals "^11.1.0"
 
+"@babel/traverse@^7.7.0":
+  version "7.14.5"
+  resolved "https://registry.nlark.com/@babel/traverse/download/@babel/traverse-7.14.5.tgz#c111b0f58afab4fea3d3385a406f692748c59870"
+  integrity sha1-wRGw9Yr6tP6j0zhaQG9pJ0jFmHA=
+  dependencies:
+    "@babel/code-frame" "^7.14.5"
+    "@babel/generator" "^7.14.5"
+    "@babel/helper-function-name" "^7.14.5"
+    "@babel/helper-hoist-variables" "^7.14.5"
+    "@babel/helper-split-export-declaration" "^7.14.5"
+    "@babel/parser" "^7.14.5"
+    "@babel/types" "^7.14.5"
+    debug "^4.1.0"
+    globals "^11.1.0"
+
 "@babel/types@^7.0.0", "@babel/types@^7.12.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14", "@babel/types@^7.4.4":
   version "7.13.14"
   resolved "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d"
@@ -920,7 +1004,7 @@
     lodash "^4.17.19"
     to-fast-properties "^2.0.0"
 
-"@babel/types@^7.6.1", "@babel/types@^7.9.6":
+"@babel/types@^7.14.5", "@babel/types@^7.6.1", "@babel/types@^7.7.0", "@babel/types@^7.9.6":
   version "7.14.5"
   resolved "https://registry.nlark.com/@babel/types/download/@babel/types-7.14.5.tgz?cache=0&sync_timestamp=1623280355970&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff"
   integrity sha1-O7mXuoKaIQTO2yBonEpbgSHTg/8=
@@ -1105,6 +1189,11 @@
   resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz#c3c5ae543c897caa9c2a68630bed355be5f9990f"
   integrity sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ==
 
+"@ember-data/rfc395-data@^0.0.4":
+  version "0.0.4"
+  resolved "https://registry.npm.taobao.org/@ember-data/rfc395-data/download/@ember-data/rfc395-data-0.0.4.tgz#ecb86efdf5d7733a76ff14ea651a1b0ed1f8a843"
+  integrity sha1-7Lhu/fXXczp2/xTqZRobDtH4qEM=
+
 "@emmetio/abbreviation@^2.2.2":
   version "2.2.2"
   resolved "https://registry.nlark.com/@emmetio/abbreviation/download/@emmetio/abbreviation-2.2.2.tgz#746762fd9e7a8c2ea604f580c62e3cfe250e6989"
@@ -2414,6 +2503,18 @@ axios@^0.21.1:
   dependencies:
     follow-redirects "^1.10.0"
 
+babel-eslint@10.1.0:
+  version "10.1.0"
+  resolved "https://registry.nlark.com/babel-eslint/download/babel-eslint-10.1.0.tgz?cache=0&sync_timestamp=1618846971799&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbabel-eslint%2Fdownload%2Fbabel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
+  integrity sha1-aWjlaKkQt4+zd5zdi2rC9HmUMjI=
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    "@babel/parser" "^7.7.0"
+    "@babel/traverse" "^7.7.0"
+    "@babel/types" "^7.7.0"
+    eslint-visitor-keys "^1.0.0"
+    resolve "^1.12.0"
+
 babel-plugin-dynamic-import-node@^2.3.3:
   version "2.3.3"
   resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
@@ -4093,6 +4194,11 @@ electron-to-chromium@^1.3.723:
   resolved "https://registry.nlark.com/electron-to-chromium/download/electron-to-chromium-1.3.752.tgz?cache=0&sync_timestamp=1623290610685&other_urls=https%3A%2F%2Fregistry.nlark.com%2Felectron-to-chromium%2Fdownload%2Felectron-to-chromium-1.3.752.tgz#0728587f1b9b970ec9ffad932496429aef750d09"
   integrity sha1-ByhYfxublw7J/62TJJZCmu91DQk=
 
+ember-rfc176-data@^0.3.12:
+  version "0.3.17"
+  resolved "https://registry.npm.taobao.org/ember-rfc176-data/download/ember-rfc176-data-0.3.17.tgz#d4fc6c33abd6ef7b3440c107a28e04417b49860a"
+  integrity sha1-1PxsM6vW73s0QMEHoo4EQXtJhgo=
+
 emmet@^2.3.0:
   version "2.3.4"
   resolved "https://registry.nlark.com/emmet/download/emmet-2.3.4.tgz#5ba0d7a5569a68c7697dfa890c772e4f3179d123"
@@ -4277,6 +4383,69 @@ eslint-define-config@^1.0.8:
   resolved "https://registry.npmjs.org/eslint-define-config/-/eslint-define-config-1.0.8.tgz#56cb61f1bcba8ec7a29beec58a85d2ce9299297a"
   integrity sha512-Vfjv/3l112BQ0s+Ua+WGNxtEyxj++IaFCiBkhjT1wlBWtbHpuZcI0t8eCnJZnJrdv0b9n2GK0mcmQsPRRjVCXg==
 
+eslint-plugin-ember@7.11.0:
+  version "7.11.0"
+  resolved "https://registry.nlark.com/eslint-plugin-ember/download/eslint-plugin-ember-7.11.0.tgz#b770b0c68a18bbba4b66d32921750af143a4abf9"
+  integrity sha1-t3CwxooYu7pLZtMpIXUK8UOkq/k=
+  dependencies:
+    "@ember-data/rfc395-data" "^0.0.4"
+    ember-rfc176-data "^0.3.12"
+    snake-case "^3.0.3"
+
+eslint-plugin-es@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.npm.taobao.org/eslint-plugin-es/download/eslint-plugin-es-3.0.1.tgz?cache=0&sync_timestamp=1605772184308&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Feslint-plugin-es%2Fdownload%2Feslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893"
+  integrity sha1-dafN/czdwFiZNK7rOEF18iHFeJM=
+  dependencies:
+    eslint-utils "^2.0.0"
+    regexpp "^3.0.0"
+
+eslint-plugin-html@^6.1.2:
+  version "6.1.2"
+  resolved "https://registry.npm.taobao.org/eslint-plugin-html/download/eslint-plugin-html-6.1.2.tgz#fa26e4804428956c80e963b6499c192061c2daf3"
+  integrity sha1-+ibkgEQolWyA6WO2SZwZIGHC2vM=
+  dependencies:
+    htmlparser2 "^6.0.1"
+
+eslint-plugin-javascript@^1.3.4:
+  version "1.3.4"
+  resolved "https://registry.npm.taobao.org/eslint-plugin-javascript/download/eslint-plugin-javascript-1.3.4.tgz#4c133cd2093f41dbc2f54f584077e1dfe67262dc"
+  integrity sha1-TBM80gk/QdvC9U9YQHfh3+ZyYtw=
+  dependencies:
+    babel-eslint "10.1.0"
+    eslint-plugin-ember "7.11.0"
+    eslint-plugin-json "2.1.1"
+    eslint-plugin-node "11.0.0"
+
+eslint-plugin-json@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.nlark.com/eslint-plugin-json/download/eslint-plugin-json-2.1.1.tgz#7b9c4da2121f6f48d44efceb9a99ac0d4d12b299"
+  integrity sha1-e5xNohIfb0jUTvzrmpmsDU0Sspk=
+  dependencies:
+    lodash "^4.17.15"
+    vscode-json-languageservice "^3.5.1"
+
+eslint-plugin-jsx@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.npm.taobao.org/eslint-plugin-jsx/download/eslint-plugin-jsx-0.1.0.tgz#6d0dc2a519d7102b17a9774a231b3548077f2a52"
+  integrity sha1-bQ3CpRnXECsXqXdKIxs1SAd/KlI=
+  dependencies:
+    eslint-plugin-react "3.4.2"
+    html-tags "1"
+    svg-tags "1"
+
+eslint-plugin-node@11.0.0:
+  version "11.0.0"
+  resolved "https://registry.nlark.com/eslint-plugin-node/download/eslint-plugin-node-11.0.0.tgz#365944bb0804c5d1d501182a9bc41a0ffefed726"
+  integrity sha1-NllEuwgExdHVARgqm8QaD/7+1yY=
+  dependencies:
+    eslint-plugin-es "^3.0.0"
+    eslint-utils "^2.0.0"
+    ignore "^5.1.1"
+    minimatch "^3.0.4"
+    resolve "^1.10.1"
+    semver "^6.1.0"
+
 eslint-plugin-prettier@^3.4.0:
   version "3.4.0"
   resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7"
@@ -4284,6 +4453,18 @@ eslint-plugin-prettier@^3.4.0:
   dependencies:
     prettier-linter-helpers "^1.0.0"
 
+eslint-plugin-react@3.4.2:
+  version "3.4.2"
+  resolved "https://registry.nlark.com/eslint-plugin-react/download/eslint-plugin-react-3.4.2.tgz?cache=0&sync_timestamp=1622319784610&other_urls=https%3A%2F%2Fregistry.nlark.com%2Feslint-plugin-react%2Fdownload%2Feslint-plugin-react-3.4.2.tgz#9e6ef8a8054f8ac3b87b97236e7b849e5835dc6c"
+  integrity sha1-nm74qAVPisO4e5cjbnuEnlg13Gw=
+
+eslint-plugin-typescript@^0.14.0:
+  version "0.14.0"
+  resolved "https://registry.npm.taobao.org/eslint-plugin-typescript/download/eslint-plugin-typescript-0.14.0.tgz#068549c3f4c7f3f85d88d398c29fa96bf500884c"
+  integrity sha1-BoVJw/TH8/hdiNOYwp+pa/UAiEw=
+  dependencies:
+    requireindex "~1.1.0"
+
 eslint-plugin-vue@^7.10.0:
   version "7.11.0"
   resolved "https://registry.nlark.com/eslint-plugin-vue/download/eslint-plugin-vue-7.11.0.tgz#c19b098899b7e3cd692beffbbe73611064ef1ea6"
@@ -4302,7 +4483,7 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1:
     esrecurse "^4.3.0"
     estraverse "^4.1.1"
 
-eslint-utils@^2.1.0:
+eslint-utils@^2.0.0, eslint-utils@^2.1.0:
   version "2.1.0"
   resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
   integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
@@ -4316,7 +4497,7 @@ eslint-utils@^3.0.0:
   dependencies:
     eslint-visitor-keys "^2.0.0"
 
-eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
+eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
   version "1.3.0"
   resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
   integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
@@ -5524,6 +5705,11 @@ html-minifier-terser@^5.1.1:
     relateurl "^0.2.7"
     terser "^4.6.3"
 
+html-tags@1:
+  version "1.2.0"
+  resolved "https://registry.npm.taobao.org/html-tags/download/html-tags-1.2.0.tgz#c78de65b5663aa597989dd2b7ab49200d7e4db98"
+  integrity sha1-x43mW1Zjqll5id0rerSSANfk25g=
+
 html-tags@^3.1.0:
   version "3.1.0"
   resolved "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140"
@@ -5551,7 +5737,7 @@ htmlparser2@^3.10.0, htmlparser2@^3.8.3:
     inherits "^2.0.1"
     readable-stream "^3.1.1"
 
-htmlparser2@^6.1.0:
+htmlparser2@^6.0.1, htmlparser2@^6.1.0:
   version "6.1.0"
   resolved "https://registry.npm.taobao.org/htmlparser2/download/htmlparser2-6.1.0.tgz?cache=0&sync_timestamp=1617914918585&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
   integrity sha1-xNditsM3GgXb5l6UrkOp+EX7j7c=
@@ -8599,6 +8785,11 @@ regex-not@^1.0.0, regex-not@^1.0.2:
     extend-shallow "^3.0.2"
     safe-regex "^1.1.0"
 
+regexpp@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.nlark.com/regexpp/download/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
+  integrity sha1-BCWido2PI7rXDKS5BGH6LxIT4bI=
+
 regexpp@^3.1.0:
   version "3.1.0"
   resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
@@ -8730,6 +8921,11 @@ require-main-filename@^2.0.0:
   resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
   integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
 
+requireindex@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.npm.taobao.org/requireindex/download/requireindex-1.1.0.tgz#e5404b81557ef75db6e49c5a72004893fe03e162"
+  integrity sha1-5UBLgVV+91225JxacgBIk/4D4WI=
+
 requires-port@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
@@ -8770,7 +8966,7 @@ resolve-url@^0.2.1:
   resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
   integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
 
-resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.19.0, resolve@^1.20.0:
+resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.19.0, resolve@^1.20.0:
   version "1.20.0"
   resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
   integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
@@ -8966,7 +9162,7 @@ semver@7.3.5, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5:
   dependencies:
     lru-cache "^6.0.0"
 
-semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
+semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
   version "6.3.0"
   resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
   integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
@@ -9082,7 +9278,7 @@ slice-ansi@^4.0.0:
     astral-regex "^2.0.0"
     is-fullwidth-code-point "^3.0.0"
 
-snake-case@^3.0.4:
+snake-case@^3.0.3, snake-case@^3.0.4:
   version "3.0.4"
   resolved "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
   integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
@@ -9634,7 +9830,7 @@ svg-baker@1.7.0:
     query-string "^4.3.2"
     traverse "^0.6.6"
 
-svg-tags@^1.0.0:
+svg-tags@1, svg-tags@^1.0.0:
   version "1.0.0"
   resolved "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
   integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=
@@ -10657,6 +10853,17 @@ vscode-html-languageservice@^4.0.4:
     vscode-nls "^5.0.0"
     vscode-uri "^3.0.2"
 
+vscode-json-languageservice@^3.5.1:
+  version "3.11.0"
+  resolved "https://registry.nlark.com/vscode-json-languageservice/download/vscode-json-languageservice-3.11.0.tgz#ad574b36c4346bd7830f1d34b5a5213d3af8d232"
+  integrity sha1-rVdLNsQ0a9eDDx00taUhPTr40jI=
+  dependencies:
+    jsonc-parser "^3.0.0"
+    vscode-languageserver-textdocument "^1.0.1"
+    vscode-languageserver-types "3.16.0-next.2"
+    vscode-nls "^5.0.0"
+    vscode-uri "^2.1.2"
+
 vscode-json-languageservice@^4.1.4:
   version "4.1.4"
   resolved "https://registry.nlark.com/vscode-json-languageservice/download/vscode-json-languageservice-4.1.4.tgz#c83d3d812f8f17ab525724c611d8ff5e8834fc84"
@@ -10687,6 +10894,11 @@ vscode-languageserver-textdocument@^1.0.1:
   resolved "https://registry.npm.taobao.org/vscode-languageserver-textdocument/download/vscode-languageserver-textdocument-1.0.1.tgz#178168e87efad6171b372add1dea34f53e5d330f"
   integrity sha1-F4Fo6H761hcbNyrdHeo09T5dMw8=
 
+vscode-languageserver-types@3.16.0-next.2:
+  version "3.16.0-next.2"
+  resolved "https://registry.npm.taobao.org/vscode-languageserver-types/download/vscode-languageserver-types-3.16.0-next.2.tgz#940bd15c992295a65eae8ab6b8568a1e8daa3083"
+  integrity sha1-lAvRXJkilaZeroq2uFaKHo2qMIM=
+
 vscode-languageserver-types@3.17.0-next.1:
   version "3.17.0-next.1"
   resolved "https://registry.npm.taobao.org/vscode-languageserver-types/download/vscode-languageserver-types-3.17.0-next.1.tgz#396348493ccf567f0c22538033ebf95da5c5e4e3"