@@@@@@
This commit is contained in:
76
library/layouts/VabLayoutColumn/index.vue
Normal file
76
library/layouts/VabLayoutColumn/index.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div
|
||||
class="vab-layout-column"
|
||||
:class="{
|
||||
fixed: fixedHeader,
|
||||
'no-tabs-bar': !showTabs,
|
||||
}"
|
||||
>
|
||||
<vab-column-bar />
|
||||
<div
|
||||
class="vab-main"
|
||||
:class="{
|
||||
['vab-main-' + theme.columnStyle]: true,
|
||||
'is-collapse-main': collapse,
|
||||
'is-no-tabs': !showTabs,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="vab-layout-header"
|
||||
:class="{
|
||||
'fixed-header': fixedHeader,
|
||||
'is-no-tabs': !showTabs,
|
||||
}"
|
||||
>
|
||||
<vab-nav />
|
||||
<vab-tabs v-show="showTabs" />
|
||||
</div>
|
||||
<vab-app-main />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useSettingsStore } from '/@/store/modules/settings'
|
||||
|
||||
defineOptions({
|
||||
name: 'VabLayoutColumn',
|
||||
})
|
||||
|
||||
defineProps({
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
fixedHeader: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showTabs: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
})
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
const { theme } = storeToRefs(settingsStore)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vab-layout-column {
|
||||
.vab-main {
|
||||
&.is-collapse-main {
|
||||
&.vab-main-horizontal,
|
||||
&.vab-main-semicircle {
|
||||
margin-left: calc(var(--el-left-menu-width-min) * 1.4);
|
||||
|
||||
:deep() {
|
||||
.fixed-header {
|
||||
width: calc(100% - var(--el-left-menu-width-min) * 1.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
70
library/layouts/VabLayoutFall/index.vue
Normal file
70
library/layouts/VabLayoutFall/index.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div
|
||||
class="vab-layout-fall"
|
||||
:class="{
|
||||
fixed: fixedHeader,
|
||||
'no-tabs-bar': !showTabs,
|
||||
}"
|
||||
>
|
||||
<vab-fall-bar />
|
||||
<div
|
||||
class="vab-main"
|
||||
:class="{
|
||||
'is-collapse-main': collapse,
|
||||
'is-no-tabs': !showTabs,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="vab-layout-header"
|
||||
:class="{
|
||||
'fixed-header': fixedHeader,
|
||||
'is-no-tabs': !showTabs,
|
||||
}"
|
||||
>
|
||||
<vab-nav />
|
||||
<vab-tabs v-show="showTabs" />
|
||||
</div>
|
||||
<vab-app-main />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineOptions({
|
||||
name: 'VabLayoutFall',
|
||||
})
|
||||
|
||||
defineProps({
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
fixedHeader: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showTabs: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vab-layout-fall {
|
||||
.vab-main {
|
||||
&.is-collapse-main {
|
||||
&.vab-main-horizontal,
|
||||
&.vab-main-semicircle {
|
||||
margin-left: calc(var(--el-left-menu-width-min) * 1.4);
|
||||
|
||||
:deep() {
|
||||
.fixed-header {
|
||||
width: calc(100% - var(--el-left-menu-width-min) * 1.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
61
library/layouts/VabLayoutVertical/index.vue
Normal file
61
library/layouts/VabLayoutVertical/index.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div
|
||||
class="vab-layout-vertical"
|
||||
:class="{
|
||||
fixed: fixedHeader,
|
||||
'no-tabs-bar': !showTabs,
|
||||
}"
|
||||
>
|
||||
<vab-side-bar />
|
||||
<div v-if="device === 'mobile' && !collapse" class="vab-modal" @click="foldSideBar"></div>
|
||||
<div
|
||||
class="vab-main"
|
||||
:class="{
|
||||
'is-collapse-main': collapse,
|
||||
'is-no-tabs': !showTabs,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="vab-layout-header"
|
||||
:class="{
|
||||
'fixed-header': fixedHeader,
|
||||
'is-no-tabs': !showTabs,
|
||||
}"
|
||||
>
|
||||
<vab-nav />
|
||||
<vab-tabs v-show="showTabs" />
|
||||
</div>
|
||||
<vab-app-main />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useSettingsStore } from '/@/store/modules/settings'
|
||||
|
||||
defineOptions({
|
||||
name: 'VabLayoutVertical',
|
||||
})
|
||||
|
||||
defineProps({
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
fixedHeader: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showTabs: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
device: {
|
||||
type: String,
|
||||
default: 'desktop',
|
||||
},
|
||||
})
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
const { foldSideBar } = settingsStore
|
||||
</script>
|
||||
176
library/layouts/index.vue
Normal file
176
library/layouts/index.vue
Normal file
@@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<el-scrollbar ref="scrollbarRef" wrap-class="scroll-wrap">
|
||||
<div class="school-apartment-box" :class="{ mobile }">
|
||||
<component :is="layout" :collapse="collapse" :device="device" :fixed-header="theme.fixedHeader" :show-tabs="theme.showTabs" />
|
||||
</div>
|
||||
<vab-statistics />
|
||||
<el-backtop target="#app .scroll-wrap" />
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElScrollbar } from 'element-plus'
|
||||
import { useSettingsStore } from '/@/store/modules/settings'
|
||||
import { useUserStore } from '/@/store/modules/user'
|
||||
import { convertToCamelCase } from '/@/utils/convertToCamelCase'
|
||||
|
||||
defineOptions({
|
||||
name: 'Layout',
|
||||
})
|
||||
|
||||
interface ComponentType {
|
||||
default: Component
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>()
|
||||
const userStore = useUserStore()
|
||||
const { username } = storeToRefs(userStore)
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
const { device, collapse, theme } = storeToRefs(settingsStore)
|
||||
const { toggleDevice, foldSideBar, openSideBar, updateTheme } = settingsStore
|
||||
const mobile = ref(false)
|
||||
let oldLayout = theme.value.layout
|
||||
const visibility = useDocumentVisibility()
|
||||
const imports = import.meta.glob<ComponentType>('./**/*.vue', { eager: true })
|
||||
const Components: Record<string, Component> = {}
|
||||
Object.getOwnPropertyNames(imports).forEach((key: any) => {
|
||||
Components[key.replaceAll(/(\/|\.|index.vue)/g, '')] = imports[key].default
|
||||
})
|
||||
|
||||
const layout = computed(() => Components[convertToCamelCase(`vab-layout-${theme.value.layout}`)])
|
||||
|
||||
const resizeBody = () => {
|
||||
const { width } = useWindowSize()
|
||||
mobile.value = width.value - 1 < 992
|
||||
}
|
||||
|
||||
watch(mobile, (value) => {
|
||||
if (value) {
|
||||
oldLayout = theme.value.layout
|
||||
foldSideBar()
|
||||
} else openSideBar()
|
||||
theme.value.layout = value ? 'vertical' : oldLayout
|
||||
toggleDevice(value ? 'mobile' : 'desktop')
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
resizeBody()
|
||||
window.addEventListener('resize', resizeBody)
|
||||
updateTheme()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (mobile.value) theme.value.layout = oldLayout
|
||||
window.removeEventListener('resize', resizeBody)
|
||||
})
|
||||
|
||||
watch(visibility, (current, previous) => {
|
||||
if (current === 'visible' && previous === 'hidden') $baseNotify(`尊敬的${username.value},欢迎回来`, '', 'success', 'bottom-right')
|
||||
})
|
||||
|
||||
watch(
|
||||
route,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
scrollbarRef.value!.setScrollTop(0)
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-scrollbar__view.scroll-view {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.school-apartment-box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
[class*='vab-layout-'] {
|
||||
:deep() {
|
||||
.vab-layout-header {
|
||||
border-bottom: 1px solid var(--el-border-color);
|
||||
|
||||
&.is-no-tabs {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.fixed {
|
||||
padding-top: calc(var(--el-nav-height) + var(--el-tabs-height));
|
||||
}
|
||||
|
||||
&.fixed.no-tabs-bar {
|
||||
padding-top: var(--el-nav-height);
|
||||
}
|
||||
}
|
||||
|
||||
:deep() {
|
||||
.fixed-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: calc(var(--el-z-index) - 1);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vab-main {
|
||||
position: relative;
|
||||
width: auto;
|
||||
min-height: 100%;
|
||||
margin-left: var(--el-left-menu-width);
|
||||
|
||||
&.is-collapse-main {
|
||||
margin-left: var(--el-left-menu-width-min);
|
||||
|
||||
.fixed-header {
|
||||
width: var(--el-right-content-width-min);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.is-collapse-main) {
|
||||
.fixed-header {
|
||||
width: calc(100% - var(--el-left-menu-width));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机端开始 */
|
||||
&.mobile {
|
||||
:deep() {
|
||||
.vab-layout-vertical {
|
||||
.el-scrollbar.vab-side-bar {
|
||||
z-index: calc(var(--el-z-index) + 1);
|
||||
|
||||
&.is-collapse {
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.vab-main {
|
||||
.fixed-header {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 隐藏分页和页码跳转 */
|
||||
.el-pager,
|
||||
.el-pagination__jump {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机端结束 */
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user