Просмотр исходного кода

refactor(beautify): D6 profile 主包门面页清理 (hex 10->1, debt 30->3)

- script defs 五维色板 5 值映射 BrandColors.body/mind/wisdom/action/wealth
- palette hoist:\-wisdom-mid->\-wisdom-deep, \-danger-ant->\-danger-2,
  \-pink->\-pink, \-pink-deep->\-pink-deep(删声明+使用处替换)
- 仅保留无令牌的 \-fill-2b #F2F2F2(§14 合法单页变量)
- 主包 7 门面页 debt 均 < 30;hardcoded hex 1707->1698
liaoxg 6 дней назад
Родитель
Сommit
9936de09ee

+ 1420 - 1426
cfc-frontend/pages/profile-main/profile.vue

@@ -1,1426 +1,1420 @@
-<template>
-  <view class="container">
-    <!-- 登录浮层(全局组件,页面内弹出底部登录) -->
-    <login-sheet ref="loginSheet" @success="onSheetLoginSuccess" />
-    <!-- 未登录 -->
-    <view v-if="!isLoggedIn">
-      <view class="login-prompt">
-        <text class="prompt-icon">👤</text>
-        <text class="prompt-title">登录浠艾福</text>
-        <text class="prompt-desc">登录后查看个人资料、积分记录、能量数据与家庭管理</text>
-        <button class="login-btn" @click="goLogin">登录 / 注册</button>
-        <text class="skip-link" @click="goSkip">暂不登录,先逛逛 ›</text>
-      </view>
-
-      <view class="philosophy-card">
-        <text class="philosophy-title">照顾家庭,从照顾好自己开始</text>
-        <text class="philosophy-desc">你的状态,就是家的状态。先安顿好自己,才有余力温暖家人。</text>
-      </view>
-    </view>
-
-    <!-- 已登录 -->
-    <template v-else>
-      <!-- 退出切换 -->
-      <view class="exit-switch" v-if="isSwitchedChild" @click="onExitSwitch">
-        <text>🔄 退出切换</text>
-      </view>
-
-      <!-- 身份卡 -->
-      <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 v-if="roleLabel" class="role-tag">{{ roleLabel }}</text>
-            </view>
-            <view class="user-sub" v-if="memberLevel">
-              <view class="level-badge" :class="'level-' + memberLevel">{{ memberLevelText }}</view>
-              <text v-if="isLifetime" class="days-left">永久有效</text>
-              <text v-else-if="membershipDays > 0 && membershipDays <= 30" class="days-left">剩余 {{ membershipDays }} 天</text>
-              <view v-if="hasUpgradeSpace" class="upgrade-btn" @click="goUpgrade">
-                <text class="upgrade-btn-text">{{ upgradeBtnText }}</text>
-              </view>
-            </view>
-            <view class="user-sub" v-else>
-              <text class="days-left">开通会员解锁更多权益</text>
-              <view class="upgrade-btn" @click="goUpgrade">
-                <text class="upgrade-btn-text">立即开通</text>
-              </view>
-            </view>
-          </view>
-        </view>
-        <view class="user-card-right" @click="goToPoints">
-          <text class="points-num">{{ totalPoints }}</text>
-          <text class="points-label">积分</text>
-        </view>
-      </view>
-
-      <!-- 我的分享海报浮动按钮(纯 CSS 二维码图标,避免 emoji 渲染成计算器) -->
-      <view class="share-qr-float" @click="showShareQr">
-        <view class="qr-glyph">
-          <view class="qr-eye qr-eye-tl"></view>
-          <view class="qr-eye qr-eye-tr"></view>
-          <view class="qr-eye qr-eye-bl"></view>
-          <view class="qr-mid"></view>
-          <view class="qr-cluster">
-            <view class="qr-pip"></view>
-            <view class="qr-pip"></view>
-            <view class="qr-pip"></view>
-            <view class="qr-pip"></view>
-          </view>
-        </view>
-      </view>
-
-      <!-- 家族成员速览 -->
-      <view class="family-strip" v-if="familyMembers.length > 0">
-        <view class="family-strip-header">
-          <text class="family-strip-title">我的家庭</text>
-          <text class="family-strip-count">{{ familyMembers.length }} 位成员</text>
-        </view>
-        <view class="family-avatars">
-          <view
-            v-for="member in familyMembers"
-            :key="member.id"
-            class="family-avatar-item"
-            @click="goMemberDetail(member)"
-          >
-            <view class="family-avatar-wrap">
-              <image v-if="member.avatar" class="family-avatar-img" :src="member.avatar" mode="aspectFill" />
-              <text v-else class="family-avatar-text">{{ member.nickname ? member.nickname.charAt(0) : '?' }}</text>
-              <view class="family-avatar-tag" :class="'tag-' + (member.effectiveRole || member.source || 'member')">{{ member.roleLabel || memberRoleLabel(member.effectiveRole) }}</view>
-            </view>
-            <text class="family-avatar-name">{{ member.nickname || member.realName || '成员' }}</text>
-          </view>
-          <view class="family-avatar-item" @click="goToFamily">
-            <view class="family-avatar-wrap family-avatar-add">
-              <text class="family-avatar-plus">+</text>
-            </view>
-            <text class="family-avatar-name">添加</text>
-          </view>
-        </view>
-      </view>
-
-      <!-- 个人成就统计 -->
-      <view class="achievement-section">
-        <view class="section-header-row">
-          <text class="section-title">🏆 我的成就</text>
-          <text class="section-sub">持续成长,看见改变</text>
-        </view>
-        <view class="achievement-grid">
-          <view class="ach-item" @click="goToPoints">
-            <view class="ach-icon-wrap" style="background:rgba(249,115,22,0.12)">
-              <text class="ach-icon">💰</text>
-            </view>
-            <text class="ach-num">{{ totalPoints }}</text>
-            <text class="ach-label">累计积分</text>
-          </view>
-          <view class="ach-item" @click="goToStreak">
-            <view class="ach-icon-wrap" style="background:rgba(255,140,66,0.12)">
-              <text class="ach-icon">🔥</text>
-            </view>
-            <text class="ach-num">{{ streakDays }}</text>
-            <text class="ach-label">连续打卡</text>
-          </view>
-          <view class="ach-item" @click="goToTasks">
-            <view class="ach-icon-wrap" style="background:rgba(99,102,241,0.12)">
-              <text class="ach-icon">✅</text>
-            </view>
-            <text class="ach-num">{{ completedTasks }}</text>
-            <text class="ach-label">完成任务</text>
-          </view>
-          <view class="ach-item" @click="goToWishes">
-            <view class="ach-icon-wrap" style="background:rgba(245,158,11,0.12)">
-              <text class="ach-icon">🎁</text>
-            </view>
-            <text class="ach-num">{{ rewardsEarned }}</text>
-            <text class="ach-label">获得奖励</text>
-          </view>
-          <view class="ach-item" @click="goToBadges">
-            <view class="ach-icon-wrap" style="background:rgba(236,72,153,0.12)">
-              <text class="ach-icon">🏅</text>
-            </view>
-            <text class="ach-num">{{ badgesCollected }}</text>
-            <text class="ach-label">收集勋章</text>
-          </view>
-          <view class="ach-item" @click="goToGrowth">
-            <view class="ach-icon-wrap" style="background:rgba(16,185,129,0.12)">
-              <text class="ach-icon">📈</text>
-            </view>
-            <text class="ach-num">{{ growthRecords }}</text>
-            <text class="ach-label">成长记录</text>
-          </view>
-          <view class="ach-item" @click="goToChallenges">
-            <view class="ach-icon-wrap" style="background:rgba(255,107,157,0.12)">
-              <text class="ach-icon">🎯</text>
-            </view>
-            <text class="ach-num">{{ challengesJoined }}</text>
-            <text class="ach-label">参加挑战</text>
-          </view>
-          <view class="ach-item" @click="goToHealthReports">
-            <view class="ach-icon-wrap" style="background:rgba(14,165,233,0.12)">
-              <text class="ach-icon">📋</text>
-            </view>
-            <text class="ach-num">{{ healthReports }}</text>
-            <text class="ach-label">上传报告</text>
-          </view>
-          <view class="ach-item" @click="goToWealthCenter">
-            <view class="ach-icon-wrap" style="background:rgba(245,158,11,0.12)">
-              <text class="ach-icon">💰</text>
-            </view>
-            <text class="ach-num">{{ referralEarnings }}</text>
-            <text class="ach-label">推广收益</text>
-          </view>
-          <view class="ach-item" @click="goTeamTree">
-            <view class="ach-icon-wrap" style="background:rgba(16,185,129,0.12)">
-              <text class="ach-icon">🌳</text>
-            </view>
-            <text class="ach-num">{{ teamMembers }}</text>
-            <text class="ach-label">我的团队</text>
-          </view>
-        </view>
-      </view>
-
-      <!-- 我的订单(电商风格) -->
-      <view class="order-section">
-        <view class="order-section-header">
-          <text class="section-title">🛒 我的订单</text>
-          <text class="order-all-link" @click="goToOrders">全部订单 ›</text>
-        </view>
-        <view class="order-card">
-          <view class="order-grid">
-            <view class="order-grid-item" @click="goToOrderStatus('pending')">
-              <view class="order-icon-wrap">
-                <text class="order-icon">💳</text>
-                <text class="order-badge" v-if="orderPending > 0">{{ orderPending }}</text>
-              </view>
-              <text class="order-grid-text">待付款</text>
-            </view>
-            <view class="order-grid-item" @click="goToOrderStatus('paid')">
-              <view class="order-icon-wrap">
-                <text class="order-icon">📦</text>
-                <text class="order-badge" v-if="orderUnpaid > 0">{{ orderUnpaid }}</text>
-              </view>
-              <text class="order-grid-text">待发货</text>
-            </view>
-            <view class="order-grid-item" @click="goToOrderStatus('shipped')">
-              <view class="order-icon-wrap">
-                <text class="order-icon">🚚</text>
-                <text class="order-badge" v-if="orderShipped > 0">{{ orderShipped }}</text>
-              </view>
-              <text class="order-grid-text">待收货</text>
-            </view>
-            <view class="order-grid-item" @click="goToOrderStatus('refunding')">
-              <view class="order-icon-wrap">
-                <text class="order-icon">🔧</text>
-                <text class="order-badge" v-if="orderAfterSale > 0">{{ orderAfterSale }}</text>
-              </view>
-              <text class="order-grid-text">售后</text>
-            </view>
-            <view class="order-grid-item" @click="goToOrders">
-              <view class="order-icon-wrap">
-                <text class="order-icon">📋</text>
-              </view>
-              <text class="order-grid-text">全部</text>
-            </view>
-          </view>
-          <view class="order-extra-row">
-            <view class="order-extra-item" @click="goToCart">
-              <text class="order-extra-icon">🛒</text>
-              <text class="order-extra-text">购物车</text>
-              <text class="order-extra-badge" v-if="cartCount > 0">{{ cartCount > 99 ? '99+' : cartCount }}</text>
-            </view>
-            <view class="order-extra-divider"></view>
-            <view class="order-extra-item" @click="goToAddress">
-              <text class="order-extra-icon">📍</text>
-              <text class="order-extra-text">收货地址</text>
-            </view>
-          </view>
-        </view>
-      </view>
-
-      <!-- 规划师服务中心入口(仅规划师可见) -->
-      <view class="service-center-section" v-if="role === 'teacher' && teacherStatus === 'approved'">
-        <view class="service-center-card" @click="goToServiceCenter">
-          <view class="service-center-icon">👨‍🏫</view>
-          <view class="service-center-info">
-            <text class="service-center-title">服务中心</text>
-            <text class="service-center-desc">待处理任务:{{ pendingTasks }} 条 · 消息:{{ unreadMessages }} 条</text>
-          </view>
-          <text class="service-center-arrow">›</text>
-        </view>
-      </view>
-
-      <!-- 规划师待审核提示 -->
-      <view class="service-center-section" v-if="role === 'teacher' && teacherStatus !== 'approved'">
-        <view class="service-center-card disabled-card">
-          <view class="service-center-icon">👨‍🏫</view>
-          <view class="service-center-info">
-            <text class="service-center-title">服务中心</text>
-            <text class="service-center-desc">{{ teacherStatus === 'pending' ? '申请审核中,暂未开放' : teacherStatus === 'rejected' ? '申请未通过,请联系管理员' : '规划师服务' }}</text>
-          </view>
-        </view>
-      </view>
-
-      <!-- 设置 + 退出 -->
-      <view class="bottom-menu-section">
-        <view class="menu-row" @click="goToMessageHistory">
-          <text class="menu-row-icon">📨</text>
-          <text class="menu-row-text">历史消息</text>
-          <text class="menu-row-arrow">›</text>
-        </view>
-        <view class="menu-row" @click="goToSettings">
-          <text class="menu-row-icon">⚙️</text>
-          <text class="menu-row-text">设置</text>
-          <text class="menu-row-arrow">›</text>
-        </view>
-        <view class="logout-btn" @click="logout">
-          <text class="logout-text">退出登录</text>
-        </view>
-      </view>
-
-      </template>
-    <!-- 我的分享海报:复用文章/活动/商品同一套 ContentSharePoster 组件(canvas 绘制 + 保存到相册) -->
-    <ContentSharePoster
-      :show="showSharePoster"
-      :title="shareHeadline"
-      :energyData="posterEnergyData"
-      :brandFallback="true"
-      :qrCodeBase64="posterQrCode || ''"
-      typeLabel="邀友加入"
-      :summary="posterSummary"
-      ctaText="长按识别二维码 · 加入浠艾福"
-      :inviteText="posterInviteText"
-      @close="closeSharePoster"
-    />
-    <FloatingAvatar />
-  </view>
-</template>
-
-<script>
-import FloatingAvatar from '../../components/AIFloatingAvatar.vue'
-import ContentSharePoster from '../../components/ContentSharePoster.vue'
-import {
-  getChildren, getFamilyMemberList,
-  getTodayTasksByCategory, getChallengeList, getMyMembership,
-  verifyPassword, getPointsBalance, getUserInfo,
-  cartCount, getOrderCounts, getReferralSummary,
-  getProfileStats, getMyReferrer, getTeamConsumption,
-  getTeacherInfo, getTeacherPendingTasks, getTeacherUnreadCount,
-  getReferralCode, extractReferralCode, getShareQrCode, getEnergySandbox,
-  vendorStatus
-} from '../../utils/api.js'
-
-export default {
-  components: { FloatingAvatar, ContentSharePoster },
-  data() {
-    return {
-      nickname: '',
-      role: 'parent',
-      isSwitchedChild: false,
-      userInfo: {},
-      memberLevel: null,
-      membershipDays: 0,
-      totalPoints: 0,
-      referralEarnings: 0,
-      teamMembers: 0,
-      // 个人成就
-      completedTasks: 0,
-      streakDays: 0,
-      rewardsEarned: 0,
-      badgesCollected: 0,
-      growthRecords: 0,
-      challengesJoined: 0,
-      healthReports: 0,
-      // 家庭
-      familyMembers: [],
-      // 商城
-      orderPending: 0,
-      orderUnpaid: 0,
-      orderShipped: 0,
-      orderAfterSale: 0,
-      cartCount: 0,
-      // 待办
-      pendingTasks: 0,
-      unreadMessages: 0,
-      teacherStatus: 'pending',
-      isVendor: false,
-      profileProgress: 0,
-      myReferrer: null,
-      // 分享推广码
-      showSharePoster: false,
-      referralCode: '',
-      posterQrCode: '',
-      posterEnergyData: null,
-      referralCodeLoaded: false,
-    }
-  },
-  computed: {
-    isLoggedIn() {
-      return !!uni.getStorageSync('token')
-    },
-    roleLabel() {
-      var map = { parent: '', child: '成员', teacher: '规划师' }
-      return map[this.role] || '用户'
-    },
-    memberLevelText() {
-      var map = { FREE: '免费用户', BASIC: '体验会员', FAMILY: '家庭会员', PREMIUM: '高级会员', LIFETIME: '终身会员' }
-      return map[this.memberLevel] || this.memberLevel || ''
-    },
-    isLifetime() {
-      return this.memberLevel === 'LIFETIME'
-    },
-    hasUpgradeSpace() {
-      return this.memberLevel === 'FREE' || this.memberLevel === 'FAMILY'
-    },
-    upgradeBtnText() {
-      return this.hasUpgradeSpace ? '升级' : '立即开通'
-    },
-    // 分享海报标题:XXX邀请你关注家庭健康(昵称过长自动截断)
-    shareHeadline() {
-      var name = (this.nickname || '').trim()
-      if (!name) return '邀请你关注家庭健康'
-      if (name.length > 8) name = name.substring(0, 8) + '…'
-      return name + '邀请你关注家庭健康'
-    },
-    posterSummary() {
-      return '身体 · 心理 · 智慧 · 行动 · 财富,一家专注全家健康的成长平台'
-    },
-    posterInviteText() {
-      var name = (this.nickname || '').trim()
-      if (!name) return '扫码加入浠艾福,一起照顾好这个家'
-      if (name.length > 8) name = name.substring(0, 8) + '…'
-      return '「' + name + '」邀请你加入浠艾福'
-    }
-  },
-  onShow() {
-    if (!this.isLoggedIn) {
-      return
-    }
-    var role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || 'parent'
-    this.role = role
-    this.isSwitchedChild = uni.getStorageSync('isSwitchedChild') || false
-    this.nickname = (uni.getStorageSync('userInfo') || {}).nickname || ''
-
-    // 服务商身份判断(成就区「我的团队」入口按此分发)
-    this.checkVendorStatus()
-
-    // 规划师加载额外数据
-    if (role === 'teacher') {
-      this.loadTeacherStatus()
-      this.loadTeacherData()
-    } else {
-      this.loadAllData()
-      this.loadMyReferrer()
-    }
-  },
-  methods: {
-    // 服务商身份:vendorStatus 返回 approved 即为已通过审核的服务商
-    checkVendorStatus() {
-      var self = this
-      vendorStatus().then(function(res) {
-        self.isVendor = !!(res && res.data && res.data.vendorStatus === 'approved')
-      }).catch(function() {
-        self.isVendor = false
-      })
-    },
-    loadTeacherStatus() {
-      var self = this
-      getTeacherInfo().then(function(res) {
-        if (res && res.code === 200 && res.data) {
-          self.teacherStatus = res.data.verificationStatus || res.data.status || 'pending'
-        }
-      }).catch(function() {})
-    },
-    loadTeacherData() {
-      var self = this
-      // 并行加载待处理任务和未读消息
-      getTeacherPendingTasks().then(function(res) {
-        if (res && res.data && Array.isArray(res.data)) {
-          self.pendingTasks = res.data.length
-        } else if (res && res.data && res.data.pendingCount != null) {
-          self.pendingTasks = res.data.pendingCount
-        }
-      }).catch(function() {})
-      getTeacherUnreadCount().then(function(res) {
-        if (res && res.data != null) {
-          self.unreadMessages = res.data
-        }
-      }).catch(function() {})
-    },
-    loadAllData() {
-      this.loadUserInfo()
-      this.loadMembership()
-      this.loadPoints()
-      this.loadFamily()
-      this.loadTasks()
-      this.loadChallenges()
-      this.loadOrderCounts()
-      this.loadCartCount()
-      this.loadProfileStats()
-      this.loadReferralEarnings()
-      this.loadTeamInfo()
-    },
-    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
-      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() {})
-    },
-    loadPoints() {
-      // 累计积分由 loadProfileStats 汇总家庭成员积分,此处不再单独覆盖
-    },
-    loadFamily() {
-      var self = this
-      getFamilyMemberList({ visibleOnly: true }).then(function(res) {
-        var data = res && res.data ? res.data : []
-        self.familyMembers = Array.isArray(data) ? data : []
-      }).catch(function() {
-        self.familyMembers = []
-      })
-    },
-    loadTasks() {
-      var self = this
-      var memberId = uni.getStorageSync('currentChildId') || uni.getStorageSync('userId')
-      if (!memberId) return
-      getTodayTasksByCategory(memberId, 'action').then(function(res) {
-        if (res && res.data) {
-          self.pendingTasks = Array.isArray(res.data) ? res.data.length : 0
-        }
-      }).catch(function() {})
-      // fallback to storage
-      if (!self.pendingTasks) {
-        self.pendingTasks = parseInt(uni.getStorageSync('pendingTaskCount') || 0)
-      }
-    },
-    loadChallenges() {
-      var self = this
-      getChallengeList({}).then(function(res) {
-        if (res && res.data) {
-          // 不在此处使用,仅确保请求
-        }
-      }).catch(function() {})
-    },
-    loadOrderCounts() {
-      var self = this
-      getOrderCounts().then(function(res) {
-        if (res && res.data) {
-          self.orderPending = res.data.pending || 0
-          self.orderUnpaid = res.data.paid || 0
-          self.orderShipped = res.data.shipped || 0
-          self.orderAfterSale = res.data.refunding || 0
-        }
-      }).catch(function() {})
-    },
-    loadCartCount() {
-      var self = this
-      cartCount().then(function(res) {
-        if (res && res.data != null) {
-          self.cartCount = res.data || 0
-        }
-      }).catch(function() {})
-    },
-    loadProfileStats() {
-      var self = this
-      getProfileStats().then(function(res) {
-        if (res && res.code === 200 && res.data) {
-          var d = res.data
-          if (d.totalPoints != null) self.totalPoints = d.totalPoints
-          if (d.streakDays != null) self.streakDays = d.streakDays
-          if (d.completedTasks != null) self.completedTasks = d.completedTasks
-          if (d.rewardsEarned != null) self.rewardsEarned = d.rewardsEarned
-          if (d.badgesCollected != null) self.badgesCollected = d.badgesCollected
-          if (d.growthRecords != null) self.growthRecords = d.growthRecords
-          if (d.challengesJoined != null) self.challengesJoined = d.challengesJoined
-          if (d.healthReports != null) self.healthReports = d.healthReports
-        }
-      }).catch(function() {})
-    },
-
-    loadReferralEarnings() {
-      var self = this
-      getReferralSummary().then(function(res) {
-        if (res && res.code === 200 && res.data) {
-          self.referralEarnings = res.data.totalEarnings || 0
-        }
-      }).catch(function() {})
-    },
-    loadTeamInfo() {
-      var self = this
-      getTeamConsumption(3).then(function(res) {
-        if (res && res.data && res.data.totalMembers != null) {
-          self.teamMembers = res.data.totalMembers
-        }
-      }).catch(function() {})
-    },
-    async loadMyReferrer() {
-      try {
-        var memberId = uni.getStorageSync('currentMemberId') || uni.getStorageSync('currentChildId') || 0
-        var res = await getMyReferrer(memberId)
-        if (res && res.code === 200 && res.data && res.data.hasReferrer) {
-          this.myReferrer = res.data
-        }
-      } catch (e) {
-        console.error('获取推荐人失败', e)
-      }
-    },
-    // ===== 分享海报(复用 ContentSharePoster,与文章/活动/商品同一套生成逻辑)=====
-    async showShareQr() {
-      uni.showLoading({ title: '生成海报中...' })
-      try {
-        if (!this.referralCodeLoaded) {
-          await this.loadReferralCode()
-        }
-        var scene = 'ref=' + (this.referralCode || '')
-        if (scene.length > 32) {
-          scene = scene.substring(0, 32)
-        }
-        // 首页路径,扫码后进入首页并绑定推荐人
-        // 注意:微信 getwxacodeunlimit 的 page 不能带前导斜杠,否则报 errcode 41030 invalid page rid
-        var res = await getShareQrCode('pages/index-home/index', scene)
-        if (res && res.code === 200 && res.data && res.data.qrCodeBase64) {
-          this.posterQrCode = res.data.qrCodeBase64
-          // 必须在 showSharePoster=true 之前取到数据:组件 watch 到 show 后 300ms 即开始绘制
-          await this.loadPosterEnergy()
-          this.showSharePoster = true
-        } else {
-          uni.showToast({ title: '生成失败,请重试', icon: 'none' })
-        }
-      } catch (e) {
-        console.error('生成分享海报失败', e)
-        uni.showToast({ title: '生成失败,请重试', icon: 'none' })
-      } finally {
-        uni.hideLoading()
-      }
-    },
-    closeSharePoster() {
-      this.showSharePoster = false
-    },
-    // 五维能量数据卡数据(方案C):家庭聚合视角;未解锁全景/取数失败时置空,海报降级为品牌卡
-    loadPosterEnergy() {
-      var self = this
-      return getEnergySandbox('family').then(function(res) {
-        self.posterEnergyData = self.mapPosterEnergy(res)
-      }).catch(function(e) {
-        console.error('获取五维能量失败,海报降级为品牌卡', e)
-        self.posterEnergyData = null
-      })
-    },
-    mapPosterEnergy(res) {
-      if (!res || res.code !== 200 || !res.data) return null
-      // locked=true 表示用户未解锁全景,此时不展示任何数据,改为品牌卡
-      if (res.data.locked) return null
-      // 只认家庭聚合视角;仅当接口返回的是裸 DTO(无 personalData/familyData 包装)时才直接取 res.data
-      var d = res.data.familyData || null
-      if (!d) {
-        if (res.data.personalData) return null
-        d = res.data
-      }
-      if (!d || typeof d !== 'object') return null
-      var defs = [
-        { key: 'body', label: '身', color: '#FF8C42' },
-        { key: 'mind', label: '心', color: '#FF6B9D' },
-        { key: 'wisdom', label: '智', color: '#6366F1' },
-        { key: 'action', label: '行', color: '#10B981' },
-        { key: 'wealth', label: '富', color: '#F59E0B' }
-      ]
-      var dims = []
-      var sum = 0
-      for (var i = 0; i < defs.length; i++) {
-        var raw = d[defs[i].key + 'Score']
-        if (raw === null || raw === undefined || raw === '' || isNaN(raw)) continue
-        var n = Number(raw)
-        if (n < 0) n = 0
-        if (n > 100) n = 100
-        sum += n
-        dims.push({ key: defs[i].key, label: defs[i].label, score: n, color: defs[i].color })
-      }
-      if (dims.length === 0) return null
-      var overall = d.overallScore
-      if (overall === null || overall === undefined || overall === '' || isNaN(overall)) {
-        overall = Math.round(sum / dims.length)
-      }
-      return { label: '我们家的能量', overall: Number(overall), dims: dims }
-    },
-
-    async loadReferralCode() {
-      if (this.referralCodeLoaded) return
-      var self = this
-      try {
-        var res = await getReferralCode()
-        self.referralCode = extractReferralCode(res) || ''
-      } catch (e) {
-        console.error('获取推广码失败', e)
-      } finally {
-        self.referralCodeLoaded = true
-      }
-    },
-    goToServiceCenter() {
-      uni.navigateTo({ url: '/pages/service-center/index' })
-    },
-    goTeamTree() {
-      // 服务商 → 服务商团队;非服务商 → 引导申请
-      if (this.isVendor) {
-        uni.navigateTo({ url: '/pages/vendor/team-system/team-system' })
-        return
-      }
-      uni.showModal({
-        title: '提示',
-        content: '您尚未申请任何服务角色,是否立即申请?',
-        confirmText: '去申请',
-        cancelText: '取消',
-        success: function(res) {
-          if (res.confirm) {
-            uni.navigateTo({ url: '/pages/profile/service-role-apply' })
-          }
-        }
-      })
-    },
-    goLogin: function() {
-      this.openLoginSheet()
-    },
-    // 登录浮层成功回调:刷新个人资料与登录后数据
-    onLoginSuccess: function() {
-      if (this.loadUserInfo) this.loadUserInfo()
-    },
-    goSkip: function() {
-      uni.switchTab({ url: '/pages/index-home/index' })
-    },
-    goToEditInfo: function() {
-      uni.navigateTo({ url: '/pages/user-edit/user-edit' })
-    },
-    goToPoints: function() {
-      uni.navigateTo({ url: '/pages/points/points' })
-    },
-    goToStreak: function() {
-      var memberId = uni.getStorageSync('currentMemberId') || uni.getStorageSync('currentChildId')
-      var url = '/pages/stats/completion-rate'
-      if (memberId) {
-        url += '?memberId=' + memberId
-      } else {
-        url += '?familyView=1'
-      }
-      uni.navigateTo({ url: url })
-    },
-    goToTasks: function() {
-      uni.navigateTo({ url: '/pages/tasks/tasks' })
-    },
-    goToWishes: function() {
-      uni.navigateTo({ url: '/pages/wishes/index' })
-    },
-    goToBadges: function() {
-      uni.navigateTo({ url: '/pages/rewards/badge' })
-    },
-    goToGrowth: function() {
-      uni.navigateTo({ url: '/pages/growth-main/index' })
-    },
-    goToChallenges: function() {
-      uni.navigateTo({ url: '/pages/health/challenge-manage' })
-    },
-    goToHealthReports: function() {
-      uni.navigateTo({ url: '/pages/health/report-list' })
-    },
-    goToWealthCenter: function() {
-      uni.navigateTo({ url: '/pages/promotion/index' })
-    },
-    goUpgrade: function() {
-      uni.navigateTo({ url: '/pages/membership/upgrade' })
-    },
-    goToFamily: function() {
-      uni.navigateTo({ url: '/pages/profile-extra/family-members' })
-    },
-    goMemberDetail: function(member) {
-      uni.navigateTo({ url: '/pages/home-pages/member-home-detail?memberId=' + member.id })
-    },
-    goToAppointments: function() {
-      uni.navigateTo({ url: '/pages/parent/appointments' })
-    },
-    goToOrders: function() {
-      uni.navigateTo({ url: '/pages/shop/order-list/order-list' })
-    },
-    goToOrderStatus: function(status) {
-      uni.navigateTo({ url: '/pages/shop/order-list/order-list?status=' + status })
-    },
-    goToCart: function() {
-      uni.navigateTo({ url: '/pages/shop/cart/cart' })
-    },
-    goToAddress: function() {
-      uni.navigateTo({ url: '/pages/shop/address/address' })
-    },
-    goToMessageHistory: function() {
-      uni.navigateTo({ url: '/pages/profile/message-history' })
-    },
-    goToSettings: function() {
-      uni.showActionSheet({
-        itemList: ['完善信息', '家庭成员', '隐私政策', '用户协议', '我的画像', '提醒设置'],
-        success: function(res) {
-          var urls = {
-            0: '/pages/user-edit/user-edit',
-            1: '/pages/profile-extra/family-members',
-            2: '/pages/policy/privacy',
-            3: '/pages/policy/agreement',
-            4: '/pages/profile/portrait-edit',
-            5: '/pages/reminder-config/index'
-          }
-          if (urls[res.tapIndex]) {
-            uni.navigateTo({ url: urls[res.tapIndex] })
-          }
-        }
-      })
-    },
-    memberRoleLabel: function(role) {
-      var map = { parent: '家长', child: '成员', teacher: '规划师' }
-      return map[role] || '成员'
-    },
-    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' })
-            })
-          }
-        }
-      })
-    },
-    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)
-      })
-    }
-  }
-}
-</script>
-
-<style scoped lang="scss">
-// ===== 页面级局部调色板(单页专有色阶;同值才映射全局令牌,约定见 uni.scss §14) =====
-$c-text-gray-400:   $facade-text-gray-400;
-$c-fill-2b:         #F2F2F2;
-$c-wisdom-mid:      #4F46E5;   // indigo-600
-$c-danger-ant:      #FF4D4F;   // Ant Design 红
-$c-pink:            #EC4899;   // pink-500
-$c-pink-deep:       #DB2777;   // pink-600
-$c-indigo:          $accent-indigo;   // indigo-500(rgba 渐变用)
-
-.container {
-  min-height: 100vh;
-  background: $facade-fill-warm-gray;
-  padding-bottom: calc(160rpx + env(safe-area-inset-bottom));
-}
-
-/* 登录引导 */
-.login-prompt {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  padding: 200rpx 60rpx;
-}
-.prompt-icon { font-size: 100rpx; margin-bottom: 30rpx; }
-.prompt-title { font-size: 40rpx; font-weight: bold; color: $facade-text-strong; margin-bottom: 16rpx; }
-.prompt-desc { font-size: 26rpx; color: $facade-text-muted; margin-bottom: 20rpx; }
-.login-btn {
-  background: linear-gradient(135deg, $brand-primary, $brand-primary-light);
-  color: $app-surface;
-  border-radius: 50rpx;
-  font-size: 30rpx;
-  padding: 24rpx 80rpx;
-}
-.skip-link {
-  font-size: 26rpx;
-  color: $facade-text-muted;
-  margin-top: 24rpx;
-  text-decoration: underline;
-}
-.philosophy-card {
-  margin: 0 40rpx 48rpx;
-  background: linear-gradient(135deg, $facade-brand-tint, rgba($brand-primary, 0.06));
-  border-radius: 20rpx;
-  padding: 28rpx 32rpx;
-  border-left: 6rpx solid $brand-primary;
-}
-.philosophy-title {
-  font-size: 28rpx;
-  font-weight: bold;
-  color: $facade-text-strong;
-  display: block;
-  margin-bottom: 8rpx;
-}
-.philosophy-desc {
-  font-size: 24rpx;
-  color: $facade-text-faint;
-  line-height: 1.6;
-  display: block;
-}
-
-/* 退出切换 */
-.exit-switch {
-  margin: 0 30rpx 16rpx;
-  background: linear-gradient(135deg, $brand-primary, $brand-primary-light);
-  color: $app-surface;
-  padding: 16rpx;
-  border-radius: 12rpx;
-  text-align: center;
-  font-size: 26rpx;
-}
-
-/* 身份卡 */
-.user-card {
-  margin: 24rpx 30rpx 20rpx;
-  background: linear-gradient(135deg, $brand-primary 0%, $brand-primary-light 100%);
-  border-radius: 24rpx;
-  padding: 32rpx 32rpx;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  box-shadow: 0 8rpx 32rpx rgba($c-indigo, 0.3);
-}
-.user-card-left {
-  display: flex;
-  align-items: center;
-  flex: 1;
-}
-.avatar-wrap {
-  width: 100rpx;
-  height: 100rpx;
-  border-radius: 50%;
-  background: rgba($app-surface, 0.2);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  margin-right: 20rpx;
-  overflow: hidden;
-  border: 3rpx solid rgba($app-surface, 0.3);
-}
-.avatar-img {
-  width: 100rpx;
-  height: 100rpx;
-  border-radius: 50%;
-}
-.avatar-text {
-  font-size: 44rpx;
-  color: $app-surface;
-}
-.user-meta { flex: 1; }
-.user-name-row {
-  display: flex;
-  align-items: center;
-  gap: 12rpx;
-  margin-bottom: 8rpx;
-}
-.nickname {
-  font-size: 34rpx;
-  font-weight: bold;
-  color: $app-surface;
-}
-.role-tag {
-  font-size: 20rpx;
-  background: rgba($app-surface, 0.2);
-  color: $app-surface;
-  padding: 4rpx 14rpx;
-  border-radius: 20rpx;
-}
-.referrer-line {
-  font-size: 24rpx;
-  color: rgba($app-surface, 0.7);
-  margin-bottom: 6rpx;
-}
-.user-sub {
-  display: flex;
-  align-items: center;
-  gap: 12rpx;
-}
-.level-badge {
-  font-size: 22rpx;
-  padding: 6rpx 20rpx;
-  border-radius: 22rpx;
-  font-weight: bold;
-  border: 2rpx solid rgba($app-surface, 0.35);
-  display: flex;
-  align-items: center;
-  gap: 6rpx;
-  box-sizing: border-box;
-  height: 40rpx;
-}
-.level-badge::before {
-  content: '👑';
-  font-size: 18rpx;
-}
-.level-FREE { background: linear-gradient(135deg, $c-text-gray-400, $facade-text-slate); color: $app-surface; }
-.level-FREE::before { content: ''; }
-.level-FAMILY { background: linear-gradient(135deg, $dim-wealth, $status-warning-deep); color: $app-surface; }
-.level-PREMIUM { background: linear-gradient(135deg, $dim-wisdom, $c-wisdom-mid); color: $app-surface; }
-.level-LIFETIME {
-  background: linear-gradient(135deg, $c-pink, $c-pink-deep);
-  color: $app-surface;
-  box-shadow: 0 4rpx 16rpx rgba($c-pink, 0.45);
-  border-color: rgba($app-surface, 0.55);
-}
-.days-left {
-  font-size: 20rpx;
-  color: rgba($app-surface, 0.85);
-}
-.upgrade-btn {
-  background: rgba($app-surface, 0.22);
-  border: 2rpx solid rgba($app-surface, 0.6);
-  border-radius: 20rpx;
-  padding: 6rpx 20rpx;
-  flex-shrink: 0;
-  box-sizing: border-box;
-  height: 40rpx;
-  display: flex;
-  align-items: center;
-}
-.upgrade-btn-text {
-  font-size: 20rpx;
-  font-weight: bold;
-  color: $app-surface;
-  line-height: 1;
-}
-.user-card-right {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  gap: 6rpx;
-  background: rgba($app-surface, 0.15);
-  padding: 12rpx 24rpx;
-  border-radius: 14rpx;
-}
-.points-num {
-  font-size: 36rpx;
-  font-weight: bold;
-  color: $app-surface;
-}
-.points-label {
-  font-size: 20rpx;
-  color: rgba($app-surface, 0.7);
-}
-
-/* 家庭成员速览 */
-.family-strip {
-  margin: 0 30rpx 20rpx;
-  background: $app-surface;
-  border-radius: 20rpx;
-  padding: 20rpx 24rpx 16rpx;
-  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
-}
-.family-strip-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 14rpx;
-}
-.family-strip-title {
-  font-size: 26rpx;
-  font-weight: bold;
-  color: $facade-text-strong;
-}
-.family-strip-count {
-  font-size: 22rpx;
-  color: $facade-text-muted;
-}
-.family-avatars {
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  gap: 16rpx;
-  overflow-x: auto;
-  padding-bottom: 4rpx;
-}
-.family-avatar-item {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  gap: 6rpx;
-  flex-shrink: 0;
-}
-.family-avatar-wrap {
-  width: 72rpx;
-  height: 72rpx;
-  border-radius: 50%;
-  background: $facade-fill;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  overflow: hidden;
-  position: relative;
-}
-.family-avatar-img {
-  width: 72rpx;
-  height: 72rpx;
-  border-radius: 50%;
-}
-.family-avatar-text {
-  font-size: 28rpx;
-  color: $facade-text-body;
-}
-.family-avatar-wrap.family-avatar-add {
-  background: $facade-fill-warm-gray;
-  border: 2rpx dashed $facade-text-ghost;
-}
-.family-avatar-plus {
-  font-size: 36rpx;
-  color: $facade-text-muted;
-}
-.family-avatar-tag {
-  position: absolute;
-  bottom: -4rpx;
-  right: -4rpx;
-  font-size: 14rpx;
-  padding: 2rpx 6rpx;
-  border-radius: 8rpx;
-  color: $app-surface;
-}
-.family-avatar-tag.tag-parent { background: $dim-wisdom; }
-.family-avatar-tag.tag-child { background: $brand-primary; }
-.family-avatar-tag.tag-teacher { background: $dim-action; }
-.family-avatar-tag.tag-member { background: $c-text-gray-400; }
-.family-avatar-name {
-  font-size: 20rpx;
-  color: $facade-text-body;
-  white-space: nowrap;
-}
-
-/* 个人成就 */
-.achievement-section {
-  margin: 0 30rpx 20rpx;
-  background: $app-surface;
-  border-radius: 20rpx;
-  padding: 24rpx;
-  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
-}
-.section-header-row {
-  display: flex;
-  justify-content: space-between;
-  align-items: baseline;
-  margin-bottom: 16rpx;
-}
-.section-title {
-  font-size: 28rpx;
-  font-weight: bold;
-  color: $facade-text-strong;
-}
-.section-sub {
-  font-size: 22rpx;
-  color: $facade-text-muted;
-}
-.achievement-grid {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 0;
-}
-.ach-item {
-  width: 25%;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  gap: 6rpx;
-  padding: 10rpx 0;
-}
-.ach-icon-wrap {
-  width: 64rpx;
-  height: 64rpx;
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  margin-bottom: 4rpx;
-}
-.ach-icon {
-  font-size: 32rpx;
-  line-height: 1;
-}
-.ach-num {
-  font-size: 28rpx;
-  font-weight: bold;
-  color: $facade-text-strong;
-  line-height: 1;
-}
-.ach-label {
-  font-size: 20rpx;
-  color: $facade-text-muted;
-  line-height: 1;
-}
-
-/* 我的订单(电商风格) */
-.order-section {
-  margin: 0 30rpx 20rpx;
-}
-.order-section-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  margin-bottom: 14rpx;
-}
-.order-all-link {
-  font-size: 24rpx;
-  color: $facade-text-muted;
-}
-.order-card {
-  background: $app-surface;
-  border-radius: 20rpx;
-  padding: 24rpx 12rpx;
-  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
-}
-.order-grid {
-  display: flex;
-  flex-wrap: wrap;
-}
-.order-grid-item {
-  width: 20%;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  gap: 10rpx;
-  padding: 8rpx 0;
-}
-.order-icon-wrap {
-  position: relative;
-  width: 64rpx;
-  height: 64rpx;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
-.order-icon {
-  font-size: 40rpx;
-  line-height: 1;
-}
-.order-badge {
-  position: absolute;
-  top: -8rpx;
-  right: -14rpx;
-  min-width: 30rpx;
-  height: 30rpx;
-  line-height: 30rpx;
-  border-radius: 15rpx;
-  background: $c-danger-ant;
-  color: $app-surface;
-  font-size: 18rpx;
-  text-align: center;
-  padding: 0 6rpx;
-}
-.order-grid-text {
-  font-size: 22rpx;
-  color: $facade-text-body;
-  line-height: 1;
-}
-.order-extra-row {
-  display: flex;
-  align-items: center;
-  margin-top: 20rpx;
-  padding-top: 20rpx;
-  border-top: 1rpx solid $c-fill-2b;
-}
-.order-extra-item {
-  flex: 1;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  gap: 8rpx;
-}
-.order-extra-icon {
-  font-size: 28rpx;
-}
-.order-extra-text {
-  font-size: 24rpx;
-  color: $facade-text-strong;
-}
-.order-extra-badge {
-  min-width: 30rpx;
-  height: 30rpx;
-  line-height: 30rpx;
-  border-radius: 15rpx;
-  background: $brand-primary;
-  color: $app-surface;
-  font-size: 18rpx;
-  text-align: center;
-  padding: 0 6rpx;
-}
-.order-extra-divider {
-  width: 1rpx;
-  height: 30rpx;
-  background: $c-fill-2b;
-}
-
-/* 规划师服务中心入口 */
-.service-center-section {
-  margin: 0 30rpx 20rpx;
-}
-.service-center-card {
-  background: linear-gradient(135deg, $brand-primary 0%, $brand-primary-light 100%);
-  border-radius: 20rpx;
-  padding: 24rpx;
-  display: flex;
-  align-items: center;
-  gap: 20rpx;
-  box-shadow: 0 4rpx 16rpx rgba($brand-primary, 0.25);
-}
-.service-center-card.disabled-card {
-  background: linear-gradient(135deg, $uni-border-color-light, $app-text-subtle);
-  box-shadow: none;
-  opacity: 0.8;
-}
-.service-center-icon {
-  font-size: 48rpx;
-}
-.service-center-info {
-  flex: 1;
-}
-.service-center-title {
-  font-size: 30rpx;
-  font-weight: bold;
-  color: $app-surface;
-  display: block;
-}
-.service-center-desc {
-  font-size: 22rpx;
-  color: rgba($app-surface, 0.8);
-  margin-top: 6rpx;
-  display: block;
-}
-.service-center-card.disabled-card .service-center-title {
-  color: $app-surface;
-}
-.service-center-card.disabled-card .service-center-desc {
-  color: rgba($app-surface, 0.9);
-}
-.service-center-arrow {
-  font-size: 40rpx;
-  color: $app-surface;
-}
-
-/* 设置 + 退出 */
-.bottom-menu-section {
-  margin: 0 30rpx;
-  padding-bottom: 20rpx;
-}
-.menu-row {
-  width: 100%;
-  background: $app-surface;
-  border-radius: 16rpx;
-  padding: 24rpx;
-  display: flex;
-  align-items: center;
-  gap: 14rpx;
-  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
-  margin-bottom: 20rpx;
-}
-.menu-row-icon {
-  font-size: 30rpx;
-}
-.menu-row-text {
-  flex: 1;
-  font-size: 26rpx;
-  color: $facade-text-strong;
-}
-.menu-row-arrow {
-  font-size: 28rpx;
-  color: $facade-text-ghost;
-}
-.logout-btn {
-  width: 100%;
-  background: $app-surface;
-  border-radius: 16rpx;
-  padding: 24rpx;
-  text-align: center;
-  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
-}
-.logout-text {
-  font-size: 26rpx;
-  color: $c-danger-ant;
-  font-weight: 500;
-}
-
-/* 分享推广码浮动按钮 */
-.share-qr-float {
-  position: fixed;
-  top: 180rpx;
-  right: 30rpx;
-  width: 80rpx;
-  height: 80rpx;
-  border-radius: 50%;
-  background: $app-surface;
-  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.15);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 99;
-}
-/* 二维码图标(纯 CSS 绘制,不依赖 emoji 字体) */
-.qr-glyph {
-  position: relative;
-  width: 46rpx;
-  height: 46rpx;
-}
-.qr-eye {
-  position: absolute;
-  width: 16rpx;
-  height: 16rpx;
-  border: 4rpx solid $uni-text-color;
-  border-radius: 3rpx;
-  box-sizing: border-box;
-}
-.qr-eye-tl { left: 0; top: 0; }
-.qr-eye-tr { right: 0; top: 0; }
-.qr-eye-bl { left: 0; bottom: 0; }
-.qr-mid {
-  position: absolute;
-  left: 20rpx;
-  top: 20rpx;
-  width: 7rpx;
-  height: 7rpx;
-  background: $uni-text-color;
-  border-radius: 1rpx;
-}
-.qr-cluster {
-  position: absolute;
-  right: 0;
-  bottom: 0;
-  width: 18rpx;
-  display: flex;
-  flex-wrap: wrap;
-}
-.qr-pip {
-  width: 7rpx;
-  height: 7rpx;
-  margin: 1rpx;
-  background: $uni-text-color;
-  border-radius: 1rpx;
-}
-</style>
+<template>
+  <view class="container">
+    <!-- 登录浮层(全局组件,页面内弹出底部登录) -->
+    <login-sheet ref="loginSheet" @success="onSheetLoginSuccess" />
+    <!-- 未登录 -->
+    <view v-if="!isLoggedIn">
+      <view class="login-prompt">
+        <text class="prompt-icon">👤</text>
+        <text class="prompt-title">登录浠艾福</text>
+        <text class="prompt-desc">登录后查看个人资料、积分记录、能量数据与家庭管理</text>
+        <button class="login-btn" @click="goLogin">登录 / 注册</button>
+        <text class="skip-link" @click="goSkip">暂不登录,先逛逛 ›</text>
+      </view>
+
+      <view class="philosophy-card">
+        <text class="philosophy-title">照顾家庭,从照顾好自己开始</text>
+        <text class="philosophy-desc">你的状态,就是家的状态。先安顿好自己,才有余力温暖家人。</text>
+      </view>
+    </view>
+
+    <!-- 已登录 -->
+    <template v-else>
+      <!-- 退出切换 -->
+      <view class="exit-switch" v-if="isSwitchedChild" @click="onExitSwitch">
+        <text>🔄 退出切换</text>
+      </view>
+
+      <!-- 身份卡 -->
+      <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 v-if="roleLabel" class="role-tag">{{ roleLabel }}</text>
+            </view>
+            <view class="user-sub" v-if="memberLevel">
+              <view class="level-badge" :class="'level-' + memberLevel">{{ memberLevelText }}</view>
+              <text v-if="isLifetime" class="days-left">永久有效</text>
+              <text v-else-if="membershipDays > 0 && membershipDays <= 30" class="days-left">剩余 {{ membershipDays }} 天</text>
+              <view v-if="hasUpgradeSpace" class="upgrade-btn" @click="goUpgrade">
+                <text class="upgrade-btn-text">{{ upgradeBtnText }}</text>
+              </view>
+            </view>
+            <view class="user-sub" v-else>
+              <text class="days-left">开通会员解锁更多权益</text>
+              <view class="upgrade-btn" @click="goUpgrade">
+                <text class="upgrade-btn-text">立即开通</text>
+              </view>
+            </view>
+          </view>
+        </view>
+        <view class="user-card-right" @click="goToPoints">
+          <text class="points-num">{{ totalPoints }}</text>
+          <text class="points-label">积分</text>
+        </view>
+      </view>
+
+      <!-- 我的分享海报浮动按钮(纯 CSS 二维码图标,避免 emoji 渲染成计算器) -->
+      <view class="share-qr-float" @click="showShareQr">
+        <view class="qr-glyph">
+          <view class="qr-eye qr-eye-tl"></view>
+          <view class="qr-eye qr-eye-tr"></view>
+          <view class="qr-eye qr-eye-bl"></view>
+          <view class="qr-mid"></view>
+          <view class="qr-cluster">
+            <view class="qr-pip"></view>
+            <view class="qr-pip"></view>
+            <view class="qr-pip"></view>
+            <view class="qr-pip"></view>
+          </view>
+        </view>
+      </view>
+
+      <!-- 家族成员速览 -->
+      <view class="family-strip" v-if="familyMembers.length > 0">
+        <view class="family-strip-header">
+          <text class="family-strip-title">我的家庭</text>
+          <text class="family-strip-count">{{ familyMembers.length }} 位成员</text>
+        </view>
+        <view class="family-avatars">
+          <view
+            v-for="member in familyMembers"
+            :key="member.id"
+            class="family-avatar-item"
+            @click="goMemberDetail(member)"
+          >
+            <view class="family-avatar-wrap">
+              <image v-if="member.avatar" class="family-avatar-img" :src="member.avatar" mode="aspectFill" />
+              <text v-else class="family-avatar-text">{{ member.nickname ? member.nickname.charAt(0) : '?' }}</text>
+              <view class="family-avatar-tag" :class="'tag-' + (member.effectiveRole || member.source || 'member')">{{ member.roleLabel || memberRoleLabel(member.effectiveRole) }}</view>
+            </view>
+            <text class="family-avatar-name">{{ member.nickname || member.realName || '成员' }}</text>
+          </view>
+          <view class="family-avatar-item" @click="goToFamily">
+            <view class="family-avatar-wrap family-avatar-add">
+              <text class="family-avatar-plus">+</text>
+            </view>
+            <text class="family-avatar-name">添加</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- 个人成就统计 -->
+      <view class="achievement-section">
+        <view class="section-header-row">
+          <text class="section-title">🏆 我的成就</text>
+          <text class="section-sub">持续成长,看见改变</text>
+        </view>
+        <view class="achievement-grid">
+          <view class="ach-item" @click="goToPoints">
+            <view class="ach-icon-wrap" style="background:rgba(249,115,22,0.12)">
+              <text class="ach-icon">💰</text>
+            </view>
+            <text class="ach-num">{{ totalPoints }}</text>
+            <text class="ach-label">累计积分</text>
+          </view>
+          <view class="ach-item" @click="goToStreak">
+            <view class="ach-icon-wrap" style="background:rgba(255,140,66,0.12)">
+              <text class="ach-icon">🔥</text>
+            </view>
+            <text class="ach-num">{{ streakDays }}</text>
+            <text class="ach-label">连续打卡</text>
+          </view>
+          <view class="ach-item" @click="goToTasks">
+            <view class="ach-icon-wrap" style="background:rgba(99,102,241,0.12)">
+              <text class="ach-icon">✅</text>
+            </view>
+            <text class="ach-num">{{ completedTasks }}</text>
+            <text class="ach-label">完成任务</text>
+          </view>
+          <view class="ach-item" @click="goToWishes">
+            <view class="ach-icon-wrap" style="background:rgba(245,158,11,0.12)">
+              <text class="ach-icon">🎁</text>
+            </view>
+            <text class="ach-num">{{ rewardsEarned }}</text>
+            <text class="ach-label">获得奖励</text>
+          </view>
+          <view class="ach-item" @click="goToBadges">
+            <view class="ach-icon-wrap" style="background:rgba(236,72,153,0.12)">
+              <text class="ach-icon">🏅</text>
+            </view>
+            <text class="ach-num">{{ badgesCollected }}</text>
+            <text class="ach-label">收集勋章</text>
+          </view>
+          <view class="ach-item" @click="goToGrowth">
+            <view class="ach-icon-wrap" style="background:rgba(16,185,129,0.12)">
+              <text class="ach-icon">📈</text>
+            </view>
+            <text class="ach-num">{{ growthRecords }}</text>
+            <text class="ach-label">成长记录</text>
+          </view>
+          <view class="ach-item" @click="goToChallenges">
+            <view class="ach-icon-wrap" style="background:rgba(255,107,157,0.12)">
+              <text class="ach-icon">🎯</text>
+            </view>
+            <text class="ach-num">{{ challengesJoined }}</text>
+            <text class="ach-label">参加挑战</text>
+          </view>
+          <view class="ach-item" @click="goToHealthReports">
+            <view class="ach-icon-wrap" style="background:rgba(14,165,233,0.12)">
+              <text class="ach-icon">📋</text>
+            </view>
+            <text class="ach-num">{{ healthReports }}</text>
+            <text class="ach-label">上传报告</text>
+          </view>
+          <view class="ach-item" @click="goToWealthCenter">
+            <view class="ach-icon-wrap" style="background:rgba(245,158,11,0.12)">
+              <text class="ach-icon">💰</text>
+            </view>
+            <text class="ach-num">{{ referralEarnings }}</text>
+            <text class="ach-label">推广收益</text>
+          </view>
+          <view class="ach-item" @click="goTeamTree">
+            <view class="ach-icon-wrap" style="background:rgba(16,185,129,0.12)">
+              <text class="ach-icon">🌳</text>
+            </view>
+            <text class="ach-num">{{ teamMembers }}</text>
+            <text class="ach-label">我的团队</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- 我的订单(电商风格) -->
+      <view class="order-section">
+        <view class="order-section-header">
+          <text class="section-title">🛒 我的订单</text>
+          <text class="order-all-link" @click="goToOrders">全部订单 ›</text>
+        </view>
+        <view class="order-card">
+          <view class="order-grid">
+            <view class="order-grid-item" @click="goToOrderStatus('pending')">
+              <view class="order-icon-wrap">
+                <text class="order-icon">💳</text>
+                <text class="order-badge" v-if="orderPending > 0">{{ orderPending }}</text>
+              </view>
+              <text class="order-grid-text">待付款</text>
+            </view>
+            <view class="order-grid-item" @click="goToOrderStatus('paid')">
+              <view class="order-icon-wrap">
+                <text class="order-icon">📦</text>
+                <text class="order-badge" v-if="orderUnpaid > 0">{{ orderUnpaid }}</text>
+              </view>
+              <text class="order-grid-text">待发货</text>
+            </view>
+            <view class="order-grid-item" @click="goToOrderStatus('shipped')">
+              <view class="order-icon-wrap">
+                <text class="order-icon">🚚</text>
+                <text class="order-badge" v-if="orderShipped > 0">{{ orderShipped }}</text>
+              </view>
+              <text class="order-grid-text">待收货</text>
+            </view>
+            <view class="order-grid-item" @click="goToOrderStatus('refunding')">
+              <view class="order-icon-wrap">
+                <text class="order-icon">🔧</text>
+                <text class="order-badge" v-if="orderAfterSale > 0">{{ orderAfterSale }}</text>
+              </view>
+              <text class="order-grid-text">售后</text>
+            </view>
+            <view class="order-grid-item" @click="goToOrders">
+              <view class="order-icon-wrap">
+                <text class="order-icon">📋</text>
+              </view>
+              <text class="order-grid-text">全部</text>
+            </view>
+          </view>
+          <view class="order-extra-row">
+            <view class="order-extra-item" @click="goToCart">
+              <text class="order-extra-icon">🛒</text>
+              <text class="order-extra-text">购物车</text>
+              <text class="order-extra-badge" v-if="cartCount > 0">{{ cartCount > 99 ? '99+' : cartCount }}</text>
+            </view>
+            <view class="order-extra-divider"></view>
+            <view class="order-extra-item" @click="goToAddress">
+              <text class="order-extra-icon">📍</text>
+              <text class="order-extra-text">收货地址</text>
+            </view>
+          </view>
+        </view>
+      </view>
+
+      <!-- 规划师服务中心入口(仅规划师可见) -->
+      <view class="service-center-section" v-if="role === 'teacher' && teacherStatus === 'approved'">
+        <view class="service-center-card" @click="goToServiceCenter">
+          <view class="service-center-icon">👨‍🏫</view>
+          <view class="service-center-info">
+            <text class="service-center-title">服务中心</text>
+            <text class="service-center-desc">待处理任务:{{ pendingTasks }} 条 · 消息:{{ unreadMessages }} 条</text>
+          </view>
+          <text class="service-center-arrow">›</text>
+        </view>
+      </view>
+
+      <!-- 规划师待审核提示 -->
+      <view class="service-center-section" v-if="role === 'teacher' && teacherStatus !== 'approved'">
+        <view class="service-center-card disabled-card">
+          <view class="service-center-icon">👨‍🏫</view>
+          <view class="service-center-info">
+            <text class="service-center-title">服务中心</text>
+            <text class="service-center-desc">{{ teacherStatus === 'pending' ? '申请审核中,暂未开放' : teacherStatus === 'rejected' ? '申请未通过,请联系管理员' : '规划师服务' }}</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- 设置 + 退出 -->
+      <view class="bottom-menu-section">
+        <view class="menu-row" @click="goToMessageHistory">
+          <text class="menu-row-icon">📨</text>
+          <text class="menu-row-text">历史消息</text>
+          <text class="menu-row-arrow">›</text>
+        </view>
+        <view class="menu-row" @click="goToSettings">
+          <text class="menu-row-icon">⚙️</text>
+          <text class="menu-row-text">设置</text>
+          <text class="menu-row-arrow">›</text>
+        </view>
+        <view class="logout-btn" @click="logout">
+          <text class="logout-text">退出登录</text>
+        </view>
+      </view>
+
+      </template>
+    <!-- 我的分享海报:复用文章/活动/商品同一套 ContentSharePoster 组件(canvas 绘制 + 保存到相册) -->
+    <ContentSharePoster
+      :show="showSharePoster"
+      :title="shareHeadline"
+      :energyData="posterEnergyData"
+      :brandFallback="true"
+      :qrCodeBase64="posterQrCode || ''"
+      typeLabel="邀友加入"
+      :summary="posterSummary"
+      ctaText="长按识别二维码 · 加入浠艾福"
+      :inviteText="posterInviteText"
+      @close="closeSharePoster"
+    />
+    <FloatingAvatar />
+  </view>
+</template>
+
+<script>
+import FloatingAvatar from '../../components/AIFloatingAvatar.vue'
+import ContentSharePoster from '../../components/ContentSharePoster.vue'
+import {
+  getChildren, getFamilyMemberList,
+  getTodayTasksByCategory, getChallengeList, getMyMembership,
+  verifyPassword, getPointsBalance, getUserInfo,
+  cartCount, getOrderCounts, getReferralSummary,
+  getProfileStats, getMyReferrer, getTeamConsumption,
+  getTeacherInfo, getTeacherPendingTasks, getTeacherUnreadCount,
+  getReferralCode, extractReferralCode, getShareQrCode, getEnergySandbox,
+  vendorStatus
+} from '../../utils/api.js'
+
+export default {
+  components: { FloatingAvatar, ContentSharePoster },
+  data() {
+    return {
+      nickname: '',
+      role: 'parent',
+      isSwitchedChild: false,
+      userInfo: {},
+      memberLevel: null,
+      membershipDays: 0,
+      totalPoints: 0,
+      referralEarnings: 0,
+      teamMembers: 0,
+      // 个人成就
+      completedTasks: 0,
+      streakDays: 0,
+      rewardsEarned: 0,
+      badgesCollected: 0,
+      growthRecords: 0,
+      challengesJoined: 0,
+      healthReports: 0,
+      // 家庭
+      familyMembers: [],
+      // 商城
+      orderPending: 0,
+      orderUnpaid: 0,
+      orderShipped: 0,
+      orderAfterSale: 0,
+      cartCount: 0,
+      // 待办
+      pendingTasks: 0,
+      unreadMessages: 0,
+      teacherStatus: 'pending',
+      isVendor: false,
+      profileProgress: 0,
+      myReferrer: null,
+      // 分享推广码
+      showSharePoster: false,
+      referralCode: '',
+      posterQrCode: '',
+      posterEnergyData: null,
+      referralCodeLoaded: false,
+    }
+  },
+  computed: {
+    isLoggedIn() {
+      return !!uni.getStorageSync('token')
+    },
+    roleLabel() {
+      var map = { parent: '', child: '成员', teacher: '规划师' }
+      return map[this.role] || '用户'
+    },
+    memberLevelText() {
+      var map = { FREE: '免费用户', BASIC: '体验会员', FAMILY: '家庭会员', PREMIUM: '高级会员', LIFETIME: '终身会员' }
+      return map[this.memberLevel] || this.memberLevel || ''
+    },
+    isLifetime() {
+      return this.memberLevel === 'LIFETIME'
+    },
+    hasUpgradeSpace() {
+      return this.memberLevel === 'FREE' || this.memberLevel === 'FAMILY'
+    },
+    upgradeBtnText() {
+      return this.hasUpgradeSpace ? '升级' : '立即开通'
+    },
+    // 分享海报标题:XXX邀请你关注家庭健康(昵称过长自动截断)
+    shareHeadline() {
+      var name = (this.nickname || '').trim()
+      if (!name) return '邀请你关注家庭健康'
+      if (name.length > 8) name = name.substring(0, 8) + '…'
+      return name + '邀请你关注家庭健康'
+    },
+    posterSummary() {
+      return '身体 · 心理 · 智慧 · 行动 · 财富,一家专注全家健康的成长平台'
+    },
+    posterInviteText() {
+      var name = (this.nickname || '').trim()
+      if (!name) return '扫码加入浠艾福,一起照顾好这个家'
+      if (name.length > 8) name = name.substring(0, 8) + '…'
+      return '「' + name + '」邀请你加入浠艾福'
+    }
+  },
+  onShow() {
+    if (!this.isLoggedIn) {
+      return
+    }
+    var role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || 'parent'
+    this.role = role
+    this.isSwitchedChild = uni.getStorageSync('isSwitchedChild') || false
+    this.nickname = (uni.getStorageSync('userInfo') || {}).nickname || ''
+
+    // 服务商身份判断(成就区「我的团队」入口按此分发)
+    this.checkVendorStatus()
+
+    // 规划师加载额外数据
+    if (role === 'teacher') {
+      this.loadTeacherStatus()
+      this.loadTeacherData()
+    } else {
+      this.loadAllData()
+      this.loadMyReferrer()
+    }
+  },
+  methods: {
+    // 服务商身份:vendorStatus 返回 approved 即为已通过审核的服务商
+    checkVendorStatus() {
+      var self = this
+      vendorStatus().then(function(res) {
+        self.isVendor = !!(res && res.data && res.data.vendorStatus === 'approved')
+      }).catch(function() {
+        self.isVendor = false
+      })
+    },
+    loadTeacherStatus() {
+      var self = this
+      getTeacherInfo().then(function(res) {
+        if (res && res.code === 200 && res.data) {
+          self.teacherStatus = res.data.verificationStatus || res.data.status || 'pending'
+        }
+      }).catch(function() {})
+    },
+    loadTeacherData() {
+      var self = this
+      // 并行加载待处理任务和未读消息
+      getTeacherPendingTasks().then(function(res) {
+        if (res && res.data && Array.isArray(res.data)) {
+          self.pendingTasks = res.data.length
+        } else if (res && res.data && res.data.pendingCount != null) {
+          self.pendingTasks = res.data.pendingCount
+        }
+      }).catch(function() {})
+      getTeacherUnreadCount().then(function(res) {
+        if (res && res.data != null) {
+          self.unreadMessages = res.data
+        }
+      }).catch(function() {})
+    },
+    loadAllData() {
+      this.loadUserInfo()
+      this.loadMembership()
+      this.loadPoints()
+      this.loadFamily()
+      this.loadTasks()
+      this.loadChallenges()
+      this.loadOrderCounts()
+      this.loadCartCount()
+      this.loadProfileStats()
+      this.loadReferralEarnings()
+      this.loadTeamInfo()
+    },
+    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
+      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() {})
+    },
+    loadPoints() {
+      // 累计积分由 loadProfileStats 汇总家庭成员积分,此处不再单独覆盖
+    },
+    loadFamily() {
+      var self = this
+      getFamilyMemberList({ visibleOnly: true }).then(function(res) {
+        var data = res && res.data ? res.data : []
+        self.familyMembers = Array.isArray(data) ? data : []
+      }).catch(function() {
+        self.familyMembers = []
+      })
+    },
+    loadTasks() {
+      var self = this
+      var memberId = uni.getStorageSync('currentChildId') || uni.getStorageSync('userId')
+      if (!memberId) return
+      getTodayTasksByCategory(memberId, 'action').then(function(res) {
+        if (res && res.data) {
+          self.pendingTasks = Array.isArray(res.data) ? res.data.length : 0
+        }
+      }).catch(function() {})
+      // fallback to storage
+      if (!self.pendingTasks) {
+        self.pendingTasks = parseInt(uni.getStorageSync('pendingTaskCount') || 0)
+      }
+    },
+    loadChallenges() {
+      var self = this
+      getChallengeList({}).then(function(res) {
+        if (res && res.data) {
+          // 不在此处使用,仅确保请求
+        }
+      }).catch(function() {})
+    },
+    loadOrderCounts() {
+      var self = this
+      getOrderCounts().then(function(res) {
+        if (res && res.data) {
+          self.orderPending = res.data.pending || 0
+          self.orderUnpaid = res.data.paid || 0
+          self.orderShipped = res.data.shipped || 0
+          self.orderAfterSale = res.data.refunding || 0
+        }
+      }).catch(function() {})
+    },
+    loadCartCount() {
+      var self = this
+      cartCount().then(function(res) {
+        if (res && res.data != null) {
+          self.cartCount = res.data || 0
+        }
+      }).catch(function() {})
+    },
+    loadProfileStats() {
+      var self = this
+      getProfileStats().then(function(res) {
+        if (res && res.code === 200 && res.data) {
+          var d = res.data
+          if (d.totalPoints != null) self.totalPoints = d.totalPoints
+          if (d.streakDays != null) self.streakDays = d.streakDays
+          if (d.completedTasks != null) self.completedTasks = d.completedTasks
+          if (d.rewardsEarned != null) self.rewardsEarned = d.rewardsEarned
+          if (d.badgesCollected != null) self.badgesCollected = d.badgesCollected
+          if (d.growthRecords != null) self.growthRecords = d.growthRecords
+          if (d.challengesJoined != null) self.challengesJoined = d.challengesJoined
+          if (d.healthReports != null) self.healthReports = d.healthReports
+        }
+      }).catch(function() {})
+    },
+
+    loadReferralEarnings() {
+      var self = this
+      getReferralSummary().then(function(res) {
+        if (res && res.code === 200 && res.data) {
+          self.referralEarnings = res.data.totalEarnings || 0
+        }
+      }).catch(function() {})
+    },
+    loadTeamInfo() {
+      var self = this
+      getTeamConsumption(3).then(function(res) {
+        if (res && res.data && res.data.totalMembers != null) {
+          self.teamMembers = res.data.totalMembers
+        }
+      }).catch(function() {})
+    },
+    async loadMyReferrer() {
+      try {
+        var memberId = uni.getStorageSync('currentMemberId') || uni.getStorageSync('currentChildId') || 0
+        var res = await getMyReferrer(memberId)
+        if (res && res.code === 200 && res.data && res.data.hasReferrer) {
+          this.myReferrer = res.data
+        }
+      } catch (e) {
+        console.error('获取推荐人失败', e)
+      }
+    },
+    // ===== 分享海报(复用 ContentSharePoster,与文章/活动/商品同一套生成逻辑)=====
+    async showShareQr() {
+      uni.showLoading({ title: '生成海报中...' })
+      try {
+        if (!this.referralCodeLoaded) {
+          await this.loadReferralCode()
+        }
+        var scene = 'ref=' + (this.referralCode || '')
+        if (scene.length > 32) {
+          scene = scene.substring(0, 32)
+        }
+        // 首页路径,扫码后进入首页并绑定推荐人
+        // 注意:微信 getwxacodeunlimit 的 page 不能带前导斜杠,否则报 errcode 41030 invalid page rid
+        var res = await getShareQrCode('pages/index-home/index', scene)
+        if (res && res.code === 200 && res.data && res.data.qrCodeBase64) {
+          this.posterQrCode = res.data.qrCodeBase64
+          // 必须在 showSharePoster=true 之前取到数据:组件 watch 到 show 后 300ms 即开始绘制
+          await this.loadPosterEnergy()
+          this.showSharePoster = true
+        } else {
+          uni.showToast({ title: '生成失败,请重试', icon: 'none' })
+        }
+      } catch (e) {
+        console.error('生成分享海报失败', e)
+        uni.showToast({ title: '生成失败,请重试', icon: 'none' })
+      } finally {
+        uni.hideLoading()
+      }
+    },
+    closeSharePoster() {
+      this.showSharePoster = false
+    },
+    // 五维能量数据卡数据(方案C):家庭聚合视角;未解锁全景/取数失败时置空,海报降级为品牌卡
+    loadPosterEnergy() {
+      var self = this
+      return getEnergySandbox('family').then(function(res) {
+        self.posterEnergyData = self.mapPosterEnergy(res)
+      }).catch(function(e) {
+        console.error('获取五维能量失败,海报降级为品牌卡', e)
+        self.posterEnergyData = null
+      })
+    },
+    mapPosterEnergy(res) {
+      if (!res || res.code !== 200 || !res.data) return null
+      // locked=true 表示用户未解锁全景,此时不展示任何数据,改为品牌卡
+      if (res.data.locked) return null
+      // 只认家庭聚合视角;仅当接口返回的是裸 DTO(无 personalData/familyData 包装)时才直接取 res.data
+      var d = res.data.familyData || null
+      if (!d) {
+        if (res.data.personalData) return null
+        d = res.data
+      }
+      if (!d || typeof d !== 'object') return null
+      var defs = [
+        { key: 'body', label: '身', color: BrandColors.body },
+        { key: 'mind', label: '心', color: BrandColors.mind },
+        { key: 'wisdom', label: '智', color: BrandColors.wisdom },
+        { key: 'action', label: '行', color: BrandColors.action },
+        { key: 'wealth', label: '富', color: BrandColors.wealth }
+      ]
+      var dims = []
+      var sum = 0
+      for (var i = 0; i < defs.length; i++) {
+        var raw = d[defs[i].key + 'Score']
+        if (raw === null || raw === undefined || raw === '' || isNaN(raw)) continue
+        var n = Number(raw)
+        if (n < 0) n = 0
+        if (n > 100) n = 100
+        sum += n
+        dims.push({ key: defs[i].key, label: defs[i].label, score: n, color: defs[i].color })
+      }
+      if (dims.length === 0) return null
+      var overall = d.overallScore
+      if (overall === null || overall === undefined || overall === '' || isNaN(overall)) {
+        overall = Math.round(sum / dims.length)
+      }
+      return { label: '我们家的能量', overall: Number(overall), dims: dims }
+    },
+
+    async loadReferralCode() {
+      if (this.referralCodeLoaded) return
+      var self = this
+      try {
+        var res = await getReferralCode()
+        self.referralCode = extractReferralCode(res) || ''
+      } catch (e) {
+        console.error('获取推广码失败', e)
+      } finally {
+        self.referralCodeLoaded = true
+      }
+    },
+    goToServiceCenter() {
+      uni.navigateTo({ url: '/pages/service-center/index' })
+    },
+    goTeamTree() {
+      // 服务商 → 服务商团队;非服务商 → 引导申请
+      if (this.isVendor) {
+        uni.navigateTo({ url: '/pages/vendor/team-system/team-system' })
+        return
+      }
+      uni.showModal({
+        title: '提示',
+        content: '您尚未申请任何服务角色,是否立即申请?',
+        confirmText: '去申请',
+        cancelText: '取消',
+        success: function(res) {
+          if (res.confirm) {
+            uni.navigateTo({ url: '/pages/profile/service-role-apply' })
+          }
+        }
+      })
+    },
+    goLogin: function() {
+      this.openLoginSheet()
+    },
+    // 登录浮层成功回调:刷新个人资料与登录后数据
+    onLoginSuccess: function() {
+      if (this.loadUserInfo) this.loadUserInfo()
+    },
+    goSkip: function() {
+      uni.switchTab({ url: '/pages/index-home/index' })
+    },
+    goToEditInfo: function() {
+      uni.navigateTo({ url: '/pages/user-edit/user-edit' })
+    },
+    goToPoints: function() {
+      uni.navigateTo({ url: '/pages/points/points' })
+    },
+    goToStreak: function() {
+      var memberId = uni.getStorageSync('currentMemberId') || uni.getStorageSync('currentChildId')
+      var url = '/pages/stats/completion-rate'
+      if (memberId) {
+        url += '?memberId=' + memberId
+      } else {
+        url += '?familyView=1'
+      }
+      uni.navigateTo({ url: url })
+    },
+    goToTasks: function() {
+      uni.navigateTo({ url: '/pages/tasks/tasks' })
+    },
+    goToWishes: function() {
+      uni.navigateTo({ url: '/pages/wishes/index' })
+    },
+    goToBadges: function() {
+      uni.navigateTo({ url: '/pages/rewards/badge' })
+    },
+    goToGrowth: function() {
+      uni.navigateTo({ url: '/pages/growth-main/index' })
+    },
+    goToChallenges: function() {
+      uni.navigateTo({ url: '/pages/health/challenge-manage' })
+    },
+    goToHealthReports: function() {
+      uni.navigateTo({ url: '/pages/health/report-list' })
+    },
+    goToWealthCenter: function() {
+      uni.navigateTo({ url: '/pages/promotion/index' })
+    },
+    goUpgrade: function() {
+      uni.navigateTo({ url: '/pages/membership/upgrade' })
+    },
+    goToFamily: function() {
+      uni.navigateTo({ url: '/pages/profile-extra/family-members' })
+    },
+    goMemberDetail: function(member) {
+      uni.navigateTo({ url: '/pages/home-pages/member-home-detail?memberId=' + member.id })
+    },
+    goToAppointments: function() {
+      uni.navigateTo({ url: '/pages/parent/appointments' })
+    },
+    goToOrders: function() {
+      uni.navigateTo({ url: '/pages/shop/order-list/order-list' })
+    },
+    goToOrderStatus: function(status) {
+      uni.navigateTo({ url: '/pages/shop/order-list/order-list?status=' + status })
+    },
+    goToCart: function() {
+      uni.navigateTo({ url: '/pages/shop/cart/cart' })
+    },
+    goToAddress: function() {
+      uni.navigateTo({ url: '/pages/shop/address/address' })
+    },
+    goToMessageHistory: function() {
+      uni.navigateTo({ url: '/pages/profile/message-history' })
+    },
+    goToSettings: function() {
+      uni.showActionSheet({
+        itemList: ['完善信息', '家庭成员', '隐私政策', '用户协议', '我的画像', '提醒设置'],
+        success: function(res) {
+          var urls = {
+            0: '/pages/user-edit/user-edit',
+            1: '/pages/profile-extra/family-members',
+            2: '/pages/policy/privacy',
+            3: '/pages/policy/agreement',
+            4: '/pages/profile/portrait-edit',
+            5: '/pages/reminder-config/index'
+          }
+          if (urls[res.tapIndex]) {
+            uni.navigateTo({ url: urls[res.tapIndex] })
+          }
+        }
+      })
+    },
+    memberRoleLabel: function(role) {
+      var map = { parent: '家长', child: '成员', teacher: '规划师' }
+      return map[role] || '成员'
+    },
+    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' })
+            })
+          }
+        }
+      })
+    },
+    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)
+      })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+// ===== 页面级局部调色板(单页专有色阶;同值才映射全局令牌,约定见 uni.scss §14) =====
+$c-text-gray-400:   $facade-text-gray-400;
+$c-fill-2b:         #F2F2F2;

+.container {
+  min-height: 100vh;
+  background: $facade-fill-warm-gray;
+  padding-bottom: calc(160rpx + env(safe-area-inset-bottom));
+}
+
+/* 登录引导 */
+.login-prompt {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 200rpx 60rpx;
+}
+.prompt-icon { font-size: 100rpx; margin-bottom: 30rpx; }
+.prompt-title { font-size: 40rpx; font-weight: bold; color: $facade-text-strong; margin-bottom: 16rpx; }
+.prompt-desc { font-size: 26rpx; color: $facade-text-muted; margin-bottom: 20rpx; }
+.login-btn {
+  background: linear-gradient(135deg, $brand-primary, $brand-primary-light);
+  color: $app-surface;
+  border-radius: 50rpx;
+  font-size: 30rpx;
+  padding: 24rpx 80rpx;
+}
+.skip-link {
+  font-size: 26rpx;
+  color: $facade-text-muted;
+  margin-top: 24rpx;
+  text-decoration: underline;
+}
+.philosophy-card {
+  margin: 0 40rpx 48rpx;
+  background: linear-gradient(135deg, $facade-brand-tint, rgba($brand-primary, 0.06));
+  border-radius: 20rpx;
+  padding: 28rpx 32rpx;
+  border-left: 6rpx solid $brand-primary;
+}
+.philosophy-title {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: $facade-text-strong;
+  display: block;
+  margin-bottom: 8rpx;
+}
+.philosophy-desc {
+  font-size: 24rpx;
+  color: $facade-text-faint;
+  line-height: 1.6;
+  display: block;
+}
+
+/* 退出切换 */
+.exit-switch {
+  margin: 0 30rpx 16rpx;
+  background: linear-gradient(135deg, $brand-primary, $brand-primary-light);
+  color: $app-surface;
+  padding: 16rpx;
+  border-radius: 12rpx;
+  text-align: center;
+  font-size: 26rpx;
+}
+
+/* 身份卡 */
+.user-card {
+  margin: 24rpx 30rpx 20rpx;
+  background: linear-gradient(135deg, $brand-primary 0%, $brand-primary-light 100%);
+  border-radius: 24rpx;
+  padding: 32rpx 32rpx;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  box-shadow: 0 8rpx 32rpx rgba($c-indigo, 0.3);
+}
+.user-card-left {
+  display: flex;
+  align-items: center;
+  flex: 1;
+}
+.avatar-wrap {
+  width: 100rpx;
+  height: 100rpx;
+  border-radius: 50%;
+  background: rgba($app-surface, 0.2);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 20rpx;
+  overflow: hidden;
+  border: 3rpx solid rgba($app-surface, 0.3);
+}
+.avatar-img {
+  width: 100rpx;
+  height: 100rpx;
+  border-radius: 50%;
+}
+.avatar-text {
+  font-size: 44rpx;
+  color: $app-surface;
+}
+.user-meta { flex: 1; }
+.user-name-row {
+  display: flex;
+  align-items: center;
+  gap: 12rpx;
+  margin-bottom: 8rpx;
+}
+.nickname {
+  font-size: 34rpx;
+  font-weight: bold;
+  color: $app-surface;
+}
+.role-tag {
+  font-size: 20rpx;
+  background: rgba($app-surface, 0.2);
+  color: $app-surface;
+  padding: 4rpx 14rpx;
+  border-radius: 20rpx;
+}
+.referrer-line {
+  font-size: 24rpx;
+  color: rgba($app-surface, 0.7);
+  margin-bottom: 6rpx;
+}
+.user-sub {
+  display: flex;
+  align-items: center;
+  gap: 12rpx;
+}
+.level-badge {
+  font-size: 22rpx;
+  padding: 6rpx 20rpx;
+  border-radius: 22rpx;
+  font-weight: bold;
+  border: 2rpx solid rgba($app-surface, 0.35);
+  display: flex;
+  align-items: center;
+  gap: 6rpx;
+  box-sizing: border-box;
+  height: 40rpx;
+}
+.level-badge::before {
+  content: '👑';
+  font-size: 18rpx;
+}
+.level-FREE { background: linear-gradient(135deg, $c-text-gray-400, $facade-text-slate); color: $app-surface; }
+.level-FREE::before { content: ''; }
+.level-FAMILY { background: linear-gradient(135deg, $dim-wealth, $status-warning-deep); color: $app-surface; }
+.level-PREMIUM { background: linear-gradient(135deg, $dim-wisdom, $dim-wisdom-deep); color: $app-surface; }
+.level-LIFETIME {
+  background: linear-gradient(135deg, $accent-pink, $accent-pink-deep);
+  color: $app-surface;
+  box-shadow: 0 4rpx 16rpx rgba($accent-pink, 0.45);
+  border-color: rgba($app-surface, 0.55);
+}
+.days-left {
+  font-size: 20rpx;
+  color: rgba($app-surface, 0.85);
+}
+.upgrade-btn {
+  background: rgba($app-surface, 0.22);
+  border: 2rpx solid rgba($app-surface, 0.6);
+  border-radius: 20rpx;
+  padding: 6rpx 20rpx;
+  flex-shrink: 0;
+  box-sizing: border-box;
+  height: 40rpx;
+  display: flex;
+  align-items: center;
+}
+.upgrade-btn-text {
+  font-size: 20rpx;
+  font-weight: bold;
+  color: $app-surface;
+  line-height: 1;
+}
+.user-card-right {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 6rpx;
+  background: rgba($app-surface, 0.15);
+  padding: 12rpx 24rpx;
+  border-radius: 14rpx;
+}
+.points-num {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: $app-surface;
+}
+.points-label {
+  font-size: 20rpx;
+  color: rgba($app-surface, 0.7);
+}
+
+/* 家庭成员速览 */
+.family-strip {
+  margin: 0 30rpx 20rpx;
+  background: $app-surface;
+  border-radius: 20rpx;
+  padding: 20rpx 24rpx 16rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+}
+.family-strip-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 14rpx;
+}
+.family-strip-title {
+  font-size: 26rpx;
+  font-weight: bold;
+  color: $facade-text-strong;
+}
+.family-strip-count {
+  font-size: 22rpx;
+  color: $facade-text-muted;
+}
+.family-avatars {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  gap: 16rpx;
+  overflow-x: auto;
+  padding-bottom: 4rpx;
+}
+.family-avatar-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 6rpx;
+  flex-shrink: 0;
+}
+.family-avatar-wrap {
+  width: 72rpx;
+  height: 72rpx;
+  border-radius: 50%;
+  background: $facade-fill;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  overflow: hidden;
+  position: relative;
+}
+.family-avatar-img {
+  width: 72rpx;
+  height: 72rpx;
+  border-radius: 50%;
+}
+.family-avatar-text {
+  font-size: 28rpx;
+  color: $facade-text-body;
+}
+.family-avatar-wrap.family-avatar-add {
+  background: $facade-fill-warm-gray;
+  border: 2rpx dashed $facade-text-ghost;
+}
+.family-avatar-plus {
+  font-size: 36rpx;
+  color: $facade-text-muted;
+}
+.family-avatar-tag {
+  position: absolute;
+  bottom: -4rpx;
+  right: -4rpx;
+  font-size: 14rpx;
+  padding: 2rpx 6rpx;
+  border-radius: 8rpx;
+  color: $app-surface;
+}
+.family-avatar-tag.tag-parent { background: $dim-wisdom; }
+.family-avatar-tag.tag-child { background: $brand-primary; }
+.family-avatar-tag.tag-teacher { background: $dim-action; }
+.family-avatar-tag.tag-member { background: $c-text-gray-400; }
+.family-avatar-name {
+  font-size: 20rpx;
+  color: $facade-text-body;
+  white-space: nowrap;
+}
+
+/* 个人成就 */
+.achievement-section {
+  margin: 0 30rpx 20rpx;
+  background: $app-surface;
+  border-radius: 20rpx;
+  padding: 24rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+}
+.section-header-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: baseline;
+  margin-bottom: 16rpx;
+}
+.section-title {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: $facade-text-strong;
+}
+.section-sub {
+  font-size: 22rpx;
+  color: $facade-text-muted;
+}
+.achievement-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 0;
+}
+.ach-item {
+  width: 25%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 6rpx;
+  padding: 10rpx 0;
+}
+.ach-icon-wrap {
+  width: 64rpx;
+  height: 64rpx;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 4rpx;
+}
+.ach-icon {
+  font-size: 32rpx;
+  line-height: 1;
+}
+.ach-num {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: $facade-text-strong;
+  line-height: 1;
+}
+.ach-label {
+  font-size: 20rpx;
+  color: $facade-text-muted;
+  line-height: 1;
+}
+
+/* 我的订单(电商风格) */
+.order-section {
+  margin: 0 30rpx 20rpx;
+}
+.order-section-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 14rpx;
+}
+.order-all-link {
+  font-size: 24rpx;
+  color: $facade-text-muted;
+}
+.order-card {
+  background: $app-surface;
+  border-radius: 20rpx;
+  padding: 24rpx 12rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+}
+.order-grid {
+  display: flex;
+  flex-wrap: wrap;
+}
+.order-grid-item {
+  width: 20%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 10rpx;
+  padding: 8rpx 0;
+}
+.order-icon-wrap {
+  position: relative;
+  width: 64rpx;
+  height: 64rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.order-icon {
+  font-size: 40rpx;
+  line-height: 1;
+}
+.order-badge {
+  position: absolute;
+  top: -8rpx;
+  right: -14rpx;
+  min-width: 30rpx;
+  height: 30rpx;
+  line-height: 30rpx;
+  border-radius: 15rpx;
+  background: $status-danger-2;
+  color: $app-surface;
+  font-size: 18rpx;
+  text-align: center;
+  padding: 0 6rpx;
+}
+.order-grid-text {
+  font-size: 22rpx;
+  color: $facade-text-body;
+  line-height: 1;
+}
+.order-extra-row {
+  display: flex;
+  align-items: center;
+  margin-top: 20rpx;
+  padding-top: 20rpx;
+  border-top: 1rpx solid $c-fill-2b;
+}
+.order-extra-item {
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8rpx;
+}
+.order-extra-icon {
+  font-size: 28rpx;
+}
+.order-extra-text {
+  font-size: 24rpx;
+  color: $facade-text-strong;
+}
+.order-extra-badge {
+  min-width: 30rpx;
+  height: 30rpx;
+  line-height: 30rpx;
+  border-radius: 15rpx;
+  background: $brand-primary;
+  color: $app-surface;
+  font-size: 18rpx;
+  text-align: center;
+  padding: 0 6rpx;
+}
+.order-extra-divider {
+  width: 1rpx;
+  height: 30rpx;
+  background: $c-fill-2b;
+}
+
+/* 规划师服务中心入口 */
+.service-center-section {
+  margin: 0 30rpx 20rpx;
+}
+.service-center-card {
+  background: linear-gradient(135deg, $brand-primary 0%, $brand-primary-light 100%);
+  border-radius: 20rpx;
+  padding: 24rpx;
+  display: flex;
+  align-items: center;
+  gap: 20rpx;
+  box-shadow: 0 4rpx 16rpx rgba($brand-primary, 0.25);
+}
+.service-center-card.disabled-card {
+  background: linear-gradient(135deg, $uni-border-color-light, $app-text-subtle);
+  box-shadow: none;
+  opacity: 0.8;
+}
+.service-center-icon {
+  font-size: 48rpx;
+}
+.service-center-info {
+  flex: 1;
+}
+.service-center-title {
+  font-size: 30rpx;
+  font-weight: bold;
+  color: $app-surface;
+  display: block;
+}
+.service-center-desc {
+  font-size: 22rpx;
+  color: rgba($app-surface, 0.8);
+  margin-top: 6rpx;
+  display: block;
+}
+.service-center-card.disabled-card .service-center-title {
+  color: $app-surface;
+}
+.service-center-card.disabled-card .service-center-desc {
+  color: rgba($app-surface, 0.9);
+}
+.service-center-arrow {
+  font-size: 40rpx;
+  color: $app-surface;
+}
+
+/* 设置 + 退出 */
+.bottom-menu-section {
+  margin: 0 30rpx;
+  padding-bottom: 20rpx;
+}
+.menu-row {
+  width: 100%;
+  background: $app-surface;
+  border-radius: 16rpx;
+  padding: 24rpx;
+  display: flex;
+  align-items: center;
+  gap: 14rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
+  margin-bottom: 20rpx;
+}
+.menu-row-icon {
+  font-size: 30rpx;
+}
+.menu-row-text {
+  flex: 1;
+  font-size: 26rpx;
+  color: $facade-text-strong;
+}
+.menu-row-arrow {
+  font-size: 28rpx;
+  color: $facade-text-ghost;
+}
+.logout-btn {
+  width: 100%;
+  background: $app-surface;
+  border-radius: 16rpx;
+  padding: 24rpx;
+  text-align: center;
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04);
+}
+.logout-text {
+  font-size: 26rpx;
+  color: $status-danger-2;
+  font-weight: 500;
+}
+
+/* 分享推广码浮动按钮 */
+.share-qr-float {
+  position: fixed;
+  top: 180rpx;
+  right: 30rpx;
+  width: 80rpx;
+  height: 80rpx;
+  border-radius: 50%;
+  background: $app-surface;
+  box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.15);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 99;
+}
+/* 二维码图标(纯 CSS 绘制,不依赖 emoji 字体) */
+.qr-glyph {
+  position: relative;
+  width: 46rpx;
+  height: 46rpx;
+}
+.qr-eye {
+  position: absolute;
+  width: 16rpx;
+  height: 16rpx;
+  border: 4rpx solid $uni-text-color;
+  border-radius: 3rpx;
+  box-sizing: border-box;
+}
+.qr-eye-tl { left: 0; top: 0; }
+.qr-eye-tr { right: 0; top: 0; }
+.qr-eye-bl { left: 0; bottom: 0; }
+.qr-mid {
+  position: absolute;
+  left: 20rpx;
+  top: 20rpx;
+  width: 7rpx;
+  height: 7rpx;
+  background: $uni-text-color;
+  border-radius: 1rpx;
+}
+.qr-cluster {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  width: 18rpx;
+  display: flex;
+  flex-wrap: wrap;
+}
+.qr-pip {
+  width: 7rpx;
+  height: 7rpx;
+  margin: 1rpx;
+  background: $uni-text-color;
+  border-radius: 1rpx;
+}
+</style>

+ 42 - 0
cfc-frontend/scripts/d6-profile-vue.js

@@ -0,0 +1,42 @@
+#!/usr/bin/env node
+const fs = require('fs');
+const F = 'pages/profile-main/profile.vue';
+let src = fs.readFileSync(F, 'utf8');
+
+// defs 数组五维色 -> BrandColors 引用(brand-colors.js 已有 body/mind/wisdom/action/wealth)
+src = src.replace(
+  "{ key: 'body', label: '身', color: '#FF8C42' }",
+  "{ key: 'body', label: '身', color: BrandColors.body }"
+);
+src = src.replace(
+  "{ key: 'mind', label: '心', color: '#FF6B9D' }",
+  "{ key: 'mind', label: '心', color: BrandColors.mind }"
+);
+src = src.replace(
+  "{ key: 'wisdom', label: '智', color: '#6366F1' }",
+  "{ key: 'wisdom', label: '智', color: BrandColors.wisdom }"
+);
+src = src.replace(
+  "{ key: 'action', label: '行', color: '#10B981' }",
+  "{ key: 'action', label: '行', color: BrandColors.action }"
+);
+src = src.replace(
+  "{ key: 'wealth', label: '富', color: '#F59E0B' }",
+  "{ key: 'wealth', label: '富', color: BrandColors.wealth }"
+);
+
+fs.writeFileSync(F, src);
+console.log('defs mapped to BrandColors');
+
+// 统计剩余 hex
+const lines = src.split('\n');
+let n = 0;
+for (let i = 0; i < lines.length; i++) {
+  if (/#[0-9a-fA-F]{3,8}\b/.test(lines[i])) {
+    if (!/^\\s*\\$c-/.test(lines[i]) && !/BrandColors\./.test(lines[i])) {
+      console.log('REMAIN ' + (i + 1) + ': ' + lines[i].trim());
+      n++;
+    }
+  }
+}
+console.log('remaining non-palette, non-BrandColors:', n);

+ 44 - 0
cfc-frontend/scripts/d6b-profile-hoist.js

@@ -0,0 +1,44 @@
+#!/usr/bin/env node
+/**
+ * D6b: profile.vue palette hoist
+ * 局部变量 $c-wisdom-mid/$c-danger-ant/$c-pink/$c-pink-deep 均有全局等值令牌 ->
+ * 提升为全局引用(删声明 + 使用处替换),仅保留无令牌的 $c-fill-2b
+ */
+const fs = require('fs');
+const F = 'pages/profile-main/profile.vue';
+let lines = fs.readFileSync(F, 'utf8').split('\n');
+
+const HOIST = [
+  ['$c-wisdom-mid', '$dim-wisdom-deep', '#4F46E5'],
+  ['$c-danger-ant', '$status-danger-2', '#FF4D4F'],
+  ['$c-pink-deep', '$accent-pink-deep', '#DB2777'],
+  ['$c-pink', '$accent-pink', '#EC4899'],
+];
+
+let src = lines.join('\n');
+
+// 先删除这 4 行声明(含其 hex 定义)
+for (const [v] of HOIST) {
+  const re = new RegExp('^\\s*' + v.replace(/\$/g, '\\$') + '\\s*:[^\\n]*;[^\\n]*\\n', 'm');
+  if (!re.test(src)) { console.warn('DECL NOT FOUND:', v); }
+  src = src.replace(re, '');
+}
+
+// 再替换使用处(顺序:先 pink-deep 再 pink,避免前缀误伤)
+for (const [v, token] of HOIST) {
+  const re = new RegExp(v.replace(/\$/g, '\\$') + '(?![a-zA-Z0-9-])', 'g');
+  const before = src;
+  src = src.replace(re, token);
+  if (before === src) console.warn('USE NOT REPLACED:', v);
+}
+
+fs.writeFileSync(F, src);
+console.log('hoisted 4 vars to global tokens');
+
+// 校验剩余
+lines = src.split('\n');
+let n = 0;
+for (let i = 0; i < lines.length; i++) {
+  if (/#[0-9a-fA-F]{3,8}\b/.test(lines[i])) { console.log('HEX ' + (i + 1) + ': ' + lines[i].trim()); n++; }
+}
+console.log('remaining hex lines:', n);