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

547 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>{{ 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 class="menu-box" v-show="showMenuBox" @mouseenter="handleBoxEnter" @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 style="font-weight: bold; font-size: 16px">{{ 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 == child.path"
src="@/assets/images/up.png"
style="width: 14px; height: 14px"
alt=""
/>
<img v-else src="@/assets/images/down.png" style="width: 14px; height: 14px" alt="" />
</span>
<span class="menu-star">
<img src="@/assets/images/star.png" style="width: 10px; height: 9px" alt="" />
</span>
</div>
<!-- 二级区域(只在当前一级展开时显示) -->
<div v-show="openLevel1 === 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 }}
</div>
<!-- 三级(只展开当前二级) -->
<div v-show="openLevel2 === 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" alt="" />
</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" alt="" />
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch'
import bonusGit from '@/components/bonus/Git'
import bonusDoc from '@/components/bonus/Doc'
import { getUserProfile } from '@/api/system/user'
export default {
components: {
Breadcrumb,
TopNav,
Hamburger,
Screenfull,
SizeSelect,
Search,
bonusGit,
bonusDoc,
},
data() {
return {
title: process.env.VUE_APP_TITLE,
user: {},
onlyOneChild: null,
basePath: null,
basePath2: null,
menuList: [],
showMenuBox: false,
currentMenu: {}, // 当前 hover 的一级菜单
openLevel1: '', // 当前展开的一级菜单 path
openLevel2: '', // 当前展开的二级菜单 path
}
},
computed: {
...mapGetters(['sidebarRouters', 'sidebar', 'avatar', 'device']),
setting: {
get() {
return this.$store.state.settings.showSettings
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'showSettings',
value: val,
})
},
},
topNav: {
get() {
return this.$store.state.settings.topNav
},
},
},
created() {
this.getUser()
// 过滤掉 sidebarRouters 中隐藏的路由
this.menuList = this.sidebarRouters.filter((route) => !route.hidden)
},
mounted() {},
methods: {
getUser() {
getUserProfile().then((response) => {
this.user = response.data
})
},
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
async logout() {
this.$confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.$store.dispatch('LogOut').then((res) => {
console.log('🚀 ~ res-退出登录:', res)
console.log('logout', process.env.VUE_APP_BASE_API)
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) {
console.log('🚀 ~ item.redirect:', item.redirect)
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
// 构建带 fullPath 的菜单树
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
})
}
this.currentMenu = {
...item,
fullPath: item.path,
children: buildPath(item.children || [], item.path),
}
},
handleMenuLeave() {
this.showMenuBox = false
},
handleBoxEnter() {
this.showMenuBox = true
},
handleBoxLeave() {
this.showMenuBox = false
},
goRoute(route) {
console.log('🚀 ~ route:', route)
if (route.fullPath) {
this.$router.push({
path: route.fullPath,
query: route.query,
})
this.showMenuBox = false
}
},
// 点击一级父节点
toggleLevel1(item) {
console.log('🚀 ~ item:', item)
if (this.openLevel1 === item.path) {
// 已展开 → 收起
this.openLevel1 = ''
this.openLevel2 = ''
} else {
// 展开当前,关闭其它
this.openLevel1 = item.path
this.openLevel2 = ''
}
},
// 点击二级父节点
toggleLevel2(item) {
console.log('🚀 ~ item:', item)
if (this.openLevel2 === item.path) {
this.openLevel2 = ''
} else {
this.openLevel2 = item.path
}
},
},
}
</script>
<style lang="scss" scoped>
.navbar {
height: 50px;
overflow: hidden;
position: relative;
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%);
.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%;
background: linear-gradient(90deg, #00d2be 0%, #4eacff 100%);
.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: #2cbab2;
line-height: 30px;
.list-box {
padding: 16px;
width: 290px;
height: 100%;
background: linear-gradient(0deg, rgba(44, 186, 178, 0.1) 0%, rgba(44, 186, 178, 0) 100%);
border-radius: 8px;
}
}
.menu-title-top {
width: 100%;
display: flex;
align-items: center;
}
.menu-title {
width: 100%;
display: flex;
align-items: center;
cursor: pointer;
// 移入效果
&:hover {
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;
background: #2cbab2;
border-radius: 4px 4px 4px 4px;
}
.children-title-tip {
margin-right: 4px;
width: 8px;
height: 8px;
background: #2cbab2;
border-radius: 50%;
}
.child-left {
// 与父节点左边距2个字符
margin-left: 1rem;
}
}
</style>