179 lines
4.6 KiB
Vue
179 lines
4.6 KiB
Vue
<template>
|
||
<header class="common-header">
|
||
<div class="logo" @click="goHome" style="cursor: pointer;">
|
||
|
||
<slot name="logo">
|
||
<img src="@/assets/imgs/logo.webp" alt="Logo" />
|
||
</slot>
|
||
</div>
|
||
<nav class="nav">
|
||
<slot name="nav"></slot>
|
||
</nav>
|
||
<div class="actions">
|
||
<slot name="actions">
|
||
<el-dropdown @command="handleCommand" placement="bottom-end">
|
||
<div class="user-info cursor-pointer">
|
||
<img
|
||
:src="getAvatarUrl()"
|
||
alt="User Avatar"
|
||
style="
|
||
height: 32px;
|
||
width: 32px;
|
||
border-radius: 50%;
|
||
margin-right: 8px;
|
||
"
|
||
/>
|
||
<span>{{ getUserName() }}</span>
|
||
</div>
|
||
<template #dropdown>
|
||
<el-dropdown-menu>
|
||
<el-dropdown-item command="profile">
|
||
<!-- <el-icon><user /></el-icon> -->
|
||
<i class="fas fa-user"></i>
|
||
<span>个人中心</span>
|
||
</el-dropdown-item>
|
||
<el-dropdown-item command="logout" divided>
|
||
<!-- <el-icon><arrow-right /></el-icon> -->
|
||
<i class="fas fa-sign-out-alt"></i>
|
||
<span>退出登录</span>
|
||
</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</template>
|
||
</el-dropdown>
|
||
</slot>
|
||
</div>
|
||
</header>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
// 安全获取头像URL
|
||
defineOptions({ name: "CommonHeader" });
|
||
import { useRouter } from "vue-router";
|
||
import { User, ArrowRight } from "@element-plus/icons-vue";
|
||
import { ElMessage } from "element-plus";
|
||
import { authAPI } from "@/services/api";
|
||
|
||
const router = useRouter();
|
||
|
||
// 创建一个函数来安全地访问 localStorage
|
||
const getAvatarUrl = () => {
|
||
try {
|
||
// 检查 window 和 localStorage 是否存在
|
||
if (typeof window !== "undefined" && window.localStorage) {
|
||
try {
|
||
const userItem = window.localStorage.getItem("user");
|
||
const userInfo = userItem ? JSON.parse(userItem) : {};
|
||
return userInfo.avatar || "/src/assets/imgs/default_avatar.png";
|
||
} catch (error) {
|
||
console.warn("解析用户信息失败:", error);
|
||
return "/src/assets/imgs/default_avatar.png";
|
||
}
|
||
}
|
||
// 如果 localStorage 不可用,返回默认头像
|
||
return "/src/assets/imgs/default_avatar.png";
|
||
} catch (error) {
|
||
console.warn("获取头像失败:", error);
|
||
return "/src/assets/imgs/default_avatar.png";
|
||
}
|
||
};
|
||
|
||
// 创建一个函数来安全地访问 localStorage 中的用户名
|
||
const getUserName = () => {
|
||
try {
|
||
// 检查 window 和 localStorage 是否存在
|
||
if (typeof window !== "undefined" && window.localStorage) {
|
||
return JSON.parse(window.localStorage.getItem("user") || "{}").nickname;
|
||
}
|
||
// 如果 localStorage 不可用,返回默认用户名
|
||
return "用户";
|
||
} catch (error) {
|
||
console.warn("获取用户名失败:", error);
|
||
return "用户";
|
||
}
|
||
};
|
||
|
||
// 点击logo返回首页
|
||
const goHome = () => {
|
||
router.push('/');
|
||
};
|
||
|
||
// 处理下拉菜单命令
|
||
const handleCommand = (command: string) => {
|
||
switch (command) {
|
||
case "profile":
|
||
handleProfile();
|
||
break;
|
||
case "logout":
|
||
handleLogout();
|
||
break;
|
||
}
|
||
};
|
||
|
||
// 个人中心处理函数
|
||
const handleProfile = () => {
|
||
// 这里可以根据实际项目情况跳转到个人中心页面
|
||
ElMessage.success("跳转到个人中心");
|
||
// 示例:router.push('/profile');
|
||
};
|
||
|
||
// 登出处理函数
|
||
const handleLogout = async () => {
|
||
try {
|
||
// 调用登出API
|
||
await authAPI.logout();
|
||
|
||
// 清除本地登录状态
|
||
if (typeof window !== "undefined" && window.localStorage) {
|
||
window.localStorage.removeItem("user");
|
||
window.localStorage.removeItem("token");
|
||
window.localStorage.removeItem("isAuthenticated");
|
||
window.localStorage.removeItem("token");
|
||
}
|
||
|
||
// 跳转到登录页面
|
||
router.push("/login");
|
||
|
||
ElMessage.success("退出登录成功");
|
||
} catch (error) {
|
||
console.error("退出登录失败:", error);
|
||
ElMessage.error("退出登录失败");
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.common-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
height: 64px;
|
||
padding: 0 24px;
|
||
background: #fff;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||
}
|
||
.logo img {
|
||
height: 40px;
|
||
}
|
||
.nav {
|
||
flex: 1;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
.actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
|
||
.user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.cursor-pointer {
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
</style>
|