Explorar o código

feat(frontend): gut-flora-detail 新增报告快速分析浮层(支持 reportId/draftId)

iwt hai 1 semana
pai
achega
036e9ccef0
Modificáronse 1 ficheiros con 205 adicións e 1 borrados
  1. 205 1
      cfc-frontend/pages/health/gut-flora-detail.vue

+ 205 - 1
cfc-frontend/pages/health/gut-flora-detail.vue

@@ -228,6 +228,42 @@
       <view class="bottom-spacer"></view>
     </scroll-view>
 
+    <!-- 报告快速分析入口(仅查看模式,reportId 或 draftId 存在) -->
+    <view class="quick-analyze-fab" v-if="!isEditing && (reportId || draftId)" @tap="openQuickAnalyze">
+      <text class="quick-analyze-fab-icon">🎯</text>
+      <text class="quick-analyze-fab-text">快速分析</text>
+    </view>
+
+    <!-- 快速分析浮层 -->
+    <view class="quick-analyze-overlay" v-if="quickAnalyze.show" @tap="closeQuickAnalyze"></view>
+    <view class="quick-analyze-panel" v-if="quickAnalyze.show">
+      <view class="quick-analyze-header">
+        <text class="quick-analyze-title">报告快速分析</text>
+        <text class="quick-analyze-close" @tap="closeQuickAnalyze">✕</text>
+      </view>
+      <view class="quick-analyze-hint" v-if="quickAnalyze.usedToday">免费版今日次数已用完,升级会员解锁更多分析</view>
+      <scroll-view class="quick-analyze-messages" scroll-y>
+        <view class="quick-analyze-message" v-for="(msg, qidx) in quickAnalyze.messages" :key="qidx" :class="'msg-' + msg.role">
+          <text class="quick-analyze-msg-text">{{ msg.content }}</text>
+        </view>
+        <view class="quick-analyze-loading" v-if="quickAnalyze.sending">
+          <text class="quick-analyze-loading-text">AI 正在分析中...</text>
+        </view>
+      </scroll-view>
+      <view class="quick-analyze-chips" v-if="quickAnalyze.messages.length === 0">
+        <view class="quick-analyze-chip" v-for="(q, qi) in quickQuestions" :key="qi" @tap="sendQuickQuestion(q)">
+          <text class="quick-analyze-chip-text">{{ q }}</text>
+        </view>
+      </view>
+      <view class="quick-analyze-input-bar">
+        <input class="quick-analyze-input" v-model="quickAnalyze.inputText" placeholder="输入你想问的问题..."
+          :disabled="quickAnalyze.sending || quickAnalyze.usedToday" confirm-type="send" @confirm="sendQuickAnalyze" />
+        <view class="quick-analyze-send" :class="{ 'send-disabled': quickAnalyze.sending || quickAnalyze.usedToday }" @tap="sendQuickAnalyze">
+          <text class="quick-analyze-send-text">发送</text>
+        </view>
+      </view>
+    </view>
+
     <health-knowledge-popup :visible="knowledgeVisible" :data="knowledgeData" @close="closeKnowledge" />
 
     <feedback-popup :visible="feedbackVisible" :report-id="reportId" @close="closeFeedback" />
@@ -332,7 +368,7 @@
 </template>
 
 <script>
-import { getReportDetail, editHealthReport, queryKnowledgeBase, queryIndicatorKnowledge, getGutFloraAnalysis, confirmReportPreview, discardReportDraft, parseReportDraft, getHealthFoods, getFoodCautionList, getFamilyMemberList, addFamilyMember } from '../../utils/api.js'
+import { getReportDetail, editHealthReport, queryKnowledgeBase, queryIndicatorKnowledge, getGutFloraAnalysis, confirmReportPreview, discardReportDraft, parseReportDraft, getHealthFoods, getFoodCautionList, getFamilyMemberList, addFamilyMember, reportQuickAnalyze, getMyMembership } from '../../utils/api.js'
 import HealthKnowledgePopup from '../../components/health-knowledge-popup.vue'
 import FeedbackPopup from '../../components/feedback-popup.vue'
 import { parseDate } from '../../utils/format.js'
@@ -399,6 +435,14 @@ export default {
       extractedName: '',
       extractedGender: '',
       extractedAge: '',
+      quickAnalyze: {
+        show: false,
+        sending: false,
+        messages: [],
+        inputText: '',
+        conversationId: '',
+        usedToday: false
+      }
     }
   },
   computed: {
@@ -474,6 +518,13 @@ riskGroupAbnormalCount: function() {
       if (this.selectedMemberObj) return this.selectedMemberObj.nickname || this.selectedMemberObj.name || '已选择'
       if (this.extractedName) return this.extractedName + '(待绑定)'
       return '未选择'
+    },
+    quickQuestions: function() {
+      return [
+        '这份报告最需要关注哪些异常指标?',
+        '报告中提示了哪些健康风险?',
+        '有哪些改善建议?'
+      ]
     }
   },
   onLoad: function(options) {
@@ -487,6 +538,52 @@ riskGroupAbnormalCount: function() {
     }
   },
   methods: {
+    // ===== 报告快速分析 =====
+    openQuickAnalyze: function() {
+      this.quickAnalyze.show = true
+      var self = this
+      getMyMembership().then(function(res) {
+        var level = res.data && res.data.memberLevel
+        if (level && level !== 'FREE') {
+          self.quickAnalyze.usedToday = false
+        }
+      }).catch(function() {})
+    },
+    closeQuickAnalyze: function() {
+      this.quickAnalyze.show = false
+    },
+    sendQuickQuestion: function(q) {
+      if (q && q.trim()) {
+        this.quickAnalyze.inputText = q
+        this.sendQuickAnalyze()
+      }
+    },
+    sendQuickAnalyze: function() {
+      var self = this
+      var text = (this.quickAnalyze.inputText || '').trim()
+      if (!text || this.quickAnalyze.sending) return
+      this.quickAnalyze.messages.push({ role: 'user', content: text })
+      this.quickAnalyze.inputText = ''
+      this.quickAnalyze.sending = true
+      reportQuickAnalyze(text, this.reportId, this.quickAnalyze.conversationId, this.draftId).then(function(res) {
+        if (res.code === 200 && res.data) {
+          self.quickAnalyze.messages.push({ role: 'ai', content: res.data.answer || '(无回答)' })
+          if (res.data.conversationId) {
+            self.quickAnalyze.conversationId = res.data.conversationId
+          }
+        } else {
+          var msg = res.message || '分析失败'
+          if (msg.indexOf('每日仅限') !== -1) {
+            self.quickAnalyze.usedToday = true
+          }
+          self.quickAnalyze.messages.push({ role: 'ai', content: msg })
+        }
+      }).catch(function() {
+        self.quickAnalyze.messages.push({ role: 'ai', content: 'AI 服务暂不可用,请稍后重试' })
+      }).finally(function() {
+        self.quickAnalyze.sending = false
+      })
+    },
     goBack: function() { uni.navigateBack() },
     /** 状态 → CSS安全英文(兼容中英文,与 report-confirm 保持一致) */
     _cssForStatus: function(s) {
@@ -1366,4 +1463,111 @@ applyDraftPayload: function(payload) {
   margin-top: 4rpx;
   line-height: 1.5;
 }
+/* ===== 报告快速分析 ===== */
+.quick-analyze-fab {
+  position: fixed;
+  right: 30rpx;
+  bottom: 60rpx;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  background: linear-gradient(135deg, #5B9BD5, #3B82F6);
+  border-radius: 44rpx;
+  padding: 18rpx 30rpx;
+  box-shadow: 0 4rpx 16rpx rgba(59, 130, 246, 0.4);
+  z-index: 90;
+}
+.quick-analyze-fab-icon { font-size: 32rpx; margin-right: 10rpx; }
+.quick-analyze-fab-text { font-size: 28rpx; color: #fff; font-weight: 500; }
+.quick-analyze-fab:active { opacity: 0.85; }
+.quick-analyze-overlay {
+  position: fixed;
+  top: 0; left: 0; right: 0; bottom: 0;
+  background: rgba(0, 0, 0, 0.45);
+  z-index: 98;
+}
+.quick-analyze-panel {
+  position: fixed;
+  left: 30rpx; right: 30rpx;
+  bottom: 40rpx;
+  background: #fff;
+  border-radius: 20rpx;
+  padding: 24rpx;
+  z-index: 99;
+  display: flex;
+  flex-direction: column;
+  max-height: 70vh;
+}
+.quick-analyze-header {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 16rpx;
+}
+.quick-analyze-title { font-size: 30rpx; font-weight: bold; color: #333; }
+.quick-analyze-close { font-size: 32rpx; color: #999; padding: 8rpx; }
+.quick-analyze-hint {
+  font-size: 24rpx;
+  color: #E65100;
+  background: #FFF3E0;
+  border-radius: 12rpx;
+  padding: 12rpx 16rpx;
+  margin-bottom: 12rpx;
+}
+.quick-analyze-messages {
+  max-height: 50vh;
+  margin-bottom: 16rpx;
+}
+.quick-analyze-message {
+  margin-bottom: 12rpx;
+  display: flex;
+  flex-direction: column;
+}
+.quick-analyze-message.msg-user { align-items: flex-end; }
+.quick-analyze-message.msg-ai { align-items: flex-start; }
+.quick-analyze-msg-text {
+  font-size: 26rpx;
+  color: #333;
+  background: #F3F4F6;
+  border-radius: 14rpx;
+  padding: 14rpx 18rpx;
+  max-width: 80%;
+  line-height: 1.5;
+}
+.msg-user .quick-analyze-msg-text { background: #5B9BD5; color: #fff; }
+.quick-analyze-loading { display: flex; justify-content: center; padding: 12rpx 0; }
+.quick-analyze-loading-text { font-size: 24rpx; color: #999; }
+.quick-analyze-chips { display: flex; flex-direction: column; margin-bottom: 16rpx; }
+.quick-analyze-chip {
+  background: #EFF6FF;
+  border: 1rpx solid #BFDBFE;
+  border-radius: 12rpx;
+  padding: 14rpx 18rpx;
+  margin-bottom: 10rpx;
+}
+.quick-analyze-chip:active { opacity: 0.8; }
+.quick-analyze-chip-text { font-size: 26rpx; color: #1D4ED8; }
+.quick-analyze-input-bar {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+.quick-analyze-input {
+  flex: 1;
+  height: 72rpx;
+  background: #F3F4F6;
+  border-radius: 36rpx;
+  padding: 0 28rpx;
+  font-size: 26rpx;
+  color: #333;
+  margin-right: 16rpx;
+}
+.quick-analyze-send {
+  background: #5B9BD5;
+  border-radius: 36rpx;
+  padding: 16rpx 34rpx;
+}
+.quick-analyze-send.send-disabled { opacity: 0.5; }
+.quick-analyze-send-text { font-size: 26rpx; color: #fff; }
 </style>