mirror of https://gitee.com/xiaonuobase/snowy
【更新】重写layout布局,为更多布局扩展更方便,顺手解决标签点击不切换应用的问题
parent
e6f4ee7f4d
commit
d00dd22a29
|
@ -28,7 +28,7 @@
|
|||
<strong>We're sorry but Snowy2.0 doesn't work properly without JavaScript
|
||||
enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app">
|
||||
<div id="app" class="admin-ui">
|
||||
<div class="app-loading">
|
||||
<div class="app-loading__logo">
|
||||
<img src="/img/logo.png"/>
|
||||
|
|
|
@ -46,10 +46,10 @@ const DEFAULT_CONFIG = {
|
|||
SNOWY_BREADCRUMD_OPEN: false,
|
||||
|
||||
// 顶栏是否应用主题色
|
||||
SNOWY_TOP_HANDER_THEME_COLOR_OPEN: false,
|
||||
SNOWY_TOP_HEADER_THEME_COLOR_OPEN: false,
|
||||
|
||||
// 顶栏主题色通栏
|
||||
SNOWY_TOP_HANDER_THEME_COLOR_SPREAD: false,
|
||||
SNOWY_TOP_HEADER_THEME_COLOR_SPREAD: false,
|
||||
|
||||
// 侧边菜单是否排他展开
|
||||
SNOWY_SIDE_UNIQUE_OPEN: true,
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
},
|
||||
computed: {
|
||||
...mapState(iframeStore, ['iframeList']),
|
||||
...mapState(globalStore, ['ismobile', 'layoutTags'])
|
||||
...mapState(globalStore, ['isMobile', 'layoutTags'])
|
||||
},
|
||||
watch: {
|
||||
$route(e) {
|
||||
|
@ -35,12 +35,12 @@
|
|||
...mapActions(iframeStore, ['setIframeList', 'pushIframeList', 'clearIframeList']),
|
||||
push(route) {
|
||||
if (route.meta.type === 'iframe') {
|
||||
if (this.ismobile || !this.layoutTags) {
|
||||
if (this.isMobile || !this.layoutTags) {
|
||||
this.setIframeList(route)
|
||||
} else {
|
||||
this.pushIframeList(route)
|
||||
}
|
||||
} else if (this.ismobile || !this.layoutTags) {
|
||||
} else if (this.isMobile || !this.layoutTags) {
|
||||
this.clearIframeList()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,7 @@
|
|||
<a-button type="primary" @click="leaveFor('/usercenter')">消息中心</a-button>
|
||||
</a-space>
|
||||
</a-drawer>
|
||||
<xn-form-container
|
||||
title="详情"
|
||||
:width="700"
|
||||
:visible="visible"
|
||||
:destroy-on-close="true"
|
||||
@close="onClose"
|
||||
>
|
||||
<xn-form-container title="详情" :width="700" :visible="visible" :destroy-on-close="true" @close="onClose">
|
||||
<a-form ref="formRef" :model="formData" layout="vertical">
|
||||
<a-form-item label="主题:" name="subject">
|
||||
<span>{{ formData.subject }}</span>
|
||||
|
@ -84,7 +78,10 @@
|
|||
let clientId = tool.data.get('CLIENTID') ? tool.data.get('CLIENTID') : ''
|
||||
let url = sysConfig.API_URL + '/dev/message/createSseConnect?clientId=' + clientId
|
||||
// heartbeatTimeout:心跳超时监测 30s
|
||||
let source = new EventSourcePolyfill(url, { headers: { token: tool.data.get('TOKEN') }, heartbeatTimeout: 30000 })
|
||||
let source = new EventSourcePolyfill(url, {
|
||||
headers: { token: tool.data.get('TOKEN') },
|
||||
heartbeatTimeout: 300000
|
||||
})
|
||||
// 监听打开事件
|
||||
source.addEventListener('open', (e) => {})
|
||||
// 监听消息事件
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
mode="horizontal"
|
||||
v-if="menu && menu.length > 1"
|
||||
class="module-menu"
|
||||
id="moduleMunu"
|
||||
id="moduleMenu"
|
||||
>
|
||||
<a-menu-item
|
||||
v-for="item in menu"
|
||||
|
@ -21,7 +21,7 @@
|
|||
</a-menu-item>
|
||||
</a-menu>
|
||||
</div>
|
||||
<div v-else class="panel-item hidden-sm-and-down">
|
||||
<div v-else>
|
||||
<a-popover v-if="menu.length > 1" placement="bottomLeft">
|
||||
<template #content>
|
||||
<a-row :gutter="[0, 5]" class="module-row">
|
||||
|
@ -35,7 +35,9 @@
|
|||
</div>
|
||||
</a-row>
|
||||
</template>
|
||||
<appstore-outlined />
|
||||
<div class="panel-item hidden-sm-and-down module-card-scope">
|
||||
<appstore-outlined />
|
||||
</div>
|
||||
</a-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -49,24 +51,30 @@
|
|||
|
||||
const store = globalStore()
|
||||
|
||||
const { moduleUnfoldOpen, topHanderThemeColorOpen } = storeToRefs(store)
|
||||
const moduleBackColor = ref(topHanderThemeColorOpen)
|
||||
|
||||
const { moduleUnfoldOpen, topHeaderThemeColorOpen } = storeToRefs(store)
|
||||
const moduleBackColor = ref(topHeaderThemeColorOpen)
|
||||
const module = computed(() => {
|
||||
return store.module
|
||||
})
|
||||
// 监听目录是否折叠
|
||||
watch(moduleUnfoldOpen, (newValue) => {
|
||||
nextTick(() => {
|
||||
setModuleBackColor()
|
||||
})
|
||||
})
|
||||
watch(module, (newValue) => {
|
||||
selectedKeys.value = [newValue]
|
||||
setSelectedKeys()
|
||||
})
|
||||
// 监听是否开启了顶栏颜色
|
||||
watch(topHanderThemeColorOpen, (newValue) => {
|
||||
watch(topHeaderThemeColorOpen, (newValue) => {
|
||||
moduleBackColor.value = newValue
|
||||
setModuleBackColor()
|
||||
})
|
||||
|
||||
const emit = defineEmits({ switchModule: null })
|
||||
const menu = router.getMenu()
|
||||
const selectedKeys = ref([tool.data.get('SNOWY_MENU_MODULE_ID')])
|
||||
const selectedKeys = ref([module.value])
|
||||
const moduleClick = (id) => {
|
||||
emit('switchModule', id)
|
||||
tool.data.set('SNOWY_MENU_MODULE_ID', id)
|
||||
|
@ -82,24 +90,24 @@
|
|||
const setModuleBackColor = () => {
|
||||
if (moduleUnfoldOpen.value) {
|
||||
try {
|
||||
const moduleMunu = document.getElementById('moduleMunu')
|
||||
const moduleMenu = document.getElementById('moduleMenu')
|
||||
moduleBackColor.value
|
||||
? moduleMunu.classList.add('module-menu-color')
|
||||
: moduleMunu.classList.remove('module-menu-color')
|
||||
? moduleMenu.classList.add('module-menu-color')
|
||||
: moduleMenu.classList.remove('module-menu-color')
|
||||
} catch (err) {}
|
||||
setSelectedKeys()
|
||||
}
|
||||
}
|
||||
// 设置选中
|
||||
const setSelectedKeys = () => {
|
||||
// 顶部应用列表让显示出来默认的,不这么实现不会显示的,相信老俞
|
||||
// 顶部应用列表让显示出来默认的
|
||||
moduleBackColor.value
|
||||
? (selectedKeys.value = new Array([]))
|
||||
: (selectedKeys.value = [tool.data.get('SNOWY_MENU_MODULE_ID')])
|
||||
}
|
||||
</script>
|
||||
|
||||
<style type="less">
|
||||
<style lang="less">
|
||||
.module-row {
|
||||
max-width: 357px;
|
||||
}
|
||||
|
@ -135,4 +143,7 @@
|
|||
color: white;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
.module-card-scope {
|
||||
height: 49px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -41,14 +41,14 @@
|
|||
</div>
|
||||
<div class="mb-4 layout-slide">
|
||||
<h4 class="">顶栏应用主题色:</h4>
|
||||
<a-switch :checked="topHanderThemeColorOpen" @change="changeTopHanderThemeColorOpen" />
|
||||
<a-switch :checked="topHeaderThemeColorOpen" @change="changeTopHanderThemeColorOpen" />
|
||||
</div>
|
||||
<div class="mb-4 layout-slide">
|
||||
<h4>顶栏主题色通栏:</h4>
|
||||
<a-switch
|
||||
style="float: right"
|
||||
:checked="topHanderThemeColorSpread"
|
||||
:disabled="!topHanderThemeColorOpen"
|
||||
:checked="topHeaderThemeColorSpread"
|
||||
:disabled="!topHeaderThemeColorOpen"
|
||||
@change="changeTopHanderThemeColorSpread"
|
||||
/>
|
||||
</div>
|
||||
|
@ -99,8 +99,8 @@
|
|||
sideUniqueOpen: 'SIDE_UNIQUE_OPEN',
|
||||
layoutTagsOpen: 'LAYOUT_TAGS_OPEN',
|
||||
breadcrumbOpen: 'BREADCRUMD_OPEN',
|
||||
topHanderThemeColorOpen: 'TOP_HANDER_THEME_COLOR_OPEN',
|
||||
topHanderThemeColorSpread: 'TOP_HANDER_THEME_COLOR_SPREAD',
|
||||
topHeaderThemeColorOpen: 'TOP_HEADER_THEME_COLOR_OPEN',
|
||||
topHeaderThemeColorSpread: 'TOP_HEADER_THEME_COLOR_SPREAD',
|
||||
moduleUnfoldOpen: 'MODULE_UNFOLD_OPEN'
|
||||
}
|
||||
export default defineComponent({
|
||||
|
@ -159,22 +159,22 @@
|
|||
'layoutTagsOpen',
|
||||
'breadcrumbOpen',
|
||||
'moduleUnfoldOpen',
|
||||
'topHanderThemeColorOpen',
|
||||
'topHanderThemeColorSpread',
|
||||
'topHeaderThemeColorOpen',
|
||||
'topHeaderThemeColorSpread',
|
||||
'formStyle'
|
||||
])
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
changeTopHanderThemeColorOpen() {
|
||||
this.toggleState('topHanderThemeColorOpen')
|
||||
if (!this.topHanderThemeColorOpen) {
|
||||
this.globalStore.topHanderThemeColorSpread = false
|
||||
tool.data.set('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD', false)
|
||||
this.toggleState('topHeaderThemeColorOpen')
|
||||
if (!this.topHeaderThemeColorOpen) {
|
||||
this.globalStore.topHeaderThemeColorSpread = false
|
||||
tool.data.set('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD', false)
|
||||
}
|
||||
},
|
||||
changeTopHanderThemeColorSpread() {
|
||||
this.toggleState('topHanderThemeColorSpread')
|
||||
this.toggleState('topHeaderThemeColorSpread')
|
||||
},
|
||||
toggleState(stateName) {
|
||||
this.globalStore.toggleConfig(stateName)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="adminui-topbar">
|
||||
<div class="admin-ui-topbar">
|
||||
<div class="left-panel">
|
||||
<a-breadcrumb>
|
||||
<template v-for="item in breadList" :key="item.title">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div v-if="!isMobile" class="screen panel-item hidden-sm-and-down" @click="fullscreen">
|
||||
<fullscreen-outlined />
|
||||
</div>
|
||||
<dev-user-message />
|
||||
<!-- <dev-user-message />-->
|
||||
<a-dropdown class="user panel-item">
|
||||
<div class="user-avatar">
|
||||
<a-avatar :src="userInfo.avatar" />
|
||||
|
@ -74,7 +74,7 @@
|
|||
const setDrawer = ref(import.meta.env.VITE_SET_DRAWER)
|
||||
const store = globalStore()
|
||||
const isMobile = computed(() => {
|
||||
return store.ismobile
|
||||
return store.isMobile
|
||||
})
|
||||
const userInfo = computed(() => {
|
||||
return store.userInfo
|
||||
|
|
|
@ -1,501 +1,388 @@
|
|||
<template>
|
||||
<div class="aminui">
|
||||
<!-- 经典布局 -->
|
||||
<template v-if="layout === 'classical'">
|
||||
<a-layout>
|
||||
<a-layout-sider
|
||||
v-if="!ismobile"
|
||||
v-model:collapsed="menuIsCollapse"
|
||||
:trigger="null"
|
||||
collapsible
|
||||
:theme="sideTheme"
|
||||
width="210"
|
||||
>
|
||||
<header id="snowyHeaderLogo" class="snowy-header-logo">
|
||||
<div class="snowy-header-left">
|
||||
<div class="logo-bar">
|
||||
<img class="logo" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
||||
<span>{{ sysBaseConfig.SNOWY_SYS_NAME }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div :class="menuIsCollapse ? 'aminui-side isCollapse' : 'aminui-side'">
|
||||
<div class="adminui-side-scroll">
|
||||
<a-menu
|
||||
v-model:openKeys="openKeys"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
:theme="sideTheme"
|
||||
mode="inline"
|
||||
@select="onSelect"
|
||||
@openChange="onOpenChange"
|
||||
>
|
||||
<NavMenu :nav-menus="menu" />
|
||||
</a-menu>
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-sider>
|
||||
<!-- 手机端情况下的左侧菜单 -->
|
||||
<Side-m v-if="ismobile" />
|
||||
<!-- 右侧布局 -->
|
||||
<a-layout>
|
||||
<div id="snowyHeader" class="snowy-header">
|
||||
<div class="snowy-header-left" style="padding-left: 0px">
|
||||
<div v-if="!ismobile" class="panel-item hidden-sm-and-down" @click="menuIsCollapseClick">
|
||||
<MenuUnfoldOutlined v-if="menuIsCollapse" />
|
||||
<MenuFoldOutlined v-else />
|
||||
</div>
|
||||
<moduleMenu @switchModule="switchModule" />
|
||||
<Topbar v-if="!ismobile && breadcrumbOpen" />
|
||||
</div>
|
||||
<div class="snowy-header-right">
|
||||
<userbar />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 多标签 -->
|
||||
<Tags v-if="!ismobile && layoutTagsOpen" />
|
||||
<a-layout-content class="main-content-wrapper">
|
||||
<div id="adminui-main" class="adminui-main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive :include="keepLiveRoute">
|
||||
<component :is="Component" :key="$route.name" v-if="routeShow" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
<iframe-view />
|
||||
<div class="main-bottom-wrapper">
|
||||
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
|
||||
sysBaseConfig.SNOWY_SYS_COPYRIGHT
|
||||
}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<!-- 双排菜单布局 -->
|
||||
<template v-else-if="layout === 'doublerow'">
|
||||
<a-layout>
|
||||
<a-layout-sider v-if="!ismobile" width="80" :theme="sideTheme" :trigger="null" collapsible>
|
||||
<header id="snowyHeaderLogo" class="snowy-header-logo">
|
||||
<div class="snowy-header-left">
|
||||
<div class="logo-bar">
|
||||
<router-link to="/">
|
||||
<img class="logo" :title="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<a-menu v-model:selectedKeys="doublerowSelectedKey" :theme="sideTheme" class="snowy-doublerow-layout-menu">
|
||||
<a-menu-item
|
||||
v-for="item in menu"
|
||||
:key="item.path"
|
||||
style="
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
height: auto;
|
||||
line-height: 20px;
|
||||
flex: none;
|
||||
display: block;
|
||||
padding: 12px 0 !important;
|
||||
"
|
||||
@click="showMenu(item)"
|
||||
>
|
||||
<a
|
||||
v-if="item.meta && item.meta.type === 'link'"
|
||||
:href="item.path"
|
||||
target="_blank"
|
||||
@click.stop="() => {}"
|
||||
></a>
|
||||
<template #icon>
|
||||
<component :is="item.meta.icon" style="padding-left: 10px" />
|
||||
</template>
|
||||
<div class="snowy-doublerow-layout-menu-item-fort-div">
|
||||
<span class="snowy-doublerow-layout-menu-item-fort-div-span">
|
||||
{{ item.meta.title }}
|
||||
</span>
|
||||
</div>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
<a-layout-sider
|
||||
v-if="!ismobile"
|
||||
v-show="layoutSiderDowbleMenu"
|
||||
v-model:collapsed="menuIsCollapse"
|
||||
:trigger="null"
|
||||
width="170"
|
||||
collapsible
|
||||
:theme="secondMenuSideTheme"
|
||||
>
|
||||
<div v-if="!menuIsCollapse" id="snowyDoublerowSideTop" class="snowy-doublerow-side-top">
|
||||
<h2 class="snowy-title">{{ pmenu.meta.title }}</h2>
|
||||
</div>
|
||||
<a-menu
|
||||
v-model:collapsed="menuIsCollapse"
|
||||
v-model:openKeys="openKeys"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
mode="inline"
|
||||
:theme="secondMenuSideTheme"
|
||||
@select="onSelect"
|
||||
>
|
||||
<NavMenu :nav-menus="nextMenu" />
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
<!-- 手机端情况下的左侧菜单 -->
|
||||
<Side-m v-if="ismobile" />
|
||||
<a-layout>
|
||||
<div id="snowyHeader" class="snowy-header">
|
||||
<div class="snowy-header-left" style="padding-left: 0px">
|
||||
<div v-if="!ismobile" class="panel-item hidden-sm-and-down" @click="menuIsCollapseClick">
|
||||
<MenuUnfoldOutlined v-if="menuIsCollapse" />
|
||||
<MenuFoldOutlined v-else />
|
||||
</div>
|
||||
<moduleMenu @switchModule="switchModule" />
|
||||
<Topbar v-if="!ismobile && breadcrumbOpen" />
|
||||
</div>
|
||||
<div class="snowy-header-right">
|
||||
<userbar />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 多标签 -->
|
||||
<Tags v-if="!ismobile && layoutTagsOpen"></Tags>
|
||||
<a-layout-content class="main-content-wrapper">
|
||||
<div id="adminui-main" class="adminui-main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive :include="keepLiveRoute">
|
||||
<component :is="Component" v-if="routeShow" :key="$route.name" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
<iframe-view />
|
||||
<div class="main-bottom-wrapper">
|
||||
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
|
||||
sysBaseConfig.SNOWY_SYS_COPYRIGHT
|
||||
}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<!-- 退出最大化 -->
|
||||
<div class="main-maximize-exit" @click="exitMaximize">
|
||||
<fullscreen-exit-outlined style="color: #fff" />
|
||||
</div>
|
||||
<!-- 经典布局 -->
|
||||
<classical
|
||||
v-if="layout === 'classical'"
|
||||
:is-mobile="isMobile"
|
||||
:menu-is-collapse="menuIsCollapse"
|
||||
:side-theme="sideTheme"
|
||||
:sys-base-config="sysBaseConfig"
|
||||
:open-keys="openKeys"
|
||||
:selected-keys="selectedKeys"
|
||||
:menu="menu"
|
||||
:breadcrumb-open="breadcrumbOpen"
|
||||
:layout-tags-open="layoutTagsOpen"
|
||||
:keep-live-route="keepLiveRoute"
|
||||
:route-show="routeShow"
|
||||
:route="route"
|
||||
@onSelect="onSelect"
|
||||
@onOpenChange="onOpenChange"
|
||||
@menuIsCollapseClick="menuIsCollapseClick"
|
||||
@switchModule="switchModule"
|
||||
/>
|
||||
<!-- 双排菜单布局 -->
|
||||
<double-row
|
||||
v-else-if="layout === 'doublerow'"
|
||||
:is-mobile="isMobile"
|
||||
:menu-is-collapse="menuIsCollapse"
|
||||
:side-theme="sideTheme"
|
||||
:sys-base-config="sysBaseConfig"
|
||||
:open-keys="openKeys"
|
||||
:selected-keys="selectedKeys"
|
||||
:menu="menu"
|
||||
:breadcrumb-open="breadcrumbOpen"
|
||||
:layout-tags-open="layoutTagsOpen"
|
||||
:keep-live-route="keepLiveRoute"
|
||||
:route-show="routeShow"
|
||||
:route="route"
|
||||
:layoutSiderDowbleMenu="layoutSiderDowbleMenu"
|
||||
:secondMenuSideTheme="secondMenuSideTheme"
|
||||
:nextMenu="nextMenu"
|
||||
:doublerowSelectedKey="doublerowSelectedKey"
|
||||
:pMenu="pMenu"
|
||||
@onSelect="onSelect"
|
||||
@showMenu="showMenu"
|
||||
@onOpenChange="onOpenChange"
|
||||
@menuIsCollapseClick="menuIsCollapseClick"
|
||||
@switchModule="switchModule"
|
||||
/>
|
||||
<!-- 退出最大化 -->
|
||||
<div class="main-maximize-exit" @click="exitMaximize">
|
||||
<fullscreen-exit-outlined style="color: #fff" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
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 moduleMenu from './components/moduleMenu.vue'
|
||||
import { ThemeModeEnum } from '@/utils/enum'
|
||||
<script setup>
|
||||
import Classical from '@/layout/pattern/classical.vue'
|
||||
import DoubleRow from '@/layout/pattern/doublerow.vue'
|
||||
import { globalStore, keepAliveStore } from '@/store'
|
||||
import { mapState, mapStores, mapActions } from 'pinia'
|
||||
import { ThemeModeEnum } from '@/utils/enum'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import tool from '@/utils/tool'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Index',
|
||||
components: {
|
||||
SideM,
|
||||
Topbar,
|
||||
Tags,
|
||||
NavMenu,
|
||||
userbar,
|
||||
moduleMenu,
|
||||
iframeView
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
menu: [],
|
||||
moduleMenu: [],
|
||||
nextMenu: [],
|
||||
pmenu: {},
|
||||
doublerowSelectedKey: [],
|
||||
layoutSiderDowbleMenu: true,
|
||||
onSelectTag: false,
|
||||
selectedKeys: [],
|
||||
openKeys: [],
|
||||
openKeysOther: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapStores(globalStore),
|
||||
...mapState(globalStore, [
|
||||
'theme',
|
||||
'ismobile',
|
||||
'layout',
|
||||
'layoutTagsOpen',
|
||||
'menuIsCollapse',
|
||||
'breadcrumbOpen',
|
||||
'topHanderThemeColorOpen',
|
||||
'topHanderThemeColorSpread',
|
||||
'topHanderThemeColor',
|
||||
'sideUniqueOpen',
|
||||
'sysBaseConfig'
|
||||
]),
|
||||
...mapState(keepAliveStore, ['keepLiveRoute', 'routeShow']),
|
||||
sideTheme() {
|
||||
const theme = this.theme
|
||||
return theme === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : theme
|
||||
},
|
||||
secondMenuSideTheme() {
|
||||
const theme = this.theme
|
||||
return theme === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : ThemeModeEnum.LIGHT
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.showThis()
|
||||
},
|
||||
layout: {
|
||||
handler(val) {
|
||||
document.body.setAttribute('data-layout', val)
|
||||
if (val.includes('doublerow')) {
|
||||
this.setDoublerowSelectedKey()
|
||||
const store = globalStore()
|
||||
const kStore = keepAliveStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const menu = ref([])
|
||||
const pMenu = ref({})
|
||||
const nextMenu = ref([])
|
||||
const selectedKeys = ref([])
|
||||
const openKeys = ref([])
|
||||
const onSelectTag = ref(false)
|
||||
const moduleMenu = ref([])
|
||||
const doublerowSelectedKey = ref([])
|
||||
const layoutSiderDowbleMenu = ref(true)
|
||||
const currentRoute = ref()
|
||||
// computed计算方法 - start
|
||||
const layout = computed(() => {
|
||||
return store.layout
|
||||
})
|
||||
const isMobile = computed(() => {
|
||||
return store.isMobile
|
||||
})
|
||||
const menuIsCollapse = computed(() => {
|
||||
return store.menuIsCollapse
|
||||
})
|
||||
const theme = computed(() => {
|
||||
return store.theme
|
||||
})
|
||||
const layoutTagsOpen = computed(() => {
|
||||
return store.layoutTagsOpen
|
||||
})
|
||||
const breadcrumbOpen = computed(() => {
|
||||
return store.breadcrumbOpen
|
||||
})
|
||||
const topHeaderThemeColorOpen = computed(() => {
|
||||
return store.topHeaderThemeColorOpen
|
||||
})
|
||||
const topHeaderThemeColorSpread = computed(() => {
|
||||
return store.topHeaderThemeColorSpread
|
||||
})
|
||||
const sideUniqueOpen = computed(() => {
|
||||
return store.sideUniqueOpen
|
||||
})
|
||||
const sysBaseConfig = computed(() => {
|
||||
return store.sysBaseConfig
|
||||
})
|
||||
const module = computed(() => {
|
||||
return store.module
|
||||
})
|
||||
const keepLiveRoute = computed(() => {
|
||||
return kStore.keepLiveRoute
|
||||
})
|
||||
const routeShow = computed(() => {
|
||||
return kStore.routeShow
|
||||
})
|
||||
const sideTheme = computed(() => {
|
||||
return theme.value === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : theme.value
|
||||
})
|
||||
const secondMenuSideTheme = computed(() => {
|
||||
return theme.value === ThemeModeEnum.REAL_DARK ? ThemeModeEnum.DARK : ThemeModeEnum.LIGHT
|
||||
})
|
||||
// 转换外部链接的路由
|
||||
const filterUrl = (map) => {
|
||||
const newMap = []
|
||||
const traverse = (maps) => {
|
||||
maps &&
|
||||
maps.forEach((item) => {
|
||||
item.meta = item.meta ? item.meta : {}
|
||||
// 处理隐藏
|
||||
if (item.meta.hidden) {
|
||||
return false
|
||||
}
|
||||
// 处理iframe
|
||||
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)
|
||||
})
|
||||
}
|
||||
traverse(map)
|
||||
return newMap
|
||||
}
|
||||
// 路由监听高亮
|
||||
const showThis = () => {
|
||||
pMenu.value = route.meta.breadcrumb ? route.meta.breadcrumb[0] : {}
|
||||
// 展开的
|
||||
nextTick(() => {
|
||||
// 取得默认路由地址并设置展开
|
||||
const active = route.meta.active || route.fullPath
|
||||
selectedKeys.value = new Array(active)
|
||||
const pidKey = getParentKeys(pMenu.value.children, active)
|
||||
const nextTickMenu = pMenu.value.children
|
||||
if (pidKey) {
|
||||
const parentPath = pidKey[pidKey.length - 1]
|
||||
if (layout.value === 'doublerow') {
|
||||
// 这一串操作下来只为取到最上面的路由的孩子们,最后成为双排菜单的第二排
|
||||
const nextMenuTemp = nextTickMenu.filter((item) => item.path === parentPath)[0].children
|
||||
if (nextMenuTemp) {
|
||||
nextMenu.value = nextTickMenu.filter((item) => item.path === parentPath)[0].children
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
// 顶栏主题色
|
||||
this.switchoverTopHanderThemeColor()
|
||||
})
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
topHanderThemeColorOpen() {
|
||||
this.switchoverTopHanderThemeColor()
|
||||
},
|
||||
topHanderThemeColorSpread() {
|
||||
this.switchoverTopHanderThemeColor()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 判断浏览器宽度,顺手加入缓存
|
||||
this.onLayoutResize()
|
||||
window.addEventListener('resize', this.onLayoutResize)
|
||||
this.moduleMenu = this.$router.getMenu()
|
||||
// 获取缓存中的菜单模块是哪个
|
||||
const menuModuleId = tool.data.get('SNOWY_MENU_MODULE_ID')
|
||||
let menu = []
|
||||
if (menuModuleId) {
|
||||
// 防止切换一个无此应用的人
|
||||
const module = this.$router.getMenu().filter((item) => item.id === menuModuleId)
|
||||
if (module.length > 0) {
|
||||
menu = module[0].children
|
||||
} else {
|
||||
menu = this.$router.getMenu()[0].children
|
||||
}
|
||||
}
|
||||
if (!onSelectTag.value || sideUniqueOpen.value) {
|
||||
openKeys.value = pidKey
|
||||
}
|
||||
// 双排菜单下
|
||||
if (layout.value === 'doublerow') {
|
||||
setDoubleRowSelectedKey()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 执行-start
|
||||
moduleMenu.value = router.getMenu()
|
||||
// 获取缓存中的菜单模块是哪个
|
||||
const menuModuleId = tool.data.get('SNOWY_MENU_MODULE_ID')
|
||||
let initMenu = []
|
||||
if (menuModuleId) {
|
||||
// 防止切换一个无此应用的人
|
||||
const module = router.getMenu().filter((item) => item.id === menuModuleId)
|
||||
if (module.length > 0) {
|
||||
initMenu = module[0].children
|
||||
} else {
|
||||
initMenu = router.getMenu()[0].children
|
||||
}
|
||||
} else {
|
||||
initMenu = router.getMenu()[0].children
|
||||
}
|
||||
menu.value = filterUrl(initMenu)
|
||||
showThis()
|
||||
|
||||
onMounted(() => {
|
||||
switchoverTopHeaderThemeColor()
|
||||
})
|
||||
watch(route, (newValue) => {
|
||||
currentRoute.value = route.path
|
||||
// 清理选中的
|
||||
selectedKeys.value = []
|
||||
showThis()
|
||||
if (layoutTagsOpen.value) {
|
||||
const pidKey = getParentKeys(moduleMenu.value, route.path)
|
||||
moduleMenu.value.forEach((item) => {
|
||||
if (pidKey.includes(item.path)) {
|
||||
tagSwitchModule(item.id, route.path)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
// 监听是否开启了顶栏颜色
|
||||
watch(layout, (newValue) => {
|
||||
document.body.setAttribute('data-layout', newValue)
|
||||
if (newValue.includes('doublerow')) {
|
||||
showThis()
|
||||
setDoubleRowSelectedKey()
|
||||
}
|
||||
nextTick(() => {
|
||||
// 顶栏主题色
|
||||
switchoverTopHeaderThemeColor()
|
||||
})
|
||||
})
|
||||
watch(topHeaderThemeColorOpen, (newValue) => {
|
||||
console.log(topHeaderThemeColorOpen)
|
||||
switchoverTopHeaderThemeColor()
|
||||
})
|
||||
watch(topHeaderThemeColorSpread, (newValue) => {
|
||||
switchoverTopHeaderThemeColor()
|
||||
})
|
||||
|
||||
const menuIsCollapseClick = () => {
|
||||
store.toggleConfig('menuIsCollapse')
|
||||
}
|
||||
// 切换顶栏颜色
|
||||
const switchoverTopHeaderThemeColor = () => {
|
||||
console.log('刷新完之后' + topHeaderThemeColorOpen.value)
|
||||
// 界面顶栏设置颜色
|
||||
const header = document.getElementById('snowyHeader')
|
||||
topHeaderThemeColorOpen.value
|
||||
? header.classList.add('snowy-header-primary-color')
|
||||
: header.classList.remove('snowy-header-primary-color')
|
||||
// 判断是否开启了通栏
|
||||
const headerLogin = document.getElementById('snowyHeaderLogo')
|
||||
try {
|
||||
topHeaderThemeColorSpread.value
|
||||
? headerLogin.classList.add('snowy-header-logo-primary-color')
|
||||
: headerLogin.classList.remove('snowy-header-logo-primary-color')
|
||||
} catch (e) {}
|
||||
// 如果是双排菜单,吧第二排的也给渲染了
|
||||
if (layout.value === 'doublerow') {
|
||||
const snowyDoublerowSideTop = document.getElementById('snowyDoublerowSideTop')
|
||||
try {
|
||||
topHeaderThemeColorSpread.value
|
||||
? snowyDoublerowSideTop.classList.add('snowy-doublerow-side-top-primary-color')
|
||||
: snowyDoublerowSideTop.classList.remove('snowy-doublerow-side-top-primary-color')
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置双排菜单下的首列默认选中
|
||||
const setDoubleRowSelectedKey = () => {
|
||||
const pidKey = getParentKeys(menu.value, selectedKeys.value.toString())
|
||||
nextTick(() => {
|
||||
const pidKeyArray = []
|
||||
for (const key in pidKey) {
|
||||
pidKeyArray.push(key)
|
||||
}
|
||||
layoutSiderDowbleMenu.value = pidKeyArray.length > 1
|
||||
})
|
||||
// 设置第一排选中的
|
||||
menu.value.forEach((item) => {
|
||||
if (pidKey !== undefined) {
|
||||
if (pidKey[pidKey.length - 1].toString() === item.path) {
|
||||
doublerowSelectedKey.value = [item.path]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// 菜单展开/关闭的回调
|
||||
const onOpenChange = (keys) => {
|
||||
if (sideUniqueOpen.value) {
|
||||
// 获取最新的
|
||||
const openKey = keys[keys.length - 1]
|
||||
if (keys.length > 1) {
|
||||
// 获取上级
|
||||
openKeys.value = getParentKeys(menu.value, openKey)
|
||||
} else {
|
||||
menu = this.$router.getMenu()[0].children
|
||||
openKeys.value = Array.of(openKey) // new Array(openKey);
|
||||
}
|
||||
// 此菜单为正常模块下的菜单
|
||||
this.menu = this.filterUrl(menu)
|
||||
this.showThis()
|
||||
},
|
||||
mounted() {
|
||||
this.switchoverTopHanderThemeColor()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(globalStore, ['setTheme', 'setIsmobile', 'setLayout', 'setMenuIsCollapse']),
|
||||
// 切换应用
|
||||
switchModule(id) {
|
||||
const menu = this.moduleMenu
|
||||
if (menu.length > 0) {
|
||||
const menus = menu.filter((item) => item.id === id)[0].children
|
||||
if (menus.length > 0) {
|
||||
// 将此模块的唯一值加入缓存
|
||||
tool.data.set('SNOWY_MENU_MODULE_ID', id)
|
||||
// 正儿八百的菜单
|
||||
this.menu = this.filterUrl(menus)
|
||||
// 然后将其跳转至指定界面,默认始终取排序第一的
|
||||
const path = this.traverseChild(this.menu)
|
||||
this.$router.push({ path })
|
||||
} else {
|
||||
this.$message.warning('该模块下无任何菜单')
|
||||
}
|
||||
} else {
|
||||
openKeys.value = keys
|
||||
}
|
||||
}
|
||||
// 获取上级keys
|
||||
const getParentKeys = (data, val) => {
|
||||
const traverse = (array, val) => {
|
||||
// 递归父级key
|
||||
for (const element of array) {
|
||||
if (element.path === val) {
|
||||
return [element.path]
|
||||
}
|
||||
},
|
||||
// 遍历子集获取一个path
|
||||
traverseChild(menu) {
|
||||
if (menu[0].children !== undefined) {
|
||||
if (menu[0].children.length > 0) {
|
||||
return this.traverseChild(menu[0].children)
|
||||
} else {
|
||||
return menu[0].path
|
||||
if (element.children) {
|
||||
const far = traverse(element.children, val)
|
||||
if (far) {
|
||||
return far.concat(element.path)
|
||||
}
|
||||
} else {
|
||||
return menu[0].path
|
||||
}
|
||||
},
|
||||
// 当菜单被选中时
|
||||
onSelect(obj) {
|
||||
this.onSelectTag = true
|
||||
const pathLength = obj.keyPath.length
|
||||
const path = obj.keyPath[pathLength - 1]
|
||||
this.$router.push({ path })
|
||||
// 设置选中
|
||||
this.selectedKeys = obj.selectedKeys
|
||||
},
|
||||
onLayoutResize() {
|
||||
const clientWidth = document.body.clientWidth
|
||||
this.setIsmobile(clientWidth < 992)
|
||||
},
|
||||
// 路由监听高亮
|
||||
showThis() {
|
||||
this.pmenu = this.$route.meta.breadcrumb ? this.$route.meta.breadcrumb[0] : {}
|
||||
const nextTickMenu = this.filterUrl(this.pmenu.children)
|
||||
this.$nextTick(() => {
|
||||
let routeMenu = this.filterUrl(this.pmenu.children)
|
||||
const active = this.$route.meta.active || this.$route.fullPath
|
||||
const parentPathArray = this.getParentKeys(routeMenu, active)
|
||||
if (parentPathArray) {
|
||||
const parentPath = parentPathArray[parentPathArray.length - 1]
|
||||
// 这一串操作下来只为取到最上面的路由的孩子们,最后成为双排菜单的第二排
|
||||
const nextMenuTemp = nextTickMenu.filter((item) => item.path === parentPath)[0].children
|
||||
if (nextMenuTemp) {
|
||||
this.nextMenu = nextTickMenu.filter((item) => item.path === parentPath)[0].children
|
||||
}
|
||||
}
|
||||
this.selectedKeys = new Array(active)
|
||||
if (!this.onSelectTag) {
|
||||
const pidKey = this.getParentKeys(this.menu, active)
|
||||
this.openKeys = pidKey
|
||||
} else if (this.sideUniqueOpen) {
|
||||
const pidKey = this.getParentKeys(this.menu, active)
|
||||
this.openKeys = pidKey
|
||||
}
|
||||
// 双排菜单下
|
||||
if (this.layout === 'doublerow') {
|
||||
this.setDoublerowSelectedKey()
|
||||
}
|
||||
})
|
||||
},
|
||||
// 双排菜单下点击显示右侧分栏
|
||||
showMenu(route) {
|
||||
this.pmenu = route
|
||||
if (this.pmenu.children) {
|
||||
this.nextMenu = this.filterUrl(this.pmenu.children)
|
||||
}
|
||||
if (!route.children || route.children.length === 0) {
|
||||
this.layoutSiderDowbleMenu = false
|
||||
this.$router.push({ path: route.path })
|
||||
} else {
|
||||
this.layoutSiderDowbleMenu = true
|
||||
}
|
||||
if (this.layout === 'doublerow') {
|
||||
this.doublerowSelectedKey = [route.path]
|
||||
}
|
||||
},
|
||||
// 设置双排菜单下的首列默认选中
|
||||
setDoublerowSelectedKey() {
|
||||
const pidKey = this.getParentKeys(this.menu, this.selectedKeys.toString())
|
||||
this.$nextTick(() => {
|
||||
const pidKeyArray = []
|
||||
for (const key in pidKey) {
|
||||
pidKeyArray.push(key)
|
||||
}
|
||||
if (pidKeyArray.length > 1) {
|
||||
this.layoutSiderDowbleMenu = true
|
||||
} else {
|
||||
this.layoutSiderDowbleMenu = false
|
||||
}
|
||||
})
|
||||
// 设置第一排选中的
|
||||
this.menu.forEach((item) => {
|
||||
if (pidKey !== undefined) {
|
||||
if (pidKey[pidKey.length - 1].toString() === item.path) {
|
||||
this.doublerowSelectedKey = [item.path]
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// 菜单展开/关闭的回调
|
||||
onOpenChange(keys) {
|
||||
if (this.sideUniqueOpen) {
|
||||
// 获取最新的
|
||||
const openKey = keys[keys.length - 1]
|
||||
if (keys.length > 1) {
|
||||
// 获取上级
|
||||
const pidKey = this.getParentKeys(this.menu, openKey)
|
||||
this.openKeys = pidKey
|
||||
} else {
|
||||
this.openKeys = Array.of(openKey) // new Array(openKey);
|
||||
}
|
||||
} else {
|
||||
this.openKeys = keys
|
||||
}
|
||||
},
|
||||
// 获取上级keys
|
||||
getParentKeys(data, val) {
|
||||
// 递归父级key
|
||||
for (const element of data) {
|
||||
if (element.path === val) {
|
||||
return [element.path]
|
||||
}
|
||||
if (element.children) {
|
||||
const far = this.getParentKeys(element.children, val)
|
||||
if (far) {
|
||||
return far.concat(element.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 转换外部链接的路由
|
||||
filterUrl(map) {
|
||||
const newMap = []
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
map &&
|
||||
map.forEach((item) => {
|
||||
item.meta = item.meta ? item.meta : {}
|
||||
// 处理隐藏
|
||||
if (item.meta.hidden) {
|
||||
return false
|
||||
}
|
||||
// 处理http
|
||||
if (item.meta.type === 'iframe') {
|
||||
item.path = `/i/${item.name}`
|
||||
}
|
||||
// 递归循环
|
||||
if (item.children && item.children.length > 0) {
|
||||
item.children = this.filterUrl(item.children)
|
||||
}
|
||||
newMap.push(item)
|
||||
})
|
||||
return newMap
|
||||
},
|
||||
menuIsCollapseClick() {
|
||||
this.globalStore.toggleConfig('menuIsCollapse')
|
||||
},
|
||||
// 退出最大化
|
||||
exitMaximize() {
|
||||
document.getElementById('app').classList.remove('main-maximize')
|
||||
},
|
||||
// 切换顶栏颜色
|
||||
switchoverTopHanderThemeColor() {
|
||||
// 界面顶栏设置颜色
|
||||
const header = document.getElementById('snowyHeader')
|
||||
this.topHanderThemeColorOpen
|
||||
? header.classList.add('snowy-header-primary-color')
|
||||
: header.classList.remove('snowy-header-primary-color')
|
||||
// 判断是否开启了通栏
|
||||
const headerLogin = document.getElementById('snowyHeaderLogo')
|
||||
try {
|
||||
this.topHanderThemeColorSpread
|
||||
? headerLogin.classList.add('snowy-header-logo-primary-color')
|
||||
: headerLogin.classList.remove('snowy-header-logo-primary-color')
|
||||
} catch (e) {}
|
||||
// 如果是双排菜单,吧第二排的也给渲染了
|
||||
if (this.layout === 'doublerow') {
|
||||
const snowyDoublerowSideTop = document.getElementById('snowyDoublerowSideTop')
|
||||
try {
|
||||
this.topHanderThemeColorSpread
|
||||
? snowyDoublerowSideTop.classList.add('snowy-doublerow-side-top-primary-color')
|
||||
: snowyDoublerowSideTop.classList.remove('snowy-doublerow-side-top-primary-color')
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return traverse(data, val)
|
||||
}
|
||||
// 双排菜单下点击显示右侧分栏
|
||||
const showMenu = (route) => {
|
||||
pMenu.value = route
|
||||
if (pMenu.value.children) {
|
||||
nextMenu.value = filterUrl(pMenu.value.children)
|
||||
}
|
||||
if (!route.children || route.children.length === 0) {
|
||||
layoutSiderDowbleMenu.value = false
|
||||
router.push({ path: route.path })
|
||||
} else {
|
||||
layoutSiderDowbleMenu.value = true
|
||||
}
|
||||
if (layout.value === 'doublerow') {
|
||||
doublerowSelectedKey.value = [route.path]
|
||||
}
|
||||
}
|
||||
// 当菜单被选中时
|
||||
const onSelect = (obj) => {
|
||||
onSelectTag.value = true
|
||||
const pathLength = obj.keyPath.length
|
||||
const path = obj.keyPath[pathLength - 1]
|
||||
router.push({ path })
|
||||
// 设置选中
|
||||
selectedKeys.value = obj.selectedKeys
|
||||
}
|
||||
const onLayoutResize = () => {
|
||||
const clientWidth = document.body.clientWidth
|
||||
store.setIsMobile(clientWidth < 992)
|
||||
}
|
||||
// 切换应用
|
||||
const switchModule = (id) => {
|
||||
if (moduleMenu.value.length > 0) {
|
||||
showThis()
|
||||
const menus = moduleMenu.value.filter((item) => item.id === id)[0].children
|
||||
if (menus.length > 0) {
|
||||
// 将此模块的唯一值加入缓存
|
||||
tool.data.set('SNOWY_MENU_MODULE_ID', id)
|
||||
// 正儿八百的菜单
|
||||
menu.value = filterUrl(menus)
|
||||
// 然后将其跳转至指定界面,默认始终取排序第一的
|
||||
const path = traverseChild(menu.value)
|
||||
router.push({ path })
|
||||
} else {
|
||||
message.warning('该模块下无任何菜单')
|
||||
}
|
||||
}
|
||||
}
|
||||
// 通过标签切换应用
|
||||
const tagSwitchModule = (id, path) => {
|
||||
// 将此模块的唯一值加入缓存
|
||||
tool.data.set('SNOWY_MENU_MODULE_ID', id)
|
||||
store.setModule(id)
|
||||
const menus = moduleMenu.value.filter((item) => item.id === id)[0].children
|
||||
// 正儿八百的菜单
|
||||
menu.value = filterUrl(menus)
|
||||
router.push({ path })
|
||||
}
|
||||
// 遍历子集获取一个path
|
||||
const traverseChild = (menu) => {
|
||||
if (menu[0].children !== undefined) {
|
||||
if (menu[0].children.length > 0) {
|
||||
return traverseChild(menu[0].children)
|
||||
} else {
|
||||
return menu[0].path
|
||||
}
|
||||
} else {
|
||||
return menu[0].path
|
||||
}
|
||||
}
|
||||
// 退出最大化
|
||||
const exitMaximize = () => {
|
||||
document.getElementById('app').classList.remove('main-maximize')
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
<template>
|
||||
<a-layout>
|
||||
<a-layout-sider
|
||||
v-if="!isMobile"
|
||||
v-model:collapsed="menuIsCollapse"
|
||||
:trigger="null"
|
||||
collapsible
|
||||
:theme="sideTheme"
|
||||
width="210"
|
||||
>
|
||||
<header id="snowyHeaderLogo" class="snowy-header-logo">
|
||||
<div class="snowy-header-left">
|
||||
<div class="logo-bar">
|
||||
<img class="logo" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
||||
<span>{{ sysBaseConfig.SNOWY_SYS_NAME }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div :class="menuIsCollapse ? 'admin-ui-side isCollapse' : 'admin-ui-side'">
|
||||
<div class="admin-ui-side-scroll">
|
||||
<a-menu
|
||||
v-model:openKeys="openKeys"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
:theme="sideTheme"
|
||||
mode="inline"
|
||||
@select="onSelect"
|
||||
@openChange="onOpenChange"
|
||||
>
|
||||
<NavMenu :nav-menus="menu" />
|
||||
</a-menu>
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-sider>
|
||||
<!-- 手机端情况下的左侧菜单 -->
|
||||
<Side-m v-if="isMobile" />
|
||||
<!-- 右侧布局 -->
|
||||
<a-layout>
|
||||
<div id="snowyHeader" class="snowy-header">
|
||||
<div class="snowy-header-left" style="padding-left: 0px">
|
||||
<div v-if="!isMobile" class="panel-item hidden-sm-and-down" @click="menuIsCollapseClick">
|
||||
<MenuUnfoldOutlined v-if="menuIsCollapse" />
|
||||
<MenuFoldOutlined v-else />
|
||||
</div>
|
||||
<moduleMenu @switchModule="switchModule" />
|
||||
<top-bar v-if="!isMobile && breadcrumbOpen" />
|
||||
</div>
|
||||
<div class="snowy-header-right">
|
||||
<user-bar />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 多标签 -->
|
||||
<Tags v-if="!isMobile && layoutTagsOpen" />
|
||||
<a-layout-content class="main-content-wrapper">
|
||||
<div id="admin-ui-main" class="admin-ui-main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive :include="keepLiveRoute">
|
||||
<component :is="Component" :key="route.name" v-if="routeShow" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
<iframe-view />
|
||||
<div class="main-bottom-wrapper">
|
||||
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
|
||||
sysBaseConfig.SNOWY_SYS_COPYRIGHT
|
||||
}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script setup name="classicalLayout">
|
||||
import UserBar from '@/layout/components/userbar.vue'
|
||||
import Tags from '@/layout/components/tags.vue'
|
||||
import SideM from '@/layout/components/sideM.vue'
|
||||
import NavMenu from '@/layout/components/NavMenu.vue'
|
||||
import ModuleMenu from '@/layout/components/moduleMenu.vue'
|
||||
import IframeView from '@/layout/components/iframeView.vue'
|
||||
import TopBar from '@/layout/components/topbar.vue'
|
||||
|
||||
const props = defineProps({
|
||||
isMobile: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
menuIsCollapse: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
sideTheme: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
},
|
||||
sysBaseConfig: {
|
||||
type: Object,
|
||||
default: () => undefined
|
||||
},
|
||||
openKeys: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
selectedKeys: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
menu: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
breadcrumbOpen: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
layoutTagsOpen: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
keepLiveRoute: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
routeShow: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
route: {
|
||||
type: Object,
|
||||
default: () => undefined
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['onSelect', 'onOpenChange', 'menuIsCollapseClick', 'switchModule'])
|
||||
const onSelect = (obj) => {
|
||||
emit('onSelect', obj)
|
||||
}
|
||||
// 菜单展开时
|
||||
const onOpenChange = (keys) => {
|
||||
emit('onOpenChange', keys)
|
||||
}
|
||||
// 切换应用时
|
||||
const switchModule = (id) => {
|
||||
emit('switchModule', id)
|
||||
}
|
||||
const menuIsCollapseClick = () => {
|
||||
emit('menuIsCollapseClick')
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,189 @@
|
|||
<template>
|
||||
<a-layout>
|
||||
<a-layout-sider v-if="!isMobile" width="80" :theme="sideTheme" :trigger="null" collapsible>
|
||||
<header id="snowyHeaderLogo" class="snowy-header-logo">
|
||||
<div class="snowy-header-left">
|
||||
<div class="logo-bar">
|
||||
<router-link to="/">
|
||||
<img class="logo" :title="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<a-menu v-model:selectedKeys="doublerowSelectedKey" :theme="sideTheme" class="snowy-doublerow-layout-menu">
|
||||
<a-menu-item
|
||||
v-for="item in menu"
|
||||
:key="item.path"
|
||||
style="
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
height: auto;
|
||||
line-height: 20px;
|
||||
flex: none;
|
||||
display: block;
|
||||
padding: 12px 0 !important;
|
||||
"
|
||||
@click="showMenu(item)"
|
||||
>
|
||||
<a v-if="item.meta && item.meta.type === 'link'" :href="item.path" target="_blank" @click.stop="() => {}"></a>
|
||||
<template #icon>
|
||||
<component :is="item.meta.icon" style="padding-left: 10px" />
|
||||
</template>
|
||||
<div class="snowy-doublerow-layout-menu-item-fort-div">
|
||||
<span class="snowy-doublerow-layout-menu-item-fort-div-span">
|
||||
{{ item.meta.title }}
|
||||
</span>
|
||||
</div>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
<a-layout-sider
|
||||
v-if="!isMobile"
|
||||
v-show="layoutSiderDowbleMenu"
|
||||
v-model:collapsed="menuIsCollapse"
|
||||
:trigger="null"
|
||||
width="170"
|
||||
collapsible
|
||||
:theme="secondMenuSideTheme"
|
||||
>
|
||||
<div v-if="!menuIsCollapse" id="snowyDoublerowSideTop" class="snowy-doublerow-side-top">
|
||||
<h2 class="snowy-title">{{ pMenu.meta.title }}</h2>
|
||||
</div>
|
||||
<a-menu
|
||||
v-model:collapsed="menuIsCollapse"
|
||||
v-model:openKeys="openKeys"
|
||||
v-model:selectedKeys="selectedKeys"
|
||||
mode="inline"
|
||||
:theme="secondMenuSideTheme"
|
||||
@select="onSelect"
|
||||
>
|
||||
<NavMenu :nav-menus="nextMenu" />
|
||||
</a-menu>
|
||||
</a-layout-sider>
|
||||
<!-- 手机端情况下的左侧菜单 -->
|
||||
<Side-m v-if="isMobile" />
|
||||
<a-layout>
|
||||
<div id="snowyHeader" class="snowy-header">
|
||||
<div class="snowy-header-left" style="padding-left: 0px">
|
||||
<moduleMenu @switchModule="switchModule" />
|
||||
<top-bar v-if="!isMobile && breadcrumbOpen" />
|
||||
</div>
|
||||
<div class="snowy-header-right">
|
||||
<user-bar />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 多标签 -->
|
||||
<Tags v-if="!isMobile && layoutTagsOpen"></Tags>
|
||||
<a-layout-content class="main-content-wrapper">
|
||||
<div id="admin-ui-main" class="admin-ui-main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive :include="keepLiveRoute">
|
||||
<component :is="Component" v-if="routeShow" :key="route.name" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
<iframe-view />
|
||||
<div class="main-bottom-wrapper">
|
||||
<a style="color: #a0a0a0" :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL" target="_blank">{{
|
||||
sysBaseConfig.SNOWY_SYS_COPYRIGHT
|
||||
}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
<script setup name="doublerowLayout">
|
||||
import UserBar from '@/layout/components/userbar.vue'
|
||||
import Tags from '@/layout/components/tags.vue'
|
||||
import SideM from '@/layout/components/sideM.vue'
|
||||
import NavMenu from '@/layout/components/NavMenu.vue'
|
||||
import ModuleMenu from '@/layout/components/moduleMenu.vue'
|
||||
import IframeView from '@/layout/components/iframeView.vue'
|
||||
import TopBar from '@/layout/components/topbar.vue'
|
||||
|
||||
const props = defineProps({
|
||||
isMobile: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
menuIsCollapse: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
sideTheme: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
},
|
||||
sysBaseConfig: {
|
||||
type: Object,
|
||||
default: () => undefined
|
||||
},
|
||||
openKeys: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
selectedKeys: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
menu: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
breadcrumbOpen: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
layoutTagsOpen: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
keepLiveRoute: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
routeShow: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
},
|
||||
route: {
|
||||
type: Object,
|
||||
default: () => undefined
|
||||
},
|
||||
layoutSiderDowbleMenu: {
|
||||
type: Boolean,
|
||||
default: () => true
|
||||
},
|
||||
secondMenuSideTheme: {
|
||||
type: String,
|
||||
default: () => undefined
|
||||
},
|
||||
nextMenu: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
doublerowSelectedKey: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
pMenu: {
|
||||
type: Object,
|
||||
default: () => undefined
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['onSelect', 'showMenu', 'onOpenChange', 'menuIsCollapseClick', 'switchModule'])
|
||||
const onSelect = (obj) => {
|
||||
emit('onSelect', obj)
|
||||
}
|
||||
const showMenu = (route) => {
|
||||
emit('showMenu', route)
|
||||
}
|
||||
const menuIsCollapseClick = () => {
|
||||
emit('menuIsCollapseClick')
|
||||
}
|
||||
// 切换应用时
|
||||
const switchModule = (id) => {
|
||||
emit('switchModule', id)
|
||||
}
|
||||
</script>
|
|
@ -12,7 +12,7 @@ import { nextTick } from 'vue'
|
|||
import { viewTagsStore } from '@/store'
|
||||
|
||||
export function beforeEach(to, from) {
|
||||
const adminMain = document.querySelector('#adminui-main')
|
||||
const adminMain = document.querySelector('#admin-ui-main')
|
||||
if (!adminMain) {
|
||||
return false
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ export function beforeEach(to, from) {
|
|||
}
|
||||
|
||||
export function afterEach(to) {
|
||||
const adminMain = document.querySelector('#adminui-main')
|
||||
const adminMain = document.querySelector('#admin-ui-main')
|
||||
if (!adminMain) {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export const globalStore = defineStore({
|
|||
id: 'global',
|
||||
state: () => ({
|
||||
// 移动端布局
|
||||
ismobile: false,
|
||||
isMobile: false,
|
||||
// 布局
|
||||
layout: getCacheConfig('SNOWY_LAYOUT'),
|
||||
// 菜单是否折叠 toggle
|
||||
|
@ -46,9 +46,9 @@ export const globalStore = defineStore({
|
|||
// 是否展示面包屑
|
||||
breadcrumbOpen: getCacheConfig('SNOWY_BREADCRUMD_OPEN'),
|
||||
// 顶栏是否应用主题色
|
||||
topHanderThemeColorOpen: getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_OPEN'),
|
||||
topHeaderThemeColorOpen: getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_OPEN'),
|
||||
// 顶栏主题色通栏
|
||||
topHanderThemeColorSpread: getCacheConfig('SNOWY_TOP_HANDER_THEME_COLOR_SPREAD'),
|
||||
topHeaderThemeColorSpread: getCacheConfig('SNOWY_TOP_HEADER_THEME_COLOR_SPREAD'),
|
||||
// 模块坞
|
||||
moduleUnfoldOpen: getCacheConfig('SNOWY_MODULE_UNFOLD_OPEN'),
|
||||
// 主题
|
||||
|
@ -60,12 +60,14 @@ export const globalStore = defineStore({
|
|||
// 用户信息
|
||||
userInfo: toolDataGet('USER_INFO') || {},
|
||||
// 系统配置
|
||||
sysBaseConfig: toolDataGet('SNOWY_SYS_BASE_CONFIG') || config.SYS_BASE_CONFIG
|
||||
sysBaseConfig: toolDataGet('SNOWY_SYS_BASE_CONFIG') || config.SYS_BASE_CONFIG,
|
||||
// 默认应用
|
||||
module: getCacheConfig('SNOWY_MENU_MODULE_ID')
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
setIsmobile(key) {
|
||||
this.ismobile = key
|
||||
setIsMobile(key) {
|
||||
this.isMobile = key
|
||||
},
|
||||
setLayout(key) {
|
||||
this.layout = key
|
||||
|
@ -95,6 +97,9 @@ export const globalStore = defineStore({
|
|||
},
|
||||
setSysBaseConfig(key) {
|
||||
this.sysBaseConfig = key
|
||||
},
|
||||
setModule(key) {
|
||||
this.module = key
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -33,20 +33,20 @@ a, button, input, textarea {
|
|||
}
|
||||
|
||||
/* 大布局样式 */
|
||||
.aminui {
|
||||
.admin-ui {
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
.aminui-wrapper {
|
||||
.admin-ui-wrapper {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.adminui-main {
|
||||
.admin-ui-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
@ -222,16 +222,16 @@ a, button, input, textarea {
|
|||
}
|
||||
|
||||
/* 面包屑 */
|
||||
.adminui-topbar {
|
||||
.admin-ui-topbar {
|
||||
padding-left: 15px
|
||||
}
|
||||
|
||||
.adminui-topbar .left-panel {
|
||||
.admin-ui-topbar .left-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.adminui-topbar .right-panel {
|
||||
.admin-ui-topbar .right-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -363,7 +363,7 @@ a, button, input, textarea {
|
|||
}
|
||||
|
||||
/*页面最大化*/
|
||||
.aminui.main-maximize {
|
||||
.admin-ui.main-maximize {
|
||||
.main-maximize-exit {
|
||||
display: block;
|
||||
}
|
||||
|
@ -436,9 +436,10 @@ a, button, input, textarea {
|
|||
|
||||
// 滚动条,需要哪里,加哪个class
|
||||
body,
|
||||
.ant-scrolling-effect,
|
||||
.ant-drawer-wrapper-body,
|
||||
.ant-drawer-body,
|
||||
.aminui,
|
||||
.admin-ui,
|
||||
.ant-modal-wrap,
|
||||
.ant-transfer-list-content,
|
||||
.ant-card,
|
||||
|
@ -460,7 +461,7 @@ body,
|
|||
.gen-preview-content,
|
||||
.ant-menu,
|
||||
|
||||
.adminui-main{
|
||||
.admin-ui-main{
|
||||
&::-webkit-scrollbar {
|
||||
/*滚动条整体样式*/
|
||||
width : 0px; /*高宽分别对应横竖滚动条的尺寸*/
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
margin-left: 0px !important;
|
||||
}
|
||||
|
||||
.adminui-main {
|
||||
.admin-ui-main {
|
||||
> .el-container {
|
||||
display: block;
|
||||
height: auto;
|
||||
|
@ -84,43 +84,43 @@
|
|||
}
|
||||
}
|
||||
|
||||
.adminui-main > .el-container > *:first-child:not(.el-aside):not(.el-header) {
|
||||
.admin-ui-main > .el-container > *:first-child:not(.el-aside):not(.el-header) {
|
||||
border: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.adminui-main > .el-container > *:first-child:not(.el-aside):not(.el-header) + .el-aside {
|
||||
.admin-ui-main > .el-container > *:first-child:not(.el-aside):not(.el-header) + .el-aside {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.adminui-main > .el-container > .el-aside {
|
||||
.admin-ui-main > .el-container > .el-aside {
|
||||
border-bottom: 1px solid #ebeef5 !important;
|
||||
}
|
||||
|
||||
.adminui-main > .el-container > .el-container {
|
||||
.admin-ui-main > .el-container > .el-container {
|
||||
border-top: 1px solid #ebeef5;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.adminui-main > .el-container > .el-header {
|
||||
.admin-ui-main > .el-container > .el-header {
|
||||
@extend . headerPublic;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.adminui-main > .el-container > .el-main {
|
||||
.admin-ui-main > .el-container > .el-main {
|
||||
border-top: 1px solid #ebeef5;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.adminui-main > .el-container > .el-main + .el-aside {
|
||||
.admin-ui-main > .el-container > .el-main + .el-aside {
|
||||
border-left: 0 !important;
|
||||
border-top: 1px solid #ebeef5;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.adminui-main > .el-container > .el-container > .el-header {
|
||||
.admin-ui-main > .el-container > .el-container > .el-header {
|
||||
@extend . headerPublic
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue