1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-02-12 11:30:07 +08:00

211 lines
5.3 KiB
Vue

<template>
<div :class="classObj" class="app-wrapper" v-loading="loading" :element-loading-text="loadingText" fullscreen>
<div v-if="classObj.mobile && classObj.openSidebar" class="drawer-bg" @click="handleClickOutside" />
<div class="app-sidebar" v-if="!globalStore.isFullScreen">
<Sidebar @menu-click="handleMenuClick" :menu-router="!classObj.openMenuTabs" />
</div>
<div class="main-container">
<mobile-header v-if="classObj.mobile" />
<Tabs v-if="classObj.openMenuTabs" />
<app-main :keep-alive="classObj.openMenuTabs ? tabsStore.cachedTabs : null" class="app-main" />
<Footer class="app-footer" v-if="!globalStore.isFullScreen" />
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, computed, ref, watch, onBeforeUnmount } from 'vue';
import { Sidebar, Footer, AppMain, MobileHeader, Tabs } from './components';
import useResize from './hooks/useResize';
import { GlobalStore, MenuStore, TabsStore } from '@/store';
import { DeviceType } from '@/enums/app';
import { getSystemAvailable } from '@/api/modules/setting';
import { useRoute, useRouter } from 'vue-router';
import { loadProductProFromDB } from '@/utils/xpack';
import { useTheme } from '@/hooks/use-theme';
const { switchTheme } = useTheme();
useResize();
const router = useRouter();
const route = useRoute();
const menuStore = MenuStore();
const globalStore = GlobalStore();
const tabsStore = TabsStore();
const loading = ref(false);
const loadingText = ref();
let timer: NodeJS.Timer | null = null;
const classObj = computed(() => {
return {
fullScreen: globalStore.isFullScreen,
hideSidebar: menuStore.isCollapse,
openSidebar: !menuStore.isCollapse,
mobile: globalStore.device === DeviceType.Mobile,
openMenuTabs: globalStore.openMenuTabs,
withoutAnimation: menuStore.withoutAnimation,
};
});
const handleClickOutside = () => {
menuStore.closeSidebar(false);
};
watch(
() => globalStore.isLoading,
() => {
if (globalStore.isLoading) {
loadStatus();
} else {
loading.value = globalStore.isLoading;
}
},
);
const handleMenuClick = async (path) => {
await router.push({ path: path });
tabsStore.addTab(route);
tabsStore.activeTabPath = route.path;
};
const loadStatus = async () => {
loading.value = globalStore.isLoading;
loadingText.value = globalStore.loadingText;
if (loading.value) {
timer = setInterval(async () => {
await getSystemAvailable()
.then((res) => {
if (res) {
location.reload();
clearInterval(Number(timer));
timer = null;
}
})
.catch(() => {
location.reload();
clearInterval(Number(timer));
timer = null;
});
}, 1000 * 10);
}
};
onBeforeUnmount(() => {
clearInterval(Number(timer));
timer = null;
});
onMounted(() => {
if (globalStore.openMenuTabs && !tabsStore.activeTabPath) {
handleMenuClick('/');
}
loadStatus();
loadProductProFromDB();
const mqList = window.matchMedia('(prefers-color-scheme: dark)');
if (mqList.addEventListener) {
mqList.addEventListener('change', () => {
switchTheme();
});
} else if (mqList.addListener) {
mqList.addListener(() => {
switchTheme();
});
}
});
</script>
<style scoped lang="scss">
.app-wrapper {
position: relative;
width: 100%;
}
.drawer-bg {
background-color: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
.main-container {
display: flex;
flex-direction: column;
position: relative;
height: 100vh;
transition: margin-left 0.3s;
margin-left: var(--panel-menu-width);
background-color: #f4f4f4;
overflow-x: hidden;
}
.app-main {
padding: 20px;
flex: 1;
overflow: auto;
}
.app-sidebar {
transition: width 0.3s;
width: var(--panel-menu-width) !important;
position: fixed;
font-size: 0px;
top: 0;
bottom: 0;
left: 0;
overflow: hidden;
}
.hideSidebar {
.main-container {
margin-left: var(--panel-menu-hide-width);
}
.app-sidebar {
width: var(--panel-menu-hide-width) !important;
}
.fixed-header {
width: calc(100% - var(--panel-menu-hide-width));
}
}
.fullScreen {
.main-container {
margin-left: 0px;
}
}
// for mobile response 适配移动端
.mobile {
.main-container {
margin-left: 0px;
}
.app-sidebar {
transition: transform 0.3s;
width: var(--panel-menu-width) !important;
background: #ffffff;
z-index: 9999;
}
.app-footer {
display: block;
text-align: center;
}
&.openSidebar {
position: fixed;
top: 0;
}
&.hideSidebar {
.app-sidebar {
pointer-events: none;
transition-duration: 0.3s;
transform: translate3d(calc(0px - var(--panel-menu-width)), 0, 0);
}
}
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
}
}
</style>