Files
admin-sjzx/src/layouts/admin/components/navMenus.vue

224 lines
6.2 KiB
Vue
Raw Normal View History

2025-08-27 19:25:29 +08:00
<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"
/>
2026-06-15 17:57:14 +08:00
<span
class="nav-menu-text"
v-if="globalPopUpRef?.eventList?.length > 0"
>
{{ globalPopUpRef.eventList.length > 99 ? '99+' : globalPopUpRef.eventList.length }}
2025-08-27 19:25:29 +08:00
</span>
</div>
</el-tooltip>
2026-06-15 17:57:14 +08:00
2025-08-27 19:25:29 +08:00
<el-dropdown style="height: 100%" @command="handleCommand">
2026-06-15 17:57:14 +08:00
<div class="admin-info" :class="state.currentNavMenu === 'adminInfo' ? 'hover' : ''">
2025-08-27 19:25:29 +08:00
<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">修改密码</el-dropdown-item>
2026-06-15 17:57:14 +08:00
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
2025-08-27 19:25:29 +08:00
</el-dropdown-menu>
</template>
</el-dropdown>
2026-06-15 17:57:14 +08:00
2025-08-27 19:25:29 +08:00
<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'
2026-06-15 17:57:14 +08:00
import { useNavTabs } from '@/stores/navTabs'
import { logout } from '@/api/user-boot/user'
import Config from './config.vue'
2025-08-27 19:25:29 +08:00
import PopupPwd from './popup/password.vue'
import AdminInfo from './popup/adminInfo.vue'
2026-06-15 17:57:14 +08:00
// 环境标识
const IS_LNQR = import.meta.env.VITE_NAME === 'LNqr'
2025-08-27 19:25:29 +08:00
const adminInfo = useAdminInfo()
const navTabs = useNavTabs()
const configStore = useConfig()
2026-06-15 17:57:14 +08:00
// 引用
2025-08-27 19:25:29 +08:00
const popupPwd = ref()
const popupAdminInfo = ref()
2026-06-15 17:57:14 +08:00
const globalPopUpRef = ref()
// 状态
2025-08-27 19:25:29 +08:00
const state = reactive({
currentNavMenu: '',
})
2026-06-15 17:57:14 +08:00
// 打开暂降事件
const temporaryLandingEvent = () => {
if (globalPopUpRef.value) {
globalPopUpRef.value.open()
2025-08-27 19:25:29 +08:00
}
}
2026-06-15 17:57:14 +08:00
// 下拉菜单命令
const handleCommand = async (key: string) => {
2025-08-27 19:25:29 +08:00
switch (key) {
case 'adminInfo':
2026-06-15 17:57:14 +08:00
popupAdminInfo.value?.open()
2025-08-27 19:25:29 +08:00
break
case 'changePwd':
2026-06-15 17:57:14 +08:00
popupPwd.value?.open()
2025-08-27 19:25:29 +08:00
break
2026-06-15 17:57:14 +08:00
case 'logout':
await handleLogout()
2025-08-27 19:25:29 +08:00
break
}
}
2026-06-15 17:57:14 +08:00
// 统一登出逻辑
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.href = '/login'
}
}
}
// 清理本地数据
const clearLocalData = () => {
// 清空 localStorage
window.localStorage.clear()
// 清空用户状态
adminInfo.reset()
// 清空标签页
navTabs.closeTabs()
// 清 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=/;`
})
console.log('✅ 本地数据已全部清空')
}
// 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
2025-08-27 19:25:29 +08:00
}
</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;
2026-06-15 17:57:14 +08:00
left: 20px;
2025-08-27 19:25:29 +08:00
font-size: 12px;
2026-06-15 17:57:14 +08:00
background: #ff0000;
2025-08-27 19:25:29 +08:00
color: #fff;
border-radius: 5px;
padding: 0 3px;
}
2026-06-15 17:57:14 +08:00
@keyframes twinkle {
0% { transform: scale(0); }
80% { transform: scale(1.2); }
100% { transform: scale(1); }
}
2025-08-27 19:25:29 +08:00
</style>