250 lines
6.1 KiB
Plaintext
250 lines
6.1 KiB
Plaintext
<template>
|
|
<div
|
|
class="ant-admin-layout"
|
|
:class="{
|
|
'ant-layout-Fluid': !getHeaderFixed,
|
|
'ant-light-theme': getNavTheme === 'light',
|
|
'ant-layout-mix': getLayout === 'mix' && getNavTheme === 'dark',
|
|
'page-full-screen': isFullscreen,
|
|
}"
|
|
>
|
|
<pro-layout
|
|
v-model:collapsed="baseState.collapsed"
|
|
v-model:selectedKeys="baseState.selectedKeys"
|
|
v-model:openKeys="baseState.openKeys"
|
|
v-bind="layoutConf"
|
|
class="ant-layout-Fluid"
|
|
>
|
|
<template #headerContentRender>
|
|
<header-left @update:collapsed="onCollapsed" />
|
|
</template>
|
|
<template #rightContentRender>
|
|
<header-right />
|
|
</template>
|
|
<div class="antd-admin-container">
|
|
<!-- 多标签 -->
|
|
<TabsView
|
|
class="antd-admin-tabs"
|
|
v-if="getMultiTabsShow"
|
|
@page-full-screen="togglePageFullScreen"
|
|
/>
|
|
<div class="antd-admin-body" ref="adminBodyRef">
|
|
<!-- 页面主内容 -->
|
|
<div class="antd-admin-content">
|
|
<main-view />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</pro-layout>
|
|
|
|
<!--项目配置-->
|
|
<template v-if="getIsProjectSetting">
|
|
<ProjectSetting ref="drawerSetting" />
|
|
|
|
<div class="shadow-lg circular" @click="openSetting">
|
|
<SettingOutlined
|
|
:style="{ fontSize: '20px' }"
|
|
class="transition ease-in-out transform delay-150 hover:animate-spin"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
<script lang="ts" setup>
|
|
import { ref, unref, reactive, computed, provide, h, watchEffect, watch } from 'vue';
|
|
import { useAsyncRouteStore } from '@/store/modules/asyncRoute';
|
|
import { generatorMenu } from '@/utils/index';
|
|
import { useRouter } from 'vue-router';
|
|
import { TabsView } from './components/TagsView';
|
|
import { MainView } from './components/Main';
|
|
import LOGO from '@/assets/images/logo.png';
|
|
import HeaderLeft from './components/Header/HeaderLeft.vue';
|
|
import HeaderRight from './components/Header/HeaderRight.vue';
|
|
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
|
|
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
|
import type { RouteContextProps } from '@ant-design-vue/pro-layout';
|
|
import { useFullscreen } from '@vueuse/core';
|
|
import ProjectSetting from './components/Header/ProjectSetting.vue';
|
|
import { SettingOutlined } from '@ant-design/icons-vue';
|
|
|
|
// 当前路由
|
|
const router = useRouter();
|
|
const settingStore = useProjectSettingStore();
|
|
const {
|
|
getLayout,
|
|
getNavTheme,
|
|
getHeaderTheme,
|
|
getMultiTabsShow,
|
|
getMenuWidth,
|
|
getHeaderHeight,
|
|
getHeaderFixed,
|
|
getHeaderRender,
|
|
getMenuCollapsed,
|
|
getMenuSplit,
|
|
getMenuTitle,
|
|
getIsProjectSetting,
|
|
} = useProjectSetting();
|
|
|
|
const drawerSetting = ref();
|
|
const adminBodyRef = ref<HTMLElement | null>(null);
|
|
const asyncRouteStore = useAsyncRouteStore();
|
|
const { isFullscreen, toggle } = useFullscreen(adminBodyRef);
|
|
|
|
const menuData = computed(() => {
|
|
return generatorMenu(asyncRouteStore.getMenus);
|
|
});
|
|
|
|
const baseState = reactive<Omit<RouteContextProps, 'menuData'>>({
|
|
selectedKeys: [],
|
|
openKeys: [],
|
|
collapsed: unref(getMenuCollapsed) ? true : false,
|
|
});
|
|
|
|
watch(
|
|
router.currentRoute,
|
|
() => {
|
|
const matched = router.currentRoute.value.matched.concat();
|
|
baseState.selectedKeys = matched.map((r) => r.path);
|
|
baseState.openKeys = matched
|
|
.filter((r) => r.path !== router.currentRoute.value.path)
|
|
.map((r) => r.path);
|
|
},
|
|
{
|
|
immediate: true,
|
|
},
|
|
);
|
|
|
|
watch(
|
|
() => baseState.collapsed,
|
|
(collapsed) => {
|
|
settingStore.menuSetting.collapsed = collapsed;
|
|
},
|
|
);
|
|
|
|
const layoutConf = reactive({
|
|
title: getMenuTitle,
|
|
logo: () => {
|
|
return h('img', {
|
|
src: LOGO,
|
|
});
|
|
},
|
|
menuData, //菜单集合
|
|
splitMenus: getMenuSplit,
|
|
isMobile: false, //是否手机
|
|
siderWidth: getMenuWidth, //菜单宽度
|
|
headerHeight: getHeaderHeight, //顶部高度
|
|
fixedHeader: getHeaderFixed, //固定顶部
|
|
fixSiderbar: true, //固定侧边
|
|
headerTheme: getHeaderTheme, // 标题栏主题
|
|
navTheme: getNavTheme, //导航栏的主题
|
|
layout: getLayout, //布局模式
|
|
headerRender: getHeaderRender,
|
|
contentWidth: 'Fluid', //内容区域宽度模式
|
|
contentStyle: 'margin:0px',
|
|
class: 'ant-layout-Fluid',
|
|
});
|
|
|
|
provide('collapsed', baseState.collapsed);
|
|
|
|
provide('isPageFullScreen', isFullscreen);
|
|
|
|
provide('openSetting', openSetting);
|
|
|
|
function onCollapsed() {
|
|
baseState.collapsed = !baseState.collapsed;
|
|
}
|
|
|
|
//切换内容页全屏
|
|
function togglePageFullScreen() {
|
|
toggle();
|
|
}
|
|
|
|
//打开设置
|
|
function openSetting() {
|
|
const { openDrawer } = drawerSetting.value;
|
|
openDrawer();
|
|
}
|
|
</script>
|
|
<style lang="less" scoped>
|
|
.ant-admin-layout {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
height: 100vh;
|
|
}
|
|
|
|
//内容全屏
|
|
.page-full-screen {
|
|
.antd-admin-body {
|
|
background: #f0f2f5;
|
|
}
|
|
}
|
|
|
|
.dark {
|
|
.page-full-screen {
|
|
.antd-admin-body {
|
|
background: #000;
|
|
}
|
|
}
|
|
}
|
|
.antd-admin-tabs {
|
|
margin-top: 10px;
|
|
padding: 0 10px;
|
|
width: 100%;
|
|
}
|
|
|
|
.antd-admin-body {
|
|
height: calc(100vh - 126px);
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
box-sizing: border-box;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
position: relative;
|
|
margin-top: 10px;
|
|
|
|
.antd-admin-content {
|
|
margin: 0 10px;
|
|
}
|
|
}
|
|
|
|
.ant-layout-Fluid {
|
|
overflow-y: scroll;
|
|
|
|
.antd-admin-body {
|
|
overflow: inherit;
|
|
}
|
|
}
|
|
|
|
.ant-light-theme {
|
|
:deep(.ant-pro-sider) {
|
|
background: #fff;
|
|
}
|
|
}
|
|
|
|
.ant-layout-mix {
|
|
:deep(.ant-menu-horizontal .ant-menu-item a) {
|
|
color: #fff;
|
|
}
|
|
}
|
|
|
|
.circular {
|
|
position: fixed;
|
|
right: -2px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 40px;
|
|
height: 40px;
|
|
background-color: #1e6fff;
|
|
font-size: 24px;
|
|
color: #fff;
|
|
border-radius: 10px 0 0 10px;
|
|
cursor: pointer;
|
|
z-index: 200;
|
|
}
|
|
</style>
|