|
@@ -11,20 +11,47 @@
|
|
|
<div class="header-right">
|
|
<div class="header-right">
|
|
|
<lang-popover ref="langPopoverRef" />
|
|
<lang-popover ref="langPopoverRef" />
|
|
|
<div class="avatar-dropdown-container" @click="onToggleAvatarDropdown">
|
|
<div class="avatar-dropdown-container" @click="onToggleAvatarDropdown">
|
|
|
- <img src="@/assets/images/common/logo.svg" class="icon icon-avatar" />
|
|
|
|
|
|
|
+ <img :src="avatarSrc" class="icon icon-avatar" />
|
|
|
<img src="@/assets/images/common/icon_down.svg" class="icon icon-down" />
|
|
<img src="@/assets/images/common/icon_down.svg" class="icon icon-down" />
|
|
|
<div v-if="isAvatarDropdownOpen" class="dropdown-container">
|
|
<div v-if="isAvatarDropdownOpen" class="dropdown-container">
|
|
|
- <div class="uid-info" @click="onCopy">
|
|
|
|
|
- <div class="uid-info-left">
|
|
|
|
|
- <img src="@/assets/images/common/code.svg" />
|
|
|
|
|
- <span> {{ userInfo?.uid }} </span>
|
|
|
|
|
|
|
+ <!-- 用户信息区 -->
|
|
|
|
|
+ <div class="user-profile-section">
|
|
|
|
|
+ <img :src="avatarSrc" class="profile-avatar" />
|
|
|
|
|
+ <div class="profile-info">
|
|
|
|
|
+ <div class="profile-name">{{ userInfo?.nickname || userInfo?.username || 'User' }}</div>
|
|
|
|
|
+ <div class="profile-uid" @click="onCopy">
|
|
|
|
|
+ <span>ID: {{ userInfo?.uid }}</span>
|
|
|
|
|
+ <img src="@/assets/images/common/copy-icon.svg" class="copy-icon" />
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
- <img src="@/assets/images/common/copy-icon.svg" />
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+ <!-- 余额显示 -->
|
|
|
|
|
+ <div class="balance-section">
|
|
|
|
|
+ <div class="balance-label">{{ $t('finance.balance') }}</div>
|
|
|
|
|
+ <div class="balance-value">{{ userInfo?.balance ?? '0.00' }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 基本信息 -->
|
|
|
|
|
+ <div class="info-section">
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <span class="info-label">{{ $t('user.region') }}</span>
|
|
|
|
|
+ <span class="info-value">{{ userInfo?.region || '--' }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <span class="info-label">{{ $t('user.age') }}</span>
|
|
|
|
|
+ <span class="info-value">{{ userInfo?.age || '--' }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="info-item">
|
|
|
|
|
+ <span class="info-label">{{ $t('user.gender') }}</span>
|
|
|
|
|
+ <span class="info-value">{{ genderText }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 退出登录 -->
|
|
|
<div class="logout-wrapper" @click="onLogout">
|
|
<div class="logout-wrapper" @click="onLogout">
|
|
|
<img src="@/assets/images/common/exit.svg" />
|
|
<img src="@/assets/images/common/exit.svg" />
|
|
|
- <span> {{ $t("退出登录") }} </span>
|
|
|
|
|
|
|
+ <span>{{ $t("退出登录") }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -38,12 +65,23 @@
|
|
|
import LangPopover from "@/components/LangPopover/index.vue";
|
|
import LangPopover from "@/components/LangPopover/index.vue";
|
|
|
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
|
|
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
|
|
|
import { useRouter } from "vue-router";
|
|
import { useRouter } from "vue-router";
|
|
|
|
|
+import { useI18n } from "vue-i18n";
|
|
|
import { copyText } from "@/utils/utils";
|
|
import { copyText } from "@/utils/utils";
|
|
|
import { useGlobalStore } from "@/store/modules/globalStore";
|
|
import { useGlobalStore } from "@/store/modules/globalStore";
|
|
|
import { requestGetUserInfo } from "@/api";
|
|
import { requestGetUserInfo } from "@/api";
|
|
|
|
|
+import defaultAvatar from "@/assets/images/common/logo.svg";
|
|
|
|
|
|
|
|
|
|
+const { t } = useI18n();
|
|
|
const router = useRouter();
|
|
const router = useRouter();
|
|
|
const userInfo = ref<UserInfo>();
|
|
const userInfo = ref<UserInfo>();
|
|
|
|
|
+const avatarSrc = computed(() => userInfo.value?.avatar || defaultAvatar);
|
|
|
|
|
+
|
|
|
|
|
+const genderText = computed(() => {
|
|
|
|
|
+ const g = userInfo.value?.gender;
|
|
|
|
|
+ if (g === 1) return t('user.male');
|
|
|
|
|
+ if (g === 2) return t('user.female');
|
|
|
|
|
+ return '--';
|
|
|
|
|
+});
|
|
|
|
|
|
|
|
const isAvatarDropdownOpen = ref(false);
|
|
const isAvatarDropdownOpen = ref(false);
|
|
|
const langPopoverRef = ref<typeof LangPopover>(null);
|
|
const langPopoverRef = ref<typeof LangPopover>(null);
|
|
@@ -72,7 +110,7 @@ const handleClickOutside = (event: Event) => {
|
|
|
|
|
|
|
|
const getUserInfo = async () => {
|
|
const getUserInfo = async () => {
|
|
|
const res = await requestGetUserInfo();
|
|
const res = await requestGetUserInfo();
|
|
|
- userInfo.value = res.data;
|
|
|
|
|
|
|
+ userInfo.value = res.data.user || res.data;
|
|
|
};
|
|
};
|
|
|
const globalStore = useGlobalStore();
|
|
const globalStore = useGlobalStore();
|
|
|
const isLoggedIn = computed(() => globalStore.isLoggedIn);
|
|
const isLoggedIn = computed(() => globalStore.isLoggedIn);
|
|
@@ -155,6 +193,8 @@ onUnmounted(() => {
|
|
|
margin-left: 7px;
|
|
margin-left: 7px;
|
|
|
width: min(8vw, 38.4px);
|
|
width: min(8vw, 38.4px);
|
|
|
height: min(8vw, 38.4px);
|
|
height: min(8vw, 38.4px);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ object-fit: cover;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.icon-down {
|
|
.icon-down {
|
|
@@ -169,52 +209,135 @@ onUnmounted(() => {
|
|
|
position: absolute;
|
|
position: absolute;
|
|
|
top: 150%;
|
|
top: 150%;
|
|
|
right: 0;
|
|
right: 0;
|
|
|
- width: 164px;
|
|
|
|
|
- height: 92px;
|
|
|
|
|
- background: #161617;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
|
|
+ width: 220px;
|
|
|
|
|
+ background: #1e1e20;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
|
- align-items: flex-start;
|
|
|
|
|
- padding: 4px;
|
|
|
|
|
- gap: 4px;
|
|
|
|
|
|
|
+ padding: 12px;
|
|
|
|
|
+ gap: 8px;
|
|
|
z-index: 50;
|
|
z-index: 50;
|
|
|
- box-shadow: 0px 0px 5px 0px rgba(128, 128, 128, 0.2);
|
|
|
|
|
- .uid-info {
|
|
|
|
|
- width: 156px;
|
|
|
|
|
- height: 40px;
|
|
|
|
|
- background: #232325;
|
|
|
|
|
- border-radius: 4px;
|
|
|
|
|
|
|
+ box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.4);
|
|
|
|
|
+
|
|
|
|
|
+ // 用户信息区
|
|
|
|
|
+ .user-profile-section {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- flex-direction: row;
|
|
|
|
|
- justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- padding: 8px 12px;
|
|
|
|
|
gap: 10px;
|
|
gap: 10px;
|
|
|
- cursor: pointer;
|
|
|
|
|
- .uid-info-left {
|
|
|
|
|
|
|
+ padding-bottom: 10px;
|
|
|
|
|
+ border-bottom: 1px solid #2a2a2c;
|
|
|
|
|
+
|
|
|
|
|
+ .profile-avatar {
|
|
|
|
|
+ width: 42px;
|
|
|
|
|
+ height: 42px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ object-fit: cover;
|
|
|
|
|
+ border: 2px solid #e8a820;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .profile-info {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+
|
|
|
|
|
+ .profile-name {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .profile-uid {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+ margin-top: 2px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+
|
|
|
|
|
+ span {
|
|
|
|
|
+ font-size: 11px;
|
|
|
|
|
+ color: #828694;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .copy-icon {
|
|
|
|
|
+ width: 12px;
|
|
|
|
|
+ height: 12px;
|
|
|
|
|
+ opacity: 0.6;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 余额显示
|
|
|
|
|
+ .balance-section {
|
|
|
|
|
+ background: linear-gradient(135deg, #2a2520 0%, #1e1e20 100%);
|
|
|
|
|
+ border: 1px solid #3a3020;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ padding: 10px 12px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+
|
|
|
|
|
+ .balance-label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #828694;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .balance-value {
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ color: #e8a820;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 基本信息
|
|
|
|
|
+ .info-section {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 6px;
|
|
|
|
|
+ padding: 6px 0;
|
|
|
|
|
+ border-bottom: 1px solid #2a2a2c;
|
|
|
|
|
+
|
|
|
|
|
+ .info-item {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- justify-content: flex-start;
|
|
|
|
|
- padding: 0px;
|
|
|
|
|
- gap: 4px;
|
|
|
|
|
- width: 90px;
|
|
|
|
|
- height: 26px;
|
|
|
|
|
|
|
+ padding: 2px 4px;
|
|
|
|
|
+
|
|
|
|
|
+ .info-label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #828694;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .info-value {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #d0d0d0;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 退出登录
|
|
|
.logout-wrapper {
|
|
.logout-wrapper {
|
|
|
- width: 156px;
|
|
|
|
|
- height: 40px;
|
|
|
|
|
- border-radius: 4px;
|
|
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- flex-direction: row;
|
|
|
|
|
- justify-content: flex-start;
|
|
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- padding: 8px 12px;
|
|
|
|
|
- gap: 4px;
|
|
|
|
|
|
|
+ padding: 8px 4px;
|
|
|
|
|
+ gap: 6px;
|
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
|
color: #828694;
|
|
color: #828694;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ transition: background 0.2s;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background: #232325;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ img {
|
|
|
|
|
+ width: 16px;
|
|
|
|
|
+ height: 16px;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|