Browse Source

fix(frontend): health-main 移除已删除报告入口 + growth-emotion-checkin 添加照片上传

liaoxg 2 months ago
parent
commit
db5cd6253b

+ 13 - 3
cfc-backend/src/main/java/com/etotem/cfc/service/UnlockGateService.java

@@ -145,17 +145,27 @@ public class UnlockGateService {
     }
     }
 
 
     /**
     /**
-     * 家庭级判据:family 内任一维度能量值有值(>0)即解锁首页能量沙盘。
+     * 家庭级判据:family 内任一成员做过五维自检,或任一维度能量值有值(>0),即解锁首页能量沙盘。
      * 放宽自改进前的"须做完五维自检":做过任一测评/上传报告/完成任务,只要任一经落库为
      * 放宽自改进前的"须做完五维自检":做过任一测评/上传报告/完成任务,只要任一经落库为
      * five_dimension_score 的能量维度 >0,即可展示沙盘。
      * five_dimension_score 的能量维度 >0,即可展示沙盘。
      */
      */
     public boolean hasFamilySelfCheck(Long familyId) {
     public boolean hasFamilySelfCheck(Long familyId) {
         if (familyId == null) return false;
         if (familyId == null) return false;
-        long count = fiveDimensionScoreMapper.selectCount(
+        // 来源1:五维自检记录(five_dimension_self_checks)
+        List<User> familyUsers = userMapper.selectList(
+                new LambdaQueryWrapper<User>().eq(User::getFamilyId, familyId));
+        if (!familyUsers.isEmpty()) {
+            List<Long> userIds = familyUsers.stream().map(User::getId).collect(Collectors.toList());
+            long selfCheckCount = selfCheckMapper.selectCount(
+                    new LambdaQueryWrapper<FiveDimensionSelfCheck>().in(FiveDimensionSelfCheck::getUserId, userIds));
+            if (selfCheckCount >= 1) return true;
+        }
+        // 来源2:任一维度能量快照 >0(five_dimension_score)
+        long scoreCount = fiveDimensionScoreMapper.selectCount(
                 new LambdaQueryWrapper<FiveDimensionScore>()
                 new LambdaQueryWrapper<FiveDimensionScore>()
                         .eq(FiveDimensionScore::getFamilyId, familyId)
                         .eq(FiveDimensionScore::getFamilyId, familyId)
                         .gt(FiveDimensionScore::getScore, 0));
                         .gt(FiveDimensionScore::getScore, 0));
-        return count >= 1;
+        return scoreCount >= 1;
     }
     }
 
 
     // ========== 当前锁定关卡 ==========
     // ========== 当前锁定关卡 ==========

+ 43 - 43
cfc-frontend/pages/growth/growth-emotion-checkin.vue

@@ -38,12 +38,52 @@
         </view>
         </view>
       </view>
       </view>
 
 
-      <!-- 文字记录 -->
+      <!-- 文字记录 + 媒体附件 -->
       <view class="card">
       <view class="card">
         <view class="card-accent"></view>
         <view class="card-accent"></view>
         <view class="card-body">
         <view class="card-body">
           <text class="card-title">✍️ 文字记录</text>
           <text class="card-title">✍️ 文字记录</text>
           <textarea class="note-input" v-model="note" placeholder="今天发生了什么?说说你的感受..." maxlength="500" />
           <textarea class="note-input" v-model="note" placeholder="今天发生了什么?说说你的感受..." maxlength="500" />
+          <!-- 并排两个按钮 + 展开区域 -->
+          <view class="media-toolbar">
+            <view class="tool-btn" @tap="choosePhoto">
+              <text class="tool-icon">📷</text>
+              <text class="tool-label">上传照片</text>
+              <text class="tool-count" v-if="photos.length > 0">{{ photos.length }}/9</text>
+            </view>
+            <view class="tool-divider"></view>
+            <view class="tool-btn" @tap="toggleRecord">
+              <text class="tool-icon">🎙</text>
+              <text class="tool-label">{{ isRecording ? '录音中…' : (voicePath ? '已录制' : '录制音频') }}</text>
+              <text class="tool-count" v-if="isRecording">{{ recordSeconds }}s</text>
+            </view>
+          </view>
+          <!-- 照片缩略图 -->
+          <view class="photo-strip" v-if="photos.length > 0">
+            <view class="photo-item" v-for="(img, idx) in photos" :key="getPhotoKey(img, idx)" @tap="removePhoto(idx)">
+              <image :src="img" mode="aspectFill" class="photo-img"/>
+              <view class="photo-delete-overlay">
+                <text class="delete-icon">×</text>
+              </view>
+            </view>
+          </view>
+          <!-- 录音状态 -->
+          <view class="voice-strip" v-if="isRecording">
+            <view class="waveform">
+              <view class="wave-bar" v-for="n in 7" :key="n" :style="{animationDelay: (n * 0.1) + 's'}"></view>
+            </view>
+            <view class="voice-controls">
+              <view class="mini-btn cancel-mini" @tap="cancelRecord"><text>取消</text></view>
+              <view class="mini-btn done-mini" @tap="finishRecord"><text>完成</text></view>
+            </view>
+          </view>
+          <view class="voice-strip" v-else-if="voicePath">
+            <view class="voice-player">
+              <text class="play-icon">▶</text>
+              <text class="voice-duration">{{ recordDurationText }}</text>
+            </view>
+            <view class="delete-voice" @tap="deleteVoice"><text>×</text></view>
+          </view>
         </view>
         </view>
       </view>
       </view>
 
 
@@ -63,53 +103,14 @@
         <view class="card-accent"></view>
         <view class="card-accent"></view>
         <view class="card-body">
         <view class="card-body">
           <text class="card-title">近期心情</text>
           <text class="card-title">近期心情</text>
-          <view class="history-list">
+<view class="history-list">
             <view class="history-item" v-for="item in history" :key="item.id">
             <view class="history-item" v-for="item in history" :key="item.id">
               <view class="history-left">
               <view class="history-left">
                 <text class="history-type">{{ emotionIcon(item.emotionType) }} {{ emotionLabel(item.emotionType) }}</text>
                 <text class="history-type">{{ emotionIcon(item.emotionType) }} {{ emotionLabel(item.emotionType) }}</text>
                 <text class="history-content">{{ item.note || '-' }}</text>
                 <text class="history-content">{{ item.note || '-' }}</text>
-<!-- 并排两个按钮 + 展开区域 -->
-            <view class="media-toolbar">
-              <view class="tool-btn" @tap="choosePhoto">
-                <text class="tool-icon">📷</text>
-                <text class="tool-label">上传照片</text>
-                <text class="tool-count" v-if="photos.length > 0">{{ photos.length }}/9</text>
-              </view>
-              <view class="tool-divider"></view>
-              <view class="tool-btn" @tap="toggleRecord">
-                <text class="tool-icon">🎙</text>
-                <text class="tool-label">{{ isRecording ? '录音中…' : (voicePath ? '已录制' : '录制音频') }}</text>
-                <text class="tool-count" v-if="isRecording">{{ recordSeconds }}s</text>
-              </view>
-            </view>
-            <!-- 照片缩略图 -->
-            <view class="photo-strip" v-if="photos.length > 0">
-              <view class="photo-item" v-for="(img, idx) in photos" :key="getPhotoKey(img, idx)" @tap="removePhoto(idx)">
-                <image :src="img" mode="aspectFill" class="photo-img"/>
-                <view class="photo-delete-overlay">
-                  <text class="delete-icon">×</text>
-                </view>
-              </view>
-            </view>
-            <!-- 录音状态 -->
-            <view class="voice-strip" v-if="isRecording">
-              <view class="waveform">
-                <view class="wave-bar" v-for="n in 7" :key="n" :style="{animationDelay: (n * 0.1) + 's'}"></view>
-              </view>
-              <view class="voice-controls">
-                <view class="mini-btn cancel-mini" @tap="cancelRecord"><text>取消</text></view>
-                <view class="mini-btn done-mini" @tap="finishRecord"><text>完成</text></view>
+                <text class="history-date">{{ formatDate(item.createdAt) }}</text>
               </view>
               </view>
             </view>
             </view>
-            <view class="voice-strip" v-else-if="voicePath">
-              <view class="voice-player">
-                <text class="play-icon">▶</text>
-                <text class="voice-duration">{{ recordDurationText }}</text>
-              </view>
-              <view class="delete-voice" @tap="deleteVoice"><text>×</text></view>
-            </view>
-              <text class="history-date">{{ formatDate(item.createdAt) }}</text>
-            </view>
           </view>
           </view>
         </view>
         </view>
       </view>
       </view>
@@ -234,7 +235,6 @@ export default {
     removePhoto: function(idx) {
     removePhoto: function(idx) {
       this.photos.splice(idx, 1)
       this.photos.splice(idx, 1)
     },
     },
-    }, 
     cancelRecord: function() {
     cancelRecord: function() {
       this.recorderManager.stop()
       this.recorderManager.stop()
       this.voicePath = ''
       this.voicePath = ''

+ 7 - 9
cfc-frontend/pages/health-main/index.vue

@@ -177,14 +177,11 @@
       </view>
       </view>
 
 
       <view class="section section-data-collect">
       <view class="section section-data-collect">
-        <view class="data-card" @click="goPage('/pages/health/report-upload')">
-          <view class="data-card-icon" style="background:rgba(249,115,22,0.12)"><text>📋</text></view>
-          <view class="data-card-info">
-            <text class="data-card-title">上传健康报告</text>
-            <text class="data-card-desc">体检/肠道/舌诊报告 · 解读</text>
-          </view>
-          <text class="data-card-arrow">›</text>
-        </view>
+        <ReportUploadCard
+          title="上传报告"
+          desc="体检报告 · 菌群检测 · 认知测评 · 心理测评 · 情绪打卡"
+          :tags="['体检报告', '菌群检测', '认知测评', '心理测评', '情绪打卡']"
+          @click="goPage('/pages/health/report-upload')" />
 
 
         <view class="data-card data-card-assessment">
         <view class="data-card data-card-assessment">
           <view class="data-card-head">
           <view class="data-card-head">
@@ -250,10 +247,11 @@
 import LoginGuideCard from '../../components/LoginGuideCard.vue'
 import LoginGuideCard from '../../components/LoginGuideCard.vue'
 import RadarChart from '../../components/RadarChart.vue'
 import RadarChart from '../../components/RadarChart.vue'
 import ArticleBookshelf from '../../components/ArticleBookshelf.vue'
 import ArticleBookshelf from '../../components/ArticleBookshelf.vue'
+import ReportUploadCard from '../../components/report-upload-card.vue'
 import { parseDate } from '../../utils/format.js'
 import { parseDate } from '../../utils/format.js'
 
 
 export default {
 export default {
-  components: { LoginGuideCard, RadarChart, ArticleBookshelf },
+  components: { LoginGuideCard, RadarChart, ArticleBookshelf, ReportUploadCard },
   data() {
   data() {
     return {
     return {
       isLoggedIn: false,
       isLoggedIn: false,

BIN
docs/参考资料/方案/胰腺炎糖尿病进阶方案.docx


BIN
docs/参考资料/方案/胰腺炎糖尿病进阶方案.pdf