update 重做菜单
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
"swiper": "^6.5.0",
|
"swiper": "^6.5.0",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-awesome-swiper": "^4.1.1",
|
"vue-awesome-swiper": "^4.1.1",
|
||||||
|
"vue-color": "^2.8.1",
|
||||||
"vue-highlight.js": "^3.1.0",
|
"vue-highlight.js": "^3.1.0",
|
||||||
"vue-router": "^3.5.1"
|
"vue-router": "^3.5.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,12 +4,9 @@
|
|||||||
.main(@nav-background: @layout-header-background;
|
.main(@nav-background: @layout-header-background;
|
||||||
@nav-box-shadow-color: fade(@black, 25%);
|
@nav-box-shadow-color: fade(@black, 25%);
|
||||||
@nav-scrollbar-background: fade(@white, 50%);
|
@nav-scrollbar-background: fade(@white, 50%);
|
||||||
|
@nav-app-color: fade(@white, 35%);
|
||||||
@logo-color: @white;
|
@logo-color: @white;
|
||||||
@logo-box-shadow: none;
|
@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-color: fade(@white, 60%);
|
||||||
@header-action-hover-color: @white;
|
@header-action-hover-color: @white;
|
||||||
@header-action-hover-background: fade(@white, 20%);
|
@header-action-hover-background: fade(@white, 20%);
|
||||||
|
|||||||
@@ -3,12 +3,9 @@
|
|||||||
.main(@nav-background: @white;
|
.main(@nav-background: @white;
|
||||||
@nav-box-shadow-color: fade(@black, 5%);
|
@nav-box-shadow-color: fade(@black, 5%);
|
||||||
@nav-scrollbar-background: fade(@black, 30%);
|
@nav-scrollbar-background: fade(@black, 30%);
|
||||||
|
@nav-app-color: fade(@black, 35%);
|
||||||
@logo-color: @black;
|
@logo-color: @black;
|
||||||
@logo-box-shadow: inset -1px -1px 1px @border-color-split;
|
@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-color: fade(@black, 35%);
|
||||||
@header-action-hover-color: @icon-color-hover;
|
@header-action-hover-color: @icon-color-hover;
|
||||||
@header-action-hover-background: fade(@black, 5%);
|
@header-action-hover-background: fade(@black, 5%);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@import (reference) '~@/assets/style/extend.less';
|
@import (reference) '~@/assets/style/extend.less';
|
||||||
@container-width: 1200px;
|
@container-width: 1400px;
|
||||||
.container {
|
.container {
|
||||||
width: @container-width;
|
width: @container-width;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
@@ -4,12 +4,9 @@
|
|||||||
.main(@nav-background: @layout-header-background,
|
.main(@nav-background: @layout-header-background,
|
||||||
@nav-box-shadow-color: fade(@black, 25%),
|
@nav-box-shadow-color: fade(@black, 25%),
|
||||||
@nav-scrollbar-background: fade(@white, 30%),
|
@nav-scrollbar-background: fade(@white, 30%),
|
||||||
|
@nav-app-color: fade(@white, 35%),
|
||||||
@logo-color: @white,
|
@logo-color: @white,
|
||||||
@logo-box-shadow: none,
|
@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-color: fade(@white, 60%),
|
||||||
@header-action-hover-color: @white,
|
@header-action-hover-color: @white,
|
||||||
@header-action-hover-background: fade(@white, 20%),
|
@header-action-hover-background: fade(@white, 20%),
|
||||||
@@ -251,6 +248,52 @@
|
|||||||
border-right: 0;
|
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--left-menu,
|
||||||
.yo-layout--right-menu {
|
.yo-layout--right-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -345,15 +388,21 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
box-shadow: 2px 0 8px @nav-box-shadow-color;
|
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 {
|
.swiper-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: (@layout-header-height / 2) + (@padding-xxs * 2);
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 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 { api } from '@/common/api'
|
||||||
import { token } from '@/common/token'
|
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 { encryptByDES, decryptByDES } from '@/util/des'
|
||||||
import app from '@/main'
|
import app from '@/main'
|
||||||
|
|
||||||
@@ -50,7 +50,6 @@ const doLogout = () => {
|
|||||||
if (success) {
|
if (success) {
|
||||||
removeGlobal()
|
removeGlobal()
|
||||||
token.value = ''
|
token.value = ''
|
||||||
window.localStorage.removeItem(ACTIVE_APP_KEY)
|
|
||||||
if (app.$route.path === '/') {
|
if (app.$route.path === '/') {
|
||||||
app.$router.replace('/login')
|
app.$router.replace('/login')
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
const SESSION_KEY = '__SESSION'
|
const SESSION_KEY = '__SESSION'
|
||||||
const SETTING_KEY = '__SETTINGS'
|
const SETTING_KEY = '__SETTINGS'
|
||||||
const GLOBAL_INFO_KEY = '__GLOBAL_INFO'
|
const GLOBAL_INFO_KEY = '__GLOBAL_INFO'
|
||||||
const ACTIVE_APP_KEY = '__ACTIVE_APP'
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
SESSION_KEY,
|
SESSION_KEY,
|
||||||
SETTING_KEY,
|
SETTING_KEY,
|
||||||
GLOBAL_INFO_KEY,
|
GLOBAL_INFO_KEY,
|
||||||
ACTIVE_APP_KEY
|
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ export default {
|
|||||||
columns: this.columns.filter(p => !p.hidden),
|
columns: this.columns.filter(p => !p.hidden),
|
||||||
bordered: true,
|
bordered: true,
|
||||||
size: 'middle',
|
size: 'middle',
|
||||||
rowKey: record => record.id,
|
rowKey: record => record.id || Math.random().toString(16).slice(2),
|
||||||
scroll: { x: 'max-content' }
|
scroll: { x: 'max-content' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,10 @@
|
|||||||
}
|
}
|
||||||
.home-header-content {
|
.home-header-content {
|
||||||
margin-left: @padding-lg;
|
margin-left: @padding-lg;
|
||||||
span {
|
h4 {
|
||||||
color: @primary-color;
|
span {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@@ -9,11 +9,15 @@
|
|||||||
<yo-image :id="$root.global.info.avatar" :size="64" icon="user" type="avatar" />
|
<yo-image :id="$root.global.info.avatar" :size="64" icon="user" type="avatar" />
|
||||||
</div>
|
</div>
|
||||||
<div class="home-header-content">
|
<div class="home-header-content">
|
||||||
<h2>
|
<h4>
|
||||||
{{ $moment().format('A') }}好,
|
{{ $moment().format('A') }}好,
|
||||||
<span>{{ $root.global.info.nickName || $root.global.info.name }}</span>,欢迎您登录系统!
|
<span>{{ $root.global.info.nickName || $root.global.info.name }}</span>,欢迎您登录系统!
|
||||||
</h2>
|
</h4>
|
||||||
<p>上次IP:{{ $root.global.info.lastLoginIp }} 上次登录时间:{{ $root.global.info.lastLoginTime }}</p>
|
<p>
|
||||||
|
<span>上次IP:{{ $root.global.info.lastLoginIp }}</span>
|
||||||
|
<a-divider type="vertical" />
|
||||||
|
<span>上次登录时间:{{ $root.global.info.lastLoginTime }}</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|||||||
@@ -7,6 +7,15 @@
|
|||||||
<a-form-model-item label="唯一编码" prop="code">
|
<a-form-model-item label="唯一编码" prop="code">
|
||||||
<a-input placeholder="请输入唯一编码" v-model="form.code" />
|
<a-input placeholder="请输入唯一编码" v-model="form.code" />
|
||||||
</a-form-model-item>
|
</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-form-model-item label="排序" prop="sort">
|
||||||
<a-input-number
|
<a-input-number
|
||||||
:max="1000"
|
:max="1000"
|
||||||
@@ -17,13 +26,23 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-model-item>
|
</a-form-model-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<yo-icon-selector ref="icon-selector" v-model="form.icon" />
|
||||||
</a-form-model>
|
</a-form-model>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import YoIconSelector from '@/components/yoIconSelector';
|
||||||
|
import { Chrome } from 'vue-color';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
YoIconSelector,
|
||||||
|
ChromePicker: Chrome,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
|
color: '#fff',
|
||||||
active: false,
|
active: false,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
@@ -58,6 +77,10 @@ export default {
|
|||||||
this.$refs.form.resetFields();
|
this.$refs.form.resetFields();
|
||||||
}, 300);
|
}, 300);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onOpenSelectIcon() {
|
||||||
|
this.$refs['icon-selector'].onOpen(this.form.icon);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
>
|
>
|
||||||
<a-icon :type="$root.global.settings.siderCollapsed ? 'menu-unfold' : 'menu-fold'" />
|
<a-icon :type="$root.global.settings.siderCollapsed ? 'menu-unfold' : 'menu-fold'" />
|
||||||
</a>
|
</a>
|
||||||
<search :menus="nav.menus" />
|
<search :menus="nav.content" />
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<User />
|
<User />
|
||||||
@@ -29,9 +29,11 @@
|
|||||||
</section>
|
</section>
|
||||||
<container v-else-if="$root.global.settings.layout === 'top-nav'">
|
<container v-else-if="$root.global.settings.layout === 'top-nav'">
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
|
<a @click="showNav = !showNav" class="header-action mr-md">
|
||||||
|
<a-icon type="menu" />
|
||||||
|
</a>
|
||||||
<Logo />
|
<Logo />
|
||||||
<Sider :nav="nav" @open="(nav) => $emit('open', nav)" />
|
<search :menus="nav.content" />
|
||||||
<search :menus="nav.menus" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<User />
|
<User />
|
||||||
@@ -47,12 +49,26 @@
|
|||||||
<a-icon type="setting" />
|
<a-icon type="setting" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</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>
|
</container>
|
||||||
</a-layout-header>
|
</a-layout-header>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import Logo from '../logo';
|
import Logo from '../logo';
|
||||||
import Sider from '../sider';
|
import Nav from '../nav';
|
||||||
|
|
||||||
import User from './user';
|
import User from './user';
|
||||||
import Search from './search';
|
import Search from './search';
|
||||||
@@ -60,7 +76,7 @@ import Search from './search';
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Logo,
|
Logo,
|
||||||
Sider,
|
Nav,
|
||||||
|
|
||||||
User,
|
User,
|
||||||
Search,
|
Search,
|
||||||
@@ -69,12 +85,16 @@ export default {
|
|||||||
nav: {
|
nav: {
|
||||||
default() {
|
default() {
|
||||||
return {
|
return {
|
||||||
apps: [],
|
content: [],
|
||||||
menus: [],
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
type: Object,
|
type: Object,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showNav: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -46,7 +46,7 @@ export default {
|
|||||||
onSearch(value) {
|
onSearch(value) {
|
||||||
this.searchText = 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) => {
|
const search = (m) => {
|
||||||
if (!value) return []
|
if (!value) return []
|
||||||
@@ -83,12 +83,14 @@ export default {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
this.searchResult = unzip(search(menus)).map(p => {
|
const result = unzip(search(menus)).filter(p => p.parents.length).map(p => {
|
||||||
return {
|
return {
|
||||||
parents: p.parents.join('-'),
|
parents: p.parents.join('-'),
|
||||||
children: p.children
|
children: p.children
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.searchResult = result
|
||||||
},
|
},
|
||||||
|
|
||||||
onSearchSelect(value, node) {
|
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 />
|
<Logo />
|
||||||
<div class="yo-sider-nav">
|
<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-container" id="layout--swiper-container">
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
@@ -27,19 +26,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-layout-sider>
|
</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>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import Logo from '../logo';
|
import Logo from '../logo';
|
||||||
import App from './app';
|
|
||||||
import Menu from './menu';
|
import Menu from './menu';
|
||||||
|
|
||||||
import Swiper from 'swiper';
|
import Swiper from 'swiper';
|
||||||
@@ -59,7 +49,6 @@ let timer,
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Logo,
|
Logo,
|
||||||
App,
|
|
||||||
Menu,
|
Menu,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import { HmacMD5 } from "crypto-js"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
nav: {
|
nav: {
|
||||||
default() {
|
default() {
|
||||||
return {
|
return {
|
||||||
modules: [],
|
content: []
|
||||||
menus: [],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -75,6 +76,17 @@ export default {
|
|||||||
openChange: this.onMenuOpenChange,
|
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,
|
[`yo-layout--${$root.global.settings.layout}`]: true,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<Sider
|
<Sider :nav="nav" v-if="$root.global.settings.layout === 'left-menu'" />
|
||||||
:nav="nav"
|
|
||||||
@change-app="onChangeApp"
|
|
||||||
v-if="$root.global.settings.layout === 'left-menu'"
|
|
||||||
/>
|
|
||||||
<a-layout>
|
<a-layout>
|
||||||
<Header :nav="nav" @reload="onReloadContentWindow" @setting="setting.visible = true" />
|
<Header :nav="nav" @reload="onReloadContentWindow" @setting="setting.visible = true" />
|
||||||
<a-layout>
|
<a-layout>
|
||||||
@@ -40,7 +36,6 @@ import Content from './_layout/content';
|
|||||||
import Setting from './setting';
|
import Setting from './setting';
|
||||||
|
|
||||||
import { setGlobal } from '@/common/login';
|
import { setGlobal } from '@/common/login';
|
||||||
import { ACTIVE_APP_KEY } from '@/common/storage';
|
|
||||||
|
|
||||||
import { EMPTY_ID } from '@/util/global';
|
import { EMPTY_ID } from '@/util/global';
|
||||||
|
|
||||||
@@ -65,8 +60,7 @@ export default {
|
|||||||
},
|
},
|
||||||
nav: {
|
nav: {
|
||||||
loading: false,
|
loading: false,
|
||||||
apps: [],
|
content: [],
|
||||||
menus: [],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -77,15 +71,14 @@ export default {
|
|||||||
|
|
||||||
this.nav.loading = true;
|
this.nav.loading = true;
|
||||||
|
|
||||||
this.$api.getLoginUser().then(({ data }) => {
|
this.$api.getLoginUser().then(async ({ data }) => {
|
||||||
// 去除应用和菜单信息,存储基本信息
|
// 去除应用和菜单信息,存储基本信息
|
||||||
const info = this.$_.cloneDeep(data);
|
const info = this.$_.cloneDeep(data);
|
||||||
delete info.apps;
|
delete info.apps;
|
||||||
delete info.menus;
|
delete info.menus;
|
||||||
setGlobal(info);
|
setGlobal(info);
|
||||||
|
|
||||||
data.apps.map((p) => (p.active = p.active));
|
this.nav.content = await this.onSetNav(data);
|
||||||
this.onSetNav(data);
|
|
||||||
this.nav.loading = false;
|
this.nav.loading = false;
|
||||||
|
|
||||||
this.$root.global.defaultWindow.map((options) => {
|
this.$root.global.defaultWindow.map((options) => {
|
||||||
@@ -206,37 +199,22 @@ export default {
|
|||||||
this.$refs.content.onLoadContentWindow(key);
|
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) {
|
onSetNav(nav) {
|
||||||
// 从本地存储获取当前选中的应用及菜单
|
const getNav = [];
|
||||||
this.nav.apps = nav.apps;
|
nav.apps.forEach((app) => {
|
||||||
const code = window.localStorage.getItem(ACTIVE_APP_KEY);
|
getNav.push({
|
||||||
if (code) {
|
app,
|
||||||
this.nav.apps.map((p) => (p.active = p.code === code.code));
|
});
|
||||||
this.onChangeApp({
|
});
|
||||||
code,
|
|
||||||
|
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) {
|
serializeMenu(menus) {
|
||||||
@@ -252,7 +230,7 @@ export default {
|
|||||||
return m;
|
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"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.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:
|
class-utils@^0.3.5:
|
||||||
version "0.3.6"
|
version "0.3.6"
|
||||||
resolved "https://registry.npm.taobao.org/class-utils/download/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
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"
|
resolved "https://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
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:
|
lodash.toarray@^4.4.0:
|
||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
resolved "https://registry.npm.taobao.org/lodash.toarray/download/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
|
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:
|
dependencies:
|
||||||
object-visit "^1.0.0"
|
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:
|
md5.js@^1.3.4:
|
||||||
version "1.3.5"
|
version "1.3.5"
|
||||||
resolved "https://registry.npm.taobao.org/md5.js/download/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
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"
|
resolved "https://registry.npm.taobao.org/timsort/download/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
|
||||||
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
|
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
|
||||||
|
|
||||||
tinycolor2@^1.4.1:
|
tinycolor2@^1.1.2, tinycolor2@^1.4.1:
|
||||||
version "1.4.2"
|
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"
|
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=
|
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"
|
resolved "https://registry.npm.taobao.org/vue-awesome-swiper/download/vue-awesome-swiper-4.1.1.tgz#8f7ab221ad003021d756b86aa618f429924900fe"
|
||||||
integrity sha1-j3qyIa0AMCHXVrhqphj0KZJJAP4=
|
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:
|
vue-eslint-parser@^7.0.0:
|
||||||
version "7.6.0"
|
version "7.6.0"
|
||||||
resolved "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.6.0.tgz#01ea1a2932f581ff244336565d712801f8f72561"
|
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