This commit is contained in:
parent
7830a6ebbd
commit
479a246518
|
|
@ -11,8 +11,8 @@
|
|||
{
|
||||
"path": "pages/assistant/assistant",
|
||||
"style": {
|
||||
"navigationBarTitleText": "AI助手",
|
||||
"navigationBarBackgroundColor": "#64B5F6",
|
||||
"navigationBarTitleText": "宠物助手",
|
||||
"navigationBarBackgroundColor": "#FF8A80",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,81 +1,109 @@
|
|||
<template>
|
||||
<view class="assistant-container">
|
||||
<u-navbar title="AI助手" :border="false" bg-color="#4ecdc4">
|
||||
<template #right>
|
||||
<u-icon name="book" color="white" size="20" @click="openKnowledge"></u-icon>
|
||||
</template>
|
||||
</u-navbar>
|
||||
|
||||
<!-- 快捷问题 -->
|
||||
<view class="quick-questions" v-if="messageList.length <= 1">
|
||||
<u-text text="常见问题" type="primary" size="16" bold margin="20rpx 0"></u-text>
|
||||
<view class="question-grid">
|
||||
<u-button
|
||||
v-for="question in quickQuestions"
|
||||
:key="question.id"
|
||||
:text="question.text"
|
||||
type="info"
|
||||
size="mini"
|
||||
plain
|
||||
@click="askQuestion(question.text)"
|
||||
></u-button>
|
||||
<!-- 宠物助手信息卡片 -->
|
||||
<view class="assistant-info-card">
|
||||
<view class="assistant-avatar-wrapper">
|
||||
<view class="assistant-avatar">
|
||||
<text class="avatar-emoji">🤖</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="assistant-info-text">
|
||||
<text class="assistant-name">宠物助手</text>
|
||||
<text class="assistant-status">专业的宠物护理顾问</text>
|
||||
</view>
|
||||
<view class="chat-status">
|
||||
<view class="status-dot"></view>
|
||||
<text class="status-text">在线</text>
|
||||
</view>
|
||||
<view class="knowledge-icon" @click="openKnowledge">
|
||||
<text class="icon-text">📚</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 聊天区域 -->
|
||||
<scroll-view class="chat-area" scroll-y="true" :scroll-top="scrollTop" scroll-with-animation="true">
|
||||
<view class="message-list">
|
||||
<view class="message-item" v-for="(message, index) in messageList" :key="index"
|
||||
:class="message.type === 'user' ? 'user-message' : 'ai-message'">
|
||||
<u-avatar
|
||||
v-if="message.type === 'user'"
|
||||
:src="userAvatar"
|
||||
size="35"
|
||||
shape="circle"
|
||||
></u-avatar>
|
||||
<u-avatar
|
||||
v-else
|
||||
src="/static/ai-avatar.png"
|
||||
size="35"
|
||||
shape="circle"
|
||||
></u-avatar>
|
||||
<view class="message-content">
|
||||
<u-text :text="message.content" size="14" :type="message.type === 'user' ? 'primary' : 'info'"></u-text>
|
||||
<u-text :text="message.time" type="tips" size="10" margin="8rpx 0 0 0"></u-text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 聊天消息列表 -->
|
||||
<view class="chat-messages">
|
||||
<scroll-view
|
||||
class="chat-scroll"
|
||||
scroll-y
|
||||
:scroll-top="scrollTop"
|
||||
scroll-with-animation
|
||||
>
|
||||
<view class="message-list">
|
||||
<!-- 消息项 -->
|
||||
<template v-for="(message, index) in messageList" :key="index">
|
||||
<!-- AI消息 -->
|
||||
<view class="message-item ai" v-if="message.type === 'ai'">
|
||||
<view class="message-avatar">
|
||||
<view class="assistant-avatar">
|
||||
<text class="avatar-emoji">🤖</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="message-content ai">
|
||||
<view class="message-bubble ai">
|
||||
<text class="message-text" v-if="!(isThinking && index === messageList.length - 1)">{{ message.content }}</text>
|
||||
<view class="typing-dots" v-else>
|
||||
<view class="typing-dot"></view>
|
||||
<view class="typing-dot"></view>
|
||||
<view class="typing-dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="message-time" v-if="!(isThinking && index === messageList.length - 1)">{{ message.time }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- AI思考中状态 -->
|
||||
<view class="message-item ai-message" v-if="isThinking">
|
||||
<u-avatar src="/static/ai-avatar.png" size="35" shape="circle"></u-avatar>
|
||||
<view class="message-content thinking">
|
||||
<u-loading-icon mode="flower" color="#4ecdc4"></u-loading-icon>
|
||||
<u-text text="AI正在思考中..." type="tips" size="12" margin="0 0 0 20rpx"></u-text>
|
||||
<!-- 用户消息 -->
|
||||
<view class="message-item user" v-if="message.type === 'user'">
|
||||
<view class="message-content user">
|
||||
<view class="message-bubble user">
|
||||
<text class="message-text">{{ message.content }}</text>
|
||||
</view>
|
||||
<text class="message-time">{{ message.time }}</text>
|
||||
</view>
|
||||
<view class="message-avatar">
|
||||
<view class="user-avatar">
|
||||
<text class="avatar-emoji">👤</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- AI思考中状态 -->
|
||||
<view class="message-item ai" v-if="isThinking">
|
||||
<view class="message-avatar">
|
||||
<view class="assistant-avatar">
|
||||
<text class="avatar-emoji">🤖</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="message-content ai">
|
||||
<view class="message-bubble ai typing-bubble">
|
||||
<view class="typing-dots">
|
||||
<view class="typing-dot"></view>
|
||||
<view class="typing-dot"></view>
|
||||
<view class="typing-dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 输入区域 -->
|
||||
<view class="input-area">
|
||||
<view class="chat-input-area">
|
||||
<view class="input-container">
|
||||
<u-input
|
||||
v-model="inputMessage"
|
||||
placeholder="请输入您的问题..."
|
||||
:border="false"
|
||||
bg-color="#f5f5f5"
|
||||
shape="circle"
|
||||
@confirm="sendMessage"
|
||||
confirm-type="send"
|
||||
></u-input>
|
||||
<u-button
|
||||
:text="inputMessage.trim() ? '发送' : '🎤'"
|
||||
type="primary"
|
||||
size="mini"
|
||||
shape="circle"
|
||||
:disabled="isThinking"
|
||||
@click="inputMessage.trim() ? sendMessage() : startVoiceInput()"
|
||||
></u-button>
|
||||
<view class="input-wrapper">
|
||||
<input
|
||||
v-model="inputMessage"
|
||||
placeholder="和宠物助手说点什么..."
|
||||
class="message-input"
|
||||
@confirm="sendMessage"
|
||||
confirm-type="send"
|
||||
maxlength="500"
|
||||
/>
|
||||
</view>
|
||||
<view class="send-button" @click="sendMessage" :class="{ active: inputMessage.trim() }">
|
||||
<text class="send-text">发送</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -235,95 +263,354 @@ export default {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
.assistant-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f8f9fa;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.assistant-info-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
margin: 20rpx 30rpx 0 30rpx;
|
||||
margin-top: calc(20rpx + env(safe-area-inset-top));
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.assistant-avatar-wrapper {
|
||||
margin-right: 24rpx;
|
||||
|
||||
.assistant-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 8rpx 24rpx rgba(255, 138, 128, 0.3);
|
||||
|
||||
.avatar-emoji {
|
||||
font-size: 40rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.assistant-info-text {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
|
||||
.assistant-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.assistant-status {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-right: 20rpx;
|
||||
|
||||
.status-dot {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
background: #4CAF50;
|
||||
box-shadow: 0 0 0 4rpx rgba(76, 175, 80, 0.2);
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 24rpx;
|
||||
color: #4CAF50;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.knowledge-icon {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 30rpx;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.icon-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.quick-questions {
|
||||
background-color: white;
|
||||
padding: 20rpx;
|
||||
margin: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
margin: 20rpx 30rpx;
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.2);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
|
||||
.question-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #FF8A80;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
:deep(.u-button) {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.question-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
|
||||
.question-button {
|
||||
background: rgba(255, 138, 128, 0.1);
|
||||
border: 2rpx solid rgba(255, 138, 128, 0.3);
|
||||
border-radius: 20rpx;
|
||||
padding: 16rpx 24rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
background: rgba(255, 138, 128, 0.2);
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.question-text {
|
||||
font-size: 26rpx;
|
||||
color: #FF8A80;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-area {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
.chat-messages {
|
||||
margin-top: 20rpx;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-scroll {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.message-list {
|
||||
.message-item {
|
||||
display: flex;
|
||||
margin-bottom: 30rpx;
|
||||
align-items: flex-start;
|
||||
padding: 20rpx 0;
|
||||
padding-bottom: 80rpx;
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&.user-message {
|
||||
flex-direction: row-reverse;
|
||||
.message-item {
|
||||
display: flex;
|
||||
margin-bottom: 24rpx;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
background-color: #4ecdc4;
|
||||
margin-right: 20rpx;
|
||||
border-radius: 20rpx 20rpx 8rpx 20rpx;
|
||||
.message-item.user {
|
||||
justify-content: flex-end;
|
||||
padding: 0 10rpx 0 80rpx;
|
||||
}
|
||||
|
||||
:deep(.u-text) {
|
||||
color: white !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.message-item.ai {
|
||||
justify-content: flex-start;
|
||||
padding: 0 80rpx 0 10rpx;
|
||||
}
|
||||
|
||||
&.ai-message {
|
||||
.message-content {
|
||||
background-color: white;
|
||||
margin-left: 20rpx;
|
||||
border-radius: 20rpx 20rpx 20rpx 8rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
.message-avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
margin: 0 16rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&.thinking {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.assistant-avatar, .user-avatar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.assistant-avatar {
|
||||
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
|
||||
box-shadow: 0 8rpx 24rpx rgba(255, 138, 128, 0.3);
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
background: linear-gradient(135deg, #81C784, #A5D6A7);
|
||||
box-shadow: 0 8rpx 24rpx rgba(129, 199, 132, 0.3);
|
||||
}
|
||||
|
||||
.avatar-emoji {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
max-width: 70%;
|
||||
padding: 20rpx;
|
||||
|
||||
:deep(.u-text) {
|
||||
line-height: 1.5;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 65%;
|
||||
}
|
||||
|
||||
.input-area {
|
||||
background-color: white;
|
||||
padding: 20rpx 30rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
.message-content.user {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
.message-content.ai {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
:deep(.u-input) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.message-bubble {
|
||||
padding: 20rpx 24rpx;
|
||||
border-radius: 24rpx;
|
||||
word-wrap: break-word;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.message-bubble.ai {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10rpx);
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
|
||||
border-bottom-left-radius: 8rpx;
|
||||
}
|
||||
|
||||
.message-bubble.ai.typing-bubble {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.message-bubble.user {
|
||||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 100%);
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.3);
|
||||
border-bottom-right-radius: 8rpx;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
font-size: 28rpx;
|
||||
line-height: 1.4;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.message-bubble.user .message-text {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.message-time {
|
||||
margin-top: 8rpx;
|
||||
font-size: 20rpx;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.message-content.user .message-time {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.message-content.ai .message-time {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.typing-dots {
|
||||
display: flex;
|
||||
gap: 8rpx;
|
||||
justify-content: center;
|
||||
|
||||
.typing-dot {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #FF8A80;
|
||||
animation: typing 1.4s infinite ease-in-out;
|
||||
|
||||
&:nth-child(1) { animation-delay: -0.32s; }
|
||||
&:nth-child(2) { animation-delay: -0.16s; }
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
0%, 80%, 100% {
|
||||
transform: scale(0.8);
|
||||
opacity: 0.5;
|
||||
}
|
||||
40% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-input-area {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(20rpx);
|
||||
padding: 16rpx 20rpx;
|
||||
//padding-bottom: calc(16rpx + env(safe-area-inset-bottom));
|
||||
border-top: 1rpx solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
|
||||
.input-wrapper {
|
||||
flex: 1;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 28rpx;
|
||||
padding: 0 20rpx;
|
||||
backdrop-filter: blur(10rpx);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
height: 56rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.message-input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.send-button {
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 24rpx;
|
||||
background: rgba(200, 200, 200, 0.5);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.send-text {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.send-button.active {
|
||||
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 100%);
|
||||
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.4);
|
||||
|
||||
.send-text {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue