完善ai问诊页面样式

This commit is contained in:
2026-04-10 11:03:48 +08:00
parent 3196876bac
commit 15ded03ffb
153 changed files with 257 additions and 284 deletions

View File

@@ -1,152 +1,174 @@
<!-- 机构端 - AI问诊页面 -->
<template>
<view class="ai-page">
<!-- #ifdef MP-WEIXIN -->
<view class="detail-navbar">
<view class="detail-navbar-back" @click="uni.navigateBack()">
<text class="back-arrow"></text>
<text class="back-text">返回</text>
</view>
<text class="detail-navbar-title">AI问诊</text>
<view style="width: 120rpx;"></view>
</view>
<!-- #endif -->
<!-- 高风险提示横幅(始终显示) -->
<view class="risk-banner">
<text class="risk-banner-icon">⚠️</text>
<text class="risk-banner-text">AI问诊仅供参考不能代替专业医生诊断紧急情况请立即拨打120</text>
</view>
<!-- 症状快捷选择 -->
<view v-if="!hasConversation" class="quick-select-area">
<text class="qs-title">请选择主要症状(可多选)</text>
<view class="qs-tags">
<view
v-for="sym in symptomOptions"
:key="sym"
class="qs-tag"
:class="selectedSymptoms.includes(sym) ? 'qs-tag-selected' : ''"
@click="toggleSymptom(sym)"
>
{{ sym }}
<!-- ===== 顶部固定区 ===== -->
<view class="top-fixed">
<!-- #ifdef MP-WEIXIN -->
<view class="detail-navbar">
<view class="detail-navbar-back" @click="uni.navigateBack()">
<text class="back-arrow"></text>
<text class="back-text">返回</text>
</view>
<text class="detail-navbar-title">AI问诊</text>
<view style="width: 120rpx;"></view>
</view>
<view v-if="selectedSymptoms.length > 0" class="qs-confirm-row">
<view class="qs-confirm-btn" @click="startWithSymptoms">开始问诊</view>
<!-- #endif -->
<!-- 高风险提示横幅(始终显示) -->
<view class="risk-banner">
<text class="risk-banner-icon">⚠️</text>
<text class="risk-banner-text">AI问诊仅供参考不能代替专业医生诊断紧急情况请立即拨打120</text>
</view>
</view>
<!-- 对话区域 -->
<scroll-view
class="chat-scroll"
direction="vertical"
:scroll-into-view="lastMsgId"
:scroll-with-animation="true"
>
<!-- 欢迎提示 -->
<view class="welcome-msg" v-if="messages.length === 0 && !hasConversation">
<view class="welcome-avatar">🤖</view>
<view class="welcome-bubble">
<text class="welcome-title">您好我是医养AI助手</text>
<text class="welcome-desc">我可以帮助您初步了解用户症状、进行健康风险评估,以及提供护理建议。请选择上方症状或直接输入描述。</text>
<text class="welcome-disclaimer">⚠ 本工具仅供辅助参考,最终诊疗请遵循医嘱。</text>
</view>
</view>
<!-- 消息列表 -->
<view
v-for="(msg, idx) in messages"
:key="idx"
:id="'msg-' + idx"
class="msg-row"
:class="msg.role === 'user' ? 'msg-row-right' : 'msg-row-left'"
<!-- ===== 中间自适应聊天区 ===== -->
<view class="middle-flex">
<scroll-view
class="chat-scroll"
direction="vertical"
:scroll-into-view="lastMsgId"
:scroll-with-animation="true"
>
<!-- AI头像 -->
<view v-if="msg.role === 'ai'" class="msg-avatar ai-avatar">🤖</view>
<view class="msg-bubble-wrap" :class="msg.role === 'user' ? 'mbw-right' : 'mbw-left'">
<!-- 高风险提醒卡片 -->
<view v-if="msg.riskLevel === 'high'" class="risk-card">
<view class="risk-card-header">
<text class="risk-card-icon">🚨</text>
<text class="risk-card-title">高风险提示</text>
</view>
<text class="risk-card-body">{{ msg.content }}</text>
<view class="risk-card-actions">
<view class="risk-action-btn rca-call" @click="callEmergency">一键拨打120</view>
<view class="risk-action-btn rca-notify" @click="notifyFamily">通知家属</view>
</view>
</view>
<!-- 普通气泡 -->
<view v-else class="msg-bubble" :class="msg.role === 'user' ? 'bubble-user' : 'bubble-ai'">
<text class="msg-text">{{ msg.content }}</text>
</view>
<!-- 建议操作列表AI回复带操作 -->
<view v-if="msg.suggestions && msg.suggestions.length > 0" class="suggestion-list">
<!-- 症状快捷选择(在聊天区顶部,随聊天区滚动) -->
<view v-if="!hasConversation" class="quick-select-area">
<text class="qs-title">请选择主要症状(可多选)</text>
<view class="qs-tags">
<view
v-for="sug in msg.suggestions"
:key="sug"
class="suggestion-item"
@click="sendMessage(sug)"
v-for="sym in symptomOptions"
:key="sym"
class="qs-tag"
:class="selectedSymptoms.includes(sym) ? 'qs-tag-selected' : ''"
@click="toggleSymptom(sym)"
>
{{ sug }}
{{ sym }}
</view>
</view>
<view v-if="selectedSymptoms.length > 0" class="qs-confirm-row">
<view class="qs-confirm-btn" @click="startWithSymptoms">开始问诊</view>
</view>
</view>
<!-- 用户头像 -->
<view v-if="msg.role === 'user'" class="msg-avatar user-avatar">👩‍⚕️</view>
</view>
<!-- AI加载中 -->
<view v-if="isLoading" class="msg-row msg-row-left">
<view class="msg-avatar ai-avatar">🤖</view>
<view class="loading-bubble">
<view class="loading-dot"></view>
<view class="loading-dot"></view>
<view class="loading-dot"></view>
<!-- 欢迎提示 -->
<view class="welcome-msg" v-if="messages.length === 0 && !hasConversation">
<view class="welcome-avatar">🤖</view>
<view class="welcome-bubble">
<text class="welcome-title">您好我是医养AI助手</text>
<text class="welcome-desc">我可以帮助您初步了解用户症状、进行健康风险评估,以及提供护理建议。请选择上方症状或直接输入描述。</text>
<text class="welcome-disclaimer">⚠ 本工具仅供辅助参考,最终诊疗请遵循医嘱。</text>
</view>
</view>
</view>
<view id="msg-bottom" style="height: 20rpx;"></view>
</scroll-view>
<!-- 快捷问题(有对话后显示) -->
<view v-if="hasConversation && quickReplies.length > 0" class="quick-replies">
<scroll-view direction="horizontal" class="qr-scroll">
<!-- 消息列表 -->
<view
v-for="qr in quickReplies"
:key="qr"
class="qr-chip"
@click="sendMessage(qr)"
v-for="(msg, idx) in messages"
:key="idx"
:id="'msg-' + idx"
class="msg-row"
:class="msg.role === 'user' ? 'msg-row-right' : 'msg-row-left'"
>
{{ qr }}
<!-- AI头像 -->
<view v-if="msg.role === 'ai'" class="msg-avatar ai-avatar">🤖</view>
<view class="msg-bubble-wrap" :class="msg.role === 'user' ? 'mbw-right' : 'mbw-left'">
<!-- 高风险提醒卡片 -->
<view v-if="msg.riskLevel === 'high'" class="risk-card">
<view class="risk-card-header">
<text class="risk-card-icon">🚨</text>
<text class="risk-card-title">高风险提示</text>
</view>
<text class="risk-card-body">{{ msg.content }}</text>
<view class="risk-card-actions">
<view class="risk-action-btn rca-call" @click="callEmergency">一键拨打120</view>
<view class="risk-action-btn rca-notify" @click="notifyFamily">通知家属</view>
</view>
</view>
<!-- 普通气泡 -->
<view v-else class="msg-bubble" :class="msg.role === 'user' ? 'bubble-user' : 'bubble-ai'">
<text class="msg-text">{{ msg.content }}</text>
</view>
<!-- 建议操作列表AI回复带操作 -->
<view v-if="msg.suggestions && msg.suggestions.length > 0" class="suggestion-list">
<view
v-for="sug in msg.suggestions"
:key="sug"
class="suggestion-item"
@click="sendMessage(sug)"
>
{{ sug }}
</view>
</view>
</view>
<!-- 用户头像 -->
<view v-if="msg.role === 'user'" class="msg-avatar user-avatar">👩‍⚕️</view>
</view>
<!-- AI加载中 -->
<view v-if="isLoading" class="msg-row msg-row-left">
<view class="msg-avatar ai-avatar">🤖</view>
<view class="loading-bubble">
<view class="loading-dot"></view>
<view class="loading-dot"></view>
<view class="loading-dot"></view>
</view>
</view>
<view id="msg-bottom" style="height: 20rpx;"></view>
</scroll-view>
</view>
<!-- 输入区 -->
<view class="input-bar">
<view class="input-bar-inner">
<input
class="chat-input"
v-model="inputText"
placeholder="描述症状或询问护理建议..."
:confirm-type="'send'"
@confirm="onSend"
:maxlength="200"
/>
<view class="send-btn" :class="inputText.trim() ? 'send-btn-active' : ''" @click="onSend">
发送
<!-- ===== 底部固定区 ===== -->
<view class="bottom-fixed">
<!-- 快捷问题模块 -->
<view v-if="quickReplies.length > 0" class="quick-replies">
<view class="quick-replies-header" @click="toggleQuickReplies">
<view class="qr-header-left">
<text class="qr-header-icon">💬</text>
<text class="qr-title">快捷问题</text>
</view>
<view class="qr-toggle">
<text class="qr-toggle-text">{{ quickRepliesExpanded ? '收起' : '展开' }}</text>
<text class="qr-toggle-icon">{{ quickRepliesExpanded ? '▾' : '▸' }}</text>
</view>
</view>
<view v-if="quickRepliesExpanded" class="quick-replies-body">
<scroll-view class="qr-scroll" :scroll-x="true" :scroll-y="false">
<view class="qr-scroll-inner">
<view
v-for="qr in quickReplies"
:key="qr"
class="qr-chip"
@click="sendMessage(qr)"
>
{{ qr }}
</view>
</view>
</scroll-view>
</view>
</view>
<view class="input-actions">
<view class="ia-btn" @click="clearConversation">清空对话</view>
<view class="ia-btn" @click="exportRecord">导出记录</view>
<view class="ia-btn ia-btn-primary" @click="referToDoctor">转诊医生</view>
<!-- 输入区 -->
<view class="input-bar">
<view class="input-bar-inner">
<input
class="chat-input"
v-model="inputText"
placeholder="描述症状或询问护理建议..."
:confirm-type="'send'"
@confirm="onSend"
:maxlength="200"
/>
<view class="send-btn" :class="inputText.trim() ? 'send-btn-active' : ''" @click="onSend">
发送
</view>
</view>
<view class="input-actions">
<view class="ia-btn" @click="clearConversation">清空对话</view>
<view class="ia-btn" @click="exportRecord">导出记录</view>
<view class="ia-btn ia-btn-primary" @click="referToDoctor">转诊医生</view>
</view>
</view>
</view>
</view>
@@ -194,7 +216,8 @@
lastMsgId: '' as string,
selectedSymptoms: [] as string[],
symptomOptions: ['头晕', '胸痛', '发烧', '呼吸困难', '腹痛', '跌倒', '意识模糊', '血压异常', '血糖异常', '情绪异常'] as string[],
quickReplies: ['症状加重了', '需要上门服务', '联系家属', '转诊医生', '今日用药'] as string[]
quickReplies: ['症状加重了', '需要上门服务', '联系家属', '转诊医生', '今日用药'] as string[],
quickRepliesExpanded: false as boolean
}
},
@@ -282,11 +305,16 @@
this.messages = []
this.hasConversation = false
this.lastMsgId = ''
this.quickRepliesExpanded = false
}
}
})
},
toggleQuickReplies() {
this.quickRepliesExpanded = !this.quickRepliesExpanded
},
exportRecord() {
uni.showToast({ title: '导出功能开发中', icon: 'none' })
},
@@ -309,9 +337,34 @@
<style>
.ai-page {
background-color: #f0f2f7;
min-height: 100vh;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* ===== 三段式布局容器 ===== */
.top-fixed {
flex: none;
z-index: 10;
background-color: #f0f2f7;
}
.middle-flex {
flex: 1;
min-height: 0;
overflow: hidden;
display: flex;
flex-direction: column;
}
.bottom-fixed {
flex: none;
z-index: 10;
background-color: #ffffff;
border-top-width: 1rpx;
border-top-style: solid;
border-top-color: #eeeeee;
}
/* ===== 导航栏 ===== */
@@ -444,7 +497,9 @@
/* ===== 聊天滚动区 ===== */
.chat-scroll {
flex: 1;
width: 100%;
padding: 20rpx 0;
box-sizing: border-box;
}
/* ===== 欢迎消息 ===== */
@@ -686,34 +741,98 @@
margin: 0 4rpx;
}
/* ===== 快捷回复 ===== */
/* ===== 快捷问题模块 ===== */
.quick-replies {
background-color: #ffffff;
flex: none;
background-color: #f8f9ff;
border-top-width: 1rpx;
border-top-style: solid;
border-top-color: #f0f0f0;
border-top-color: #dde3f8;
}
.quick-replies-header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 16rpx 24rpx;
}
.qr-header-left {
display: flex;
flex-direction: row;
align-items: center;
}
.qr-header-icon {
font-size: 26rpx;
margin-right: 10rpx;
}
.qr-title {
font-size: 26rpx;
font-weight: 600;
color: #444444;
}
.qr-toggle {
display: flex;
flex-direction: row;
align-items: center;
background-color: rgb(66,121,240);
border-radius: 24rpx;
padding: 8rpx 20rpx;
}
.qr-toggle-text {
font-size: 22rpx;
color: #ffffff;
margin-right: 6rpx;
}
.qr-toggle-icon {
font-size: 24rpx;
color: #ffffff;
line-height: 1;
}
.quick-replies-body {
padding-bottom: 12rpx;
}
.qr-scroll {
white-space: nowrap;
width: 100%;
}
.qr-scroll-inner {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
padding: 0 16rpx;
}
.qr-chip {
display: inline-flex;
display: flex;
flex-direction: row;
align-items: center;
flex-shrink: 0;
font-size: 24rpx;
color: rgb(66,121,240);
background-color: #eef2fe;
border-radius: 20rpx;
padding: 10rpx 24rpx;
margin: 12rpx 8rpx;
background-color: #ffffff;
border-width: 1rpx;
border-style: solid;
border-color: rgb(66,121,240);
border-radius: 24rpx;
padding: 10rpx 28rpx;
margin: 0 8rpx;
height: 60rpx;
line-height: 60rpx;
}
/* ===== 输入区 ===== */
.input-bar {
background-color: #ffffff;
border-top-width: 1rpx;
border-top-style: solid;
border-top-color: #eeeeee;
padding-bottom: env(safe-area-inset-bottom);
}