Files
sunProduct/src/layout/components/Navbar.vue
2026-09-20 08:57:53 +08:00

271 lines
6.7 KiB
Vue

<template>
<div :class="'nav' + navType" class="navbar">
<hamburger
v-show="Showhamburger"
id="hamburger-container"
:is-active="appStore.sidebar.opened"
class="hamburger-container"
@toggle-click="toggleSideBar"
>
</hamburger>
<div class="flex-1 h-full"></div>
<div class="right-menu flex align-center">
<template v-if="appStore.device !== 'mobile'">
<el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
<div>
<el-popover :persistent="false" :width="400" placement="bottom-end" transition="el-zoom-in-top" trigger="click">
<template #reference>
<el-badge :max="99" :value="newNotice > 0 ? newNotice : ''">
<div class="right-menu-item hover-effect" style="display: block"><svg-icon icon-class="message" /></div>
</el-badge>
</template>
<template #default>
<notice></notice>
</template>
</el-popover>
</div>
</el-tooltip>
</template>
<div class="avatar-container">
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
<div class="avatar-wrapper">
<img :src="userStore.avatar" alt="头像" class="user-avatar" />
<el-icon><caret-bottom /></el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-if="isShow" command="changecommunity" divided>
<span>{{ proxy.$t('navbar.community') }}</span>
</el-dropdown-item>
<router-link v-if="isShow" v-has-permi="['system:user:profile']" to="/system/user/profile">
<el-dropdown-item>{{ proxy.$t('navbar.personalCenter') }}</el-dropdown-item>
</router-link>
<el-dropdown-item :divided="isShow" command="logout">
<span>{{ proxy.$t('navbar.logout') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import hamburger from '@/components/Hamburger/index.vue';
import { useAppStore } from '@/store/modules/app';
import { useUserStore } from '@/store/modules/user';
import { useSettingsStore } from '@/store/modules/settings';
import { useNoticeStore } from '@/store/modules/notice';
import notice from './notice/index.vue';
import router from '@/router';
import { ElMessageBoxOptions } from 'element-plus/es/components/message-box/src/message-box.type';
import { CaretBottom } from '@element-plus/icons-vue';
import { closeWebSocket } from '@/utils/websocket';
import { closeSSE } from '@/utils/sse';
const props = defineProps({
Showhamburger: {
type: Boolean,
default: true
}
});
const appStore = useAppStore();
const userStore = useUserStore();
const settingsStore = useSettingsStore();
const noticeStore = storeToRefs(useNoticeStore());
const newNotice = ref(<number>0);
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const navType = computed(() => settingsStore.navType);
// 是否切换了租户
const dynamic = ref(true);
const toggleSideBar = () => {
appStore.toggleSideBar(false);
};
const logout = async () => {
await ElMessageBox.confirm('确定退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
} as ElMessageBoxOptions);
userStore.logout().then(() => {
// 关闭长连接
closeWebSocket();
closeSSE();
router.replace({
path: '/login',
query: {
redirect: encodeURIComponent(router.currentRoute.value.fullPath || '/')
}
});
proxy?.$tab.closeAllPage();
});
};
const routerPush = useRouter();
const changecommunity = () => {
routerPush.push({
path: '/community'
});
};
const route = useRoute();
const isShow = ref(true);
const hiddenAction = ['communitylist'];
onMounted(() => {
if (hiddenAction.includes(typeof route.name === 'string' ? route.name : '')) {
isShow.value = false;
}
});
const emits = defineEmits(['setLayout']);
const setLayout = () => {
emits('setLayout');
};
// 定义Command方法对象 通过key直接调用方法
const commandMap: { [key: string]: any } = {
setLayout,
logout,
changecommunity
};
const handleCommand = (command: string) => {
// 判断是否存在该方法
if (commandMap[command]) {
commandMap[command]();
}
};
//用深度监听 消息
watch(
() => noticeStore.state.value.notices,
(newVal) => {
newNotice.value = newVal.filter((item: any) => !item.read).length;
},
{ deep: true }
);
</script>
<style lang="scss" scoped>
.navbar.navtop {
.hamburger-container {
display: none !important;
}
}
:deep(.el-select .el-input__wrapper) {
height: 30px;
}
:deep(.el-badge__content.is-fixed) {
top: 12px;
}
.align-center {
align-items: center;
}
.navbar {
height: 50px;
overflow: hidden;
position: relative;
background: #dfedff;
background: transparent;
//border-bottom: 1px solid #dfedff;
color: #c0c4cc;
box-shadow: none;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
.hamburger-container {
line-height: 46px;
height: 100%;
cursor: pointer;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
display: flex;
align-items: center;
margin-right: 8px;
&:hover {
background: #fafafa52;
}
}
.topmenu-container {
position: absolute;
left: 50px;
}
.topbar-container {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
overflow: hidden;
margin-left: 8px;
}
.errLog-container {
display: inline-block;
vertical-align: top;
}
.right-menu {
height: 100%;
line-height: 50px;
display: flex;
align-items: center;
&:focus {
outline: none;
}
.right-menu-item {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 18px;
color: #fff;
color: #c0c4cc;
vertical-align: text-bottom;
&.hover-effect {
cursor: pointer;
transition: background 0.3s;
}
}
.avatar-container {
margin-right: 40px;
.avatar-wrapper {
margin-top: 5px;
// margin-left: 20px;
position: relative;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: var(--app-radius-md);
margin-top: 10px;
}
i {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
}
</style>