|
@@ -0,0 +1,604 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="guide-panel">
|
|
|
|
|
+ <div class="guide-container">
|
|
|
|
|
+ <div class="guide-header">
|
|
|
|
|
+ <div class="guide-title">
|
|
|
|
|
+ <span class="title-icon">🤖</span>
|
|
|
|
|
+ <span class="title-text">数字人导览</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="guide-close" @click="$emit('close')">×</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="guide-main">
|
|
|
|
|
+ <div class="guide-avatar-section">
|
|
|
|
|
+ <div class="avatar-wrapper">
|
|
|
|
|
+ <div class="avatar-glow"></div>
|
|
|
|
|
+ <div class="avatar-scan"></div>
|
|
|
|
|
+ <div class="avatar-body">
|
|
|
|
|
+ <div class="body-head">👤</div>
|
|
|
|
|
+ <div class="body-torso"></div>
|
|
|
|
|
+ <div class="body-legs">
|
|
|
|
|
+ <div class="leg left"></div>
|
|
|
|
|
+ <div class="leg right"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="avatar-wave" v-if="isSpeaking">
|
|
|
|
|
+ <span v-for="i in 7" :key="i" class="wave-bar" :style="{ animationDelay: `${i * 0.08}s` }"></span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="avatar-info">
|
|
|
|
|
+ <div class="avatar-name">水文智能导览员</div>
|
|
|
|
|
+ <div class="avatar-status" :class="{ speaking: isSpeaking }">
|
|
|
|
|
+ <span class="status-dot"></span>
|
|
|
|
|
+ <span class="status-text">{{ isSpeaking ? '正在回复...' : '等待提问' }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="guide-chat-section">
|
|
|
|
|
+ <div class="chat-header">
|
|
|
|
|
+ <span class="chat-title">💬 智能问答</span>
|
|
|
|
|
+ <span class="chat-tip">输入您的问题,数字人将为您解答</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="chat-messages" ref="chatMessagesRef">
|
|
|
|
|
+ <div class="chat-message ai" v-if="chatMessages.length === 0">
|
|
|
|
|
+ <div class="message-avatar">🤖</div>
|
|
|
|
|
+ <div class="message-content">
|
|
|
|
|
+ <div class="message-text">您好!我是水文智能导览员,请问有什么关于水文知识的问题需要咨询吗?</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <template v-for="(msg, index) in chatMessages" :key="index">
|
|
|
|
|
+ <div class="chat-message user">
|
|
|
|
|
+ <div class="message-avatar">👤</div>
|
|
|
|
|
+ <div class="message-content">
|
|
|
|
|
+ <div class="message-text">{{ msg.question }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="chat-message ai">
|
|
|
|
|
+ <div class="message-avatar">🤖</div>
|
|
|
|
|
+ <div class="message-content">
|
|
|
|
|
+ <div class="message-text">{{ msg.answer }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <div class="chat-message ai typing" v-if="isTyping">
|
|
|
|
|
+ <div class="message-avatar">🤖</div>
|
|
|
|
|
+ <div class="message-content">
|
|
|
|
|
+ <div class="typing-indicator">
|
|
|
|
|
+ <span></span>
|
|
|
|
|
+ <span></span>
|
|
|
|
|
+ <span></span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="chat-input-area">
|
|
|
|
|
+ <div class="quick-questions">
|
|
|
|
|
+ <span class="quick-label">快捷问题:</span>
|
|
|
|
|
+ <button
|
|
|
|
|
+ v-for="(q, index) in quickQuestions"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ class="quick-btn"
|
|
|
|
|
+ @click="sendQuickQuestion(q)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ q }}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="input-wrapper">
|
|
|
|
|
+ <input
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ v-model="inputMessage"
|
|
|
|
|
+ placeholder="请输入您的问题..."
|
|
|
|
|
+ @keyup.enter="sendMessage"
|
|
|
|
|
+ class="chat-input"
|
|
|
|
|
+ />
|
|
|
|
|
+ <button class="send-btn" @click="sendMessage" :disabled="!inputMessage.trim()">
|
|
|
|
|
+ 发送
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, nextTick } from "vue"
|
|
|
|
|
+
|
|
|
|
|
+defineEmits(["close"])
|
|
|
|
|
+
|
|
|
|
|
+const chatMessagesRef = ref(null)
|
|
|
|
|
+const inputMessage = ref("")
|
|
|
|
|
+const chatMessages = ref([])
|
|
|
|
|
+const isSpeaking = ref(false)
|
|
|
|
|
+const isTyping = ref(false)
|
|
|
|
|
+
|
|
|
|
|
+const quickQuestions = [
|
|
|
|
|
+ "什么是水文?",
|
|
|
|
|
+ "水位怎么测量?",
|
|
|
|
|
+ "洪水来了怎么办?",
|
|
|
|
|
+ "如何节约用水?"
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
|
|
+const knowledgeBase = {
|
|
|
|
|
+ "什么是水文": "水文是研究地球上水的起源、存在、分布、循环、运动等变化规律的科学。水文工作主要包括水位、流量、水质等要素的监测和分析,为水资源管理、防洪减灾等提供科学依据。",
|
|
|
|
|
+ "水位怎么测量": "水位测量常用的方法有:1. 水尺读数法:通过读取水尺刻度获取水位;2. 自记水位计:自动记录水位变化;3. 雷达水位计:利用雷达波测量水位,精度高。",
|
|
|
|
|
+ "洪水来了怎么办": "遇到洪水时:1. 保持冷静,迅速向高处转移;2. 远离低洼地区、河道和危险建筑;3. 不要游泳逃生,不要攀爬带电设施;4. 如被洪水包围,设法发出求救信号等待救援。",
|
|
|
|
|
+ "如何节约用水": "节水小技巧:1. 随手关闭水龙头;2. 使用节水器具;3. 一水多用,如洗菜水浇花;4. 缩短洗澡时间;5. 及时修复漏水设施。每个人的小行动,汇聚成节水大力量!"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getAnswer(question) {
|
|
|
|
|
+ const keywords = {
|
|
|
|
|
+ "水文": "水文是研究地球上水的起源、存在、分布、循环、运动等变化规律的科学。水文工作为水资源管理和防洪减灾提供重要支撑。",
|
|
|
|
|
+ "水位": "水位是指水体表面相对于某一基准面的高度。测量水位的方法有水尺、自记水位计、雷达水位计等。水位数据是水文监测的基础数据。",
|
|
|
|
|
+ "洪水": "洪水是由暴雨、融雪等引起的江河湖泊水量迅猛增加的现象。防洪措施包括工程措施(堤防、水库)和非工程措施(预报预警、应急预案)。",
|
|
|
|
|
+ "节水": "节约用水是保护水资源的重要方式。可以通过使用节水器具、一水多用、减少浪费等方式实现节水。",
|
|
|
|
|
+ "水资源": "水资源是指可资利用或有可能被利用的水源。我国水资源总量丰富,但人均占有量仅为世界平均水平的四分之一,需要珍惜保护。",
|
|
|
|
|
+ "水质": "水质是指水的物理、化学和生物特性。水质监测包括pH值、溶解氧、浊度、各类污染物等指标的检测,保障饮用水安全。",
|
|
|
|
|
+ "降雨": "降雨量使用雨量筒或雨量计测量,单位为毫米。降雨数据对于洪水预报、水资源计算等具有重要意义。",
|
|
|
|
|
+ "防汛": "防汛工作包括:完善防洪工程体系、加强监测预报预警、制定应急预案、开展防汛演练、普及防灾知识等。"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (const [key, answer] of Object.entries(keywords)) {
|
|
|
|
|
+ if (question.includes(key)) {
|
|
|
|
|
+ return answer
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return "感谢您的提问!关于" + question + ",建议您查阅相关的水文资料或咨询专业人士获取更详细的信息。我会持续学习,努力为您提供更好的服务。"
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function sendMessage() {
|
|
|
|
|
+ const message = inputMessage.value.trim()
|
|
|
|
|
+ if (!message) return
|
|
|
|
|
+
|
|
|
|
|
+ chatMessages.value.push({
|
|
|
|
|
+ question: message,
|
|
|
|
|
+ answer: ""
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ inputMessage.value = ""
|
|
|
|
|
+ isTyping.value = true
|
|
|
|
|
+
|
|
|
|
|
+ scrollToBottom()
|
|
|
|
|
+
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ const answer = getAnswer(message)
|
|
|
|
|
+ chatMessages.value[chatMessages.value.length - 1].answer = answer
|
|
|
|
|
+ isTyping.value = false
|
|
|
|
|
+ isSpeaking.value = true
|
|
|
|
|
+
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ isSpeaking.value = false
|
|
|
|
|
+ }, 2000)
|
|
|
|
|
+
|
|
|
|
|
+ scrollToBottom()
|
|
|
|
|
+ }, 1000 + Math.random() * 1000)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function sendQuickQuestion(question) {
|
|
|
|
|
+ inputMessage.value = question
|
|
|
|
|
+ sendMessage()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function scrollToBottom() {
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ if (chatMessagesRef.value) {
|
|
|
|
|
+ chatMessagesRef.value.scrollTop = chatMessagesRef.value.scrollHeight
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss">
|
|
|
|
|
+.guide-panel {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 80px;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ z-index: 100;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.85);
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ pointer-events: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.guide-container {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 95%;
|
|
|
|
|
+ max-width: 1600px;
|
|
|
|
|
+ height: 90%;
|
|
|
|
|
+ background: linear-gradient(135deg, rgba(0, 30, 60, 0.95) 0%, rgba(0, 50, 80, 0.95) 100%);
|
|
|
|
|
+ border: 2px solid rgba(48, 220, 255, 0.5);
|
|
|
|
|
+ border-radius: 10px;
|
|
|
|
|
+ box-shadow: 0 0 30px rgba(48, 220, 255, 0.3);
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.guide-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ padding: 20px 30px;
|
|
|
|
|
+ background: linear-gradient(90deg, rgba(48, 220, 255, 0.1) 0%, transparent 100%);
|
|
|
|
|
+ border-bottom: 1px solid rgba(48, 220, 255, 0.2);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.guide-title {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ .title-icon {
|
|
|
|
|
+ font-size: 28px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .title-text {
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ letter-spacing: 2px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.guide-close {
|
|
|
|
|
+ width: 36px;
|
|
|
|
|
+ height: 36px;
|
|
|
|
|
+ background: rgba(0, 20, 40, 0.8);
|
|
|
|
|
+ border: 1px solid rgba(48, 220, 255, 0.5);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ color: #30dcff;
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.3);
|
|
|
|
|
+ transform: scale(1.1);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.guide-main {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ padding: 30px;
|
|
|
|
|
+ gap: 30px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.guide-avatar-section {
|
|
|
|
|
+ width: 250px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ .avatar-wrapper {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 180px;
|
|
|
|
|
+ height: 280px;
|
|
|
|
|
+ .avatar-glow {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 50%;
|
|
|
|
|
+ left: 50%;
|
|
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
|
|
+ width: 160px;
|
|
|
|
|
+ height: 260px;
|
|
|
|
|
+ background: radial-gradient(ellipse, rgba(48, 220, 255, 0.15) 0%, transparent 70%);
|
|
|
|
|
+ animation: glowPulse 3s ease-in-out infinite;
|
|
|
|
|
+ }
|
|
|
|
|
+ .avatar-scan {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ height: 2px;
|
|
|
|
|
+ background: linear-gradient(90deg, transparent, rgba(48, 220, 255, 0.8), transparent);
|
|
|
|
|
+ animation: scanLine 3s linear infinite;
|
|
|
|
|
+ }
|
|
|
|
|
+ .avatar-body {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ .body-head {
|
|
|
|
|
+ width: 70px;
|
|
|
|
|
+ height: 70px;
|
|
|
|
|
+ background: linear-gradient(135deg, rgba(48, 220, 255, 0.3) 0%, rgba(0, 100, 150, 0.3) 100%);
|
|
|
|
|
+ border: 2px solid rgba(48, 220, 255, 0.5);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ font-size: 36px;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .body-torso {
|
|
|
|
|
+ width: 80px;
|
|
|
|
|
+ height: 100px;
|
|
|
|
|
+ background: linear-gradient(180deg, rgba(48, 220, 255, 0.25) 0%, rgba(48, 220, 255, 0.15) 100%);
|
|
|
|
|
+ border: 2px solid rgba(48, 220, 255, 0.4);
|
|
|
|
|
+ border-radius: 40px 40px 20px 20px;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .body-legs {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 15px;
|
|
|
|
|
+ .leg {
|
|
|
|
|
+ width: 25px;
|
|
|
|
|
+ height: 80px;
|
|
|
|
|
+ background: linear-gradient(180deg, rgba(48, 220, 255, 0.2) 0%, rgba(48, 220, 255, 0.1) 100%);
|
|
|
|
|
+ border: 2px solid rgba(48, 220, 255, 0.35);
|
|
|
|
|
+ border-radius: 12px 12px 8px 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .avatar-wave {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ bottom: -30px;
|
|
|
|
|
+ left: 50%;
|
|
|
|
|
+ transform: translateX(-50%);
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+ align-items: flex-end;
|
|
|
|
|
+ .wave-bar {
|
|
|
|
|
+ width: 5px;
|
|
|
|
|
+ background: linear-gradient(180deg, #30dcff, rgba(48, 220, 255, 0.3));
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+ animation: waveAnim 0.4s ease-in-out infinite alternate;
|
|
|
|
|
+ &:nth-child(1) { height: 15px; }
|
|
|
|
|
+ &:nth-child(2) { height: 25px; }
|
|
|
|
|
+ &:nth-child(3) { height: 35px; }
|
|
|
|
|
+ &:nth-child(4) { height: 40px; }
|
|
|
|
|
+ &:nth-child(5) { height: 35px; }
|
|
|
|
|
+ &:nth-child(6) { height: 25px; }
|
|
|
|
|
+ &:nth-child(7) { height: 15px; }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .avatar-info {
|
|
|
|
|
+ margin-top: 40px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ .avatar-name {
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .avatar-status {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ padding: 8px 20px;
|
|
|
|
|
+ background: rgba(100, 100, 100, 0.3);
|
|
|
|
|
+ border-radius: 20px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ .status-dot {
|
|
|
|
|
+ width: 8px;
|
|
|
|
|
+ height: 8px;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.4);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.speaking {
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.2);
|
|
|
|
|
+ color: #30dcff;
|
|
|
|
|
+ .status-dot {
|
|
|
|
|
+ background: #30dcff;
|
|
|
|
|
+ box-shadow: 0 0 10px rgba(48, 220, 255, 0.8);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@keyframes glowPulse {
|
|
|
|
|
+ 0%, 100% { opacity: 0.5; transform: translate(-50%, -50%) scale(1); }
|
|
|
|
|
+ 50% { opacity: 1; transform: translate(-50%, -50%) scale(1.1); }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@keyframes scanLine {
|
|
|
|
|
+ 0% { top: 0; opacity: 0; }
|
|
|
|
|
+ 10% { opacity: 1; }
|
|
|
|
|
+ 90% { opacity: 1; }
|
|
|
|
|
+ 100% { top: 100%; opacity: 0; }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@keyframes waveAnim {
|
|
|
|
|
+ 0% { transform: scaleY(0.6); }
|
|
|
|
|
+ 100% { transform: scaleY(1); }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.guide-chat-section {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 15px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.chat-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ padding-bottom: 15px;
|
|
|
|
|
+ border-bottom: 1px solid rgba(48, 220, 255, 0.1);
|
|
|
|
|
+ .chat-title {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #30dcff;
|
|
|
|
|
+ }
|
|
|
|
|
+ .chat-tip {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.chat-messages {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ padding-right: 10px;
|
|
|
|
|
+ &::-webkit-scrollbar {
|
|
|
|
|
+ width: 6px;
|
|
|
|
|
+ }
|
|
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.1);
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+ }
|
|
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.3);
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.chat-message {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ margin-bottom: 15px;
|
|
|
|
|
+ &.user {
|
|
|
|
|
+ flex-direction: row-reverse;
|
|
|
|
|
+ }
|
|
|
|
|
+ .message-avatar {
|
|
|
|
|
+ width: 36px;
|
|
|
|
|
+ height: 36px;
|
|
|
|
|
+ background: linear-gradient(135deg, rgba(48, 220, 255, 0.3) 0%, rgba(0, 100, 150, 0.3) 100%);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.user .message-avatar {
|
|
|
|
|
+ background: linear-gradient(135deg, rgba(0, 255, 136, 0.3) 0%, rgba(0, 150, 100, 0.3) 100%);
|
|
|
|
|
+ }
|
|
|
|
|
+ .message-content {
|
|
|
|
|
+ max-width: 80%;
|
|
|
|
|
+ .message-text {
|
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.1);
|
|
|
|
|
+ border: 1px solid rgba(48, 220, 255, 0.2);
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ border-top-left-radius: 4px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ line-height: 1.6;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ &.user .message-text {
|
|
|
|
|
+ background: rgba(0, 255, 136, 0.1);
|
|
|
|
|
+ border-color: rgba(0, 255, 136, 0.2);
|
|
|
|
|
+ border-top-left-radius: 12px;
|
|
|
|
|
+ border-top-right-radius: 4px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.typing-indicator {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+ padding: 16px;
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.1);
|
|
|
|
|
+ border: 1px solid rgba(48, 220, 255, 0.2);
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ border-top-left-radius: 4px;
|
|
|
|
|
+ span {
|
|
|
|
|
+ width: 8px;
|
|
|
|
|
+ height: 8px;
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.6);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ animation: typingBounce 0.6s ease-in-out infinite;
|
|
|
|
|
+ &:nth-child(2) {
|
|
|
|
|
+ animation-delay: 0.1s;
|
|
|
|
|
+ }
|
|
|
|
|
+ &:nth-child(3) {
|
|
|
|
|
+ animation-delay: 0.2s;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@keyframes typingBounce {
|
|
|
|
|
+ 0%, 100% {
|
|
|
|
|
+ transform: translateY(0);
|
|
|
|
|
+ }
|
|
|
|
|
+ 50% {
|
|
|
|
|
+ transform: translateY(-8px);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.chat-input-area {
|
|
|
|
|
+ padding-top: 15px;
|
|
|
|
|
+ border-top: 1px solid rgba(48, 220, 255, 0.1);
|
|
|
|
|
+ .quick-questions {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ .quick-label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
+ }
|
|
|
|
|
+ .quick-btn {
|
|
|
|
|
+ padding: 6px 14px;
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.1);
|
|
|
|
|
+ border: 1px solid rgba(48, 220, 255, 0.2);
|
|
|
|
|
+ border-radius: 15px;
|
|
|
|
|
+ color: rgba(48, 220, 255, 0.8);
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ background: rgba(48, 220, 255, 0.2);
|
|
|
|
|
+ border-color: rgba(48, 220, 255, 0.4);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .input-wrapper {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ .chat-input {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
|
+ background: rgba(0, 20, 40, 0.6);
|
|
|
|
|
+ border: 1px solid rgba(48, 220, 255, 0.3);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ outline: none;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ &::placeholder {
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.4);
|
|
|
|
|
+ }
|
|
|
|
|
+ &:focus {
|
|
|
|
|
+ border-color: rgba(48, 220, 255, 0.6);
|
|
|
|
|
+ box-shadow: 0 0 10px rgba(48, 220, 255, 0.2);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .send-btn {
|
|
|
|
|
+ padding: 12px 24px;
|
|
|
|
|
+ background: linear-gradient(135deg, rgba(48, 220, 255, 0.3) 0%, rgba(0, 100, 150, 0.3) 100%);
|
|
|
|
|
+ border: 1px solid rgba(48, 220, 255, 0.4);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+ &:hover:not(:disabled) {
|
|
|
|
|
+ background: linear-gradient(135deg, rgba(48, 220, 255, 0.5) 0%, rgba(0, 100, 150, 0.5) 100%);
|
|
|
|
|
+ box-shadow: 0 0 15px rgba(48, 220, 255, 0.3);
|
|
|
|
|
+ }
|
|
|
|
|
+ &:disabled {
|
|
|
|
|
+ opacity: 0.5;
|
|
|
|
|
+ cursor: not-allowed;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|