163 lines
5.4 KiB
Vue
163 lines
5.4 KiB
Vue
<template>
|
||
<div class="header-container">
|
||
<div class="header">
|
||
<!-- 左侧Logo(完全不动) -->
|
||
<div class="logo">
|
||
<img src="@/assets/images/favicon.png" alt="logo" />
|
||
<span class="header-title">元境</span>
|
||
</div>
|
||
|
||
<!-- 右侧操作区 -->
|
||
<div class="header-actions">
|
||
<!-- 登录后显示:充值 + 余额 一体化模块 -->
|
||
<template v-if="loginStore.isLoggedIn">
|
||
<!-- 一体化:余额 + 充值按钮 -->
|
||
<div class="balance-recharge-combo" @click="showRechargeModal = true">
|
||
<div class="balance-main">
|
||
<span class="balance-icon-wrap">
|
||
<i class="iconfont icon-yue"></i>
|
||
</span>
|
||
<div class="balance-copy">
|
||
<span class="balance-label">账户余额</span>
|
||
<span class="balance-text">
|
||
{{ formattedBalance }}
|
||
<span class="balance-unit">元</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<span class="combo-divider"></span>
|
||
<span class="recharge-text">充值</span>
|
||
</div>
|
||
|
||
<!-- 用户信息 -->
|
||
<div class="user-profile" :class="{ 'dropdown-open': userDropdownVisible }">
|
||
<div class="user-trigger" @click="toggleUserDropdown">
|
||
<div class="user-avatar">
|
||
<i class="iconfont icon-a-414126695"></i>
|
||
</div>
|
||
<svg class="dropdown-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M6 9l6 6 6-6" />
|
||
</svg>
|
||
</div>
|
||
|
||
<Transition name="dropdown">
|
||
<div v-if="userDropdownVisible" class="user-dropdown">
|
||
<div class="dropdown-item user-id">
|
||
<span class="item-label">用户名:</span>
|
||
<span class="item-value">{{ loginStore.userInfo?.user?.name || loginStore.userInfo?.user?.username }}</span>
|
||
</div>
|
||
<!-- <div class="dropdown-item user-id">
|
||
<span class="item-label">用户ID:</span>
|
||
<span class="item-value">{{ loginStore.userInfo?.user?.id }}</span>
|
||
</div> -->
|
||
<div class="dropdown-divider"></div>
|
||
<div class="dropdown-item logout" @click="handleLogout">
|
||
<svg class="item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
|
||
<polyline points="16 17 21 12 16 7" />
|
||
<line x1="21" y1="12" x2="9" y2="12" />
|
||
</svg>
|
||
<span>退出登录</span>
|
||
</div>
|
||
</div>
|
||
</Transition>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 未登录:登录按钮 -->
|
||
<!-- <div v-else class="btn" @click="$router.push('/login')">
|
||
登录
|
||
</div> -->
|
||
</div>
|
||
</div>
|
||
|
||
<Recharge v-if="showRechargeModal" @close="showRechargeModal = false" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang='ts'>
|
||
import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
|
||
import Recharge from '@/components/Recharge/Recharge.vue';
|
||
import { useLoginStore } from '@/store/LoginStore';
|
||
import { useRouter } from 'vue-router';
|
||
import { balance } from '@/apis/home';
|
||
import type { BalanceResult } from '@/types/home';
|
||
|
||
const router = useRouter();
|
||
const loginStore = useLoginStore();
|
||
|
||
// 控制充值弹窗
|
||
const showRechargeModal = ref(false);
|
||
// 控制用户下拉
|
||
const userDropdownVisible = ref(false);
|
||
// 余额
|
||
const balances = ref(0);
|
||
// const userDisplayName = computed(() => loginStore.userInfo?.user?.name || loginStore.userInfo?.user?.username || '用户');
|
||
// const userInitial = computed(() => userDisplayName.value.trim().charAt(0).toUpperCase() || 'U');
|
||
const formattedBalance = computed(() => Number(balances.value || 0).toLocaleString('zh-CN'));
|
||
|
||
// 切换下拉菜单
|
||
const toggleUserDropdown = () => {
|
||
userDropdownVisible.value = !userDropdownVisible.value;
|
||
};
|
||
|
||
// 退出登录
|
||
const handleLogout = () => {
|
||
loginStore.logout();
|
||
router.push('/login');
|
||
userDropdownVisible.value = false;
|
||
};
|
||
|
||
// ==============================================
|
||
// 获取余额(仅登录后调用)
|
||
// ==============================================
|
||
const getBalance = async () => {
|
||
try {
|
||
const res = await balance<BalanceResult>();
|
||
if (res.status === 'ok') {
|
||
balances.value = res.data[0].balance;
|
||
}
|
||
} catch (err) {
|
||
console.error('获取余额失败:', err);
|
||
}
|
||
};
|
||
|
||
// ==============================================
|
||
// 监听登录状态 → 登录后才请求余额
|
||
// ==============================================
|
||
watch(
|
||
() => loginStore.isLoggedIn,
|
||
(newVal) => {
|
||
if (newVal) {
|
||
getBalance(); // 登录成功后获取余额
|
||
} else {
|
||
balances.value = 0; // 退出登录清空余额
|
||
}
|
||
},
|
||
{ immediate: true }
|
||
);
|
||
|
||
// 点击外部关闭下拉
|
||
const handleClickOutside = (event: MouseEvent) => {
|
||
const target = event.target as HTMLElement;
|
||
if (!target.closest('.user-profile')) {
|
||
userDropdownVisible.value = false;
|
||
}
|
||
};
|
||
|
||
// 会话超时
|
||
|
||
|
||
onMounted(() => {
|
||
|
||
document.addEventListener('click', handleClickOutside);
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
document.removeEventListener('click', handleClickOutside);
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang='less'>
|
||
@import url('../../assets/less/Header/header.less');
|
||
</style> |