Files
Situation-Awareness-Platfor…/src/layouts/DefaultLayout/index.vue
2025-03-21 11:00:56 +08:00

212 lines
7.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<d-layout class="d-layout h-full" :class="{ 'home-background': isHome }">
<d-header class="d-header">
<!-- header -->
<Header @clickMenu="handleClickMenu" :asideSetShow="asideSetShow" ref="refHeader">
<!-- 二级导航左侧内容 -->
<template v-if="$slots.headerLeft && !route?.meta?.hideNav" #info>
<slot name="headerLeft"></slot>
</template>
<!-- 二级导航右侧内容 -->
<template v-if="$slots.headerRight && !route?.meta?.hideNav" #menu>
<slot name="headerRight"></slot>
</template>
<template v-if="$slots.bodyHeader && !route?.meta?.hideNav" #bodyHeader>
<slot name="bodyHeader"></slot>
</template>
<template v-if="$slots.headerBottom && !route?.meta?.hideNav" #headerBottom>
<slot name="headerBottom"></slot>
</template>
</Header>
</d-header>
<!-- 顶栏信息 -->
<div v-if="$slots.contentBanner">
<slot name="contentBanner"></slot>
</div>
<!-- 主体 -->
<d-layout class="flex-col">
<d-aside class="left-side-bar" v-if="asideSetShow" :style="{ width: mainMarginLeftWidth + 'px' }">
<Aside :asideDefaultWidth="mainMarginLeftWidth"></Aside>
</d-aside>
<d-drawer v-model="asideVisible" position="left" lock-scroll style="max-height: 100%; top: 0;"
:style="{ width: '240px', overflowY: 'hidden' }">
<div class="p-[16px] flex justify-between items-center h-[60px]">
<GLink class="g-toolbar-left-logo" href="/" />
<d-icon class="cursor-pointer" name="close" @click="asideVisible = false"></d-icon>
</div>
<Aside :asideDefaultWidth="240" @on-select="handleClickMenu" style="height: calc(100% - 60px);padding-top: 0px;"></Aside>
</d-drawer>
<d-layout :style="{ marginLeft: mainMarginLeftWidth + 'px', transition: 'margin-left ease 0.1s' }">
<d-layout :class="responsiveClass" :style="{ minHeight: `calc(100% - ${footerSize?.height.value || 0}px)` }">
<!-- sidebar -->
<d-aside class="d-aside mr-[32px] pt-24" v-if="route?.meta?.sidebarType">
<slot name="sidebar"></slot>
</d-aside>
<!-- 内容 -->
<d-content>
<slot name="content">
<RouterView />
</slot>
</d-content>
</d-layout>
<!-- footer -->
<!-- <d-footer v-if="!route?.meta?.hiddenFooter" ref="refFooter">
<slot name="footer">
<Footer />
</slot>
</d-footer> -->
</d-layout>
</d-layout>
<!-- 浮动工具栏移动端不显示 -->
<!-- <ToolsFloat v-if="showToolsFloat" />-->
</d-layout>
</template>
<script setup lang="ts">
defineOptions({ name: 'DefaultLayout' });
import { RouterView, useRoute, useRouter } from 'vue-router';
import { computed, ref, watch, watchEffect, onMounted, onUnmounted } from 'vue';
import Header from '@/components/Header/index.vue';
import Footer from '@/components/Footer/index.vue';
import Aside from './aside.vue';
import { useGlobalInfoStore } from '@/stores/Global';
import ToolsFloat from '@/components/ToolsFloat/index.vue';
import { useStorage, useElementSize } from '@vueuse/core';
import { usePageResize } from '@/utils/hooks/usePageResize';
import microApp from '@micro-zoe/micro-app';
defineProps<{ customAside?: boolean; }>();
const router = useRouter();
const solt = defineSlots();
const sizeStore = usePageResize();
const globalStore = useGlobalInfoStore();
const route = useRoute();
const asideVisible = ref(false);
const refFooter = ref(null);
const refHeader: any = ref(null);
const footerSize = useElementSize(refFooter);
const isHome = computed(() => route.name === 'home');
// aside 设置可见性 header有两层有顶栏信息,两层sidebar 都不可见
const asideSetShow = computed(() => {
if (route.meta.asideMenu === 'drawer') return false;
return refHeader.value?.height <= 56 && !solt.contentBanner && !route.meta.sidebarType;
});
const emit = defineEmits<{
clickMenu: [];
}>();
watch(route, () => {
globalStore.setIsNotFound(false); // 切换路由默认不显示404防止一直显示404
}, { deep: true });
const asideDefaultWidth = useStorage('asideDefaultWidth', sizeStore.isMobile.value ? 0 : 240);
const mainMarginLeftWidth = computed(() => {
if (!asideSetShow.value || sizeStore.isMobile.value) {
return 0;
} else {
return asideDefaultWidth.value;
}
});
// 是否展示浮动工具栏(非移动端 || 未设置隐藏)
const showToolsFloat = computed(() => {
return sizeStore.widthType.value !== 'sm' && !route.meta.hiddenToolsFloat;
});
const responsiveClass = computed(() => { // 控制移动和pc布局
let className = 'm-auto max-w-normal px-normal w-full';
let viewportContent = 'width=device-width,initial-scale=0,user-scalable=yes,maximum-scale=1.0';
if (sizeStore.isMobile.value) { // 设备是否为手机
if (route?.meta?.hasMobile) { // 是否有手机端页面
className = 'w-full';
viewportContent = 'width=device-width, initial-scale=1.0';
}
} else {
if (route?.meta?.className) {
className = `${route?.meta?.className as string}`;
}
if (route.name === 'homepage' && globalStore.namespaceType === 1) { // 组织主页样式特殊处理
className = 'm-auto min-w-sm px-normal max-w-[1280px] w-full pt-[12px]';
}
}
document?.querySelector("meta[name='viewport']")?.setAttribute('content', viewportContent);
return className;
});
const handleClickMenu = () => {
if (sizeStore.isMobile.value || !asideSetShow.value) { // 不可见时弹框
asideVisible.value = !asideVisible.value;
} else { // 可见时收起
asideDefaultWidth.value = asideDefaultWidth.value >= 240 ? 0 : 240;
}
};
const outOfSearch = ref(true); // 在search页面隐藏footer
router.afterEach((to, form) => {
outOfSearch.value = to.name !== 'search';
});
microApp.router.afterEach({
'micoro-app-homeweb-app': (to, from) => {
outOfSearch.value = to.pathname !== '/search';
}
});
const checkPage = (data: any) => {
if (data.type === 'checkPage') {
return 'ready';
}
};
onMounted(() => {
microApp.addDataListener('micoro-app-homeweb-app', checkPage, false);
});
onUnmounted(() => {
microApp.removeDataListener('micoro-app-homeweb-app', checkPage);
});
</script>
<style lang="scss" scoped>
.left-side-bar {
position: fixed;
left: 0;
bottom: 0;
top: 56px;
background-color: #fff;
z-index: 10;
border-right: 1px solid #F1F1F8;
overflow-y: auto;
overflow-x: hidden;
transition: width ease 0.1s;
}
.g-toolbar-left-logo {
display: inline-block;
width: 102px;
height: 28px;
background: url(../../assets/imgs/logo/logo.png) no-repeat;
background-size: contain;
vertical-align: middle;
background-position: 0 center;
}
.home-background {
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 1)),url('@/assets/imgs/home/bg.png');
background-size: cover;
background-position: center;
z-index: -1;
}
}
</style>