Prechádzať zdrojové kódy

feat: 边侧栏大体完成,增加一些权限路由测试页面,实现根据动态路由加载边侧栏列表(涉及权限和无需权限页面)

zhusiqing 3 rokov pred
rodič
commit
183e9879b8

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
.eslintcache


+ 8 - 0
CHANGELOG.md

@@ -1,3 +1,11 @@
+## 0.5.0(2021-12-21)
+
+### Features
+
+- 实现根据动态路由加载边侧栏列表,涉及权限和无需权限页面
+- 增加一些权限路由测试页面
+- 边侧栏大体完成
+
 ## 0.4.0(2021-12-20)
 
 ### Features

+ 0 - 2
components.d.ts

@@ -18,9 +18,7 @@ declare module 'vue' {
     ASpin: typeof import('ant-design-vue/es')['Spin']
     HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
     InitLoading: typeof import('./src/components/InitLoading.vue')['default']
-    UploadOutlined: typeof import('@ant-design/icons-vue')['UploadOutlined']
     UserOutlined: typeof import('@ant-design/icons-vue')['UserOutlined']
-    VideoCameraOutlined: typeof import('@ant-design/icons-vue')['VideoCameraOutlined']
   }
 }
 

+ 1 - 1
log.md

@@ -4,7 +4,7 @@
 - [x] 头部布局组件
 - [x] 底部布局组件
 - [x] 边侧栏布局组件
-- [ ] 权限路由设计
+- [x] 权限路由设计
 - [ ] 登录页
 - [ ] 登录态相关处理
 

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "vite-template",
-  "version": "0.4.0",
+  "version": "0.5.0",
   "scripts": {
     "dev": "vite",
     "build": "vue-tsc --noEmit && vite build",

+ 6 - 2
src/App.vue

@@ -4,14 +4,18 @@
   import { RouterView, useRouter, useRoute } from 'vue-router';
   import { AppRoute, NotFoundRoute } from '@/router/base';
   import { authRoutes } from '@/router/auth';
+  import { filterAuthHandle } from '@/router/utils'
   import { AppStore } from '@/store/modules/app';
 
   const router = useRouter()
   const route = useRoute()
   const store = AppStore()
-  // TODO: 等二级路由添加好后,再增加无需权限时的判断
+
+  // TODO: 增加无需权限时的判断
+  // 此处模拟接口请求获取权限列表
   setTimeout(() => {
-    const authFilterRoutes = authRoutes.filter(route => Number(route.meta?.auth) === 1)
+    const authFilterRoutes = filterAuthHandle([1], authRoutes)
+    console.log(authFilterRoutes);
     const childrenRoutes = [...authFilterRoutes, ...AppRoute.children as []]
     router.removeRoute(AppRoute.name as string)
     router.addRoute({

+ 27 - 10
src/layouts/app/Sider.vue

@@ -15,14 +15,29 @@
       theme="dark"
       mode="inline"
     >
-      <a-menu-item
+      <component
+        :is="menu.children?.length ? SubMenu: MenuItem"
         v-for="menu in menus"
         :key="menu.name"
-        @click="toPageHandle(menu.name)"
+        :title="menu.meta?.title || menu.name"
+        @click="menu.children?.length ? null :toPageHandle(menu.name)"
       >
-        <user-outlined />
-        <span class="nav-text">{{ menu.name }}</span>
-      </a-menu-item>
+        <template #icon>
+          <component :is="getIcon(menu.meta?.icon)" />
+        </template>
+        <template v-if="menu.children?.length">
+          <MenuItem
+            v-for="child in menu.children"
+            :key="child.name"
+            @click="toPageHandle(child.name)"
+          >
+            <span class="nav-text">{{ child.meta?.title || child.name }}</span>
+          </MenuItem>
+        </template>
+        <template v-else>
+          <span class="nav-text">{{ menu.meta?.title || menu.name }}</span>
+        </template>
+      </component>
     </a-menu>
   </a-layout-sider>
 </template>
@@ -30,7 +45,9 @@
   import { ref, computed, watch, toRef } from 'vue';
   import { useRouter, useRoute, onBeforeRouteUpdate } from 'vue-router';
   import { AppStore } from '@/store/modules/app';
-  import type { RouteRecordName, RouteLocationNormalized } from 'vue-router'
+  import type { RouteRecordName, RouteLocationNormalized, RouteMeta } from 'vue-router'
+  import { MenuItem, SubMenu } from 'ant-design-vue';
+  import * as Icon from '@ant-design/icons-vue';
 
   const router = useRouter()
   const route = useRoute()
@@ -40,14 +57,10 @@
   const matchRouteHandle = (to: RouteLocationNormalized) => {
     menus.value.forEach(el => {
       if (el.name === to.name) {
-        console.log(el, to);
         selectedKeys.value = [to.name as string]
       }
     })
   }
-  // onBeforeRouteUpdate(to => {
-  //   matchRouteHandle(to)
-  // })
   matchRouteHandle(route)
   const toHomeHandle = () => {
     router.push('/')
@@ -55,6 +68,10 @@
   const toPageHandle = (name: RouteRecordName | undefined) => {
     router.push({ name })
   }
+  const getIcon = (name: unknown) => {
+    // 这里将字符串假定为UserOutlined来通过Icon的类型校验
+    return Icon[name as 'UserOutlined'] || 'AppstoreOutlined'
+  }
 </script>
 
 <style lang="less" scoped>

+ 12 - 0
src/pages/Common/index.vue

@@ -0,0 +1,12 @@
+<template>
+  <div class="common">
+    通用页面
+  </div>
+</template>
+<script lang="ts" setup>
+  import { ref } from 'vue'
+
+</script>
+<style scoped>
+.common{}
+</style>

+ 12 - 0
src/pages/System/Role/index.vue

@@ -0,0 +1,12 @@
+<template>
+  <div class="system-role">
+    系统-角色页面
+  </div>
+</template>
+<script lang="ts" setup>
+  import { ref } from 'vue'
+
+</script>
+<style scoped>
+.system-role{}
+</style>

+ 11 - 0
src/pages/System/User/index.vue

@@ -0,0 +1,11 @@
+<template>
+  <div class="system-user">
+    系统-用户页面
+  </div>
+</template>
+<script lang="ts" setup>
+
+</script>
+<style scoped>
+.system-user{}
+</style>

+ 7 - 0
src/pages/System/index.vue

@@ -0,0 +1,7 @@
+<template>
+  <RouterView />
+</template>
+<script lang="ts" setup>
+  import { RouterView} from 'vue-router'
+</script>
+

+ 15 - 0
src/pages/Test/Test.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>{{ text }}</div>
+</template>
+<script lang="ts" setup>
+  import { ref, onUpdated } from "vue";
+  import { useRoute } from 'vue-router'
+  const route = useRoute()
+  const text = ref(route.name)
+  onUpdated(() => {
+    text.value = route.name
+  })
+</script>
+<style scoped>
+
+</style>

+ 2 - 11
src/pages/Test/index.vue

@@ -1,15 +1,6 @@
 <template>
-  <div>{{ text }}</div>
+  <RouterView />
 </template>
 <script lang="ts" setup>
-  import { ref, onUpdated } from "vue";
-  import { useRoute } from 'vue-router'
-  const route = useRoute()
-  const text = ref(route.name)
-  onUpdated(() => {
-    text.value = route.name
-  })
+import { RouterView } from 'vue-router'
 </script>
-<style scoped>
-
-</style>

+ 77 - 23
src/router/auth.ts

@@ -1,37 +1,91 @@
 import { RouteRecordRaw } from 'vue-router';
-import Test from '@/pages/Test/index.vue'
+import TestPage from '@/pages/Test/index.vue'
+import Test from '@/pages/Test/Test.vue'
+import SystemPage from '@/pages/System/index.vue';
 
 export const authRoutes: RouteRecordRaw[] = [
   {
-    path: 'test1',
-    name: 'Test1',
-    component: Test,
+    path: 'system',
+    name: 'System',
+    component: SystemPage,
+    redirect: '/app/system/user',
     meta: {
-      auth: 1
-    }
-  },
-  {
-    path: 'test2',
-    name: 'Test2',
-    component: Test,
-    meta: {
-      auth: 1
-    }
+      icon: 'SettingOutlined',
+      title: '系统设置'
+    },
+    children: [
+      {
+        path: 'user',
+        name: 'SystemUser',
+        component: () => import('@/pages/System/User/index.vue'),
+        meta: {
+          auth: 1,
+          title: '用户管理'
+        }
+      },
+      {
+        path: 'role',
+        name: 'SystemRole',
+        component: () => import('@/pages/System/Role/index.vue'),
+        meta: {
+          auth: 1,
+          title: '角色管理'
+        }
+      }
+    ]
+
   },
   {
-    path: 'test3',
-    name: 'Test3',
-    component: () => import('@/pages/Test/index.vue'),
+    path: 'common',
+    name: 'Common',
+    component: () => import('@/pages/Common/index.vue'),
     meta: {
-      auth: 1
+      icon: 'AppstoreOutlined',
+      title: '通用页面'
     }
   },
   {
-    path: 'test4',
-    name: 'Test4',
-    component: () => import('@/pages/Test/index.vue'),
+    path: 'test',
+    name: 'Test',
+    component: TestPage,
+    redirect: '/test/1',
     meta: {
-      auth: 2
-    }
+      icon: 'ApiOutlined',
+      title: '测试路由权限'
+    },
+    children: [
+      {
+        path: '1',
+        name: 'Test1',
+        component: Test,
+        meta: {
+          auth: 1
+        }
+      },
+      {
+        path: '2',
+        name: 'Test2',
+        component: () => import('@/pages/Test/Test.vue'),
+        meta: {
+          auth: 1
+        }
+      },
+      {
+        path: '3',
+        name: 'Test3',
+        component: Test,
+        meta: {
+          auth: 2
+        }
+      },
+      {
+        path: '4',
+        name: 'Test4',
+        component: () => import('@/pages/Test/Test.vue'),
+        meta: {
+          auth: 2
+        }
+      }
+    ]
   }
 ]

+ 10 - 5
src/router/base.ts

@@ -1,7 +1,12 @@
 import type { RouteRecordRaw } from 'vue-router';
 import ErrorPage from '@/pages/Error/index.vue';
 import AppLayout from '@/layouts/app/index.vue';
-import { EnumPage } from './constant';
+
+export enum EnumPage {
+  App = '/app',
+  Login = '/login',
+  Error = '/error'
+}
 export const RootRoute: RouteRecordRaw = {
   path: '/',
   name: 'Root',
@@ -24,8 +29,9 @@ export const AppRoute: RouteRecordRaw = {
     }
   ]
 }
+
 export const LoginRoute: RouteRecordRaw = {
-  path: '/login',
+  path: EnumPage.Login,
   name: 'Login',
   component: () => import('@/pages/Login/index.vue'),
   meta: {
@@ -34,7 +40,7 @@ export const LoginRoute: RouteRecordRaw = {
 }
 
 export const ErrorRoute: RouteRecordRaw = {
-  path: '/error',
+  path: EnumPage.Error,
   name: 'Error',
   component: ErrorPage,
   meta: {
@@ -52,6 +58,5 @@ export const baseRoutes: RouteRecordRaw[] = [
   RootRoute,
   AppRoute,
   LoginRoute,
-  ErrorRoute,
-  // NotFoundRoute
+  ErrorRoute
 ]

+ 0 - 5
src/router/constant.ts

@@ -1,5 +0,0 @@
-export enum EnumPage {
-  App = '/app',
-  Login = '/login',
-  Error = 'error'
-}

+ 7 - 8
src/router/index.ts

@@ -14,14 +14,13 @@ export const router = createRouter({
   })
 })
 
-router.beforeEach((to, from, next) => {
-  nProgress.start()
-  next()
-})
-
-router.afterEach(() => {
-  nProgress.done()
-})
 export const setupRouter = (app: App) => {
   app.use(router)
+  router.beforeEach((to, from, next) => {
+    nProgress.start()
+    next()
+  })
+  router.afterEach(() => {
+    nProgress.done()
+  })
 }

+ 18 - 0
src/router/utils.ts

@@ -0,0 +1,18 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+// 根据权限列表返回过滤后的路由
+export const filterAuthHandle = (authList: (string|number)[], routes: RouteRecordRaw[]) => {
+  return routes.filter(el => {
+    if (el.children?.length) {
+      el.children = filterAuthHandle(authList, el.children)
+      return true
+    } else {
+      if (authList.includes(el.meta?.auth as string)) {
+        return true
+      } else if (!el.meta?.hasOwnProperty('auth')) {
+        return true
+      }
+      return false
+    }
+  })
+}

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov