Przeglądaj źródła

fix: member pricing display, wisdom/body page layout, :key expr in FamilyTianpanCard, remove FamilyRelationGraph

liaoxg 1 miesiąc temu
rodzic
commit
72f6e06930

+ 1 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/DanAssessmentController.java

@@ -359,6 +359,7 @@ public class DanAssessmentController {
         }
         List<DanAssessmentResult> list = danAssessmentResultMapper.selectList(
                 new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DanAssessmentResult>()
+                        .eq(DanAssessmentResult::getChildId, memberId)
                         .eq(DanAssessmentResult::getDimension, dimension)
                         .eq(DanAssessmentResult::getDraftStatus, "confirmed")
                         .orderByDesc(DanAssessmentResult::getCreatedAt));

+ 1 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/assessment/AssessmentResultController.java

@@ -39,7 +39,7 @@ public class AssessmentResultController {
 
         DanAssessmentResult result = cognitiveService.getChildLatestResult(childId);
         if (result == null) {
-            return Result.error("未找到测评结果");
+            return Result.success(null);
         }
 
         AssessmentResultDTO dto = new AssessmentResultDTO();

+ 1 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/assessment/CognitiveController.java

@@ -46,7 +46,7 @@ public class CognitiveController {
 
         DanAssessmentResult result = cognitiveService.getChildLatestResult(childId);
         if (result == null) {
-            return Result.error("未找到测评结果");
+            return Result.success(null);
         }
 
         Map<String, Object> scores = new LinkedHashMap<>();

+ 1 - 1
cfc-frontend/components/DimensionActivities.vue

@@ -241,7 +241,7 @@ export default {
   height: 160rpx;
 }
 
-.activity-swiper ::deep .swiper-slide {
+.activity-swiper .swiper-slide {
   width: 100%;
   height: 100%;
 }

+ 4 - 0
cfc-frontend/components/DimensionProducts.vue

@@ -51,6 +51,10 @@ export default {
     }
   },
   methods: {
+    formatPriceWithSymbol: function(price) {
+      if (price == null) return '免费'
+      return '¥' + (Number(price) / 100).toFixed(0)
+    },
     parseWeights: function(str) {
       if (!str) return []
       try {

+ 126 - 0
cfc-frontend/components/FamilyTianpanCard.vue

@@ -56,6 +56,38 @@
       </view>
     </view>
 
+    <!-- 传统文化信息(八字/五行/星座/灵数) -->
+    <view class="tp-traditional" v-if="traditionalData">
+      <!-- 八字四柱 -->
+      <view class="tp-trad-row" v-if="traditionalData.eightCharacters">
+        <view class="tp-trad-item" v-for="(val, key) in traditionalData.eightCharacters" :key="getBaziKey(key)">
+          <text class="tp-trad-label">{{ pillarLabels[key] || key }}</text>
+          <text class="tp-trad-value">{{ val }}</text>
+        </view>
+      </view>
+      <!-- 五行能量 -->
+      <view class="tp-trad-row" v-if="traditionalData.wuxingElements">
+        <view class="tp-trad-item" v-for="wx in wuxingData" :key="getWuxingKey(wx)">
+          <text class="tp-trad-label">{{ wx.label }}</text>
+          <view class="tp-trad-bar-track">
+            <view class="tp-trad-bar-fill" :style="{ width: wx.value + '%', background: wx.color }"></view>
+          </view>
+          <text class="tp-trad-val">{{ wx.value }}%</text>
+        </view>
+      </view>
+      <!-- 星座 + 灵数 -->
+      <view class="tp-trad-row tp-trad-row-split">
+        <view class="tp-trad-tag" v-if="traditionalData.zodiac">
+          <text class="tp-trad-tag-icon">&#x2600;</text>
+          <text class="tp-trad-tag-text">{{ traditionalData.zodiac }}</text>
+        </view>
+        <view class="tp-trad-tag" v-if="traditionalData.lifeNumber">
+          <text class="tp-trad-tag-icon">&#x1F52E;</text>
+          <text class="tp-trad-tag-text">灵数 {{ traditionalData.lifeNumber }}</text>
+        </view>
+      </view>
+    </view>
+
     <!-- 底部周报提示 -->
     <view class="tp-footer" v-if="weeklyTip">
       <text class="tp-footer-icon">&#x1F4A1;</text>
@@ -118,6 +150,10 @@ export default {
     visible: {
       type: Boolean,
       default: true
+    },
+    traditionalData: {
+      type: Object,
+      default: function() { return null }
     }
   },
   data: function() {
@@ -209,6 +245,27 @@ export default {
       } catch (e) {
         return false
       }
+    },
+    pillarLabels: function() {
+      return { year: '年柱', month: '月柱', day: '日柱', hour: '时柱' }
+    },
+    wuxingData: function() {
+      if (!this.traditionalData || !this.traditionalData.wuxingElements) return []
+      var colorMap = { wood: '#10B981', fire: '#FF6B9D', earth: '#FF8C42', metal: '#6366F1', water: '#3B82F6' }
+      var labelMap = { wood: '木', fire: '火', earth: '土', metal: '金', water: '水' }
+      var elements = this.traditionalData.wuxingElements
+      var result = []
+      for (var key in elements) {
+        if (elements.hasOwnProperty(key)) {
+          result.push({
+            key: key,
+            label: labelMap[key] || key,
+            value: elements[key] || 0,
+            color: colorMap[key] || '#94A3B8'
+          })
+        }
+      }
+      return result
     }
   },
   watch: {
@@ -235,6 +292,8 @@ export default {
     }
   },
   methods: {
+    getBaziKey: function(key) { return 'bazi-' + key },
+    getWuxingKey: function(wx) { return 'wx-' + wx.key },
     goDetail: function() {
       uni.navigateTo({
         url: '/pages/mind-detail/family-dashboard'
@@ -785,4 +844,71 @@ export default {
   color: var(--theme-color, #FF6B9D);
   font-weight: 600;
 }
+
+/* ===== 传统文化信息 ===== */
+.tp-traditional {
+  margin-top: 20rpx;
+  padding-top: 20rpx;
+  border-top: 1rpx solid var(--theme-border, rgba(255, 107, 157, 0.10));
+}
+.tp-trad-row {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  margin-bottom: 16rpx;
+}
+.tp-trad-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  flex: 1;
+  min-width: 120rpx;
+  margin-bottom: 8rpx;
+}
+.tp-trad-label {
+  font-size: 20rpx;
+  color: #94A3B8;
+  margin-bottom: 6rpx;
+}
+.tp-trad-value {
+  font-size: 26rpx;
+  font-weight: 600;
+  color: var(--theme-color, #FF6B9D);
+}
+.tp-trad-bar-track {
+  width: 80%;
+  height: 8rpx;
+  background: #E2E8F0;
+  border-radius: 4rpx;
+  overflow: hidden;
+  margin-bottom: 4rpx;
+}
+.tp-trad-bar-fill {
+  height: 100%;
+  border-radius: 4rpx;
+}
+.tp-trad-val {
+  font-size: 20rpx;
+  color: #64748B;
+}
+.tp-trad-row-split {
+  justify-content: space-around;
+}
+.tp-trad-tag {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  background: var(--theme-lighter, #FFF0F3);
+  padding: 8rpx 20rpx;
+  border-radius: 20rpx;
+}
+.tp-trad-tag-icon {
+  font-size: 24rpx;
+  margin-right: 8rpx;
+}
+.tp-trad-tag-text {
+  font-size: 24rpx;
+  font-weight: 600;
+  color: var(--theme-color, #FF6B9D);
+}
 </style>

+ 2 - 1
cfc-frontend/pages/article-center/index.vue

@@ -239,7 +239,8 @@ export default {
       this.page++
       this.loadArticles(true)
     },
-    goDetail(id) {
+    goDetail(idOrArticle) {
+      var id = idOrArticle && idOrArticle.id ? idOrArticle.id : idOrArticle
       uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id })
     },
     goEdit() {

+ 24 - 98
cfc-frontend/pages/body/index.vue

@@ -8,6 +8,28 @@
       tagline="科学管理全家健康"
       quote="身体健康是幸福的基础" />
 
+    <!-- 雷达图 -->
+    <view class="section" v-if="dimensionData">
+      <view class="section-header" v-if="dimensionData.isAverage">
+        <text class="section-title">七维健康图</text>
+        <text class="avg-badge">同龄同性平均值 · 上传报告后显示个人数据</text>
+      </view>
+      <view class="section-header" v-else>
+        <text class="section-title">七维健康图</text>
+      </view>
+      <RadarChart
+        v-if="radarDimensions && radarDimensions.length >= 3"
+        :dimensions="radarDimensions"
+        :scores="radarScores"
+        :avg-scores="radarAvgScores"
+        fillColor="#FF8C42"
+        gridColor="#FED7AA"
+        labelColor="#9A3412"
+        :width="580"
+        :height="580"
+        @dimensionClick="goDimensionDetail" />
+    </view>
+
     <!-- 家庭成员选择条 -->
     <FamilyMemberStrip
       v-if="isLoggedIn"
@@ -34,60 +56,6 @@
       :sandboxData="sandboxData"
       :dualDimension="dualDimension" />
 
-    <!-- 关系图谱(登录后可见) -->
-    <FamilyRelationGraph
-      v-if="isLoggedIn && familyMembersVisible.length > 0"
-      dimensionCode="body"
-      :selfId="activeChildId"
-      :members="familyMembersVisible"
-      :energyMap="energyMapForGraph"
-      :intimacyMap="intimacyMapForGraph"
-      @memberTap="goMemberDetail" />
-
-    <!-- 健康打卡卡片 -->
-    <HealthCheckinCard
-      v-if="isLoggedIn && activeChildId"
-      :childId="activeChildId" />
-
-    <!-- 家庭挑战任务 -->
-    <view class="section challenge-section" v-if="isLoggedIn && activeChallenges.length > 0">
-      <view class="section-header">
-        <text class="section-title">🔥 家庭挑战</text>
-      </view>
-      <FamilyChallengeCard
-        v-for="ch in activeChallenges"
-        :key="ch.id"
-        :challenge="ch" />
-    </view>
-
-      <!-- 雷达图 -->
-      <view class="section" v-if="dimensionData">
-        <view class="section-header" v-if="dimensionData.isAverage">
-          <text class="section-title">七维健康图</text>
-          <text class="avg-badge">同龄同性平均值 · 上传报告后显示个人数据</text>
-        </view>
-        <view class="section-header" v-else>
-          <text class="section-title">七维健康图</text>
-        </view>
-        <RadarChart
-          v-if="radarDimensions && radarDimensions.length >= 3"
-          :dimensions="radarDimensions"
-          :scores="radarScores"
-          :avg-scores="radarAvgScores"
-          fillColor="#FF8C42"
-          gridColor="#FED7AA"
-          labelColor="#9A3412"
-          :width="580"
-          :height="580"
-          @dimensionClick="goDimensionDetail" />
-    </view>
-
-    <!-- 七维健康全景(嵌入卡片) -->
-    <HealthDimensionsSection
-      v-if="isLoggedIn && dimensionData"
-      :healthData="dimensionData"
-      :activeChildId="activeChildId" />
-
     <!-- 功能入口 -->
     <view class="func-section" v-if="sectionVisible('func_entries')">
       <view class="func-grid">
@@ -174,18 +142,13 @@ import DimensionActivities from '../../components/DimensionActivities.vue'
 import DimensionProducts from '../../components/DimensionProducts.vue'
 import DimensionProductList from '../../components/DimensionProductList.vue'
 import DimensionArticles from '../../components/DimensionArticles.vue'
-import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
 import RadarChart from '../../components/RadarChart.vue'
-import HealthDimensionsSection from '../../components/HealthDimensionsSection.vue'
-import HealthCheckinCard from '../../components/HealthCheckinCard.vue'
 import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
 import FamilyMemberStrip from '../../components/FamilyMemberStrip.vue'
-import FamilyChallengeCard from '../../components/FamilyChallengeCard.vue'
-
-import { getVisibleSections, getEnergyOverview, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getVisibleFamilyMembers, getDimensionOverview, getFeaturedArticles, getChallengeList } from '../../utils/api.js'
+import { getVisibleSections, getEnergyOverview, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getVisibleFamilyMembers, getDimensionOverview, getFeaturedArticles } from '../../utils/api.js'
 
 export default {
-  components: { TabTransition, PageBanner, LoginGuideCard, FamilyEnergyBar, DimensionTasks, DimensionActivities, DimensionProducts, DimensionProductList, DimensionArticles, FamilyRelationGraph, RadarChart, HealthDimensionsSection, HealthCheckinCard, AIFloatingAvatar, FamilyMemberStrip, FamilyChallengeCard },
+  components: { TabTransition, PageBanner, LoginGuideCard, FamilyEnergyBar, DimensionTasks, DimensionActivities, DimensionProducts, DimensionProductList, DimensionArticles, RadarChart, AIFloatingAvatar, FamilyMemberStrip },
   data() {
     return {
       isLoggedIn: false,
@@ -206,7 +169,6 @@ export default {
       dimensionProducts: [],
       bodyArticles: [],
       dimensionData: null,
-      activeChallenges: [],
       /** Mock 平均值(7维):生长发育/睡眠质量/视力健康/免疫力/营养均衡/肠胃健康/运动活力 */
       radarAvgScores: [72, 68, 75, 70, 73, 69, 71],
       funcList: [
@@ -221,23 +183,6 @@ export default {
     }
   },
   computed: {
-    energyMapForGraph: function() {
-      var map = {}
-      if (this.sandboxData && this.sandboxData.members) {
-        for (var i = 0; i < this.sandboxData.members.length; i++) {
-          var m = this.sandboxData.members[i]
-          map[m.memberId || m.id] = {
-            bodyScore: m.bodyScore || 0,
-            mindScore: m.mindScore || 0,
-            actionScore: m.actionScore || 0
-          }
-        }
-      }
-      return map
-    },
-    intimacyMapForGraph: function() {
-      return {}
-    },
     /** 七维雷达图:维度标签(遵守 AGENTS.md 禁止模板内方法调用,使用 computed 缓存) */
     radarDimensions: function() {
       var dims = this.dimensionData && this.dimensionData.dimensions
@@ -278,7 +223,6 @@ export default {
     if (this.isLoggedIn) {
       this.loadChildren()
       this.loadFamilyMembersVisible()
-      this.loadChallenges()
     }
     // 游客也能浏览活动和商品
     this.loadDimensionActivities()
@@ -460,18 +404,6 @@ export default {
         self.familyMembersVisible = []
       })
     },
-    loadChallenges: function() {
-      var familyId = uni.getStorageSync('familyId')
-      if (!familyId) return
-      var self = this
-      getChallengeList({ familyId: familyId }).then(function(res) {
-        if (res.code === 200 && Array.isArray(res.data)) {
-          self.activeChallenges = res.data
-        }
-      }).catch(function() {
-        self.activeChallenges = []
-      })
-    },
     scrollToSection: function(section) {
       uni.pageScrollTo({ selector: '#' + section, duration: 300 })
     },
@@ -499,12 +431,6 @@ export default {
       uni.navigateTo({ url: '/pages/article-center/index?dimension=body' })
     },
     goTasks: function() { uni.switchTab({ url: '/pages/tasks/tasks' }) },
-    goMemberDetail: function(member) {
-      if (!member || !member.memberId) return
-      uni.navigateTo({
-        url: '/pages/member-detail/member-detail?memberId=' + member.memberId + '&memberType=' + (member.memberType || 'child') + '&entrySource=relation-graph&dimensionCode=body'
-      })
-    },
     goFamilyMembers: function() {
       uni.navigateTo({ url: '/pages/profile/family-members' })
     },

+ 29 - 3
cfc-frontend/pages/home-pages/child-index.vue

@@ -53,6 +53,13 @@
   dimensionCode="child"
   :sandboxData="sandboxData" />
 
+<!-- 家庭成员选择条 -->
+<FamilyMemberStrip
+  v-if="hasChildren && familyMembersVisible.length > 0"
+  :members="familyMembersVisible"
+  :selectedMemberId="selectedMemberId"
+  @select="onFamilyMemberSelect" />
+
 <!-- 连续打卡徽章 -->
 <view
 class="streak-badge-wrap animate-slide-up animate-stagger-3"
@@ -297,7 +304,7 @@ B) 积分卡片 — Claymorphism 暖橙黏土风格
 </template>
 
 <script>
-import { getChildren, getTodayTasks, getEnergyOverview, getEnergyLogs, getActivityList, getProductsByDomain, getFamilyEnergySandbox } from '../../utils/api.js'
+import { getChildren, getTodayTasks, getEnergyOverview, getEnergyLogs, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getVisibleFamilyMembers } from '../../utils/api.js'
 import PageBanner from '../../components/PageBanner.vue'
 import FamilyEnergyBar from '../../components/FamilyEnergyBar.vue'
 import WuxingSandbox from '../../components/wuxing-sandbox.vue'
@@ -309,6 +316,7 @@ import BaseEmpty from '../../components/BaseEmpty.vue'
 import BaseLoading from '../../components/BaseLoading.vue'
 import OnboardingGuide from '../../components/OnboardingGuide.vue'
 import ConfettiCelebration from '../../components/ConfettiCelebration.vue'
+import FamilyMemberStrip from '../../components/FamilyMemberStrip.vue'
 
 /**
  * 等级配置表
@@ -346,7 +354,8 @@ export default {
     BaseEmpty,
     BaseLoading,
     OnboardingGuide,
-    ConfettiCelebration
+    ConfettiCelebration,
+    FamilyMemberStrip
   },
   data() {
     return {
@@ -374,7 +383,9 @@ export default {
       energyLogs: [],
       sandboxData: null,
       dimensionActivities: [],
-      dimensionProducts: []
+      dimensionProducts: [],
+      familyMembersVisible: [],
+      selectedMemberId: null
     }
   },
   computed: {
@@ -479,6 +490,18 @@ export default {
     this._mounted = true
   },
   methods: {
+    onFamilyMemberSelect(member) {
+      this.selectedMemberId = member.id
+    },
+    loadFamilyMembersVisible() {
+      var self = this
+      getVisibleFamilyMembers().then(function(res) {
+        self.familyMembersVisible = res.data || []
+      }).catch(function(e) {
+        console.log('获取可见家庭成员失败', e)
+        self.familyMembersVisible = []
+      })
+    },
     // ======================== 数据加载 ========================
     async loadData() {
       this.loading = true
@@ -583,6 +606,9 @@ export default {
           }
         }
 
+        // 加载家庭成员
+        this.loadFamilyMembersVisible()
+
         // 加载维度活动
         try {
           var actRes = await getActivityList({ dimensionCode: 'child', page: 1, size: 3 })

+ 2 - 2
cfc-frontend/pages/home-pages/parent-index.vue

@@ -304,11 +304,11 @@
           </view>
           <view class="qr-code-modal-body">
             <view class="qr-code-image-container">
-              <image :src="qrCodeData?.qrCodeBase64 || ''" class="qr-code-image" mode="aspectFit" />
+              <image :src="(qrCodeData && qrCodeData.qrCodeBase64) || ''" class="qr-code-image" mode="aspectFit" />
             </view>
             <view class="qr-code-referral-code">
               <text class="qr-code-label">邀请码:</text>
-              <text class="qr-code-code">{{ qrCodeData?.referralCode || '' }}</text>
+              <text class="qr-code-code">{{ (qrCodeData && qrCodeData.referralCode) || '' }}</text>
               <text class="qr-code-copy" @click="onCopyReferralCode">复制</text>
             </view>
           </view>

+ 6 - 21
cfc-frontend/pages/index-home/index.vue

@@ -68,7 +68,6 @@
     <FamilyMemberStrip
       :members="familyMembersVisible"
       :selectedMemberId="selectedMemberId"
-      :energyMap="energyMapForGraph"
       @select="onFamilyMemberSelect" />
 
     <!-- 五维能量条 -->
@@ -79,7 +78,7 @@
       :dualDimension="dualDimension" />
 
     <!-- 家庭挑战任务 -->
-    <view class="section challenge-section" v-if="isLoggedIn && activeChallenges.length > 0">
+    <view class="section challenge-section" v-if="isLoggedIn() && activeChallenges.length > 0">
       <view class="section-header">
         <text class="section-title">🔥 家庭挑战</text>
       </view>
@@ -118,7 +117,7 @@
       @moreProducts="goMoreProducts" />
 
     <!-- ===== 我的圈子 ===== -->
-    <view class="circle-section" v-if="isLoggedIn">
+    <view class="circle-section" v-if="isLoggedIn()">
       <view class="circle-header">
         <text class="circle-section-title">🤝 我的圈子</text>
         <text class="circle-header-link" @click="goDiscoverCircles">发现更多 ›</text>
@@ -458,17 +457,6 @@ export default {
         wealth: d.wealthScore || 0
       }
     },
-    energyMapForGraph: function() {
-      var map = {}
-      var members = this.sandboxData && this.sandboxData.members || []
-      for (var i = 0; i < members.length; i++) {
-        var m = members[i]
-        if (m.memberId && m.actionScore !== undefined) {
-          map[m.memberId] = m.actionScore
-        }
-      }
-      return map
-    },
     actionArticles: function() {
       if (!this.articles || this.articles.length === 0) return []
       var result = []
@@ -680,9 +668,9 @@ export default {
     },
     loadDiscoverCircles: function() {
       var self = this
-      discoverCircles({ page: 1, size: 3 }).then(function(res) {
+      discoverCircles(this.currentChildId).then(function(res) {
         if (res.code === 200 && res.data) {
-          self.discoverCirclesList = Array.isArray(res.data) ? res.data : (res.data.list || [])
+          self.discoverCirclesList = Array.isArray(res.data) ? res.data.slice(0, 3) : []
         }
       }).catch(function() { self.discoverCirclesList = [] })
     },
@@ -749,10 +737,6 @@ export default {
     goTasks: function() {
       uni.switchTab({ url: '/pages/tasks/tasks' })
     },
-    goMemberDetail: function(member) {
-      if (!member || !member.memberId) return
-      uni.navigateTo({ url: '/pages/child/child-detail?id=' + member.memberId })
-    },
     goActivityDetail: function(act) {
       if (!act || !act.id) return
       uni.navigateTo({ url: '/pages/discover-detail/activity-detail/activity-detail?id=' + act.id })
@@ -939,7 +923,8 @@ export default {
     goArticles: function() {
       uni.navigateTo({ url: '/pages/mind-detail/articles' })
     },
-    goArticleDetail: function(id) {
+    goArticleDetail: function(article) {
+      var id = article && article.id ? article.id : article
       uni.navigateTo({ url: '/pages/mind-detail/article-detail?id=' + id })
     },
     onTypeChange(value) {

+ 10 - 247
cfc-frontend/pages/mind/index.vue

@@ -8,19 +8,6 @@
       tagline="心智成长 · 智慧人生"
       quote="知己知彼,百战不殆" />
 
-    <!-- 家庭成员选择条 -->
-    <FamilyMemberStrip
-      v-if="isLoggedIn"
-      :members="familyMembersVisible"
-      :selectedMemberId="selectedMemberId"
-      @select="onFamilyMemberSelect" />
-
-    <!-- ===== 心·心理 ===== -->
-    <view class="section-title-bar">
-      <text class="section-title-icon">&#x2764;</text>
-      <text class="section-title-text">心·心理</text>
-    </view>
-
     <!-- ===== 家庭天盘模块(今日运势 / 今日心情 / 吉位) ===== -->
     <FamilyTianpanCard
       v-if="isLoggedIn"
@@ -28,7 +15,15 @@
       :fortune="dailyFortune"
       :mood="todayMood"
       :dominantElement="dominantElement"
-      :weeklyTip="familyWeeklyInsight" />
+      :weeklyTip="familyWeeklyInsight"
+      :traditionalData="traditionalData" />
+
+    <!-- 家庭成员选择条 -->
+    <FamilyMemberStrip
+      v-if="isLoggedIn"
+      :members="familyMembersVisible"
+      :selectedMemberId="selectedMemberId"
+      @select="onFamilyMemberSelect" />
 
     <!-- 游客登录引导卡 -->
     <template v-if="!isLoggedIn">
@@ -80,70 +75,6 @@
             <text class="emi-footer-icon">&#x2192;</text>
           </view>
         </view>
-        <!-- 关系图谱(登录后可见) -->
-        <FamilyRelationGraph
-      v-if="isLoggedIn && familyMembersVisible.length > 0"
-      dimensionCode="mind"
-      :selfId="activeChildId"
-      :members="familyMembersVisible"
-      :energyMap="energyMapForGraph"
-      :intimacyMap="intimacyMapForGraph"
-      :compatibilityMap="compatibilityMapForGraph"
-      @memberTap="goMemberDetail" />
-
-    <!-- ===== 心理能量概况 ===== -->
-    <view class="energy-overview" v-if="emiData">
-      <view class="energy-badge">
-        <text class="badge-icon">&#x2764;</text>
-        <text class="badge-value">{{ emiData.overallScore || 0 }}</text>
-        <text class="badge-label">心能量</text>
-      </view>
-      <view class="energy-badge">
-        <text class="badge-icon">&#x1F4AA;</text>
-        <text class="badge-value">{{ emiData.resilienceScore || 0 }}</text>
-        <text class="badge-label">韧性评分</text>
-      </view>
-      <view class="energy-badge">
-        <text class="badge-icon">&#x1F64F;</text>
-        <text class="badge-value">{{ emiData.emotionScore || 0 }}</text>
-        <text class="badge-label">情绪评分</text>
-      </view>
-    </view>
-
-    <!-- ===== 心理报告上传 ===== -->
-    <view class="mind-report-section" v-if="isLoggedIn">
-      <!-- 上传报告入口卡(参照身页面卡片风格) -->
-      <view class="mind-report-card" @click="chooseAndUploadReport">
-        <view class="mind-report-left">
-          <text class="mind-report-icon">&#x1F4CB;</text>
-        </view>
-        <view class="mind-report-right">
-          <text class="mind-report-title">上传心理报告</text>
-          <text class="mind-report-desc">上传 EMI 心理测评报告或第三方心理评估报告,AI 智能解析生成可视化分析</text>
-          <view class="mind-report-tags">
-            <text class="mind-tag">EMI 测评</text>
-            <text class="mind-tag">AI 解析</text>
-            <text class="mind-tag">可视化</text>
-          </view>
-        </view>
-        <text class="mind-report-arrow">&#x203A;</text>
-      </view>
-      <!-- 已上传报告列表 -->
-      <view class="mind-report-list" v-if="uploadedReports && uploadedReports.length > 0">
-        <view class="mind-report-item" v-for="report in uploadedReports" :key="report.id" @click="viewReport(report)">
-          <text class="mind-report-item-icon">&#x1F4C4;</text>
-          <text class="mind-report-item-name">{{ report.fileName || '心理报告' }}</text>
-          <text class="mind-report-item-date">{{ formatDate(report.createdAt) }}</text>
-          <text :class="['mind-report-item-status', report.status === 'parsed' ? 'parsed' : 'pending']">
-            {{ report.status === 'parsed' ? '已解析' : '待解析' }}
-          </text>
-        </view>
-      </view>
-      <view class="mind-report-empty" v-else-if="!reportUploadLoading">
-        <text class="mind-report-empty-icon">&#x1F4C1;</text>
-        <text class="mind-report-empty-text">暂无上传的报告,点击上方卡片上传</text>
-      </view>
-    </view>
 
     <!-- 肠脑轴情绪卡片 -->
     <view class="section" v-if="gutIndicators && gutIndicators.length > 0">
@@ -175,137 +106,6 @@
       @articleClick="goArticleDetail"
       @moreArticles="goArticles" />
 
-    <!-- ===== 传统文化(八字/五行/星座/灵数) ===== -->
-    <view class="culture-section" v-if="isLoggedIn && traditionalData">
-      <!-- 八字四柱 -->
-      <view class="culture-card" v-if="traditionalData.eightCharacters">
-        <view class="culture-card-header">
-          <text class="culture-card-icon">&#x2637;</text>
-          <text class="culture-card-title">八字四柱</text>
-        </view>
-        <view class="bazi-grid">
-          <view class="bazi-column" v-for="(val, key) in traditionalData.eightCharacters" :key="key">
-            <text class="bazi-pillar-label">{{ pillarLabels[key] || key }}</text>
-            <text class="bazi-pillar-value">{{ val }}</text>
-          </view>
-        </view>
-      </view>
-
-      <!-- 五行能量 -->
-      <view class="culture-card" v-if="traditionalData.wuxingElements">
-        <view class="culture-card-header">
-          <text class="culture-card-icon">&#x267E;</text>
-          <text class="culture-card-title">五行能量</text>
-        </view>
-        <view class="wuxing-list">
-          <view class="wuxing-item" v-for="wx in wuxingData" :key="wx.key">
-            <text class="wuxing-label">{{ wx.label }}</text>
-            <view class="wuxing-bar-track">
-              <view class="wuxing-bar-fill" :style="{ width: wx.value + '%', background: wx.color }"></view>
-            </view>
-            <text class="wuxing-value">{{ wx.value }}%</text>
-          </view>
-        </view>
-        <view class="energy-card" v-if="traditionalData.wuxingReading">
-          <view class="energy-header">
-            <text class="energy-icon">&#x2728;</text>
-            <text class="energy-label">今日能量文</text>
-          </view>
-          <view class="energy-divider"></view>
-          <text class="energy-quote">{{ traditionalData.wuxingReading.personalTrait || '' }}</text>
-          <text class="energy-advice" v-if="traditionalData.wuxingReading.mindGrowthAdvice">{{ traditionalData.wuxingReading.mindGrowthAdvice }}</text>
-          <view class="energy-footer">
-            <text class="energy-footer-dot"></text>
-            <text class="energy-footer-dot"></text>
-            <text class="energy-footer-dot"></text>
-          </view>
-        </view>
-      </view>
-
-      <!-- 太阳星座 + 生命灵数 双栏 -->
-      <view class="culture-dual">
-        <view class="culture-dual-item" v-if="traditionalData.zodiac">
-          <text class="culture-dual-icon">&#x2600;</text>
-          <text class="culture-dual-label">太阳星座</text>
-          <text class="culture-dual-value">{{ traditionalData.zodiac }}</text>
-        </view>
-        <view class="culture-dual-item" v-if="traditionalData.numSoul">
-          <text class="culture-dual-icon">&#x1F52E;</text>
-          <text class="culture-dual-label">生命灵数</text>
-          <text class="culture-dual-value">{{ traditionalData.lifeNumber || '' }}</text>
-        </view>
-      </view>
-
-      <!-- 关键信息(家庭 + 个人) -->
-      <view class="key-info-card" v-if="compatibilityData || traditionalData">
-        <view class="key-info-header">
-          <text class="key-info-icon">&#x1F511;</text>
-          <text class="key-info-title">关键信息</text>
-        </view>
-        <view class="key-info-body">
-          <!-- 左侧:家庭概览 -->
-          <view class="key-info-col" v-if="compatibilityData">
-            <view class="ki-subtitle">家庭</view>
-            <view class="ki-row" v-if="familyWuxingLabel">
-              <text class="ki-label">主导五行</text>
-              <view class="ki-dot" :style="'background:' + familyWuxingLabel.color"></view>
-              <text class="ki-valued">{{ familyWuxingLabel.label }} {{ familyWuxingLabel.value }}%</text>
-            </view>
-            <view class="ki-row">
-              <text class="ki-label">成员</text>
-              <text class="ki-valued">{{ familyMemberCount }}人</text>
-            </view>
-          </view>
-          <!-- 右侧:个人速览 -->
-          <view class="key-info-col" v-if="traditionalData">
-            <view class="ki-subtitle">个人</view>
-            <view class="ki-row" v-if="luckyColorInfo">
-              <text class="ki-label">幸运色</text>
-              <view class="ki-swatch" :style="'background:' + luckyColorInfo.hex"></view>
-              <text class="ki-valued">{{ luckyColorInfo.name }}</text>
-            </view>
-            <view class="ki-row" v-if="luckyNumber">
-              <text class="ki-label">幸运数</text>
-              <text class="ki-num">{{ luckyNumber }}</text>
-            </view>
-            <view class="ki-row" v-if="dailyFortune">
-              <text class="ki-label">运势</text>
-              <text class="ki-fortune" :class="'ki-fortune-' + dailyFortune.level">{{ dailyFortune.text }}</text>
-            </view>
-          </view>
-        </view>
-        <!-- 本周提示 -->
-        <view class="ki-insight" v-if="familyWeeklyInsight">
-          <text class="ki-insight-icon">&#x1F4A1;</text>
-          <text class="ki-insight-text">{{ familyWeeklyInsight }}</text>
-        </view>
-        <!-- 查看详情 -->
-        <view class="ki-footer" @click="onFuncClick({needLogin:true, page:'/pages/mind-detail/family-dashboard'})">
-          <text>查看家庭天盘详细 &#x2192;</text>
-        </view>
-      </view>
-    </view>
-
-    <!-- ===== DAN 报告(A2-心维度) ===== -->
-    <view class="section" v-if="isLoggedIn && danReports.length > 0">
-      <view class="section-header">
-        <text class="section-title">&#x1F4CA; DAN 报告</text>
-        <text class="section-more" @click="goDanUpload('mind')">上传 +</text>
-      </view>
-      <view class="dan-card" v-for="report in danReports" :key="report.id">
-        <view class="dan-card-header">
-          <text class="dan-report-date">{{ formatDate(report.assessmentDate) }}</text>
-          <text :class="['dan-status', report.draftStatus === 'confirmed' ? 'confirmed' : 'pending']">
-            {{ report.draftStatus === 'confirmed' ? '已确认' : '待确认' }}
-          </text>
-        </view>
-        <text class="dan-report-desc">DAN A2 心维度测评报告</text>
-        <view class="dan-card-footer" @click="viewDanReport(report)">
-          <text class="dan-view-link">查看详情 &rarr;</text>
-        </view>
-      </view>
-    </view>
-
     <!-- ===== 底部:维度任务/活动/商品 ===== -->
     <DimensionTasks
       v-if="isLoggedIn"
@@ -368,8 +168,6 @@ import DimensionTasks from '../../components/DimensionTasks.vue'
 import DimensionActivities from '../../components/DimensionActivities.vue'
 import DimensionProducts from '../../components/DimensionProducts.vue'
 import DimensionArticles from '../../components/DimensionArticles.vue'
-import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
-
 import PsychCrisisBanner from '../../components/PsychCrisisBanner.vue'
 import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
 import FamilyTianpanCard from '../../components/FamilyTianpanCard.vue'
@@ -378,7 +176,7 @@ import { getVisibleSections, getFeaturedArticles, getEmiReport, getFamilyEnergyS
 import config from '../../config.js'
 
 export default {
-  components: { TabTransition, PageBanner, RadarChart, LoginGuideCard, FamilyEnergyBar, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, FamilyRelationGraph, PsychCrisisBanner, AIFloatingAvatar, FamilyTianpanCard, FamilyMemberStrip },
+  components: { TabTransition, PageBanner, RadarChart, LoginGuideCard, FamilyEnergyBar, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, PsychCrisisBanner, AIFloatingAvatar, FamilyTianpanCard, FamilyMemberStrip },
   data() {
     return {
       isLoggedIn: false,
@@ -476,34 +274,6 @@ export default {
         this.emiData.neuroticismScore || 0
       ]
     },
-    energyMapForGraph: function() {
-      var map = {}
-      if (this.sandboxData && this.sandboxData.members) {
-        for (var i = 0; i < this.sandboxData.members.length; i++) {
-          var m = this.sandboxData.members[i]
-          map[m.memberId || m.id] = {
-            bodyScore: m.bodyScore || 0,
-            mindScore: m.mindScore || 0,
-            actionScore: m.actionScore || 0
-          }
-        }
-      }
-      return map
-    },
-    intimacyMapForGraph: function() {
-      return {}
-    },
-    compatibilityMapForGraph: function() {
-      var map = {}
-      if (this.compatibilityData && this.compatibilityData.relationships) {
-        for (var i = 0; i < this.compatibilityData.relationships.length; i++) {
-          var r = this.compatibilityData.relationships[i]
-          var key = r.memberId1 < r.memberId2 ? r.memberId1 + '-' + r.memberId2 : r.memberId2 + '-' + r.memberId1
-          map[key] = { overallScore: r.overallScore }
-        }
-      }
-      return map
-    },
     emotionArticles: function() {
       if (!this.articles || this.articles.length === 0) return []
       var result = []
@@ -1119,13 +889,6 @@ export default {
       uni.navigateTo({ url: '/pages/shop/index' })
     },
     goTasks: function() { uni.switchTab({ url: '/pages/tasks/tasks' }) },
-    goMemberDetail: function(member) {
-      if (!member || !member.memberId) return
-      var currentId = this.currentChildId
-      uni.navigateTo({
-        url: '/pages/member-detail/member-detail?memberId=' + member.memberId + '&entrySource=relation-graph&selfId=' + currentId + '&dimensionCode=mind'
-      })
-    },
     goFamilyMembers: function() {
       uni.navigateTo({ url: '/pages/profile-extra/family-members' })
     },

+ 64 - 3
cfc-frontend/pages/wealth/index.vue

@@ -17,6 +17,13 @@
         tagline="利他创富 · 价值共享"
         quote="富足源于利他与坚持" />
 
+      <!-- 家庭成员选择条 -->
+      <FamilyMemberStrip
+        v-if="isLoggedIn"
+        :members="familyMembersVisible"
+        :selectedMemberId="selectedMemberId"
+        @select="onFamilyMemberSelect" />
+
       <!-- 模式切换 / 退出切换入口(家长未切时显示"切换到孩子视角";已切时显示"退出切换") -->
  <!-- 已切孩子态:点击"退出切换"回到家长模式 -->
  <view v-if="isSwitchedChild" class="exit-switch" @click="exitSwitch">
@@ -127,6 +134,31 @@
         </view>
       </view>
 
+      <!-- 消费中心 -->
+      <view class="section">
+        <view class="section-header">
+          <text class="section-title">🛍️ 消费中心</text>
+        </view>
+        <view class="service-grid">
+          <view class="service-item" @click="goToShop">
+            <text class="service-icon">🏪</text>
+            <text class="service-label">商城首页</text>
+          </view>
+          <view class="service-item" @click="goToCart">
+            <text class="service-icon">🛒</text>
+            <text class="service-label">购物车</text>
+          </view>
+          <view class="service-item" @click="goToOrders">
+            <text class="service-icon">📋</text>
+            <text class="service-label">我的订单</text>
+          </view>
+          <view class="service-item" @click="goToAfterSales">
+            <text class="service-icon">🔄</text>
+            <text class="service-label">售后服务</text>
+          </view>
+        </view>
+      </view>
+
       <!-- 商品推荐 -->
       <DimensionProductList
         v-if="isLoggedIn"
@@ -163,17 +195,19 @@ import PageBanner from '../../components/PageBanner.vue'
 import DimensionProductList from '../../components/DimensionProductList.vue'
 import WealthSubScores from '../../components/WealthSubScores.vue'
 import BodyWealthAlert from '../../components/BodyWealthAlert.vue'
+import FamilyMemberStrip from '../../components/FamilyMemberStrip.vue'
 import {
   verifyPassword,
   getChildren,
   getWealthDetail,
   getReferralCode,
   getReferralSummary,
-  getCommissionSummary
+  getCommissionSummary,
+  getVisibleFamilyMembers
 } from '../../utils/api.js'
 
 export default {
-  components: { TabTransition, PageBanner, DimensionProductList, WealthSubScores, BodyWealthAlert },
+  components: { TabTransition, PageBanner, DimensionProductList, WealthSubScores, BodyWealthAlert, FamilyMemberStrip },
   data() {
     return {
       showTabTransition: true,
@@ -209,7 +243,9 @@ export default {
         referralCount: 0,
         referralCode: ''
       },
-      children: []
+      children: [],
+      familyMembersVisible: [],
+      selectedMemberId: null
     }
   },
   computed: {
@@ -245,9 +281,22 @@ export default {
     this.loadChildren()
     this.loadWealthDetail()
     this.loadWealthData()
+    this.loadFamilyMembersVisible()
     this._watchPageReady()
   },
   methods: {
+    onFamilyMemberSelect(member) {
+      this.selectedMemberId = member.id
+    },
+    loadFamilyMembersVisible() {
+      var self = this
+      getVisibleFamilyMembers().then(function(res) {
+        self.familyMembersVisible = res.data || []
+      }).catch(function(e) {
+        console.log('获取可见家庭成员失败', e)
+        self.familyMembersVisible = []
+      })
+    },
     goLogin() {
       uni.navigateTo({ url: '/pages/login/login' })
     },
@@ -445,6 +494,18 @@ export default {
     goToPromotion() {
       uni.navigateTo({ url: '/pages/promotion/index' })
     },
+    goToShop() {
+      uni.navigateTo({ url: '/pages/shop/index/index' })
+    },
+    goToCart() {
+      uni.navigateTo({ url: '/pages/shop/cart/cart' })
+    },
+    goToOrders() {
+      uni.navigateTo({ url: '/pages/shop/order-list/order-list' })
+    },
+    goToAfterSales() {
+      uni.navigateTo({ url: '/pages/shop/after-sales/after-sales' })
+    },
     goToIncome() {
       uni.navigateTo({ url: '/pages/promotion/commission' })
     },

+ 71 - 181
cfc-frontend/pages/wisdom/index.vue

@@ -8,7 +8,30 @@
       tagline="学以启智 · 慧及未来"
       quote="知者不惑,仁者不忧" />
 
-    <!-- 2. 游客专属区块 -->
+    <!-- 2. 认知雷达图(登录后) -->
+    <view class="section" v-if="isLoggedIn && cognitiveReport">
+      <view class="section-header">
+        <text class="section-title">认知雷达</text>
+        <text class="section-more" @click="goCognitiveReport">查看详情 ›</text>
+      </view>
+      <RadarChart
+        :dimensions="cognitiveDimensions"
+        :scores="cognitiveScores"
+        :avg-scores="cognitiveAvgScores"
+        :childName="activeChildName"
+        fillColor="#6366F1"
+        gridColor="#E0E7FF"
+        labelColor="#3730A3" />
+    </view>
+
+    <!-- 家庭成员选择条 -->
+    <FamilyMemberStrip
+      v-if="isLoggedIn"
+      :members="familyMembersVisible"
+      :selectedMemberId="selectedMemberId"
+      @select="onFamilyMemberSelect" />
+
+    <!-- 3. 游客专属区块 -->
     <template v-if="!isLoggedIn">
       <LoginGuideCard
         title="登录后查看全家智慧成长数据"
@@ -19,42 +42,34 @@
         ]" />
     </template>
 
-    <!-- 3. 五维能量条(登录后) -->
+    <!-- 4. 五维能量条(登录后) -->
     <FamilyEnergyBar
       v-if="isLoggedIn"
       dimensionCode="wisdom"
       :sandboxData="sandboxData"
       :dualDimension="dualDimension" />
 
-    <!-- 4. 认知雷达图(登录后) -->
-    <view class="section" v-if="isLoggedIn && cognitiveReport">
+    <!-- ===== DAN 报告(登录后) ===== -->
+    <view class="section" v-if="isLoggedIn">
       <view class="section-header">
-        <text class="section-title">认知雷达</text>
-        <text class="section-more" @click="goCognitiveReport">查看详情 ›</text>
+        <text class="section-title">&#x1F4CA; DAN 报告</text>
+        <text class="section-more" @click="goDanUpload">上传 +</text>
+      </view>
+      <view class="dan-card" v-for="report in danReports" :key="report.id" @click="viewDanReport(report)">
+        <view class="dan-card-header">
+          <text class="dan-report-date">{{ formatDate(report.assessmentDate) }}</text>
+          <text :class="['dan-status', report.draftStatus === 'confirmed' ? 'confirmed' : 'pending']">
+            {{ report.draftStatus === 'confirmed' ? '已确认' : '待确认' }}
+          </text>
+        </view>
+        <text class="dan-report-desc">DAN B4 智维度测评报告</text>
+      </view>
+      <view class="dan-empty" v-if="danReports.length === 0">
+        <text class="dan-empty-text">暂无 DAN 报告,点击上方「上传 +」上传测评报告</text>
       </view>
-      <RadarChart
-        :dimensions="cognitiveDimensions"
-        :scores="cognitiveScores"
-        :avg-scores="cognitiveAvgScores"
-        :childName="activeChildName"
-        fillColor="#6366F1"
-        gridColor="#E0E7FF"
-        labelColor="#3730A3" />
     </view>
 
-    <!-- 5. 家庭成员关系图谱(登录后) -->
-    <FamilyRelationGraph
-      v-if="isLoggedIn && familyMembersVisible.length > 0"
-      dimensionCode="wisdom"
-      :selfId="activeChildId"
-      :members="familyMembersVisible"
-      :energyMap="energyMapForGraph"
-      :intimacyMap="intimacyMapForGraph"
-      @memberTap="goMemberDetail" />
-
-
-
-    <!-- 7. 功能入口 -->
+    <!-- 6. 功能入口 -->
     <view class="func-section" v-if="sectionVisible('func_entries')">
       <view class="func-grid">
         <view class="func-item" v-for="item in funcList" :key="item.label" @click="onFuncClick(item)">
@@ -66,7 +81,7 @@
       </view>
     </view>
 
-    <!-- 8. 维度任务 -->
+    <!-- 7. 维度任务 -->
     <DimensionTasks
       v-if="isLoggedIn"
       dimensionCode="wisdom"
@@ -74,7 +89,7 @@
       @taskClick="onTaskClick"
       @moreTasks="goTasks" />
 
-    <!-- 9. 维度活动 -->
+    <!-- 8. 维度活动 -->
     <DimensionActivities
       dimensionCode="wisdom"
       :activities="dimensionActivities"
@@ -82,14 +97,14 @@
       @activityClick="goActivityDetail"
       @moreActivities="goMoreActivities" />
 
-    <!-- 10. 维度商品 -->
+    <!-- 9. 维度商品 -->
     <DimensionProducts
       dimensionCode="wisdom"
       :products="dimensionProducts"
       @productClick="goProductDetail"
       @moreProducts="goMoreProducts" />
 
-    <!-- 11. 推荐阅读 -->
+    <!-- 10. 推荐阅读 -->
     <DimensionArticles
       v-if="sectionVisible('recommended_reading')"
       dimensionCode="wisdom"
@@ -98,40 +113,7 @@
       @articleClick="goArticleDetail"
       @moreArticles="goMoreArticles" />
 
-    <!-- 12. 智慧小贴士 -->
-    <view class="section" v-if="sectionVisible('wisdom_tips')">
-      <view class="section-header">
-        <text class="section-title">智慧小贴士</text>
-      </view>
-      <view class="tips-list">
-        <view class="tip-card" v-for="item in wisdomTips" :key="item.id">
-          <text class="tip-title">{{ item.title }}</text>
-          <text class="tip-summary">{{ item.summary }}</text>
-        </view>
-      </view>
-    </view>
-
-    <!-- ===== DAN 报告(B4-智维度) ===== -->
-    <view class="section" v-if="isLoggedIn && danReports.length > 0">
-      <view class="section-header">
-        <text class="section-title">&#x1F4CA; DAN 报告</text>
-        <text class="section-more" @click="goDanUpload('wisdom')">上传 +</text>
-      </view>
-      <view class="dan-card" v-for="report in danReports" :key="report.id">
-        <view class="dan-card-header">
-          <text class="dan-report-date">{{ formatDate(report.assessmentDate) }}</text>
-          <text :class="['dan-status', report.draftStatus === 'confirmed' ? 'confirmed' : 'pending']">
-            {{ report.draftStatus === 'confirmed' ? '已确认' : '待确认' }}
-          </text>
-        </view>
-        <text class="dan-report-desc">DAN B4 智维度测评报告</text>
-        <view class="dan-card-footer" @click="viewDanReport(report)">
-          <text class="dan-view-link">查看详情 &rarr;</text>
-        </view>
-      </view>
-    </view>
-
-    <!-- 13. 快捷操作按钮 -->
+    <!-- 11. 快捷操作按钮 -->
     <view class="section quick-actions" v-if="isLoggedIn">
       <view class="action-btn" @click="goCognitiveReport">
         <text class="action-icon">📊</text>
@@ -145,9 +127,9 @@
         <text class="action-icon">📋</text>
         <text class="action-text">测评预约</text>
       </view>
-      <view class="action-btn" @click="goHome">
-        <text class="action-icon">🏠</text>
-        <text class="action-text">返回首页</text>
+      <view class="action-btn" @click="goDanUpload">
+        <text class="action-icon">&#x1F4C4;</text>
+        <text class="action-text">上传报告</text>
       </view>
     </view>
 
@@ -167,12 +149,12 @@ import DimensionTasks from '../../components/DimensionTasks.vue'
 import DimensionActivities from '../../components/DimensionActivities.vue'
 import DimensionProducts from '../../components/DimensionProducts.vue'
 import DimensionArticles from '../../components/DimensionArticles.vue'
-import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
 import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
-import { getVisibleSections, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getAssessmentLatestResult, getFeaturedArticles, getContactList, getHealthAlerts, getMilestones, getDanReportByChild } from '../../utils/api.js'
+import FamilyMemberStrip from '../../components/FamilyMemberStrip.vue'
+import { getVisibleSections, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getAssessmentLatestResult, getFeaturedArticles, getDanReportByChild } from '../../utils/api.js'
 
 export default {
-  components: { TabTransition, PageBanner, LoginGuideCard, RadarChart, FamilyEnergyBar, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, FamilyRelationGraph, AIFloatingAvatar },
+  components: { TabTransition, PageBanner, LoginGuideCard, RadarChart, FamilyEnergyBar, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, AIFloatingAvatar, FamilyMemberStrip },
   data() {
     return {
       isLoggedIn: false,
@@ -183,6 +165,7 @@ export default {
       userName: '',
       children: [],
       familyMembersVisible: [],
+      selectedMemberId: null,
       sandboxData: null,
       dualDimension: null,
       visibleSections: [],
@@ -191,12 +174,8 @@ export default {
       dimensionActivities: [],
       dimensionProducts: [],
       articles: [],
-      wisdomTips: [],
       /** Mock 平均值(6维认知):感知/专注/记忆/逻辑/空间/加工速度 */
       cognitiveAvgScores: [70, 65, 72, 68, 66, 71],
-      contactList: [],
-      healthAlerts: [],
-      milestones: [],
       danReports: [],
       funcList: [
         { icon: '\u{1F4CA}', label: '认知报告', needLogin: true, page: '/pages/wisdom-detail/cognitive-report' },
@@ -207,24 +186,6 @@ export default {
     }
   },
   computed: {
-    energyMapForGraph: function() {
-      var map = {}
-      if (this.sandboxData && this.sandboxData.members) {
-        for (var i = 0; i < this.sandboxData.members.length; i++) {
-          var m = this.sandboxData.members[i]
-          map[m.memberId || m.id] = {
-            bodyScore: m.bodyScore || 0,
-            mindScore: m.mindScore || 0,
-            actionScore: m.actionScore || 0,
-            wisdomScore: m.wisdomScore || 0
-          }
-        }
-      }
-      return map
-    },
-    intimacyMapForGraph: function() {
-      return {}
-    },
     wisdomArticles: function() {
       if (!this.articles || this.articles.length === 0) return []
       var result = []
@@ -271,7 +232,6 @@ export default {
       this.loadChildren()
       this.loadFamilyMembersVisible()
       this.loadCognitiveReport()
-      this.loadRelationshipHealth()
       this.loadDanReports()
     }
     this.loadDimensionActivities()
@@ -281,8 +241,11 @@ export default {
     this._watchPageReady()
   },
   methods: {
+    onFamilyMemberSelect: function(member) {
+      this.selectedMemberId = member.id
+    },
     loadSectionConfig: function() {
-      var baseSections = ['func_entries', 'wisdom_tips', 'recommended_reading']
+      var baseSections = ['func_entries', 'recommended_reading']
       if (!uni.getStorageSync('token')) {
         this.visibleSections = baseSections
         return
@@ -297,7 +260,7 @@ export default {
           self.visibleSections = merged
         }
       }).catch(function(e) {
-        self.visibleSections = ['func_entries', 'wisdom_tips']
+        self.visibleSections = ['func_entries', 'recommended_reading']
       })
     },
     loadChildren: function() {
@@ -327,7 +290,6 @@ export default {
                 self.loadCognitiveReport()
             }
         }
-        self.loadContacts()
       }).catch(function(e) {})
     },
     loadFamilyMembersVisible: function() {
@@ -364,6 +326,7 @@ export default {
       }
       this.loadFamilyMembersVisible()
       this.loadCognitiveReport()
+      this.loadDanReports()
     },
     loadDimensionTasks: function() {
       var self = this
@@ -413,12 +376,6 @@ export default {
       }
     },
     scrollToSection: function(section) {},
-    goMemberDetail: function(memberId) {
-      uni.navigateTo({ url: '/pages/member-detail/member-detail?memberId=' + memberId + '&entrySource=relation-graph&dimensionCode=wisdom' })
-    },
-    goFamilyMembers: function() {
-      uni.navigateTo({ url: '/pages/profile-extra/family-members' })
-    },
     goCognitiveReport: function() {
       uni.navigateTo({ url: '/pages/wisdom-detail/cognitive-report' })
     },
@@ -428,15 +385,8 @@ export default {
     goAssessment: function() {
       uni.navigateTo({ url: '/pages/assessment/apply' })
     },
-    goHome: function() {
-      uni.switchTab({ url: '/pages/index-home/index' })
-    },
     onTaskClick: function(task) {},
     goTasks: function() { uni.switchTab({ url: '/pages/tasks/tasks' }) },
-    goActivityDetail: function(id) {},
-    goMoreActivities: function() {
-      uni.navigateTo({ url: '/pages/activity/index' })
-    },
     goActivityDetail: function(act) {
       if (!act || !act.id) return
       uni.navigateTo({ url: '/pages/discover-detail/activity-detail/activity-detail?id=' + act.id })
@@ -503,55 +453,11 @@ export default {
       uni.navigateTo({ url: '/pages/mind-detail/article-detail?id=' + (article.id || article) })
     },
 
-    // ===== 重要关系 =====
-    loadContacts: function() {
-      var self = this
-      getContactList({}).then(function(res) {
-        if (res.code === 200 && res.data) {
-          self.contactList = Array.isArray(res.data) ? res.data : []
-        }
-      }).catch(function(e) {
-        console.log('获取联系人失败', e)
-      })
-    },
-    loadRelationshipHealth: function() {
-      var self = this
-      getHealthAlerts({}).then(function(res) {
-        if (res.code === 200 && res.data) {
-          self.healthAlerts = Array.isArray(res.data) ? res.data : []
-        }
-      }).catch(function() {
-        self.healthAlerts = []
-      })
-      getMilestones({}, 30).then(function(res) {
-        if (res.code === 200 && res.data) {
-          self.milestones = Array.isArray(res.data) ? res.data : []
-        }
-      }).catch(function() {
-        self.milestones = []
-      })
-    },
-    onContactClick: function(item) {
-      uni.navigateTo({ url: '/pages/wisdom-detail/contact-detail?id=' + item.id })
-    },
-    onShowImport: function() {
-      uni.showToast({ title: '导入通讯录', icon: 'none' })
-    },
-    goInteractionLog: function(memberId) {
-      if (memberId) {
-        uni.navigateTo({ url: '/pages/wisdom-detail/interaction-log?memberId=' + memberId })
-      } else {
-        uni.navigateTo({ url: '/pages/wisdom-detail/interaction-log' })
-      }
-    },
-    goRelationshipQuestionnaire: function() {
-      uni.navigateTo({ url: '/pages/wisdom-detail/relationship-questionnaire' })
-    },
     _watchPageReady() {
       var self = this
       var unwatch = this.$watch(function() {
         if (self.isLoggedIn) {
-          return !!(self.cognitiveReport || self.energyOverview)
+          return !!(self.cognitiveReport || self.sandboxData)
         }
         return !!(self.dimensionActivities && self.dimensionActivities.length > 0) ||
                !!(self.dimensionProducts && self.dimensionProducts.length > 0)
@@ -669,32 +575,6 @@ export default {
   color: #999;
 }
 
-/* ===== 智慧小贴士 ===== */
-.tips-list {
-  display: flex;
-  flex-direction: column;
-}
-.tip-card {
-  background: #fff;
-  border-radius: 16rpx;
-  padding: 24rpx 20rpx;
-  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
-  margin-bottom: 16rpx;
-}
-.tip-title {
-  font-size: 28rpx;
-  font-weight: bold;
-  color: #333;
-  display: block;
-  margin-bottom: 8rpx;
-}
-.tip-summary {
-  font-size: 24rpx;
-  color: #888;
-  line-height: 1.5;
-  display: block;
-}
-
 /* ===== 快捷操作按钮 ===== */
 .quick-actions {
   display: flex;
@@ -776,4 +656,14 @@ export default {
   font-size: 26rpx;
   color: #6366F1;
 }
+.dan-empty {
+  background: #fff;
+  border-radius: 16rpx;
+  padding: 40rpx 24rpx;
+  text-align: center;
+}
+.dan-empty-text {
+  font-size: 24rpx;
+  color: #999;
+}
 </style>