From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/ai/chat/index/components/message/MessageWebSearch.vue |  190 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 190 insertions(+), 0 deletions(-)

diff --git a/src/views/ai/chat/index/components/message/MessageWebSearch.vue b/src/views/ai/chat/index/components/message/MessageWebSearch.vue
new file mode 100644
index 0000000..f77e1ca
--- /dev/null
+++ b/src/views/ai/chat/index/components/message/MessageWebSearch.vue
@@ -0,0 +1,190 @@
+<!-- 鑱旂綉鎼滅储缁撴灉缁勪欢 -->
+<template>
+  <!-- 鑱旂綉鎼滅储缁撴灉鍒楄〃 -->
+  <div
+    v-if="webSearchPages && webSearchPages.length > 0"
+    class="mt-10px p-10px rounded-8px bg-[#f5f5f5]"
+  >
+    <!-- 鏍囬鏍忥細鍙偣鍑诲睍寮�/鏀惰捣 -->
+    <div
+      class="text-14px text-[#666] mb-8px flex items-center justify-between cursor-pointer hover:text-[#409eff]"
+      @click="toggleExpanded"
+    >
+      <div class="flex items-center">
+        <Icon icon="ep:search" class="mr-5px" />
+        鑱旂綉鎼滅储缁撴灉 ({{ webSearchPages.length }} 鏉�)
+      </div>
+      <Icon
+        :icon="isExpanded ? 'ep:arrow-up' : 'ep:arrow-down'"
+        class="text-12px transition-transform duration-200"
+      />
+    </div>
+
+    <!-- 鍙睍寮�鐨勬悳绱㈢粨鏋滃垪琛� -->
+    <div v-show="isExpanded" class="flex flex-col gap-8px transition-all duration-200 ease-in-out">
+      <div
+        v-for="(result, index) in webSearchPages"
+        :key="index"
+        class="p-10px bg-white rounded-6px cursor-pointer transition-all hover:bg-[#e6f4ff]"
+        @click="handleClick(result)"
+      >
+        <div class="flex items-start gap-8px">
+          <!-- 缃戠珯鍥炬爣 -->
+          <div class="flex-shrink-0 w-16px h-16px mt-2px">
+            <img
+              v-if="result.icon"
+              :src="result.icon"
+              :alt="result.name"
+              class="w-full h-full object-contain rounded-2px"
+              @error="handleImageError"
+            />
+            <Icon v-else icon="ep:link" class="w-full h-full text-[#666]" />
+          </div>
+
+          <!-- 鍐呭鍖哄煙 -->
+          <div class="flex-1 min-w-0">
+            <!-- 鏍囬鍜屾潵婧� -->
+            <div class="flex items-center gap-4px mb-4px">
+              <span class="text-12px text-[#999] truncate">{{ result.name }}</span>
+            </div>
+
+            <!-- 涓绘爣棰� -->
+            <div class="text-14px text-[#1a73e8] font-medium mb-4px line-clamp-2 leading-[1.4]">
+              {{ result.title }}
+            </div>
+
+            <!-- 鎻忚堪 -->
+            <div class="text-13px text-[#666] line-clamp-2 leading-[1.4] mb-4px">
+              {{ result.snippet }}
+            </div>
+
+            <!-- URL -->
+            <div class="text-12px text-[#006621] truncate">
+              {{ result.url }}
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- 鑱旂綉鎼滅储璇︽儏寮圭獥 -->
+  <el-popover
+    v-model:visible="dialogVisible"
+    :width="600"
+    trigger="click"
+    placement="top-start"
+    :offset="55"
+    popper-class="web-search-popover"
+  >
+    <template #reference>
+      <div ref="resultRef"></div>
+    </template>
+    <template #default>
+      <div v-if="selectedResult">
+        <!-- 鏍囬鍖哄煙 -->
+        <div class="flex items-start gap-8px mb-12px">
+          <div class="flex-shrink-0 w-20px h-20px mt-2px">
+            <img
+              v-if="selectedResult.icon"
+              :src="selectedResult.icon"
+              :alt="selectedResult.name"
+              class="w-full h-full object-contain rounded-2px"
+              @error="handleImageError"
+            />
+            <Icon v-else icon="ep:link" class="w-full h-full text-[#666]" />
+          </div>
+          <div class="flex-1 min-w-0">
+            <div class="text-16px font-bold text-[#333] mb-4px line-clamp-2">
+              {{ selectedResult.title }}
+            </div>
+            <div class="text-12px text-[#999] mb-4px">{{ selectedResult.name }}</div>
+            <div class="text-12px text-[#006621] break-all">{{ selectedResult.url }}</div>
+          </div>
+        </div>
+
+        <!-- 鍐呭鍖哄煙 -->
+        <div class="max-h-[60vh] overflow-y-auto">
+          <!-- 绠�鐭弿杩� -->
+          <div class="mb-12px">
+            <div class="text-14px font-medium text-[#333] mb-6px">绠�鐭弿杩�</div>
+            <div class="text-14px leading-[1.6] text-[#666] bg-[#f8f9fa] p-10px rounded-6px">
+              {{ selectedResult.snippet }}
+            </div>
+          </div>
+
+          <!-- 鍐呭鎽樿 -->
+          <div v-if="selectedResult.summary">
+            <div class="text-14px font-medium text-[#333] mb-6px">鍐呭鎽樿</div>
+            <div
+              class="text-14px leading-[1.6] text-[#333] bg-[#f8f9fa] p-10px rounded-6px whitespace-pre-wrap"
+            >
+              {{ selectedResult.summary }}
+            </div>
+          </div>
+        </div>
+
+        <!-- 鎿嶄綔鎸夐挳 -->
+        <div class="flex justify-end gap-8px mt-12px pt-12px border-t border-[#eee]">
+          <el-button size="small" @click="dialogVisible = false">鍏抽棴</el-button>
+          <el-button type="primary" size="small" @click="openUrl(selectedResult.url)">
+            璁块棶鍘熸枃
+          </el-button>
+        </div>
+      </div>
+    </template>
+  </el-popover>
+</template>
+
+<script setup lang="ts">
+defineProps<{
+  webSearchPages: {
+    name: string // 鍚嶇О
+    icon: string // 鍥炬爣
+    title: string // 鏍囬
+    url: string // URL
+    snippet: string // 鍐呭鐨勭畝鐭弿杩�
+    summary: string // 鍐呭鐨勬枃鏈憳瑕�
+  }[]
+}>()
+
+const isExpanded = ref(false) // 鏄惁灞曞紑鎼滅储缁撴灉
+const selectedResult = ref<{
+  name: string
+  icon: string
+  title: string
+  url: string
+  snippet: string
+  summary: string
+} | null>(null) // 閫変腑鐨勬悳绱㈢粨鏋�
+const dialogVisible = ref(false) // 璇︽儏寮圭獥
+const resultRef = ref<HTMLElement>() // 璇︽儏寮圭獥 Ref
+
+/** 鍒囨崲灞曞紑/鏀惰捣鐘舵�� */
+const toggleExpanded = () => {
+  isExpanded.value = !isExpanded.value
+}
+
+/** 鐐瑰嚮鎼滅储缁撴灉澶勭悊 */
+const handleClick = (result: any) => {
+  selectedResult.value = result
+  dialogVisible.value = true
+}
+
+/** 澶勭悊鍥剧墖鍔犺浇閿欒 */
+const handleImageError = (event: Event) => {
+  const img = event.target as HTMLImageElement
+  img.style.display = 'none'
+}
+
+/** 鎵撳紑URL */
+const openUrl = (url: string) => {
+  window.open(url, '_blank')
+}
+</script>
+
+<style scoped>
+.web-search-popover {
+  max-width: 600px;
+}
+</style>

--
Gitblit v1.8.0