From f945f2fe9dae35c3b5fd4beea2b182904df0e16e Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 29 四月 2026 10:56:25 +0800
Subject: [PATCH] feat(AIChatSidebar): 添加AI助手欢迎界面和快速提示功能

---
 src/components/AIChatSidebar/index.vue | 1014 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 989 insertions(+), 25 deletions(-)

diff --git a/src/components/AIChatSidebar/index.vue b/src/components/AIChatSidebar/index.vue
index bab4dea..548ec31 100644
--- a/src/components/AIChatSidebar/index.vue
+++ b/src/components/AIChatSidebar/index.vue
@@ -41,18 +41,18 @@
           </div>
           <div class="header-actions">
             <el-tooltip content="浼氳瘽鍘嗗彶" placement="bottom">
-              <el-button link @click="toggleHistory">
+              <el-button link class="header-action-btn" @click="handleToggleHistory">
                 <el-icon :size="18"><Timer /></el-icon>
               </el-button>
             </el-tooltip>
             <el-tooltip content="寮�鍚柊浼氳瘽" placement="bottom">
-              <el-button link @click="newChat">
+              <el-button link class="header-action-btn" @click="handleNewChat">
                 <el-icon :size="18"><Plus /></el-icon>
               </el-button>
             </el-tooltip>
             <div class="action-divider"></div>
             <el-tooltip content="鍏抽棴" placement="bottom">
-              <el-button link class="close-btn" @click="visible = false">
+              <el-button link class="header-action-btn close-btn" @click="handleManualClose">
                 <el-icon :size="18"><Close /></el-icon>
               </el-button>
             </el-tooltip>
@@ -99,6 +99,80 @@
         </div>
 
         <div v-else class="chat-main">
+          <div :class="['chat-hero', { compact: hasMessages }]">
+            <div :class="['assistant-stand', { thinking: isSending, compact: hasMessages }]">
+              <div class="assistant-halo"></div>
+              <div class="assistant-scan-ring"></div>
+              <div class="assistant-orbit assistant-orbit-a"></div>
+              <div class="assistant-orbit assistant-orbit-b"></div>
+              <div class="assistant-bot">
+                <div class="assistant-bot-antenna assistant-bot-antenna-left"></div>
+                <div class="assistant-bot-antenna assistant-bot-antenna-right"></div>
+                <div class="assistant-bot-head">
+                  <div class="assistant-bot-head-glow"></div>
+                  <div class="assistant-bot-eye assistant-bot-eye-left"></div>
+                  <div class="assistant-bot-eye assistant-bot-eye-right"></div>
+                  <div class="assistant-bot-mouth"></div>
+                </div>
+                <div class="assistant-bot-neck"></div>
+                <div class="assistant-bot-body">
+                  <div class="assistant-bot-core">
+                    <div class="assistant-bot-core-ring"></div>
+                    <el-icon :size="22"><component :is="currentAssistant.icon" /></el-icon>
+                  </div>
+                  <div class="assistant-bot-arm assistant-bot-arm-left"></div>
+                  <div class="assistant-bot-arm assistant-bot-arm-right"></div>
+                </div>
+              </div>
+              <div class="assistant-status">
+                <span class="assistant-status-dot"></span>
+                {{ isSending ? '鎬濊�冧腑...' : currentAssistant.label }}
+              </div>
+              <div class="assistant-base assistant-base-lg"></div>
+              <div class="assistant-base assistant-base-md"></div>
+              <div class="assistant-base assistant-base-sm"></div>
+            </div>
+
+            <div :class="['welcome-card', { compact: hasMessages }]">
+              <div class="welcome-eyebrow">鏅鸿兘鍔╂墜</div>
+              <h3 class="welcome-title">
+                鎮ㄥソ
+                <br />
+                鎴戞槸{{ currentAssistant.label }}鍒嗘瀽瑙h鍔╂墜
+              </h3>
+              <p class="welcome-desc">
+                {{ currentAssistant.description || '鎴戝彲浠ュ洿缁曚笟鍔¢棶棰樻彁渚涜В璇汇�佹煡璇㈠缓璁拰鍒嗘瀽鏀寔锛屽府鍔╀綘鏇村揩瀹屾垚鍒ゆ柇涓庡鐞嗐��' }}
+              </p>
+
+              <div class="quick-prompt-list">
+                <button
+                    v-for="prompt in displayedQuickPrompts"
+                    :key="prompt"
+                    type="button"
+                    class="quick-prompt-btn"
+                    :disabled="isSending"
+                    @click="sendQuickPrompt(prompt)"
+                >
+                  {{ prompt }}
+                </button>
+              </div>
+
+              <button
+                  v-if="quickPrompts.length > quickPromptLimit"
+                  type="button"
+                  class="more-prompts-btn"
+                  @click="refreshQuickPrompts"
+              >
+                <el-icon><RefreshRight /></el-icon>
+                <span>鎹竴鎹�</span>
+              </button>
+            </div>
+          </div>
+
+          <div v-show="!hasMessages" class="hero-dot-grid" aria-hidden="true">
+            <span v-for="dot in 28" :key="dot"></span>
+          </div>
+
           <div class="message-list" ref="messageListRef">
             <div
                 v-for="(message, index) in messages"
@@ -149,10 +223,10 @@
 
           <div class="input-area">
             <div class="input-actions">
-              <el-button link type="primary" size="small" @click="newChat">
+              <el-button link class="utility-action-btn" type="primary" size="small" @click="handleNewChat">
                 <el-icon><Plus /></el-icon>鏂颁細璇�
               </el-button>
-              <el-button v-if="isSending" link type="danger" size="small" @click="stopGeneration">
+              <el-button v-if="isSending" link class="utility-action-btn stop-action-btn" type="danger" size="small" @click="stopGeneration">
                 <el-icon><VideoPause /></el-icon>鍋滄鐢熸垚
               </el-button>
               <el-upload
@@ -164,7 +238,7 @@
                   :on-change="handleFileChange"
                   :disabled="isSending"
               >
-                <el-button link type="primary" size="small" :disabled="isSending">
+                <el-button link class="utility-action-btn upload-action-btn" type="primary" size="small" :disabled="isSending">
                   <el-icon><Upload /></el-icon>鍒嗘瀽鏂囦欢
                 </el-button>
               </el-upload>
@@ -188,8 +262,9 @@
                   class="send-btn"
                   :disabled="isSending || (!inputMessage.trim() && !selectedFile)"
                   @click="sendMessage"
+                  aria-label="鍙戦��"
               >
-                鍙戦��
+                <el-icon><Promotion /></el-icon>
               </el-button>
             </div>
           </div>
@@ -203,7 +278,7 @@
 import { ref, onMounted, onUnmounted, nextTick, watch, computed } from 'vue'
 import request from '@/utils/request'
 import * as echarts from 'echarts'
-import { Cpu, User, Plus, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close, ShoppingCart } from '@element-plus/icons-vue'
+import { Cpu, User, Plus, Timer, Delete, ChatDotSquare, VideoPause, Upload, Document, Close, ShoppingCart, Promotion, RefreshRight } from '@element-plus/icons-vue'
 import { ElMessage } from 'element-plus'
 
 const props = defineProps({
@@ -228,6 +303,7 @@
     storageKey: 'ai_chat_uuid',
     placeholder: '璇疯緭鍏ユ偍鐨勯棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)',
     welcomeMessage: '浣犲ソ',
+    description: '鎴戝彲浠ュ洖绛斾綘鐨勯棶棰橈紝涓轰綘鎻愪緵涓氬姟鏁版嵁瑙h淇℃伅銆佸鐞嗗缓璁拰杈呭姪鍐崇瓥鏀寔銆�',
     allowFileUpload: true,
     emptySessionText: '鏆傛棤鍘嗗彶浼氳瘽'
   },
@@ -241,6 +317,7 @@
     storageKey: 'purchase_ai_chat_uuid',
     placeholder: '璇疯緭鍏ラ噰璐棶棰�... (Enter 鍙戦��, Shift+Enter 鎹㈣)',
     welcomeMessage: '浣犲ソ',
+    description: '鎴戝彲浠ュ崗鍔╀綘鍒嗘瀽閲囪喘璁㈠崟銆佸埌璐ц繘搴︺�佷緵搴斿晢琛ㄧ幇鍜屼粯娆炬儏鍐碉紝甯姪浣犲揩閫熷畾浣嶉噰璐紓甯搞��',
     allowFileUpload: false,
     emptySessionText: '鏆傛棤閲囪喘浼氳瘽'
   }
@@ -250,6 +327,52 @@
 const selectedAssistantKey = ref(props.defaultAssistant || assistants.value[0]?.key || 'general')
 const currentAssistant = computed(() => assistants.value.find(item => item.key === selectedAssistantKey.value) || assistants.value[0] || builtInAssistants[0])
 const showAssistantSwitch = computed(() => assistants.value.length > 1)
+const assistantQuickPromptMap = {
+  general: [
+    '鎴戝綋鍓嶆湁鍝簺瀹℃壒寰呭姙闇�瑕佸鐞嗭紵',
+    '甯垜鍒楀嚭浠婂ぉ鏂板鐨勫鎵瑰緟鍔炪��',
+    '褰撳墠寰呮垜瀹℃壒鐨勫崟鎹紝鎸夋椂闂村�掑簭鍒楀嚭鏉ャ��',
+    '鎴戝彂璧风殑瀹℃壒閲岋紝鍝簺杩樺湪澶勭悊涓紵',
+    '鏌ヨ娴佺▼缂栧彿 XXX 鐨勫鎵硅鎯呫��',
+    '娴佺▼缂栧彿 XXX 鐜板湪鍗″湪鍝釜瀹℃壒鑺傜偣锛熷綋鍓嶅鎵逛汉鏄皝锛�',
+    '甯垜鏌ョ湅娴佺▼缂栧彿 XXX 鐨勫鎵规祦杞褰曘��',
+    '杩�7澶╂垜鐨勫鎵瑰緟鍔炵粺璁℃儏鍐垫�庝箞鏍凤紵',
+    '鏈湀鎴戠殑瀹℃壒涓紝閫氳繃銆侀┏鍥炪�佸鐞嗕腑鍚勬湁澶氬皯锛�',
+    '杩�30澶╁悇绫诲瀷瀹℃壒鏁伴噺鍒嗗竷鏄粈涔堬紵',
+    '甯垜瀹℃壒閫氳繃娴佺▼缂栧彿 XXX锛屽娉ㄢ�滃悓鎰忊�濄��',
+    '甯垜椹冲洖娴佺▼缂栧彿 XXX锛屽娉ㄢ�滆琛ュ厖璇存槑鈥濄��',
+    '鎾ら攢鎴戝垰鍒氬娴佺▼缂栧彿 XXX 鐨勫鎵规搷浣溿��',
+    '甯垜淇敼娴佺▼缂栧彿 XXX 鐨勫娉ㄤ负鈥滃凡琛ュ厖闄勪欢鈥濄��',
+    '鍒犻櫎鎴戝彂璧风殑娴佺▼缂栧彿 XXX銆�'
+  ],
+  purchase: [
+    '鏈湀閲囪喘閲戦鎺掑悕鍓嶅崄鐨勭墿鏂欐湁鍝簺锛�',
+    '鍝簺閲囪喘璁㈠崟杩樻湭鍏ュ簱锛�',
+    '鏈�杩�7澶╀緵搴斿晢鍒拌揣寮傚父鏈夊摢浜涳紵',
+    '甯垜缁熻寰呬粯娆鹃噰璐崟',
+    '鍒楀嚭鏈湀閲囪喘閫�璐ф儏鍐�'
+  ]
+}
+const quickPromptLimit = 3
+const quickPromptStart = ref(0)
+const quickPrompts = computed(() => {
+  const assistant = currentAssistant.value || {}
+  if (Array.isArray(assistant.quickPrompts) && assistant.quickPrompts.length) {
+    return assistant.quickPrompts
+  }
+  return assistantQuickPromptMap[assistant.key] || assistantQuickPromptMap.general
+})
+const displayedQuickPrompts = computed(() => {
+  const prompts = quickPrompts.value || []
+  if (prompts.length <= quickPromptLimit) return prompts
+
+  const result = []
+  for (let i = 0; i < quickPromptLimit; i++) {
+    result.push(prompts[(quickPromptStart.value + i) % prompts.length])
+  }
+  return result
+})
+const hasMessages = computed(() => messages.value.length > 0)
 
 const visible = ref(false)
 const windowWidth = ref(window.innerWidth)
@@ -274,11 +397,31 @@
 const sessions = ref([])
 const loadingSessions = ref(false)
 
+const abortCurrentRequest = () => {
+  if (!currentAbortController.value) return
+
+  currentAbortController.value.abort()
+  currentAbortController.value = null
+  isSending.value = false
+
+  const lastMsg = messages.value[messages.value.length - 1]
+  if (lastMsg && !lastMsg.isUser) {
+    lastMsg.isTyping = false
+  }
+}
+
 const toggleHistory = () => {
   showHistory.value = !showHistory.value
   if (showHistory.value) {
     loadSessions()
   }
+}
+
+const handleToggleHistory = () => {
+  if (isSending.value) {
+    abortCurrentRequest()
+  }
+  toggleHistory()
 }
 
 const loadSessions = async () => {
@@ -395,12 +538,7 @@
 watch(selectedAssistantKey, (nextKey, prevKey) => {
   if (!prevKey || nextKey === prevKey) return
 
-  if (currentAbortController.value) {
-    currentAbortController.value.abort()
-    currentAbortController.value = null
-  }
-
-  isSending.value = false
+  abortCurrentRequest()
   disposeCharts()
   messages.value = []
   outputState.value = {}
@@ -408,6 +546,7 @@
   showHistory.value = false
   selectedFile.value = null
   inputMessage.value = ''
+  quickPromptStart.value = 0
   initUUID()
   hello()
 })
@@ -425,6 +564,13 @@
 
 const handleClose = () => {
   visible.value = false
+}
+
+const handleManualClose = () => {
+  if (isSending.value) {
+    abortCurrentRequest()
+  }
+  handleClose()
 }
 
 const initUUID = () => {
@@ -447,9 +593,29 @@
   sessions.value = []
   showHistory.value = false
   selectedFile.value = null
+  quickPromptStart.value = 0
   localStorage.removeItem(currentAssistant.value.storageKey)
   initUUID()
   hello()
+}
+
+const handleNewChat = () => {
+  if (isSending.value) {
+    abortCurrentRequest()
+  }
+  newChat()
+}
+
+const sendQuickPrompt = (prompt) => {
+  if (!prompt || isSending.value) return
+  inputMessage.value = prompt
+  sendMessage()
+}
+
+const refreshQuickPrompts = () => {
+  const prompts = quickPrompts.value || []
+  if (prompts.length <= quickPromptLimit) return
+  quickPromptStart.value = (quickPromptStart.value + quickPromptLimit) % prompts.length
 }
 
 const disposeCharts = () => {
@@ -673,17 +839,7 @@
 }
 
 const stopGeneration = () => {
-  if (currentAbortController.value) {
-    currentAbortController.value.abort()
-    currentAbortController.value = null
-    isSending.value = false
-
-    // 灏嗘渶鍚庝竴鏉℃秷鎭爣璁颁负闈炴墦瀛楃姸鎬�
-    const lastMsg = messages.value[messages.value.length - 1]
-    if (lastMsg && !lastMsg.isUser) {
-      lastMsg.isTyping = false
-    }
-  }
+  abortCurrentRequest()
 }
 
 const sendRequest = (message) => {
@@ -1376,6 +1532,40 @@
         }
       }
     }
+
+    :deep(.header-action-btn) {
+      position: relative;
+      overflow: hidden;
+      background: linear-gradient(180deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.08));
+      border: 1px solid rgba(255, 255, 255, 0.16);
+      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 10px 18px rgba(0, 0, 0, 0.12);
+
+      &::before {
+        content: '';
+        position: absolute;
+        inset: 0;
+        background: linear-gradient(135deg, rgba(255, 255, 255, 0.22), transparent 55%);
+        pointer-events: none;
+      }
+
+      &::after {
+        content: '';
+        position: absolute;
+        top: -120%;
+        left: -40%;
+        width: 60%;
+        height: 260%;
+        background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.28), transparent);
+        transform: rotate(24deg);
+        opacity: 0;
+        transition: all 0.35s ease;
+      }
+
+      &:hover::after {
+        left: 100%;
+        opacity: 1;
+      }
+    }
   }
 
   .assistant-switcher {
@@ -1392,6 +1582,11 @@
       gap: 6px;
       flex-wrap: wrap;
       justify-content: center;
+      padding: 4px;
+      border-radius: 999px;
+      background: linear-gradient(180deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.08));
+      border: 1px solid rgba(255, 255, 255, 0.12);
+      box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 10px 18px rgba(0, 0, 0, 0.1);
     }
 
     :deep(.el-radio-button__inner) {
@@ -1839,6 +2034,40 @@
       display: inline-flex;
       align-items: center;
     }
+
+    :deep(.utility-action-btn) {
+      position: relative;
+      height: 34px;
+      padding: 0 14px;
+      border-radius: 999px;
+      border: 1px solid rgba(92, 119, 255, 0.18);
+      background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(236, 243, 255, 0.98));
+      color: $primary-blue;
+      font-weight: 600;
+      box-shadow: 0 10px 20px rgba(0, 85, 212, 0.08);
+      transition: all 0.25s ease;
+
+      .el-icon {
+        margin-right: 5px;
+      }
+
+      &:hover:not(.is-disabled) {
+        color: #fff;
+        border-color: transparent;
+        background: linear-gradient(135deg, #1f6dff 0%, #6b38ef 100%);
+        box-shadow: 0 14px 24px rgba(64, 90, 255, 0.2);
+        transform: translateY(-1px);
+      }
+    }
+
+    :deep(.stop-action-btn) {
+      border-color: rgba(255, 99, 123, 0.18);
+      color: #d33e5e;
+
+      &:hover:not(.is-disabled) {
+        background: linear-gradient(135deg, #f5536e 0%, #a33cff 100%);
+      }
+    }
   }
 
   .input-box {
@@ -1944,6 +2173,10 @@
       box-shadow: 0 6px 20px rgba(0, 85, 212, 0.4);
       transition: all 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275);
       overflow: hidden;
+      display: inline-flex;
+      align-items: center;
+      gap: 6px;
+      letter-spacing: 0.3px;
 
       &::before {
         content: '';
@@ -1973,6 +2206,11 @@
         background: linear-gradient(145deg, #b0b0b0, #c5c5c5);
         box-shadow: none;
         cursor: not-allowed;
+      }
+
+      .el-icon {
+        font-size: 15px;
+        transform: translateY(-1px);
       }
     }
   }
@@ -2034,4 +2272,730 @@
     color: #5ac8fa;
   }
 }
+
+.chat-main {
+  background:
+    radial-gradient(circle at top left, rgba(46, 140, 224, 0.12) 0%, transparent 34%),
+    linear-gradient(180deg, #fff 0%, #f7fbff 46%, #fff 100%);
+}
+
+.chat-hero {
+  display: grid;
+  grid-template-columns: 164px minmax(0, 1fr);
+  gap: 18px;
+  align-items: start;
+  padding: 14px 18px 6px;
+
+  &.compact {
+    grid-template-columns: 122px minmax(0, 1fr);
+    gap: 12px;
+    padding: 8px 18px 2px;
+  }
+}
+
+.assistant-stand {
+  position: relative;
+  min-height: 252px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
+  padding-top: 18px;
+  overflow: hidden;
+
+  &.compact {
+    min-height: 176px;
+    padding-top: 8px;
+  }
+
+  &.thinking {
+    .assistant-halo {
+      opacity: 1;
+      transform: scale(1.08);
+      filter: blur(8px);
+    }
+
+    .assistant-scan-ring {
+      opacity: 1;
+      animation-duration: 1.6s;
+    }
+
+    .assistant-orbit {
+      opacity: 1;
+    }
+
+    .assistant-bot {
+      transform: translateY(-4px) scale(1.02);
+    }
+
+    .assistant-bot-head {
+      box-shadow: 0 0 30px rgba(80, 157, 255, 0.36);
+    }
+
+    .assistant-bot-eye {
+      animation: robotBlinkFast 1.1s infinite;
+      box-shadow: 0 0 16px rgba(72, 186, 255, 0.95);
+    }
+
+    .assistant-bot-mouth {
+      width: 28px;
+      opacity: 1;
+      animation: robotTalk 1.2s ease-in-out infinite;
+    }
+
+    .assistant-bot-core {
+      animation: corePulse 1.4s ease-in-out infinite;
+      box-shadow: 0 0 24px rgba(78, 120, 255, 0.26);
+    }
+
+    .assistant-bot-core-ring {
+      animation: coreRotate 3s linear infinite;
+    }
+
+    .assistant-status {
+      color: #6a3bee;
+      box-shadow: 0 10px 22px rgba(106, 59, 238, 0.14);
+    }
+
+    .assistant-status-dot {
+      background: #6a3bee;
+      box-shadow: 0 0 12px rgba(106, 59, 238, 0.9);
+      animation: thinkingDot 1s ease-in-out infinite;
+    }
+
+    .assistant-base-sm {
+      box-shadow: 0 0 24px rgba(255, 93, 122, 0.48);
+    }
+  }
+}
+
+.assistant-halo {
+  position: absolute;
+  top: 22px;
+  width: 130px;
+  height: 130px;
+  border-radius: 50%;
+  background: radial-gradient(circle, rgba(46, 140, 224, 0.3) 0%, rgba(0, 85, 212, 0.18) 42%, rgba(113, 54, 244, 0.12) 60%, transparent 78%);
+  filter: blur(6px);
+  opacity: 0.82;
+  transition: all 0.35s ease;
+}
+
+.assistant-scan-ring {
+  position: absolute;
+  top: 40px;
+  width: 132px;
+  height: 132px;
+  border-radius: 50%;
+  border: 1px solid rgba(90, 159, 224, 0.22);
+  box-shadow: inset 0 0 16px rgba(255, 255, 255, 0.25);
+  opacity: 0.55;
+  animation: scanRing 4s linear infinite;
+}
+
+.assistant-orbit {
+  position: absolute;
+  top: 52px;
+  width: 150px;
+  height: 150px;
+  border-radius: 50%;
+  border: 1px dashed rgba(92, 135, 255, 0.22);
+  opacity: 0.45;
+}
+
+.assistant-orbit-a {
+  animation: orbitRotate 8s linear infinite;
+}
+
+.assistant-orbit-b {
+  width: 118px;
+  height: 118px;
+  top: 68px;
+  border-color: rgba(255, 108, 150, 0.22);
+  animation: orbitRotateReverse 5.6s linear infinite;
+}
+
+.assistant-bot {
+  position: relative;
+  z-index: 1;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  margin-top: 12px;
+  transition: transform 0.35s ease;
+}
+
+.assistant-bot-antenna {
+  position: absolute;
+  top: -4px;
+  width: 4px;
+  height: 20px;
+  border-radius: 999px;
+  background: linear-gradient(180deg, #fefefe, #aac9ff);
+
+  &::before {
+    content: '';
+    position: absolute;
+    top: -6px;
+    left: 50%;
+    width: 10px;
+    height: 10px;
+    border-radius: 50%;
+    transform: translateX(-50%);
+    background: linear-gradient(135deg, #54bfff, #7a41ff);
+    box-shadow: 0 0 14px rgba(84, 191, 255, 0.65);
+  }
+}
+
+.assistant-bot-antenna-left {
+  left: 36px;
+  transform: rotate(-14deg);
+}
+
+.assistant-bot-antenna-right {
+  right: 36px;
+  transform: rotate(14deg);
+}
+
+.assistant-bot-head {
+  position: relative;
+  width: 92px;
+  height: 78px;
+  border-radius: 28px;
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, #e8f1ff 100%);
+  border: 1px solid rgba(0, 85, 212, 0.14);
+  box-shadow: 0 16px 32px rgba(0, 85, 212, 0.14);
+}
+
+.assistant-bot-head-glow {
+  position: absolute;
+  inset: 10px 16px auto;
+  height: 20px;
+  border-radius: 999px;
+  background: linear-gradient(180deg, rgba(0, 85, 212, 0.16), transparent);
+}
+
+.assistant-bot-eye {
+  position: absolute;
+  top: 30px;
+  width: 16px;
+  height: 16px;
+  border-radius: 50%;
+  background: radial-gradient(circle, #8ef0ff 0%, #56c0ff 42%, #2869ff 100%);
+  box-shadow: 0 0 12px rgba(72, 186, 255, 0.72);
+  animation: robotBlink 3.2s infinite;
+}
+
+.assistant-bot-eye-left {
+  left: 22px;
+}
+
+.assistant-bot-eye-right {
+  right: 22px;
+}
+
+.assistant-bot-mouth {
+  position: absolute;
+  left: 50%;
+  bottom: 16px;
+  width: 22px;
+  height: 4px;
+  transform: translateX(-50%);
+  border-radius: 999px;
+  background: linear-gradient(90deg, rgba(72, 186, 255, 0.2), rgba(72, 186, 255, 0.9), rgba(72, 186, 255, 0.2));
+}
+
+.assistant-bot-neck {
+  width: 16px;
+  height: 10px;
+  border-radius: 0 0 10px 10px;
+  background: linear-gradient(180deg, #dceaff, #bdd5ff);
+  margin-top: -2px;
+}
+
+.assistant-bot-body {
+  position: relative;
+  width: 104px;
+  height: 92px;
+  margin-top: 2px;
+  border-radius: 28px 28px 34px 34px;
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, #e3eeff 100%);
+  border: 1px solid rgba(0, 85, 212, 0.14);
+  box-shadow: 0 18px 36px rgba(0, 85, 212, 0.16);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.assistant-bot-arm {
+  position: absolute;
+  top: 18px;
+  width: 16px;
+  height: 44px;
+  border-radius: 999px;
+  background: linear-gradient(180deg, #eff5ff, #c7dbff);
+  border: 1px solid rgba(0, 85, 212, 0.12);
+}
+
+.assistant-bot-arm-left {
+  left: -10px;
+  transform: rotate(16deg);
+}
+
+.assistant-bot-arm-right {
+  right: -10px;
+  transform: rotate(-16deg);
+}
+
+.assistant-bot-core {
+  position: relative;
+  width: 46px;
+  height: 46px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: $primary-blue;
+  background: radial-gradient(circle, rgba(255, 255, 255, 1) 0%, #dae8ff 55%, #adc7ff 100%);
+}
+
+.assistant-bot-core-ring {
+  position: absolute;
+  inset: -6px;
+  border-radius: 50%;
+  border: 1px solid rgba(88, 135, 255, 0.3);
+  border-top-color: rgba(255, 96, 139, 0.85);
+  border-right-color: rgba(79, 145, 255, 0.9);
+}
+
+.assistant-status {
+  position: relative;
+  z-index: 1;
+  margin-top: 14px;
+  padding: 6px 12px;
+  border-radius: 999px;
+  font-size: 12px;
+  font-weight: 600;
+  color: $deep-blue;
+  background: rgba(255, 255, 255, 0.95);
+  border: 1px solid rgba(0, 85, 212, 0.12);
+  box-shadow: 0 8px 20px rgba(0, 85, 212, 0.08);
+  display: inline-flex;
+  align-items: center;
+  gap: 6px;
+}
+
+.assistant-status-dot {
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  background: #2e8ce0;
+  box-shadow: 0 0 10px rgba(46, 140, 224, 0.72);
+}
+
+.assistant-base {
+  position: absolute;
+  bottom: 0;
+  left: 50%;
+  transform: translateX(-50%);
+  border-radius: 50%;
+  border: 2px solid rgba(255, 93, 122, 0.22);
+  background: radial-gradient(circle, rgba(255, 255, 255, 0.9) 0%, rgba(255, 111, 145, 0.1) 70%, transparent 100%);
+}
+
+.assistant-base-lg {
+  width: 118px;
+  height: 30px;
+}
+
+.assistant-base-md {
+  bottom: 6px;
+  width: 88px;
+  height: 20px;
+  border-color: rgba(255, 93, 122, 0.34);
+}
+
+.assistant-base-sm {
+  bottom: 11px;
+  width: 54px;
+  height: 10px;
+  background: linear-gradient(90deg, rgba(255, 93, 122, 0.95), rgba(255, 173, 188, 0.9));
+  border: none;
+  box-shadow: 0 0 18px rgba(255, 93, 122, 0.38);
+}
+
+@keyframes robotBlink {
+  0%, 44%, 48%, 100% {
+    transform: scaleY(1);
+  }
+  46% {
+    transform: scaleY(0.14);
+  }
+}
+
+@keyframes robotBlinkFast {
+  0%, 100% {
+    transform: scaleY(1);
+  }
+  50% {
+    transform: scaleY(0.3);
+  }
+}
+
+@keyframes robotTalk {
+  0%, 100% {
+    transform: translateX(-50%) scaleX(1);
+  }
+  50% {
+    transform: translateX(-50%) scaleX(1.35);
+  }
+}
+
+@keyframes corePulse {
+  0%, 100% {
+    transform: scale(1);
+    filter: brightness(1);
+  }
+  50% {
+    transform: scale(1.08);
+    filter: brightness(1.08);
+  }
+}
+
+@keyframes coreRotate {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@keyframes orbitRotate {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+@keyframes orbitRotateReverse {
+  from {
+    transform: rotate(360deg);
+  }
+  to {
+    transform: rotate(0deg);
+  }
+}
+
+@keyframes scanRing {
+  0%, 100% {
+    transform: scale(0.96);
+    opacity: 0.42;
+  }
+  50% {
+    transform: scale(1.04);
+    opacity: 0.86;
+  }
+}
+
+@keyframes thinkingDot {
+  0%, 100% {
+    transform: scale(1);
+  }
+  50% {
+    transform: scale(1.35);
+  }
+}
+
+.welcome-card {
+  position: relative;
+  padding: 14px 14px 12px;
+  border-radius: 16px;
+  background:
+    linear-gradient(#fff, #fff) padding-box,
+    linear-gradient(135deg, rgba(255, 64, 96, 0.85), rgba(117, 65, 255, 0.9)) border-box;
+  border: 1px solid transparent;
+  box-shadow: 0 16px 36px rgba(0, 85, 212, 0.12);
+
+  &.compact {
+    padding: 10px 12px;
+    border-radius: 12px;
+    box-shadow: 0 8px 16px rgba(0, 85, 212, 0.07);
+
+    .welcome-eyebrow {
+      margin-bottom: 4px;
+    }
+
+    .welcome-title {
+      font-size: 17px;
+      line-height: 1.3;
+
+      br {
+        display: none;
+      }
+    }
+
+    .welcome-desc {
+      margin-top: 6px;
+      font-size: 12px;
+      line-height: 1.55;
+    }
+
+    .quick-prompt-list {
+      margin-top: 10px;
+      gap: 6px;
+    }
+
+    .quick-prompt-btn {
+      padding: 8px 10px;
+      font-size: 12px;
+      border-radius: 7px;
+    }
+
+    .more-prompts-btn {
+      margin-top: 8px;
+      font-size: 12px;
+    }
+  }
+}
+
+.welcome-eyebrow {
+  font-size: 11px;
+  font-weight: 700;
+  letter-spacing: 2px;
+  color: rgba(0, 85, 212, 0.58);
+  margin-bottom: 8px;
+}
+
+.welcome-title {
+  margin: 0;
+  font-size: 26px;
+  line-height: 1.2;
+  font-weight: 800;
+  color: #172033;
+}
+
+.welcome-desc {
+  margin: 10px 0 0;
+  font-size: 13px;
+  line-height: 1.7;
+  color: #5f6980;
+}
+
+.quick-prompt-list {
+  display: grid;
+  gap: 8px;
+  margin-top: 14px;
+}
+
+.quick-prompt-btn {
+  width: 100%;
+  border: none;
+  border-radius: 10px;
+  padding: 11px 14px;
+  text-align: left;
+  font-size: 13px;
+  font-weight: 600;
+  color: #fff;
+  cursor: pointer;
+  background: linear-gradient(90deg, #ff4c55 0%, #7c38ef 100%);
+  box-shadow: 0 12px 22px rgba(124, 56, 239, 0.18);
+  transition: transform 0.25s ease, box-shadow 0.25s ease, opacity 0.2s ease;
+  position: relative;
+  overflow: hidden;
+
+  &::before {
+    content: '';
+    position: absolute;
+    inset: 0;
+    background: linear-gradient(135deg, rgba(255, 255, 255, 0.22), transparent 56%);
+    pointer-events: none;
+  }
+
+  &::after {
+    content: '';
+    position: absolute;
+    top: -120%;
+    left: -30%;
+    width: 45%;
+    height: 260%;
+    background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.3), transparent);
+    transform: rotate(22deg);
+    opacity: 0;
+    transition: all 0.35s ease;
+  }
+
+  &:hover:not(:disabled) {
+    transform: translateY(-2px) scale(1.01);
+    box-shadow: 0 16px 28px rgba(124, 56, 239, 0.24);
+
+    &::after {
+      left: 100%;
+      opacity: 1;
+    }
+  }
+
+  &:disabled {
+    cursor: not-allowed;
+    opacity: 0.65;
+  }
+}
+
+.more-prompts-btn {
+  margin-top: 10px;
+  padding: 0 12px;
+  height: 32px;
+  border: 1px solid rgba(208, 65, 81, 0.12);
+  border-radius: 999px;
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(255, 241, 245, 0.96));
+  color: #d04151;
+  font-size: 13px;
+  font-weight: 600;
+  cursor: pointer;
+  display: inline-flex;
+  align-items: center;
+  gap: 6px;
+  box-shadow: 0 10px 18px rgba(208, 65, 81, 0.08);
+  transition: all 0.25s ease;
+
+  &:hover {
+    transform: translateY(-1px);
+    background: linear-gradient(135deg, #ff5570 0%, #8a3df6 100%);
+    border-color: transparent;
+    color: #fff;
+    box-shadow: 0 14px 24px rgba(138, 61, 246, 0.18);
+  }
+}
+
+.hero-dot-grid {
+  display: grid;
+  grid-template-columns: repeat(14, 1fr);
+  gap: 7px;
+  padding: 0 18px 14px;
+
+  span {
+    display: block;
+    width: 100%;
+    aspect-ratio: 1;
+    border-radius: 2px;
+    background: linear-gradient(135deg, rgba(255, 110, 138, 0.95), rgba(255, 190, 201, 0.55));
+  }
+}
+
+.message-list {
+  padding: 8px 18px 18px;
+  gap: 16px;
+  background: transparent;
+}
+
+.input-area {
+  padding: 12px 18px 16px;
+  background: #fff;
+  border-top: none;
+
+  &::before {
+    display: none;
+  }
+
+  .input-box {
+    padding: 14px 16px 16px;
+    border: 1px solid rgba(123, 56, 239, 0.9);
+    border-radius: 22px;
+    margin: 0;
+    transition: all 0.25s ease;
+    box-shadow: 0 14px 34px rgba(0, 85, 212, 0.08);
+
+    &:focus-within {
+      border-color: #7c38ef;
+      box-shadow: 0 0 0 3px rgba(124, 56, 239, 0.1), 0 18px 40px rgba(0, 85, 212, 0.12);
+      transform: none;
+    }
+
+    :deep(.el-textarea__inner) {
+      padding-right: 58px;
+      padding-bottom: 0;
+      min-height: 104px;
+
+      &::placeholder {
+        color: #a0a9bc;
+      }
+    }
+
+    .send-btn {
+      right: 25px;
+      top: 50%;
+      transform: translateY(-50%);
+      width: 36px;
+      min-width: 36px;
+      height: 36px;
+      padding: 0;
+      background: linear-gradient(135deg, #ff5570 0%, #7a36f2 58%, #2d79ff 100%);
+      border-radius: 50%;
+      box-shadow: 0 12px 24px rgba(109, 50, 236, 0.24);
+      transition: all 0.25s ease;
+      gap: 0;
+
+      &:hover:not(:disabled) {
+        transform: translateY(calc(-50% - 1px)) scale(1.04);
+        box-shadow: 0 16px 28px rgba(109, 50, 236, 0.3);
+      }
+
+      &:active:not(:disabled) {
+        transform: translateY(-50%) scale(0.96);
+      }
+
+      .el-icon {
+        margin: 0;
+        font-size: 16px;
+        transform: translate(0, -1px);
+      }
+    }
+  }
+}
+
+@media (max-width: 767px) {
+  .chat-hero {
+    grid-template-columns: 1fr;
+    gap: 10px;
+    padding: 14px 14px 6px;
+
+    &.compact {
+      padding: 8px 14px 4px;
+    }
+  }
+
+  .assistant-stand {
+    min-height: 184px;
+  }
+
+  .welcome-card {
+    padding: 12px 12px 10px;
+  }
+
+  .welcome-title {
+    font-size: 21px;
+  }
+
+  .hero-dot-grid {
+    grid-template-columns: repeat(12, 1fr);
+    gap: 6px;
+    padding: 0 14px 12px;
+  }
+
+  .message-list {
+    padding: 8px 14px 14px;
+  }
+
+  .input-area {
+    padding: 10px 14px 14px;
+  }
+
+  .input-area .input-actions {
+    gap: 10px;
+    flex-wrap: wrap;
+  }
+}
 </style>

--
Gitblit v1.9.3