bonus-ui/src/layout/components/Navbar.vue

548 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<div class="navbar">
<div class="app-title">
<span>{{ title }}</span>
</div>
<div class="menus" @mouseleave="handleMenuLeave">
<div
v-for="(item, index) in menuList"
:key="index"
class="menu-item"
@mouseenter="handleMenuEnter(item)"
@click="handleMenuClick(item)"
>
<div class="menu-btn">
<span v-if="item.redirect == 'index' || item.redirect == 'index1'">
{{ item.children[0].meta.title }}
</span>
<span v-else-if="item.meta && item.meta.title">{{ item.meta.title }}</span>
<div class="tab-item-btn"></div>
</div>
</div>
</div>
<div class="right-menu">
<template v-if="device !== 'mobile'">
<search id="header-search" class="right-menu-item" />
<!-- <screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip> -->
</template>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
<div>
<img :src="avatar" class="user-avatar" />
<span class="nick-name">{{ user.nickName }}</span>
<i class="el-icon-arrow-down" style="color: #fff"></i>
</div>
<el-dropdown-menu slot="dropdown">
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item @click.native="setting = true">
<span>布局设置</span>
</el-dropdown-item>
<el-dropdown-item divided @click.native="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<div style="height: 50px"></div>
<div class="menu-box" v-show="showMenuBox" @mouseenter="handleBoxEnter">
<div class="menu-warp" @mouseleave="handleBoxLeave">
<div class="menu-list">
<div class="list-box">
<div class="menu-title-top" v-if="currentMenu && currentMenu.meta">
<div class="title-tip"></div>
<span class="title-text">{{ currentMenu.meta.title }}</span>
</div>
<div v-for="(child, i) in currentMenu.children || []" :key="i" class="sub-menu-item" v-if="!child.hidden">
<div v-if="child.children && child.children.length">
<div class="menu-title" @click="toggleLevel1(child)">
<div class="children-title-tip"></div>
<span>
<span style="margin-right: 5px">{{ child.meta.title }}</span>
<img
v-if="openLevel1.includes(child.path)"
src="@/assets/images/up.png"
style="width: 14px; height: 14px"
/>
<img v-else src="@/assets/images/down.png" style="width: 14px; height: 14px" />
</span>
<span class="menu-star">
<img src="@/assets/images/star.png" style="width: 10px; height: 9px" />
</span>
</div>
<div v-show="openLevel1.includes(child.path)">
<div v-for="(c2, j) in child.children" :key="j" class="sub-menu-item" v-if="!c2.hidden">
<div v-if="c2.children && c2.children.length">
<div class="menu-title" @click="toggleLevel2(c2)">
{{ c2.meta.title }}
<img
v-if="openLevel2.includes(c2.path)"
src="@/assets/images/up.png"
style="width: 12px; height: 12px; margin-left: 6px"
/>
<img
v-else
src="@/assets/images/down.png"
style="width: 12px; height: 12px; margin-left: 6px"
/>
</div>
<div v-show="openLevel2.includes(c2.path)">
<div
v-for="(c3, k) in c2.children"
:key="k"
class="sub-menu-item"
v-if="!c3.hidden"
@click="goRoute(c3)"
>
{{ c3.meta.title }}
</div>
</div>
</div>
<div v-else class="menu-title" @click="goRoute(c2)">
<span class="child-left">- {{ c2.meta.title }}</span>
<span class="menu-star">
<img src="@/assets/images/star.png" style="width: 10px; height: 9px" />
</span>
</div>
</div>
</div>
</div>
<div v-else class="menu-title" @click="goRoute(child)">
<div class="children-title-tip"></div>
<span>{{ child.meta.title }}</span>
<span class="menu-star">
<img src="@/assets/images/star.png" style="width: 10px; height: 9px" />
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Search from '@/components/HeaderSearch'
import { getUserProfile } from '@/api/system/user'
export default {
components: { Search },
data() {
return {
title: process.env.VUE_APP_TITLE,
user: {},
menuList: [],
showMenuBox: false,
currentMenu: {},
openLevel1: [],
openLevel2: [],
}
},
computed: {
...mapGetters(['sidebarRouters', 'avatar', 'device']),
setting: {
get() {
return this.$store.state.settings.showSettings
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'showSettings',
value: val,
})
},
},
},
created() {
this.getUser()
this.menuList = this.sidebarRouters.filter((route) => !route.hidden)
},
methods: {
getUser() {
getUserProfile().then((response) => {
this.user = response.data
})
},
async logout() {
this.$confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.$store.dispatch('LogOut').then((res) => {
this.$store.dispatch('tagsView/delAllViews')
if (process.env.VUE_APP_BASE_API == '/iws/jxhzb-api') {
window.location.href = 'http://sgwpdm.ah.sgcc.com.cn/iws'
} else {
this.$router.push({ path: '/login' })
}
})
})
.catch((err) => {
console.log('🚀 ~ err-退出登录:', err)
})
},
handleMenuClick(item) {
if (item.redirect == 'index' || item.redirect == 'index1') {
this.$router.push({ path: '/' + item.redirect })
}
},
handleMenuEnter(item) {
if (item.redirect == 'index' || item.redirect == 'index1') {
this.showMenuBox = false
return
}
this.showMenuBox = true
const buildPath = (nodes, parentPath = '') => {
return nodes.map((n) => {
let currentPath = n.path || ''
if (!currentPath.startsWith('/')) {
currentPath = parentPath.replace(/\/$/, '') + '/' + currentPath
}
const newNode = { ...n, fullPath: currentPath }
if (n.children && n.children.length) {
newNode.children = buildPath(n.children, currentPath)
}
return newNode
})
}
const children = buildPath(item.children || [], item.path)
this.currentMenu = {
...item,
fullPath: item.path,
children,
}
const level1 = []
const level2 = []
children.forEach((l1) => {
if (l1.children && l1.children.length) {
level1.push(l1.path)
l1.children.forEach((l2) => {
if (l2.children && l2.children.length) {
level2.push(l2.path)
}
})
}
})
this.openLevel1 = level1
this.openLevel2 = level2
},
handleMenuLeave() {
this.showMenuBox = false
},
handleBoxEnter() {
this.showMenuBox = true
},
handleBoxLeave() {
this.showMenuBox = false
},
goRoute(route) {
if (route.fullPath) {
this.$router.push({ path: route.fullPath, query: route.query })
this.showMenuBox = false
}
},
toggleLevel1(item) {
const idx = this.openLevel1.indexOf(item.path)
if (idx > -1) this.openLevel1.splice(idx, 1)
else this.openLevel1.push(item.path)
},
toggleLevel2(item) {
const idx = this.openLevel2.indexOf(item.path)
if (idx > -1) this.openLevel2.splice(idx, 1)
else this.openLevel2.push(item.path)
},
},
}
</script>
<style lang="scss" scoped>
.navbar {
width: 100%;
height: 50px;
overflow: hidden;
position: fixed;
display: flex;
align-items: center;
justify-content: space-between;
// background: #fff;
// background-image: url('../../assets/images/titleGif.gif');
// background-size: cover;
// background-repeat: no-repeat;
// background-position: center;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
z-index: 10;
.app-title {
width: 314px;
height: 50px;
padding-left: 14px;
font-family: Microsoft YaHei, Microsoft YaHei;
font-weight: bold;
font-size: 20px;
color: #fff;
text-align: center;
display: flex;
align-items: center;
}
.menus {
min-width: 998px;
height: 50px;
line-height: 50px;
flex: 1;
display: flex;
align-items: center;
justify-content: space-around;
margin: 0 20px;
.menu-item {
height: 50px;
cursor: pointer;
font-family: Microsoft YaHei, Microsoft YaHei;
font-weight: bold;
font-size: 16px;
color: #ffffff;
text-align: center;
font-style: normal;
text-transform: none;
.menu-btn {
width: 100%;
text-align: center;
}
// 移入下方横条
&:hover {
.tab-item-btn {
margin: 5px auto 0;
width: 15px;
height: 2px;
margin-top: -8px;
background: #fff;
}
}
}
}
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
.breadcrumb-container {
float: left;
}
.topmenu-container {
position: absolute;
left: 50px;
}
.errLog-container {
display: inline-block;
vertical-align: top;
}
.right-menu {
float: right;
height: 100%;
line-height: 50px;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #bfbfbf; /* 纯黑色,比#262626更黑 */
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background 0.3s;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
}
.avatar-container {
margin-right: 16px;
.user-avatar {
cursor: pointer;
width: 18px;
height: 18px;
vertical-align: text-bottom;
color: #262626;
/* 移除了opacity属性使用color属性实现颜色调整 */
}
.nick-name {
margin: 0 3px;
font-family: Microsoft YaHei, Microsoft YaHei;
font-weight: 400;
font-size: 14px;
color: #ffffff;
text-align: center;
font-style: normal;
text-transform: none;
}
}
}
}
.menu-box {
position: absolute;
z-index: 99999999;
width: 100%;
height: calc(100% - 50px);
// background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
// 蒙层
background: rgba(0, 0, 0, 0.5);
.menu-warp {
width: 100%;
background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
border-radius: 0 0 16px 16px;
}
.menu-list {
padding: 16px 20px;
width: 100%;
min-height: 287px;
background: #f8fdfc;
border-radius: 16px;
font-family: Microsoft YaHei, Microsoft YaHei;
font-weight: 400;
font-size: 14px;
color: #095a4d;
line-height: 30px;
.list-box {
padding: 16px;
width: 290px;
height: 100%;
// background: linear-gradient(0deg, rgba(44, 186, 178, 0) 0%, rgba(44, 186, 178, 0.1) 100%);
background: linear-gradient(180deg, #e6ffff, rgba(233, 255, 255, 0) 90px);
border-radius: 12px;
}
}
.menu-title-top {
width: 100%;
display: flex;
align-items: center;
span {
color: #095a4d;
font-weight: 800;
}
}
.menu-title {
width: 100%;
display: flex;
align-items: center;
cursor: pointer;
// 移入效果
&:hover {
color: #2cbab2;
background: rgba(44, 186, 178, 0.1);
border-radius: 4px;
}
}
.menu-star {
padding-right: 5px;
flex: 1;
display: flex;
justify-content: flex-end;
align-items: center;
opacity: 0; // 默认不显示
transition: opacity 0.2s;
}
/* hover 当前行时,显示星标 */
.menu-title:hover .menu-star {
opacity: 1;
}
.title-tip {
margin-right: 4px;
width: 8px;
height: 16px;
line-height: 24px;
background: #2cbab2;
margin-bottom: 20px;
border-radius: 4px 4px 4px 4px;
}
.title-text {
font-size: 18px;
// color: #0f7969;
line-height: 24px;
font-weight: 700;
margin-bottom: 20px;
}
.children-title-tip {
margin-right: 4px;
width: 8px;
height: 8px;
background: #2cbab2;
border-radius: 50%;
}
.child-left {
// 与父节点左边距2个字符
margin-left: 1rem;
}
}
/* 只改“下一级里的”二级、三级颜色 */
.menu-box {
/* 二级child.children 里面的 menu-title */
.sub-menu-item {
.sub-menu-item {
> .menu-title {
color: #333;
}
/* 三级:最里面的 sub-menu-item */
.sub-menu-item {
color: #333;
}
}
}
}
</style>