二级Layout与隐藏路由,个人中心Layout

This commit is contained in:
洛洛希雅Lolosia 2023-06-25 17:19:33 +08:00
parent dbf7b68027
commit 1710ca21e6
31 changed files with 233 additions and 49 deletions

View File

@ -1,6 +1,6 @@
import NProgress from 'nprogress' import NProgress from 'nprogress'
import type { RouteRecordName } from 'vue-router' import type { RouteRecordName } from 'vue-router'
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
import router, { asyncRoutes, constantRoutes } from '@/router' import router, { asyncRoutes, constantRoutes } from '@/router'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
import { useBasicStore } from '@/store/basic' import { useBasicStore } from '@/store/basic'

View File

@ -0,0 +1,8 @@
<template>
<sub-menu :parent-router="userRoute" />
</template>
<script setup>
import SubMenu from "@/layout/submenu/index.vue";
import { userRoute } from "@/router/modules/user";
</script>

View File

@ -70,7 +70,7 @@ import { elMessage } from "@/hooks/use-element";
import { useBasicStore } from "@/store/basic"; import { useBasicStore } from "@/store/basic";
import { langTitle } from "@/hooks/use-common"; import { langTitle } from "@/hooks/use-common";
import userImage from "@/assets/layout/user.png"; import userImage from "@/assets/layout/user.png";
import Debugger from "@/layout/app-main/component/Debugger.vue"; import Debugger from "@/layout/default/app-main/component/Debugger.vue";
const basicStore = useBasicStore(); const basicStore = useBasicStore();
const { settings, sidebar, setToggleSideBar, userInfo } = basicStore; const { settings, sidebar, setToggleSideBar, userInfo } = basicStore;

View File

@ -28,7 +28,7 @@
import { ref } from 'vue' import { ref } from 'vue'
import { resolve } from 'path-browserify' import { resolve } from 'path-browserify'
import Link from './Link.vue' import Link from './Link.vue'
import MenuIcon from '../../components/MenuIcon.vue' import MenuIcon from '../../../components/MenuIcon.vue'
import type { RouteRawConfig } from '~/basic' import type { RouteRawConfig } from '~/basic'
import { isExternal } from '@/hooks/use-layout' import { isExternal } from '@/hooks/use-layout'
import { langTitle } from '@/hooks/use-common' import { langTitle } from '@/hooks/use-common'

View File

@ -0,0 +1,84 @@
<template>
<div :class="classObj" class="layout-wrapper">
<!--left side-->
<Sidebar v-if="settings.showLeftMenu" class="sidebar-container" :parent-router="prop.parentRouter" />
<!--right container-->
<div class="main-container">
<Navbar v-if="settings.showTopNavbar" class="nav-bar" />
<TagsView v-if="settings.showTagsView" />
<AppMain class="app-main" />
</div>
</div>
</template>
<script setup lang="ts" name="SubMenuLayout">
import { computed } from 'vue'
import Sidebar from './sidebar/index.vue'
import AppMain from '../default/app-main/index.vue'
import Navbar from '../default/app-main/Navbar.vue'
import TagsView from '../default/app-main/TagsView.vue'
import { useBasicStore } from '@/store/basic'
import { resizeHandler } from '@/hooks/use-layout'
import type { RouteRawConfig } from '~/basic'
const prop = defineProps<{
parentRouter: RouteRawConfig
}>()
const { sidebar, settings } = useBasicStore()
const classObj = computed(() => {
return {
closeSidebar: !sidebar.opened,
hideSidebar: !settings.showLeftMenu
}
})
resizeHandler()
</script>
<style lang="scss" scoped>
.main-container {
transition: margin-left var(--sideBar-switch-duration);
margin-left: var(--side-bar-width);
position: relative;
height: 100vh;
display: flex;
flex-direction: column;
.nav-bar {
flex-shrink: 0;
height: 50px;
}
.app-main {
flex-grow: 1;
overflow: auto;
}
}
.sidebar-container {
transition: width var(--sideBar-switch-duration);
width: var(--side-bar-width) !important;
background-color: var(--el-menu-bg-color);
height: 100%;
position: fixed;
font-size: 0;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
border-right: 0.5px solid var(--side-bar-border-right-color);
}
.closeSidebar {
.sidebar-container {
width: 54px !important;
}
.main-container {
margin-left: 54px !important;
}
}
.hideSidebar {
.sidebar-container {
width: 0 !important;
}
.main-container {
margin-left: 0;
}
}
</style>

View File

@ -0,0 +1,67 @@
<template>
<div id="Sidebar" class="reset-menu-style">
<!--logo-->
<Logo v-if="settings.sidebarLogo" :collapse="!sidebar.opened" />
<!--router menu-->
<el-scrollbar>
<el-menu
class="el-menu-vertical"
:collapse="!sidebar.opened"
:default-active="activeMenu"
:collapse-transition="false"
mode="vertical"
>
<sidebar-item v-for="r in routes" :key="r.path" :item="r" :base-path="basePath(r.path)" />
</el-menu>
</el-scrollbar>
</div>
</template>
<script setup lang="ts" name="SubMenuSideBar">
import { computed } from 'vue'
import { storeToRefs } from 'pinia/dist/pinia'
import { useRoute } from 'vue-router'
import Logo from '@/layout/default/sidebar/Logo.vue'
import SidebarItem from '@/layout/default/sidebar/SidebarItem.vue'
import { useBasicStore } from '@/store/basic'
const { settings, sidebar } = storeToRefs(useBasicStore())
const route = useRoute()
const activeMenu = ref<any>(route.path)
import type { BootstrapIcons, RouteRawConfig, RouterTypes } from '~/basic'
const prop = defineProps<{
parentRouter: RouteRawConfig
}>()
watch(
() => route.path,
(val) => {
activeMenu.value = val
}
)
const routes = computed(() => {
return [
{
path: '/',
meta: {
title: '返回',
icon: 'arrow-left-square' as BootstrapIcons
}
},
...prop.parentRouter.children!
] as RouterTypes
})
function basePath(path: string) {
if (path.startsWith('/')) return `/${path}`
else return `${prop.parentRouter.path}/${path}`
}
</script>
<style lang="scss">
//fix open the item style issue
.el-menu-vertical {
width: var(--side-bar-width);
}
</style>

View File

@ -1,7 +1,8 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import type { RouterTypes } from '~/basic' import type { RouterTypes } from '~/basic'
import settings from '@/settings' import settings from '@/settings'
const Layout = () => import('@/layout/index.vue') import { userRoute } from '@/router/modules/user'
const Layout = () => import('@/layout/default/index.vue')
export const constantRoutes: RouterTypes = [ export const constantRoutes: RouterTypes = [
{ {
@ -38,19 +39,7 @@ export const constantRoutes: RouterTypes = [
} }
] ]
}, },
{ userRoute
path: '/user',
name: '用户',
component: Layout,
hidden: true,
children: [
{
path: 'profile',
name: '首选项',
component: () => import('@/views/user/profile/index.vue')
}
]
}
] ]
//角色和code数组动态路由 //角色和code数组动态路由

View File

@ -1,4 +1,4 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
const BasicDemo = { const BasicDemo = {
path: '/basic-demo', path: '/basic-demo',
component: Layout, component: Layout,

View File

@ -1,6 +1,6 @@
/** When your routing table is too long, you can split it into small modules**/ /** When your routing table is too long, you can split it into small modules**/
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
const chartsRouter = { const chartsRouter = {
path: '/charts', path: '/charts',

View File

@ -1,4 +1,4 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
const directive = { const directive = {
path: '/directive', path: '/directive',

View File

@ -1,4 +1,4 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
const excel = { const excel = {
path: '/excel', path: '/excel',
component: Layout, component: Layout,

View File

@ -1,4 +1,4 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
const guid = { const guid = {
path: '/guide', path: '/guide',
component: Layout, component: Layout,

View File

@ -1,4 +1,4 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
const other = { const other = {
path: '/other', path: '/other',
component: Layout, component: Layout,

View File

@ -1,4 +1,4 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
const richText = { const richText = {
path: '/rich-text', path: '/rich-text',
component: Layout, component: Layout,

View File

@ -1,4 +1,4 @@
import Layout from '@/layout/index.vue' import Layout from '@/layout/default/index.vue'
const table = { const table = {
path: '/table', path: '/table',
component: Layout, component: Layout,

View File

@ -0,0 +1,17 @@
import type { BootstrapIcons, RouteRawConfig } from "~/basic";
export const userRoute = {
path: '/user',
name: 'User',
component: () => import('@/layout/UserProfileLayout.vue'),
meta: { title: '用户中心', icon: 'person' as BootstrapIcons },
hidden: true,
children: [
{
path: 'profile',
name: 'Profile',
meta: {title: '个人信息', icon: 'text-left' as BootstrapIcons},
component: () => import('@/views/user/profile/index.vue')
}
]
} as RouteRawConfig

65
typings/basic.d.ts vendored
View File

@ -11,31 +11,50 @@
/*router*/ /*router*/
import type { RouteRecordRaw } from 'vue-router' import type { RouteRecordRaw } from 'vue-router'
export interface rawConfig {
hidden?: boolean import type icons from 'bootstrap-icons/font/bootstrap-icons.json'
alwaysShow?: boolean export type BootstrapIcons = keyof typeof icons;
code?: number
name?: string export interface RawConfig {
fullPath?: string /** 是否隐藏路由 */
path?: string hidden: boolean
meta?: { /** TODO 不知道。 */
alwaysShow: boolean
/** TODO 不知道。 */
code: number
/** 路由名称 */
name: string
/** 完整路径,一般不填 */
fullPath: string
/** 路径,可以为相对路径 */
path: string
/** 元数据,没有元数据时不显示菜单 */
meta: Omit<Partial<RawConfigMeta>, 'title'> & Required<Pick<RawConfigMeta, 'title'>>
/** 子路由 */
children: RouterTypes
/** 重定向,绝对路径 */
redirect: string
/** 是否显示子菜单 */
expand: boolean
}
export interface RawConfigMeta {
/** 路由标题,显示在菜单按钮上 */
title: string title: string
icon?: string /** 路由图标 */
affix?: boolean icon: BootstrapIcons
activeMenu?: string affix: boolean
breadcrumb?: boolean activeMenu: string
roles?: Array<string> breadcrumb: boolean
elSvgIcon?: string roles: Array<string>
code?: number code: number
cachePage?: boolean cachePage: boolean
leaveRmCachePage?: boolean leaveRmCachePage: boolean
closeTabRmCache?: boolean closeTabRmCache: boolean
} }
children?: RouterOptions
redirect?: string export type RouteRawConfig = RouteRecordRaw & Partial<RawConfig>
} export type RouterTypes = Array<RouteRawConfig>
export type RouteRawConfig = RouteRecordRaw & rawConfig
export type RouterTypes = Array<rawProp>
/*settings*/ /*settings*/
export interface SettingsConfig { export interface SettingsConfig {