|
|
@@ -162,34 +162,6 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <!-- 健康报告状态卡片 -->
|
|
|
- <view class="section" v-if="reportStatus.hasReport">
|
|
|
- <view class="report-card" @click="goToReport">
|
|
|
- <view class="report-left">
|
|
|
- <text class="report-icon">📋</text>
|
|
|
- <view class="report-info">
|
|
|
- <text class="report-title">已有健康报告</text>
|
|
|
- <text class="report-desc" v-if="reportStatus.reportType === 'gut_flora'">肠道菌群检测 · {{ reportStatus.reportDate }}</text>
|
|
|
- <text class="report-desc" v-else-if="reportStatus.reportType === 'physical_exam'">体检报告 · {{ reportStatus.reportDate }}</text>
|
|
|
- <text class="report-desc" v-else>健康报告 · {{ reportStatus.reportDate }}</text>
|
|
|
- <text class="report-score" v-if="reportStatus.overallScore">综合评分:{{ reportStatus.overallScore }}分</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <text class="report-arrow">›</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="section" v-else>
|
|
|
- <view class="report-upload-card" @click="goToUploadReport">
|
|
|
- <view class="report-upload-left">
|
|
|
- <text class="report-upload-icon">📷</text>
|
|
|
- <view class="report-upload-info">
|
|
|
- <text class="report-upload-title">上传健康报告</text>
|
|
|
- <text class="report-upload-desc">上传体检或菌群检测报告,获取个性化营养方案</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <text class="report-upload-arrow">›</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
<!-- 今日成长 -->
|
|
|
<view class="section">
|
|
|
<view class="progress-card">
|
|
|
@@ -198,7 +170,7 @@
|
|
|
<text class="progress-date">{{ todayDate }}</text>
|
|
|
</view>
|
|
|
<view class="progress-grid" v-if="progressItems.length > 0">
|
|
|
- <view class="progress-grid-item" v-for="(item, idx) in progressItems" :key="getProgressKey(item)" @click="handleProgressClick(item)">
|
|
|
+ <view class="progress-grid-item" v-for="(item, idx) in progressItems" :key="getProgressKey(item)" @click="handleProgressClick(idx)">
|
|
|
<text class="progress-grid-icon">{{ item.icon }}</text>
|
|
|
<text class="progress-grid-label">{{ item.label }}</text>
|
|
|
<text class="progress-grid-status" :class="item.done ? 'status-done' : 'status-pending'">{{ item.done ? '✔' : (item.actionText || '去记录') }}</text>
|
|
|
@@ -226,36 +198,33 @@
|
|
|
<text class="action-icon">🍽️</text>
|
|
|
<view class="action-info">
|
|
|
<text class="action-title">饮食推荐</text>
|
|
|
- <text class="action-desc">基于菌群报告的个性化食材建议</text>
|
|
|
+ <text class="action-desc">选同住人,获取今日个性化饮食建议</text>
|
|
|
</view>
|
|
|
<text class="action-arrow">›</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <!-- 任务中心 -->
|
|
|
- <view class="section">
|
|
|
- <view class="action-card" @click="goToTasks">
|
|
|
- <text class="action-icon">📋</text>
|
|
|
- <view class="action-info">
|
|
|
- <text class="action-title">任务中心</text>
|
|
|
- <text class="action-desc">查看今日待办任务,完成挑战获取奖励</text>
|
|
|
+ <!-- 任务中心(内联) -->
|
|
|
+ <view class="section" v-if="recentTasks.length > 0">
|
|
|
+ <view class="task-preview-card">
|
|
|
+ <view class="task-preview-header">
|
|
|
+ <text class="task-preview-title">📋 待办任务</text>
|
|
|
+ <text class="task-preview-more" @click="goToTasks">更多 ›</text>
|
|
|
</view>
|
|
|
- <text class="action-arrow">›</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <DimensionActivities :isLoggedIn="true" @activityClick="goActivityDetail" @moreActivities="goMoreActivities" style="margin-bottom:60rpx" />
|
|
|
- <!-- 今日任务 -->
|
|
|
- <DailyTaskCard v-if="isLoggedIn" />
|
|
|
- <!-- 报告上传 -->
|
|
|
- <view class="section">
|
|
|
- <view class="action-card" @click="goToUploadReport">
|
|
|
- <text class="action-icon">📷</text>
|
|
|
- <view class="action-info">
|
|
|
- <text class="action-title">上传报告</text>
|
|
|
- <text class="action-desc">体检报告 · 菌群检测 · 认知测评 · 心理测评 · 情绪打卡</text>
|
|
|
+ <view class="task-preview-list">
|
|
|
+ <view class="task-preview-item" v-for="(task, idx) in recentTasks" :key="getTaskKey(task, idx)" @click="goToTasks">
|
|
|
+ <view class="task-preview-left">
|
|
|
+ <text class="task-preview-name">{{ task.title }}</text>
|
|
|
+ <view class="task-preview-meta">
|
|
|
+ <text class="task-preview-points">+{{ task.points }}分</text>
|
|
|
+ <text class="task-preview-deadline" v-if="task.deadline">⏱ {{ formatTaskTime(task.deadline) }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="task-preview-arrow">›</text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
- <text class="action-arrow">›</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
+ <DimensionActivities :isLoggedIn="true" @activityClick="goActivityDetail" @moreActivities="goMoreActivities" style="margin-bottom:60rpx" />
|
|
|
<!-- 推荐阅读 -->
|
|
|
<view class="section" v-if="recommendArticles.length > 0">
|
|
|
<view class="section-header">
|
|
|
@@ -281,16 +250,14 @@ import LoginGuideCard from '../../components/LoginGuideCard.vue'
|
|
|
import DimensionActivities from '../../components/DimensionActivities.vue'
|
|
|
import DimensionProducts from '../../components/DimensionProducts.vue'
|
|
|
import ArticleBookshelf from '../../components/ArticleBookshelf.vue'
|
|
|
-import DailyTaskCard from '../../components/daily-task-card.vue'
|
|
|
-import { healthCheckinList, getHealthMealList, getFoodCautionList, getGrowthRecommendations, getExerciseRecords, getSleepRecords, getEmotionCheckinList, getCheckinList, getLatestHealthReport } from '../../utils/api.js'
|
|
|
+import { healthCheckinList, getHealthMealList, getFoodCautionList, getGrowthRecommendations, getExerciseRecords, getSleepRecords, getEmotionCheckinList, getCheckinList, getTodayTasks } from '../../utils/api.js'
|
|
|
import { parseDate } from '../../utils/format.js'
|
|
|
export default {
|
|
|
- components: { LoginGuideCard, DimensionActivities, DimensionProducts, ArticleBookshelf, DailyTaskCard },
|
|
|
- data() { return { memberId: '', todayDate: '', hasIncomplete: false, incompleteCount: 0, progressItems: [], streakDays: 0, activeChallenges: 0, completeness: 0, cautionCount: 0,
|
|
|
+ components: { LoginGuideCard, DimensionActivities, DimensionProducts, ArticleBookshelf },
|
|
|
+ data() { return { memberId: '', todayDate: '', hasIncomplete: false, incompleteCount: 0, progressItems: [], recentTasks: [], streakDays: 0, activeChallenges: 0, completeness: 0, cautionCount: 0,
|
|
|
healthArticles: [],
|
|
|
growthArticles: [],
|
|
|
- isLoggedIn: false,
|
|
|
- reportStatus: { hasReport: false, reportId: null, reportType: '', reportDate: '', overallScore: null } } },
|
|
|
+ isLoggedIn: false } },
|
|
|
computed: {
|
|
|
doneCount: function() { var c = 0; for (var i = 0; i < this.progressItems.length; i++) if (this.progressItems[i] && this.progressItems[i].done) c++; return c },
|
|
|
totalCount: function() { return this.progressItems.length },
|
|
|
@@ -314,25 +281,35 @@ export default {
|
|
|
pad: function(n) { return n < 10 ? '0' + n : '' + n },
|
|
|
getProgressKey: function(item) { return item && item.label ? item.label : 'p-' + Math.random() },
|
|
|
dismissReminder: function() { this.hasIncomplete = false },
|
|
|
- handleProgressClick: function(item) {
|
|
|
+ handleProgressClick: function(idx) {
|
|
|
+ var item = this.progressItems[idx]
|
|
|
if (!item || !item.key) return
|
|
|
var m = { diet: '/pages/growth/diet-checkin', exercise: '/pages/growth/exercise-checkin', sleep: '/pages/growth/sleep-checkin', emotion: '/pages/growth/growth-emotion-checkin', checkin: '/pages/wealth-sub/checkin' }
|
|
|
var url = m[item.key]
|
|
|
if (url) uni.navigateTo({ url: url })
|
|
|
},
|
|
|
- goToReport: function() {
|
|
|
- if (this.reportStatus.reportId) uni.navigateTo({ url: '/pages/health/report-detail?id=' + this.reportStatus.reportId })
|
|
|
+ getTaskKey: function(task, idx) { return (task && task.id) ? ('t' + task.id) : ('tk' + idx) },
|
|
|
+ formatTaskTime: function(dateVal) {
|
|
|
+ if (!dateVal) return ''
|
|
|
+ var d = parseDate(dateVal)
|
|
|
+ if (!d) return ''
|
|
|
+ return (d.getMonth() + 1) + '/' + d.getDate() + ' ' + this.pad(d.getHours()) + ':' + this.pad(d.getMinutes())
|
|
|
},
|
|
|
- goToUploadReport: function() {
|
|
|
- var id = this.memberId || ''
|
|
|
- uni.navigateTo({ url: '/pages/health/report-upload?memberId=' + id + '&from=growth' })
|
|
|
+ async loadRecentTasks() {
|
|
|
+ var self = this
|
|
|
+ try {
|
|
|
+ var res = await getTodayTasks(self.memberId ? { memberId: self.memberId } : {})
|
|
|
+ if (res && res.code === 200 && res.data) {
|
|
|
+ self.recentTasks = (res.data || []).slice(0, 3)
|
|
|
+ }
|
|
|
+ } catch(e) {}
|
|
|
},
|
|
|
goActivityDetail: function(act) { uni.navigateTo({ url: '/pages/activity/activity-detail/activity-detail?id=' + act.id }) },
|
|
|
goMoreActivities: function() { uni.navigateTo({ url: '/pages/activity/index' }) },
|
|
|
goToTasks: function() { uni.navigateTo({ url: '/pages/child/tasks' }) },
|
|
|
handleGuestFeatureTap: function() { uni.showToast({ title: '登录后即可体验该功能', icon: 'none' }) },
|
|
|
goToCaution: function() { uni.navigateTo({ url: '/pages/growth/caution-detail' }) },
|
|
|
- goToFoods: function() { uni.navigateTo({ url: '/pages/growth/foods-detail' }) },
|
|
|
+ goToFoods: function() { uni.navigateTo({ url: '/pages/diet/index' }) },
|
|
|
goToArticle: function(article) { var id = article && article.id ? article.id : article; if (!id) return; uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id }) },
|
|
|
goToProduct: function(prod) { var id = prod && prod.id ? prod.id : prod; if (!id) return; uni.navigateTo({ url: '/pages/shop/detail/detail?id=' + id }) },
|
|
|
goMoreProducts: function() { uni.navigateTo({ url: '/pages/shop/index/index' }) },
|
|
|
@@ -356,33 +333,12 @@ export default {
|
|
|
},
|
|
|
async loadAllData() {
|
|
|
var self = this
|
|
|
- try { await self.loadReportStatus() } catch(e) {}
|
|
|
try { await self.loadProgressItems() } catch(e) {}
|
|
|
+ try { await self.loadRecentTasks() } catch(e) {}
|
|
|
try { await self.loadCautionData() } catch(e) {}
|
|
|
try { await self.loadGrowthRecommendations() } catch(e) {}
|
|
|
try { await self.loadMilestones() } catch(e) {}
|
|
|
},
|
|
|
- async loadReportStatus() {
|
|
|
- var self = this
|
|
|
- if (!self.memberId) return
|
|
|
- try {
|
|
|
- var res = await getLatestHealthReport(self.memberId)
|
|
|
- if (res.code === 200 && res.data) {
|
|
|
- var r = res.data
|
|
|
- self.reportStatus = {
|
|
|
- hasReport: true,
|
|
|
- reportId: r.id,
|
|
|
- reportType: r.reportType || '',
|
|
|
- reportDate: r.reportDate ? r.reportDate.substring(0, 10) : '',
|
|
|
- overallScore: r.overallScore || null
|
|
|
- }
|
|
|
- } else {
|
|
|
- self.reportStatus = { hasReport: false, reportId: null, reportType: '', reportDate: '', overallScore: null }
|
|
|
- }
|
|
|
- } catch(e) {
|
|
|
- self.reportStatus = { hasReport: false, reportId: null, reportType: '', reportDate: '', overallScore: null }
|
|
|
- }
|
|
|
- },
|
|
|
async loadProgressItems() {
|
|
|
var self = this
|
|
|
var items = []
|
|
|
@@ -550,25 +506,20 @@ export default {
|
|
|
.progress-footer{display:flex;justify-content:space-between;align-items:center;margin-top:16rpx;padding-top:16rpx;border-top:1rpx solid #f5f5f5}
|
|
|
.footer-text{font-size:24rpx;color:#666;font-weight:bold}
|
|
|
.footer-streak{font-size:24rpx;color:#F97316;font-weight:bold}
|
|
|
-/* 报告状态卡片 */
|
|
|
-.report-card{background:#fff;border-radius:16rpx;padding:20rpx 24rpx;box-shadow:0 2rpx 12rpx rgba(0,0,0,0.06);display:flex;align-items:center;cursor:pointer}
|
|
|
-.report-card:active{opacity:0.85}
|
|
|
-.report-left{display:flex;align-items:center;flex:1;min-width:0}
|
|
|
-.report-icon{font-size:40rpx;margin-right:16rpx;flex-shrink:0}
|
|
|
-.report-info{flex:1;min-width:0}
|
|
|
-.report-title{font-size:28rpx;font-weight:600;color:#333;display:block}
|
|
|
-.report-desc{font-size:22rpx;color:#888;display:block;margin-top:4rpx;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
|
-.report-score{font-size:22rpx;color:#10B981;font-weight:bold;display:block;margin-top:2rpx}
|
|
|
-.report-arrow{font-size:32rpx;color:#ccc;flex-shrink:0}
|
|
|
-/* 报告上传提示卡 */
|
|
|
-.report-upload-card{background:linear-gradient(135deg,#FF8C42,#F97316);border-radius:16rpx;padding:20rpx 24rpx;box-shadow:0 4rpx 16rpx rgba(249,115,22,0.25);display:flex;align-items:center}
|
|
|
-.report-upload-card:active{opacity:0.9}
|
|
|
-.report-upload-left{display:flex;align-items:center;flex:1;min-width:0}
|
|
|
-.report-upload-icon{font-size:44rpx;margin-right:16rpx;flex-shrink:0}
|
|
|
-.report-upload-info{flex:1;min-width:0}
|
|
|
-.report-upload-title{font-size:28rpx;font-weight:600;color:#fff;display:block}
|
|
|
-.report-upload-desc{font-size:22rpx;color:rgba(255,255,255,0.85);display:block;margin-top:4rpx}
|
|
|
-.report-upload-arrow{font-size:32rpx;color:rgba(255,255,255,0.7);flex-shrink:0}
|
|
|
+/* 任务中心预览 */
|
|
|
+.task-preview-card{background:#fff;border-radius:20rpx;padding:24rpx;box-shadow:0 2rpx 12rpx rgba(0,0,0,0.06)}
|
|
|
+.task-preview-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16rpx}
|
|
|
+.task-preview-title{font-size:28rpx;font-weight:bold;color:#333}
|
|
|
+.task-preview-more{font-size:24rpx;color:#F97316}
|
|
|
+.task-preview-list{display:flex;flex-direction:column}
|
|
|
+.task-preview-item{display:flex;align-items:center;padding:16rpx 0;border-bottom:1rpx solid #f5f5f5}
|
|
|
+.task-preview-item:last-child{border-bottom:none}
|
|
|
+.task-preview-left{flex:1;min-width:0}
|
|
|
+.task-preview-name{font-size:26rpx;color:#333;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
|
+.task-preview-meta{display:flex;align-items:center;gap:12rpx;margin-top:6rpx}
|
|
|
+.task-preview-points{font-size:22rpx;color:#F97316;font-weight:bold}
|
|
|
+.task-preview-deadline{font-size:20rpx;color:#999}
|
|
|
+.task-preview-arrow{font-size:28rpx;color:#ccc;flex-shrink:0;margin-left:12rpx}
|
|
|
/* ===== 五维闭环体系样式 ===== */
|
|
|
.wuxing-section { margin: 0 24rpx 16rpx; background: #fff; border-radius: 20rpx; padding: 24rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06); }
|
|
|
.wuxing-title { font-size: 30rpx; font-weight: bold; color: #333; text-align: center; margin-bottom: 6rpx; }
|