332 lines
9.6 KiB
Vue
332 lines
9.6 KiB
Vue
<template>
|
|
<!-- 通栏布局 -->
|
|
<template v-if="layout==='header'">
|
|
<header class="pi-header">
|
|
<div class="pi-header-left">
|
|
<div class="logo-bar">
|
|
<img class="logo" src="/images/logo-r.png">
|
|
<span>{{ config.APP_NAME }}</span>
|
|
</div>
|
|
<ul v-if="!isMobile" class="nav">
|
|
<li v-for="item in menu" :key="item" :class="pMenu.path===item.path?'active':''"
|
|
@click="showMenu(item)">
|
|
<el-icon>
|
|
<component :is="item.meta?.icon || 'el-icon-menu'"/>
|
|
</el-icon>
|
|
<span>{{ item.meta.title }}</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="pi-header-right">
|
|
<userbar></userbar>
|
|
</div>
|
|
</header>
|
|
<section class="pi-wrapper">
|
|
<div v-if="!isMobile && nextMenu.length>0 || !pMenu.component"
|
|
:class="menuIsCollapse?'pi-side isCollapse':'pi-side'">
|
|
<div v-if="!menuIsCollapse" class="pi-side-top">
|
|
<h2>{{ pMenu.meta.title }}</h2>
|
|
</div>
|
|
<div class="pi-side-scroll">
|
|
<el-scrollbar>
|
|
<el-menu :default-active="active" router :collapse="menuIsCollapse"
|
|
:unique-opened="false">
|
|
<NavMenu :navMenus="nextMenu"></NavMenu>
|
|
</el-menu>
|
|
</el-scrollbar>
|
|
</div>
|
|
<div class="pi-side-bottom" @click="global.TOGGLE_menuIsCollapse()">
|
|
<el-icon>
|
|
<el-icon-expand v-if="menuIsCollapse"/>
|
|
<el-icon-fold v-else/>
|
|
</el-icon>
|
|
</div>
|
|
</div>
|
|
<Side-m v-if="isMobile"></Side-m>
|
|
<div class="pi-body el-container">
|
|
<Topbar v-if="!isMobile"></Topbar>
|
|
<Tags v-if="!isMobile && layoutTags"></Tags>
|
|
<div class="pi-main" id="pi-main">
|
|
<router-view v-slot="{ Component }">
|
|
<keep-alive :include="keepAlive.keepLiveRoute">
|
|
<component :is="Component" :key="route.fullPath" v-if="keepAlive.routeShow"/>
|
|
</keep-alive>
|
|
</router-view>
|
|
<iframe-view></iframe-view>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<!-- 经典布局 -->
|
|
<template v-else-if="layout==='menu'">
|
|
<section class="pi-wrapper">
|
|
<div v-if="!isMobile" :class="menuIsCollapse?'pi-side isCollapse':'pi-side'">
|
|
<div class="logo-bar">
|
|
<img class="logo" src="/images/logo-r.png">
|
|
<span class="title" v-if="!menuIsCollapse">{{ config.APP_NAME }}</span>
|
|
</div>
|
|
<div class="pi-side-scroll">
|
|
<el-scrollbar>
|
|
<el-menu :default-active="active" router :collapse="menuIsCollapse"
|
|
:unique-opened="false">
|
|
<NavMenu :navMenus="menu"></NavMenu>
|
|
</el-menu>
|
|
</el-scrollbar>
|
|
</div>
|
|
<div class="pi-side-bottom" @click="global.TOGGLE_menuIsCollapse()">
|
|
<el-icon>
|
|
<el-icon-expand v-if="menuIsCollapse"/>
|
|
<el-icon-fold v-else/>
|
|
</el-icon>
|
|
</div>
|
|
</div>
|
|
<Side-m v-if="isMobile"></Side-m>
|
|
<div class="pi-body el-container">
|
|
<Topbar v-if="!isMobile">
|
|
<userbar></userbar>
|
|
</Topbar>
|
|
<Tags v-if="!isMobile && layoutTags"></Tags>
|
|
<div class="pi-main" id="pi-main">
|
|
<router-view v-slot="{ Component }">
|
|
<keep-alive :include="keepAlive.keepLiveRoute">
|
|
<component :is="Component" :key="route.fullPath" v-if="keepAlive.routeShow"/>
|
|
</keep-alive>
|
|
</router-view>
|
|
<iframe-view></iframe-view>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<!-- 功能坞布局 -->
|
|
<template v-else-if="layout==='dock'">
|
|
<section class="pi-dock">
|
|
<header class="pi-header" :class="isMobile?'':'pi-pad'">
|
|
<div class="pi-header-left">
|
|
<div class="logo-bar">
|
|
<img class="logo" src="/images/logo-r.png">
|
|
<span>{{ config.APP_NAME }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="pi-header-right">
|
|
<div v-if="!isMobile" class="pi-header-menu">
|
|
<el-menu mode="horizontal" :default-active="active" router background-color="#222b45"
|
|
text-color="#fff" active-text-color="var(--el-color-primary)">
|
|
<NavMenu :navMenus="menu"></NavMenu>
|
|
</el-menu>
|
|
</div>
|
|
<Side-m v-if="isMobile"></Side-m>
|
|
<userbar></userbar>
|
|
</div>
|
|
</header>
|
|
<section class="pi-wrapper">
|
|
<div class="pi-body el-container">
|
|
<Tags v-if="!isMobile && layoutTags"></Tags>
|
|
<div class="pi-main" id="pi-main" :class="isMobile?'':'pi-pad'">
|
|
<router-view v-slot="{ Component }">
|
|
<keep-alive :include="keepAlive.keepLiveRoute">
|
|
<component :is="Component" :key="route.fullPath" v-if="keepAlive.routeShow"/>
|
|
</keep-alive>
|
|
</router-view>
|
|
<iframe-view></iframe-view>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</section>
|
|
</template>
|
|
|
|
<!-- 浮动布局 -->
|
|
<template v-else-if="layout==='float'">
|
|
<section class="pi-wrapper">
|
|
<div v-if="!isMobile" class="pi-side isCollapse">
|
|
<div class="logo-bar">
|
|
<img class="logo" src="/images/logo-r.png">
|
|
</div>
|
|
<div class="pi-side-scroll">
|
|
<el-scrollbar>
|
|
<el-menu :default-active="active" router :collapse="true"
|
|
:unique-opened="false">
|
|
<NavMenu :navMenus="menu"></NavMenu>
|
|
</el-menu>
|
|
</el-scrollbar>
|
|
</div>
|
|
</div>
|
|
<Side-m v-if="isMobile"></Side-m>
|
|
<div class="pi-body el-container">
|
|
<Topbar v-if="!isMobile">
|
|
<userbar></userbar>
|
|
</Topbar>
|
|
<Tags v-if="!isMobile && layoutTags"></Tags>
|
|
<div class="pi-main" id="pi-main">
|
|
<router-view v-slot="{ Component }">
|
|
<keep-alive :include="keepAlive.keepLiveRoute">
|
|
<component :is="Component" :key="route.fullPath" v-if="keepAlive.routeShow"/>
|
|
</keep-alive>
|
|
</router-view>
|
|
<iframe-view></iframe-view>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<!-- 分栏布局 -->
|
|
<template v-else>
|
|
<section class="pi-wrapper">
|
|
<div v-if="!isMobile" class="pi-side-split">
|
|
<div class="pi-side-split-top">
|
|
<router-link to="/dashboard">
|
|
<img class="logo" :title="config.APP_NAME" src="/images/logo-r.png">
|
|
</router-link>
|
|
</div>
|
|
<div class="pi-side-split-scroll">
|
|
<el-scrollbar>
|
|
<ul>
|
|
<li v-for="item in menu" :key="item" :class="pMenu.path===item.path?'active':''"
|
|
@click="showMenu(item)">
|
|
<el-icon>
|
|
<component :is="item.meta?.icon || 'el-icon-menu'"/>
|
|
</el-icon>
|
|
<p>{{ item.meta.title }}</p>
|
|
</li>
|
|
</ul>
|
|
</el-scrollbar>
|
|
</div>
|
|
</div>
|
|
<div v-if="!isMobile && nextMenu.length>0 || !pMenu.component"
|
|
:class="menuIsCollapse?'pi-side isCollapse':'pi-side'">
|
|
<div v-if="!menuIsCollapse" class="pi-side-top">
|
|
<h2>{{ pMenu.meta.title }}</h2>
|
|
</div>
|
|
<div class="pi-side-scroll">
|
|
<el-scrollbar>
|
|
<el-menu :default-active="active" router :collapse="menuIsCollapse"
|
|
:unique-opened="false">
|
|
<NavMenu :navMenus="nextMenu"></NavMenu>
|
|
</el-menu>
|
|
</el-scrollbar>
|
|
</div>
|
|
<div class="pi-side-bottom" @click="global.TOGGLE_menuIsCollapse()">
|
|
<el-icon>
|
|
<el-icon-expand v-if="menuIsCollapse"/>
|
|
<el-icon-fold v-else/>
|
|
</el-icon>
|
|
</div>
|
|
</div>
|
|
<Side-m v-if="isMobile"></Side-m>
|
|
<div class="pi-body el-container">
|
|
<Topbar>
|
|
<userbar></userbar>
|
|
</Topbar>
|
|
<Tags v-if="!isMobile && layoutTags"></Tags>
|
|
<div class="pi-main" id="pi-main">
|
|
<router-view v-slot="{ Component }">
|
|
<keep-alive :include="keepAlive.keepLiveRoute">
|
|
<component :is="Component" :key="route.fullPath" v-if="keepAlive.routeShow"/>
|
|
</keep-alive>
|
|
</router-view>
|
|
<iframe-view></iframe-view>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<div class="main-maximize-exit" @click="exitMaximize">
|
|
<el-icon>
|
|
<el-icon-close/>
|
|
</el-icon>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {ref, watch, computed, nextTick} from 'vue'
|
|
import SideM from './components/sideM.vue';
|
|
import Topbar from './components/topbar.vue';
|
|
import Tags from './components/tags.vue';
|
|
import NavMenu from './components/NavMenu.vue';
|
|
import userbar from './components/userbar.vue';
|
|
import iframeView from './components/iframeView.vue';
|
|
import globalStore from "@/store/global.js";
|
|
import keepAliveStore from "@/store/keepAlive.js";
|
|
import {useRoute, useRouter} from 'vue-router'
|
|
import config from "@/config";
|
|
import {getMenu} from '@/utils/route'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
let nextMenu = ref([])
|
|
let pMenu = ref([])
|
|
let active = ref("")
|
|
let menu = filterUrl(getMenu());
|
|
const global = globalStore()
|
|
const keepAlive = keepAliveStore()
|
|
|
|
const isMobile = computed(() => global.isMobile)
|
|
const layout = computed(() => global.layout)
|
|
const layoutTags = computed(() => global.layoutTags)
|
|
const menuIsCollapse = computed(() => global.menuIsCollapse)
|
|
|
|
onLayoutResize();
|
|
window.addEventListener('resize', onLayoutResize);
|
|
showThis()
|
|
|
|
watch(route, () => {
|
|
showThis()
|
|
})
|
|
|
|
watch(layout, (val) => {
|
|
document.body.setAttribute('data-layout', val)
|
|
}, {immediate: true})
|
|
|
|
function exitMaximize() {
|
|
document.getElementById('app').classList.remove('main-maximize')
|
|
}
|
|
|
|
function filterUrl(map) {
|
|
const newMap = [];
|
|
map && map.forEach(item => {
|
|
item.meta = item.meta ? item.meta : {};
|
|
//处理隐藏
|
|
if (item.meta.hidden || item.meta.type === "button") {
|
|
return false
|
|
}
|
|
//处理http
|
|
if (item.meta.type === 'iframe') {
|
|
item.path = `/i/${item.name}`;
|
|
}
|
|
//递归循环
|
|
if (item.children && item.children.length > 0) {
|
|
item.children = filterUrl(item.children)
|
|
}
|
|
newMap.push(item)
|
|
})
|
|
return newMap;
|
|
}
|
|
|
|
function showMenu(route) {
|
|
pMenu.value = route;
|
|
nextMenu.value = filterUrl(route.children);
|
|
if ((!route.children || route.children.length === 0) && route.component) {
|
|
router.push({path: route.path})
|
|
}
|
|
}
|
|
|
|
function showThis() {
|
|
pMenu.value = route.meta.breadcrumb ? route.meta.breadcrumb[0] : {}
|
|
nextMenu.value = filterUrl(pMenu.value.children);
|
|
nextTick(() => {
|
|
active.value = route.meta.active || route.fullPath;
|
|
})
|
|
}
|
|
|
|
function onLayoutResize() {
|
|
global.SET_isMobile(document.body.clientWidth < 992)
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
:deep(.el-menu--horizontal) {
|
|
height: auto;
|
|
}
|
|
</style>
|