Files
bdrp-app/src/pages/me.vue
2026-04-23 14:57:35 +08:00

360 lines
13 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

<script setup>
import { storeToRefs } from 'pinia'
import { computed, onBeforeMount, ref, watch } from 'vue'
import { openCustomerService } from '@/composables/useCustomerService'
import { useAgentStore } from '@/stores/agentStore'
import { useDialogStore } from '@/stores/dialogStore'
import { useUserStore } from '@/stores/userStore'
import headShot from '/static/images/head_shot.webp'
definePage({ layout: 'home' })
const agentStore = useAgentStore()
const userStore = useUserStore()
const dialogStore = useDialogStore()
const { isAgent, level, ExpiryTime } = storeToRefs(agentStore)
const { userAvatar, isLoggedIn, mobile } = storeToRefs(userStore)
const isWeChat = ref(false)
const levelNames = {
'normal': '普通代理',
'': '普通代理',
'VIP': 'VIP代理',
'SVIP': 'SVIP代理',
}
const levelText = {
'normal': '基础代理特权',
'': '基础代理特权',
'VIP': '高级代理特权',
'SVIP': '尊享代理特权',
}
const levelGradient = computed(() => ({
border: {
'normal': '',
'': '',
'VIP': '',
'SVIP': '',
}[level.value],
badge: {
'normal': 'bg-gradient-to-r from-gray-500 to-gray-600',
'': 'bg-gradient-to-r from-gray-500 to-gray-600',
'VIP': 'bg-gradient-to-r from-yellow-500 to-amber-600',
'SVIP': 'bg-gradient-to-r from-purple-500 to-pink-500',
}[level.value],
text: {
'normal': 'text-gray-600',
'': 'text-gray-600',
'VIP': 'text-amber-600',
'SVIP': 'text-purple-600',
}[level.value],
}))
function maskName(name) {
if (!name || name.length < 11)
return name
return `${name.substring(0, 3)}****${name.substring(7)}`
}
function toHistory() {
uni.navigateTo({ url: '/pages/history-query' })
}
function toPromote() {
uni.navigateTo({ url: '/pages/promote' })
}
function toInvitation() {
uni.navigateTo({ url: '/pages/invitation' })
}
function toUserAgreement() {
uni.navigateTo({ url: '/pages/user-agreement' })
}
function toPrivacyPolicy() {
uni.navigateTo({ url: '/pages/privacy-policy' })
}
function redirectToLogin() {
uni.navigateTo({ url: '/pages/login' })
}
function handleLogout() {
uni.removeStorageSync('token')
uni.removeStorageSync('refreshAfter')
uni.removeStorageSync('accessExpire')
uni.removeStorageSync('userInfo')
uni.removeStorageSync('agentInfo')
// 重置状态
userStore.resetUser()
agentStore.resetAgent()
uni.reLaunch({ url: '/pages/index' })
}
function goCancelAccountPage() {
if (!mobile.value) {
uni.showToast({ title: '请先绑定手机号', icon: 'none' })
return
}
uni.navigateTo({ url: '/pages/cancel-account' })
}
function toService() {
openCustomerService()
}
function toVipConfig() {
uni.navigateTo({ url: '/pages/agent-vip-config' })
}
function toVipRenewal() {
uni.navigateTo({ url: '/pages/agent-vip-apply' })
}
function formatExpiryTime(expiryTimeStr) {
if (!expiryTimeStr)
return '未知'
// 假设expiryTimeStr格式是 "YYYY-MM-DD HH:MM:SS"
// 只返回日期部分 "YYYY-MM-DD"
return expiryTimeStr.split(' ')[0]
}
/** 与 bdrp-mini `/static/image/shot_*.png` 一致,资源放在 `src/static/image/` */
function getDefaultAvatar() {
if (!isAgent.value)
return headShot
const normalizedLevel = String(level.value || '').toUpperCase()
switch (normalizedLevel) {
case 'NORMAL':
case 'normal':
case '':
return '/static/image/shot_nonal.png'
case 'VIP':
return '/static/image/shot_vip.png'
case 'SVIP':
return '/static/image/shot_svip.png'
default:
return headShot
}
}
/** 用户头像 URLstore 已 resolve默认图为本地资源加载失败时回退到 headShot */
const avatarDisplay = ref(headShot)
function syncAvatarDisplay() {
avatarDisplay.value = userAvatar.value || getDefaultAvatar()
}
watch([userAvatar, isAgent, level], syncAvatarDisplay, { immediate: true })
function onAvatarError() {
avatarDisplay.value = headShot
}
function showBindPhoneDialog() {
dialogStore.openBindPhone()
}
onBeforeMount(() => {
// 获取存储的用户和代理信息
const userInfo = uni.getStorageSync('userInfo')
if (userInfo) {
try {
const parsedUserInfo = typeof userInfo === 'string' ? JSON.parse(userInfo) : userInfo
userStore.updateUserInfo(parsedUserInfo)
}
catch (e) {
console.error('解析用户信息失败', e)
}
}
const agentInfo = uni.getStorageSync('agentInfo')
if (agentInfo) {
try {
const parsedAgentInfo = typeof agentInfo === 'string' ? JSON.parse(agentInfo) : agentInfo
agentStore.updateAgentInfo(parsedAgentInfo)
}
catch (e) {
console.error('解析代理信息失败', e)
}
}
})
</script>
<template>
<view class="box-border min-h-screen">
<view class="flex flex-col p-4 space-y-6">
<!-- 用户信息卡片 -->
<view
class="group profile-section relative flex items-center gap-4 rounded-xl bg-white p-6 transition-all hover:shadow-xl"
@click="!isLoggedIn ? redirectToLogin() : null">
<view class="relative">
<!-- 头像容器添加overflow-hidden解决边框问题 -->
<view class="overflow-hidden rounded-full p-0.5" :class="levelGradient.border">
<image :src="avatarDisplay" mode="aspectFill" alt="User Avatar"
class="h-24 w-24 border-4 border-white rounded-full" @error="onAvatarError" />
</view>
<!-- 代理标识 -->
<view v-if="isAgent" class="absolute -bottom-2 -right-2">
<view class="flex items-center justify-center rounded-full px-3 py-1 text-xs text-white font-bold shadow-sm"
:class="levelGradient.badge">
{{ levelNames[level] }}
</view>
</view>
</view>
<view class="space-y-1">
<view class="text-2xl text-gray-800 font-bold">
{{
!isLoggedIn
? "点击登录"
: mobile
? maskName(mobile)
: isWeChat
? "微信用户"
: "未绑定手机号"
}}
</view>
<!-- 手机号绑定提示 -->
<template v-if="isLoggedIn && !mobile">
<view class="cursor-pointer text-sm text-blue-500 hover:underline" @click.stop="showBindPhoneDialog">
点击绑定手机号码
</view>
</template>
<view v-if="isAgent" class="text-sm font-medium" :class="levelGradient.text">
🎖 {{ levelText[level] }}
</view>
</view>
</view>
<VipBanner v-if="isAgent && (level === 'normal' || level === '')" />
<!-- 功能菜单 -->
<view>
<view class="overflow-hidden rounded-xl bg-white shadow-sm">
<template v-if="isAgent && ['VIP', 'SVIP'].includes(level)">
<view
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-purple-50"
@click="toVipConfig">
<view class="flex items-center gap-3">
<image src="/static/images/me/dlbgpz.png" class="h-6 w-6" alt="代理报告配置" />
<text class="text-purple-700 font-medium">
代理报告配置
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
<view
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-amber-50"
@click="toVipRenewal">
<view class="flex items-center gap-3">
<image src="/static/images/me/xfhy.png" class="h-6 w-6" alt="代理会员" />
<view class="flex flex-col items-start">
<text class="text-amber-700 font-medium">
续费代理会员
</text>
<text class="text-xs text-gray-500">
有效期至 {{ formatExpiryTime(ExpiryTime) }}
</text>
</view>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
</template>
<view
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
@click="toPromote">
<view class="flex items-center gap-3">
<image src="/static/images/index/tgbg.png" class="h-6 w-6" alt="推广报告" />
<text class="text-gray-700 font-medium">
推广报告
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
<view
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
@click="toInvitation">
<view class="flex items-center gap-3">
<image src="/static/images/index/yqhy.png" class="h-6 w-6" alt="邀请下级" />
<text class="text-gray-700 font-medium">
邀请下级
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
<view
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
@click="toHistory">
<view class="flex items-center gap-3">
<image src="/static/images/index/wdbg.png" class="h-6 w-6" alt="我的报告" />
<text class="text-gray-700 font-medium">
我的报告
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
<view
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
@click="toUserAgreement">
<view class="flex items-center gap-3">
<image src="/static/images/me/yhxy.png" class="h-6 w-6" alt="用户协议" />
<text class="text-gray-700 font-medium">
用户协议
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
<view
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
@click="toPrivacyPolicy">
<view class="flex items-center gap-3">
<image src="/static/images/me/yszc.png" class="h-6 w-6" alt="隐私政策" />
<text class="text-gray-700 font-medium">
隐私政策
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
<view class="w-full flex items-center justify-between px-6 py-4 transition-colors hover:bg-blue-50"
@click="toService">
<view class="flex items-center gap-3">
<image src="/static/images/me/lxkf.png" class="h-6 w-6" alt="联系客服" />
<text class="text-gray-700 font-medium">
联系客服
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
<view v-if="isLoggedIn && mobile"
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-red-50"
@click="goCancelAccountPage">
<view class="flex items-center gap-3">
<image src="/static/images/me/cancelAccount.svg" class="h-6 w-6" alt="注销账号" />
<text class="text-gray-700 font-medium">
注销账号
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
<view v-if="isLoggedIn && !isWeChat"
class="w-full flex items-center justify-between px-6 py-4 transition-colors hover:bg-red-50"
@click="handleLogout">
<view class="flex items-center gap-3">
<image src="/static/images/me/tcdl.png" class="h-6 w-6" alt="退出登录" />
<text class="text-gray-700 font-medium">
退出登录
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
</view>
</view>
</view>
</view>
</view>
</template>
<style scoped></style>