|
|
@@ -392,12 +392,48 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
+
|
|
|
+ <!-- 报告快速分析入口(仅查看模式) -->
|
|
|
+ <view class="quick-analyze-fab" v-if="pageMode==='view' && reportId" @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>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import ReportBlocksRenderer from '../../components/report-blocks-renderer.vue'
|
|
|
-import { getReportDetail, getDanReportDetail, getReportPayload, editHealthReport, parseReportDraft, confirmReportPreview, discardReportDraft, confirmTongue, discardTongue, getFamilyMemberList, addFamilyMember, queryIndicatorKnowledge, queryBacteriaKnowledge } from '../../utils/api.js'
|
|
|
+import { getReportDetail, getDanReportDetail, getReportPayload, editHealthReport, parseReportDraft, confirmReportPreview, discardReportDraft, confirmTongue, discardTongue, getFamilyMemberList, addFamilyMember, queryIndicatorKnowledge, queryBacteriaKnowledge, reportQuickAnalyze, getMyMembership } from '../../utils/api.js'
|
|
|
import { parseDate } from '../../utils/format.js'
|
|
|
|
|
|
export default {
|
|
|
@@ -455,7 +491,16 @@ export default {
|
|
|
collapseState: { gutFlora: false, diseaseRisk: false, probiotic: false, taxonomy: false, pathogen: false },
|
|
|
showHelpPopup: false,
|
|
|
helpData: {},
|
|
|
- _kbCache: {}
|
|
|
+ _kbCache: {},
|
|
|
+ // 报告快速分析浮层
|
|
|
+ quickAnalyze: {
|
|
|
+ show: false,
|
|
|
+ sending: false,
|
|
|
+ messages: [], // [{role:'user'|'ai', content}]
|
|
|
+ inputText: '',
|
|
|
+ conversationId: '',
|
|
|
+ usedToday: false // 免费版今日已用(前端预判,最终以后端为准)
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -463,6 +508,13 @@ export default {
|
|
|
var map = { gut_flora: '肠道菌群报告', dan: 'DAN测评报告', physical_exam: '体检报告', tongue: '舌诊报告' }
|
|
|
return map[this.reportType] || '健康报告'
|
|
|
},
|
|
|
+ quickQuestions: function() {
|
|
|
+ return [
|
|
|
+ '这份报告最需要关注哪些异常指标?',
|
|
|
+ '报告中提示了哪些健康风险?',
|
|
|
+ '有哪些改善建议?'
|
|
|
+ ]
|
|
|
+ },
|
|
|
isGutFlora() {
|
|
|
return this.reportType === 'gut_flora'
|
|
|
},
|
|
|
@@ -585,6 +637,53 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
+ // ===== 报告快速分析 =====
|
|
|
+ openQuickAnalyze: function() {
|
|
|
+ this.quickAnalyze.show = true
|
|
|
+ var self = this
|
|
|
+ // 预判免费版今日额度(仅用于 UI 展示,最终以后端校验为准)
|
|
|
+ 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).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
|
|
|
+ })
|
|
|
+ },
|
|
|
loadData() {
|
|
|
var self = this
|
|
|
uni.showLoading({ title: '加载中...' })
|
|
|
@@ -2188,4 +2287,113 @@ export default {
|
|
|
margin-top: 6rpx;
|
|
|
opacity: 0.8;
|
|
|
}
|
|
|
+
|
|
|
+/* ===== 报告快速分析 ===== */
|
|
|
+.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>
|