Files
bdrp-app/src/pages/me.vue

361 lines
13 KiB
Vue
Raw Normal View History

2026-04-20 16:42:28 +08:00
<script setup>
import { storeToRefs } from 'pinia'
import { computed, onBeforeMount, ref, watch } from 'vue'
import { openCustomerService } from '@/composables/useCustomerService'
import { useEnv } from '@/composables/useEnv'
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 } = useEnv()
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>