Răsfoiți Sursa

菌群检测问题

jiapu 1 săptămână în urmă
părinte
comite
dd69a51be5

+ 1 - 0
cfc-backend/src/main/java/com/etotem/cfc/controller/HealthReportController.java

@@ -716,6 +716,7 @@ public class HealthReportController {
         result.put("parseMethod", draft.getParseMethod());
         result.put("parseError", draft.getParseError());
         result.put("reportId", draft.getConfirmedReportId());
+        result.put("reportType", draft.getReportType());
         return Result.success(result);
     }
 

+ 1 - 0
cfc-frontend/config.js

@@ -20,6 +20,7 @@ try {
     switch (env) {
       case 'develop':
         //API_BASE_URL = 'http://cfc.iwintrue.com'
+        //API_BASE_URL = 'http://192.168.1.57:9082'
         API_BASE_URL = 'https://cfc.etotem.com.cn'
         break
       case 'trial':

+ 7 - 1
cfc-frontend/pages/health/report-list.vue

@@ -145,9 +145,15 @@ export default {
     },
     loadCollectingReports() {
       var self = this
+      var prevCount = self.collectingReports.length
       getCollectingReports().then(function(res) {
         if (res.code === 200) {
-          self.collectingReports = res.data || []
+          var list = res.data || []
+          self.collectingReports = list
+          // 采集卡片消失后刷新列表,让刚入库的报告立刻出现
+          if (prevCount > 0 && list.length < prevCount) {
+            self.loadData()
+          }
         }
       }).catch(function() {
         // 采集进度轮询失败静默,下一轮重试

+ 153 - 25
cfc-frontend/pages/health/report-upload.vue

@@ -43,8 +43,24 @@
         </view>
       </view>
 
+      <!-- 采集中:上传成功后后台解析,页面需展示进度,避免看起来像卡住 -->
+      <view class="collecting-panel" v-if="collecting">
+        <view class="collecting-card">
+          <view class="collecting-icon">
+            <view class="spinner" v-if="!collectError"></view>
+            <text class="collecting-fail-mark" v-else>!</text>
+          </view>
+          <view class="collecting-info">
+            <text class="collecting-title">{{ collectError ? '采集失败' : '数据采集中' }}</text>
+            <text class="collecting-file">{{ collectFileName || '健康报告' }}</text>
+            <text class="collecting-hint">{{ collectError || '后台正在解析报告,完成后自动入库,无需重复上传' }}</text>
+          </view>
+        </view>
+        <view class="collecting-btn" @click="goReportList">去报告列表查看</view>
+      </view>
+
       <!-- 上传方式 -->
-      <view class="upload-methods" v-if="reportKind">
+      <view class="upload-methods" v-if="reportKind && !collecting">
         <view class="upload-card card-file" @click="pickFile">
           <view class="upload-card-icon">📄</view>
           <text class="upload-card-title">从聊天选择文件</text>
@@ -207,7 +223,11 @@ export default {
       showKindSheet: false,
       pendingIsPhoto: false,
       collectDraftId: null,
-      collectTimer: null
+      collectTimer: null,
+      collecting: false,
+      collectFileName: '',
+      collectError: '',
+      collectPollCount: 0
     }
   },
   computed: {
@@ -245,10 +265,7 @@ export default {
     }
   },
   onUnload: function() {
-    if (this.collectTimer) {
-      clearInterval(this.collectTimer)
-      this.collectTimer = null
-    }
+    this.stopCollectPolling()
   },
   methods: {
     selectReportKind: function(kind) {
@@ -399,7 +416,9 @@ export default {
           return
         }
         self.collectDraftId = draftId
-        uni.showToast({ title: '数据采集中,完成后可在报告列表查看', icon: 'none', duration: 3000 })
+        self.collecting = true
+        self.collectError = ''
+        self.collectFileName = (self.selectedFile && (self.selectedFile.name || self.selectedFile.path)) || '健康报告'
         self.startCollectPolling(draftId)
       }).catch(function(err) {
         uni.hideLoading()
@@ -408,29 +427,62 @@ export default {
         uni.showToast({ title: msg, icon: 'none' })
       })
     },
-    // 轮询采集状态,完成后仅提示,用户可前往报告列表查看
+    stopCollectPolling: function() {
+      if (this.collectTimer) {
+        clearInterval(this.collectTimer)
+        this.collectTimer = null
+      }
+    },
+    // 轮询采集状态:立即查一次,再每 4 秒查,完成后跳转详情/列表
     startCollectPolling: function(draftId) {
       var self = this
-      if (self.collectTimer) {
-        clearInterval(self.collectTimer)
-      }
+      self.stopCollectPolling()
+      self.collectPollCount = 0
+      self.pollCollectStatus(draftId)
       self.collectTimer = setInterval(function() {
-        getReportCollectStatus(draftId).then(function(res) {
-          var data = res.data || {}
-          var status = data.parseStatus
-          if (status === 'completed' || status === 'failed') {
-            clearInterval(self.collectTimer)
-            self.collectTimer = null
-            if (status === 'completed') {
-              uni.showToast({ title: '报告已采集完成', icon: 'success', duration: 2000 })
+        self.pollCollectStatus(draftId)
+      }, 4000)
+    },
+    pollCollectStatus: function(draftId) {
+      var self = this
+      self.collectPollCount = (self.collectPollCount || 0) + 1
+      // 约 6 分钟仍未完成:停轮询,提示去列表看进度(后台任务可能仍在跑)
+      if (self.collectPollCount > 90) {
+        self.stopCollectPolling()
+        self.collectError = '解析耗时较长,可去报告列表查看进度,无需重复上传'
+        return
+      }
+      getReportCollectStatus(draftId).then(function(res) {
+        var data = res.data || {}
+        var status = data.parseStatus
+        if (status === 'completed') {
+          self.stopCollectPolling()
+          self.collecting = false
+          uni.showToast({ title: '报告已采集完成', icon: 'success', duration: 2000 })
+          var reportId = data.reportId
+          var reportType = data.reportType || 'gut_flora'
+          setTimeout(function() {
+            if (reportId) {
+              var url = reportType === 'gut_flora'
+                ? '/pages/health/gut-flora-detail?reportId=' + reportId
+                : '/pages/health/report-detail?reportType=' + reportType + '&reportId=' + reportId
+              uni.redirectTo({ url: url })
             } else {
-              uni.showToast({ title: (data.parseError || '报告采集失败,请重试'), icon: 'none', duration: 3000 })
+              uni.redirectTo({ url: '/pages/health/report-list' })
             }
-          }
-        }).catch(function() {
-          // 轮询失败静默,下次继续
-        })
-      }, 4000)
+          }, 600)
+        } else if (status === 'failed') {
+          self.stopCollectPolling()
+          self.collectError = data.parseError || '报告采集失败,请重试'
+          uni.showToast({ title: self.collectError, icon: 'none', duration: 3000 })
+        }
+      }).catch(function() {
+        // 轮询失败静默,下次继续
+      })
+    },
+    goReportList: function() {
+      this.stopCollectPolling()
+      uni.redirectTo({ url: '/pages/health/report-list' })
     },
     // DAN测评:parse-preview → 预览确认页
     uploadDanAndGoPreview: function(filePath) {
@@ -699,6 +751,82 @@ export default {
   line-height: 1.6;
 }
 
+.collecting-panel {
+  margin-bottom: 20rpx;
+}
+.collecting-card {
+  display: flex;
+  flex-direction: row;
+  align-items: flex-start;
+  background: #FFF8E6;
+  border: 1rpx solid #F5D78E;
+  border-radius: 16rpx;
+  padding: 28rpx 24rpx;
+}
+.collecting-icon {
+  width: 56rpx;
+  height: 56rpx;
+  border-radius: 50%;
+  background: #F0B429;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 20rpx;
+  flex-shrink: 0;
+}
+.spinner {
+  width: 28rpx;
+  height: 28rpx;
+  border: 4rpx solid rgba(255,255,255,0.4);
+  border-top-color: #fff;
+  border-radius: 50%;
+  animation: collecting-spin 1s linear infinite;
+}
+@keyframes collecting-spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+.collecting-fail-mark {
+  font-size: 32rpx;
+  color: #fff;
+  font-weight: bold;
+}
+.collecting-info {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  min-width: 0;
+}
+.collecting-title {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #7A5C00;
+}
+.collecting-file {
+  font-size: 24rpx;
+  color: #A08A45;
+  margin-top: 6rpx;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.collecting-hint {
+  font-size: 22rpx;
+  color: #C0A75A;
+  margin-top: 8rpx;
+  line-height: 1.5;
+}
+.collecting-btn {
+  margin-top: 20rpx;
+  height: 80rpx;
+  line-height: 80rpx;
+  text-align: center;
+  background: #5B9BD5;
+  color: #fff;
+  font-size: 28rpx;
+  border-radius: 12rpx;
+}
+
 .upload-methods {
   display: flex;
   flex-direction: row;