Files
education/frontend/src/layout/index.vue
T
2026-08-23 16:12:57 +08:00

200 lines
4.7 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>
<div :class="classObj" class="app-wrapper" :style="{'--current-color': '#00875A', '--current-color-light': '#00875A1a', '--current-color-dark-bg': '#00875A33'}">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<!-- 顶部全宽 Header -->
<div class="top-header">
<div class="top-header__left">
<hamburger
v-if="device === 'mobile'"
id="mobile-hamburger"
:is-active="sidebar.opened"
class="mobile-hamburger"
@toggleClick="toggleSideBar"
/>
<span class="sys-title" title="关闭所有已打开的页签" @click="handleCloseAllTabs">教学管理信息系统</span>
</div>
<semester-bar class="top-header__center" />
<navbar class="top-header__right" :header-mode="true" />
</div>
<!-- 下方侧边栏 + 主内容 -->
<div class="lower-container" :class="{sidebarHide:sidebar.hide}">
<sidebar v-if="!sidebar.hide" class="sidebar-container"/>
<div :class="{hasTagsView:true,sidebarHide:sidebar.hide}" class="main-container">
<tags-view/>
<app-main/>
</div>
</div>
</div>
</template>
<script>
import { AppMain, Navbar, Sidebar, TagsView } from './components'
import SemesterBar from './components/SemesterBar'
import Hamburger from '@/components/Hamburger'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
import variables from '@/assets/styles/variables.scss'
export default {
name: 'Layout',
components: {
AppMain,
Navbar,
Sidebar,
TagsView,
SemesterBar,
Hamburger
},
mixins: [ResizeMixin],
computed: {
...mapState({
sidebar: state => state.app.sidebar,
device: state => state.app.device
}),
classObj() {
return {
hideSidebar: !this.sidebar.opened,
mobile: this.device === 'mobile'
}
},
variables() {
return variables
}
},
methods: {
handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
},
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
handleCloseAllTabs() {
this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
const last = visitedViews[visitedViews.length - 1]
if (last) {
this.$router.push(last.fullPath).catch(() => {})
} else {
this.$router.push('/').catch(() => {})
}
})
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/assets/styles/mixin.scss";
@import "~@/assets/styles/variables.scss";
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
/* 顶部全宽 Header */
.top-header {
flex-shrink: 0;
height: 60px;
display: flex;
align-items: center;
background: var(--edu-green-primary);
background: linear-gradient(90deg, var(--edu-green-primary) 0%, var(--edu-green-dark) 100%);
box-shadow: 0 2px 8px rgba(0, 21, 41, 0.16);
padding: 0 20px;
z-index: 10;
&__left {
display: flex;
align-items: center;
flex-shrink: 0;
height: 100%;
gap: 14px;
.mobile-hamburger {
display: flex;
align-items: center;
justify-content: center;
height: 36px;
width: 36px;
border-radius: 8px;
cursor: pointer;
color: #fff;
transition: background 0.25s ease;
&:hover {
background: rgba(255, 255, 255, 0.15);
}
}
.sys-title {
font-size: 19px;
font-weight: 700;
color: #fff;
white-space: nowrap;
letter-spacing: 1.5px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
cursor: pointer;
border-radius: 6px;
padding: 4px 10px;
transition: background 0.25s ease;
&:hover {
background: rgba(255, 255, 255, 0.15);
}
}
}
&__center {
flex: 1;
min-width: 0;
display: flex;
justify-content: center;
height: 100%;
}
&__right {
flex-shrink: 0;
height: 100%;
}
}
/* 下方主体 */
.lower-container {
flex: 1;
min-height: 0;
display: flex;
position: relative;
}
.sidebar-container {
flex-shrink: 0;
}
.main-container {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
height: 100%;
background-color: #f5f7fa;
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
</style>