| | |
| | | <view class="header"> |
| | | <view class="user-main" @tap="handleAccountTap"> |
| | | <view class="avatar"> |
| | | <view class="icon" :class="isLoggedIn ? 'icon-camera' : 'icon-user'"></view> |
| | | <!-- 有头像则渲染图片,否则回退图标(已登录相机 / 未登录用户) --> |
| | | <image v-if="avatar" class="avatar-img" :src="avatar" mode="aspectFill" /> |
| | | <view v-else class="icon" :class="isLoggedIn ? 'icon-camera' : 'icon-user'"></view> |
| | | </view> |
| | | <view class="user-text"> |
| | | <!-- 已登录:昵称 + 会员等级;未登录:登录入口 + 引导文案 --> |
| | | <text class="user-name">{{ isLoggedIn ? nickname : '点击登录 / 注册' }}</text> |
| | | <text class="user-name">{{ isLoggedIn ? displayName : '点击登录 / 注册' }}</text> |
| | | <view v-if="isLoggedIn" class="level-pill"> |
| | | <view class="level-medal"> |
| | | <text class="level-medal-text">V</text> |
| | |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 收益数据展示区(343×74pt):未登录或 L0 普通用户不展示 --> |
| | | <!-- 收益数据展示区(343×74pt):未登录或 C 普通用户不展示 --> |
| | | <view v-if="!isRestrictedView" class="earnings-card"> |
| | | <view v-for="item in earnings" :key="item.key" class="earning-item"> |
| | | <text class="earning-label">{{ item.label }}</text> |
| | |
| | | import { computed, ref } from 'vue' |
| | | import { onShow } from '@dcloudio/uni-app' |
| | | import { getToken } from '@/utils/request.js' |
| | | import { getMemberInfo } from '@/api/index.js' |
| | | import { formatYuan } from '@/utils/format.js' |
| | | import config from '@/config/index.js' |
| | | import StockOrderToast from '@/components/stock-order-toast/stock-order-toast.vue' |
| | | |
| | |
| | | /** 登录态:本页需同时兼容「已登录 / 未登录」两种展示,故以本地 token 判定 */ |
| | | const isLoggedIn = ref(false) |
| | | |
| | | /** 用户昵称:用户信息接口未就绪,先本地 mock(联调后替换为 getUserInfo) */ |
| | | const nickname = ref('辉煌G891') |
| | | /** 用户姓名/昵称:登录后由 getMemberInfo 下发;注册未采集,通常为空 */ |
| | | const nickname = ref('') |
| | | |
| | | /** 用户等级:取值 L0~L4,其中 L0 为普通用户;等级接口未联调,先本地 mock(联调后取 getUserInfo 下发等级) */ |
| | | const userLevel = ref('L4') |
| | | /** 用户手机号:登录后由 getMemberInfo 下发(已脱敏,形如 133****5555) */ |
| | | const phone = ref('') |
| | | |
| | | /** 是否受限展示:未登录或 L0 普通用户,个人中心仅展示「收货地址」「联系我们」 */ |
| | | const isRestrictedView = computed(() => !isLoggedIn.value || userLevel.value === 'L0') |
| | | /** 头部展示名:姓名优先,为空时回退展示脱敏手机号 */ |
| | | const displayName = computed(() => nickname.value || phone.value) |
| | | |
| | | /** 收益三栏:未登录态统一展示 0.00 */ |
| | | /** 用户头像:登录后由 getMemberInfo 下发,为空时回退默认图标 */ |
| | | const avatar = ref('') |
| | | |
| | | /** 用户等级:取值 C/L1~L4,登录后由 getMemberInfo 下发;C 为普通用户 */ |
| | | const userLevel = ref('C') |
| | | |
| | | /** 是否受限展示:未登录或 C 普通用户,个人中心仅展示「收货地址」「联系我们」 */ |
| | | const isRestrictedView = computed(() => !isLoggedIn.value || userLevel.value === 'C') |
| | | |
| | | /** 收益汇总原始值(单位:分),登录后由 getMemberInfo 下发,未登录保持全零 */ |
| | | const earningsRaw = ref({ today: 0, month: 0, total: 0 }) |
| | | |
| | | /** 收益三栏:后端下发单位为分,统一格式化为元展示;未登录统一展示 0.00 */ |
| | | const earnings = computed(() => { |
| | | const zeroValue = '0.00' |
| | | const source = isLoggedIn.value ? earningsRaw.value : { today: 0, month: 0, total: 0 } |
| | | return [ |
| | | { key: 'today', label: '今日收益', value: isLoggedIn.value ? '10.00' : zeroValue }, |
| | | { key: 'month', label: '本月收益', value: isLoggedIn.value ? '400.00' : zeroValue }, |
| | | { key: 'total', label: '累计收益', value: isLoggedIn.value ? '128000.00' : zeroValue } |
| | | { key: 'today', label: '今日收益', value: formatYuan(source.today) }, |
| | | { key: 'month', label: '本月收益', value: formatYuan(source.month) }, |
| | | { key: 'total', label: '累计收益', value: formatYuan(source.total) } |
| | | ] |
| | | }) |
| | | |
| | |
| | | { key: 'contact', icon: 'contact', title: '联系我们' } |
| | | ] |
| | | |
| | | /** 当前可见菜单:受限展示(未登录 / L0)时仅保留「收货地址」「联系我们」 */ |
| | | /** 当前可见菜单:受限展示(未登录 / C)时仅保留「收货地址」「联系我们」 */ |
| | | const menuList = computed(() => |
| | | isRestrictedView.value ? MENU_LIST.filter((menu) => !menu.restricted) : MENU_LIST |
| | | ) |
| | | |
| | | /** 头像 / 名称 / 按钮点击:未登录跳登录页,已登录进入资料编辑 */ |
| | | /** 头像 / 名称 / 编辑资料按钮点击:未登录跳登录页,已登录进入「我的资料」页 */ |
| | | const handleAccountTap = () => { |
| | | if (!isLoggedIn.value) { |
| | | uni.reLaunch({ url: config.loginPage }) |
| | | return |
| | | } |
| | | uni.showToast({ title: '敬请期待', icon: 'none' }) |
| | | uni.navigateTo({ url: '/pages/profile/edit' }) |
| | | } |
| | | |
| | | /** 菜单项点击:未登录先提示登录;已登录进入二级功能页(未接入的暂为占位反馈) */ |
| | |
| | | uni.showToast({ title: '敬请期待', icon: 'none' }) |
| | | } |
| | | |
| | | // 每次页面显示均刷新登录态,保证登录 / 退出后展示态同步 |
| | | /** |
| | | * 拉取当前会员信息(昵称 / 头像 / 等级 / 收益汇总) |
| | | * 失败时静默降级为普通用户态,不阻塞页面展示 |
| | | */ |
| | | const loadMemberInfo = async () => { |
| | | try { |
| | | const res = await getMemberInfo() |
| | | const data = res.data || {} |
| | | nickname.value = data.nickname || '' |
| | | // 手机号后端已脱敏(133****5555),可直接用于展示兜底 |
| | | phone.value = data.phone || '' |
| | | avatar.value = data.avatar || '' |
| | | // 等级缺省兜底 C,与后端 MemberLevelEnum.normalize 保持一致 |
| | | userLevel.value = data.memberLevel || 'C' |
| | | earningsRaw.value = data.earnings || { today: 0, month: 0, total: 0 } |
| | | } catch (error) { |
| | | console.error('[PROFILE] 拉取会员信息失败', error) |
| | | nickname.value = '' |
| | | phone.value = '' |
| | | avatar.value = '' |
| | | userLevel.value = 'C' |
| | | earningsRaw.value = { today: 0, month: 0, total: 0 } |
| | | } |
| | | } |
| | | |
| | | // 每次页面显示均刷新登录态,保证登录 / 退出后展示态同步;已登录则拉取会员信息 |
| | | onShow(() => { |
| | | isLoggedIn.value = Boolean(getToken()) |
| | | if (isLoggedIn.value) { |
| | | loadMemberInfo() |
| | | } |
| | | }) |
| | | </script> |
| | | |
| | |
| | | border: 5rpx solid #ffffff; |
| | | } |
| | | |
| | | /* 用户头像图片:铺满头像容器并裁为圆形 */ |
| | | .avatar-img { |
| | | width: 100%; |
| | | height: 100%; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | /* 已登录:相机图标;未登录:用户图标 */ |
| | | .icon-camera { |
| | | width: 64rpx; |