feat:更新layout
This commit is contained in:
parent
02ea680fac
commit
19322ac91d
@ -2,6 +2,8 @@ import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
|
||||
import Login from "@/views/login/index.vue"; //登录组件
|
||||
import Layout from "@/views/layout/index.vue"; //首页布局
|
||||
import CallBack from "@/views/login/OauthCallBack.vue"; //反馈页面
|
||||
import Home from '@/views/home/index.vue'; //家
|
||||
import Auth from '@/views/role/pages/Auth.vue'; //权限管理
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
@ -18,6 +20,19 @@ const routes: Array<RouteRecordRaw> = [
|
||||
path: "/layout",
|
||||
name: "Layout",
|
||||
component: Layout,
|
||||
children:[
|
||||
{
|
||||
path:'',
|
||||
name:'home',
|
||||
component:Home,
|
||||
},
|
||||
// 后续用动态菜单
|
||||
{
|
||||
path:'role',
|
||||
name:'roleAuth',
|
||||
component:Auth
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
|
8
src/views/home/index.vue
Normal file
8
src/views/home/index.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div>我老家</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
</style>
|
125
src/views/layout/components/LayoutHeader.vue
Normal file
125
src/views/layout/components/LayoutHeader.vue
Normal file
@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<n-layout-header bordered>
|
||||
<div class="header-icon">
|
||||
<img src="/logo.jpg">
|
||||
<div class="header-icon__text">
|
||||
<p class="cn">零枢</p>
|
||||
<p class="en">ZeroNode</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-avatar">
|
||||
<div class="header-avatar__info">
|
||||
<n-avatar src="@/assets/images/luolan_avatar.jpg" round :size="45"
|
||||
fallback-src="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg">
|
||||
</n-avatar>
|
||||
<p class="username">白盐浊泉</p>
|
||||
<n-dropdown :options="options" @select="handleSelect">
|
||||
<n-icon :size="16" color="#000" style="cursor: pointer;">
|
||||
<CaretDownOutline />
|
||||
</n-icon>
|
||||
</n-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</n-layout-header>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
import { useAuth0 } from '@auth0/auth0-vue';
|
||||
import {
|
||||
Pencil as EditIcon,
|
||||
LogOutOutline as LogoutIcon,
|
||||
PersonCircleOutline as UserIcon,
|
||||
CaretDownOutline
|
||||
} from '@vicons/ionicons5';
|
||||
import { NIcon } from 'naive-ui';
|
||||
const { logout } = useAuth0();
|
||||
const router = useRouter();
|
||||
function renderIcon(icon: Component) {
|
||||
return () => {
|
||||
return h(NIcon, null, {
|
||||
default: () => h(icon)
|
||||
})
|
||||
}
|
||||
}
|
||||
const options = [
|
||||
{
|
||||
label: '用户资料',
|
||||
key: 'profile',
|
||||
icon: renderIcon(UserIcon)
|
||||
},
|
||||
{
|
||||
label: '编辑用户资料',
|
||||
key: 'editProfile',
|
||||
icon: renderIcon(EditIcon)
|
||||
},
|
||||
{
|
||||
label: '退出登录',
|
||||
key: 'logout',
|
||||
icon: renderIcon(LogoutIcon)
|
||||
}
|
||||
];
|
||||
|
||||
const handleSelect = (key: string | number) => {
|
||||
if(key === 'logout'){
|
||||
logout({ logoutParams: { returnTo: window.location.origin } });
|
||||
router.push('/');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
.n-layout-header {
|
||||
height: 60px;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.header-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
gap: 12px;
|
||||
|
||||
img {
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&__text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 45px;
|
||||
|
||||
.cn {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.en {
|
||||
color: $primaryColor;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 右侧
|
||||
.header-avatar {
|
||||
&__info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.username {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
99
src/views/layout/components/LayoutNav.vue
Normal file
99
src/views/layout/components/LayoutNav.vue
Normal file
@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<n-layout-sider bordered collapse-mode="width" :collapsed-width="64" :width="240" :collapsed="!menuApp.isExpaned"
|
||||
show-trigger @collapse="menuApp.isExpaned = false" @expand="menuApp.isExpaned = true" :style="{
|
||||
'--n-collapsed-width': '64px',
|
||||
transition: 'width 0.3s var(--n-bezier)'
|
||||
}">
|
||||
<n-menu v-model:value="activeKey" :collapsed="!menuApp.isExpaned" :collapsed-width="64"
|
||||
:collapsed-icon-size="22" :options="menuOptions" :expand-icon="expandIcon" :style="{
|
||||
'--n-item-icon-margin': '0 auto',
|
||||
'--n-item-icon-size': '22px'
|
||||
}" />
|
||||
</n-layout-sider>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
import {
|
||||
LogOutOutline as HomeIcon,
|
||||
LaptopOutline as WorkIcon,
|
||||
CaretDownOutline,
|
||||
HomeSharp,
|
||||
PersonCircleSharp,
|
||||
Layers
|
||||
} from '@vicons/ionicons5'
|
||||
import { MenuOption, NIcon } from 'naive-ui';
|
||||
import { useAppStore } from '@/store/app';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { RouterLink } from 'vue-router';
|
||||
import { h } from 'vue'
|
||||
const appStore = useAppStore();
|
||||
const activeKey = ref('default');
|
||||
const { menuApp } = storeToRefs(appStore)
|
||||
const expandIcon = () => {
|
||||
return h(NIcon, null, { default: () => h(CaretDownOutline) })
|
||||
}
|
||||
|
||||
function renderIcon(icon: Component) {
|
||||
return () => h(NIcon, null, { default: () => h(icon) })
|
||||
}
|
||||
const menuOptions: MenuOption[] = [
|
||||
{
|
||||
label: () =>
|
||||
h(
|
||||
RouterLink,
|
||||
{
|
||||
to: {
|
||||
name: 'home',
|
||||
params: {
|
||||
lang: 'zh-CN'
|
||||
}
|
||||
}
|
||||
},
|
||||
{ default: () => '概览' }
|
||||
),
|
||||
key: 'default',
|
||||
icon: renderIcon(HomeSharp)
|
||||
},
|
||||
{
|
||||
label: '角色管理',
|
||||
key: 'role',
|
||||
icon: renderIcon(PersonCircleSharp),
|
||||
children: [
|
||||
{
|
||||
label: () => h(
|
||||
RouterLink,
|
||||
{
|
||||
to: {
|
||||
name: 'roleAuth',
|
||||
params: {
|
||||
lang: 'zh-CN'
|
||||
}
|
||||
}
|
||||
},
|
||||
{ default: () => '权限分配' }
|
||||
),
|
||||
key: 'role-auth',
|
||||
icon: renderIcon(Layers)
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
/* 确保菜单项在折叠状态下图标居中 */
|
||||
.n-menu-item-content--collapsed {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 添加平滑过渡效果 */
|
||||
.n-layout-sider {
|
||||
transition: width 0.3s var(--n-bezier);
|
||||
height:100%;
|
||||
}
|
||||
|
||||
/* 调整折叠状态下菜单项的样式 */
|
||||
.n-menu .n-menu-item-content--collapsed .n-menu-item-content__icon {
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<n-layout>
|
||||
<n-layout-header>颐和园路</n-layout-header>
|
||||
<n-layout content-class="layout__main" has-sider>
|
||||
<n-menu :collapsed="!menuApp.isExpaned" :collapsed-width="64" :collapsed-icon-size="22" :options="menuOptions"
|
||||
:render-label="renderMenuLabel" :render-icon="renderMenuIcon" :expand-icon="expandIcon" />
|
||||
<n-layout-content content-style="padding: 24px;">
|
||||
<n-layout style="height: 100vh;">
|
||||
<LayoutHeader />
|
||||
<n-layout has-sider style="height: calc(100vh - 60px);">
|
||||
<LayoutNav />
|
||||
<n-layout-content
|
||||
content-style="padding: 24px; min-height: calc(100vh - 60px);"
|
||||
:native-scrollbar="false"
|
||||
>
|
||||
<RouterView></RouterView>
|
||||
</n-layout-content>
|
||||
</n-layout>
|
||||
@ -12,119 +14,16 @@
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
import { BookmarkOutline, CaretDownOutline } from '@vicons/ionicons5';
|
||||
import { MenuOption, NIcon } from 'naive-ui';
|
||||
import { useAppStore } from '@/store/app';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const appStore = useAppStore();
|
||||
const { menuApp } = storeToRefs(appStore)
|
||||
const expandIcon = () => {
|
||||
return h(NIcon, null, { default: () => h(CaretDownOutline) })
|
||||
}
|
||||
const renderMenuIcon = (option: MenuOption) => {
|
||||
// 渲染图标占位符以保持缩进
|
||||
if (option.key === 'sheep-man')
|
||||
return true
|
||||
// 返回 falsy 值,不再渲染图标及占位符
|
||||
if (option.key === 'food')
|
||||
return null
|
||||
return h(NIcon, null, { default: () => h(BookmarkOutline) })
|
||||
}
|
||||
const menuOptions: MenuOption[] = [
|
||||
{
|
||||
label: '且听风吟',
|
||||
key: 'hear-the-wind-sing',
|
||||
href: 'https://baike.baidu.com/item/%E4%B8%94%E5%90%AC%E9%A3%8E%E5%90%9F/3199'
|
||||
},
|
||||
{
|
||||
label: '1973年的弹珠玩具',
|
||||
key: 'pinball-1973',
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
label: '鼠',
|
||||
key: 'rat'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '寻羊冒险记',
|
||||
key: 'a-wild-sheep-chase',
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
label: '舞,舞,舞',
|
||||
key: 'dance-dance-dance',
|
||||
children: [
|
||||
{
|
||||
type: 'group',
|
||||
label: '人物',
|
||||
key: 'people',
|
||||
children: [
|
||||
{
|
||||
label: '叙事者',
|
||||
key: 'narrator'
|
||||
},
|
||||
{
|
||||
label: '羊男',
|
||||
key: 'sheep-man'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '饮品',
|
||||
key: 'beverage',
|
||||
children: [
|
||||
{
|
||||
label: '威士忌',
|
||||
key: 'whisky',
|
||||
href: 'https://baike.baidu.com/item/%E5%A8%81%E5%A3%AB%E5%BF%8C%E9%85%92/2959816?fromtitle=%E5%A8%81%E5%A3%AB%E5%BF%8C&fromid=573&fr=aladdin'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '食物',
|
||||
key: 'food',
|
||||
children: [
|
||||
{
|
||||
label: '三明治',
|
||||
key: 'sandwich'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '过去增多,未来减少',
|
||||
key: 'the-past-increases-the-future-recedes'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
const renderMenuLabel = (option: MenuOption) => {
|
||||
if ('href' in option) {
|
||||
return h(
|
||||
'a',
|
||||
{ href: option.href, target: '_blank' },
|
||||
option.label as string
|
||||
)
|
||||
}
|
||||
return option.label as string
|
||||
}
|
||||
// icon
|
||||
import LayoutHeader from './components/LayoutHeader.vue';
|
||||
import LayoutNav from './components/LayoutNav.vue';
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='scss'>
|
||||
.n-layout-header {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.n-layout-sider {
|
||||
background: rgba(128, 128, 128, 0.3);
|
||||
}
|
||||
|
||||
.n-layout-content {
|
||||
background: rgba(128, 128, 128, 0.4);
|
||||
}
|
||||
.layout__main{
|
||||
height:calc(100vh - 60px);
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
background:#f5f7f9
|
||||
}
|
||||
</style>
|
@ -211,14 +211,10 @@ const handleDemo = () => {
|
||||
console.log('观看演示');
|
||||
}
|
||||
|
||||
const { loginWithRedirect, logout } = useAuth0();
|
||||
const { loginWithRedirect } = useAuth0();
|
||||
const handleLogin = () => {
|
||||
loginWithRedirect();
|
||||
}
|
||||
// 登出
|
||||
const handleLogout = () => {
|
||||
logout({ logoutParams: { returnTo: window.location.origin } });
|
||||
}
|
||||
// 联系我们
|
||||
const handleContact = () => {
|
||||
dialog.warning({
|
||||
|
8
src/views/role/pages/Auth.vue
Normal file
8
src/views/role/pages/Auth.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div>权限管理菜单内容</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user