|
@@ -228,6 +228,42 @@
|
|
|
<view class="bottom-spacer"></view>
|
|
<view class="bottom-spacer"></view>
|
|
|
</scroll-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" />
|
|
<health-knowledge-popup :visible="knowledgeVisible" :data="knowledgeData" @close="closeKnowledge" />
|
|
|
|
|
|
|
|
<feedback-popup :visible="feedbackVisible" :report-id="reportId" @close="closeFeedback" />
|
|
<feedback-popup :visible="feedbackVisible" :report-id="reportId" @close="closeFeedback" />
|
|
@@ -332,7 +368,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<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 HealthKnowledgePopup from '../../components/health-knowledge-popup.vue'
|
|
|
import FeedbackPopup from '../../components/feedback-popup.vue'
|
|
import FeedbackPopup from '../../components/feedback-popup.vue'
|
|
|
import { parseDate } from '../../utils/format.js'
|
|
import { parseDate } from '../../utils/format.js'
|
|
@@ -399,6 +435,14 @@ export default {
|
|
|
extractedName: '',
|
|
extractedName: '',
|
|
|
extractedGender: '',
|
|
extractedGender: '',
|
|
|
extractedAge: '',
|
|
extractedAge: '',
|
|
|
|
|
+ quickAnalyze: {
|
|
|
|
|
+ show: false,
|
|
|
|
|
+ sending: false,
|
|
|
|
|
+ messages: [],
|
|
|
|
|
+ inputText: '',
|
|
|
|
|
+ conversationId: '',
|
|
|
|
|
+ usedToday: false
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
computed: {
|
|
computed: {
|
|
@@ -474,6 +518,13 @@ riskGroupAbnormalCount: function() {
|
|
|
if (this.selectedMemberObj) return this.selectedMemberObj.nickname || this.selectedMemberObj.name || '已选择'
|
|
if (this.selectedMemberObj) return this.selectedMemberObj.nickname || this.selectedMemberObj.name || '已选择'
|
|
|
if (this.extractedName) return this.extractedName + '(待绑定)'
|
|
if (this.extractedName) return this.extractedName + '(待绑定)'
|
|
|
return '未选择'
|
|
return '未选择'
|
|
|
|
|
+ },
|
|
|
|
|
+ quickQuestions: function() {
|
|
|
|
|
+ return [
|
|
|
|
|
+ '这份报告最需要关注哪些异常指标?',
|
|
|
|
|
+ '报告中提示了哪些健康风险?',
|
|
|
|
|
+ '有哪些改善建议?'
|
|
|
|
|
+ ]
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
onLoad: function(options) {
|
|
onLoad: function(options) {
|
|
@@ -487,6 +538,52 @@ riskGroupAbnormalCount: function() {
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
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() },
|
|
goBack: function() { uni.navigateBack() },
|
|
|
/** 状态 → CSS安全英文(兼容中英文,与 report-confirm 保持一致) */
|
|
/** 状态 → CSS安全英文(兼容中英文,与 report-confirm 保持一致) */
|
|
|
_cssForStatus: function(s) {
|
|
_cssForStatus: function(s) {
|
|
@@ -1366,4 +1463,111 @@ applyDraftPayload: function(payload) {
|
|
|
margin-top: 4rpx;
|
|
margin-top: 4rpx;
|
|
|
line-height: 1.5;
|
|
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>
|
|
</style>
|