|
@@ -137,6 +137,50 @@
|
|
|
</view>
|
|
</view>
|
|
|
<view v-else>
|
|
<view v-else>
|
|
|
<PageBanner theme="action" tagline="干预 · 记录 · 成长" quote="知行合一,每天进步一点点" />
|
|
<PageBanner theme="action" tagline="干预 · 记录 · 成长" quote="知行合一,每天进步一点点" />
|
|
|
|
|
+ <!-- 里程碑 -->
|
|
|
|
|
+ <view class="section">
|
|
|
|
|
+ <view class="milestone-card">
|
|
|
|
|
+ <text class="section-title-row">🏆 里程碑</text>
|
|
|
|
|
+ <view class="milestone-grid">
|
|
|
|
|
+ <view class="milestone-item">
|
|
|
|
|
+ <text class="milestone-icon">🔥</text>
|
|
|
|
|
+ <text class="milestone-value">{{ streakDays }}天</text>
|
|
|
|
|
+ <text class="milestone-label">连续打卡</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="milestone-item">
|
|
|
|
|
+ <text class="milestone-icon">🎯</text>
|
|
|
|
|
+ <text class="milestone-value">{{ activeChallenges }}</text>
|
|
|
|
|
+ <text class="milestone-label">进行中挑战</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="milestone-item">
|
|
|
|
|
+ <text class="milestone-icon">📈</text>
|
|
|
|
|
+ <text class="milestone-value">{{ completeness }}%</text>
|
|
|
|
|
+ <text class="milestone-label">档案完整度</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- 成长记录 -->
|
|
|
|
|
+ <view class="section">
|
|
|
|
|
+ <view class="survey-card">
|
|
|
|
|
+ <text class="section-title-row">📋 成长记录</text>
|
|
|
|
|
+ <view class="survey-pending" v-if="pendingSurvey">
|
|
|
|
|
+ <text class="survey-alert">⚠ 本周还未完成调研</text>
|
|
|
|
|
+ <text class="survey-title-text">{{ pendingSurvey.title }}</text>
|
|
|
|
|
+ <text class="survey-btn" @click="startSurvey">[开始填写]</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="survey-done" v-else-if="allDone"><text class="survey-done-text">✅ 所有调研已完成</text></view>
|
|
|
|
|
+ <view class="survey-history-list" v-if="surveyHistory.length > 0">
|
|
|
|
|
+ <text class="history-label">历史调研:</text>
|
|
|
|
|
+ <view class="history-item" v-for="(h, hIdx) in surveyHistory" :key="getHistoryKey(h)">
|
|
|
|
|
+ <text class="history-date">{{ h._date }}</text>
|
|
|
|
|
+ <text class="history-content">{{ h._content }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="survey-more" @click="viewAllHistory">查看全部调研 ›</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="survey-empty" v-else-if="!pendingSurvey"><text class="survey-empty-text">暂无待完成调研</text></view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
<view class="reminder-bar" v-if="hasIncomplete">
|
|
<view class="reminder-bar" v-if="hasIncomplete">
|
|
|
<text class="reminder-text">⚠ 今日还有 {{ incompleteCount }} 项未记录</text>
|
|
<text class="reminder-text">⚠ 今日还有 {{ incompleteCount }} 项未记录</text>
|
|
|
<text class="reminder-close" @click="dismissReminder">✕</text>
|
|
<text class="reminder-close" @click="dismissReminder">✕</text>
|
|
@@ -144,7 +188,7 @@
|
|
|
<view class="section">
|
|
<view class="section">
|
|
|
<view class="progress-card">
|
|
<view class="progress-card">
|
|
|
<view class="progress-header">
|
|
<view class="progress-header">
|
|
|
- <text class="progress-title">今日干预</text>
|
|
|
|
|
|
|
+ <text class="progress-title">今日成长</text>
|
|
|
<text class="progress-date">{{ todayDate }}</text>
|
|
<text class="progress-date">{{ todayDate }}</text>
|
|
|
</view>
|
|
</view>
|
|
|
<view class="progress-grid">
|
|
<view class="progress-grid">
|
|
@@ -170,27 +214,6 @@
|
|
|
<text class="action-arrow">›</text>
|
|
<text class="action-arrow">›</text>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="section">
|
|
|
|
|
- <view class="action-card" @click="goToDiet">
|
|
|
|
|
- <text class="action-icon">🍽️</text>
|
|
|
|
|
- <view class="action-info">
|
|
|
|
|
- <text class="action-title">饮食主页</text>
|
|
|
|
|
- <text class="action-desc">今日共餐 · 食材推荐 · 饮食记录</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <text class="action-arrow">›</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="section">
|
|
|
|
|
- <view class="action-card" @click="goToFoods">
|
|
|
|
|
- <text class="action-icon">🥗</text>
|
|
|
|
|
- <view class="action-info">
|
|
|
|
|
- <text class="action-title">饮食推荐</text>
|
|
|
|
|
- <text class="action-desc">基于菌群报告的个性化食材建议</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <text class="action-arrow">›</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
-
|
|
|
|
|
<view class="section">
|
|
<view class="section">
|
|
|
<view class="diet-card">
|
|
<view class="diet-card">
|
|
|
<view class="diet-card-header">
|
|
<view class="diet-card-header">
|
|
@@ -210,43 +233,21 @@
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
- <!-- 推荐文章 -->
|
|
|
|
|
- <view class="section" v-if="healthArticles.length > 0 || growthArticles.length > 0">
|
|
|
|
|
- <view class="rec-section-title">📖 推荐阅读</view>
|
|
|
|
|
- <view class="rec-card" v-for="item in healthArticles" :key="getArticleKey(item)" @click="goToArticle(item.id)">
|
|
|
|
|
- <image class="rec-img" :src="item.coverImage" mode="aspectFill" v-if="item.coverImage"/>
|
|
|
|
|
- <view class="rec-info">
|
|
|
|
|
- <text class="rec-title">{{ item.title }}</text>
|
|
|
|
|
- <text class="rec-desc">{{ item.summary }}</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="rec-card" v-for="item in growthArticles" :key="getArticleKey(item)" @click="goToArticle(item.id)">
|
|
|
|
|
- <image class="rec-img" :src="item.coverImage" mode="aspectFill" v-if="item.coverImage"/>
|
|
|
|
|
- <view class="rec-info">
|
|
|
|
|
- <text class="rec-title">{{ item.title }}</text>
|
|
|
|
|
- <text class="rec-desc">{{ item.summary }}</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
|
|
+ <!-- ===== 推荐商品 ===== -->
|
|
|
|
|
+ <RecommendedFeed
|
|
|
|
|
+ :products="recommendedProducts"
|
|
|
|
|
+ :activities="[]"
|
|
|
|
|
+ :loading="loadingProducts"
|
|
|
|
|
+ @itemClick="onFeedItemClick"
|
|
|
|
|
+ @more="goMoreDiscover" />
|
|
|
|
|
|
|
|
- <!-- 推荐商品 -->
|
|
|
|
|
- <view class="section" v-if="healthProducts.length > 0 || growthProducts.length > 0">
|
|
|
|
|
- <view class="rec-section-title">🛒 推荐商品</view>
|
|
|
|
|
- <view class="rec-product" v-for="item in healthProducts" :key="getProductKey(item)" @click="goToProduct(item.id)">
|
|
|
|
|
- <image class="rec-pimg" :src="item.coverImage" mode="aspectFill"/>
|
|
|
|
|
- <view class="rec-pinfo">
|
|
|
|
|
- <text class="rec-pname">{{ item.name }}</text>
|
|
|
|
|
- <text class="rec-pdesc">{{ item.intro || item.description || '' }}</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="rec-product" v-for="item in growthProducts" :key="getProductKey(item)" @click="goToProduct(item.id)">
|
|
|
|
|
- <image class="rec-pimg" :src="item.coverImage" mode="aspectFill"/>
|
|
|
|
|
- <view class="rec-pinfo">
|
|
|
|
|
- <text class="rec-pname">{{ item.name }}</text>
|
|
|
|
|
- <text class="rec-pdesc">{{ item.intro || item.description || '' }}</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
|
|
+ <!-- ===== 推荐阅读 ===== -->
|
|
|
|
|
+ <ArticleBookshelf
|
|
|
|
|
+ :articles="indexArticles"
|
|
|
|
|
+ :loading="articlesLoading"
|
|
|
|
|
+ :isLoggedIn="isLoggedIn"
|
|
|
|
|
+ @articleClick="goArticleDetail"
|
|
|
|
|
+ @moreArticles="goMoreArticles" />
|
|
|
|
|
|
|
|
<view class="section">
|
|
<view class="section">
|
|
|
<view class="section-title-row">📊 记录概览</view>
|
|
<view class="section-title-row">📊 记录概览</view>
|
|
@@ -269,48 +270,6 @@
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="section">
|
|
|
|
|
- <view class="milestone-card">
|
|
|
|
|
- <text class="section-title-row">🏆 里程碑</text>
|
|
|
|
|
- <view class="milestone-grid">
|
|
|
|
|
- <view class="milestone-item">
|
|
|
|
|
- <text class="milestone-icon">🔥</text>
|
|
|
|
|
- <text class="milestone-value">{{ streakDays }}天</text>
|
|
|
|
|
- <text class="milestone-label">连续打卡</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="milestone-item">
|
|
|
|
|
- <text class="milestone-icon">🎯</text>
|
|
|
|
|
- <text class="milestone-value">{{ activeChallenges }}</text>
|
|
|
|
|
- <text class="milestone-label">进行中挑战</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="milestone-item">
|
|
|
|
|
- <text class="milestone-icon">📈</text>
|
|
|
|
|
- <text class="milestone-value">{{ completeness }}%</text>
|
|
|
|
|
- <text class="milestone-label">档案完整度</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="section">
|
|
|
|
|
- <view class="survey-card">
|
|
|
|
|
- <text class="section-title-row">📋 成长记录</text>
|
|
|
|
|
- <view class="survey-pending" v-if="pendingSurvey">
|
|
|
|
|
- <text class="survey-alert">⚠ 本周还未完成调研</text>
|
|
|
|
|
- <text class="survey-title-text">{{ pendingSurvey.title }}</text>
|
|
|
|
|
- <text class="survey-btn" @click="startSurvey">[开始填写]</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="survey-done" v-else-if="allDone"><text class="survey-done-text">✅ 所有调研已完成</text></view>
|
|
|
|
|
- <view class="survey-history-list" v-if="surveyHistory.length > 0">
|
|
|
|
|
- <text class="history-label">历史调研:</text>
|
|
|
|
|
- <view class="history-item" v-for="(h, hIdx) in surveyHistory" :key="getHistoryKey(h)">
|
|
|
|
|
- <text class="history-date">{{ h._date }}</text>
|
|
|
|
|
- <text class="history-content">{{ h._content }}</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <text class="survey-more" @click="viewAllHistory">查看全部调研 ›</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="survey-empty" v-else-if="!pendingSurvey"><text class="survey-empty-text">暂无待完成调研</text></view>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
<DimensionActivities :isLoggedIn="true" @activityClick="goActivityDetail" @moreActivities="goMoreActivities" style="margin-bottom:60rpx" />
|
|
<DimensionActivities :isLoggedIn="true" @activityClick="goActivityDetail" @moreActivities="goMoreActivities" style="margin-bottom:60rpx" />
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
@@ -319,17 +278,27 @@
|
|
|
import PageBanner from '../../components/PageBanner.vue'
|
|
import PageBanner from '../../components/PageBanner.vue'
|
|
|
import LoginGuideCard from '../../components/LoginGuideCard.vue'
|
|
import LoginGuideCard from '../../components/LoginGuideCard.vue'
|
|
|
import DimensionActivities from '../../components/DimensionActivities.vue'
|
|
import DimensionActivities from '../../components/DimensionActivities.vue'
|
|
|
-import { healthCheckinList, getDietDailyRecords, getDietIngredients, getSurveyStatus, getSurveyHistory, getFoodCautionList, getGrowthRecommendations, getExerciseList, getMindCheckinList } from '../../utils/api.js'
|
|
|
|
|
|
|
+import RecommendedFeed from '../../components/RecommendedFeed.vue'
|
|
|
|
|
+import ArticleBookshelf from '../../components/ArticleBookshelf.vue'
|
|
|
|
|
+import { healthCheckinList, getDietIngredients, getSurveyStatus, getSurveyHistory, getFoodCautionList, getExerciseList, getMindCheckinList, getSleepList, getHealthMealList, productList, getFeaturedArticles } from '../../utils/api.js'
|
|
|
export default {
|
|
export default {
|
|
|
- components: { PageBanner, LoginGuideCard, DimensionActivities },
|
|
|
|
|
|
|
+ components: { PageBanner, LoginGuideCard, DimensionActivities, RecommendedFeed, ArticleBookshelf },
|
|
|
data() { return { memberId: '', todayDate: '', hasIncomplete: false, incompleteCount: 0, progressItems: [], trackingTabs: [{ key: 'diet', label: '饮食', icon: '🍽️' }, { key: 'exercise', label: '运动', icon: '🏃' }, { key: 'sleep', label: '睡眠', icon: '😴' }, { key: 'emotion', label: '心情', icon: '😊' }], trackingData: { diet: [], exercise: [], sleep: [], emotion: [] }, streakDays: 0, activeChallenges: 0, completeness: 0, cautionCount: 0,
|
|
data() { return { memberId: '', todayDate: '', hasIncomplete: false, incompleteCount: 0, progressItems: [], trackingTabs: [{ key: 'diet', label: '饮食', icon: '🍽️' }, { key: 'exercise', label: '运动', icon: '🏃' }, { key: 'sleep', label: '睡眠', icon: '😴' }, { key: 'emotion', label: '心情', icon: '😊' }], trackingData: { diet: [], exercise: [], sleep: [], emotion: [] }, streakDays: 0, activeChallenges: 0, completeness: 0, cautionCount: 0,
|
|
|
- healthArticles: [],
|
|
|
|
|
- healthProducts: [],
|
|
|
|
|
- growthArticles: [],
|
|
|
|
|
- growthProducts: [],
|
|
|
|
|
pendingSurvey: null, allDone: false, surveyHistory: [], isLoggedIn: false,
|
|
pendingSurvey: null, allDone: false, surveyHistory: [], isLoggedIn: false,
|
|
|
ingredients: [],
|
|
ingredients: [],
|
|
|
- ingredientsLoading: false } },
|
|
|
|
|
|
|
+ ingredientsLoading: false,
|
|
|
|
|
+ // 推荐商品 + 推荐阅读(与首页 parent-index 一致)
|
|
|
|
|
+ recommendedProducts: [],
|
|
|
|
|
+ loadingProducts: false,
|
|
|
|
|
+ indexArticles: [],
|
|
|
|
|
+ articlesLoading: false,
|
|
|
|
|
+ gradientColors: [
|
|
|
|
|
+ 'linear-gradient(135deg, #6366F1, #818CF8)',
|
|
|
|
|
+ 'linear-gradient(135deg, #8B5CF6, #A78BFA)',
|
|
|
|
|
+ 'linear-gradient(135deg, #5B9BD5, #8FC5E8)',
|
|
|
|
|
+ 'linear-gradient(135deg, #10B981, #34D399)',
|
|
|
|
|
+ 'linear-gradient(135deg, #F97316, #FB923C)'
|
|
|
|
|
+ ] } },
|
|
|
computed: {
|
|
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 },
|
|
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 }
|
|
totalCount: function() { return this.progressItems.length }
|
|
@@ -349,8 +318,6 @@ export default {
|
|
|
getRecordKey: function(rec) { return rec && rec._text ? rec._text + rec._content : 'r-' + Math.random() },
|
|
getRecordKey: function(rec) { return rec && rec._text ? rec._text + rec._content : 'r-' + Math.random() },
|
|
|
getIngredientKey: function(item, index) { return 'ing-' + (item.id || index) },
|
|
getIngredientKey: function(item, index) { return 'ing-' + (item.id || index) },
|
|
|
getHistoryKey: function(h) { return h && h._date ? h._date + h._content : 'h-' + Math.random() },
|
|
getHistoryKey: function(h) { return h && h._date ? h._date + h._content : 'h-' + Math.random() },
|
|
|
- getArticleKey: function(item) { return item && item.id ? 'a' + item.id : 'a-' + Math.random() },
|
|
|
|
|
- getProductKey: function(item) { return item && item.id ? 'p' + item.id : 'p-' + Math.random() },
|
|
|
|
|
dismissReminder: function() { this.hasIncomplete = false },
|
|
dismissReminder: function() { this.hasIncomplete = false },
|
|
|
viewAllRecordsByType: function(key) {
|
|
viewAllRecordsByType: function(key) {
|
|
|
var m = { diet: '/pages/health/diet-index', exercise: '/pages/health/exercise-index', sleep: '/pages/health/sleep-index', emotion: '/pages/mind-detail/emotion-checkin' }
|
|
var m = { diet: '/pages/health/diet-index', exercise: '/pages/health/exercise-index', sleep: '/pages/health/sleep-index', emotion: '/pages/mind-detail/emotion-checkin' }
|
|
@@ -372,53 +339,143 @@ export default {
|
|
|
handleGuestFeatureTap: function() { uni.showToast({ title: '登录后即可体验该功能', icon: 'none' }) },
|
|
handleGuestFeatureTap: function() { uni.showToast({ title: '登录后即可体验该功能', icon: 'none' }) },
|
|
|
goToCaution: function() { uni.navigateTo({ url: '/pages/growth/caution-detail' }) },
|
|
goToCaution: function() { uni.navigateTo({ url: '/pages/growth/caution-detail' }) },
|
|
|
goToDiet: function() { uni.navigateTo({ url: '/pages/diet/index' }) },
|
|
goToDiet: function() { uni.navigateTo({ url: '/pages/diet/index' }) },
|
|
|
- goToFoods: function() { uni.navigateTo({ url: '/pages/growth/foods-detail' }) },
|
|
|
|
|
- goToArticle: function(id) { uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id }) },
|
|
|
|
|
- goToProduct: function(id) { uni.navigateTo({ url: '/pages/shop/detail/detail?id=' + id }) },
|
|
|
|
|
goPage: function(url) { uni.navigateTo({ url: url }) },
|
|
goPage: function(url) { uni.navigateTo({ url: url }) },
|
|
|
|
|
+ // ===== 推荐商品 + 推荐阅读(与首页 parent-index 一致) =====
|
|
|
|
|
+ onFeedItemClick: function(item) {
|
|
|
|
|
+ if (item && item.type === 'product' && item.id) {
|
|
|
|
|
+ uni.navigateTo({ url: '/pages/discover-detail/product-detail/product-detail?id=' + item.id })
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ goMoreDiscover: function() {
|
|
|
|
|
+ uni.navigateTo({ url: '/pages/shop/index/index' })
|
|
|
|
|
+ },
|
|
|
|
|
+ goArticleDetail: function(articleOrId) {
|
|
|
|
|
+ var id = typeof articleOrId === 'object' ? articleOrId.id : articleOrId
|
|
|
|
|
+ if (id) uni.navigateTo({ url: '/pages/article-center/article-detail?id=' + id })
|
|
|
|
|
+ },
|
|
|
|
|
+ goMoreArticles: function() {
|
|
|
|
|
+ uni.navigateTo({ url: '/pages/article-center/index' })
|
|
|
|
|
+ },
|
|
|
async loadAllData() {
|
|
async loadAllData() {
|
|
|
var self = this
|
|
var self = this
|
|
|
self.loadProgressItems()
|
|
self.loadProgressItems()
|
|
|
self.loadSurveyData()
|
|
self.loadSurveyData()
|
|
|
- self.loadGrowthRecommendations()
|
|
|
|
|
|
|
+ self.loadRecommendedProducts()
|
|
|
|
|
+ self.loadFeaturedArticles()
|
|
|
self.loadCautionData()
|
|
self.loadCautionData()
|
|
|
self.loadMilestones()
|
|
self.loadMilestones()
|
|
|
self.loadDietIngredients()
|
|
self.loadDietIngredients()
|
|
|
},
|
|
},
|
|
|
|
|
+ loadRecommendedProducts: function() {
|
|
|
|
|
+ var self = this
|
|
|
|
|
+ self.loadingProducts = true
|
|
|
|
|
+ productList({ page: 1, size: 6 }).then(function(res) {
|
|
|
|
|
+ self.loadingProducts = false
|
|
|
|
|
+ if (res && res.code === 200 && res.data) {
|
|
|
|
|
+ var list = res.data.records || []
|
|
|
|
|
+ self.recommendedProducts = list.map(function(p) {
|
|
|
|
|
+ p.type = 'product'
|
|
|
|
|
+ return p
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(function() {
|
|
|
|
|
+ self.loadingProducts = false
|
|
|
|
|
+ self.recommendedProducts = []
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ loadFeaturedArticles: function() {
|
|
|
|
|
+ var self = this
|
|
|
|
|
+ self.articlesLoading = true
|
|
|
|
|
+ getFeaturedArticles({ size: 5 }).then(function(res) {
|
|
|
|
|
+ self.articlesLoading = false
|
|
|
|
|
+ if (res && res.code === 200) {
|
|
|
|
|
+ var rawList = res.data && (Array.isArray(res.data) ? res.data : (res.data.data || res.data.records || []))
|
|
|
|
|
+ var list = Array.isArray(rawList) ? rawList : []
|
|
|
|
|
+ self.indexArticles = list.map(function(item, index) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ id: item.id,
|
|
|
|
|
+ category: item.categoryName || item.category || '热门文章',
|
|
|
|
|
+ categoryColor: self.gradientColors[index % self.gradientColors.length],
|
|
|
|
|
+ title: item.title || '',
|
|
|
|
|
+ summary: item.summary || '',
|
|
|
|
|
+ views: item.viewCount ? String(item.viewCount) : '0',
|
|
|
|
|
+ date: item.publishedAt ? item.publishedAt.slice(0, 10) : '',
|
|
|
|
|
+ coverImage: item.coverImage
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(function() {
|
|
|
|
|
+ self.articlesLoading = false
|
|
|
|
|
+ self.indexArticles = []
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
async loadProgressItems() {
|
|
async loadProgressItems() {
|
|
|
var self = this
|
|
var self = this
|
|
|
var items = []
|
|
var items = []
|
|
|
- var checkinDone = false
|
|
|
|
|
- try {
|
|
|
|
|
- var ciRes = await healthCheckinList({ yearMonth: self.todayDate.substring(0, 7) })
|
|
|
|
|
- if (ciRes.code === 200 && ciRes.data) {
|
|
|
|
|
- for (var ci = 0; ci < ciRes.data.length; ci++) { if (ciRes.data[ci] && ciRes.data[ci].checkinDate && ciRes.data[ci].checkinDate.substring(0, 10) === self.todayDate) { checkinDone = true; break } }
|
|
|
|
|
- }
|
|
|
|
|
- } catch(e) {}
|
|
|
|
|
- items.push({ key: 'checkin', icon: '✅', label: '今日打卡', done: checkinDone, actionText: '打卡' })
|
|
|
|
|
var dietDone = false
|
|
var dietDone = false
|
|
|
try {
|
|
try {
|
|
|
- var dRes = await getDietDailyRecords({ date: self.todayDate })
|
|
|
|
|
- if (dRes.code === 200 && dRes.data && dRes.data.length > 0) dietDone = true
|
|
|
|
|
|
|
+ var dRes = await getHealthMealList({ memberId: self.memberId })
|
|
|
|
|
+ if (dRes.code === 200 && dRes.data && dRes.data.length > 0) {
|
|
|
|
|
+ for (var dm = 0; dm < dRes.data.length; dm++) {
|
|
|
|
|
+ var dRec = dRes.data[dm]
|
|
|
|
|
+ if (!dRec) continue
|
|
|
|
|
+ var dDate = dRec.createdAt
|
|
|
|
|
+ if (dDate instanceof Date) dDate = dDate.toISOString().substring(0, 10)
|
|
|
|
|
+ else if (typeof dDate === 'string') dDate = dDate.substring(0, 10)
|
|
|
|
|
+ else continue
|
|
|
|
|
+ if (dDate === self.todayDate) { dietDone = true; break }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
} catch(e) {}
|
|
} catch(e) {}
|
|
|
items.push({ key: 'diet', icon: '🍽️', label: '饮食记录', done: dietDone, actionText: '补录' })
|
|
items.push({ key: 'diet', icon: '🍽️', label: '饮食记录', done: dietDone, actionText: '补录' })
|
|
|
var exerciseDone = false
|
|
var exerciseDone = false
|
|
|
try {
|
|
try {
|
|
|
- var exRes = await getExerciseList({})
|
|
|
|
|
|
|
+ var exRes = await getExerciseList({ memberId: self.memberId })
|
|
|
if (exRes.code === 200 && exRes.data && exRes.data.length > 0) {
|
|
if (exRes.code === 200 && exRes.data && exRes.data.length > 0) {
|
|
|
- for (var ex = 0; ex < exRes.data.length; ex++) { var exRec = exRes.data[ex]; if (exRec && exRec.startTime && typeof exRec.startTime === 'string' && exRec.startTime.substring(0, 10) === self.todayDate) { exerciseDone = true; break } }
|
|
|
|
|
|
|
+ for (var ex = 0; ex < exRes.data.length; ex++) {
|
|
|
|
|
+ var exRec = exRes.data[ex]
|
|
|
|
|
+ if (!exRec) continue
|
|
|
|
|
+ var exDate = exRec.createdAt
|
|
|
|
|
+ if (exDate instanceof Date) exDate = exDate.toISOString().substring(0, 10)
|
|
|
|
|
+ else if (typeof exDate === 'string') exDate = exDate.substring(0, 10)
|
|
|
|
|
+ else continue
|
|
|
|
|
+ if (exDate === self.todayDate) { exerciseDone = true; break }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
} catch(e) {}
|
|
} catch(e) {}
|
|
|
items.push({ key: 'exercise', icon: '🏃', label: '运动记录', done: exerciseDone, actionText: '记录' })
|
|
items.push({ key: 'exercise', icon: '🏃', label: '运动记录', done: exerciseDone, actionText: '记录' })
|
|
|
|
|
+ var sleepDone = false
|
|
|
|
|
+ try {
|
|
|
|
|
+ var slRes = await getSleepList({ memberId: self.memberId })
|
|
|
|
|
+ if (slRes.code === 200 && slRes.data && slRes.data.length > 0) {
|
|
|
|
|
+ for (var sl = 0; sl < slRes.data.length; sl++) {
|
|
|
|
|
+ var slRec = slRes.data[sl]
|
|
|
|
|
+ if (!slRec) continue
|
|
|
|
|
+ var slDate = slRec.createdAt
|
|
|
|
|
+ if (slDate instanceof Date) slDate = slDate.toISOString().substring(0, 10)
|
|
|
|
|
+ else if (typeof slDate === 'string') slDate = slDate.substring(0, 10)
|
|
|
|
|
+ else continue
|
|
|
|
|
+ if (slDate === self.todayDate) { sleepDone = true; break }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch(e) {}
|
|
|
|
|
+ items.push({ key: 'sleep', icon: '😴', label: '睡眠记录', done: sleepDone, actionText: '记录' })
|
|
|
var emotionDone = false
|
|
var emotionDone = false
|
|
|
try {
|
|
try {
|
|
|
- var emRes = await getMindCheckinList({ page: 1, size: 20 })
|
|
|
|
|
|
|
+ var emRes = await getMindCheckinList({ page: 1, size: 20, memberId: self.memberId })
|
|
|
if (emRes.code === 200 && emRes.data && emRes.data.length > 0) {
|
|
if (emRes.code === 200 && emRes.data && emRes.data.length > 0) {
|
|
|
- for (var em = 0; em < emRes.data.length; em++) { var emRec = emRes.data[em]; if (emRec && emRec.checkinDate && typeof emRec.checkinDate === 'string' && emRec.checkinDate.substring(0, 10) === self.todayDate) { emotionDone = true; break } }
|
|
|
|
|
|
|
+ for (var em = 0; em < emRes.data.length; em++) {
|
|
|
|
|
+ var emRec = emRes.data[em]
|
|
|
|
|
+ if (!emRec) continue
|
|
|
|
|
+ var emDate = emRec.checkinDate
|
|
|
|
|
+ if (emDate instanceof Date) emDate = emDate.toISOString().substring(0, 10)
|
|
|
|
|
+ else if (typeof emDate === 'string') emDate = emDate.substring(0, 10)
|
|
|
|
|
+ else continue
|
|
|
|
|
+ if (emDate === self.todayDate) { emotionDone = true; break }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
} catch(e) {}
|
|
} catch(e) {}
|
|
|
items.push({ key: 'emotion', icon: '😊', label: '心情记录', done: emotionDone, actionText: '记录' })
|
|
items.push({ key: 'emotion', icon: '😊', label: '心情记录', done: emotionDone, actionText: '记录' })
|
|
|
- items.push({ key: 'survey', icon: '📋', label: '本周调研', done: self.allDone, actionText: self.allDone ? '' : '开始' })
|
|
|
|
|
self.progressItems = items.filter(function(it) { return it && it.key })
|
|
self.progressItems = items.filter(function(it) { return it && it.key })
|
|
|
self.incompleteCount = 0
|
|
self.incompleteCount = 0
|
|
|
for (var pi = 0; pi < items.length; pi++) if (items[pi] && !items[pi].done) self.incompleteCount++
|
|
for (var pi = 0; pi < items.length; pi++) if (items[pi] && !items[pi].done) self.incompleteCount++
|
|
@@ -443,21 +500,6 @@ export default {
|
|
|
}
|
|
}
|
|
|
} catch(e) {}
|
|
} catch(e) {}
|
|
|
},
|
|
},
|
|
|
- async loadGrowthRecommendations() {
|
|
|
|
|
- var self = this
|
|
|
|
|
- try {
|
|
|
|
|
- var res = await getGrowthRecommendations('health', 6)
|
|
|
|
|
- if (res && res.code === 200 && res.data) {
|
|
|
|
|
- var arts = res.data.articles || []
|
|
|
|
|
- var prods = res.data.products || []
|
|
|
|
|
- // 按 growth_category 分组
|
|
|
|
|
- self.healthArticles = arts.filter(function(a){ return a.growthCategory === 'health' })
|
|
|
|
|
- self.healthProducts = prods.filter(function(p){ return p.growthCategory === 'health' })
|
|
|
|
|
- self.growthArticles = arts.filter(function(a){ return a.growthCategory === 'growth' })
|
|
|
|
|
- self.growthProducts = prods.filter(function(p){ return p.growthCategory === 'growth' })
|
|
|
|
|
- }
|
|
|
|
|
- } catch(e) {}
|
|
|
|
|
- },
|
|
|
|
|
async loadCautionData() {
|
|
async loadCautionData() {
|
|
|
var self = this
|
|
var self = this
|
|
|
try {
|
|
try {
|
|
@@ -522,20 +564,6 @@ export default {
|
|
|
.action-title{font-size:28rpx;font-weight:600;color:#333;display:block}
|
|
.action-title{font-size:28rpx;font-weight:600;color:#333;display:block}
|
|
|
.action-desc{font-size:22rpx;color:#888;margin-top:4rpx;display:block}
|
|
.action-desc{font-size:22rpx;color:#888;margin-top:4rpx;display:block}
|
|
|
.action-arrow{font-size:32rpx;color:#ccc}
|
|
.action-arrow{font-size:32rpx;color:#ccc}
|
|
|
-/* 成长推荐卡片 */
|
|
|
|
|
-.rec-section-title{font-size:28rpx;font-weight:600;color:#333;padding:20rpx 28rpx 8rpx}
|
|
|
|
|
-.rec-card{display:flex;background:#fff;border-radius:16rpx;margin:0 24rpx 12rpx;padding:16rpx;box-shadow:0 2rpx 8rpx rgba(0,0,0,0.06)}
|
|
|
|
|
-.rec-card:active{opacity:0.85}
|
|
|
|
|
-.rec-img{width:160rpx;height:110rpx;border-radius:12rpx;flex-shrink:0;margin-right:16rpx;background:#f5f5f5}
|
|
|
|
|
-.rec-info{flex:1;min-width:0}
|
|
|
|
|
-.rec-title{font-size:26rpx;font-weight:600;color:#333;display:block;margin-bottom:6rpx;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
|
|
|
-.rec-desc{font-size:22rpx;color:#888;display:block;line-height:1.5;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
|
|
|
|
|
-.rec-product{display:flex;background:#fff;border-radius:16rpx;margin:0 24rpx 12rpx;padding:16rpx;box-shadow:0 2rpx 8rpx rgba(0,0,0,0.06)}
|
|
|
|
|
-.rec-product:active{opacity:0.85}
|
|
|
|
|
-.rec-pimg{width:140rpx;height:140rpx;border-radius:12rpx;flex-shrink:0;margin-right:16rpx;background:#f5f5f5}
|
|
|
|
|
-.rec-pinfo{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}
|
|
|
|
|
-.rec-pname{font-size:26rpx;font-weight:600;color:#333;display:block;margin-bottom:6rpx;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
|
|
|
-.rec-pdesc{font-size:22rpx;color:#888;display:block;line-height:1.5;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
|
|
|
|
|
/* 登录后原有样式 */
|
|
/* 登录后原有样式 */
|
|
|
.reminder-bar{margin:12rpx 24rpx;background:#FFF3E0;border:1rpx solid #FFB74D;border-radius:12rpx;padding:14rpx 20rpx;display:flex;align-items:center;justify-content:space-between}
|
|
.reminder-bar{margin:12rpx 24rpx;background:#FFF3E0;border:1rpx solid #FFB74D;border-radius:12rpx;padding:14rpx 20rpx;display:flex;align-items:center;justify-content:space-between}
|
|
|
.reminder-text{font-size:24rpx;color:#E65100}
|
|
.reminder-text{font-size:24rpx;color:#E65100}
|
|
@@ -544,8 +572,8 @@ export default {
|
|
|
.progress-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16rpx}
|
|
.progress-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:16rpx}
|
|
|
.progress-title{font-size:28rpx;font-weight:bold;color:#333}
|
|
.progress-title{font-size:28rpx;font-weight:bold;color:#333}
|
|
|
.progress-date{font-size:22rpx;color:#999}
|
|
.progress-date{font-size:22rpx;color:#999}
|
|
|
-.progress-grid{display:flex;flex-wrap:wrap;gap:12rpx}
|
|
|
|
|
-.progress-grid-item{width:calc(33.33% - 8rpx);box-sizing:border-box;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#FFF7ED;border-radius:16rpx;padding:20rpx 12rpx;border:1rpx solid rgba(249,115,22,0.12)}
|
|
|
|
|
|
|
+.progress-grid{display:flex}
|
|
|
|
|
+.progress-grid-item{flex:1;box-sizing:border-box;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#FFF7ED;border-radius:16rpx;padding:20rpx 8rpx;border:1rpx solid rgba(249,115,22,0.12)}
|
|
|
.progress-grid-item:active{opacity:0.85;background:#FFEDD5}
|
|
.progress-grid-item:active{opacity:0.85;background:#FFEDD5}
|
|
|
.progress-grid-icon{font-size:40rpx;margin-bottom:8rpx}
|
|
.progress-grid-icon{font-size:40rpx;margin-bottom:8rpx}
|
|
|
.progress-grid-label{font-size:24rpx;color:#333;margin-bottom:8rpx;text-align:center}
|
|
.progress-grid-label{font-size:24rpx;color:#333;margin-bottom:8rpx;text-align:center}
|