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

feat: DAN报告上传 - 集成到mind/wisdom维度页面

在心维度和智维度Tab页面添加DAN报告卡片列表和上传入口

Ultraworked with Sisyphus

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
User 3 месяцев назад
Родитель
Сommit
f7cd740285
2 измененных файлов с 215 добавлено и 18 удалено
  1. 116 9
      cfc-frontend/pages/mind/index.vue
  2. 99 9
      cfc-frontend/pages/wisdom/index.vue

+ 116 - 9
cfc-frontend/pages/mind/index.vue

@@ -238,6 +238,26 @@
       </view>
       </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
     <DimensionTasks
       v-if="isLoggedIn"
       v-if="isLoggedIn"
@@ -305,7 +325,7 @@ import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
 
 
 import PsychCrisisBanner from '../../components/PsychCrisisBanner.vue'
 import PsychCrisisBanner from '../../components/PsychCrisisBanner.vue'
 import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
 import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
-import { getVisibleSections, getFeaturedArticles, getEmiReport, getFamilyEnergySandbox, getTodayTasksByCategory, getActivityList, getProductsByDomain, getChildren, getVisibleFamilyMembers, getEnergyOverview, getContactList, getHealthAlerts, getMilestones } from '../../utils/api.js'
+import { getVisibleSections, getFeaturedArticles, getEmiReport, getFamilyEnergySandbox, getTodayTasksByCategory, getActivityList, getProductsByDomain, getChildren, getVisibleFamilyMembers, getEnergyOverview, getContactList, getHealthAlerts, getMilestones, getDanReportByChild } from '../../utils/api.js'
 import config from '../../config.js'
 import config from '../../config.js'
 
 
 export default {
 export default {
@@ -377,7 +397,8 @@ export default {
       dimensionProducts: [],
       dimensionProducts: [],
       contactList: [],
       contactList: [],
       healthAlerts: [],
       healthAlerts: [],
-      milestones: []
+      milestones: [],
+      danReports: []
     }
     }
   },
   },
   computed: {
   computed: {
@@ -553,7 +574,8 @@ export default {
     this.isLoggedIn = !!token
     this.isLoggedIn = !!token
     if (this.isLoggedIn) {
     if (this.isLoggedIn) {
       this.role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || null
       this.role = uni.getStorageSync('currentRole') || uni.getStorageSync('role') || null
-      this.currentChildId = uni.getStorageSync('currentChildId') || null
+      // FIX: 从 Vuex store 读取 currentChildId,而非仅从 localStorage
+      this.currentChildId = (this.$store.state && this.$store.state.currentChildId) || uni.getStorageSync('currentChildId') || null
       this.userName = uni.getStorageSync('nickname') || uni.getStorageSync('userName') || '家长'
       this.userName = uni.getStorageSync('nickname') || uni.getStorageSync('userName') || '家长'
     }
     }
     this.loadSectionConfig()
     this.loadSectionConfig()
@@ -569,6 +591,7 @@ export default {
       this.loadContacts()
       this.loadContacts()
       this.loadHealthAlerts()
       this.loadHealthAlerts()
       this.loadMilestones()
       this.loadMilestones()
+      this.loadDanReports()
     }
     }
     // 游客也能浏览活动和商品
     // 游客也能浏览活动和商品
     this.loadDimensionActivities()
     this.loadDimensionActivities()
@@ -760,12 +783,10 @@ export default {
               break
               break
             }
             }
           }
           }
-          if (!found && self.children.length > 0) {
-            self.currentChildId = self.children[0].childId
-            uni.setStorageSync('currentChildId', self.currentChildId)
-          }
-          if (self.currentChildId) {
+          // FIX: 不再自动选择第一个孩子。仅在用户通过 UserQuickEntry 切换时设置 currentChildId
+          if (found) {
             self.loadDimensionData()
             self.loadDimensionData()
+            self.loadEmiData()
           }
           }
         }
         }
       }).catch(function(e) {
       }).catch(function(e) {
@@ -837,7 +858,8 @@ export default {
     },
     },
     onChildChanged: function(child) {
     onChildChanged: function(child) {
       this.currentChildId = child.childId
       this.currentChildId = child.childId
-      uni.setStorageSync('currentChildId', child.childId)
+      // FIX: 同步提交到 Vuex store
+      this.$store.commit('switchToChild', child.childId)
       this.loadDimensionData()
       this.loadDimensionData()
       this.loadEmiData()
       this.loadEmiData()
       this.loadTraditionalCultureData()
       this.loadTraditionalCultureData()
@@ -992,6 +1014,29 @@ export default {
         if (unwatch) unwatch()
         if (unwatch) unwatch()
         self.showTabTransition = false
         self.showTabTransition = false
       }, 5000)
       }, 5000)
+    },
+
+    // ===== DAN 报告 =====
+    loadDanReports: function() {
+      var self = this
+      var memberId = self.currentChildId
+      if (!memberId) return
+      getDanReportByChild(memberId, 'mind').then(function(res) {
+        if (res.code === 200 && res.data) {
+          self.danReports = res.data
+        }
+      }).catch(function() {})
+    },
+    goDanUpload: function(dimension) {
+      uni.navigateTo({ url: '/pages/dan-assessment/report-upload' })
+    },
+    viewDanReport: function(report) {
+      uni.navigateTo({ url: '/pages/dan-assessment/report-upload?draftId=' + report.id })
+    },
+    formatDate: function(dateStr) {
+      if (!dateStr) return ''
+      var d = new Date(dateStr)
+      return d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()
     }
     }
   }
   }
 }
 }
@@ -1721,4 +1766,66 @@ export default {
 .ki-footer:active {
 .ki-footer:active {
   opacity: 0.7;
   opacity: 0.7;
 }
 }
+
+/* DAN 报告卡片 */
+.dan-card {
+  background: #fff;
+  border-radius: 16rpx;
+  padding: 24rpx;
+  margin-bottom: 16rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06);
+}
+.dan-card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12rpx;
+}
+.dan-report-date {
+  font-size: 26rpx;
+  color: #666;
+}
+.dan-status {
+  font-size: 22rpx;
+  padding: 4rpx 16rpx;
+  border-radius: 8rpx;
+}
+.dan-status.confirmed {
+  background: #D1FAE5;
+  color: #065F46;
+}
+.dan-status.pending {
+  background: #FEF3C7;
+  color: #92400E;
+}
+.dan-report-desc {
+  font-size: 28rpx;
+  color: #333;
+  font-weight: 500;
+  margin-bottom: 12rpx;
+  display: block;
+}
+.dan-card-footer {
+  text-align: right;
+}
+.dan-view-link {
+  font-size: 26rpx;
+  color: #6366F1;
+}
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20rpx;
+}
+.section-title {
+  font-size: 32rpx;
+  font-weight: 700;
+  color: #333;
+}
+.section-more {
+  font-size: 26rpx;
+  color: #6366F1;
+  padding: 8rpx 16rpx;
+}
 </style>
 </style>

+ 99 - 9
cfc-frontend/pages/wisdom/index.vue

@@ -119,6 +119,26 @@
       </view>
       </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. 快捷操作按钮 -->
     <!-- 13. 快捷操作按钮 -->
     <view class="section quick-actions" v-if="isLoggedIn">
     <view class="section quick-actions" v-if="isLoggedIn">
       <view class="action-btn" @click="goCognitiveReport">
       <view class="action-btn" @click="goCognitiveReport">
@@ -158,7 +178,7 @@ import DimensionProducts from '../../components/DimensionProducts.vue'
 import DimensionArticles from '../../components/DimensionArticles.vue'
 import DimensionArticles from '../../components/DimensionArticles.vue'
 import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
 import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
 import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
 import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
-import { getVisibleSections, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getAssessmentLatestResult, getFeaturedArticles, getContactList, getHealthAlerts, getMilestones } from '../../utils/api.js'
+import { getVisibleSections, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getAssessmentLatestResult, getFeaturedArticles, getContactList, getHealthAlerts, getMilestones, getDanReportByChild } from '../../utils/api.js'
 
 
 export default {
 export default {
   components: { TabTransition, PageBanner, LoginGuideCard, RadarChart, FamilyEnergyBar, UserQuickEntry, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, FamilyRelationGraph, AIFloatingAvatar },
   components: { TabTransition, PageBanner, LoginGuideCard, RadarChart, FamilyEnergyBar, UserQuickEntry, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, FamilyRelationGraph, AIFloatingAvatar },
@@ -186,6 +206,7 @@ export default {
       contactList: [],
       contactList: [],
       healthAlerts: [],
       healthAlerts: [],
       milestones: [],
       milestones: [],
+      danReports: [],
       funcList: [
       funcList: [
         { icon: '\u{1F4CA}', label: '认知报告', needLogin: true, page: '/pages/wisdom-detail/cognitive-report' },
         { icon: '\u{1F4CA}', label: '认知报告', needLogin: true, page: '/pages/wisdom-detail/cognitive-report' },
         { icon: '\u{270F}\uFE0F', label: '自己出题', needLogin: true, page: '/pages/wisdom-detail/self-quiz' },
         { icon: '\u{270F}\uFE0F', label: '自己出题', needLogin: true, page: '/pages/wisdom-detail/self-quiz' },
@@ -261,6 +282,7 @@ export default {
       this.loadFamilyMembersVisible()
       this.loadFamilyMembersVisible()
       this.loadCognitiveReport()
       this.loadCognitiveReport()
       this.loadRelationshipHealth()
       this.loadRelationshipHealth()
+      this.loadDanReports()
     }
     }
     this.loadDimensionActivities()
     this.loadDimensionActivities()
     this.loadDimensionProducts()
     this.loadDimensionProducts()
@@ -304,14 +326,12 @@ export default {
                 }
                 }
               }
               }
             }
             }
-            if (!self.activeChildId) {
-              self.activeChildId = self.children[0].id
-              self.activeChildName = self.children[0].nickname || self.children[0].name || ''
-              uni.setStorageSync('currentChildId', self.activeChildId)
-            }
+            // FIX: 不再自动选择第一个孩子
+          }
+          // Load cognitive report only if activeChildId is set (user switched)
+          if (self.activeChildId) {
+            self.loadCognitiveReport()
           }
           }
-          // Load cognitive report AFTER activeChildId is confirmed set
-          self.loadCognitiveReport()
         }
         }
         self.loadContacts()
         self.loadContacts()
       }).catch(function(e) {})
       }).catch(function(e) {})
@@ -340,7 +360,8 @@ export default {
     },
     },
     onChildChanged: function(childId) {
     onChildChanged: function(childId) {
       this.activeChildId = childId
       this.activeChildId = childId
-      uni.setStorageSync('currentChildId', childId)
+      // FIX: 同步提交到 Vuex store
+      this.$store.commit('switchToChild', childId)
       for (var i = 0; i < this.children.length; i++) {
       for (var i = 0; i < this.children.length; i++) {
         if (this.children[i].id == childId) {
         if (this.children[i].id == childId) {
           this.activeChildName = this.children[i].nickname || this.children[i].name || ''
           this.activeChildName = this.children[i].nickname || this.children[i].name || ''
@@ -552,6 +573,29 @@ export default {
         if (unwatch) unwatch()
         if (unwatch) unwatch()
         self.showTabTransition = false
         self.showTabTransition = false
       }, 5000)
       }, 5000)
+    },
+
+    // ===== DAN 报告 =====
+    loadDanReports: function() {
+      var self = this
+      var memberId = self.activeChildId
+      if (!memberId) return
+      getDanReportByChild(memberId, 'wisdom').then(function(res) {
+        if (res.code === 200 && res.data) {
+          self.danReports = res.data
+        }
+      }).catch(function() {})
+    },
+    goDanUpload: function() {
+      uni.navigateTo({ url: '/pages/dan-assessment/report-upload' })
+    },
+    viewDanReport: function(report) {
+      uni.navigateTo({ url: '/pages/dan-assessment/report-upload?draftId=' + report.id })
+    },
+    formatDate: function(dateStr) {
+      if (!dateStr) return ''
+      var d = new Date(dateStr)
+      return d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate()
     }
     }
   }
   }
 }
 }
@@ -694,4 +738,50 @@ export default {
 .bottom-spacer {
 .bottom-spacer {
   height: 120rpx;
   height: 120rpx;
 }
 }
+
+/* DAN 报告卡片 */
+.dan-card {
+  background: #fff;
+  border-radius: 16rpx;
+  padding: 24rpx;
+  margin-bottom: 16rpx;
+  box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06);
+}
+.dan-card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12rpx;
+}
+.dan-report-date {
+  font-size: 26rpx;
+  color: #666;
+}
+.dan-status {
+  font-size: 22rpx;
+  padding: 4rpx 16rpx;
+  border-radius: 8rpx;
+}
+.dan-status.confirmed {
+  background: #D1FAE5;
+  color: #065F46;
+}
+.dan-status.pending {
+  background: #FEF3C7;
+  color: #92400E;
+}
+.dan-report-desc {
+  font-size: 28rpx;
+  color: #333;
+  font-weight: 500;
+  margin-bottom: 12rpx;
+  display: block;
+}
+.dan-card-footer {
+  text-align: right;
+}
+.dan-view-link {
+  font-size: 26rpx;
+  color: #6366F1;
+}
 </style>
 </style>