Ver código fonte

feat: add Multi-level menu

xiaoxian521 4 anos atrás
pai
commit
010ba1a9e1

+ 22 - 0
.vscode/vue3.0.code-snippets

@@ -0,0 +1,22 @@
+{
+  "Vue3.0快速生成模板": {
+    "prefix": "Vue3.0",
+    "body": [
+      "<template>",
+      "\t<div>\n",
+      "\t</div>",
+      "</template>\n",
+      "<script lang='ts'>",
+      "export default {",
+      "\tsetup(){",
+      "\t\treturn{\n\n\t\t}",
+      "\t},",
+      "}",
+      "</script>\n",
+      "<style scoped>\n",
+      "</style>",
+      "$2"
+    ],
+    "description": "Vue3.0"
+  }
+}

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

@@ -66,8 +66,9 @@ export default defineComponent({
       children: RouteRecordRaw[] = [],
       parent: RouteRecordRaw
     ) {
-      const showingChildren = children.filter(item => {
+      const showingChildren = children.filter((item: any) => {
         if (item.hidden) {
+          // 不显示hidden属性为true的菜单
           return false;
         } else {
           onlyOneChild.value = item;

+ 2 - 0
src/plugins/element-plus/index.ts

@@ -28,6 +28,7 @@ import {
   ElTooltip,
   ElDrawer,
   ElPagination,
+  ElAlert,
 } from "element-plus";
 
 const components = [
@@ -58,6 +59,7 @@ const components = [
   ElTooltip,
   ElDrawer,
   ElPagination,
+  ElAlert,
 ];
 
 const plugins = [ElLoading];

+ 16 - 0
src/plugins/i18n/config.ts

@@ -30,6 +30,14 @@ export const menusConfig = {
       hsflowChart: "流程图",
       hsseamless: "无缝滚动",
       hscontextmenu: "右键菜单",
+      hsmenus: "多级菜单",
+      hsmenu1: "菜单1",
+      "hsmenu1-1": "菜单1-1",
+      "hsmenu1-2": "菜单1-2",
+      "hsmenu1-2-1": "菜单1-2-1",
+      "hsmenu1-2-2": "菜单1-2-2",
+      "hsmenu1-3": "菜单1-3",
+      hsmenu2: "菜单2",
     },
   },
   en: {
@@ -54,6 +62,14 @@ export const menusConfig = {
       hsflowChart: "Flow Chart",
       hsseamless: "Seamless Scroll",
       hscontextmenu: "Context Menu",
+      hsmenus: "MultiLevel Menu",
+      hsmenu1: "Menu1",
+      "hsmenu1-1": "Menu1-1",
+      "hsmenu1-2": "Menu1-2",
+      "hsmenu1-2-1": "Menu1-2-1",
+      "hsmenu1-2-2": "Menu1-2-2",
+      "hsmenu1-3": "Menu1-3",
+      hsmenu2: "Menu2",
     },
   },
 };

+ 16 - 325
src/router/index.ts

@@ -1,335 +1,26 @@
 import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
 
-import Layout from "../layout/index.vue";
+import homeRouter from "./modules/home";
+import flowChartRouter from "./modules/flowchart";
+import editorRouter from "./modules/editor";
+import componentsRouter from "./modules/components";
+import nestedRouter from "./modules/nested";
+import systemRouter from "./modules/system";
+import errorRouter from "./modules/error";
+import remainingRouter from "./modules/remaining";
 
 import { storageSession } from "../utils/storage";
-
 import { i18n } from "/@/plugins/i18n/index";
 
 const routes: Array<RouteRecordRaw> = [
-  {
-    path: "/",
-    name: "home",
-    component: Layout,
-    redirect: "/welcome",
-    children: [
-      {
-        path: "/welcome",
-        name: "welcome",
-        component: () =>
-          import(/* webpackChunkName: "home" */ "../views/welcome.vue"),
-        meta: {
-          title: "message.hshome",
-          showLink: true,
-          savedPosition: false,
-        },
-      },
-    ],
-    meta: {
-      icon: "el-icon-s-home",
-      showLink: true,
-      savedPosition: false,
-    },
-  },
-  {
-    path: "/components",
-    name: "components",
-    component: Layout,
-    redirect: "/components/split-pane",
-    children: [
-      {
-        path: "/components/video",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/video/index.vue"
-          ),
-        meta: {
-          title: "message.hsvideo",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/map",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/map/index.vue"
-          ),
-        meta: {
-          title: "message.hsmap",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/draggable",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/draggable/index.vue"
-          ),
-        meta: {
-          title: "message.hsdraggable",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/split-pane",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/split-pane/index.vue"
-          ),
-        meta: {
-          title: "message.hssplitPane",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/button",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/button/index.vue"
-          ),
-        meta: {
-          title: "message.hsbutton",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/cropping",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/cropping/index.vue"
-          ),
-        meta: {
-          title: "message.hscropping",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/countTo",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/count-to/index.vue"
-          ),
-        meta: {
-          title: "message.hscountTo",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/selector",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/selector/index.vue"
-          ),
-        meta: {
-          title: "message.hsselector",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/seamlessScroll",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/seamless-scroll/index.vue"
-          ),
-        meta: {
-          title: "message.hsseamless",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/components/contextmenu",
-        component: () =>
-          import(
-            /* webpackChunkName: "components" */ "../views/components/contextmenu/index.vue"
-          ),
-        meta: {
-          title: "message.hscontextmenu",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-    ],
-    meta: {
-      icon: "el-icon-menu",
-      title: "message.hscomponents",
-      showLink: true,
-      savedPosition: true,
-    },
-  },
-  {
-    path: "/flowChart",
-    name: "flowChart",
-    component: Layout,
-    redirect: "/flowChart/index",
-    children: [
-      {
-        path: "/flowChart/index",
-        component: () =>
-          import(
-            /* webpackChunkName: "user" */ "../views/flow-chart/index.vue"
-          ),
-        meta: {
-          title: "message.hsflowChart",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-    ],
-    meta: {
-      icon: "el-icon-set-up",
-      title: "message.hsflowChart",
-      showLink: true,
-      savedPosition: true,
-    },
-  },
-  {
-    path: "/editor",
-    name: "editor",
-    component: Layout,
-    redirect: "/editor/index",
-    children: [
-      {
-        path: "/editor/index",
-        component: () =>
-          import(/* webpackChunkName: "user" */ "../views/editor/index.vue"),
-        meta: {
-          // icon: 'el-icon-edit-outline',
-          title: "message.hseditor",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-    ],
-    meta: {
-      icon: "el-icon-edit-outline",
-      title: "message.hseditor",
-      showLink: true,
-      savedPosition: true,
-    },
-  },
-  {
-    path: "/system",
-    name: "system",
-    component: Layout,
-    redirect: "/system/base",
-    children: [
-      {
-        path: "/system/base",
-        component: () =>
-          import(/* webpackChunkName: "system" */ "../views/system/user.vue"),
-        meta: {
-          // icon: '',
-          title: "message.hsBaseinfo",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/system/dict",
-        component: () =>
-          import(
-            /* webpackChunkName: "system" */ "../views/system/dict/index.vue"
-          ),
-        meta: {
-          // icon: '',
-          title: "message.hsDict",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-    ],
-    meta: {
-      icon: "el-icon-setting",
-      title: "message.hssysManagement",
-      showLink: true,
-      savedPosition: true,
-    },
-  },
-  {
-    path: "/error",
-    name: "error",
-    component: Layout,
-    redirect: "/error/401",
-    children: [
-      {
-        path: "/error/401",
-        component: () =>
-          import(/* webpackChunkName: "error" */ "../views/error/401.vue"),
-        meta: {
-          title: "message.hsfourZeroOne",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-      {
-        path: "/error/404",
-        component: () =>
-          import(/* webpackChunkName: "error" */ "../views/error/404.vue"),
-        meta: {
-          title: "message.hsfourZeroFour",
-          showLink: false,
-          savedPosition: true,
-        },
-      },
-    ],
-    meta: {
-      icon: "el-icon-position",
-      title: "message.hserror",
-      showLink: true,
-      savedPosition: true,
-    },
-  },
-  {
-    path: "/login",
-    name: "login",
-    component: () =>
-      import(/* webpackChunkName: "login" */ "../views/login.vue"),
-    meta: {
-      title: "message.hslogin",
-      showLink: false,
-    },
-  },
-  {
-    path: "/register",
-    name: "register",
-    component: () =>
-      import(/* webpackChunkName: "register" */ "../views/register.vue"),
-    meta: {
-      title: "message.hsregister",
-      showLink: false,
-    },
-  },
-  {
-    // 找不到路由重定向到404页面
-    path: "/:pathMatch(.*)",
-    component: Layout,
-    redirect: "/error/404",
-    meta: {
-      icon: "el-icon-s-home",
-      title: "message.hshome",
-      showLink: false,
-      savedPosition: false,
-    },
-  },
-  {
-    path: "/redirect",
-    component: Layout,
-    children: [
-      {
-        path: "/redirect/:path(.*)",
-        component: () => import("../views/redirect.vue"),
-      },
-    ],
-  },
+  homeRouter,
+  flowChartRouter,
+  editorRouter,
+  componentsRouter,
+  nestedRouter,
+  systemRouter,
+  errorRouter,
+  ...remainingRouter,
 ];
 
 const router = createRouter({

+ 108 - 0
src/router/modules/components.ts

@@ -0,0 +1,108 @@
+import Layout from "/@/layout/index.vue";
+
+const componentsRouter = {
+  path: "/components",
+  name: "components",
+  component: Layout,
+  redirect: "/components/split-pane",
+  children: [
+    {
+      path: "/components/video",
+      component: () => import("/@/views/components/video/index.vue"),
+      meta: {
+        title: "message.hsvideo",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/map",
+      component: () => import("/@/views/components/map/index.vue"),
+      meta: {
+        title: "message.hsmap",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/draggable",
+      component: () => import("/@/views/components/draggable/index.vue"),
+      meta: {
+        title: "message.hsdraggable",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/split-pane",
+      component: () => import("/@/views/components/split-pane/index.vue"),
+      meta: {
+        title: "message.hssplitPane",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/button",
+      component: () => import("/@/views/components/button/index.vue"),
+      meta: {
+        title: "message.hsbutton",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/cropping",
+      component: () => import("/@/views/components/cropping/index.vue"),
+      meta: {
+        title: "message.hscropping",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/countTo",
+      component: () => import("/@/views/components/count-to/index.vue"),
+      meta: {
+        title: "message.hscountTo",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/selector",
+      component: () => import("/@/views/components/selector/index.vue"),
+      meta: {
+        title: "message.hsselector",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/seamlessScroll",
+      component: () => import("/@/views/components/seamless-scroll/index.vue"),
+      meta: {
+        title: "message.hsseamless",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/components/contextmenu",
+      component: () => import("/@/views/components/contextmenu/index.vue"),
+      meta: {
+        title: "message.hscontextmenu",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+  ],
+  meta: {
+    icon: "el-icon-menu",
+    title: "message.hscomponents",
+    showLink: true,
+    savedPosition: true,
+  },
+};
+
+export default componentsRouter;

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

@@ -0,0 +1,27 @@
+import Layout from "/@/layout/index.vue";
+
+const editorRouter = {
+  path: "/editor",
+  name: "editor",
+  component: Layout,
+  redirect: "/editor/index",
+  children: [
+    {
+      path: "/editor/index",
+      component: () => import("/@/views/editor/index.vue"),
+      meta: {
+        title: "message.hseditor",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+  ],
+  meta: {
+    icon: "el-icon-edit-outline",
+    title: "message.hseditor",
+    showLink: true,
+    savedPosition: true,
+  },
+};
+
+export default editorRouter;

+ 36 - 0
src/router/modules/error.ts

@@ -0,0 +1,36 @@
+import Layout from "/@/layout/index.vue";
+
+const errorRouter = {
+  path: "/error",
+  name: "error",
+  component: Layout,
+  redirect: "/error/401",
+  children: [
+    {
+      path: "/error/401",
+      component: () => import("/@/views/error/401.vue"),
+      meta: {
+        title: "message.hsfourZeroOne",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/error/404",
+      component: () => import("/@/views/error/404.vue"),
+      meta: {
+        title: "message.hsfourZeroFour",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+  ],
+  meta: {
+    icon: "el-icon-position",
+    title: "message.hserror",
+    showLink: true,
+    savedPosition: true,
+  },
+};
+
+export default errorRouter;

+ 27 - 0
src/router/modules/flowchart.ts

@@ -0,0 +1,27 @@
+import Layout from "/@/layout/index.vue";
+
+const flowChartRouter = {
+  path: "/flowChart",
+  name: "flowChart",
+  component: Layout,
+  redirect: "/flowChart/index",
+  children: [
+    {
+      path: "/flowChart/index",
+      component: () => import("/@/views/flow-chart/index.vue"),
+      meta: {
+        title: "message.hsflowChart",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+  ],
+  meta: {
+    icon: "el-icon-set-up",
+    title: "message.hsflowChart",
+    showLink: true,
+    savedPosition: true,
+  },
+};
+
+export default flowChartRouter;

+ 27 - 0
src/router/modules/home.ts

@@ -0,0 +1,27 @@
+import Layout from "/@/layout/index.vue";
+
+const homeRouter = {
+  path: "/",
+  name: "home",
+  component: Layout,
+  redirect: "/welcome",
+  children: [
+    {
+      path: "/welcome",
+      name: "welcome",
+      component: () => import("/@/views/welcome.vue"),
+      meta: {
+        title: "message.hshome",
+        showLink: true,
+        savedPosition: false,
+      },
+    },
+  ],
+  meta: {
+    icon: "el-icon-s-home",
+    showLink: true,
+    savedPosition: false,
+  },
+};
+
+export default homeRouter;

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

@@ -0,0 +1,96 @@
+import Layout from "/@/layout/index.vue";
+
+const nestedRouter = {
+  path: "/nested",
+  component: Layout,
+  redirect: "/nested/menu1/menu1-1",
+  name: "Nested",
+  meta: {
+    title: "message.hsmenus",
+    icon: "el-icon-s-data",
+    showLink: true,
+    savedPosition: false,
+  },
+  children: [
+    {
+      path: "menu1",
+      component: () => import("/@/views/nested/menu1/index.vue"),
+      name: "Menu1",
+      meta: {
+        title: "message.hsmenu1",
+        showLink: true,
+        savedPosition: false,
+      },
+      redirect: "/nested/menu1/menu1-1",
+      children: [
+        {
+          path: "menu1-1",
+          component: () => import("/@/views/nested/menu1/menu1-1/index.vue"),
+          name: "Menu1-1",
+          meta: {
+            title: "message.hsmenu1-1",
+            showLink: true,
+            savedPosition: false,
+          },
+        },
+        {
+          path: "menu1-2",
+          component: () => import("/@/views/nested/menu1/menu1-2/index.vue"),
+          name: "Menu1-2",
+          redirect: "/nested/menu1/menu1-2/menu1-2-1",
+          meta: {
+            title: "message.hsmenu1-2",
+            showLink: true,
+            savedPosition: false,
+          },
+          children: [
+            {
+              path: "menu1-2-1",
+              component: () =>
+                import("/@/views/nested/menu1/menu1-2/menu1-2-1/index.vue"),
+              name: "Menu1-2-1",
+              meta: {
+                title: "message.hsmenu1-2-1",
+                showLink: true,
+                savedPosition: false,
+              },
+            },
+            {
+              path: "menu1-2-2",
+              component: () =>
+                import("/@/views/nested/menu1/menu1-2/menu1-2-2/index.vue"),
+              name: "Menu1-2-2",
+              meta: {
+                title: "message.hsmenu1-2-2",
+                showLink: true,
+                savedPosition: false,
+              },
+            },
+          ],
+        },
+        {
+          path: "menu1-3",
+          component: () => import("/@/views/nested/menu1/menu1-3/index.vue"),
+          name: "Menu1-3",
+          meta: {
+            title: "message.hsmenu1-3",
+            showLink: true,
+            savedPosition: false,
+          },
+        },
+      ],
+    },
+    {
+      path: "menu2",
+      name: "Menu2",
+      component: () => import("/@/views/nested/menu2/index.vue"),
+      meta: {
+        title: "message.hsmenu2",
+        showLink: true,
+        savedPosition: false,
+      },
+    },
+  ],
+};
+
+export default nestedRouter;

+ 46 - 0
src/router/modules/remaining.ts

@@ -0,0 +1,46 @@
+import Layout from "/@/layout/index.vue";
+
+const remainingRouter = [
+  {
+    path: "/login",
+    name: "login",
+    component: () => import("/@/views/login.vue"),
+    meta: {
+      title: "message.hslogin",
+      showLink: false,
+    },
+  },
+  {
+    path: "/register",
+    name: "register",
+    component: () => import("/@/views/register.vue"),
+    meta: {
+      title: "message.hsregister",
+      showLink: false,
+    },
+  },
+  {
+    // 找不到路由重定向到404页面
+    path: "/:pathMatch(.*)",
+    component: Layout,
+    redirect: "/error/404",
+    meta: {
+      icon: "el-icon-s-home",
+      title: "message.hshome",
+      showLink: false,
+      savedPosition: false,
+    },
+  },
+  {
+    path: "/redirect",
+    component: Layout,
+    children: [
+      {
+        path: "/redirect/:path(.*)",
+        component: () => import("/@/views/redirect.vue"),
+      },
+    ],
+  },
+];
+
+export default remainingRouter;

+ 36 - 0
src/router/modules/system.ts

@@ -0,0 +1,36 @@
+import Layout from "/@/layout/index.vue";
+
+const systemRouter = {
+  path: "/system",
+  name: "system",
+  component: Layout,
+  redirect: "/system/base",
+  children: [
+    {
+      path: "/system/base",
+      component: () => import("/@/views/system/user.vue"),
+      meta: {
+        title: "message.hsBaseinfo",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+    {
+      path: "/system/dict",
+      component: () => import("/@/views/system/dict/index.vue"),
+      meta: {
+        title: "message.hsDict",
+        showLink: false,
+        savedPosition: true,
+      },
+    },
+  ],
+  meta: {
+    icon: "el-icon-setting",
+    title: "message.hssysManagement",
+    showLink: true,
+    savedPosition: true,
+  },
+};
+
+export default systemRouter;

+ 3 - 0
src/style/sidebar.scss

@@ -173,6 +173,9 @@
           background-color: $subMenuHover;
         }
       }
+      .el-submenu__title {
+        color: $menuText;
+      }
     }
     & > .el-menu {
       i {

+ 12 - 0
src/views/nested/menu1/index.vue

@@ -0,0 +1,12 @@
+<template>
+  <div class="app-container">
+    <p>{{$t('message.hsmenu1')}}</p>
+    <router-view v-slot="{ Component }">
+      <transition>
+        <component :is="Component" />
+      </transition>
+    </router-view>
+  </div>
+</template>
+
+

+ 3 - 0
src/views/nested/menu1/menu1-1/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <p style="text-indent:2em">{{$t('message.hsmenu1-1')}}</p>
+</template>

+ 10 - 0
src/views/nested/menu1/menu1-2/index.vue

@@ -0,0 +1,10 @@
+<template>
+  <div>
+    <p style="text-indent:2em">{{$t('message.hsmenu1-2')}}</p>
+    <router-view v-slot="{ Component }">
+      <keep-alive>
+        <component :is="Component" />
+      </keep-alive>
+    </router-view>
+  </div>
+</template>

+ 3 - 0
src/views/nested/menu1/menu1-2/menu1-2-1/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <p style="text-indent:4em">{{$t('message.hsmenu1-2-1')}}</p>
+</template>

+ 3 - 0
src/views/nested/menu1/menu1-2/menu1-2-2/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <p style="text-indent:4em">{{$t('message.hsmenu1-2-2')}}</p>
+</template>

+ 3 - 0
src/views/nested/menu1/menu1-3/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <p style="text-indent:2em">{{$t('message.hsmenu1-3')}}</p>
+</template>

+ 3 - 0
src/views/nested/menu2/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <p class="app-container">{{$t('message.hsmenu2')}}</p>
+</template>