477 lines
12 KiB
Vue
477 lines
12 KiB
Vue
<template>
|
|
<div
|
|
class="admin-layout"
|
|
:inverted="inverted"
|
|
:class="{
|
|
'admin-layout-fix-header': fixedHeader,
|
|
'admin-layout-fix-side': fixedSide,
|
|
'admin-layout-fix-body': true,
|
|
'admin-layout-side-horizontal': navMode === 'horizontal',
|
|
'admin-layout-hide-side': !isMixMenuNoneSub,
|
|
'admin-layout-show-tabs': isMultiTabs,
|
|
'admin-layout-collapse': collapsed,
|
|
'admin-layout-theme-light': getNavTheme === 'light',
|
|
'admin-layout-header-dark': getNavTheme === 'header-dark',
|
|
}"
|
|
>
|
|
<div class="admin-layout-header">
|
|
<Logo v-if="navMode != 'horizontal'" />
|
|
<PageHeader @update:collapsed="updateCollapsed" :inverted="inverted" />
|
|
</div>
|
|
|
|
<div class="admin-layout-content">
|
|
<div
|
|
v-if="isMixMenuNoneSub && (navMode === 'vertical' || navMode === 'horizontal-mix')"
|
|
show-trigger="arrow-circle"
|
|
@collapse="collapsed = true"
|
|
@expand="collapsed = false"
|
|
:native-scrollbar="false"
|
|
:collapsed="collapsed"
|
|
collapse-mode="width"
|
|
:collapsed-width="64"
|
|
:width="leftMenuWidth"
|
|
:inverted="inverted"
|
|
class="admin-layout-sider"
|
|
>
|
|
<el-scrollbar>
|
|
<Sider v-model:location="getMenuLocation" class="left-menu" v-bind="siderOption" />
|
|
</el-scrollbar>
|
|
</div>
|
|
|
|
<div
|
|
embedded
|
|
:inverted="inverted"
|
|
class="admin-layout-content-son"
|
|
:class="{
|
|
'layout-content-inverted': getDarkTheme,
|
|
'page-full-screen': isFullscreen && !getDarkTheme,
|
|
}"
|
|
>
|
|
<TabsView
|
|
v-if="isMultiTabs"
|
|
v-model:collapsed="collapsed"
|
|
@page-full-screen="togglePageFullScreen"
|
|
/>
|
|
<div class="admin-layout-content-main">
|
|
<div class="main-view" ref="adminBodyRef">
|
|
<MainView />
|
|
<PageFooter/>
|
|
</div>
|
|
</div>
|
|
<!-- <el-back-top :right="100" /> -->
|
|
</div>
|
|
</div>
|
|
<div class="admin-layout-shade"></div>
|
|
</div>
|
|
|
|
<!--项目配置-->
|
|
<template v-if="getIsProjectSetting">
|
|
<ProjectSetting ref="drawerSetting" />
|
|
|
|
<div class="shadow-lg circular" @click="openSetting">
|
|
<el-icon class="el-input__icon" :size="20">
|
|
<SettingOutlined class="transition ease-in-out delay-150 transform hover:animate-spin" />
|
|
</el-icon>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, unref, computed, onMounted, watch, provide } from 'vue';
|
|
import { Logo } from './components/Logo';
|
|
import { TabsView } from './components/TagsView';
|
|
import { MainView } from './components/Main';
|
|
import { PageHeader } from './components/Header';
|
|
import { PageFooter } from './components/Footer';
|
|
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
|
|
import { useDesignSetting } from '@/hooks/setting/useDesignSetting';
|
|
import { useRoute } from 'vue-router';
|
|
import { useProjectSettingStore } from '@/store/modules/projectSetting';
|
|
import ProjectSetting from './components/Header/ProjectSetting.vue';
|
|
import { useFullscreen } from '@vueuse/core';
|
|
import { useDesignSettingStore } from '@/store/modules/designSetting';
|
|
import { SettingOutlined } from '@vicons/antd';
|
|
import Sider from './components/Sider/Sider.vue';
|
|
|
|
const { getDarkTheme } = useDesignSetting();
|
|
const {
|
|
getNavMode,
|
|
getMenuWidth,
|
|
getMenuMinWidth,
|
|
getNavTheme,
|
|
getHeaderSetting,
|
|
getMenuSetting,
|
|
getMultiTabsSetting,
|
|
getIsProjectSetting,
|
|
} = useProjectSetting();
|
|
|
|
const settingStore = useProjectSettingStore();
|
|
const designStore = useDesignSettingStore();
|
|
|
|
const navMode = getNavMode;
|
|
|
|
const drawerSetting = ref();
|
|
const collapsed = ref<boolean>(false);
|
|
const adminBodyRef = ref<HTMLElement | null>(null);
|
|
|
|
const { isFullscreen, toggle } = useFullscreen(adminBodyRef);
|
|
|
|
provide('isPageFullScreen', isFullscreen);
|
|
provide('collapsed', collapsed);
|
|
provide('openSetting', openSetting);
|
|
|
|
watch(
|
|
() => collapsed.value,
|
|
(to) => {
|
|
settingStore.setMenuSetting({ collapsed: to });
|
|
},
|
|
{ immediate: true },
|
|
);
|
|
|
|
//固定顶部
|
|
const fixedHeader = computed(() => {
|
|
const { fixed } = unref(getHeaderSetting);
|
|
return fixed;
|
|
});
|
|
|
|
//固定侧边栏
|
|
const fixedSide = computed(() => {
|
|
const { fixed } = unref(getMenuSetting);
|
|
return fixed;
|
|
});
|
|
|
|
//切换内容页全屏
|
|
function togglePageFullScreen() {
|
|
toggle();
|
|
}
|
|
|
|
//菜单折叠
|
|
function updateCollapsed() {
|
|
collapsed.value = !collapsed.value;
|
|
}
|
|
|
|
//打开设置
|
|
function openSetting() {
|
|
const { openDrawer } = drawerSetting.value;
|
|
openDrawer();
|
|
}
|
|
|
|
//获取主题风格色
|
|
const getAppTheme = computed(() => {
|
|
return designStore.appTheme;
|
|
});
|
|
|
|
const isMixMenuNoneSub = computed(() => {
|
|
const mixMenu = settingStore.menuSetting.mixMenu;
|
|
const currentRoute = useRoute();
|
|
if (unref(navMode) != 'horizontal-mix') return true;
|
|
if (unref(navMode) === 'horizontal-mix' && mixMenu && currentRoute.meta.isRoot) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
const isMultiTabs = computed(() => {
|
|
return unref(getMultiTabsSetting).show;
|
|
});
|
|
|
|
const inverted = computed(() => {
|
|
return ['dark', 'header-dark'].includes(unref(getNavTheme));
|
|
});
|
|
|
|
const siderOption = computed(() => {
|
|
const navTheme = unref(getNavTheme);
|
|
let backgroundColor = '#001428';
|
|
let textColor = '#bbb';
|
|
if (unref(getDarkTheme)) {
|
|
backgroundColor = '#18181c';
|
|
textColor = '#fff';
|
|
} else if (['light'].includes(navTheme)) {
|
|
backgroundColor = '#fff';
|
|
textColor = '#333';
|
|
}
|
|
|
|
return {
|
|
backgroundColor,
|
|
textColor,
|
|
};
|
|
});
|
|
|
|
const leftMenuWidth = computed(() => {
|
|
const { minMenuWidth, menuWidth } = unref(getMenuSetting);
|
|
return collapsed.value ? minMenuWidth : menuWidth;
|
|
});
|
|
|
|
const getMenuLocation = computed(() => {
|
|
return 'left';
|
|
});
|
|
|
|
const menuWidth = computed(() => {
|
|
return getMenuWidth.value + 'px';
|
|
});
|
|
|
|
const minMenuWidth = computed(() => {
|
|
return getMenuMinWidth.value + 'px';
|
|
});
|
|
|
|
//看自身需求是否保留吧,这个用处不是很大
|
|
const watchWidth = () => {
|
|
const { isFullscreen: isFullscreen } = useFullscreen();
|
|
if (isFullscreen.value) return;
|
|
const Width = document.body.clientWidth;
|
|
if (Width < 750) {
|
|
collapsed.value = true;
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
const { themeColorChange } = drawerSetting.value;
|
|
themeColorChange('#165DFF');
|
|
window.addEventListener('resize', watchWidth);
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.admin-layout {
|
|
color: rgb(51, 54, 57);
|
|
background-color: #fff;
|
|
box-sizing: border-box;
|
|
position: relative;
|
|
z-index: auto;
|
|
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
|
|
background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), color 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
&-header {
|
|
}
|
|
&-shade {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 101;
|
|
transition: background-color 0.3s cubic-bezier(0.2, 0, 0, 1) 0s,
|
|
left 0.3s cubic-bezier(0.2, 0, 0, 1) 0s;
|
|
visibility: hidden;
|
|
}
|
|
//侧边栏
|
|
&-sider {
|
|
min-height: calc(100vh - 64px);
|
|
box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
|
|
position: relative;
|
|
z-index: 13;
|
|
transition: width 0.3s cubic-bezier(0.2, 0, 0, 1) 0s, left 0.3s cubic-bezier(0.2, 0, 0, 1) 0s,
|
|
box-shadow 0.3s cubic-bezier(0.2, 0, 0, 1) 0s, border-color var(--el-transition-duration),
|
|
background-color var(--el-transition-duration), color var(--el-transition-duration);
|
|
background-color: #001428;
|
|
width: v-bind(menuWidth);
|
|
:deep(.el-menu) {
|
|
border-right: none;
|
|
}
|
|
}
|
|
|
|
//主体内容区域
|
|
&-content {
|
|
width: 100%;
|
|
:deep(.n-layout-scroll-container) {
|
|
overflow: hidden;
|
|
}
|
|
|
|
&-main {
|
|
background: #f5f7f9;
|
|
padding: 10px;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
&-son {
|
|
flex: 1;
|
|
transition: padding-left 0.3s cubic-bezier(0.2, 0, 0, 1) 0s,
|
|
box-shadow 0.3s cubic-bezier(0.2, 0, 0, 1) 0s;
|
|
}
|
|
}
|
|
|
|
//深色主题
|
|
.layout-content-inverted {
|
|
background: rgb(16, 16, 20);
|
|
}
|
|
|
|
.n-layout-header.n-layout-header--absolute-positioned {
|
|
z-index: 11;
|
|
}
|
|
|
|
.n-layout-footer {
|
|
background: none;
|
|
}
|
|
|
|
// 固定顶部
|
|
&-fix-header {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
|
|
.admin-layout-content {
|
|
flex: auto;
|
|
min-height: calc(100vh - 64px);
|
|
&-son {
|
|
:deep(.n-layout-scroll-container) {
|
|
overflow: hidden;
|
|
}
|
|
}
|
|
|
|
&-main {
|
|
padding: 10px;
|
|
height: calc(100vh - 64px);
|
|
position: relative;
|
|
overflow-y: auto;
|
|
}
|
|
}
|
|
}
|
|
|
|
//固定侧栏
|
|
&-fix-side {
|
|
.admin-layout-sider {
|
|
position: fixed;
|
|
left: 0;
|
|
bottom: 0;
|
|
top: 64px;
|
|
}
|
|
|
|
.admin-layout-content-son {
|
|
padding-left: v-bind(menuWidth);
|
|
}
|
|
|
|
.admin-layout-header {
|
|
.logo {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
z-index: 15;
|
|
}
|
|
:deep(.layout-header) {
|
|
padding-left: v-bind(menuWidth);
|
|
}
|
|
}
|
|
}
|
|
|
|
//折叠
|
|
&-collapse {
|
|
.admin-layout-content-son {
|
|
padding-left: v-bind(minMenuWidth);
|
|
}
|
|
|
|
.admin-layout-header {
|
|
:deep(.layout-header) {
|
|
padding-left: v-bind(minMenuWidth);
|
|
}
|
|
}
|
|
|
|
.admin-layout-sider {
|
|
width: v-bind(minMenuWidth);
|
|
}
|
|
}
|
|
|
|
//没有左侧菜单
|
|
&-hide-side {
|
|
.admin-layout-content-son {
|
|
padding-left: 0px;
|
|
}
|
|
}
|
|
|
|
//显示多标签
|
|
&-show-tabs {
|
|
.admin-layout-content {
|
|
&-main {
|
|
padding: 0 10px 10px 10px;
|
|
}
|
|
}
|
|
}
|
|
&-fix-header.admin-layout-show-tabs {
|
|
.admin-layout-content {
|
|
&-main {
|
|
height: calc(100vh - 64px - 44px);
|
|
//padding: 0 10px 10px 10px;
|
|
}
|
|
}
|
|
}
|
|
|
|
//横向菜单
|
|
&-side-horizontal {
|
|
//处理顶部菜单
|
|
.admin-layout-header {
|
|
.logo {
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
z-index: 15;
|
|
}
|
|
:deep(.layout-header) {
|
|
padding-left: 0px;
|
|
}
|
|
}
|
|
|
|
//处理内容区域
|
|
.admin-layout-content-son {
|
|
padding-left: 0px;
|
|
}
|
|
}
|
|
|
|
&-theme-light {
|
|
.admin-layout-content .admin-layout-sider {
|
|
background-color: #fff;
|
|
}
|
|
.el-menu {
|
|
--el-menu-bg-color: #fff;
|
|
--el-menu-text-color: rgb(51, 54, 57);
|
|
--el-menu-hover-bg-color: #165DFF;
|
|
--el-menu-hover-text-color: #fff;
|
|
}
|
|
}
|
|
|
|
//暗色顶栏
|
|
&-header-dark {
|
|
.admin-layout-header {
|
|
:deep(.layout-header) {
|
|
background-color: #001428;
|
|
color: #fff;
|
|
.link-text {
|
|
color: #fff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//内容全屏
|
|
.page-full-screen {
|
|
.main-view {
|
|
background: #f0f2f5;
|
|
}
|
|
}
|
|
|
|
.dark {
|
|
.page-full-screen {
|
|
.main-view {
|
|
background: #000;
|
|
}
|
|
}
|
|
}
|
|
|
|
.circular {
|
|
position: fixed;
|
|
right: -2px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 40px;
|
|
height: 40px;
|
|
background-color: v-bind(getAppTheme);
|
|
font-size: 24px;
|
|
color: #fff;
|
|
border-radius: 10px 0 0 10px;
|
|
cursor: pointer;
|
|
z-index: 200;
|
|
}
|
|
</style>
|