2026-09-20 13:49:49 +08:00

163 lines
5.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>