Files
sunProduct/src/layout/index.vue
2026-09-20 08:57:53 +08:00

174 lines
4.3 KiB
Vue

<template>
<!-- 👇 加这一层全局缩放容器 -->
<div :class="classObj" :style="{ '--current-color': theme }" class="app-wrapper">
<side-bar class="sidebar-container" />
<div id="main-container" :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
<div class="navbarContant">
<navbar ref="navbarRef" @set-layout="setLayout" />
</div>
<app-main />
<i v-if="bgColorStore.isShow" class="bgColor"></i>
<settings ref="settingRef" />
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, watchEffect, onMounted, onUnmounted } from 'vue';
import { useWindowSize } from '@vueuse/core';
import SideBar from './components/Sidebar/index.vue';
import { AppMain, Navbar, Settings } from './components';
import { useAppStore } from '@/store/modules/app';
import { useSettingsStore } from '@/store/modules/settings';
import { useBgColor } from '@/store/modules/bgColor';
import { initWebSocket, closeWebSocket } from '@/utils/websocket'; // 新增 closeWebSocket
import { initSSE, closeSSE } from '@/utils/sse'; // 引入 closeSSE
const bgColorStore = useBgColor();
// ======================缩放逻辑======================
const scale = ref(1);
const DESIGN_WIDTH = 1920;
const calcScale = () => {
const width = document.documentElement.clientWidth;
let ratio = width / DESIGN_WIDTH;
if (ratio < 0.7) ratio = 0.7;
if (ratio > 1) ratio = 1;
scale.value = ratio;
};
let timer: number | null = null;
const resize = () => {
clearTimeout(timer);
timer = window.setTimeout(calcScale, 100);
};
// ======================生命周期======================
onMounted(() => {
calcScale();
window.addEventListener('resize', resize);
// WebSocket
const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket');
// SSE
initSSE(import.meta.env.VITE_APP_BASE_API + '/resource/sse');
});
onUnmounted(() => {
window.removeEventListener('resize', resize);
if (timer) clearTimeout(timer);
closeWebSocket();
closeSSE();
});
// ======================原有业务逻辑======================
const settingsStore = useSettingsStore();
const theme = computed(() => settingsStore.theme);
const sidebar = computed(() => useAppStore().sidebar);
const device = computed(() => useAppStore().device);
const needTagsView = computed(() => settingsStore.tagsView);
const classObj = computed(() => ({
hideSidebar: !sidebar.value.opened,
openSidebar: sidebar.value.opened,
withoutAnimation: sidebar.value.withoutAnimation,
mobile: device.value === 'mobile'
}));
const { width } = useWindowSize();
const WIDTH = 992;
watchEffect(() => {
if (device.value === 'mobile') {
useAppStore().closeSideBar({ withoutAnimation: false });
}
if (width.value - 1 < WIDTH) {
useAppStore().toggleDevice('mobile');
useAppStore().closeSideBar({ withoutAnimation: true });
} else {
useAppStore().toggleDevice('desktop');
}
});
const navbarRef = ref<InstanceType<typeof Navbar>>();
const settingRef = ref<InstanceType<typeof Settings>>();
const setLayout = () => {
settingRef.value?.openSetting();
};
</script>
<style lang="scss" scoped>
@use '@/assets/styles/mixin.scss';
@use '@/assets/styles/variables.module.scss' as *;
.app-wrapper {
@include mixin.clearfix;
position: relative;
height: 100%;
width: 100%;
display: flex;
align-items: center;
&.mobile.openSidebar {
position: fixed;
top: 0;
}
}
.main-container {
flex: 1;
background-color: #dfedff;
}
.navbarContant {
position: relative;
z-index: 100;
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$base-sidebar-width});
transition: width 0.28s;
background: $fixed-header-bg;
}
.hideSidebar .fixed-header {
width: calc(100% - 54px);
}
.sidebarHide .fixed-header {
width: 100%;
}
.mobile .fixed-header {
width: 100%;
}
.bgColor {
width: 850px;
height: 850px;
background: #fdf1ee;
filter: blur(200px);
display: block;
position: absolute;
top: -50%;
right: -10%;
pointer-events: none;
z-index: 1;
border-radius: 50%;
}
</style>