242 lines
5.6 KiB
Vue
242 lines
5.6 KiB
Vue
<template>
|
||
<header class="layout-header">
|
||
<!-- 左侧:Logo 和系统名称 -->
|
||
<div class="header-left">
|
||
<div class="logo">
|
||
<img src="@/assets/images/logo.webp" alt="logo" />
|
||
<span class="system-name">Admin System</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧:功能按钮和用户信息 -->
|
||
<div class="header-right">
|
||
<!-- 全屏 -->
|
||
<el-tooltip :content="isFullscreen ? '退出全屏' : '全屏'">
|
||
<el-button :icon="isFullscreen ? Crop : FullScreen" circle @click="toggleFullscreen" />
|
||
</el-tooltip>
|
||
|
||
<!-- 语言选择 -->
|
||
<LanguageSelect v-model="languageStore.lang" @change="languageStore.changeLang" />
|
||
|
||
<!-- 用户信息下拉菜单 -->
|
||
<el-dropdown @command="handleCommand" class="user-dropdown">
|
||
<div class="user-info">
|
||
<el-avatar :size="32" class="user-avatar">
|
||
<el-icon :size="20"><User /></el-icon>
|
||
</el-avatar>
|
||
<span class="username">{{ activeUserName }}</span>
|
||
<el-icon class="dropdown-icon"><ArrowDown /></el-icon>
|
||
</div>
|
||
<template #dropdown>
|
||
<el-dropdown-menu>
|
||
<el-dropdown-item command="profile">
|
||
<el-icon><User /></el-icon>
|
||
个人中心
|
||
</el-dropdown-item>
|
||
<el-dropdown-item command="password">
|
||
<el-icon><Lock /></el-icon>
|
||
修改密码
|
||
</el-dropdown-item>
|
||
<el-dropdown-item divided command="logout">
|
||
<el-icon><SwitchButton /></el-icon>
|
||
退出登录
|
||
</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</template>
|
||
</el-dropdown>
|
||
</div>
|
||
</header>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed } from 'vue'
|
||
import {
|
||
Bell,
|
||
Sunny,
|
||
Moon,
|
||
FullScreen,
|
||
Crop,
|
||
User,
|
||
Lock,
|
||
SwitchButton,
|
||
ArrowDown
|
||
} from '@element-plus/icons-vue'
|
||
import { useUserStore } from '@/stores/modules/user'
|
||
import { useLanguageStore } from '@/stores/modules/language'
|
||
import LanguageSelect from '@/components/LanguageSelect/index.vue'
|
||
import { getStorage } from '@/utils/storage'
|
||
|
||
const router = useRouter()
|
||
const userStore = useUserStore()
|
||
const languageStore = useLanguageStore()
|
||
|
||
// 用户信息 - 使用 userStore 的响应式数据
|
||
const activeUserName = computed(() => userStore.userInfo?.username || '-')
|
||
const unreadCount = ref(3) // 未读消息数量
|
||
|
||
// 全屏相关
|
||
const isFullscreen = ref(false)
|
||
const toggleFullscreen = () => {
|
||
if (!document.fullscreenElement) {
|
||
document.documentElement.requestFullscreen()
|
||
isFullscreen.value = true
|
||
} else {
|
||
if (document.exitFullscreen) {
|
||
document.exitFullscreen()
|
||
isFullscreen.value = false
|
||
}
|
||
}
|
||
}
|
||
|
||
// 监听全屏变化
|
||
onMounted(() => {
|
||
document.addEventListener('fullscreenchange', () => {
|
||
isFullscreen.value = !!document.fullscreenElement
|
||
})
|
||
})
|
||
|
||
// 消息通知
|
||
const handleNotification = () => {
|
||
ElMessage.info('暂无新消息')
|
||
unreadCount.value = 0
|
||
}
|
||
|
||
// 用户操作
|
||
const handleCommand = (command: string) => {
|
||
switch (command) {
|
||
case 'profile':
|
||
router.push('/profile/personal-center')
|
||
break
|
||
case 'password':
|
||
router.push('/user/change-password')
|
||
break
|
||
case 'logout':
|
||
handleLogout()
|
||
break
|
||
}
|
||
}
|
||
|
||
// 退出登录
|
||
const handleLogout = () => {
|
||
ElMessageBox.confirm('确定要退出登录吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
const deviceNo = getStorage('device_no') as string
|
||
userStore.logout({ device_no: String(deviceNo) })
|
||
}).catch(() => {
|
||
// 取消退出
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.layout-header {
|
||
height: 60px;
|
||
background: #fff;
|
||
border-bottom: 1px solid var(--el-border-color-light);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 0 20px;
|
||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 1000;
|
||
|
||
.header-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20px;
|
||
|
||
.logo {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
|
||
img {
|
||
height: 32px;
|
||
width: auto;
|
||
}
|
||
|
||
.system-name {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: var(--el-text-color-primary);
|
||
}
|
||
}
|
||
}
|
||
|
||
.header-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
|
||
.notification-badge {
|
||
:deep(.el-badge__content) {
|
||
transform: translateY(-50%) translateX(50%);
|
||
}
|
||
}
|
||
|
||
.el-button {
|
||
border: none;
|
||
background: transparent;
|
||
padding: 8px;
|
||
color: var(--el-text-color-regular);
|
||
|
||
&:hover {
|
||
background: var(--el-fill-color-light);
|
||
color: var(--el-color-primary);
|
||
}
|
||
}
|
||
|
||
.user-dropdown {
|
||
margin-left: 8px;
|
||
cursor: pointer;
|
||
|
||
.user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 4px 8px;
|
||
border-radius: 4px;
|
||
transition: background 0.3s;
|
||
|
||
&:hover {
|
||
background: var(--el-fill-color-light);
|
||
}
|
||
|
||
.user-avatar {
|
||
background: var(--el-color-primary);
|
||
}
|
||
|
||
.username {
|
||
font-size: 14px;
|
||
color: var(--el-text-color-primary);
|
||
max-width: 100px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.dropdown-icon {
|
||
font-size: 12px;
|
||
color: var(--el-text-color-regular);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 暗色模式适配
|
||
:deep(.dark) {
|
||
.layout-header {
|
||
background: var(--el-bg-color);
|
||
border-bottom-color: var(--el-border-color-darker);
|
||
}
|
||
}
|
||
</style>
|