Преглед изворни кода

refactor(profile): 重设计我的页面 - 用户卡片+数据概览+五维能量+待办提醒+分组菜单

iwt пре 1 месец
родитељ
комит
86e112e67e
1 измењених фајлова са 678 додато и 193 уклоњено
  1. 678 193
      cfc-frontend/pages/profile-main/profile.vue

+ 678 - 193
cfc-frontend/pages/profile-main/profile.vue

@@ -1,50 +1,200 @@
 <template>
   <view class="container">
-    <!-- Tabbar 切换过渡页 -->
     <tab-transition v-if="showTabTransition" dimCode="wealth" ref="tabTransition" @close="showTabTransition = false" />
 
-    <!-- ===== 未登录状态 ===== -->
+    <!-- 未登录 -->
     <view v-if="!isLoggedIn" class="login-prompt">
-      <view class="prompt-icon">👤</view>
+      <text class="prompt-icon">👤</text>
       <text class="prompt-title">登录浠艾福</text>
-      <text class="prompt-desc">登录后查看个人资料、积分记录等</text>
+      <text class="prompt-desc">登录后查看个人资料、积分记录等</text>
       <button class="login-btn" @click="goLogin">登录 / 注册</button>
     </view>
 
-    <!-- ===== 已登录状态 ===== -->
+    <!-- 已登录 -->
     <template v-else>
-      <!-- 用户卡片 -->
-      <ProfileHeader @avatar-click="goToEditInfo" />
+      <!-- 退出切换 -->
+      <view class="exit-switch" v-if="isSwitchedChild" @click="onExitSwitch">
+        <text>🔄 退出切换</text>
+      </view>
 
-      <!-- 个人信息完善卡片(全部填满后隐藏) -->
-      <view class="profile-card" v-if="isLoggedIn && profileProgress < 14" @click="goToEditInfo">
-        <view class="profile-card-left">
-          <text class="profile-card-title">个人信息</text>
-          <text class="profile-card-desc">已完善 {{ profileProgress }}/14 个字段,点击继续补充</text>
+      <!-- 用户身份卡片 -->
+      <view class="user-card">
+        <view class="user-card-left">
+          <view class="avatar-wrap" @click="goToEditInfo">
+            <image v-if="userInfo.avatar" class="avatar-img" :src="userInfo.avatar" mode="aspectFill" />
+            <text v-else class="avatar-text">{{ nickname.charAt(0) || '👤' }}</text>
+          </view>
+          <view class="user-meta">
+            <view class="user-name-row">
+              <text class="nickname">{{ nickname || '未设置昵称' }}</text>
+              <text class="role-tag">{{ roleLabel }}</text>
+            </view>
+            <view class="user-sub" v-if="memberLevel">
+              <text class="level-badge" :class="'level-' + memberLevel">{{ memberLevelText }}</text>
+              <text v-if="membershipDays > 0 && membershipDays <= 30" class="days-left">剩余 {{ membershipDays }} 天</text>
+            </view>
+            <view class="user-sub" v-else>
+              <text class="days-left">开通会员解锁更多权益</text>
+            </view>
+          </view>
+        </view>
+        <view class="user-card-right">
+          <view class="points-box" @click="goToPoints">
+            <text class="points-num">{{ totalPoints }}</text>
+            <text class="points-label">积分</text>
+          </view>
+          <button v-if="!isSwitchedChild" class="btn-switch" @click="onSwitchMode">切换</button>
         </view>
-        <text class="profile-card-arrow">›</text>
       </view>
 
-      <!-- 成长报告 -->
-      <ProfileGrowth />
+      <!-- 核心数据概览 -->
+      <view class="stats-bar">
+        <view class="stat-item" @click="goToTasks">
+          <text class="stat-num">{{ pendingTasks }}</text>
+          <text class="stat-label">待完成任务</text>
+        </view>
+        <view class="stat-divider"></view>
+        <view class="stat-item" @click="goToCheckin">
+          <text class="stat-num">{{ streakDays }}</text>
+          <text class="stat-label">连续打卡</text>
+        </view>
+        <view class="stat-divider"></view>
+        <view class="stat-item" @click="goToFamily">
+          <text class="stat-num">{{ familyCount }}</text>
+          <text class="stat-label">家庭成员</text>
+        </view>
+        <view class="stat-divider"></view>
+        <view class="stat-item" @click="goToChallenges">
+          <text class="stat-num">{{ activeChallenges }}</text>
+          <text class="stat-label">进行中挑战</text>
+        </view>
+      </view>
+
+      <!-- 五维能量 -->
+      <view class="energy-section" v-if="sandboxData">
+        <view class="section-header">
+          <text class="section-title">🌟 五维能量</text>
+          <text class="section-more" @click="goToEnergySandbox">详情 ›</text>
+        </view>
+        <view class="energy-row">
+          <view class="energy-item" v-for="dim in energyDims" :key="dim.code">
+            <view class="energy-circle" :style="{ background: dim.color }">
+              <text class="energy-val">{{ dim.score || 0 }}</text>
+            </view>
+            <text class="energy-label">{{ dim.label }}</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- 待办提醒 -->
+      <view class="reminders-section" v-if="hasReminders">
+        <view class="section-header">
+          <text class="section-title">📌 待办提醒</text>
+        </view>
+        <view class="reminder-item" v-if="pendingTasks > 0" @click="goToTasks">
+          <text class="reminder-icon">📋</text>
+          <text class="reminder-text">有 {{ pendingTasks }} 个任务待完成</text>
+          <text class="reminder-arrow">›</text>
+        </view>
+        <view class="reminder-item" v-if="activeChallenges > 0" @click="goToChallenges">
+          <text class="reminder-icon">🔥</text>
+          <text class="reminder-text">{{ activeChallenges }} 个挑战进行中</text>
+          <text class="reminder-arrow">›</text>
+        </view>
+        <view class="reminder-item" v-if="profileProgress < 14" @click="goToEditInfo">
+          <text class="reminder-icon">📝</text>
+          <text class="reminder-text">个人信息待完善({{ profileProgress }}/14)</text>
+          <text class="reminder-arrow">›</text>
+        </view>
+      </view>
 
-      <!-- 成就徽章 -->
-      <ProfileBadges />
+      <!-- 功能菜单 -->
+      <view class="menu-section">
+        <!-- 家庭 -->
+        <view class="menu-group">
+          <view class="menu-group-title">家庭</view>
+          <view class="menu-item" @click="goToFamily">
+            <text class="menu-icon">👨‍👩‍👧‍👦</text>
+            <text class="menu-text">家庭成员</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" @click="goToChildren">
+            <text class="menu-icon">👶</text>
+            <text class="menu-text">孩子管理</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" v-if="role === 'parent'" @click="goToAppointments">
+            <text class="menu-icon">📅</text>
+            <text class="menu-text">测评预约</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" @click="goToChallenges">
+            <text class="menu-icon">🔥</text>
+            <text class="menu-text">家庭挑战</text>
+            <text class="arrow">›</text>
+          </view>
+        </view>
 
-      <!-- 健康等级称号(P2-1) -->
-      <HealthBadge
-        v-if="levelInfo"
-        :levelInfo="levelInfo"
-        :score="score"
-        :progress="progress"
-        :nextLevel="nextLevel"
-        :streakDays="streakDays" />
+        <!-- 成长 -->
+        <view class="menu-group">
+          <view class="menu-group-title">成长</view>
+          <view class="menu-item" @click="goToTasks">
+            <text class="menu-icon">📋</text>
+            <text class="menu-text">每日任务</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" @click="goToGrowth">
+            <text class="menu-icon">📈</text>
+            <text class="menu-text">成长档案</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" @click="goToReport">
+            <text class="menu-icon">📊</text>
+            <text class="menu-text">健康报告</text>
+            <text class="arrow">›</text>
+          </view>
+        </view>
 
-      <!-- 健康故事时间线(P2-1) -->
-      <HealthTimeline :events="timelineEvents" />
+        <!-- 商城 -->
+        <view class="menu-group" v-if="showServices">
+          <view class="menu-group-title">商城</view>
+          <view class="menu-item" @click="goToMembership">
+            <text class="menu-icon">👑</text>
+            <text class="menu-text">会员中心</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" @click="goToOrders">
+            <text class="menu-icon">🛒</text>
+            <text class="menu-text">我的订单</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" @click="goToCoupons">
+            <text class="menu-icon">🎫</text>
+            <text class="menu-text">优惠券</text>
+            <text class="arrow">›</text>
+          </view>
+        </view>
 
-      <!-- 菜单列表(含个人信息 + 服务/商城板块,承载"我的"Tab 的成果与权益入口) -->
-      <ProfileMenu :role="role" :show-services="true" @invite-generate="onInviteGenerate" />
+        <!-- 更多 -->
+        <view class="menu-group">
+          <view class="menu-group-title">更多</view>
+          <view class="menu-item" v-if="role === 'parent'" @click="showInviteActionSheet">
+            <text class="menu-icon">📨</text>
+            <text class="menu-text">邀请加入</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" @click="goToSettings">
+            <text class="menu-icon">⚙️</text>
+            <text class="menu-text">设置</text>
+            <text class="arrow">›</text>
+          </view>
+          <view class="menu-item" @click="logout">
+            <text class="menu-icon">🚪</text>
+            <text class="menu-text">退出登录</text>
+            <text class="arrow">›</text>
+          </view>
+        </view>
+      </view>
     </template>
     <AIFloatingAvatar />
   </view>
@@ -52,153 +202,333 @@
 
 <script>
 import TabTransition from '../../components/tab-transition.vue'
-import ProfileHeader from '../../components/ProfileHeader.vue'
-import ProfileBadges from '../../components/ProfileBadges.vue'
-import ProfileGrowth from '../../components/ProfileGrowth.vue'
-import ProfileMenu from '../../components/ProfileMenu.vue'
 import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
-import HealthBadge from '../../components/HealthBadge.vue'
-import HealthTimeline from '../../components/HealthTimeline.vue'
-import { getHealthScoreInfo, getHealthTimeline, getUserInfo } from '../../utils/api.js'
+import {
+  getChildren, getVisibleFamilyMembers, getFamilyEnergySandbox,
+  getTodayTasksByCategory, getChallengeList, getMyMembership,
+  verifyPassword, getPointsBalance, getUserInfo
+} from '../../utils/api.js'
 
 export default {
-components: {
-TabTransition,
-ProfileHeader,
-ProfileBadges,
-ProfileGrowth,
-ProfileMenu,
-AIFloatingAvatar,
-HealthBadge,
-HealthTimeline
-},
+  components: { TabTransition, AIFloatingAvatar },
   data() {
     return {
-      shareData: null,
       showTabTransition: true,
-      selectedMascot: '',
-      currentMascotName: '小助手',
-      // P2-1 身份重塑
-      levelInfo: null,
-      score: 0,
-      progress: 0,
-      nextLevel: null,
+      nickname: '',
+      role: 'parent',
+      isSwitchedChild: false,
+      userInfo: {},
+      memberLevel: null,
+      membershipDays: 0,
+      totalPoints: 0,
+      pendingTasks: 0,
       streakDays: 0,
-      timelineEvents: [],
-      // 个人信息完善进度(0-14 字段)
-      profileProgress: 0
+      familyCount: 0,
+      activeChallenges: 0,
+      profileProgress: 0,
+      sandboxData: null,
+      energyDims: []
     }
   },
   computed: {
     isLoggedIn() {
       return !!uni.getStorageSync('token')
     },
-    role() {
-      return uni.getStorageSync('currentRole') || uni.getStorageSync('role') || 'parent'
-    }
-  },
-  onShareAppMessage() {
-    if (this.shareData) {
-      return {
-        title: this.shareData.title,
-        path: this.shareData.path,
-        imageUrl: '/static/invite-card.png'
-      }
+    roleLabel() {
+      var map = { parent: '家长', child: '孩子', teacher: '规划师' }
+      return map[this.role] || '用户'
+    },
+    memberLevelText() {
+      var map = { GOLD: '金卡', PLATINUM: '白金', DIAMOND: '钻石' }
+      return map[this.memberLevel] || this.memberLevel || ''
+    },
+    hasReminders() {
+      return this.pendingTasks > 0 || this.activeChallenges > 0 || this.profileProgress < 14
     }
   },
   onShow() {
     this.showTabTransition = true
-
-    if (!uni.getStorageSync('token')) {
+    if (!this.isLoggedIn) {
       this._watchPageReady()
       return
     }
-    this.loadMascot()
-    const currentRole = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || 'parent'
-    if (currentRole === 'teacher') {
+    var role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || 'parent'
+    if (role === 'teacher') {
       uni.redirectTo({ url: '/pages/teacher/teacher-profile' })
+      return
     }
-    this.loadHealthScoreData()
-    this.loadProfileProgress()
+    this.role = role
+    this.isSwitchedChild = uni.getStorageSync('isSwitchedChild') || false
+    this.nickname = (uni.getStorageSync('userInfo') || {}).nickname || ''
+    this.loadAllData()
     this._watchPageReady()
   },
   methods: {
-    goLogin() {
-      uni.navigateTo({ url: '/pages/login/login' })
-    },
-    onInviteGenerate(shareData) {
-      this.shareData = shareData
-    },
-    changeMascot(mascot) {
-      if (this.selectedMascot === mascot) return;
-      uni.request({
-        url: this.$config.API_BASE_URL + '/api/user/mascot/set',
-        method: 'POST',
-        header: { Authorization: 'Bearer ' + uni.getStorageSync('token') },
-        data: { mascot },
-        success: (res) => {
-          if (res.data.code === 200 || res.data.code === 0) {
-            this.selectedMascot = mascot;
-            this.currentMascotName = mascot === 'xibao' ? '浠宝' : '福宝';
-            // 同步更新 localStorage 以便 AIFloatingAvatar 等组件能读到最新值
-            var userInfo = uni.getStorageSync('userInfo') || {};
-            userInfo.mascot = mascot;
-            uni.setStorageSync('userInfo', userInfo);
-            uni.showToast({ title: '已更换' });
-          }
-        }
-      });
-    },
-    loadMascot() {
-      var userInfo = uni.getStorageSync('userInfo');
-      if (userInfo && userInfo.mascot) {
-        this.selectedMascot = userInfo.mascot;
-        this.currentMascotName = userInfo.mascot === 'xibao' ? '浠宝' : '福宝';
-      }
-    },
     _watchPageReady() {
       var self = this
       this.$nextTick(function() {
         if (self.$refs.tabTransition) self.$refs.tabTransition.markReady()
       })
     },
-    loadHealthScoreData() {
-      var memberId = uni.getStorageSync('currentChildId') || null
-      if (!memberId) return
+    loadAllData() {
+      this.loadUserInfo()
+      this.loadMembership()
+      this.loadPoints()
+      this.loadFamily()
+      this.loadSandbox()
+      this.loadTasks()
+      this.loadChallenges()
+    },
+    loadUserInfo() {
+      var self = this
+      getUserInfo().then(function(res) {
+        if (res && res.code === 200 && res.data) {
+          self.userInfo = res.data
+          if (!self.nickname) self.nickname = res.data.nickname || ''
+        }
+      }).catch(function() {})
+    },
+    loadMembership() {
       var self = this
-      getHealthScoreInfo({ memberId: memberId }).then(function(res) {
-        if (res.code === 200 && res.data) {
-          self.levelInfo = res.data.level || null
-          self.score = res.data.score || 0
-          self.progress = res.data.progress || 0
-          self.nextLevel = res.data.nextLevel || null
-          self.streakDays = res.data.streakDays || 0
+      getMyMembership().then(function(res) {
+        if (res && res.data) {
+          self.memberLevel = res.data.memberLevel || res.data.levelCode || null
+          self.membershipDays = res.data.membershipDays || res.data.daysRemaining || 0
         }
       }).catch(function() {})
-      getHealthTimeline({ memberId: memberId }).then(function(res) {
-        if (res.code === 200 && Array.isArray(res.data)) {
-          self.timelineEvents = res.data.slice(0, 10)
+    },
+    loadPoints() {
+      var self = this
+      var memberId = uni.getStorageSync('currentChildId') || uni.getStorageSync('userId')
+      if (!memberId) return
+      getPointsBalance(memberId).then(function(res) {
+        if (res && res.data) {
+          self.totalPoints = res.data.totalPoints || res.data.points || 0
         }
       }).catch(function() {})
     },
-    loadProfileProgress() {
+    loadFamily() {
       var self = this
-      getUserInfo().then(function(res) {
-        if (res && res.code === 200 && res.data) {
-          var user = res.data
-          var fields = ['nickname', 'avatar', 'realName', 'gender', 'birthday', 'birthHour', 'ethnicity', 'bloodType', 'highestEducation', 'maritalStatus', 'address', 'hobbies', 'dietPreferences', 'phone']
-          var filled = 0
-          for (var i = 0; i < fields.length; i++) {
-            var v = user[fields[i]]
-            if (v !== null && v !== undefined && v !== '') filled++
+      var childrenRes = getChildren()
+      var membersRes = getVisibleFamilyMembers()
+      Promise.all([childrenRes, membersRes]).then(function(results) {
+        var children = results[0].data || []
+        var members = results[1].data || []
+        self.familyCount = members.length || children.length
+        self.streakDays = parseInt(uni.getStorageSync('streakDays') || 0)
+      }).catch(function() {
+        self.familyCount = 0
+      })
+    },
+    loadSandbox() {
+      var self = this
+      getFamilyEnergySandbox().then(function(res) {
+        if (res && res.data) {
+          self.sandboxData = res.data
+          var dims = res.data.dimensions || []
+          self.energyDims = dims.map(function(d) {
+            return {
+              code: d.code,
+              label: d.label || d.code,
+              score: d.score || 0,
+              color: self.getDimColor(d.code)
+            }
+          })
+        }
+      }).catch(function() {})
+    },
+    loadTasks() {
+      var self = this
+      var memberId = uni.getStorageSync('currentChildId') || uni.getStorageSync('userId')
+      if (!memberId) return
+      if (self.role === 'child' && memberId) {
+        getTodayTasksByCategory(memberId, 'action').then(function(res) {
+          if (res && res.data) {
+            self.pendingTasks = Array.isArray(res.data) ? res.data.length : 0
           }
-          self.profileProgress = filled
+        }).catch(function() {})
+      }
+      self.pendingTasks = parseInt(uni.getStorageSync('pendingTaskCount') || 0)
+    },
+    loadChallenges() {
+      var self = this
+      getChallengeList({}).then(function(res) {
+        if (res && res.data) {
+          self.activeChallenges = Array.isArray(res.data) ? res.data.length : 0
         }
       }).catch(function() {})
     },
-    // 修复:ProfileHeader 头像点击进入编辑页(原方法缺失)
-    goToEditInfo() {
+    getDimColor: function(code) {
+      var map = {
+        body: '#FF8C42', mind: '#FF6B9D', wisdom: '#6366F1',
+        action: '#10B981', wealth: '#F59E0B'
+      }
+      return map[code] || '#999'
+    },
+    goLogin: function() {
+      uni.navigateTo({ url: '/pages/login/login' })
+    },
+    goToEditInfo: function() {
       uni.navigateTo({ url: '/pages/user-edit/user-edit' })
+    },
+    goToPoints: function() {
+      uni.navigateTo({ url: '/pages/points/points' })
+    },
+    goToTasks: function() {
+      uni.navigateTo({ url: '/pages/tasks/tasks' })
+    },
+    goToCheckin: function() {
+      uni.navigateTo({ url: '/pages/health/daily-checkin' })
+    },
+    goToFamily: function() {
+      uni.navigateTo({ url: '/pages/profile-extra/family-members' })
+    },
+    goToChildren: function() {
+      uni.navigateTo({ url: '/pages/profile-extra/children' })
+    },
+    goToAppointments: function() {
+      uni.navigateTo({ url: '/pages/parent/appointments' })
+    },
+    goToChallenges: function() {
+      uni.navigateTo({ url: '/pages/health/challenge-manage' })
+    },
+    goToGrowth: function() {
+      uni.navigateTo({ url: '/pages/growth-main/index' })
+    },
+    goToReport: function() {
+      uni.navigateTo({ url: '/pages/profile/report-management' })
+    },
+    goToMembership: function() {
+      uni.navigateTo({ url: '/pages/membership/index' })
+    },
+    goToOrders: function() {
+      uni.navigateTo({ url: '/pages/shop/order-list/order-list' })
+    },
+    goToCoupons: function() {
+      uni.navigateTo({ url: '/pages/profile-extra/coupons' })
+    },
+    goToEnergySandbox: function() {
+      uni.switchTab({ url: '/pages/index-home/index' })
+    },
+    goToSettings: function() {
+      uni.showActionSheet({
+        itemList: ['设置密码', '隐私设置', '关于浠艾福'],
+        success: function(res) {
+          if (res.tapIndex === 0) {
+            uni.navigateTo({ url: '/pages/profile/settings' })
+          }
+        }
+      })
+    },
+    onSwitchMode: function() {
+      var self = this
+      if (self.role === 'child') {
+        uni.showModal({
+          title: '验证密码',
+          content: '请输入家长密码',
+          editable: true,
+          success: function(res) {
+            if (res.confirm && res.content) {
+              verifyPassword(res.content).then(function(result) {
+                if (result.code === 200) {
+                  self.doSwitchMode()
+                } else {
+                  uni.showToast({ title: '密码错误', icon: 'none' })
+                }
+              }).catch(function() {
+                uni.showToast({ title: '验证失败', icon: 'none' })
+              })
+            }
+          }
+        })
+      } else {
+        this.doSwitchMode()
+      }
+    },
+    doSwitchMode: function() {
+      var self = this
+      getChildren().then(function(res) {
+        var children = res.data || []
+        if (children.length === 0) {
+          uni.showModal({
+            title: '提示',
+            content: '您还没有添加孩子,请先在家庭成员中添加',
+            success: function(r) { if (r.confirm) uni.navigateTo({ url: '/pages/profile-extra/family-members' }) }
+          })
+          return
+        }
+        if (children.length === 1) {
+          self.$store.commit('switchToChild', children[0].id)
+          self.role = 'child'
+          self.isSwitchedChild = true
+          uni.showToast({ title: '已切换为孩子模式', icon: 'success' })
+          return
+        }
+        uni.showActionSheet({
+          itemList: children.map(function(c) { return c.nickname }),
+          success: function(res) {
+            var sel = children[res.tapIndex]
+            self.$store.commit('switchToChild', sel.id)
+            self.role = 'child'
+            self.isSwitchedChild = true
+            uni.showToast({ title: '已切换为' + sel.nickname + '模式', icon: 'success' })
+          }
+        })
+      }).catch(function() {})
+    },
+    onExitSwitch: function() {
+      var self = this
+      uni.showModal({
+        title: '退出切换',
+        content: '请输入家长密码以确认退出',
+        editable: true,
+        success: function(res) {
+          if (res.confirm && res.content) {
+            verifyPassword(res.content).then(function(result) {
+              if (result.code === 200) {
+                self.$store.commit('switchBackToParent')
+                self.isSwitchedChild = false
+                self.role = 'parent'
+                uni.showToast({ title: '已退出切换', icon: 'success' })
+                uni.reLaunch({ url: '/pages/index-home/index' })
+              } else {
+                uni.showToast({ title: '密码错误', icon: 'none' })
+              }
+            }).catch(function() {
+              uni.showToast({ title: '验证失败', icon: 'none' })
+            })
+          }
+        }
+      })
+    },
+    showInviteActionSheet: function() {
+      var self = this
+      var ui = uni.getStorageSync('userInfo') || {}
+      var items = ['👨‍👩‍👧‍👦 邀请家人', '👨‍🏫 邀请成长规划师']
+      uni.showActionSheet({
+        itemList: items,
+        success: function(res) {
+          var type = res.tapIndex === 0 ? 'family' : 'guide'
+          var title = (ui.nickname || '家人') + ' 邀请你加入家庭'
+          var path = type === 'guide'
+            ? '/pages/login/login?invite_type=guide'
+            : '/pages/login/login?invite_type=family'
+          self.$emit('invite-generate', { title: title, path: path, imageUrl: '/static/invite-card.png' })
+          uni.showToast({ title: '点击右上角转发', icon: 'none' })
+        }
+      })
+    },
+    logout: function() {
+      uni.showModal({
+        title: '确认退出',
+        content: '确定要退出登录吗?',
+        success: function(res) {
+          if (res.confirm) {
+            this.$store.commit('logout')
+            uni.reLaunch({ url: '/pages/index-home/index' })
+          }
+        }.bind(this)
+      })
     }
   }
 }
@@ -211,111 +541,266 @@ HealthTimeline
   padding-bottom: 120rpx;
 }
 
+/* 登录 */
 .login-prompt {
   display: flex;
   flex-direction: column;
   align-items: center;
-  justify-content: center;
   padding: 200rpx 60rpx;
 }
 .prompt-icon { font-size: 100rpx; margin-bottom: 30rpx; }
 .prompt-title { font-size: 40rpx; font-weight: bold; color: #333; margin-bottom: 16rpx; }
 .prompt-desc { font-size: 26rpx; color: #999; margin-bottom: 60rpx; }
 .login-btn {
-  width: 80%;
   background: linear-gradient(135deg, #667eea, #764ba2);
   color: #fff;
   border-radius: 50rpx;
   font-size: 30rpx;
-  padding: 24rpx;
-  line-height: 1.5;
+  padding: 24rpx 80rpx;
 }
 
-.mascot-selector {
-  margin: 20rpx 0;
-  padding: 24rpx;
-  background: #fff;
-  border-radius: 16rpx;
+/* 退出切换 */
+.exit-switch {
+  margin: 0 30rpx 16rpx;
+  background: linear-gradient(135deg, #667eea, #764ba2);
+  color: #fff;
+  padding: 16rpx;
+  border-radius: 12rpx;
+  text-align: center;
+  font-size: 26rpx;
 }
-.selector-header {
-  margin-bottom: 20rpx;
+
+/* 用户卡片 */
+.user-card {
+  margin: 30rpx;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-radius: 24rpx;
+  padding: 36rpx 32rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  box-shadow: 0 8rpx 32rpx rgba(102,126,234,0.3);
 }
-.selector-title {
-  font-size: 32rpx;
-  font-weight: bold;
-  color: #1F2937;
+.user-card-left {
+  display: flex;
+  align-items: center;
+  flex: 1;
 }
-.selector-subtitle {
-  font-size: 24rpx;
-  color: #6366F1;
-  margin-left: 16rpx;
+.avatar-wrap {
+  width: 110rpx;
+  height: 110rpx;
+  border-radius: 50%;
+  background: rgba(255,255,255,0.2);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 24rpx;
+  overflow: hidden;
+  border: 4rpx solid rgba(255,255,255,0.3);
+}
+.avatar-img {
+  width: 110rpx;
+  height: 110rpx;
+  border-radius: 50%;
 }
-.mascot-cards {
+.avatar-text {
+  font-size: 48rpx;
+  color: #fff;
+}
+.user-meta { flex: 1; }
+.user-name-row {
   display: flex;
-  gap: 20rpx;
+  align-items: center;
+  gap: 12rpx;
+  margin-bottom: 8rpx;
 }
-.mascot-card {
-  flex: 1;
+.nickname {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #fff;
+}
+.role-tag {
+  font-size: 22rpx;
+  background: rgba(255,255,255,0.2);
+  color: #fff;
+  padding: 4rpx 16rpx;
+  border-radius: 20rpx;
+}
+.user-sub {
   display: flex;
-  flex-direction: column;
   align-items: center;
-  padding: 24rpx 0;
-  border: 2rpx solid #E5E7EB;
-  border-radius: 12rpx;
+  gap: 12rpx;
 }
-.mascot-card.active {
-  border-color: #6366F1;
-  background: #EEF2FF;
+.level-badge {
+  font-size: 22rpx;
+  padding: 4rpx 16rpx;
+  border-radius: 20rpx;
+  font-weight: 600;
 }
-.card-icon {
-  width: 80rpx;
-  height: 80rpx;
-  border-radius: 50%;
+.level-GOLD { background: #F59E0B; color: #fff; }
+.level-PLATINUM { background: #6366F1; color: #fff; }
+.level-DIAMOND { background: #EC4899; color: #fff; }
+.days-left {
+  font-size: 24rpx;
+  color: rgba(255,255,255,0.8);
+}
+.user-card-right {
   display: flex;
+  flex-direction: column;
   align-items: center;
-  justify-content: center;
-  font-size: 32rpx;
+  gap: 16rpx;
+}
+.points-box {
+  text-align: center;
+  background: rgba(255,255,255,0.15);
+  padding: 16rpx 24rpx;
+  border-radius: 16rpx;
+}
+.points-num {
+  font-size: 44rpx;
   font-weight: bold;
   color: #fff;
-  margin-bottom: 12rpx;
-}
-.card-icon.xibao {
-  background: linear-gradient(135deg, #FF8C42, #FF6B9D);
+  display: block;
 }
-.card-icon.fubao {
-  background: linear-gradient(135deg, #6366F1, #10B981);
+.points-label {
+  font-size: 22rpx;
+  color: rgba(255,255,255,0.7);
 }
-.card-name {
-  font-size: 26rpx;
-  color: #374151;
+.btn-switch {
+  background: rgba(255,255,255,0.2);
+  color: #fff;
+  font-size: 24rpx;
+  padding: 10rpx 32rpx;
+  border-radius: 30rpx;
+  border: none;
 }
 
-.profile-card {
+/* 数据概览 */
+.stats-bar {
+  margin: 0 30rpx 20rpx;
+  background: #fff;
+  border-radius: 20rpx;
   display: flex;
-  flex-direction: row;
   align-items: center;
-  justify-content: space-between;
-  margin: 20rpx 30rpx;
-  padding: 28rpx 32rpx;
-  background: #fff;
-  border-radius: 16rpx;
+  padding: 28rpx 0;
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
 }
-.profile-card-left {
+.stat-item {
+  flex: 1;
   display: flex;
   flex-direction: column;
+  align-items: center;
+  gap: 8rpx;
+}
+.stat-num {
+  font-size: 40rpx;
+  font-weight: bold;
+  color: #667eea;
+}
+.stat-label {
+  font-size: 24rpx;
+  color: #999;
+}
+.stat-divider {
+  width: 1rpx;
+  height: 60rpx;
+  background: #f0f0f0;
+}
+
+/* 五维能量 */
+.energy-section {
+  margin: 0 30rpx 20rpx;
+  background: #fff;
+  border-radius: 20rpx;
+  padding: 28rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+}
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20rpx;
 }
-.profile-card-title {
+.section-title {
   font-size: 30rpx;
   font-weight: bold;
   color: #333;
 }
-.profile-card-desc {
+.section-more {
   font-size: 24rpx;
   color: #999;
-  margin-top: 8rpx;
 }
-.profile-card-arrow {
-  font-size: 40rpx;
-  color: #ccc;
+.energy-row {
+  display: flex;
+  justify-content: space-around;
+}
+.energy-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 10rpx;
+}
+.energy-circle {
+  width: 88rpx;
+  height: 88rpx;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.15);
+}
+.energy-val {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: #fff;
+}
+.energy-label {
+  font-size: 24rpx;
+  color: #666;
+}
+
+/* 待办提醒 */
+.reminders-section {
+  margin: 0 30rpx 20rpx;
+}
+.reminder-item {
+  background: #fff;
+  border-radius: 16rpx;
+  padding: 24rpx 28rpx;
+  margin-bottom: 12rpx;
+  display: flex;
+  align-items: center;
+  gap: 16rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
+}
+.reminder-icon { font-size: 36rpx; }
+.reminder-text { flex: 1; font-size: 28rpx; color: #333; }
+.reminder-arrow { font-size: 32rpx; color: #ccc; }
+
+/* 菜单 */
+.menu-section {
+  margin: 0 30rpx;
+}
+.menu-group {
+  background: #fff;
+  border-radius: 20rpx;
+  margin-bottom: 20rpx;
+  overflow: hidden;
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+}
+.menu-group-title {
+  padding: 16rpx 28rpx 8rpx;
+  font-size: 22rpx;
+  color: #999;
+}
+.menu-item {
+  display: flex;
+  align-items: center;
+  padding: 26rpx 28rpx;
+  border-bottom: 1rpx solid #f5f5f5;
 }
-</style>
+.menu-item:last-child { border-bottom: none; }
+.menu-icon { font-size: 36rpx; margin-right: 16rpx; }
+.menu-text { flex: 1; font-size: 28rpx; color: #333; }
+.arrow { font-size: 32rpx; color: #ccc; }
+</style>