| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- <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 />
- </div>
- </div>
- <!-- <el-back-top :right="100" /> -->
- </div>
- </div>
- <div class="admin-layout-shade"></div>
- <InvalidAuth />
- </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 { 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';
- import InvalidAuth from '@/components/InvalidAuth/InvalidAuth.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(() => {
- 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);
- &-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: 12px 12px 0 12px;
- 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: #2d8cf0;
- --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>
|