smart-village-web/src/layout/side-layout.vue
2025-04-30 18:37:55 +08:00

439 lines
12 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>
<a-layout class="admin-layout" style="min-height: 100%">
<div class="village-select" @click="villageModalVisible = true" v-if="!useUserStore().administratorFlag && !useUserStore().backAdministratorFlag">
<span>{{ useUserStore().getCurrentVillageName }}</span>
<SwapOutlined />
<village-select-modal v-model:visible="villageModalVisible" @success="query" />
</div>
<!-- 顶部头部信息 -->
<a-layout-header class="layout-header" :id="LAYOUT_ELEMENT_IDS.header" v-show="!fullScreenFlag">
<a-row class="layout-header-user" justify="space-between">
<a-col class="layout-header-left">
<!-- 1、顶部logo区域 -->
<div class="logo" @click="goHome">
<img class="logo-img" :src="logoImg" />
<div class="title smart-logo title-light">{{ websiteName }}</div>
</div>
<!-- <span class="collapsed-button">
<menu-unfold-outlined v-if="collapsed" class="trigger" @click="() => (collapsed = !collapsed)" />
<menu-fold-outlined v-else class="trigger" @click="() => (collapsed = !collapsed)" />
</span> -->
<!-- <a-tooltip placement="bottom">
<template #title>首页</template>
<span class="home-button" @click="goHome">
<home-outlined class="trigger" />
</span>
</a-tooltip> -->
<!-- <span class="location-breadcrumb">
<MenuLocationBreadcrumb />
</span> -->
</a-col>
<a-col class="layout-header-center" v-if="!useUserStore().administratorFlag && !useUserStore().backAdministratorFlag">
<!-- <div class="module-menu-container"> -->
<ModuleMenu />
<!-- </div> -->
</a-col>
<!---用戶操作区域-->
<a-col class="layout-header-right">
<HeaderUserSpace />
</a-col>
</a-row>
</a-layout-header>
<!--中间内容一共三部分1、顶部;2、中间内容区域;3、底部一般是公司版权信息;-->
<a-layout :id="LAYOUT_ELEMENT_IDS.main" class="admin-layout-main">
<!-- 侧边菜单 side-menu -->
<a-layout-sider
:id="LAYOUT_ELEMENT_IDS.menu"
class="side-menu"
:width="sideMenuWidth"
:collapsed="collapsed"
:theme="sideMenuTheme"
v-show="!fullScreenFlag"
>
<div class="module-title" v-if="moduleName">
{{ moduleName }}
</div>
<a-scrollbar>
<!-- 左侧菜单 -->
<SideMenu :collapsed="collapsed" />
</a-scrollbar>
</a-layout-sider>
<!--中间内容-->
<a-layout>
<PageTag />
<a-layout-content :id="LAYOUT_ELEMENT_IDS.content" class="admin-layout-content">
<!--不keepAlive的iframe使用单个iframe组件-->
<IframeIndex v-if="iframeNotKeepAlivePageFlag" :key="route.name" :name="route.name" :url="route.meta.frameUrl" />
<!--keepAlive的iframe 每个页面一个iframe组件-->
<IframeIndex
v-for="item in keepAliveIframePages"
v-show="route.name === item.name"
:key="item.name"
:name="item.name"
:url="item.meta.frameUrl"
/>
<!--非iframe使用router-view-->
<div class="height100" v-show="!iframeNotKeepAlivePageFlag && keepAliveIframePages.every((e) => route.name != e.name)">
<router-view v-slot="{ Component }">
<keep-alive :include="keepAliveIncludes">
<component :is="Component" :key="route.name" />
</keep-alive>
</router-view>
</div>
</a-layout-content>
<!-- footer 版权公司信息 -->
<!-- <a-layout-footer class="layout-footer" v-show="footerFlag">
<smart-footer />
</a-layout-footer> -->
<!--- 回到顶部 -->
<a-back-top :target="backTopTarget" :visibilityHeight="80" />
<Task />
</a-layout>
</a-layout>
<!-- 右侧帮助文档 help-doc -->
<a-layout-sider
v-if="helpDocFlag"
v-show="helpDocExpandFlag"
theme="light"
:width="180"
class="help-doc-sider"
:trigger="null"
style="min-height: 100%"
>
<SideHelpDoc />
</a-layout-sider>
</a-layout>
</template>
<script setup>
import { computed, onMounted, ref, watch } from 'vue';
import { useAppConfigStore } from '../store/modules/system/app-config';
import logoImg from '/@/assets/images/logo/logo-xc.png';
import HeaderUserSpace from './components/header-user-space/index.vue';
import ModuleMenu from './components/module-menu/index.vue';
import MenuLocationBreadcrumb from './components/menu-location-breadcrumb/index.vue';
import PageTag from './components/page-tag/index.vue';
import SideMenu from './components/side-menu/index.vue';
import SmartFooter from './components/smart-footer/index.vue';
import { smartKeepAlive } from './components/smart-keep-alive';
import IframeIndex from '/@/components/framework/iframe/iframe-index.vue';
import watermark from '../lib/smart-watermark';
import { useUserStore } from '/@/store/modules/system/user';
import SideHelpDoc from './components/side-help-doc/index.vue';
import { useRouter } from 'vue-router';
import { HOME_PAGE_NAME } from '/@/constants/system/home-const';
import { LAYOUT_ELEMENT_IDS } from '/@/layout/layout-const.js';
import { theme } from 'ant-design-vue';
import { SwapOutlined } from '@ant-design/icons-vue';
import Task from './components/task/index.vue';
import VillageSelectModal from '/@/views/system/homePage/components/VillageSelectModal.vue';
const villageModalVisible = ref(false);
const windowHeight = ref(window.innerHeight);
//是否全屏
const fullScreenFlag = computed(() => useAppConfigStore().$state.fullScreenFlag);
//菜单宽度
const websiteName = computed(() => useAppConfigStore().websiteName);
const sideMenuWidth = computed(() => useAppConfigStore().sideMenuWidth + 'px');
//主题颜色
const sideMenuTheme = computed(() => useAppConfigStore().$state.sideMenuTheme);
//是否显示标签页
const pageTagFlag = computed(() => useAppConfigStore().$state.pageTagFlag);
// 是否显示帮助文档
const helpDocFlag = computed(() => useAppConfigStore().$state.helpDocFlag);
// 是否默认展开帮助文档
const helpDocExpandFlag = computed(() => useAppConfigStore().$state.helpDocExpandFlag);
// 是否显示页脚
const footerFlag = computed(() => useAppConfigStore().$state.footerFlag);
// 是否显示水印
const watermarkFlag = computed(() => useAppConfigStore().$state.watermarkFlag);
// 多余高度
const dueHeight = computed(() => {
let due = 40;
if (useAppConfigStore().$state.pageTagFlag) {
due = due + 40;
}
if (useAppConfigStore().$state.footerFlag) {
due = due + 40;
}
return due;
});
const moduleName = computed(() => useUserStore().getModuleName);
//是否隐藏菜单
const collapsed = ref(false);
//页面初始化的时候加载水印
onMounted(() => {
if (watermarkFlag.value) {
watermark.set(LAYOUT_ELEMENT_IDS.content, useUserStore().actualName);
} else {
watermark.clear();
}
});
watch(
() => watermarkFlag.value,
(newValue) => {
if (newValue) {
watermark.set(LAYOUT_ELEMENT_IDS.content, useUserStore().actualName);
} else {
watermark.clear();
}
}
);
const color = computed(() => {
let isLight = useAppConfigStore().$state.sideMenuTheme === 'light';
return {
background: isLight ? '#FFFFFF' : '#001529',
};
});
//回到顶部
const backTopTarget = () => {
return document.getElementById(LAYOUT_ELEMENT_IDS.main);
};
const router = useRouter();
function goHome() {
router.push({ name: HOME_PAGE_NAME });
}
window.addEventListener('resize', function () {
windowHeight.value = window.innerHeight;
});
const { useToken } = theme;
const { token } = useToken();
const borderRadius = token.value.borderRadius + 'px';
// ----------------------- keep-alive相关 -----------------------
let { route, keepAliveIncludes, iframeNotKeepAlivePageFlag, keepAliveIframePages } = smartKeepAlive();
</script>
<style lang="less" scoped>
:deep(.ant-layout-header) {
height: auto;
}
:deep(.layout-header) {
height: auto;
}
.module-title {
height: 50px;
line-height: 50px;
background-color: #20b066;
color: #ffffff;
font-size: 16px;
font-weight: bold;
padding-left: 10px;
text-align: center;
// border-radius: 16px 16px 0 0;
border-radius: v-bind(borderRadius) v-bind(borderRadius) 0 0;
}
.layout-header {
background: #fff;
padding: 0;
z-index: 21;
}
.layout-header-user {
// height: @header-user-height;
height: @header-height;
align-items: center;
border-bottom: 1px solid #f6f6f6;
background-color: #20b066;
color: #fff;
}
.layout-header-left {
display: flex;
height: @header-user-height;
.collapsed-button {
margin-left: 10px;
line-height: @header-user-height;
}
.home-button {
margin-left: 15px;
cursor: pointer;
padding: 0 5px;
line-height: @header-user-height;
}
.home-button:hover {
// background-color: #efefef;
background-color: @hover-bg-color;
}
.location-breadcrumb {
margin-left: 15px;
line-height: @header-user-height;
}
}
.layout-header-center {
display: flex;
flex: 1;
justify-content: flex-end;
margin: 0 10px;
height: @header-height;
line-height: @header-height;
.module-menu-container {
display: flex;
justify-content: flex-end;
}
}
.layout-header-right {
display: flex;
height: @header-user-height;
}
.layout-container {
height: calc(100vh - @header-height);
overflow-x: hidden;
}
.admin-layout {
.side-menu {
height: calc(100vh - @header-height - 20px);
// overflow-x: hidden;
// overflow-y: scroll;
border-radius: v-bind(borderRadius) v-bind(borderRadius) 0 0;
&.fixed-side {
position: fixed;
height: calc(100vh - @header-height);
left: 0;
top: 0;
}
}
.side-menu::-webkit-scrollbar {
width: 4px;
}
.side-menu::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(0, 0, 0, 0.2);
}
.side-menu::-webkit-scrollbar-track {
border-radius: 0;
background: rgba(0, 0, 0, 0.1);
}
.help-doc-sider {
flex: 0 !important;
min-width: 100px;
height: 100vh;
max-width: 100px;
width: auto !important;
&.fixed-side {
position: fixed;
height: 100vh;
right: 0;
top: 0;
}
}
.virtual-side {
transition: all 0.2s;
}
.virtual-header {
transition: all 0.2s;
opacity: 0;
&.fixed-tabs.multi-page:not(.fixed-header) {
height: 0;
}
}
.admin-layout-main {
overflow-y: hidden;
overflow-x: hidden;
height: calc(100vh - @header-height);
padding: 20px 0 0 20px;
box-sizing: border-box;
}
.admin-layout-content {
background-color: inherit;
min-height: auto;
position: relative;
overflow-x: hidden;
padding: 20px 10px 0px 20px;
height: calc(100% - v-bind(dueHeight) px);
}
}
.layout-footer {
position: relative;
padding: 7px 0px;
display: flex;
justify-content: center;
}
.logo {
height: @header-user-height;
line-height: @header-user-height;
background-color: v-bind('color.background');
padding: 0px 15px 0px 15px;
position: relative;
top: -1px;
z-index: 21;
display: flex;
cursor: pointer;
justify-content: center;
align-items: center;
background-color: #20b066;
.logo-img {
width: 30px;
height: 30px;
}
.title {
font-size: 20px;
// font-weight: 600;
margin-left: 8px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
}
.title-light {
// color: #001529;
color: #ffffff;
}
.title-dark {
color: #ffffff;
}
}
.village-select {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
z-index: 21;
background-color: #20b066;
padding: 16px 6px;
border-radius: 0 8px 8px 0;
display: flex;
flex-direction: column;
cursor: pointer;
span {
writing-mode: vertical-lr;
text-orientation: upright;
letter-spacing: 2px;
color: #ffffff;
}
}
.height100 {
height: 100%;
}
</style>