|
|
@@ -1,4 +1,4 @@
|
|
|
-<template>
|
|
|
+<template>
|
|
|
<view class="body-container">
|
|
|
<!-- Tabbar 切换过渡页 -->
|
|
|
<tab-transition v-if="showTabTransition" dimCode="body" />
|
|
|
@@ -37,6 +37,16 @@
|
|
|
:intimacyMap="intimacyMapForGraph"
|
|
|
@memberTap="goMemberDetail" />
|
|
|
|
|
|
+ <!-- 登录后:用户快捷入口 -->
|
|
|
+ <UserQuickEntry
|
|
|
+ v-if="isLoggedIn"
|
|
|
+ :userName="userName"
|
|
|
+ roleName="家长"
|
|
|
+ :currentChildName="activeChildName"
|
|
|
+ :children="children"
|
|
|
+ @childChanged="onChildChanged"
|
|
|
+ @scrollTo="scrollToSection" />
|
|
|
+
|
|
|
<!-- 雷达图 -->
|
|
|
<view class="section" v-if="dimensionData">
|
|
|
<view class="section-header" v-if="dimensionData.isAverage">
|
|
|
@@ -77,22 +87,67 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 快捷操作按钮 -->
|
|
|
- <view class="section quick-actions" v-if="isLoggedIn">
|
|
|
- <view class="action-btn" @click="goToHealthReport">
|
|
|
- <text class="action-icon">📋</text>
|
|
|
- <text class="action-text">报告详情</text>
|
|
|
+ <!-- 健康报告摘要(登录后可见) -->
|
|
|
+ <view class="section" v-if="sectionVisible('health_report') && isLoggedIn">
|
|
|
+ <view class="section-header">
|
|
|
+ <text class="section-title">健康报告</text>
|
|
|
+ <text class="section-more" @click="goToHealthReport">查看详情 ›</text>
|
|
|
</view>
|
|
|
- <view class="action-btn" @click="goToCheckin">
|
|
|
- <text class="action-icon">🏃</text>
|
|
|
- <text class="action-text">健康打卡</text>
|
|
|
+ <view class="report-card" v-if="latestReport">
|
|
|
+ <view class="report-type-tag">{{ reportTypeLabel }}</view>
|
|
|
+ <view class="report-score-row">
|
|
|
+ <view class="score-circle">
|
|
|
+ <text class="score-value">{{ latestReport.overallScore || '--' }}</text>
|
|
|
+ <text class="score-label">综合评分</text>
|
|
|
+ </view>
|
|
|
+ <view class="report-meta">
|
|
|
+ <view class="meta-item" v-if="latestReport.gutHealthScore">
|
|
|
+ <text class="meta-label">肠道健康</text>
|
|
|
+ <text class="meta-value">{{ latestReport.gutHealthScore }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="meta-item" v-if="latestReport.nutritionScore">
|
|
|
+ <text class="meta-label">营养状况</text>
|
|
|
+ <text class="meta-value">{{ latestReport.nutritionScore }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="meta-item" v-if="latestReport.gutAge">
|
|
|
+ <text class="meta-label">肠道年龄</text>
|
|
|
+ <text class="meta-value">{{ latestReport.gutAge }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="report-date">报告日期:{{ formatDate(latestReport.reportDate) }}</text>
|
|
|
</view>
|
|
|
- <view class="action-btn" @click="goToNutritionProfile">
|
|
|
- <text class="action-icon">🥗</text>
|
|
|
- <text class="action-text">营养档案</text>
|
|
|
+ <view class="report-empty" v-else>
|
|
|
+ <text class="empty-tip">暂无健康报告</text>
|
|
|
+ <text class="empty-sub">规划师录入后将自动显示</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
+ <!-- ===== 精准营养(上传报告+产品+文章) ===== -->
|
|
|
+ <view class="section nutrition-section" v-if="isLoggedIn">
|
|
|
+ <view class="section-header">
|
|
|
+ <text class="section-title">🥗 精准营养</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 上传报告入口 -->
|
|
|
+ <view class="nutrition-report-card" @click="goToUploadReport">
|
|
|
+ <view class="nutrition-report-left">
|
|
|
+ <text class="nutrition-icon-large">📋</text>
|
|
|
+ </view>
|
|
|
+ <view class="nutrition-report-right">
|
|
|
+ <text class="nutrition-title">上传健康报告</text>
|
|
|
+ <text class="nutrition-desc">上传体检报告或肠道检测报告,AI智能解读分析,获取个性化营养方案</text>
|
|
|
+ <view class="nutrition-report-tags">
|
|
|
+ <text class="tag">体检报告</text>
|
|
|
+ <text class="tag">肠道检测</text>
|
|
|
+ <text class="tag">AI解读</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="nutrition-arrow">›</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ </view>
|
|
|
+
|
|
|
<!-- 维度任务 -->
|
|
|
<DimensionTasks
|
|
|
v-if="isLoggedIn"
|
|
|
@@ -124,6 +179,24 @@
|
|
|
@articleClick="goArticleDetail"
|
|
|
@moreArticles="goMoreArticles" />
|
|
|
|
|
|
+ <!-- 快捷操作按钮 -->
|
|
|
+ <view class="section quick-actions" v-if="isLoggedIn">
|
|
|
+ <view class="action-btn" @click="goToHealthReport">
|
|
|
+ <text class="action-icon">📋</text>
|
|
|
+ <text class="action-text">报告详情</text>
|
|
|
+ </view>
|
|
|
+ <view class="action-btn" @click="goToCheckin">
|
|
|
+ <text class="action-icon">🏃</text>
|
|
|
+ <text class="action-text">健康打卡</text>
|
|
|
+ </view>
|
|
|
+ <view class="action-btn" @click="goToNutritionProfile">
|
|
|
+ <text class="action-icon">🥗</text>
|
|
|
+ <text class="action-text">营养档案</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
<!-- 底部占位 -->
|
|
|
<view class="bottom-spacer"></view>
|
|
|
<AIFloatingAvatar />
|
|
|
@@ -135,6 +208,7 @@ import TabTransition from '../../components/tab-transition.vue'
|
|
|
import PageBanner from '../../components/PageBanner.vue'
|
|
|
import LoginGuideCard from '../../components/LoginGuideCard.vue'
|
|
|
import FamilyEnergyBar from '../../components/FamilyEnergyBar.vue'
|
|
|
+import UserQuickEntry from '../../components/UserQuickEntry.vue'
|
|
|
import DimensionTasks from '../../components/DimensionTasks.vue'
|
|
|
import DimensionActivities from '../../components/DimensionActivities.vue'
|
|
|
import DimensionProducts from '../../components/DimensionProducts.vue'
|
|
|
@@ -143,7 +217,8 @@ import FamilyRelationGraph from '../../components/FamilyRelationGraph.vue'
|
|
|
import RadarChart from '../../components/RadarChart.vue'
|
|
|
import HealthDimensionsSection from '../../components/HealthDimensionsSection.vue'
|
|
|
import AIFloatingAvatar from '../../components/AIFloatingAvatar.vue'
|
|
|
-import { getVisibleSections, getEnergyOverview, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getVisibleFamilyMembers, getDimensionOverview, getFeaturedArticles, getContactList, getHealthAlerts, getMilestones } from '../../utils/api.js'
|
|
|
+
|
|
|
+import { getVisibleSections, getEnergyOverview, getChildren, getTodayTasksByCategory, getActivityList, getProductsByDomain, getFamilyEnergySandbox, getVisibleFamilyMembers, getDimensionOverview, getFeaturedArticles } from '../../utils/api.js'
|
|
|
import config from '../../config.js'
|
|
|
|
|
|
var BASE_URL = config.api('')
|
|
|
@@ -174,7 +249,7 @@ const healthRequest = function(url, data) {
|
|
|
}
|
|
|
|
|
|
export default {
|
|
|
- components: { TabTransition, PageBanner, LoginGuideCard, FamilyEnergyBar, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, FamilyRelationGraph, RadarChart, HealthDimensionsSection, AIFloatingAvatar },
|
|
|
+ components: { TabTransition, PageBanner, LoginGuideCard, FamilyEnergyBar, UserQuickEntry, DimensionTasks, DimensionActivities, DimensionProducts, DimensionArticles, FamilyRelationGraph, RadarChart, HealthDimensionsSection, AIFloatingAvatar },
|
|
|
data() {
|
|
|
return {
|
|
|
isLoggedIn: false,
|
|
|
@@ -200,12 +275,9 @@ export default {
|
|
|
{ icon: '\u{1F3C3}', label: '运动', needLogin: true, page: '/pages/body/exercise-record' },
|
|
|
{ icon: '\u{1F957}', label: '饮食', needLogin: true, page: '/pages/body/meal-record' },
|
|
|
{ icon: '\u{1F634}', label: '作息', needLogin: true, page: '/pages/body/sleep-record' },
|
|
|
- { icon: '\u{1F9D8}', label: '冥想', needLogin: true, page: '/pages/health/meditation-index' }
|
|
|
- ],
|
|
|
- contactList: [],
|
|
|
- healthAlerts: [],
|
|
|
- milestones: []
|
|
|
- }
|
|
|
+ { icon: '\u{1F9D8}', label: '冥想', needLogin: true, page: '/pages/health/meditation-index' },
|
|
|
+ { icon: '\u{1F4CA}', label: '舌诊', needLogin: true, page: '/pages/health/report-upload?reportType=tongue' }
|
|
|
+ }
|
|
|
},
|
|
|
computed: {
|
|
|
reportTypeLabel: function() {
|
|
|
@@ -243,7 +315,6 @@ export default {
|
|
|
if (this.isLoggedIn) {
|
|
|
this.loadChildren()
|
|
|
this.loadFamilyMembersVisible()
|
|
|
- this.loadRelationshipHealth()
|
|
|
}
|
|
|
// 游客也能浏览活动和商品
|
|
|
this.loadDimensionActivities()
|
|
|
@@ -287,12 +358,14 @@ export default {
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
- // FIX: 不再自动选择第一个孩子。仅在用户通过 UserQuickEntry 切换时设置 activeChildId
|
|
|
- // 默认情况下,页面显示当前登录用户自己的数据(由 API 根据 token 推断)
|
|
|
- if (found) {
|
|
|
+ if (!found && self.children.length > 0) {
|
|
|
+ self.activeChildId = self.children[0].childId
|
|
|
+ self.activeChildName = self.children[0].name || self.children[0].nickname || '孩子'
|
|
|
+ uni.setStorageSync('currentChildId', self.activeChildId)
|
|
|
+ }
|
|
|
+ if (self.activeChildId) {
|
|
|
self.loadDashboardData()
|
|
|
}
|
|
|
- self.loadContacts()
|
|
|
}
|
|
|
}).catch(function(e) {
|
|
|
console.log('获取孩子列表失败', e)
|
|
|
@@ -392,7 +465,7 @@ export default {
|
|
|
},
|
|
|
loadFeaturedArticles: function() {
|
|
|
var self = this
|
|
|
- getFeaturedArticles({ size: 5, dimensionCode: 'body' }).then(function(res) {
|
|
|
+ getFeaturedArticles({ size: 5 }).then(function(res) {
|
|
|
if (res.code === 200 && res.data) {
|
|
|
var gradientColors = [
|
|
|
'linear-gradient(135deg, #FF8C42, #FFB074)',
|
|
|
@@ -481,74 +554,46 @@ export default {
|
|
|
return
|
|
|
}
|
|
|
if (item.page === 'health-dimensions') {
|
|
|
- uni.navigateTo({ url: '/pages/body-detail/health-dimensions?childId=' + (this.activeChildId || '') })
|
|
|
+ if (!this.activeChildId) {
|
|
|
+ uni.showToast({ title: '请先选择孩子', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ uni.navigateTo({ url: '/pages/body-detail/health-dimensions?childId=' + this.activeChildId })
|
|
|
return
|
|
|
}
|
|
|
if (item.page) uni.navigateTo({ url: item.page })
|
|
|
},
|
|
|
goToHealthReport: function() {
|
|
|
- var id = this.activeChildId || uni.getStorageSync('currentChildId') || ''
|
|
|
+ var id = this.activeChildId || uni.getStorageSync('currentChildId')
|
|
|
+ if (!id) {
|
|
|
+ uni.showToast({ title: '请先选择成员', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
uni.navigateTo({ url: '/pages/body-detail/health-report?childId=' + id })
|
|
|
},
|
|
|
goDimensionDetail: function(dimKey) {
|
|
|
uni.navigateTo({ url: '/pages/body/dimension-detail?dimension=' + dimKey + '&childId=' + this.activeChildId })
|
|
|
},
|
|
|
goToCheckin: function() {
|
|
|
- var id = this.activeChildId || uni.getStorageSync('currentChildId') || ''
|
|
|
+ var id = this.activeChildId || uni.getStorageSync('currentChildId')
|
|
|
+ if (!id) {
|
|
|
+ uni.showToast({ title: '请先选择成员', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
uni.navigateTo({ url: '/pages/body-detail/checkin?childId=' + id })
|
|
|
},
|
|
|
goToNutritionProfile: function() {
|
|
|
- var id = this.activeChildId || uni.getStorageSync('currentChildId') || ''
|
|
|
+ var id = this.activeChildId || uni.getStorageSync('currentChildId')
|
|
|
+ if (!id) {
|
|
|
+ uni.showToast({ title: '请先选择成员', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
uni.navigateTo({ url: '/pages/health/nutrition-profile?childId=' + id })
|
|
|
},
|
|
|
goToUploadReport: function() {
|
|
|
var id = this.activeChildId || uni.getStorageSync('currentChildId') || ''
|
|
|
uni.navigateTo({ url: '/pages/health/report-upload?childId=' + id + '&from=body' })
|
|
|
},
|
|
|
- // ===== 重要关系 =====
|
|
|
- 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/body-detail/contact-detail?id=' + item.id })
|
|
|
- },
|
|
|
- onShowImport: function() {
|
|
|
- uni.showToast({ title: '导入通讯录', icon: 'none' })
|
|
|
- },
|
|
|
- goInteractionLog: function(memberId) {
|
|
|
- if (memberId) {
|
|
|
- uni.navigateTo({ url: '/pages/body-detail/interaction-log?memberId=' + memberId })
|
|
|
- } else {
|
|
|
- uni.navigateTo({ url: '/pages/body-detail/interaction-log' })
|
|
|
- }
|
|
|
- },
|
|
|
- goRelationshipQuestionnaire: function() {
|
|
|
- uni.navigateTo({ url: '/pages/body-detail/relationship-questionnaire' })
|
|
|
- },
|
|
|
formatDate: function(dateStr) {
|
|
|
if (!dateStr) return '--'
|
|
|
try {
|