Parcourir la source

release: update 2.9.0

xiaoxian521 il y a 3 ans
Parent
commit
fd4cad8d4c
50 fichiers modifiés avec 687 ajouts et 831 suppressions
  1. 11 0
      CHANGELOG.en_US.md
  2. 11 0
      CHANGELOG.md
  3. 11 0
      CHANGELOG.zh_CN.md
  4. 1 1
      LICENSE
  5. 121 0
      build/plugins.ts
  6. 0 1
      index.html
  7. 2 10
      mock/asyncRoutes.ts
  8. 16 16
      package.json
  9. 256 245
      pnpm-lock.yaml
  10. 0 18
      public/iconfont.css
  11. 1 1
      public/serverConfig.json
  12. 4 145
      src/components/ReIcon/index.ts
  13. 0 97
      src/components/ReIcon/src/Icon.vue
  14. 39 0
      src/components/ReIcon/src/hooks.ts
  15. 48 0
      src/components/ReIcon/src/iconfont.ts
  16. 24 3
      src/components/ReIcon/src/iconifyIconOffline.ts
  17. 5 3
      src/components/ReIcon/src/iconifyIconOnline.ts
  18. 4 2
      src/layout/components/navbar.vue
  19. 3 3
      src/layout/components/notice/data.ts
  20. 3 7
      src/layout/components/screenfull/index.vue
  21. 7 3
      src/layout/components/setting/index.vue
  22. 11 6
      src/layout/components/sidebar/horizontal.vue
  23. 10 3
      src/layout/components/sidebar/logo.vue
  24. 28 10
      src/layout/components/sidebar/sidebarItem.vue
  25. 1 2
      src/layout/components/sidebar/vertical.vue
  26. 16 12
      src/layout/components/tag/index.scss
  27. 16 11
      src/layout/components/tag/index.vue
  28. 2 2
      src/layout/theme/element-plus.ts
  29. 1 2
      src/layout/types.ts
  30. 7 4
      src/main.ts
  31. 0 21
      src/plugins/fontawesome/index.ts
  32. 6 17
      src/router/modules/components.ts
  33. 0 2
      src/router/modules/editor.ts
  34. 2 5
      src/router/modules/error.ts
  35. 0 2
      src/router/modules/externalLink.ts
  36. 1 3
      src/router/modules/flowchart.ts
  37. 0 2
      src/router/modules/guide.ts
  38. 1 3
      src/router/modules/home.ts
  39. 1 3
      src/router/modules/menuTree.ts
  40. 0 8
      src/router/modules/nested.ts
  41. 1 1
      src/router/utils.ts
  42. 1 2
      src/store/modules/multiTags.ts
  43. 1 2
      src/store/modules/user.ts
  44. 2 2
      src/style/login.css
  45. 4 10
      src/style/sidebar.scss
  46. 0 21
      src/utils/algorithm/index.ts
  47. 1 2
      src/utils/storage/responsive.ts
  48. 2 2
      src/views/login.vue
  49. 1 1
      types/global.d.ts
  50. 4 115
      vite.config.ts

+ 11 - 0
CHANGELOG.en_US.md

@@ -1,3 +1,14 @@
+# 2.9.0 (2022-2-5)
+
+### 🎫 Feat
+
+- Added package size analysis, command `pnpm report`
+
+### 🍏 Perf
+
+- Use `iconify` to introduce icons on demand, optimize icon size, and reduce network requests
+- Optimize the route, the route can not pass `showLink: true`, it is displayed by default
+
 # 2.8.5 (2022-1-21)
 
 ### 🎫 Feat

+ 11 - 0
CHANGELOG.md

@@ -1,3 +1,14 @@
+# 2.9.0 (2022-2-5)
+
+### 🎫 Feat
+
+- Added package size analysis, command `pnpm report`
+
+### 🍏 Perf
+
+- Use `iconify` to introduce icons on demand, optimize icon size, and reduce network requests
+- Optimize the route, the route can not pass `showLink: true`, it is displayed by default
+
 # 2.8.5 (2022-1-21)
 
 ### 🎫 Feat

+ 11 - 0
CHANGELOG.zh_CN.md

@@ -1,3 +1,14 @@
+# 2.9.0(2022-2-5)
+
+### 🎫 Feat
+
+- 添加打包大小分析,命令`pnpm report`
+
+### 🍏 Perf
+
+- 采用`iconify`按需引入图标,优化图标大小,减少网络请求
+- 优化路由,路由可不传`showLink: true`,默认显示
+
 # 2.8.5(2022-1-21)
 
 ### 🎫 Feat

+ 1 - 1
LICENSE

@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2021 啝裳
+Copyright (c) 2022 啝裳
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 121 - 0
build/plugins.ts

@@ -0,0 +1,121 @@
+import vue from "@vitejs/plugin-vue";
+import svgLoader from "vite-svg-loader";
+import legacy from "@vitejs/plugin-legacy";
+import vueJsx from "@vitejs/plugin-vue-jsx";
+import WindiCSS from "vite-plugin-windicss";
+import { viteMockServe } from "vite-plugin-mock";
+import liveReload from "vite-plugin-live-reload";
+import styleImport from "vite-plugin-style-import";
+import ElementPlus from "unplugin-element-plus/vite";
+import { visualizer } from "rollup-plugin-visualizer";
+import removeConsole from "vite-plugin-remove-console";
+import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";
+
+export function getPluginsList(command, VITE_LEGACY) {
+  const prodMock = true;
+  const lifecycle = process.env.npm_lifecycle_event;
+  return [
+    vue(),
+    // jsx、tsx语法支持
+    vueJsx(),
+    WindiCSS(),
+    // 线上环境删除console
+    removeConsole(),
+    // 修改layout文件夹下的文件时自动重载浏览器 解决 https://github.com/xiaoxian521/vue-pure-admin/issues/170
+    liveReload(["src/layout/**/*", "src/router/**/*"]),
+    // 自定义主题
+    themePreprocessorPlugin({
+      scss: {
+        multipleScopeVars: [
+          {
+            scopeName: "layout-theme-default",
+            path: "src/layout/theme/default-vars.scss"
+          },
+          {
+            scopeName: "layout-theme-light",
+            path: "src/layout/theme/light-vars.scss"
+          },
+          {
+            scopeName: "layout-theme-dusk",
+            path: "src/layout/theme/dusk-vars.scss"
+          },
+          {
+            scopeName: "layout-theme-volcano",
+            path: "src/layout/theme/volcano-vars.scss"
+          },
+          {
+            scopeName: "layout-theme-yellow",
+            path: "src/layout/theme/yellow-vars.scss"
+          },
+          {
+            scopeName: "layout-theme-mingQing",
+            path: "src/layout/theme/mingQing-vars.scss"
+          },
+          {
+            scopeName: "layout-theme-auroraGreen",
+            path: "src/layout/theme/auroraGreen-vars.scss"
+          },
+          {
+            scopeName: "layout-theme-pink",
+            path: "src/layout/theme/pink-vars.scss"
+          },
+          {
+            scopeName: "layout-theme-saucePurple",
+            path: "src/layout/theme/saucePurple-vars.scss"
+          }
+        ],
+        // 默认取 multipleScopeVars[0].scopeName
+        defaultScopeName: "",
+        // 在生产模式是否抽取独立的主题css文件,extract为true以下属性有效
+        extract: true,
+        // 独立主题css文件的输出路径,默认取 viteConfig.build.assetsDir 相对于 (viteConfig.build.outDir)
+        outputDir: "",
+        // 会选取defaultScopeName对应的主题css文件在html添加link
+        themeLinkTagId: "head",
+        // "head"||"head-prepend" || "body" ||"body-prepend"
+        themeLinkTagInjectTo: "head",
+        // 是否对抽取的css文件内对应scopeName的权重类名移除
+        removeCssScopeName: false,
+        // 可以自定义css文件名称的函数
+        customThemeCssFileName: scopeName => scopeName
+      }
+    }),
+    // svg组件化支持
+    svgLoader(),
+    // 按需加载vxe-table
+    styleImport({
+      libs: [
+        {
+          libraryName: "vxe-table",
+          esModule: true,
+          ensureStyleFile: true,
+          resolveComponent: name => `vxe-table/es/${name}`,
+          resolveStyle: name => `vxe-table/es/${name}/style.css`
+        }
+      ]
+    }),
+    ElementPlus({}),
+    // mock支持
+    viteMockServe({
+      mockPath: "mock",
+      localEnabled: command === "serve",
+      prodEnabled: command !== "serve" && prodMock,
+      injectCode: `
+          import { setupProdMockServer } from './mockProdServer';
+          setupProdMockServer();
+        `,
+      logger: true
+    }),
+    // 是否为打包后的文件提供传统浏览器兼容性支持
+    VITE_LEGACY
+      ? legacy({
+          targets: ["ie >= 11"],
+          additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
+        })
+      : null,
+    // 打包分析
+    lifecycle === "report"
+      ? visualizer({ open: true, brotliSize: true, filename: "report.html" })
+      : null
+  ];
+}

+ 0 - 1
index.html

@@ -3,7 +3,6 @@
   <head>
     <meta charset="UTF-8" />
     <link rel="icon" href="/favicon.ico" />
-    <link rel="stylesheet" href="/iconfont.css" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>vue-pure-admin</title>
     <script src="/sortable.min.js"></script>

+ 2 - 10
mock/asyncRoutes.ts

@@ -10,7 +10,6 @@ const systemRouter = {
     icon: "setting",
     title: "menus.hssysManagement",
     i18n: true,
-    showLink: true,
     rank: 6
   },
   children: [
@@ -19,8 +18,7 @@ const systemRouter = {
       name: "user",
       meta: {
         title: "menus.hsBaseinfo",
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     },
     {
@@ -29,7 +27,6 @@ const systemRouter = {
       meta: {
         title: "menus.hsDict",
         i18n: true,
-        showLink: true,
         keepAlive: true
       }
     }
@@ -44,7 +41,6 @@ const permissionRouter = {
     title: "menus.permission",
     icon: "lollipop",
     i18n: true,
-    showLink: true,
     rank: 3
   },
   children: [
@@ -53,8 +49,7 @@ const permissionRouter = {
       name: "permissionPage",
       meta: {
         title: "menus.permissionPage",
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     },
     {
@@ -63,7 +58,6 @@ const permissionRouter = {
       meta: {
         title: "menus.permissionButton",
         i18n: true,
-        showLink: true,
         authority: []
       }
     }
@@ -78,7 +72,6 @@ const tabsRouter = {
     icon: "IF-team-icontabs",
     title: "menus.hstabs",
     i18n: true,
-    showLink: true,
     rank: 8
   },
   children: [
@@ -87,7 +80,6 @@ const tabsRouter = {
       name: "reTabs",
       meta: {
         title: "menus.hstabs",
-        showLink: true,
         i18n: true
       }
     },

+ 16 - 16
package.json

@@ -1,6 +1,6 @@
 {
   "name": "vue-pure-admin",
-  "version": "2.8.5",
+  "version": "2.9.0",
   "private": true,
   "engines": {
     "node": ">= 16",
@@ -10,6 +10,7 @@
     "dev": "cross-env --max_old_space_size=4096 vite",
     "serve": "pnpm dev",
     "build": "rimraf dist && cross-env vite build",
+    "report": "rimraf dist && cross-env vite build",
     "preview": "vite preview",
     "preview:build": "pnpm build && vite preview",
     "clean:cache": "rm -rf node_modules && rm -rf .eslintcache && pnpm install",
@@ -30,14 +31,11 @@
   "dependencies": {
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@ctrl/tinycolor": "^3.4.0",
-    "@fortawesome/fontawesome-svg-core": "^1.2.36",
-    "@fortawesome/free-solid-svg-icons": "^5.15.4",
-    "@fortawesome/vue-fontawesome": "^3.0.0-5",
     "@logicflow/core": "0.7.1",
     "@logicflow/extension": "0.7.1",
-    "@vueuse/core": "^7.5.3",
+    "@vueuse/core": "^7.5.5",
     "@vueuse/motion": "^2.0.0-beta.9",
-    "@vueuse/shared": "^7.5.3",
+    "@vueuse/shared": "^7.5.5",
     "animate.css": "^4.1.1",
     "axios": "^0.25.0",
     "cropperjs": "^1.5.11",
@@ -47,22 +45,20 @@
     "echarts": "^5.2.1",
     "element-plus": "1.3.0-beta.1",
     "element-resize-detector": "^1.2.3",
-    "font-awesome": "^4.7.0",
     "js-cookie": "^3.0.1",
     "lodash-es": "^4.17.21",
     "mitt": "^3.0.0",
     "mockjs": "^1.1.0",
     "nprogress": "^0.2.0",
     "path": "^0.12.7",
-    "pinia": "^2.0.9",
+    "pinia": "^2.0.11",
     "qs": "^6.10.1",
-    "remixicon": "^2.5.0",
     "resize-observer-polyfill": "^1.5.1",
     "responsive-storage": "^1.0.11",
     "rgb-hex": "^4.0.0",
     "v-contextmenu": "3.0.0",
-    "vue": "^3.2.27",
-    "vue-i18n": "^9.2.0-beta.26",
+    "vue": "^3.2.29",
+    "vue-i18n": "^9.2.0-beta.30",
     "vue-json-pretty": "^2.0.2",
     "vue-router": "^4.0.12",
     "vue-types": "^4.1.1",
@@ -76,7 +72,10 @@
     "@commitlint/cli": "13.1.0",
     "@commitlint/config-conventional": "13.1.0",
     "@iconify-icons/ep": "^1.1.3",
-    "@iconify/vue": "^3.1.2",
+    "@iconify-icons/fa": "^1.1.1",
+    "@iconify-icons/fa-solid": "^1.1.2",
+    "@iconify-icons/ri": "^1.1.1",
+    "@iconify/vue": "^3.1.3",
     "@types/element-resize-detector": "1.1.3",
     "@types/js-cookie": "^3.0.1",
     "@types/mockjs": "1.0.3",
@@ -86,12 +85,12 @@
     "@typescript-eslint/eslint-plugin": "4.31.0",
     "@typescript-eslint/parser": "4.31.0",
     "@vitejs/plugin-legacy": "^1.6.4",
-    "@vitejs/plugin-vue": "^2.0.1",
+    "@vitejs/plugin-vue": "^2.1.0",
     "@vitejs/plugin-vue-jsx": "^1.3.3",
     "@vue/eslint-config-prettier": "6.0.0",
     "@vue/eslint-config-typescript": "7.0.0",
     "@zougt/vite-plugin-theme-preprocessor": "^1.4.4",
-    "autoprefixer": "10.2.4",
+    "autoprefixer": "^10.4.2",
     "cross-env": "7.0.3",
     "eslint": "7.30.0",
     "eslint-plugin-prettier": "3.4.0",
@@ -103,8 +102,9 @@
     "prettier": "2.3.2",
     "pretty-quick": "3.1.1",
     "rimraf": "3.0.2",
-    "sass": "^1.45.0",
-    "sass-loader": "^12.3.0",
+    "rollup-plugin-visualizer": "^5.5.4",
+    "sass": "^1.49.7",
+    "sass-loader": "^12.4.0",
     "stylelint": "13.13.1",
     "stylelint-config-prettier": "8.0.2",
     "stylelint-config-standard": "22.0.0",

Fichier diff supprimé car celui-ci est trop grand
+ 256 - 245
pnpm-lock.yaml


+ 0 - 18
public/iconfont.css

@@ -1,18 +0,0 @@
-@font-face {
-  font-family: "iconfont"; /* project id 1098500 */
-  src: url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.eot");
-  src: url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.eot?#iefix")
-      format("embedded-opentype"),
-    url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.woff2") format("woff2"),
-    url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.woff") format("woff"),
-    url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.ttf") format("truetype"),
-    url("//at.alicdn.com/t/font_1098500_3d6un9zwltz.svg#iconfont") format("svg");
-}
-
-.iconfont {
-  font-family: "iconfont" !important;
-  font-size: 16px;
-  font-style: normal;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}

+ 1 - 1
public/serverConfig.json

@@ -1,5 +1,5 @@
 {
-  "Version": "2.8.5",
+  "Version": "2.9.0",
   "Title": "PureAdmin",
   "FixedHeader": true,
   "HiddenSideBar": false,

+ 4 - 145
src/components/ReIcon/index.ts

@@ -1,154 +1,13 @@
-import { h, App, defineComponent } from "vue";
-import icon from "./src/Icon.vue";
-import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
 import iconifyIconOffline from "./src/iconifyIconOffline";
 import iconifyIconOnline from "./src/iconifyIconOnline";
-
-/**
- * find icon component
- * @param icon icon图标
- * @returns component
- */
-export function findIconReg(icon: string) {
-  // fontawesome4
-  const fa4Reg = /^fa-/;
-  // fontawesome5+
-  const fa5Reg = /^FA-/;
-  // iconfont
-  const iFReg = /^IF-/;
-  // remixicon
-  const riReg = /^RI-/;
-  // typeof icon === "function" 属于SVG
-  if (fa5Reg.test(icon)) {
-    const text = icon.split(fa5Reg)[1];
-    return findIcon(
-      text.slice(0, text.indexOf(" ") == -1 ? text.length : text.indexOf(" ")),
-      "FA",
-      text.slice(text.indexOf(" ") + 1, text.length)
-    );
-  } else if (fa4Reg.test(icon)) {
-    return findIcon(icon.split(fa4Reg)[1], "fa");
-  } else if (iFReg.test(icon)) {
-    return findIcon(icon.split(iFReg)[1], "IF");
-  } else if (typeof icon === "function") {
-    return findIcon(icon, "SVG");
-  } else if (riReg.test(icon)) {
-    return findIcon(icon.split(riReg)[1], "RI");
-  } else {
-    return findIcon(icon, "EL");
-  }
-}
-
-// 支持fontawesome、iconfont、remixicon、element-plus/icons、自定义svg
-export function findIcon(icon: String, type = "EL", property?: string) {
-  if (type === "FA") {
-    return defineComponent({
-      name: "FaIcon",
-      data() {
-        return { icon, property };
-      },
-      components: { FontAwesomeIcon },
-      render() {
-        return h(
-          FontAwesomeIcon,
-          {
-            icon: `${this.icon}`,
-            [property]: true
-          },
-          {
-            default: () => []
-          }
-        );
-      }
-    });
-  } else if (type === "fa") {
-    return defineComponent({
-      name: "faIcon",
-      data() {
-        return { icon: `fa ${icon}` };
-      },
-      render() {
-        return h(
-          "i",
-          {
-            class: `${this.icon}`
-          },
-          {
-            default: () => []
-          }
-        );
-      }
-    });
-  } else if (type === "IF") {
-    return defineComponent({
-      name: "IfIcon",
-      data() {
-        return { icon: `iconfont ${icon}` };
-      },
-      render() {
-        return h(
-          "i",
-          {
-            class: `${this.icon}`
-          },
-          {
-            default: () => []
-          }
-        );
-      }
-    });
-  } else if (type === "RI") {
-    return defineComponent({
-      name: "RiIcon",
-      data() {
-        return { icon: `ri-${icon}` };
-      },
-      render() {
-        return h(
-          "i",
-          {
-            class: `${this.icon}`
-          },
-          {
-            default: () => []
-          }
-        );
-      }
-    });
-  } else if (type === "EL") {
-    return defineComponent({
-      name: "ElIcon",
-      data() {
-        return { icon };
-      },
-      render() {
-        return h(
-          IconifyIconOffline,
-          {
-            icon: `${this.icon}`
-          },
-          {
-            default: () => []
-          }
-        );
-      }
-    });
-  } else if (type === "SVG") {
-    return icon;
-  }
-}
-
-export const Icon = Object.assign(icon, {
-  install(app: App) {
-    app.component(icon.name, icon);
-  }
-});
+import fontIcon from "./src/iconfont";
 
 export const IconifyIconOffline = iconifyIconOffline;
 export const IconifyIconOnline = iconifyIconOnline;
+export const FontIcon = fontIcon;
 
 export default {
-  Icon,
   IconifyIconOffline,
-  IconifyIconOnline
+  IconifyIconOnline,
+  FontIcon
 };

+ 0 - 97
src/components/ReIcon/src/Icon.vue

@@ -1,97 +0,0 @@
-<script lang="ts">
-export default {
-  name: "Icon"
-};
-</script>
-
-<script setup lang="ts">
-import { ref, computed } from "vue";
-
-const props = defineProps({
-  content: {
-    type: String,
-    default: ""
-  },
-  size: {
-    type: Number,
-    default: 18
-  },
-  width: {
-    type: Number,
-    default: 20
-  },
-  height: {
-    type: Number,
-    default: 20
-  },
-  color: {
-    type: String,
-    default: ""
-  },
-  svg: {
-    type: Boolean,
-    default: false
-  }
-});
-
-const emit = defineEmits<{
-  (e: "click"): void;
-}>();
-
-let text = ref("");
-
-let className = computed(() => {
-  if (props.content.indexOf("fa-") > -1) {
-    return props.content.indexOf("fa ") === 0
-      ? props.content
-      : ["fa", props.content];
-  } else if (props.content.indexOf("el-icon-") > -1) {
-    return props.content;
-  } else if (props.content.indexOf("#") > -1) {
-    // eslint-disable-next-line vue/no-side-effects-in-computed-properties
-    text.value = props.content;
-    return "iconfont";
-  } else {
-    // eslint-disable-next-line vue/no-side-effects-in-computed-properties
-    text.value = props.content;
-    return "";
-  }
-});
-
-let iconStyle = computed(() => {
-  return (
-    "font-size: " +
-    props.size +
-    "px; color: " +
-    props.color +
-    "; width: " +
-    props.width +
-    "px; height: " +
-    props.height +
-    "px; font-style: normal;"
-  );
-});
-
-const clickHandle = () => {
-  emit("click");
-};
-</script>
-
-<template>
-  <i
-    v-if="!props.svg"
-    :class="className"
-    :style="iconStyle"
-    v-html="text"
-    @click="clickHandle"
-  ></i>
-  <svg
-    class="icon-svg"
-    v-if="props.svg"
-    aria-hidden="true"
-    :style="iconStyle"
-    @click="clickHandle"
-  >
-    <use :xlink:href="`#${props.content}`" />
-  </svg>
-</template>

+ 39 - 0
src/components/ReIcon/src/hooks.ts

@@ -0,0 +1,39 @@
+import { h, defineComponent, Component } from "vue";
+import { IconifyIconOffline, FontIcon } from "../index";
+
+// 支持fontawesome4、5+、iconfont、remixicon、element-plus的icons、自定义svg
+export function useRenderIcon(icon: string): Component {
+  // iconfont
+  const ifReg = /^IF-/;
+  // typeof icon === "function" 属于SVG
+  if (ifReg.test(icon)) {
+    // iconfont
+    const name = icon.split(ifReg)[1];
+    const iconName = name.slice(
+      0,
+      name.indexOf(" ") == -1 ? name.length : name.indexOf(" ")
+    );
+    const iconType = name.slice(name.indexOf(" ") + 1, name.length);
+    return defineComponent({
+      name: "FontIcon",
+      render() {
+        return h(FontIcon, {
+          icon: iconName,
+          iconType
+        });
+      }
+    });
+  } else if (typeof icon === "function") {
+    // svg
+    return icon;
+  } else {
+    return defineComponent({
+      name: "Icon",
+      render() {
+        return h(IconifyIconOffline, {
+          icon: icon
+        });
+      }
+    });
+  }
+}

+ 48 - 0
src/components/ReIcon/src/iconfont.ts

@@ -0,0 +1,48 @@
+import { h, defineComponent } from "vue";
+
+// 封装iconfont组件,默认`font-class`引用模式,支持`unicode`引用、`font-class`引用、`symbol`引用 (https://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.20&helptype=code)
+export default defineComponent({
+  name: "fontIcon",
+  props: {
+    icon: {
+      type: String,
+      default: ""
+    }
+  },
+  render() {
+    const attrs = this.$attrs;
+    if (Object.keys(attrs).includes("uni") || attrs?.iconType === "uni") {
+      return h(
+        "i",
+        {
+          class: "iconfont",
+          ...attrs
+        },
+        this.icon
+      );
+    } else if (
+      Object.keys(attrs).includes("svg") ||
+      attrs?.iconType === "svg"
+    ) {
+      return h(
+        "svg",
+        {
+          class: "icon-svg",
+          "aria-hidden": true
+        },
+        {
+          default: () => [
+            h("use", {
+              "xlink:href": `#${this.icon}`
+            })
+          ]
+        }
+      );
+    } else {
+      return h("i", {
+        class: `iconfont ${this.icon}`,
+        ...attrs
+      });
+    }
+  }
+});

+ 24 - 3
src/components/ReIcon/src/iconifyIconOffline.ts

@@ -1,5 +1,7 @@
 import { h, defineComponent } from "vue";
 import { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline";
+
+// element-plus icon
 import Check from "@iconify-icons/ep/check";
 import Menu from "@iconify-icons/ep/menu";
 import HomeFilled from "@iconify-icons/ep/home-filled";
@@ -45,8 +47,25 @@ addIcon("tickets", Tickets);
 addIcon("office-building", OfficeBuilding);
 addIcon("notebook", Notebook);
 
-// Iconify Icon在Vue里离线使用(用于内网环境)
-// https://docs.iconify.design/icon-components/vue/offline.html
+// remixicon
+import arrowRightSLine from "@iconify-icons/ri/arrow-right-s-line";
+import arrowLeftSLine from "@iconify-icons/ri/arrow-left-s-line";
+import logoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
+import nodeTree from "@iconify-icons/ri/node-tree";
+addIcon("arrow-right-s-line", arrowRightSLine);
+addIcon("arrow-left-s-line", arrowLeftSLine);
+addIcon("logout-circle-r-line", logoutCircleRLine);
+addIcon("node-tree", nodeTree);
+
+// Font Awesome 4
+import faUser from "@iconify-icons/fa/user";
+import faLock from "@iconify-icons/fa/lock";
+import faSignOut from "@iconify-icons/fa/sign-out";
+addIcon("fa-user", faUser);
+addIcon("fa-lock", faLock);
+addIcon("fa-sign-out", faSignOut);
+
+// Iconify Icon在Vue里离线使用(用于内网环境)https://docs.iconify.design/icon-components/vue/offline.html
 export default defineComponent({
   name: "IconifyIcon",
   components: { IconifyIcon },
@@ -57,10 +76,12 @@ export default defineComponent({
     }
   },
   render() {
+    const attrs = this.$attrs;
     return h(
       IconifyIcon,
       {
-        icon: `${this.icon}`
+        icon: `${this.icon}`,
+        ...attrs
       },
       {
         default: () => []

+ 5 - 3
src/components/ReIcon/src/iconifyIconOnline.ts

@@ -1,8 +1,7 @@
 import { h, defineComponent } from "vue";
 import { Icon as IconifyIcon } from "@iconify/vue";
 
-// Iconify Icon在Vue里在线使用(用于外网环境)
-// https://docs.iconify.design/icon-components/vue/offline.html
+// Iconify Icon在Vue里在线使用(用于外网环境) https://docs.iconify.design/icon-components/vue/offline.html
 export default defineComponent({
   name: "IconifyIcon",
   components: { IconifyIcon },
@@ -11,16 +10,19 @@ export default defineComponent({
       type: String,
       default: ""
     },
+    // default element plus icon
     type: {
       type: String,
       default: "ep:"
     }
   },
   render() {
+    const attrs = this.$attrs;
     return h(
       IconifyIcon,
       {
-        icon: `${this.type}${this.icon}`
+        icon: `${this.type}${this.icon}`,
+        ...attrs
       },
       {
         default: () => []

+ 4 - 2
src/layout/components/navbar.vue

@@ -120,8 +120,10 @@ function translationEn() {
         <template #dropdown>
           <el-dropdown-menu class="logout">
             <el-dropdown-item @click="logout">
-              <i class="ri-logout-circle-r-line"></i
-              >{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
+              <IconifyIconOffline
+                icon="logout-circle-r-line"
+                style="margin: 5px"
+              />{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
             >
           </el-dropdown-menu>
         </template>

+ 3 - 3
src/layout/components/notice/data.ts

@@ -108,7 +108,7 @@ export const noticesData: TabItem[] = [
       {
         avatar: "",
         title: "任务名称",
-        description: "任务需要在 2021-11-16 20:00 前启动",
+        description: "任务需要在 2022-11-16 20:00 前启动",
         datetime: "",
         extra: "未开始",
         status: "info",
@@ -118,7 +118,7 @@ export const noticesData: TabItem[] = [
         avatar: "",
         title: "第三方紧急代码变更",
         description:
-          "一拳提交于 2021-11-16,需在 2021-11-18 前完成代码变更任务",
+          "一拳提交于 2022-11-16,需在 2022-11-18 前完成代码变更任务",
         datetime: "",
         extra: "马上到期",
         status: "danger",
@@ -127,7 +127,7 @@ export const noticesData: TabItem[] = [
       {
         avatar: "",
         title: "信息安全考试",
-        description: "指派小仙于 2021-12-12 前完成更新并发布",
+        description: "指派小仙于 2022-12-12 前完成更新并发布",
         datetime: "",
         extra: "已耗时 8 天",
         status: "warning",

+ 3 - 7
src/layout/components/screenfull/index.vue

@@ -5,18 +5,14 @@ const { isFullscreen, toggle } = useFullscreen();
 
 <template>
   <div class="screen-full" @click="toggle">
-    <i
+    <FontIcon
       :title="
         isFullscreen
           ? $t('buttons.hsexitfullscreen')
           : $t('buttons.hsfullscreen')
       "
-      :class="
-        isFullscreen
-          ? 'iconfont team-iconexit-fullscreen'
-          : 'iconfont team-iconfullscreen'
-      "
-    ></i>
+      :icon="isFullscreen ? 'team-iconexit-fullscreen' : 'team-iconfullscreen'"
+    />
   </div>
 </template>
 

+ 7 - 3
src/layout/components/setting/index.vue

@@ -157,8 +157,7 @@ function onReset() {
       meta: {
         title: "menus.hshome",
         icon: "home-filled",
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     }
   ]);
@@ -437,7 +436,12 @@ nextTick(() => {
       style="width: 90%; margin: 24px 15px"
       @click="onReset"
     >
-      <i class="fa fa-sign-out"></i>
+      <IconifyIconOffline
+        icon="fa-sign-out"
+        width="15"
+        height="15"
+        style="margin-right: 4px"
+      />
       清空缓存并返回登录页</el-button
     >
   </panel>

+ 11 - 6
src/layout/components/sidebar/horizontal.vue

@@ -13,11 +13,9 @@ import Notice from "../notice/index.vue";
 import { templateRef } from "@vueuse/core";
 import SidebarItem from "./sidebarItem.vue";
 import avatars from "/@/assets/avatars.jpg";
-import { algorithm } from "/@/utils/algorithm";
 import screenfull from "../screenfull/index.vue";
 import { useRoute, useRouter } from "vue-router";
 import { storageSession } from "/@/utils/storage";
-import Icon from "/@/components/ReIcon/src/Icon.vue";
 import { deviceDetection } from "/@/utils/deviceDetection";
 import { usePermissionStoreHook } from "/@/store/modules/permission";
 import globalization from "/@/assets/svg/globalization.svg?component";
@@ -92,7 +90,7 @@ const menuSelect = (indexPath: string): void => {
       }
     });
   }
-  findCurrentRoute(algorithm.increaseIndexes(routers));
+  findCurrentRoute(routers);
 };
 
 function backHome() {
@@ -128,7 +126,11 @@ onMounted(() => {
 <template>
   <div class="horizontal-header">
     <div class="horizontal-header-left" @click="backHome">
-      <Icon svg :width="35" :height="35" content="team-iconlogo" />
+      <FontIcon
+        icon="team-iconlogo"
+        svg
+        style="width: 35px; height: 35px"
+      ></FontIcon>
       <h4>{{ title }}</h4>
     </div>
     <el-menu
@@ -183,8 +185,11 @@ onMounted(() => {
         <template #dropdown>
           <el-dropdown-menu class="logout">
             <el-dropdown-item @click="logout">
-              <i class="ri-logout-circle-r-line"></i
-              >{{ $t("buttons.hsLoginOut") }}</el-dropdown-item
+              <IconifyIconOffline
+                icon="logout-circle-r-line"
+                style="margin: 5px"
+              />
+              {{ $t("buttons.hsLoginOut") }}</el-dropdown-item
             >
           </el-dropdown-menu>
         </template>

+ 10 - 3
src/layout/components/sidebar/logo.vue

@@ -1,6 +1,5 @@
 <script setup lang="ts">
 import { getCurrentInstance } from "vue";
-import Icon from "/@/components/ReIcon/src/Icon.vue";
 const props = defineProps({
   collapse: Boolean
 });
@@ -19,7 +18,11 @@ const title =
         class="sidebar-logo-link"
         to="/"
       >
-        <Icon svg :width="35" :height="35" content="team-iconlogo" />
+        <FontIcon
+          icon="team-iconlogo"
+          svg
+          style="width: 35px; height: 35px"
+        ></FontIcon>
         <span class="sidebar-title">{{ title }}</span>
       </router-link>
       <router-link
@@ -29,7 +32,11 @@ const title =
         class="sidebar-logo-link"
         to="/"
       >
-        <Icon svg :width="35" :height="35" content="team-iconlogo" />
+        <FontIcon
+          icon="team-iconlogo"
+          svg
+          style="width: 35px; height: 35px"
+        ></FontIcon>
         <span class="sidebar-title">{{ title }}</span>
       </router-link>
     </transition>

+ 28 - 10
src/layout/components/sidebar/sidebarItem.vue

@@ -10,9 +10,8 @@ import {
 import path from "path";
 import { childrenType } from "../../types";
 import { transformI18n } from "/@/plugins/i18n";
-import { findIconReg } from "/@/components/ReIcon";
-import Icon from "/@/components/ReIcon/src/Icon.vue";
 import { useAppStoreHook } from "/@/store/modules/app";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 
 const instance = getCurrentInstance().appContext.app.config.globalProperties;
 const menuMode = instance.$storage.layout?.layout === "vertical";
@@ -32,6 +31,19 @@ const props = defineProps({
   }
 });
 
+const getExtraIconStyle = computed((): CSSProperties => {
+  if (useAppStoreHook().getSidebarStatus) {
+    return {
+      position: "absolute",
+      right: "10px"
+    };
+  } else {
+    return {
+      position: "static"
+    };
+  }
+});
+
 const getNoDropdownStyle = computed((): CSSProperties => {
   return {
     display: "flex",
@@ -143,7 +155,7 @@ function resolvePath(routePath) {
       <el-icon v-show="props.item.meta.icon">
         <component
           :is="
-            findIconReg(
+            useRenderIcon(
               onlyOneChild.meta.icon ||
                 (props.item.meta && props.item.meta.icon)
             )
@@ -176,11 +188,14 @@ function resolvePath(routePath) {
               }}
             </span>
           </el-tooltip>
-          <Icon
+          <FontIcon
             v-if="onlyOneChild.meta.extraIcon"
+            width="30px"
+            height="30px"
+            :style="getExtraIconStyle"
+            :icon="onlyOneChild.meta.extraIcon.name"
             :svg="onlyOneChild.meta.extraIcon.svg ? true : false"
-            :content="`${onlyOneChild.meta.extraIcon.name}`"
-          />
+          ></FontIcon>
         </div>
       </template>
     </el-menu-item>
@@ -195,7 +210,7 @@ function resolvePath(routePath) {
     <template #title>
       <el-icon v-show="props.item.meta.icon" :class="props.item.meta.icon">
         <component
-          :is="findIconReg(props.item.meta && props.item.meta.icon)"
+          :is="useRenderIcon(props.item.meta && props.item.meta.icon)"
         ></component>
       </el-icon>
       <span v-if="!menuMode">{{
@@ -220,11 +235,14 @@ function resolvePath(routePath) {
           </span>
         </div>
       </el-tooltip>
-      <Icon
+      <FontIcon
         v-if="props.item.meta.extraIcon"
+        width="30px"
+        height="30px"
+        style="position: absolute; right: 10px"
+        :icon="props.item.meta.extraIcon.name"
         :svg="props.item.meta.extraIcon.svg ? true : false"
-        :content="`${props.item.meta.extraIcon.name}`"
-      />
+      ></FontIcon>
     </template>
     <sidebar-item
       v-for="child in props.item.children"

+ 1 - 2
src/layout/components/sidebar/vertical.vue

@@ -2,7 +2,6 @@
 import Logo from "./logo.vue";
 import { emitter } from "/@/utils/mitt";
 import SidebarItem from "./sidebarItem.vue";
-import { algorithm } from "/@/utils/algorithm";
 import { storageLocal } from "/@/utils/storage";
 import { useRoute, useRouter } from "vue-router";
 import { computed, ref, onBeforeMount } from "vue";
@@ -48,7 +47,7 @@ const menuSelect = (indexPath: string): void => {
       }
     });
   }
-  findCurrentRoute(algorithm.increaseIndexes(router));
+  findCurrentRoute(router);
 };
 
 onBeforeMount(() => {

+ 16 - 12
src/layout/components/tag/index.scss

@@ -253,13 +253,23 @@
   }
 }
 
-.ri-arrow-left-s-line {
+.arrow-left,
+.arrow-right {
   width: 40px;
   height: 38px;
-  line-height: 38px;
-  text-align: center;
-  font-size: 20px;
   color: #00000073;
+  position: relative;
+
+  svg {
+    width: 20px;
+    height: 20px;
+    position: absolute;
+    left: 50%;
+    transform: translate(-50%, 50%);
+  }
+}
+
+.arrow-left {
   box-shadow: 5px 0 5px -6px #ccc;
 
   &:hover {
@@ -267,15 +277,9 @@
   }
 }
 
-.ri-arrow-right-s-line {
-  width: 40px;
-  height: 38px;
-  line-height: 38px;
-  text-align: center;
-  font-size: 20px;
-  border-right: 1px solid #ccc;
-  color: #00000073;
+.arrow-right {
   box-shadow: -5px 0 5px -6px #ccc;
+  border-right: 1px solid #ccc;
 
   &:hover {
     cursor: e-resize;

+ 16 - 11
src/layout/components/tag/index.vue

@@ -40,11 +40,11 @@ const activeIndex = ref<number>(-1);
 let refreshButton = "refresh-button";
 const instance = getCurrentInstance();
 const pureSetting = useSettingStoreHook();
-const showTags = ref(storageLocal.getItem("tagsVal") || false);
 const tabDom = templateRef<HTMLElement | null>("tabDom", null);
 const containerDom = templateRef<HTMLElement | null>("containerDom", null);
 const scrollbarDom = templateRef<HTMLElement | null>("scrollbarDom", null);
-
+const showTags =
+  ref(storageLocal.getItem("responsive-configure").hideTabs) ?? "false";
 let multiTags: ComputedRef<Array<RouteConfigs>> = computed(() => {
   return useMultiTagsStoreHook()?.multiTags;
 });
@@ -129,14 +129,14 @@ const moveToView = (index: number): void => {
     return;
   }
   const tabItemEl = instance.refs["dynamic" + index][0];
-  const tabItemElOffsetLeft = (tabItemEl as HTMLElement).offsetLeft;
-  const tabItemOffsetWidth = (tabItemEl as HTMLElement).offsetWidth;
+  const tabItemElOffsetLeft = (tabItemEl as HTMLElement)?.offsetLeft;
+  const tabItemOffsetWidth = (tabItemEl as HTMLElement)?.offsetWidth;
   // 标签页导航栏可视长度(不包含溢出部分)
   const scrollbarDomWidth = scrollbarDom.value
-    ? scrollbarDom.value.offsetWidth
+    ? scrollbarDom.value?.offsetWidth
     : 0;
   // 已有标签页总长度(包含溢出部分)
-  const tabDomWidth = tabDom.value ? tabDom.value.offsetWidth : 0;
+  const tabDomWidth = tabDom.value ? tabDom.value?.offsetWidth : 0;
 
   if (tabDomWidth < scrollbarDomWidth || tabItemElOffsetLeft === 0) {
     translateX.value = 0;
@@ -314,8 +314,7 @@ function deleteDynamicTag(obj: any, current: any, tag?: string) {
           meta: {
             title: "menus.hshome",
             i18n: true,
-            icon: "el-icon-s-home",
-            showLink: true
+            icon: "home-filled"
           }
         },
         obj
@@ -470,7 +469,6 @@ function showMenuModel(
    * currentIndex为1时,左侧的菜单是首页,则不显示关闭左侧标签页
    * 如果currentIndex等于routeLength-1,右侧没有菜单,则不显示关闭右侧标签页
    */
-
   if (currentIndex === 1 && routeLength !== 2) {
     // 左侧的菜单是首页,右侧存在别的菜单
     tagsViews[2].show = false;
@@ -631,7 +629,9 @@ const getContextMenuStyle = computed((): CSSProperties => {
 
 <template>
   <div ref="containerDom" class="tags-view" v-if="!showTags">
-    <i class="ri-arrow-left-s-line" @click="handleScroll(200)"></i>
+    <div class="arrow-left">
+      <IconifyIconOffline icon="arrow-left-s-line" @click="handleScroll(200)" />
+    </div>
     <div ref="scrollbarDom" class="scroll-container">
       <div class="tab" ref="tabDom" :style="getTabStyle">
         <div
@@ -671,7 +671,12 @@ const getContextMenuStyle = computed((): CSSProperties => {
         </div>
       </div>
     </div>
-    <i class="ri-arrow-right-s-line" @click="handleScroll(-200)"></i>
+    <span class="arrow-right">
+      <IconifyIconOffline
+        icon="arrow-right-s-line"
+        @click="handleScroll(-200)"
+      />
+    </span>
     <!-- 右键菜单按钮 -->
     <transition name="el-zoom-in-top">
       <ul

+ 2 - 2
src/layout/theme/element-plus.ts

@@ -1,6 +1,6 @@
 /* 动态改变element-plus主题色 */
 import rgbHex from "rgb-hex";
-import color from "css-color-function";
+import { convert } from "css-color-function";
 import { TinyColor } from "@ctrl/tinycolor";
 import epCss from "element-plus/dist/index.css";
 
@@ -48,7 +48,7 @@ export const createColors = (primary: string) => {
   };
   Object.keys(formula).forEach(key => {
     const value = formula[key].replace(/primary/, primary);
-    colors[key] = "#" + rgbHex(color.convert(value));
+    colors[key] = "#" + rgbHex(convert(value));
   });
   return colors;
 };

+ 1 - 2
src/layout/types.ts

@@ -6,8 +6,7 @@ export const routerArrays: Array<RouteConfigs> = [
     meta: {
       title: "menus.hshome",
       i18n: true,
-      icon: "home-filled",
-      showLink: true
+      icon: "home-filled"
     }
   }
 ];

+ 7 - 4
src/main.ts

@@ -6,7 +6,6 @@ import { createApp, Directive } from "vue";
 import { usI18n } from "../src/plugins/i18n";
 import { MotionPlugin } from "@vueuse/motion";
 import { useTable } from "../src/plugins/vxe-table";
-import { useFontawesome } from "../src/plugins/fontawesome";
 import { useElementPlus } from "../src/plugins/element-plus";
 import { injectResponsiveStorage } from "/@/utils/storage/responsive";
 
@@ -28,9 +27,14 @@ Object.keys(directives).forEach(key => {
 });
 
 // 全局注册`@iconify/vue`图标库
-import { IconifyIconOffline, IconifyIconOnline } from "./components/ReIcon";
+import {
+  IconifyIconOffline,
+  IconifyIconOnline,
+  FontIcon
+} from "./components/ReIcon";
 app.component("IconifyIconOffline", IconifyIconOffline);
 app.component("IconifyIconOnline", IconifyIconOnline);
+app.component("FontIcon", FontIcon);
 
 getServerConfig(app).then(async config => {
   injectResponsiveStorage(app, config);
@@ -40,8 +44,7 @@ getServerConfig(app).then(async config => {
     .use(MotionPlugin)
     .use(useElementPlus)
     .use(useTable)
-    .use(usI18n)
-    .use(useFontawesome);
+    .use(usI18n);
   await router.isReady();
   app.mount("#app");
 });

+ 0 - 21
src/plugins/fontawesome/index.ts

@@ -1,21 +0,0 @@
-/** 兼容fontawesome4和5版本
- * 4版本: www.fontawesome.com.cn/faicons/
- * 5版本:https://fontawesome.com/v5.15/icons?d=gallery&p=2&m=free
- * https://github.com/FortAwesome/vue-fontawesome
- */
-import { App } from "vue";
-import "font-awesome/css/font-awesome.css";
-import { library } from "@fortawesome/fontawesome-svg-core";
-import {
-  faUserSecret,
-  faCoffee,
-  faSpinner
-} from "@fortawesome/free-solid-svg-icons";
-import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
-// github.com/Remix-Design/RemixIcon/blob/master/README_CN.md#%E5%AE%89%E8%A3%85%E5%BC%95%E5%85%A5
-import "remixicon/fonts/remixicon.css";
-
-export function useFontawesome(app: App) {
-  library.add(faUserSecret, faCoffee, faSpinner);
-  app.component("font-awesome-icon", FontAwesomeIcon);
-}

+ 6 - 17
src/router/modules/components.ts

@@ -10,7 +10,6 @@ const componentsRouter = {
     icon: "menu",
     title: $t("menus.hscomponents"),
     i18n: true,
-    showLink: true,
     rank: 4
   },
   children: [
@@ -20,7 +19,6 @@ const componentsRouter = {
       component: () => import("/@/views/components/video/index.vue"),
       meta: {
         title: $t("menus.hsvideo"),
-        showLink: true,
         i18n: true
       }
     },
@@ -30,7 +28,6 @@ const componentsRouter = {
       component: () => import("/@/views/components/map/index.vue"),
       meta: {
         title: $t("menus.hsmap"),
-        showLink: true,
         keepAlive: true,
         i18n: true,
         transition: {
@@ -44,7 +41,6 @@ const componentsRouter = {
       component: () => import("/@/views/components/draggable/index.vue"),
       meta: {
         title: $t("menus.hsdraggable"),
-        showLink: true,
         i18n: true,
         transition: {
           enterTransition: "animate__zoomIn",
@@ -59,7 +55,6 @@ const componentsRouter = {
       component: () => import("/@/views/components/split-pane/index.vue"),
       meta: {
         title: $t("menus.hssplitPane"),
-        showLink: true,
         i18n: true,
         extraIcon: {
           svg: true,
@@ -73,8 +68,7 @@ const componentsRouter = {
       component: () => import("/@/views/components/button/index.vue"),
       meta: {
         title: $t("menus.hsbutton"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     },
     {
@@ -83,8 +77,7 @@ const componentsRouter = {
       component: () => import("/@/views/components/cropping/index.vue"),
       meta: {
         title: $t("menus.hscropping"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     },
     {
@@ -93,8 +86,7 @@ const componentsRouter = {
       component: () => import("/@/views/components/count-to/index.vue"),
       meta: {
         title: $t("menus.hscountTo"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     },
     {
@@ -103,8 +95,7 @@ const componentsRouter = {
       component: () => import("/@/views/components/selector/index.vue"),
       meta: {
         title: $t("menus.hsselector"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     },
     {
@@ -113,8 +104,7 @@ const componentsRouter = {
       component: () => import("/@/views/components/seamless-scroll/index.vue"),
       meta: {
         title: $t("menus.hsseamless"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     },
     {
@@ -123,8 +113,7 @@ const componentsRouter = {
       component: () => import("/@/views/components/contextmenu/index.vue"),
       meta: {
         title: $t("menus.hscontextmenu"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     }
   ]

+ 0 - 2
src/router/modules/editor.ts

@@ -10,7 +10,6 @@ const editorRouter = {
     icon: "edit",
     title: $t("menus.hseditor"),
     i18n: true,
-    showLink: true,
     rank: 2
   },
   children: [
@@ -20,7 +19,6 @@ const editorRouter = {
       component: () => import("/@/views/editor/index.vue"),
       meta: {
         title: $t("menus.hseditor"),
-        showLink: true,
         i18n: true,
         keepAlive: true,
         extraIcon: {

+ 2 - 5
src/router/modules/error.ts

@@ -9,7 +9,6 @@ const errorRouter = {
   meta: {
     icon: "position",
     title: $t("menus.hserror"),
-    showLink: true,
     i18n: true,
     rank: 7
   },
@@ -20,8 +19,7 @@ const errorRouter = {
       component: () => import("/@/views/error/401.vue"),
       meta: {
         title: $t("menus.hsfourZeroOne"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     },
     {
@@ -30,8 +28,7 @@ const errorRouter = {
       component: () => import("/@/views/error/404.vue"),
       meta: {
         title: $t("menus.hsfourZeroFour"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     }
   ]

+ 0 - 2
src/router/modules/externalLink.ts

@@ -8,7 +8,6 @@ const externalLink = {
   meta: {
     icon: "link",
     title: $t("menus.externalLink"),
-    showLink: true,
     i18n: true,
     rank: 190
   },
@@ -17,7 +16,6 @@ const externalLink = {
       path: "https://github.com/xiaoxian521/vue-pure-admin",
       meta: {
         title: $t("menus.externalLink"),
-        showLink: true,
         i18n: true,
         rank: 191
       }

+ 1 - 3
src/router/modules/flowchart.ts

@@ -9,7 +9,6 @@ const flowChartRouter = {
   meta: {
     icon: "set-up",
     title: $t("menus.hsflowChart"),
-    showLink: true,
     i18n: true,
     rank: 1
   },
@@ -20,8 +19,7 @@ const flowChartRouter = {
       component: () => import("/@/views/flow-chart/index.vue"),
       meta: {
         title: $t("menus.hsflowChart"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     }
   ]

+ 0 - 2
src/router/modules/guide.ts

@@ -10,7 +10,6 @@ const guideRouter = {
     icon: "guide",
     title: $t("menus.hsguide"),
     i18n: true,
-    showLink: true,
     rank: 10
   },
   children: [
@@ -20,7 +19,6 @@ const guideRouter = {
       component: () => import("/@/views/guide/index.vue"),
       meta: {
         title: $t("menus.hsguide"),
-        showLink: true,
         i18n: true
       }
     }

+ 1 - 3
src/router/modules/home.ts

@@ -9,7 +9,6 @@ const homeRouter = {
   meta: {
     icon: "home-filled",
     title: $t("menus.hshome"),
-    showLink: true,
     i18n: true,
     rank: 0
   },
@@ -20,8 +19,7 @@ const homeRouter = {
       component: () => import("/@/views/welcome.vue"),
       meta: {
         title: $t("menus.hshome"),
-        i18n: true,
-        showLink: true
+        i18n: true
       }
     }
   ]

+ 1 - 3
src/router/modules/menuTree.ts

@@ -7,10 +7,9 @@ const menuTreeRouter = {
   component: Layout,
   redirect: "/menuTree/index",
   meta: {
-    icon: "RI-node-tree",
+    icon: "node-tree",
     title: $t("menus.hsMenuTree"),
     i18n: true,
-    showLink: true,
     rank: 9
   },
   children: [
@@ -20,7 +19,6 @@ const menuTreeRouter = {
       component: () => import("/@/views/menu-tree/index.vue"),
       meta: {
         title: $t("menus.hsMenuTree"),
-        showLink: true,
         i18n: true
       }
     }

+ 0 - 8
src/router/modules/nested.ts

@@ -9,7 +9,6 @@ const nestedRouter = {
   meta: {
     title: $t("menus.hsmenus"),
     icon: "histogram",
-    showLink: true,
     i18n: true,
     rank: 5
   },
@@ -20,7 +19,6 @@ const nestedRouter = {
       name: "Menu1",
       meta: {
         title: $t("menus.hsmenu1"),
-        showLink: true,
         i18n: true,
         keepAlive: true
       },
@@ -32,7 +30,6 @@ const nestedRouter = {
           name: "Menu1-1",
           meta: {
             title: $t("menus.hsmenu1-1"),
-            showLink: true,
             i18n: true,
             keepAlive: true
           }
@@ -44,7 +41,6 @@ const nestedRouter = {
           redirect: "/nested/menu1/menu1-2/menu1-2-1",
           meta: {
             title: $t("menus.hsmenu1-2"),
-            showLink: true,
             i18n: true,
             keepAlive: true
           },
@@ -56,7 +52,6 @@ const nestedRouter = {
               name: "Menu1-2-1",
               meta: {
                 title: $t("menus.hsmenu1-2-1"),
-                showLink: true,
                 i18n: true,
                 keepAlive: true
               }
@@ -68,7 +63,6 @@ const nestedRouter = {
               name: "Menu1-2-2",
               meta: {
                 title: $t("menus.hsmenu1-2-2"),
-                showLink: true,
                 keepAlive: true,
                 i18n: true,
                 extraIcon: {
@@ -85,7 +79,6 @@ const nestedRouter = {
           name: "Menu1-3",
           meta: {
             title: $t("menus.hsmenu1-3"),
-            showLink: true,
             i18n: true,
             keepAlive: true
           }
@@ -98,7 +91,6 @@ const nestedRouter = {
       component: () => import("/@/views/nested/menu2/index.vue"),
       meta: {
         title: $t("menus.hsmenu2"),
-        showLink: true,
         i18n: true,
         keepAlive: true
       }

+ 1 - 1
src/router/utils.ts

@@ -30,7 +30,7 @@ function ascending(arr: any[]) {
 // 过滤meta中showLink为false的路由
 function filterTree(data: RouteComponent[]) {
   const newTree = data.filter(
-    (v: { meta: { showLink: boolean } }) => v.meta.showLink
+    (v: { meta: { showLink: boolean } }) => v.meta?.showLink !== false
   );
   newTree.forEach(
     (v: { children }) => v.children && (v.children = filterTree(v.children))

+ 1 - 2
src/store/modules/multiTags.ts

@@ -17,8 +17,7 @@ export const useMultiTagsStore = defineStore({
             meta: {
               title: "menus.hshome",
               icon: "home-filled",
-              i18n: true,
-              showLink: true
+              i18n: true
             }
           }
         ],

+ 1 - 2
src/store/modules/user.ts

@@ -60,8 +60,7 @@ export const useUserStore = defineStore({
           meta: {
             title: "menus.hshome",
             icon: "home-filled",
-            i18n: true,
-            showLink: true
+            i18n: true
           }
         }
       ]);

+ 2 - 2
src/style/login.css

@@ -85,7 +85,7 @@
   align-items: center;
 }
 
-.icon i {
+.icon svg {
   color: #d9d9d9;
   transition: 0.5s;
 }
@@ -107,7 +107,7 @@
   padding: 0;
 }
 
-.input-group.focus .icon i {
+.input-group.focus .icon svg {
   color: #5392f0;
 }
 

+ 4 - 10
src/style/sidebar.scss

@@ -306,6 +306,10 @@
       height: 48px;
       line-height: 48px;
       background: $menuBg;
+
+      svg {
+        position: static !important;
+      }
     }
 
     .is-active > .el-sub-menu__title,
@@ -600,16 +604,6 @@ body[layout="vertical"] {
       }
     }
 
-    .el-sub-menu {
-      overflow: hidden;
-
-      & > .el-sub-menu__title {
-        .el-sub-menu__icon-arrow {
-          display: none;
-        }
-      }
-    }
-
     /* 菜单折叠 */
     .el-menu--collapse {
       .el-sub-menu {

+ 0 - 21
src/utils/algorithm/index.ts

@@ -1,21 +0,0 @@
-interface ProxyAlgorithm {
-  increaseIndexes<T>(val: Array<T>): Array<T>;
-}
-
-class algorithmProxy implements ProxyAlgorithm {
-  constructor() {}
-
-  // 数组每一项添加索引字段
-  public increaseIndexes<T>(val: Array<T>): Array<T> {
-    return Object.keys(val)
-      .map(v => {
-        return {
-          ...val[v],
-          key: v
-        };
-      })
-      .filter(v => v.meta && v.meta.showLink);
-  }
-}
-
-export const algorithm = new algorithmProxy();

+ 1 - 2
src/utils/storage/responsive.ts

@@ -47,8 +47,7 @@ export const injectResponsiveStorage = (app: App, config: ServerConfigs) => {
                 meta: {
                   title: "menus.hshome",
                   i18n: true,
-                  icon: "home-filled",
-                  showLink: true
+                  icon: "home-filled"
                 }
               }
             ]

+ 2 - 2
src/views/login.vue

@@ -110,7 +110,7 @@ function onPwdBlur() {
           }"
         >
           <div class="icon">
-            <i class="fa fa-user"></i>
+            <IconifyIconOffline icon="fa-user" width="14" height="14" />
           </div>
           <div>
             <h5>用户名</h5>
@@ -139,7 +139,7 @@ function onPwdBlur() {
           }"
         >
           <div class="icon">
-            <i class="fa fa-lock"></i>
+            <IconifyIconOffline icon="fa-lock" width="14" height="14" />
           </div>
           <div>
             <h5>密码</h5>

+ 1 - 1
types/global.d.ts

@@ -11,6 +11,7 @@ declare module "vue" {
   export interface GlobalComponents {
     IconifyIconOffline: typeof import("../src/components/ReIcon")["IconifyIconOffline"];
     IconifyIconOnline: typeof import("../src/components/ReIcon")["IconifyIconOnline"];
+    FontIcon: typeof import("../src/components/ReIcon")["FontIcon"];
   }
 }
 
@@ -22,7 +23,6 @@ declare global {
     mozCancelAnimationFrame: (handle: number) => void;
     oCancelAnimationFrame: (handle: number) => void;
     msCancelAnimationFrame: (handle: number) => void;
-
     webkitRequestAnimationFrame: (callback: FrameRequestCallback) => number;
     mozRequestAnimationFrame: (callback: FrameRequestCallback) => number;
     oRequestAnimationFrame: (callback: FrameRequestCallback) => number;

+ 4 - 115
vite.config.ts

@@ -1,17 +1,7 @@
 import { resolve } from "path";
-import vue from "@vitejs/plugin-vue";
-import svgLoader from "vite-svg-loader";
-import legacy from "@vitejs/plugin-legacy";
-import vueJsx from "@vitejs/plugin-vue-jsx";
-import WindiCSS from "vite-plugin-windicss";
 import { warpperEnv, regExps } from "./build";
-import liveReload from "vite-plugin-live-reload";
-import { viteMockServe } from "vite-plugin-mock";
-import styleImport from "vite-plugin-style-import";
-import ElementPlus from "unplugin-element-plus/vite";
-import removeConsole from "vite-plugin-remove-console";
+import { getPluginsList } from "./build/plugins";
 import { UserConfigExport, ConfigEnv, loadEnv } from "vite";
-import themePreprocessorPlugin from "@zougt/vite-plugin-theme-preprocessor";
 
 // 当前执行node命令时文件夹的地址(工作目录)
 const root: string = process.cwd();
@@ -37,7 +27,6 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
     VITE_PROXY_DOMAIN,
     VITE_PROXY_DOMAIN_REAL
   } = warpperEnv(loadEnv(mode, root));
-  const prodMock = true;
   return {
     base: VITE_PUBLIC_PATH,
     root,
@@ -81,116 +70,16 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
             }
           : null
     },
-    plugins: [
-      vue(),
-      // jsx、tsx语法支持
-      vueJsx(),
-      WindiCSS(),
-      // 线上环境删除console
-      removeConsole(),
-      // 修改layout文件夹下的文件时自动重载浏览器 解决 https://github.com/xiaoxian521/vue-pure-admin/issues/170
-      liveReload(["src/layout/**/*"]),
-      // 自定义主题
-      themePreprocessorPlugin({
-        scss: {
-          multipleScopeVars: [
-            {
-              scopeName: "layout-theme-default",
-              path: pathResolve("src/layout/theme/default-vars.scss")
-            },
-            {
-              scopeName: "layout-theme-light",
-              path: pathResolve("src/layout/theme/light-vars.scss")
-            },
-            {
-              scopeName: "layout-theme-dusk",
-              path: pathResolve("src/layout/theme/dusk-vars.scss")
-            },
-            {
-              scopeName: "layout-theme-volcano",
-              path: pathResolve("src/layout/theme/volcano-vars.scss")
-            },
-            {
-              scopeName: "layout-theme-yellow",
-              path: pathResolve("src/layout/theme/yellow-vars.scss")
-            },
-            {
-              scopeName: "layout-theme-mingQing",
-              path: pathResolve("src/layout/theme/mingQing-vars.scss")
-            },
-            {
-              scopeName: "layout-theme-auroraGreen",
-              path: pathResolve("src/layout/theme/auroraGreen-vars.scss")
-            },
-            {
-              scopeName: "layout-theme-pink",
-              path: pathResolve("src/layout/theme/pink-vars.scss")
-            },
-            {
-              scopeName: "layout-theme-saucePurple",
-              path: pathResolve("src/layout/theme/saucePurple-vars.scss")
-            }
-          ],
-          // 默认取 multipleScopeVars[0].scopeName
-          defaultScopeName: "",
-          // 在生产模式是否抽取独立的主题css文件,extract为true以下属性有效
-          extract: true,
-          // 独立主题css文件的输出路径,默认取 viteConfig.build.assetsDir 相对于 (viteConfig.build.outDir)
-          outputDir: "",
-          // 会选取defaultScopeName对应的主题css文件在html添加link
-          themeLinkTagId: "head",
-          // "head"||"head-prepend" || "body" ||"body-prepend"
-          themeLinkTagInjectTo: "head",
-          // 是否对抽取的css文件内对应scopeName的权重类名移除
-          removeCssScopeName: false,
-          // 可以自定义css文件名称的函数
-          customThemeCssFileName: scopeName => scopeName
-        }
-      }),
-      // svg组件化支持
-      svgLoader(),
-      // 按需加载vxe-table
-      styleImport({
-        libs: [
-          {
-            libraryName: "vxe-table",
-            esModule: true,
-            ensureStyleFile: true,
-            resolveComponent: name => `vxe-table/es/${name}`,
-            resolveStyle: name => `vxe-table/es/${name}/style.css`
-          }
-        ]
-      }),
-      ElementPlus({}),
-      // mock支持
-      viteMockServe({
-        mockPath: "mock",
-        localEnabled: command === "serve",
-        prodEnabled: command !== "serve" && prodMock,
-        injectCode: `
-          import { setupProdMockServer } from './mockProdServer';
-          setupProdMockServer();
-        `,
-        logger: true
-      }),
-      // 是否为打包后的文件提供传统浏览器兼容性支持
-      VITE_LEGACY
-        ? legacy({
-            targets: ["ie >= 11"],
-            additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
-          })
-        : null
-    ],
+    plugins: getPluginsList(command, VITE_LEGACY),
     optimizeDeps: {
       include: [
         "pinia",
         "vue-i18n",
         "lodash-es",
         "@vueuse/core",
-        "element-plus/lib/locale/lang/zh-cn",
+        "@iconify/vue",
         "element-plus/lib/locale/lang/en",
-        "vxe-table/lib/locale/lang/zh-CN",
-        "vxe-table/lib/locale/lang/en-US"
+        "element-plus/lib/locale/lang/zh-cn"
       ],
       exclude: ["@zougt/vite-plugin-theme-preprocessor/dist/browser-utils"]
     },

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff