229 lines
6.4 KiB
Vue
229 lines
6.4 KiB
Vue
<template>
|
||
<div class="nav-menus" :class="configStore.layout.layoutMode">
|
||
<el-tooltip effect="dark" content="暂降事件" placement="bottom">
|
||
<div @click="temporaryLandingEvent" class="nav-menu-item">
|
||
<Icon
|
||
:color="configStore.getColorVal('headerBarTabColor')"
|
||
class="nav-menu-icon"
|
||
name="el-icon-BellFilled"
|
||
size="18"
|
||
/>
|
||
<span class="nav-menu-text" v-if="globalPopUpRef?.eventList?.length > 0">
|
||
{{ globalPopUpRef.eventList.length > 99 ? '99+' : globalPopUpRef.eventList.length }}
|
||
</span>
|
||
</div>
|
||
</el-tooltip>
|
||
|
||
<el-dropdown style="height: 100%" @command="handleCommand">
|
||
<div class="admin-info" :class="state.currentNavMenu === 'adminInfo' ? 'hover' : ''">
|
||
<el-avatar :size="25" fit="fill">
|
||
<img src="@/assets/avatar.png" alt="" />
|
||
</el-avatar>
|
||
<div class="admin-name">{{ adminInfo.nickname }}</div>
|
||
</div>
|
||
<template #dropdown>
|
||
<el-dropdown-menu>
|
||
<el-dropdown-item command="adminInfo">个人资料</el-dropdown-item>
|
||
<el-dropdown-item command="changePwd" v-if="!IS_LNQR">修改密码</el-dropdown-item>
|
||
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</template>
|
||
</el-dropdown>
|
||
|
||
<Config />
|
||
<PopupPwd ref="popupPwd" />
|
||
<AdminInfo ref="popupAdminInfo" />
|
||
<globalPopUp ref="globalPopUpRef" />
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { reactive, ref } from 'vue'
|
||
import { useConfig } from '@/stores/config'
|
||
import { useAdminInfo } from '@/stores/adminInfo'
|
||
import { useNavTabs } from '@/stores/navTabs'
|
||
import { logout } from '@/api/user-boot/user'
|
||
import { Local } from '@/utils/storage'
|
||
import Config from './config.vue'
|
||
import PopupPwd from './popup/password.vue'
|
||
import AdminInfo from './popup/adminInfo.vue'
|
||
import globalPopUp from './globalPopUp.vue'
|
||
const { replace } = useRouter()
|
||
// 环境标识
|
||
const IS_LNQR = import.meta.env.VITE_NAME === 'LNqr'
|
||
|
||
const adminInfo = useAdminInfo()
|
||
const navTabs = useNavTabs()
|
||
const configStore = useConfig()
|
||
|
||
// 引用
|
||
const popupPwd = ref()
|
||
const popupAdminInfo = ref()
|
||
const globalPopUpRef = ref()
|
||
|
||
// 状态
|
||
const state = reactive({
|
||
currentNavMenu: ''
|
||
})
|
||
|
||
// 打开暂降事件
|
||
const temporaryLandingEvent = () => {
|
||
if (globalPopUpRef.value) {
|
||
globalPopUpRef.value.open()
|
||
}
|
||
}
|
||
|
||
// 下拉菜单命令
|
||
const handleCommand = async (key: string) => {
|
||
switch (key) {
|
||
case 'adminInfo':
|
||
popupAdminInfo.value?.open()
|
||
break
|
||
case 'changePwd':
|
||
popupPwd.value?.open()
|
||
break
|
||
case 'logout':
|
||
await handleLogout()
|
||
break
|
||
}
|
||
}
|
||
|
||
// 统一登出逻辑
|
||
const handleLogout = async () => {
|
||
try {
|
||
// 1. 调用后端登出接口
|
||
await logout()
|
||
// console.log('✅ 后端登出成功')
|
||
} catch (err) {
|
||
// console.error('❌ 登出接口异常', err)
|
||
} finally {
|
||
// 2. 清理本地所有数据
|
||
clearLocalData()
|
||
|
||
// 3. LNqr 环境跳 CAS 登出
|
||
if (IS_LNQR) {
|
||
redirectToCasLogout()
|
||
} else {
|
||
// 普通环境直接跳登录页
|
||
window.location.reload()
|
||
setTimeout(() => {
|
||
replace('/login')
|
||
}, 1000)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 清理本地数据
|
||
const clearLocalData = () => {
|
||
// 清空 localStorage(保留 VXE 自定义列、DevTools 配置)
|
||
Local.clear()
|
||
|
||
// 清空用户状态
|
||
adminInfo.reset()
|
||
|
||
// 清空标签页
|
||
navTabs.closeTabs()
|
||
}
|
||
|
||
// CAS 登出跳转
|
||
const redirectToCasLogout = () => {
|
||
const casLogoutUrl =
|
||
'http://privilege-epri.dcloud.ln.dc.sgcc.com.cn/cas/logout?service=http://privilege-epri.dcloud.ln.dc.sgcc.com.cn/cas/login?service=http://PQMonitoring.dcloud.ln.dc.sgcc.com.cn'
|
||
window.location.href = casLogoutUrl
|
||
// 清 Cookie
|
||
document.cookie.split(';').forEach(cookie => {
|
||
const name = cookie.split('=')[0].trim()
|
||
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.nav-menus.Default {
|
||
border-radius: var(--el-border-radius-base);
|
||
box-shadow: var(--el-box-shadow-light);
|
||
}
|
||
|
||
.nav-menus {
|
||
height: 60px;
|
||
display: flex;
|
||
align-items: center;
|
||
margin-left: auto;
|
||
background-color: v-bind('configStore.getColorVal("headerBarBackground")');
|
||
|
||
.nav-menu-item {
|
||
position: relative;
|
||
height: 100%;
|
||
width: 40px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
|
||
.nav-menu-icon {
|
||
box-sizing: content-box;
|
||
color: v-bind('configStore.getColorVal("headerBarTabColor")');
|
||
}
|
||
|
||
&:hover {
|
||
.icon {
|
||
animation: twinkle 0.3s ease-in-out;
|
||
}
|
||
}
|
||
}
|
||
|
||
.admin-info {
|
||
display: flex;
|
||
height: 100%;
|
||
padding: 0 10px;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
color: v-bind('configStore.getColorVal("headerBarTabColor")');
|
||
|
||
&:hover {
|
||
color: v-bind('configStore.getColorVal("headerBarTabActiveColor")');
|
||
}
|
||
}
|
||
|
||
.admin-name {
|
||
padding-left: 6px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.nav-menu-item:hover,
|
||
.admin-info:hover,
|
||
.nav-menu-item.hover,
|
||
.admin-info.hover {
|
||
background: v-bind('configStore.getColorVal("headerBarHoverBackground")');
|
||
|
||
.nav-menu-icon {
|
||
color: v-bind('configStore.getColorVal("headerBarTabActiveColor")') !important;
|
||
}
|
||
}
|
||
}
|
||
|
||
.nav-menu-text {
|
||
position: absolute;
|
||
top: 13px;
|
||
left: 20px;
|
||
font-size: 12px;
|
||
background: #ff0000;
|
||
color: #fff;
|
||
border-radius: 5px;
|
||
padding: 0 3px;
|
||
}
|
||
|
||
@keyframes twinkle {
|
||
0% {
|
||
transform: scale(0);
|
||
}
|
||
80% {
|
||
transform: scale(1.2);
|
||
}
|
||
100% {
|
||
transform: scale(1);
|
||
}
|
||
}
|
||
</style>
|