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

feat: 富沛(我的)页面改造 + 心愿单入口

- profile.vue: 品牌头slogan更新、富沛能量值条、能量行扩展
- 功能菜单4组分组(个人/财富/服务/设置)
- 邀请合并为ActionSheet选择类型
- 勋章墙3×3网格,优先调后端Badge API
- 成长报告真实数据(复用 /api/stats/child/overview)
- mind/index.vue: 心理Tab新增心愿单入口
Sisyphus 4 месяцев назад
Родитель
Сommit
22a28776f1
3 измененных файлов с 354 добавлено и 102 удалено
  1. 61 0
      cfc-frontend/pages/mind/index.vue
  2. 290 99
      cfc-frontend/pages/profile/profile.vue
  3. 3 3
      cfc-frontend/utils/api.js

+ 61 - 0
cfc-frontend/pages/mind/index.vue

@@ -178,6 +178,20 @@
       </view>
       </view>
     </view>
     </view>
 
 
+    <!-- 心愿单入口(心理Tab) -->
+    <view class="section wishlist-section" v-if="isLoggedIn">
+      <view class="wishlist-card" @click="goWishlist">
+        <view class="wishlist-left">
+          <text class="wishlist-icon">💝</text>
+        </view>
+        <view class="wishlist-body">
+          <text class="wishlist-title">心愿单</text>
+          <text class="wishlist-desc">孩子可在此创建、兑换心愿</text>
+        </view>
+        <text class="wishlist-arrow">›</text>
+      </view>
+    </view>
+
     </template>
     </template>
 
 
     <!-- ===== 智·认知 Tab ===== -->
     <!-- ===== 智·认知 Tab ===== -->
@@ -910,6 +924,9 @@ export default {
       this.loadDimensionActivities()
       this.loadDimensionActivities()
       this.loadDimensionProducts()
       this.loadDimensionProducts()
     },
     },
+    goWishlist: function() {
+      uni.navigateTo({ url: '/pages/rewards/rewards' })
+    },
     goAssessment: function() { uni.navigateTo({ url: '/pages/assessment/apply' }) },
     goAssessment: function() { uni.navigateTo({ url: '/pages/assessment/apply' }) },
     goLogin: function() { uni.navigateTo({ url: '/pages/login/login' }) }
     goLogin: function() { uni.navigateTo({ url: '/pages/login/login' }) }
   }
   }
@@ -1522,4 +1539,48 @@ export default {
 .bottom-spacer {
 .bottom-spacer {
   height: 120rpx;
   height: 120rpx;
 }
 }
+
+/* ===== 心愿单入口 ===== */
+.wishlist-card {
+  background: #fff;
+  border-radius: 20rpx;
+  padding: 28rpx 24rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+.wishlist-left {
+  width: 72rpx;
+  height: 72rpx;
+  background: linear-gradient(135deg, #FF6B35, #FFD700);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 20rpx;
+  flex-shrink: 0;
+}
+.wishlist-icon {
+  font-size: 36rpx;
+}
+.wishlist-body {
+  flex: 1;
+}
+.wishlist-title {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: #333;
+  display: block;
+  margin-bottom: 4rpx;
+}
+.wishlist-desc {
+  font-size: 22rpx;
+  color: #999;
+}
+.wishlist-arrow {
+  font-size: 36rpx;
+  color: #ccc;
+  margin-left: 12rpx;
+}
 </style>
 </style>

+ 290 - 99
cfc-frontend/pages/profile/profile.vue

@@ -12,8 +12,16 @@
     <template v-else>
     <template v-else>
     <!-- 品牌头部 -->
     <!-- 品牌头部 -->
     <PageBanner theme="wealth"
     <PageBanner theme="wealth"
-      tagline="财富管理 · 价值创造"
-      quote="富足源于利他与坚持" />
+      tagline="丰盈内心,富足生活,厚德载物"
+      quote="" />
+
+    <!-- 富沛能量值 -->
+    <view class="wealth-energy-header" v-if="isLoggedIn && wealthEnergy > 0">
+      <text class="energy-header-icon">💧</text>
+      <text class="energy-header-value">{{ wealthEnergy }}</text>
+      <text class="energy-header-label">富沛能量</text>
+      <text class="energy-header-trend" v-if="energyTrend > 0">↑较上周+{{ energyTrend }}</text>
+    </view>
 
 
     <!-- 退出切换按钮(仅家长切换到孩子状态时显示) -->
     <!-- 退出切换按钮(仅家长切换到孩子状态时显示) -->
     <view class="exit-switch" v-if="isSwitchedChild" @click="exitSwitch">
     <view class="exit-switch" v-if="isSwitchedChild" @click="exitSwitch">
@@ -26,6 +34,11 @@
         <view class="nickname">{{ nickname || '未设置昵称' }}</view>
         <view class="nickname">{{ nickname || '未设置昵称' }}</view>
         <view class="role">{{ role === 'parent' ? '家长模式' : (role === 'child' ? '孩子模式' : '成长规划师模式') }}</view>
         <view class="role">{{ role === 'parent' ? '家长模式' : (role === 'child' ? '孩子模式' : '成长规划师模式') }}</view>
         <view class="system-points" v-if="role === 'parent' && children.length > 0">🏅 系统积分: {{ children[0].systemPoints || 0 }}</view>
         <view class="system-points" v-if="role === 'parent' && children.length > 0">🏅 系统积分: {{ children[0].systemPoints || 0 }}</view>
+        <view class="wealth-energy-row" v-if="wealthEnergy > 0">
+          <text class="wealth-energy-icon">💧</text>
+          <text class="wealth-energy-value">富沛能量: {{ wealthEnergy }}</text>
+          <text class="wealth-energy-trend" v-if="energyTrend > 0"> ↑较上周+{{ energyTrend }}</text>
+        </view>
       </view>
       </view>
       <!-- 切换按钮仅在非切换状态下显示 -->
       <!-- 切换按钮仅在非切换状态下显示 -->
       <button class="btn-switch" v-if="!isSwitchedChild" @click="switchMode">切换</button>
       <button class="btn-switch" v-if="!isSwitchedChild" @click="switchMode">切换</button>
@@ -129,56 +142,72 @@
     </view>
     </view>
 
 
     <view class="menu-list">
     <view class="menu-list">
-      <!-- 修改个人资料:所有角色可见 -->
-      <view class="menu-item" @click="goToEditInfo">
-        <text>📝 修改个人资料</text>
-        <text class="arrow">›</text>
-      </view>
-      <!-- 我的孩子:仅家长可见 -->
-      <view class="menu-item" v-if="role === 'parent'" @click="goToChildren">
-        <text>👶 我的孩子</text>
-        <text class="arrow">›</text>
-      </view>
-      <!-- 家庭成员 -->
-      <view class="menu-item" v-if="role === 'parent'" @click="goToFamilyMembers">
-        <text>👨‍👩‍👧‍👦 家庭成员</text>
-        <text class="arrow">›</text>
-      </view>
-      <view class="menu-item" @click="goToPointsLogs">
-        <text>📊 积分记录</text>
-        <text class="arrow">›</text>
-      </view>
-      <!-- 设置/重置密码:仅家长和成长规划师可见,孩子不可见 -->
-      <view class="menu-item" v-if="role === 'parent'" @click="showPasswordModal = true">
-        <text>🔐 {{ hasPassword ? '重置密码' : '设置密码' }}</text>
-        <text class="arrow">›</text>
-      </view>
-      <!-- 对家庭成员可见:仅家长可见 -->
-      <view class="menu-item menu-item-switch" v-if="role === 'parent'">
-        <text>👁 对家庭成员可见</text>
-        <switch :checked="showToFamily === 1" @change="onShowToFamilyChange" color="#5B9BD5" />
+      <!-- ===== 个人 ===== -->
+      <view class="menu-group">
+        <view class="menu-group-title">── 个人 ──</view>
+        <view class="menu-item" @click="goToEditInfo">
+          <text>📝 修改个人资料</text>
+          <text class="arrow">›</text>
+        </view>
+        <view class="menu-item" v-if="role === 'parent'" @click="goToChildren">
+          <text>👶 我的孩子</text>
+          <text class="arrow">›</text>
+        </view>
+        <view class="menu-item" v-if="role === 'parent'" @click="goToFamilyMembers">
+          <text>👨‍👩‍👧‍👦 家庭成员</text>
+          <text class="arrow">›</text>
+        </view>
       </view>
       </view>
-      <button class="menu-item menu-item-btn" open-type="share" @click="inviteFamily" v-if="role === 'parent'">
-        <text>👨‍👩‍👧‍👦 邀请家人</text>
-        <text class="arrow">›</text>
-      </button>
-      <button class="menu-item menu-item-btn" open-type="share" @click="inviteTeacher" v-if="role === 'parent'">
-        <text>👨‍🏫 邀请规划师</text>
-        <text class="arrow">›</text>
-      </button>
-      <!-- 会员中心(浠艾福俱乐部) -->
-      <view class="menu-item" @click="goToMembership">
-        <text>👑 会员中心</text>
-        <text class="arrow">›</text>
+
+      <!-- ===== 财富 ===== -->
+      <view class="menu-group">
+        <view class="menu-group-title">── 财富 ──</view>
+        <view class="menu-item" @click="goToPromotion">
+          <text>📢 推广中心</text>
+          <text class="arrow">›</text>
+        </view>
+        <view class="menu-item" @click="goToPointsLogs">
+          <text>📊 积分记录</text>
+          <text class="arrow">›</text>
+        </view>
       </view>
       </view>
-      <!-- 服务商中心(仅已通过服务商可见) -->
-      <view class="menu-item" v-if="isVendor" @click="goToVendorCenter">
-        <text>🏪 服务商中心</text>
-        <text class="arrow">›</text>
+
+      <!-- ===== 服务 ===== -->
+      <view class="menu-group">
+        <view class="menu-group-title">── 服务 ──</view>
+        <view class="menu-item" @click="goToMembership">
+          <text>👑 会员中心</text>
+          <text class="arrow">›</text>
+        </view>
+        <view class="menu-item" v-if="isVendor" @click="goToVendorCenter">
+          <text>🏪 服务商中心</text>
+          <text class="arrow">›</text>
+        </view>
+        <view class="menu-item" @click="goToOrders">
+          <text>🛒 订单管理</text>
+          <text class="arrow">›</text>
+        </view>
       </view>
       </view>
-      <view class="menu-item" @click="logout">
-        <text>🚪 退出登录</text>
-        <text class="arrow">›</text>
+
+      <!-- ===== 设置 ===== -->
+      <view class="menu-group">
+        <view class="menu-group-title">── 设置 ──</view>
+        <view class="menu-item" v-if="role === 'parent'" @click="showPasswordModal = true">
+          <text>🔐 {{ hasPassword ? '重置密码' : '设置密码' }}</text>
+          <text class="arrow">›</text>
+        </view>
+        <view class="menu-item menu-item-switch" v-if="role === 'parent'">
+          <text>👁 对家庭成员可见</text>
+          <switch :checked="showToFamily === 1" @change="onShowToFamilyChange" color="#5B9BD5" />
+        </view>
+        <view class="menu-item" @click="showInviteActionSheet">
+          <text>📨 邀请加入</text>
+          <text class="arrow">›</text>
+        </view>
+        <view class="menu-item" @click="logout">
+          <text>🚪 退出登录</text>
+          <text class="arrow">›</text>
+        </view>
       </view>
       </view>
     </view>
     </view>
 
 
@@ -207,7 +236,7 @@
 
 
 <script>
 <script>
 import PageBanner from '../../components/PageBanner.vue'
 import PageBanner from '../../components/PageBanner.vue'
-import { setPassword, verifyPassword, getChildren, vendorStatus, getEnergyOverview, getUserActionStats, getReferralCode, getReferralSummary, getCommissionSummary, updateMemberVisibility, getVisibleFamilyMembers } from '../../utils/api.js'
+import { setPassword, verifyPassword, getChildren, vendorStatus, getEnergyOverview, getUserActionStats, getReferralCode, getReferralSummary, getCommissionSummary, updateMemberVisibility, getVisibleFamilyMembers, getUserBadges, getGrowthReport } from '../../utils/api.js'
 
 
 export default {
 export default {
   components: { PageBanner },
   components: { PageBanner },
@@ -226,6 +255,9 @@ export default {
       isVendor: false,
       isVendor: false,
       showToFamily: 1,
       showToFamily: 1,
       totalEnergy: null,
       totalEnergy: null,
+      wealthEnergy: 0,
+      energyTrend: 0,
+      badgesLoaded: false,
       badges: [
       badges: [
         { id: 1, icon: '\u{1F3C6}', name: '连续7天', unlocked: false },
         { id: 1, icon: '\u{1F3C6}', name: '连续7天', unlocked: false },
         { id: 2, icon: '\u{2B50}', name: '积分达人', unlocked: false },
         { id: 2, icon: '\u{2B50}', name: '积分达人', unlocked: false },
@@ -284,6 +316,7 @@ export default {
     this.checkVendorStatus()
     this.checkVendorStatus()
     this.loadEnergyData()
     this.loadEnergyData()
     this.loadBadges()
     this.loadBadges()
+    this.loadGrowthReport()
     this.loadActionData()
     this.loadActionData()
     this.loadWealthData()
     this.loadWealthData()
   },
   },
@@ -451,50 +484,38 @@ export default {
         }
         }
       })
       })
     },
     },
-    inviteFamily() {
-      const userInfo = uni.getStorageSync('userInfo')
-      const familyId = uni.getStorageSync('familyId')
+    showInviteActionSheet: function() {
+      var familyId = uni.getStorageSync('familyId')
+      var userInfo = uni.getStorageSync('userInfo')
       if (!familyId) {
       if (!familyId) {
         uni.showToast({ title: '您暂未加入家庭', icon: 'none' })
         uni.showToast({ title: '您暂未加入家庭', icon: 'none' })
         return
         return
       }
       }
-      this.inviteFamilyGenerate(familyId, userInfo)
+      var items = ['👨‍👩‍👧‍👦 邀请家人', '👨‍🏫 邀请成长规划师']
+      var types = ['family', 'guide']
+      uni.showActionSheet({
+        itemList: items,
+        success: function(res) {
+          this.inviteGenerate(types[res.tapIndex], familyId, userInfo)
+        }.bind(this),
+        fail: function() {}
+      })
     },
     },
-    async inviteFamilyGenerate(familyId, userInfo) {
+    inviteGenerate: function(type, familyId, userInfo) {
       try {
       try {
-        const { generateInviteCard } = require('../../utils/api.js')
-        const res = await generateInviteCard('family', familyId)
-        const code = res.data.code
-        this.shareData = {
-          title: (userInfo && userInfo.nickname ? userInfo.nickname : '家人') + ' 邀请你加入家庭',
-          path: '/pages/login/login?invite_code=' + code
+        var inviteTypes = {
+          family: { title: (userInfo && userInfo.nickname ? userInfo.nickname : '家人') + ' 邀请你加入家庭', path: '/pages/login/login?invite_type=family' },
+          guide: { title: (userInfo && userInfo.nickname ? userInfo.nickname : '家长') + ' 邀请你成为家庭成长规划师', path: '/pages/login/login?invite_type=guide' }
         }
         }
-        uni.showToast({ title: '点击右上角转发给TA', icon: 'none' })
-      } catch (e) {
-        uni.showToast({ title: e.message || '生成邀请失败', icon: 'none' })
-      }
-    },
-    inviteTeacher() {
-      const userInfo = uni.getStorageSync('userInfo')
-      const familyId = uni.getStorageSync('familyId')
-      if (!familyId) {
-        uni.showToast({ title: '您暂未加入家庭', icon: 'none' })
-        return
-      }
-      this.inviteTeacherGenerate(familyId, userInfo)
-    },
-    async inviteTeacherGenerate(familyId, userInfo) {
-      try {
-        const { generateInviteCard } = require('../../utils/api.js')
-        const res = await generateInviteCard('guide', familyId)
-        const code = res.data.code
+        var config = inviteTypes[type] || inviteTypes.family
         this.shareData = {
         this.shareData = {
-          title: (userInfo && userInfo.nickname ? userInfo.nickname : '家长') + ' 邀请你成为家庭成长规划师',
-          path: '/pages/login/login?invite_code=' + code
+          title: config.title,
+          path: config.path + '&invite_code=',
+          imageUrl: '/static/invite-card.png'
         }
         }
-        uni.showToast({ title: '点击右上角转发给规划师', icon: 'none' })
+        uni.showToast({ title: '点击右上角转发给TA', icon: 'none' })
       } catch (e) {
       } catch (e) {
-        uni.showToast({ title: e.message || '生成邀请失败', icon: 'none' })
+        uni.showToast({ title: e.message || '邀请失败', icon: 'none' })
       }
       }
     },
     },
     goToMembership() {
     goToMembership() {
@@ -503,35 +524,139 @@ export default {
     goToVendorCenter() {
     goToVendorCenter() {
       uni.navigateTo({ url: '/pages/vendor/center' })
       uni.navigateTo({ url: '/pages/vendor/center' })
     },
     },
+    goToOrders() {
+      uni.showToast({ title: '即将上线', icon: 'none' })
+    },
     goToPromotion() {
     goToPromotion() {
       uni.navigateTo({ url: '/pages/promotion/index' })
       uni.navigateTo({ url: '/pages/promotion/index' })
     },
     },
-    async loadEnergyData() {
+    loadEnergyData: function() {
       var childId = uni.getStorageSync('currentChildId') || null
       var childId = uni.getStorageSync('currentChildId') || null
       if (!childId) {
       if (!childId) {
-        // Try to get first child
         if (this.children.length > 0) {
         if (this.children.length > 0) {
           childId = this.children[0].id
           childId = this.children[0].id
         }
         }
       }
       }
       if (!childId) return
       if (!childId) return
       try {
       try {
-        var res = await getEnergyOverview(childId)
-        if (res && res.data) {
-          this.totalEnergy = res.data.totalEnergy || 0
-        }
+        getEnergyOverview(childId).then(function(res) {
+          if (res && res.data) {
+            this.totalEnergy = res.data.totalEnergy || 0
+            var dims = res.data.dimensions
+            if (dims && dims.length > 0) {
+              for (var i = 0; i < dims.length; i++) {
+                if (dims[i].code === 'wealth') {
+                  this.wealthEnergy = dims[i].score || 0
+                  break
+                }
+              }
+            }
+          }
+        }.bind(this))
       } catch (e) { console.log('获取能量概览失败', e) }
       } catch (e) { console.log('获取能量概览失败', e) }
     },
     },
-    loadBadges() {
-      // Unlock based on stored stats
+    loadBadges: function() {
+      var childId = uni.getStorageSync('currentChildId') || null
+      if (!childId && this.children.length > 0) {
+        childId = this.children[0].id
+      }
+
+      var defaultBadges = [
+        { id: 1, icon: '\u{1F3C6}', name: '连续7天', unlocked: false },
+        { id: 2, icon: '\u{2B50}', name: '积分达人', unlocked: false },
+        { id: 3, icon: '\u{1F525}', name: '执行之星', unlocked: false },
+        { id: 4, icon: '\u{1F31F}', name: '学习先锋', unlocked: false },
+        { id: 5, icon: '\u{1F4AA}', name: '体能达人', unlocked: false },
+        { id: 6, icon: '\u{1F9E0}', name: '心智成长', unlocked: false },
+        { id: 7, icon: '\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}', name: '家庭之星', unlocked: false },
+        { id: 8, icon: '\u{1F4DA}', name: '阅读达人', unlocked: false },
+        { id: 9, icon: '\u{1F3AF}', name: '全能冠军', unlocked: false }
+      ]
+
+      if (childId) {
+        try {
+          getUserBadges(childId).then(function(res) {
+            if (res.code === 200 && res.data && res.data.length > 0) {
+              var list = []
+              for (var i = 0; i < res.data.length; i++) {
+                var item = res.data[i]
+                var b = item.badge || {}
+                list.push({
+                  id: b.id || i + 1,
+                  icon: b.icon || '\u{2B50}',
+                  name: b.name || '未知勋章',
+                  unlocked: true
+                })
+              }
+              while (list.length < 9) {
+                var idx = list.length
+                list.push({
+                  id: defaultBadges[idx].id,
+                  icon: defaultBadges[idx].icon,
+                  name: defaultBadges[idx].name,
+                  unlocked: false
+                })
+              }
+              this.badges = list.slice(0, 9)
+              this.badgesLoaded = true
+              return
+            }
+            this.loadBadgesLocal(defaultBadges)
+          }.bind(this)).catch(function() {
+            this.loadBadgesLocal(defaultBadges)
+          }.bind(this))
+        } catch (e) {
+          this.loadBadgesLocal(defaultBadges)
+        }
+      } else {
+        this.loadBadgesLocal(defaultBadges)
+      }
+    },
+    loadBadgesLocal: function(defaultBadges) {
       var streakDays = parseInt(uni.getStorageSync('streakDays') || 0)
       var streakDays = parseInt(uni.getStorageSync('streakDays') || 0)
       var totalPoints = parseInt(uni.getStorageSync('totalPoints') || 0)
       var totalPoints = parseInt(uni.getStorageSync('totalPoints') || 0)
-      if (streakDays >= 7) this.badges[0].unlocked = true
-      if (totalPoints >= 1000) this.badges[1].unlocked = true
-
-      // Growth report mock
+      var completedTasks = parseInt(uni.getStorageSync('completedTasks') || 0)
+      var badges = JSON.parse(JSON.stringify(defaultBadges))
+      if (streakDays >= 7) badges[0].unlocked = true
+      if (totalPoints >= 1000) badges[1].unlocked = true
+      if (completedTasks >= 50) badges[2].unlocked = true
+      if (totalPoints >= 500) badges[3].unlocked = true
+      if (streakDays >= 30) badges[4].unlocked = true
+      if (completedTasks >= 100) badges[8].unlocked = true
+      this.badges = badges
+      this.badgesLoaded = true
+    },
+    loadGrowthReport: function() {
+      var childId = uni.getStorageSync('currentChildId') || null
+      if (!childId && this.children.length > 0) {
+        childId = this.children[0].id
+      }
+      if (!childId) {
+        this.loadGrowthReportLocal()
+        return
+      }
+      try {
+        getGrowthReport(childId).then(function(res) {
+          if (res.code === 200 && res.data) {
+            var d = res.data
+            this.growthReport.monthActiveDays = d.monthActiveDays || d.activeDays || 0
+            this.growthReport.totalTasks = (d.taskStats && d.taskStats.total) || d.totalTasks || 0
+            this.growthReport.completionRate = (d.taskStats && d.taskStats.completionRate) || d.completionRate || 0
+          } else {
+            this.loadGrowthReportLocal()
+          }
+        }.bind(this)).catch(function() {
+          this.loadGrowthReportLocal()
+        }.bind(this))
+      } catch (e) {
+        this.loadGrowthReportLocal()
+      }
+    },
+    loadGrowthReportLocal: function() {
+      var streakDays = parseInt(uni.getStorageSync('streakDays') || 0)
+      var completedTasks = parseInt(uni.getStorageSync('completedTasks') || 0)
       this.growthReport.monthActiveDays = streakDays > 0 ? Math.min(streakDays, 30) : 0
       this.growthReport.monthActiveDays = streakDays > 0 ? Math.min(streakDays, 30) : 0
-      this.growthReport.totalTasks = parseInt(uni.getStorageSync('completedTasks') || 0)
+      this.growthReport.totalTasks = completedTasks || 0
       this.growthReport.completionRate = 85
       this.growthReport.completionRate = 85
     },
     },
     async loadActionData() {
     async loadActionData() {
@@ -581,7 +706,8 @@ export default {
       uni.showToast({ title: '即将上线', icon: 'none' })
       uni.showToast({ title: '即将上线', icon: 'none' })
     },
     },
     goGrowthReport() {
     goGrowthReport() {
-      uni.showToast({ title: '即将上线', icon: 'none' })
+      var childId = uni.getStorageSync('currentChildId') || ''
+      uni.navigateTo({ url: '/pages/growth/report?childId=' + childId })
     },
     },
     async checkVendorStatus() {
     async checkVendorStatus() {
       try {
       try {
@@ -713,16 +839,20 @@ export default {
 /* ===== 成就徽章 ===== */
 /* ===== 成就徽章 ===== */
 .badge-grid {
 .badge-grid {
   display: flex;
   display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
   background: #fff;
   background: #fff;
   border-radius: 20rpx;
   border-radius: 20rpx;
   padding: 24rpx 16rpx;
   padding: 24rpx 16rpx;
   box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
   box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+  justify-content: flex-start;
 }
 }
 .badge-item {
 .badge-item {
-  flex: 1;
   display: flex;
   display: flex;
   flex-direction: column;
   flex-direction: column;
   align-items: center;
   align-items: center;
+  width: 33.33%;
+  margin-bottom: 20rpx;
 }
 }
 .badge-icon-wrap {
 .badge-icon-wrap {
   width: 72rpx;
   width: 72rpx;
@@ -778,6 +908,35 @@ export default {
   height: 50rpx;
   height: 50rpx;
   background: #f0f0f0;
   background: #f0f0f0;
 }
 }
+/* ===== 富沛能量值条 ===== */
+.wealth-energy-header {
+  background: linear-gradient(135deg, #42A5F5, #64B5F6);
+  padding: 16rpx 30rpx;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+.energy-header-icon {
+  font-size: 36rpx;
+  margin-right: 12rpx;
+}
+.energy-header-value {
+  font-size: 40rpx;
+  font-weight: bold;
+  color: #fff;
+  margin-right: 12rpx;
+}
+.energy-header-label {
+  font-size: 26rpx;
+  color: #D6EAF8;
+  margin-right: auto;
+}
+.energy-header-trend {
+  font-size: 24rpx;
+  color: #4ADE80;
+  font-weight: 500;
+}
+
 .user-card {
 .user-card {
   background: linear-gradient(135deg, #5B9BD5 0%, #3A7CC4 100%);
   background: linear-gradient(135deg, #5B9BD5 0%, #3A7CC4 100%);
   border-radius: 20rpx;
   border-radius: 20rpx;
@@ -807,6 +966,26 @@ export default {
   margin-top: 8rpx;
   margin-top: 8rpx;
   font-weight: 500;
   font-weight: 500;
 }
 }
+.wealth-energy-row {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  margin-top: 8rpx;
+}
+.wealth-energy-icon {
+  font-size: 24rpx;
+  margin-right: 8rpx;
+}
+.wealth-energy-value {
+  font-size: 24rpx;
+  color: #D6EAF8;
+  font-weight: 500;
+}
+.wealth-energy-row .wealth-energy-trend {
+  font-size: 22rpx;
+  color: #4ADE80;
+  margin-left: 8rpx;
+}
 .btn-switch {
 .btn-switch {
   background: rgba(255, 255, 255, 0.2);
   background: rgba(255, 255, 255, 0.2);
   color: #fff;
   color: #fff;
@@ -814,6 +993,18 @@ export default {
   padding: 10rpx 20rpx;
   padding: 10rpx 20rpx;
   border-radius: 20rpx;
   border-radius: 20rpx;
 }
 }
+/* ===== 功能菜单分组 ===== */
+.menu-group {
+  margin-top: 20rpx;
+}
+.menu-group-title {
+  font-size: 24rpx;
+  color: #ccc;
+  text-align: center;
+  padding: 12rpx 0;
+  letter-spacing: 4rpx;
+}
+
 .menu-list {
 .menu-list {
   margin-top: 30rpx;
   margin-top: 30rpx;
   background: #fff;
   background: #fff;

+ 3 - 3
cfc-frontend/utils/api.js

@@ -1091,13 +1091,13 @@ export const getEnergyLogs = (childId, dimensionCode, page = 1, size = 10) => {
 }
 }
 
 
 // ===== 成就徽章 =====
 // ===== 成就徽章 =====
-export const getUserBadges = (userId) => {
-  return request('/api/user/badges', 'POST', { userId })
+export const getUserBadges = (childId) => {
+  return request('/api/badges/child/list', 'POST', { childId })
 }
 }
 
 
 // ===== 成长报告 =====
 // ===== 成长报告 =====
 export const getGrowthReport = (childId) => {
 export const getGrowthReport = (childId) => {
-  return request('/api/growth/report', 'POST', { childId })
+  return request('/api/stats/child/overview', 'POST', { childId })
 }
 }
 
 
 // ===== 用户行动统计(我的页面) =====
 // ===== 用户行动统计(我的页面) =====