update 重做菜单
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
"swiper": "^6.5.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-awesome-swiper": "^4.1.1",
|
||||
"vue-color": "^2.8.1",
|
||||
"vue-highlight.js": "^3.1.0",
|
||||
"vue-router": "^3.5.1"
|
||||
},
|
||||
|
||||
@@ -4,12 +4,9 @@
|
||||
.main(@nav-background: @layout-header-background;
|
||||
@nav-box-shadow-color: fade(@black, 25%);
|
||||
@nav-scrollbar-background: fade(@white, 50%);
|
||||
@nav-app-color: fade(@white, 35%);
|
||||
@logo-color: @white;
|
||||
@logo-box-shadow: none;
|
||||
@app-selector-color: @white;
|
||||
@app-selector-border-color: fade(@white, 10%);
|
||||
@app-selector-background-color: fade(@white, 30%);
|
||||
@app-selector-box-shadow-color: fade(@white, 15%);
|
||||
@header-action-color: fade(@white, 60%);
|
||||
@header-action-hover-color: @white;
|
||||
@header-action-hover-background: fade(@white, 20%);
|
||||
|
||||
@@ -3,12 +3,9 @@
|
||||
.main(@nav-background: @white;
|
||||
@nav-box-shadow-color: fade(@black, 5%);
|
||||
@nav-scrollbar-background: fade(@black, 30%);
|
||||
@nav-app-color: fade(@black, 35%);
|
||||
@logo-color: @black;
|
||||
@logo-box-shadow: inset -1px -1px 1px @border-color-split;
|
||||
@app-selector-color: @primary-6;
|
||||
@app-selector-border-color: @primary-3;
|
||||
@app-selector-background-color: @primary-1;
|
||||
@app-selector-box-shadow-color: @primary-1;
|
||||
@header-action-color: fade(@black, 35%);
|
||||
@header-action-hover-color: @icon-color-hover;
|
||||
@header-action-hover-background: fade(@black, 5%);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@import (reference) '~@/assets/style/extend.less';
|
||||
@container-width: 1200px;
|
||||
@container-width: 1400px;
|
||||
.container {
|
||||
width: @container-width;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -4,12 +4,9 @@
|
||||
.main(@nav-background: @layout-header-background,
|
||||
@nav-box-shadow-color: fade(@black, 25%),
|
||||
@nav-scrollbar-background: fade(@white, 30%),
|
||||
@nav-app-color: fade(@white, 35%),
|
||||
@logo-color: @white,
|
||||
@logo-box-shadow: none,
|
||||
@app-selector-color: @white,
|
||||
@app-selector-border-color: fade(@white, 10%),
|
||||
@app-selector-background-color: fade(@white, 30%),
|
||||
@app-selector-box-shadow-color: fade(@white, 15%),
|
||||
@header-action-color: fade(@white, 60%),
|
||||
@header-action-hover-color: @white,
|
||||
@header-action-hover-background: fade(@white, 20%),
|
||||
@@ -251,6 +248,52 @@
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
.yo-nav {
|
||||
padding-top: @padding-lg;
|
||||
padding-bottom: @padding-lg;
|
||||
&--row {
|
||||
padding: 1px 0;
|
||||
|
||||
column-gap: @padding-md;
|
||||
column-count: 3;
|
||||
}
|
||||
&--col {
|
||||
break-inside: avoid;
|
||||
}
|
||||
&--sub-item {
|
||||
}
|
||||
&--item-group {
|
||||
font-size: @font-size-base;
|
||||
line-height: 1.5;
|
||||
|
||||
margin-bottom: @padding-xs;
|
||||
padding-top: @padding-xs * 2;
|
||||
|
||||
color: fade(@black, 35%);
|
||||
border: @border-width-base @border-style-base transparent;
|
||||
}
|
||||
&--item {
|
||||
font-size: @font-size-base;
|
||||
line-height: 1.5;
|
||||
|
||||
position: relative;
|
||||
|
||||
margin-bottom: @padding-xs;
|
||||
padding: @padding-xs @padding-sm;
|
||||
|
||||
cursor: pointer;
|
||||
transition: @animation-duration-fast;
|
||||
|
||||
border: @border-width-base @border-style-base @border-color-split;
|
||||
border-radius: @border-radius-base;
|
||||
background-color: @white;
|
||||
&:hover {
|
||||
color: @white;
|
||||
border-color: @primary-color;
|
||||
background-color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
.yo-layout--left-menu,
|
||||
.yo-layout--right-menu {
|
||||
position: absolute;
|
||||
@@ -345,15 +388,21 @@
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
|
||||
display: flex;
|
||||
flex: 1 1 100%;
|
||||
flex-direction: column;
|
||||
|
||||
box-shadow: 2px 0 8px @nav-box-shadow-color;
|
||||
&--app {
|
||||
font-size: @font-size-sm;
|
||||
|
||||
margin-top: @padding-sm;
|
||||
padding: 0 @padding-md;
|
||||
|
||||
color: @nav-app-color;
|
||||
}
|
||||
}
|
||||
.swiper-container {
|
||||
position: absolute;
|
||||
top: (@layout-header-height / 2) + (@padding-xxs * 2);
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
||||
@@ -385,28 +434,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.yo-apps-selector {
|
||||
>span {
|
||||
line-height: @layout-header-height / 2 - 2px;
|
||||
|
||||
display: block;
|
||||
|
||||
height: @layout-header-height / 2;
|
||||
margin: @padding-xxs @padding-xs;
|
||||
|
||||
cursor: pointer;
|
||||
transition: @animation-duration-slow box-shadow;
|
||||
text-align: center;
|
||||
|
||||
color: @app-selector-color;
|
||||
border: @border-width-base @border-style-base @app-selector-border-color;
|
||||
border-radius: @border-radius-base;
|
||||
background-color: @app-selector-background-color;
|
||||
&:hover {
|
||||
box-shadow: 0 0 15px @app-selector-box-shadow-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { api } from '@/common/api'
|
||||
import { token } from '@/common/token'
|
||||
import { GLOBAL_INFO_KEY, ACTIVE_APP_KEY } from '@/common/storage'
|
||||
import { GLOBAL_INFO_KEY } from '@/common/storage'
|
||||
import { encryptByDES, decryptByDES } from '@/util/des'
|
||||
import app from '@/main'
|
||||
|
||||
@@ -50,7 +50,6 @@ const doLogout = () => {
|
||||
if (success) {
|
||||
removeGlobal()
|
||||
token.value = ''
|
||||
window.localStorage.removeItem(ACTIVE_APP_KEY)
|
||||
if (app.$route.path === '/') {
|
||||
app.$router.replace('/login')
|
||||
} else {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
const SESSION_KEY = '__SESSION'
|
||||
const SETTING_KEY = '__SETTINGS'
|
||||
const GLOBAL_INFO_KEY = '__GLOBAL_INFO'
|
||||
const ACTIVE_APP_KEY = '__ACTIVE_APP'
|
||||
|
||||
export {
|
||||
SESSION_KEY,
|
||||
SETTING_KEY,
|
||||
GLOBAL_INFO_KEY,
|
||||
ACTIVE_APP_KEY
|
||||
}
|
||||
@@ -170,7 +170,7 @@ export default {
|
||||
columns: this.columns.filter(p => !p.hidden),
|
||||
bordered: true,
|
||||
size: 'middle',
|
||||
rowKey: record => record.id,
|
||||
rowKey: record => record.id || Math.random().toString(16).slice(2),
|
||||
scroll: { x: 'max-content' }
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
}
|
||||
.home-header-content {
|
||||
margin-left: @padding-lg;
|
||||
h4 {
|
||||
span {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
<yo-image :id="$root.global.info.avatar" :size="64" icon="user" type="avatar" />
|
||||
</div>
|
||||
<div class="home-header-content">
|
||||
<h2>
|
||||
<h4>
|
||||
{{ $moment().format('A') }}好,
|
||||
<span>{{ $root.global.info.nickName || $root.global.info.name }}</span>,欢迎您登录系统!
|
||||
</h2>
|
||||
<p>上次IP:{{ $root.global.info.lastLoginIp }} 上次登录时间:{{ $root.global.info.lastLoginTime }}</p>
|
||||
</h4>
|
||||
<p>
|
||||
<span>上次IP:{{ $root.global.info.lastLoginIp }}</span>
|
||||
<a-divider type="vertical" />
|
||||
<span>上次登录时间:{{ $root.global.info.lastLoginTime }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
|
||||
@@ -7,6 +7,15 @@
|
||||
<a-form-model-item label="唯一编码" prop="code">
|
||||
<a-input placeholder="请输入唯一编码" v-model="form.code" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="图标" prop="icon">
|
||||
<a-input :disabled="true" placeholder="请选择图标" v-model="form.icon">
|
||||
<a-icon :type="form.icon" slot="addonBefore" v-if="form.icon" />
|
||||
<a-icon @click="onOpenSelectIcon" slot="addonAfter" type="setting" />
|
||||
</a-input>
|
||||
</a-form-model-item>
|
||||
<a-form-model-item prop="color">
|
||||
<chrome-picker v-model="form.color" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="排序" prop="sort">
|
||||
<a-input-number
|
||||
:max="1000"
|
||||
@@ -17,13 +26,23 @@
|
||||
/>
|
||||
</a-form-model-item>
|
||||
</div>
|
||||
|
||||
<yo-icon-selector ref="icon-selector" v-model="form.icon" />
|
||||
</a-form-model>
|
||||
</template>
|
||||
<script>
|
||||
import YoIconSelector from '@/components/yoIconSelector';
|
||||
import { Chrome } from 'vue-color';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
YoIconSelector,
|
||||
ChromePicker: Chrome,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
color: '#fff',
|
||||
active: false,
|
||||
},
|
||||
rules: {
|
||||
@@ -58,6 +77,10 @@ export default {
|
||||
this.$refs.form.resetFields();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
onOpenSelectIcon() {
|
||||
this.$refs['icon-selector'].onOpen(this.form.icon);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -10,7 +10,7 @@
|
||||
>
|
||||
<a-icon :type="$root.global.settings.siderCollapsed ? 'menu-unfold' : 'menu-fold'" />
|
||||
</a>
|
||||
<search :menus="nav.menus" />
|
||||
<search :menus="nav.content" />
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<User />
|
||||
@@ -29,9 +29,11 @@
|
||||
</section>
|
||||
<container v-else-if="$root.global.settings.layout === 'top-nav'">
|
||||
<div class="header-actions">
|
||||
<a @click="showNav = !showNav" class="header-action mr-md">
|
||||
<a-icon type="menu" />
|
||||
</a>
|
||||
<Logo />
|
||||
<Sider :nav="nav" @open="(nav) => $emit('open', nav)" />
|
||||
<search :menus="nav.menus" />
|
||||
<search :menus="nav.content" />
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<User />
|
||||
@@ -47,12 +49,26 @@
|
||||
<a-icon type="setting" />
|
||||
</a>
|
||||
</div>
|
||||
<a-drawer
|
||||
:body-style="{ padding: 0 }"
|
||||
:closable="false"
|
||||
:get-container="'.ant-layout-content > .ant-tabs'"
|
||||
:visible="showNav"
|
||||
:wrap-style="{ position: 'absolute' }"
|
||||
@close="showNav = false"
|
||||
placement="left"
|
||||
width="38.2%"
|
||||
>
|
||||
<div @blur="showNav = false" @mouseleave="showNav = false">
|
||||
<Nav :nav="nav" @open="showNav = false" />
|
||||
</div>
|
||||
</a-drawer>
|
||||
</container>
|
||||
</a-layout-header>
|
||||
</template>
|
||||
<script>
|
||||
import Logo from '../logo';
|
||||
import Sider from '../sider';
|
||||
import Nav from '../nav';
|
||||
|
||||
import User from './user';
|
||||
import Search from './search';
|
||||
@@ -60,7 +76,7 @@ import Search from './search';
|
||||
export default {
|
||||
components: {
|
||||
Logo,
|
||||
Sider,
|
||||
Nav,
|
||||
|
||||
User,
|
||||
Search,
|
||||
@@ -69,12 +85,16 @@ export default {
|
||||
nav: {
|
||||
default() {
|
||||
return {
|
||||
apps: [],
|
||||
menus: [],
|
||||
content: [],
|
||||
};
|
||||
},
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showNav: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -46,7 +46,7 @@ export default {
|
||||
onSearch(value) {
|
||||
this.searchText = value
|
||||
|
||||
const menus = this.$_.cloneDeep(this.menus)
|
||||
const menus = this.$_.concat.apply(this, this.$_.cloneDeep(this.menus.map(p => p.menu)))
|
||||
|
||||
const search = (m) => {
|
||||
if (!value) return []
|
||||
@@ -83,12 +83,14 @@ export default {
|
||||
return result
|
||||
}
|
||||
|
||||
this.searchResult = unzip(search(menus)).map(p => {
|
||||
const result = unzip(search(menus)).filter(p => p.parents.length).map(p => {
|
||||
return {
|
||||
parents: p.parents.join('-'),
|
||||
children: p.children
|
||||
}
|
||||
})
|
||||
|
||||
this.searchResult = result
|
||||
},
|
||||
|
||||
onSearchSelect(value, node) {
|
||||
|
||||
78
Web/src/views/main/_layout/nav/index.js
Normal file
78
Web/src/views/main/_layout/nav/index.js
Normal file
@@ -0,0 +1,78 @@
|
||||
export default {
|
||||
props: {
|
||||
nav: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
content: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onOpenContentWindow(menu) {
|
||||
this.$emit('open')
|
||||
setTimeout(() => {
|
||||
this.openContentWindow({
|
||||
key: menu.id,
|
||||
title: menu.meta.title,
|
||||
icon: menu.meta.icon,
|
||||
path: menu.component,
|
||||
})
|
||||
}, 300)
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<container mode="container-fluid">
|
||||
{this.nav.content.map((item, i) => {
|
||||
return (
|
||||
<section class="yo-nav">
|
||||
<h5 class="yo-nav--app">{item.app.name}</h5>
|
||||
<div class="yo-nav--row">
|
||||
{
|
||||
item.menu.map(sub => {
|
||||
return (
|
||||
<div class="yo-nav--col">
|
||||
<div class="yo-nav--sub-item">
|
||||
{
|
||||
sub.children ?
|
||||
<div class="yo-nav--item-group">
|
||||
{
|
||||
sub.meta.icon && <a-icon type={sub.meta.icon} class="mr-xs" />
|
||||
}
|
||||
{sub.meta.title}
|
||||
</div>
|
||||
:
|
||||
<div class="yo-nav--item" onClick={() => this.onOpenContentWindow(sub)}>
|
||||
{
|
||||
sub.meta.icon && <a-icon type={sub.meta.icon} class="mr-xs" />
|
||||
}
|
||||
{sub.meta.title}
|
||||
</div>
|
||||
}
|
||||
{
|
||||
sub.children && sub.children.map(menu => {
|
||||
return <div class="yo-nav--item" onClick={() => this.onOpenContentWindow(menu)}>
|
||||
{
|
||||
menu.meta.icon && <a-icon type={menu.meta.icon} class="mr-xs" />
|
||||
}
|
||||
{menu.meta.title}
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
})}
|
||||
</container>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<template>
|
||||
<a-popover :placement="placement" trigger="click">
|
||||
<template slot="content">
|
||||
<a-button-group>
|
||||
<a-button :key="app.code" @click="onChangeApp(app)" v-for="app in apps">{{ app.name }}</a-button>
|
||||
</a-button-group>
|
||||
</template>
|
||||
<div class="yo-apps-selector">
|
||||
<span>{{ appActived.name }}</span>
|
||||
</div>
|
||||
</a-popover>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
apps: {
|
||||
type: Array,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
placement() {
|
||||
const layout = this.$root.global.settings.layout;
|
||||
switch (layout) {
|
||||
case 'left-menu':
|
||||
return 'right';
|
||||
case 'right-menu':
|
||||
return 'left';
|
||||
default:
|
||||
return 'bottom';
|
||||
}
|
||||
},
|
||||
|
||||
appActived() {
|
||||
return this.apps.find((p) => p.active) || {};
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChangeApp(app) {
|
||||
this.$emit('change-app', app);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,138 +0,0 @@
|
||||
<template>
|
||||
<section>
|
||||
<a-layout-sider
|
||||
:collapsed="siderCollapsed === undefined ? $root.global.settings.siderCollapsed : siderCollapsed"
|
||||
@collapse="onCollapse"
|
||||
v-if="$root.global.settings.layout === 'left-menu' || $root.global.settings.layout === 'right-menu'"
|
||||
width="200"
|
||||
>
|
||||
<Logo />
|
||||
<div class="yo-sider-nav">
|
||||
<App :apps="nav.apps" @change-app="(app) => $emit('change-app', app)" />
|
||||
<!-- <swiper :options="siderSwiperOptions" ref="sider-swiper">
|
||||
<swiper-slide>
|
||||
<a-spin :spinning="nav.loading">
|
||||
<a-icon slot="indicator" spin type="loading" />
|
||||
<Menu
|
||||
:menu-style="{ height: '100%', borderRight: 0 }"
|
||||
:nav="nav"
|
||||
@openChange="onMenuOpenChange"
|
||||
mode="inline"
|
||||
/>
|
||||
</a-spin>
|
||||
</swiper-slide>
|
||||
<div class="swiper-scrollbar" id="layout--swiper-scrollbar" slot="scrollbar"></div>
|
||||
</swiper>-->
|
||||
<div class="swiper-container" id="layout--swiper-container">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide">
|
||||
<a-spin :spinning="nav.loading">
|
||||
<a-icon slot="indicator" spin type="loading" />
|
||||
<Menu
|
||||
:menu-style="{ height: '100%', borderRight: 0 }"
|
||||
:nav="nav"
|
||||
@openChange="onMenuOpenChange"
|
||||
mode="inline"
|
||||
/>
|
||||
</a-spin>
|
||||
</div>
|
||||
<div class="swiper-scrollbar" id="layout--swiper-scrollbar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-sider>
|
||||
<template v-else-if="$root.global.settings.layout === 'top-nav'">
|
||||
<Menu
|
||||
:menu-style="{ borderBottom: 0 }"
|
||||
:nav="nav"
|
||||
@openChange="onMenuOpenChange"
|
||||
mode="horizontal"
|
||||
/>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
import Logo from '../logo';
|
||||
import App from './app';
|
||||
import Menu from './menu';
|
||||
|
||||
import Swiper from 'swiper';
|
||||
|
||||
let timer,
|
||||
swiper,
|
||||
siderSwiperOptions = {
|
||||
direction: 'vertical',
|
||||
slidesPerView: 'auto',
|
||||
freeMode: true,
|
||||
scrollbar: {
|
||||
el: '#layout--swiper-scrollbar',
|
||||
},
|
||||
mousewheel: true,
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Logo,
|
||||
App,
|
||||
Menu,
|
||||
},
|
||||
props: {
|
||||
nav: {
|
||||
default() {
|
||||
return {
|
||||
apps: [],
|
||||
menus: [],
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
siderCollapsed: undefined,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
swiper = new Swiper('#layout--swiper-container', siderSwiperOptions);
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
if (this.$root.global.settings.layout === 'left-menu' || this.$root.global.settings.layout === 'right-menu') {
|
||||
if (!this.$root.global.settings.siderCollapsed) {
|
||||
if (window.innerWidth < 1000) {
|
||||
this.siderCollapsed = true;
|
||||
} else {
|
||||
this.siderCollapsed = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
this.onUpdateSwiper();
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
onUpdateSwiper() {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
// if (this.$refs['sider-swiper']) {
|
||||
// this.$refs['sider-swiper'].$swiper.update();
|
||||
// }
|
||||
swiper.update();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
onMenuOpenChange() {
|
||||
this.onUpdateSwiper();
|
||||
},
|
||||
|
||||
onCollapse() {
|
||||
this.onUpdateSwiper();
|
||||
},
|
||||
|
||||
windowTriggerResize() {
|
||||
let e = new Event('resize');
|
||||
window.dispatchEvent(e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -8,7 +8,6 @@
|
||||
>
|
||||
<Logo />
|
||||
<div class="yo-sider-nav">
|
||||
<App :apps="nav.apps" @change-app="(app) => $emit('change-app', app)" />
|
||||
<div class="swiper-container" id="layout--swiper-container">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide">
|
||||
@@ -27,19 +26,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</a-layout-sider>
|
||||
<template v-else-if="$root.global.settings.layout === 'top-nav'">
|
||||
<Menu
|
||||
:menu-style="{ borderBottom: 0 }"
|
||||
:nav="nav"
|
||||
@openChange="onMenuOpenChange"
|
||||
mode="horizontal"
|
||||
/>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
import Logo from '../logo';
|
||||
import App from './app';
|
||||
import Menu from './menu';
|
||||
|
||||
import Swiper from 'swiper';
|
||||
@@ -59,7 +49,6 @@ let timer,
|
||||
export default {
|
||||
components: {
|
||||
Logo,
|
||||
App,
|
||||
Menu,
|
||||
},
|
||||
props: {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { HmacMD5 } from "crypto-js"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
nav: {
|
||||
default() {
|
||||
return {
|
||||
modules: [],
|
||||
menus: [],
|
||||
content: []
|
||||
}
|
||||
},
|
||||
type: Object,
|
||||
@@ -75,6 +76,17 @@ export default {
|
||||
openChange: this.onMenuOpenChange,
|
||||
}
|
||||
|
||||
return <a-menu {...{ props, on }}>{this.renderMenu(this.nav.menus)}</a-menu>
|
||||
return (<section>
|
||||
{
|
||||
this.nav.content.map(item => {
|
||||
return (
|
||||
<section>
|
||||
<div class="yo-sider-nav--app">{item.app.name}</div>
|
||||
<a-menu {...{ props, on }}>{this.renderMenu(item.menu)}</a-menu>
|
||||
</section>
|
||||
)
|
||||
})
|
||||
}
|
||||
</section>)
|
||||
},
|
||||
}
|
||||
@@ -6,11 +6,7 @@
|
||||
[`yo-layout--${$root.global.settings.layout}`]: true,
|
||||
}"
|
||||
>
|
||||
<Sider
|
||||
:nav="nav"
|
||||
@change-app="onChangeApp"
|
||||
v-if="$root.global.settings.layout === 'left-menu'"
|
||||
/>
|
||||
<Sider :nav="nav" v-if="$root.global.settings.layout === 'left-menu'" />
|
||||
<a-layout>
|
||||
<Header :nav="nav" @reload="onReloadContentWindow" @setting="setting.visible = true" />
|
||||
<a-layout>
|
||||
@@ -40,7 +36,6 @@ import Content from './_layout/content';
|
||||
import Setting from './setting';
|
||||
|
||||
import { setGlobal } from '@/common/login';
|
||||
import { ACTIVE_APP_KEY } from '@/common/storage';
|
||||
|
||||
import { EMPTY_ID } from '@/util/global';
|
||||
|
||||
@@ -65,8 +60,7 @@ export default {
|
||||
},
|
||||
nav: {
|
||||
loading: false,
|
||||
apps: [],
|
||||
menus: [],
|
||||
content: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
@@ -77,15 +71,14 @@ export default {
|
||||
|
||||
this.nav.loading = true;
|
||||
|
||||
this.$api.getLoginUser().then(({ data }) => {
|
||||
this.$api.getLoginUser().then(async ({ data }) => {
|
||||
// 去除应用和菜单信息,存储基本信息
|
||||
const info = this.$_.cloneDeep(data);
|
||||
delete info.apps;
|
||||
delete info.menus;
|
||||
setGlobal(info);
|
||||
|
||||
data.apps.map((p) => (p.active = p.active));
|
||||
this.onSetNav(data);
|
||||
this.nav.content = await this.onSetNav(data);
|
||||
this.nav.loading = false;
|
||||
|
||||
this.$root.global.defaultWindow.map((options) => {
|
||||
@@ -206,37 +199,22 @@ export default {
|
||||
this.$refs.content.onLoadContentWindow(key);
|
||||
},
|
||||
|
||||
onChangeApp(app) {
|
||||
this.nav.loading = true;
|
||||
this.$api.sysMenuChange({ application: app.code }).then(({ data }) => {
|
||||
this.nav.apps.map((p) => (p.active = p.code === app.code));
|
||||
window.localStorage.removeItem(ACTIVE_APP_KEY);
|
||||
this.onSetNav({
|
||||
apps: this.nav.apps,
|
||||
menus: data,
|
||||
});
|
||||
|
||||
this.nav.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
onSetNav(nav) {
|
||||
// 从本地存储获取当前选中的应用及菜单
|
||||
this.nav.apps = nav.apps;
|
||||
const code = window.localStorage.getItem(ACTIVE_APP_KEY);
|
||||
if (code) {
|
||||
this.nav.apps.map((p) => (p.active = p.code === code.code));
|
||||
this.onChangeApp({
|
||||
code,
|
||||
const getNav = [];
|
||||
nav.apps.forEach((app) => {
|
||||
getNav.push({
|
||||
app,
|
||||
});
|
||||
});
|
||||
|
||||
return this.$api
|
||||
.$queue(getNav.map((p) => this.$api.sysMenuChangeAwait({ application: p.app.code })))
|
||||
.then((menus) => {
|
||||
menus.forEach((menu, i) => {
|
||||
getNav[i].menu = this.serializeMenu(menu.data);
|
||||
});
|
||||
return getNav;
|
||||
});
|
||||
} else {
|
||||
// 将默认选中菜单存储
|
||||
const app = nav.apps.find((p) => p.active);
|
||||
if (app) {
|
||||
window.localStorage.setItem(ACTIVE_APP_KEY, app.code);
|
||||
this.serializeMenu(nav.menus);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
serializeMenu(menus) {
|
||||
@@ -252,7 +230,7 @@ export default {
|
||||
return m;
|
||||
};
|
||||
|
||||
this.nav.menus = children[EMPTY_ID] ? serialize(children[EMPTY_ID]) : new Array();
|
||||
return children[EMPTY_ID] ? serialize(children[EMPTY_ID]) : new Array();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2478,6 +2478,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
clamp@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npm.taobao.org/clamp/download/clamp-1.0.1.tgz#66a0e64011816e37196828fdc8c8c147312c8634"
|
||||
integrity sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ=
|
||||
|
||||
class-utils@^0.3.5:
|
||||
version "0.3.6"
|
||||
resolved "https://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
||||
@@ -5437,6 +5442,11 @@ lodash.memoize@^4.1.2:
|
||||
resolved "https://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.throttle@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.nlark.com/lodash.throttle/download/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
|
||||
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
|
||||
|
||||
lodash.toarray@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.npm.taobao.org/lodash.toarray/download/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
|
||||
@@ -5523,6 +5533,11 @@ map-visit@^1.0.0:
|
||||
dependencies:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
material-colors@^1.0.0:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.npm.taobao.org/material-colors/download/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
|
||||
integrity sha1-bRlYhxEmmSzuzHL0vMTY8BCGX0Y=
|
||||
|
||||
md5.js@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||
@@ -8105,7 +8120,7 @@ timsort@^0.3.0:
|
||||
resolved "https://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
|
||||
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
|
||||
|
||||
tinycolor2@^1.4.1:
|
||||
tinycolor2@^1.1.2, tinycolor2@^1.4.1:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.npm.taobao.org/tinycolor2/download/tinycolor2-1.4.2.tgz?cache=0&sync_timestamp=1601056395015&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftinycolor2%2Fdownload%2Ftinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
|
||||
integrity sha1-P2pNEHGtB2dtf6Ry4frECnGdiAM=
|
||||
@@ -8493,6 +8508,16 @@ vue-awesome-swiper@^4.1.1:
|
||||
resolved "https://registry.npm.taobao.org/vue-awesome-swiper/download/vue-awesome-swiper-4.1.1.tgz#8f7ab221ad003021d756b86aa618f429924900fe"
|
||||
integrity sha1-j3qyIa0AMCHXVrhqphj0KZJJAP4=
|
||||
|
||||
vue-color@^2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.npm.taobao.org/vue-color/download/vue-color-2.8.1.tgz#a090f3dcf8ed6f07afdb865cac84b19a73302e70"
|
||||
integrity sha1-oJDz3Pjtbwev24ZcrISxmnMwLnA=
|
||||
dependencies:
|
||||
clamp "^1.0.1"
|
||||
lodash.throttle "^4.0.0"
|
||||
material-colors "^1.0.0"
|
||||
tinycolor2 "^1.1.2"
|
||||
|
||||
vue-eslint-parser@^7.0.0:
|
||||
version "7.6.0"
|
||||
resolved "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.6.0.tgz#01ea1a2932f581ff244336565d712801f8f72561"
|
||||
|
||||
Reference in New Issue
Block a user