From 54572b3c9db78d4374281087a8c66e5c3b3b6200 Mon Sep 17 00:00:00 2001
From: sd <shidong@jhsoft.cc>
Date: 星期五, 08 八月 2025 17:28:08 +0800
Subject: [PATCH] 整合文搜万物模块

---
 src/api/SurveyView.ts                              |  101 +
 src/pages/datapush/index/RightEvent.vue            |   74 
 src/assets/img/conversation.png                    |    0 
 src/assets/img/AI-avatar.png                       |    0 
 src/api/AiRetrievalView.ts                         |   25 
 src/assets/img/historical copy.png                 |    0 
 src/assets/img/historical.png                      |    0 
 src/pages/searchNew/components/cameraVideo.vue     |  232 ++++
 src/pages/modelTuning/components/rightCardList.vue |    3 
 src/pages/searchNew/index/mixins.ts                |   25 
 src/assets/img/UDP配置.png                           |    0 
 src/assets/img/article-fill@1x copy.png            |    0 
 src/pages/searchNew/components/AiRetrievalView.vue |  938 ++++++++++++++++
 src/pages/searchNew/components/SurveyView.vue      | 1570 +++++++++++++++++++++++++++
 src/pages/searchNew/index/App.vue                  |  131 ++
 src/assets/img/time-fill@1x.png                    |    0 
 src/assets/img/live-fill@1x.png                    |    0 
 src/pages/searchNew/index/main.ts                  |   30 
 src/assets/img/fold_up.png                         |    0 
 src/api/ChatHistoryView.ts                         |   20 
 src/pages/searchNew/components/ChatHistoryView.vue |  248 ++++
 21 files changed, 3,375 insertions(+), 22 deletions(-)

diff --git a/src/api/AiRetrievalView.ts b/src/api/AiRetrievalView.ts
new file mode 100644
index 0000000..368a7d0
--- /dev/null
+++ b/src/api/AiRetrievalView.ts
@@ -0,0 +1,25 @@
+import request from "@/scripts/httpRequest"
+
+export default {//娣诲姞瀵硅瘽璁板綍
+  createChat(data) {
+    return request({
+      url: '/api-v1/v1/chat/addDetail',
+      method: 'post',
+      data
+    })
+  },
+  getDetail(params) {//鑾峰彇瀵硅瘽璇︽儏
+    return request({
+      url: '/api-v1/v1/chat/detail',
+      method: 'get',
+      params
+    })
+  },
+  getChatDetail(params) {//瀵硅瘽妫�绱�
+    return request({
+      url: '/api-v1/v1/record/chat',
+      method: 'post',
+      params
+    })
+  },
+}
\ No newline at end of file
diff --git a/src/api/ChatHistoryView.ts b/src/api/ChatHistoryView.ts
new file mode 100644
index 0000000..8116dcb
--- /dev/null
+++ b/src/api/ChatHistoryView.ts
@@ -0,0 +1,20 @@
+import request from "@/scripts/httpRequest"
+
+export default {
+  getChats(data) {
+    // return service.get('/chat/all', data)
+    return request({
+      url: '/api-v1/v1/chat/all',
+      method: 'get',
+      data
+    })
+  },
+  deleteChat(params) {
+    // return service.delete('/chat/delete', { params })
+    return request({
+      url: '/api-v1/v1/chat/delete',
+      method: 'delete',
+      params
+    })
+  },
+}
\ No newline at end of file
diff --git a/src/api/SurveyView.ts b/src/api/SurveyView.ts
new file mode 100644
index 0000000..13e686f
--- /dev/null
+++ b/src/api/SurveyView.ts
@@ -0,0 +1,101 @@
+import request from '@/scripts/httpRequest'
+
+
+export default {
+  // getSurveys(params) {
+  //   return service.get('/record/all', { params })
+  // },
+  createFile(data) {
+    // return service.post('/task/add', data)
+    return request({
+      url: '/api-v1/v1/task/add',
+      method: 'post',
+      data
+    })
+  },
+  updateFile(data) {
+    // return service.put(`/task/update`, data)
+    return request({
+      url: '/api-v1/v1/task/update',
+      method: 'put',
+      data
+    })
+  },
+  deleteFile(params) {
+    // return service.delete(`/task/delete`, { params })
+    return request({
+      url: '/api-v1/v1/task/delete',
+      method: 'delete',
+      params
+    })
+  },
+  getTasks(params) {
+    // return service.get('/task/all', { params })
+    return request({
+      url: '/api-v1/v1/task/all',
+      method: 'get',
+      params
+    })
+  },
+  getCheckContents(params) {
+    // return service.get('/checkContent/all', { params })
+    return request({
+      url: '/api-v1/v1/checkContent/all',
+      method: 'get',
+      params
+    })
+  },
+  getWarnings(params) {
+    // return service.get('/warningRule/all', { params })
+    return request({
+      url: '/api-v1/v1/warningRule/all',
+      method: 'get',
+      params
+    })
+  },
+  getCameras(params) {
+    // return service.get('/task/getVideoOption')
+    return request({
+      url: '/api-v1/v1/task/getVideoOption',
+      method: 'get',
+      params
+    })
+  },
+  getTimes(params) {
+    // return service.get('/workTime/all')
+    return request({
+      url: '/api-v1/v1/workTime/all',
+      method: 'get',
+      params
+    })
+  },
+  getEvents(params) {
+    // return service.get('/task/getDictType')
+    return request({
+      url: '/api-v1/v1/task/getDictType',
+      method: 'get',
+      params
+    })
+  },
+  getSurveys(data) {
+    return request({
+      url: '/api-v1/v1/record/all',
+      method: 'post',
+      data
+    })
+  },
+ insertModelTraining  (params){
+    return request({
+      url: "/api-v1/v1/train/add ",
+      method: "post",
+      data: params
+    })
+  },
+  downloadFiles(params){
+    return request({
+      url: '/api-v1/v1/knowledge/download',
+      method: 'get',
+      params
+    })
+  },
+}
\ No newline at end of file
diff --git a/src/assets/img/AI-avatar.png b/src/assets/img/AI-avatar.png
new file mode 100644
index 0000000..d732d6c
--- /dev/null
+++ b/src/assets/img/AI-avatar.png
Binary files differ
diff --git "a/src/assets/img/UDP\351\205\215\347\275\256.png" "b/src/assets/img/UDP\351\205\215\347\275\256.png"
new file mode 100644
index 0000000..77e0ade
--- /dev/null
+++ "b/src/assets/img/UDP\351\205\215\347\275\256.png"
Binary files differ
diff --git a/src/assets/img/article-fill@1x copy.png b/src/assets/img/article-fill@1x copy.png
new file mode 100644
index 0000000..7d1825c
--- /dev/null
+++ b/src/assets/img/article-fill@1x copy.png
Binary files differ
diff --git a/src/assets/img/conversation.png b/src/assets/img/conversation.png
new file mode 100644
index 0000000..69bcfce
--- /dev/null
+++ b/src/assets/img/conversation.png
Binary files differ
diff --git a/src/assets/img/fold_up.png b/src/assets/img/fold_up.png
new file mode 100644
index 0000000..61816da
--- /dev/null
+++ b/src/assets/img/fold_up.png
Binary files differ
diff --git a/src/assets/img/historical copy.png b/src/assets/img/historical copy.png
new file mode 100644
index 0000000..09bb019
--- /dev/null
+++ b/src/assets/img/historical copy.png
Binary files differ
diff --git a/src/assets/img/historical.png b/src/assets/img/historical.png
new file mode 100644
index 0000000..09bb019
--- /dev/null
+++ b/src/assets/img/historical.png
Binary files differ
diff --git a/src/assets/img/live-fill@1x.png b/src/assets/img/live-fill@1x.png
new file mode 100644
index 0000000..84000bc
--- /dev/null
+++ b/src/assets/img/live-fill@1x.png
Binary files differ
diff --git a/src/assets/img/time-fill@1x.png b/src/assets/img/time-fill@1x.png
new file mode 100644
index 0000000..a637f01
--- /dev/null
+++ b/src/assets/img/time-fill@1x.png
Binary files differ
diff --git a/src/pages/datapush/index/RightEvent.vue b/src/pages/datapush/index/RightEvent.vue
index e07f0c5..062a47a 100644
--- a/src/pages/datapush/index/RightEvent.vue
+++ b/src/pages/datapush/index/RightEvent.vue
@@ -15,9 +15,9 @@
 
         <div>
           <span style="line-height: 38px;margin-right: 20px;">鎺ㄩ�佹柟寮�</span>
-          <el-radio :disabled="urls.length > 0" v-model="pushType" label="1">UDP</el-radio>
-          <el-radio :disabled="urls.length > 0" v-model="pushType" label="2">HTTP</el-radio>
-          <el-radio disabled v-model="pushType" label="3">MQTT</el-radio>
+          <el-radio :disabled="urls.length > 0" v-model="taskEditData.pushType" label="1">UDP</el-radio>
+          <el-radio :disabled="urls.length > 0" v-model="taskEditData.pushType" label="2">HTTP</el-radio>
+          <el-radio disabled v-model="taskEditData.pushType" label="3">MQTT</el-radio>
         </div>
         <span style="line-height: 38px">鎺ㄩ�佹湇鍔″櫒</span>
         <div class="icon-btn" v-if="urls.length < 1" @click="addUrl()">
@@ -28,13 +28,14 @@
           <div>
             <el-checkbox v-model="item.enable"></el-checkbox>
             <span class="ml20">{{ "URL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" }}</span>
-            <el-input v-if="pushType === '1'" v-model="item.ip" style="width: 180px; margin-left: 0px;margin-right: 30px" size="small"
+            <el-input v-if="taskEditData.pushType === '1'" v-model="item.server_ip"
+              style="width: 180px; margin-left: 0px;margin-right: 30px" size="small"
               placeholder="192.168.1.100"></el-input>
-              绔彛  <el-input v-if="pushType === '1'" v-model="item.sort" style="width: 70px; margin-left: 10px" size="small"
-              placeholder="8030"></el-input>
-              <el-input v-if="pushType === '2'" v-model="item.url" style="width: 360px; margin-left: 0px" size="small"
-              placeholder="http://10.10.10.10:8000/dataApi"></el-input>
-              <!-- <el-input v-if="pushType === '3'" v-model="item.url" style="width: 360px; margin-left: 0px" size="small"
+            绔彛 <el-input v-if="taskEditData.pushType === '1'" v-model="item.port" style="width: 70px; margin-left: 10px"
+              size="small" placeholder="8030"></el-input>
+            <el-input v-if="taskEditData.pushType === '2'" v-model="item.url" style="width: 360px; margin-left: 0px"
+              size="small" placeholder="http://10.10.10.10:8000/dataApi"></el-input>
+            <!-- <el-input v-if="taskEditData.pushType === '3'" v-model="item.url" style="width: 360px; margin-left: 0px" size="small"
               placeholder="MQTT"></el-input> -->
           </div>
           <div class="server-add">
@@ -110,10 +111,15 @@
               <el-input v-model="rule.rule_value" placeholder="璇疯緭鍏ュ唴瀹�" size="small"></el-input>
             </div>
             <div v-else>
-              <el-select v-model="rule.rule_values" multiple collapse-tags placeholder="璇烽�夋嫨" size="small"
-                @change="selectValue(rule, $event)">
+              <el-select v-if="!isWarningSelect" v-model="rule.rule_values" multiple collapse-tags placeholder="璇烽�夋嫨"
+                size="small" @change="selectValue(rule, $event)">
                 <el-option v-for="item in rule.ruleValueOptions" :key="item.id" :label="item.name"
                   :disabled="item.disabled" :value="item.value"></el-option>
+              </el-select>
+              <el-select v-else v-model="rule.rule_values" collapse-tags placeholder="璇烽�夋嫨" size="small"
+                @change="selectValue(rule, $event)">
+                <el-option v-for="item in rule.ruleValueOptions" :key="item.id" :label="item.name"
+                  :value="item.value"></el-option>
               </el-select>
             </div>
           </el-col>
@@ -135,7 +141,8 @@
       </div>
       <div class="config-item">
         <b>鎺ㄩ�佸瓧娈�</b>
-        <el-button v-if="pushType === '1'" type="primary" size="mini" @click="openPushImsDialog">鏌ョ湅</el-button>
+        <el-button v-if="taskEditData.pushType === '1'" type="primary" size="mini"
+          @click="openPushImsDialog">鏌ョ湅</el-button>
         <el-button v-else type="primary" size="mini" @click="openPushSetDialog">璁剧疆</el-button>
       </div>
       <div class="save-btn">
@@ -145,7 +152,8 @@
     </div>
     <el-dialog :visible="pushImageDialog" :append-to-body="false" :close-on-click-modal="false"
       class="dialog-push-field" @close="pushImageDialog = false">
-      <el-image fit="fill" src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"></el-image>
+      <!-- <el-image fit="fill" src="https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"></el-image> -->
+      <img src="@/assets/img/UDP閰嶇疆.png" style="width: 100%;">
     </el-dialog>
     <el-dialog :visible="pushFieldDialog" :append-to-body="false" :close-on-click-modal="false"
       class="dialog-push-field" @close="pushFieldDialog = false">
@@ -203,7 +211,7 @@
   },
   data() {
     return {
-      pushType: '1',
+      isWarningSelect: true,
       taskEditData: {},
       dataList: [],
       dictionary: [],
@@ -226,7 +234,7 @@
         ruleValueOptions: [],
       },
       pushFieldDialog: false,
-      pushImageDialog:false,
+      pushImageDialog: false,
       tempPushSet: [],
       pushFields: [],
       allFieldChecked: false,
@@ -252,7 +260,7 @@
             this.taskEditData.lineWay = newVal.link_type;
             this.taskEditData.eventTxt = newVal.rule_text;
             this.taskEditData.radioValue = newVal.is_satisfy_all ? "1" : "2";
-            this.pushType = '2'
+            this.taskEditData.pushType = newVal.push_type + ""
 
             if (!this.taskEditData.urls) {
               this.$set(this.taskEditData, "urls", []);
@@ -426,6 +434,8 @@
         checked: true,
         hash: Math.random().toString(36).substr(2),
         url: "",
+        server_ip: "",
+        port: ""
       });
     },
     delUrl(index) {
@@ -434,6 +444,7 @@
     },
     // 淇濆瓨
     async eventPushsSave() {
+      console.log(this.taskEditData.urls)
       if (this.taskEditData.name.length < 1) {
         this.$notify({
           type: "warning",
@@ -450,7 +461,7 @@
         return;
       }
       for (let i = 0; i < this.taskEditData.urls.length; i++) {
-        if (this.taskEditData.urls[i].url.length < 1) {
+        if (this.taskEditData.urls[i].url.length < 1 && this.taskEditData.urls[i].server_ip.length < 1) {
           this.$notify({
             type: "warning",
             message: "鎺ュ彛URL鍦板潃涓嶅厑璁镐负绌�",
@@ -511,11 +522,16 @@
         rules: ruleList,
         time_start: this.taskEditData.time[0],
         time_end: this.taskEditData.time[1],
-        urls: this.taskEditData.urls,
+        urls: this.taskEditData.urls.map(item => {
+          return {
+            ...item,
+            port: item.port ? Number(item.port) : 0
+          }
+        }),
         is_satisfy_all: this.taskEditData.radioValue === "1",
         link_type: this.taskEditData.lineWay,
         push_set: this.taskEditData.push_set,
-        pushType:this.pushType
+        push_type: Number(this.taskEditData.pushType)
       };
 
       let res = await eventPushsSave(json);
@@ -536,6 +552,12 @@
         this.baseRule.topicTypeOptions = this.dictionary.EVENTRULETOPIC;
         this.baseRule.operatorTypeOpionts = this.dictionary.EVENTTYPECOMPUTE;
         this.dictionary["alarmLevel"] = this.dictionary.ALARMLEVEL.map((el) => {
+          return {
+            name: el.name,
+            value: el.name,
+          };
+        });
+        this.dictionary["warning"] = this.dictionary.WARNING.map((el) => {
           return {
             name: el.name,
             value: el.name,
@@ -578,6 +600,7 @@
     // 鏂板缓閰嶇疆
     createSet() {
       this.dataList.push(JSON.parse(JSON.stringify(this.baseRule)));
+      console.log(this.dataList, "dataList")
     },
     cleanSet() {
       this.dataList.splice(0, this.dataList.length);
@@ -602,6 +625,11 @@
           }
         }
       });
+      if (rule.topic_type && rule.topic_type === 'warning') {
+        this.isWarningSelect = true
+      } else {
+        this.isWarningSelect = false
+      }
     },
     selectArg(rule, resetNext = false) {
       let argInfo = rule.topicArgOptions.filter((arg) => {
@@ -668,8 +696,12 @@
           return;
         }
       }
+      if (this.isWarningSelect) {
+        rule.rule_value = val
+      } else {
+        rule.rule_value = val.join(",");
+      }
 
-      rule.rule_value = val.join(",");
     },
     setOptionsDisable(rule) {
       console.log(rule);
@@ -729,9 +761,9 @@
         radioValue: "1",
         eventTxt: "",
         push_set: this.pushFields,
+        pushType: '1'
       };
       this.dataList = [];
-      this.pushType ='1'
     },
     onCancle() {
       this.$emit("onCancle");
diff --git a/src/pages/modelTuning/components/rightCardList.vue b/src/pages/modelTuning/components/rightCardList.vue
index 1eeb450..7b8ff6b 100644
--- a/src/pages/modelTuning/components/rightCardList.vue
+++ b/src/pages/modelTuning/components/rightCardList.vue
@@ -47,7 +47,7 @@
                 <!-- 閫夋嫨鏃舵 -->
                 <el-form-item label="閫夋嫨鏃舵">
                     <el-date-picker style="width: 256px;" v-model="filter.timeRange" type="daterange"
-                        value-format="yyyy-MM-dd hh:mm:ss" range-separator="鑷�" start-placeholder="寮�濮嬫棩鏈�"
+                        value-format="yyyy-MM-dd" range-separator="鑷�" start-placeholder="寮�濮嬫棩鏈�"
                         end-placeholder="缁撴潫鏃ユ湡" />
                 </el-form-item>
 
@@ -584,6 +584,7 @@
 }
 
 .image-gallery {
+    min-width: 1265px;
     background-color: #ffffff;
     padding: 20px;
     border-radius: 4px;
diff --git a/src/pages/searchNew/components/AiRetrievalView.vue b/src/pages/searchNew/components/AiRetrievalView.vue
new file mode 100644
index 0000000..e26d59b
--- /dev/null
+++ b/src/pages/searchNew/components/AiRetrievalView.vue
@@ -0,0 +1,938 @@
+<template>
+  <div class="chat-container">
+    <div class="messages">
+      <div v-for="(msg, index) in messages" :key="index"
+        :class="['message-bubble', msg.role, { 'with-think': msg.think }]">
+        <!-- 鎬濊�冨唴瀹瑰尯鍩� -->
+        <div v-if="msg.think" class="think-section">
+          <div class="think-header" @click="toggleThink(index)">
+            <span>鎬濊�冭繃绋�</span>
+            <i :class="[
+              'arrow',
+              msg.isThinkExpanded
+                ? 'el-icon-arrow-down'
+                : 'el-icon-arrow-right',
+            ]"></i>
+          </div>
+          <transition name="slide">
+            <div v-show="msg.isThinkExpanded" class="think-content">
+              {{ msg.think }}
+            </div>
+          </transition>
+        </div>
+
+        <!-- 姝e父娑堟伅鍐呭 -->
+        <div class="content">
+          <template v-if="msg.role === 'assistant'">
+            <span v-if="isGenerating && index === messages.length - 1">
+              <span v-if="!msg.think" class="generating-indicator">姝e湪鎬濊��...</span>
+              <!-- <span class="cursor"></span> -->
+            </span>
+            {{ msg.content }}
+          </template>
+          <template v-else>
+            {{ msg.content }}
+          </template>
+        </div>
+      </div>
+    </div>
+
+    <div class="preview-area" v-if="uploadedImages.length > 0">
+      <div v-for="(img, index) in uploadedImages" :key="index" class="image-preview">
+        <img :src="'data:image/png;base64,' + img.base64" class="thumbnail" />
+        <span class="image-name">{{ img.name }}</span>
+        <span class="image-size">{{ formatSize(img.size) }}</span>
+        <i class="el-icon-close remove-icon" @click="removeImage(index)"></i>
+      </div>
+    </div>
+    <div class="input-area">
+      <div class="input-area2">
+        <textarea v-model="inputText" @keydown.enter.prevent="handleEnter" :disabled="isGenerating"
+          placeholder="璇疯緭鍏ヤ綘鐨勯棶棰�" class="input-textarea" rows="1" @input="autoResize"></textarea>
+      </div>
+
+      <div class="action-buttons">
+        <el-upload action="" :auto-upload="false" :show-file-list="false" :on-change="handleImageUpload"
+          accept="image/*" class="action-img" :disabled="true">
+          <i class="el-icon-picture upload-icon"></i>
+        </el-upload>
+        <div class="action-img">
+          <i class="el-icon-microphone microphone-icon"></i>
+        </div>
+        <button @click="startStream" :disabled="isGenerating" class="send-button">
+          <i class="el-icon-position send-icon"></i>
+        </button>
+      </div>
+    </div>
+    <div class="tip-text">鍐呭鐢盇I澶фā鍨嬬敓鎴愶紝璇蜂粩缁嗙攧鍒�</div>
+  </div>
+</template>
+
+<script>
+import AiRetrieval from "@/api/AiRetrievalView";
+export default {
+  props: ["currentChatId"],
+  watch: {
+    currentChatId: {
+      immediate: true,
+      handler(newVal) {
+        if (newVal) this.loadChat(); // 鐩戝惉chatId鍙樺寲
+      },
+    },
+  },
+  name: "AiRetrieval",
+  data() {
+    return {
+      chatUrl: "",
+      severUrl:"",
+      params: "",
+      chatId: null,
+      messages: [],
+      inputText: "",
+      isGenerating: false,
+      controller: null,
+      uploadedImages: [],
+    };
+  },
+  mounted() {
+    this.fetchCameraInfo();
+  },
+  methods: {
+    async fetchCameraInfo() {
+      const response = await fetch("/config.json");
+      if (!response.ok) throw new Error(`璇锋眰澶辫触: ${response.status}`);
+      const responseData = await response.json();
+      this.chatUrl = responseData.chatUrl;
+      this.severUrl = responseData.severUrl;
+      // console.info("chatUrl:"+this.chatUrl);
+    },
+    toggleThink(index) {
+      this.$set(
+        this.messages[index],
+        "isThinkExpanded",
+        !this.messages[index].isThinkExpanded
+      );
+    },
+    handleItemSend(params) {
+      this.$emit("list-selected", params); // 瑙﹀彂鑷畾涔変簨浠� 鍒锋柊鍙充晶鍐呭鍖哄煙
+    },
+    async loadChat() {
+      if (!this.currentChatId) return;
+
+      try {
+        // console.info("鏂板璇�"+this.currentChatId);
+        const res = await AiRetrieval.getDetail({
+          chatId: this.currentChatId,
+        });
+        // console.info(res.data);
+
+        this.messages = [];
+        this.chatId = res.data[0].chatId;
+        // console.info(+this.chatId )
+        for (let i = 0; i < res.data.length; i++) {
+          this.messages.push({
+            role: "user",
+            content: res.data[i].question,
+          });
+          this.messages.push({
+            role: "assistant",
+            content: res.data[i].content,
+            think: res.data[i].think,
+          });
+        }
+        // this.messages = res.data.data;  // 鍋囪鎺ュ彛杩斿洖娑堟伅鍒楄〃
+        this.$nextTick(() => {
+          const container = this.$el.querySelector(".messages");
+          container.scrollTop = container.scrollHeight;
+        });
+      } catch (error) {
+        console.error("鍔犺浇鑱婂ぉ澶辫触:", error);
+      }
+    },
+
+    // async saveToDatabase(chatData) {
+    //   if (this.currentChatId) {            // 鏇存柊閫昏緫
+    //     await AiRetrieval.updateChat(this.currentChatId, chatData);
+    //   } else {                             // 鏂板缓閫昏緫
+    //     const res = await AiRetrieval.createChat(chatData);
+    //     this.currentChatId = res.data.chatId;
+    //   }
+    // },
+    reset() {
+      // console.info("娓呯┖瀵硅瘽璁板綍");
+      // 娓呯┖瀵硅瘽璁板綍
+      this.messages = [];
+      // 閲嶇疆杈撳叆妗�
+      this.inputMessage = "";
+      // 濡傛灉鏈夊叾浠栭渶瑕侀噸缃殑鐘舵��
+      this.searchResults = [];
+      this.currentPage = 1;
+      // 鍙互鏍规嵁闇�瑕佹坊鍔犲叾浠栭噸缃�昏緫
+    },
+    // 鏂板鑷姩璋冩暣楂樺害鏂规硶
+    autoResize(e) {
+      const textarea = e.target;
+      textarea.style.height = "auto"; // 閲嶇疆楂樺害
+      const maxHeight = 6 * 24; // 6琛�*24px琛岄珮 + 8px*2鍐呰竟璺�
+      textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
+    },
+    handleImageUpload(file) {
+      const reader = new FileReader();
+      reader.onload = (e) => {
+        const base64Data = e.target.result.split(",")[1];
+        this.uploadedImages.push({
+          name: file.name,
+          size: file.size,
+          base64: base64Data,
+        });
+      };
+      reader.readAsDataURL(file.raw);
+    },
+    removeImage(index) {
+      this.uploadedImages.splice(index, 1);
+    },
+    formatSize(bytes) {
+      if (bytes === 0) return "0 B";
+      const k = 1024;
+      const sizes = ["B", "KB", "MB", "GB"];
+      const i = Math.floor(Math.log(bytes) / Math.log(k));
+      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
+    },
+    handleEnter(e) {
+      if (!e.shiftKey && !this.isGenerating) {
+        this.startStream();
+      }
+    },
+    async startStream() {
+      if (!this.inputText.trim() || this.isGenerating) return;
+
+      this.messages.push({ role: "user", content: this.inputText });
+      const userMessage = this.inputText;
+      this.inputText = "";
+      this.messages.push({
+        role: "assistant",
+        content: "",
+        think: "",
+        isThinkExpanded: true,
+      });
+      // this.$nextTick(() => {
+      //   const container = this.$el.querySelector(".messages");
+      //   container.scrollTop = container.scrollHeight;
+      // });
+      this.isGenerating = true;
+
+      try {
+        this.controller = new AbortController();
+
+        let ids = [];
+        let idsStr = "";
+        //绛涢�夋渶缁堢粨鏋�
+        // const response = await AiRetrieval.getChatDetail(
+        //   {
+        //     message:userMessage
+        //   }
+        // );
+        const response = await fetch(this.severUrl +"/v1/record/chat", {
+          method: "POST",
+          headers: {
+            "Content-Type": "application/json",
+          },
+          body: JSON.stringify({
+            message: userMessage
+          }),
+        });
+
+        if (!response.ok) throw new Error(`璇锋眰澶辫触: ${response.status}`);
+
+        const reader = response.body.getReader();
+        const decoder = new TextDecoder();
+        let boo = true;
+        // 淇敼鍚庣殑fetch澶勭悊閫昏緫
+        while (true) {
+          const { done, value } = await reader.read();
+          if (done) break;
+
+          const chunk = decoder.decode(value, { stream: true });
+          const lines = chunk.split("\n").filter((line) => line.trim());
+
+          // 淇濆瓨鏈�鏂版秷鎭殑寮曠敤
+          const lastMessage = this.messages[this.messages.length - 1];
+
+          for (const line of lines) {
+            try {
+              const json = JSON.parse(line.replace("data:", "").trim());
+              if (json.data === true) break;
+              // 鐩存帴鏇挎崲鑰屼笉鏄拷鍔�
+              if (json.data) {
+
+                // 浣跨敤姝e垯琛ㄨ揪寮忓尮閰嶆�濊�冨唴瀹�
+                const thoughtMatch = json.data.match(
+                  /<think>(.*?)(?=\n<\/think>|$)/s
+                );
+                if (thoughtMatch) {
+                  // 鏇存柊娑堟伅鍐呭 甯hink
+                  lastMessage.think = thoughtMatch[1].trim();
+                  let con = json.data //绗竴閮ㄥ垎锛�
+                    .match(/<\/think>([\s\S]*)/)[1]
+                    .trim();
+                  // console.info('con='+con)
+                  const rescou = con
+                    .match(/绗竴閮ㄥ垎锛�(.*?)(?=\n绗簩閮ㄥ垎锛殀$)/s)[1]
+                    .trim();
+
+                  // console.info('rescou='+rescou)
+                  if (rescou) {
+                    lastMessage.content = rescou;
+                    idsStr = con.match(/绗簩閮ㄥ垎锛�([\s\S]*)/)[1].trim();
+                    // console.info("idsStr=" + idsStr);
+                    boo = false;
+                  }
+                } else {
+                  // 鏇存柊娑堟伅鍐呭
+                  lastMessage.think = json.data
+                    .match(/<think>([\s\S]*)/)[1]
+                    .trim();
+                }
+              }
+              // console.info("boo:" + boo)
+            } catch (e) {
+              console.info("")
+            }
+          }
+        }
+
+        // console.info("boo:"+boo)
+        if (boo) {
+          this.messages[this.messages.length - 1].content = "鍖归厤鍒扮殑鏁版嵁涓�0鏉�";
+        } else {
+          ids = idsStr.split(",");
+        }
+        // this.handleItemSend(lists);//鍙戦�佹暟鎹睍绀哄埌椤甸潰
+        this.handleItemSend(ids);
+        // // 淇濆瓨鍒版暟鎹簱鐨勯�昏緫
+        // console.info("淇濆瓨鏃ф暟鎹�"+this.chatId)
+        if (this.messages.length >= 2) {
+          // console.info(this.messages)
+          const userMsg = this.messages[this.messages.length - 2];
+          const assistantMsg = this.messages[this.messages.length - 1];
+          this.saveToDatabase({
+            question: userMsg.content,
+            content: assistantMsg.content,
+            think: assistantMsg.think,
+            chatId: this.chatId,
+            // images: this.uploadedImages
+          });
+        }
+      } catch (error) {
+        if (error.name !== "AbortError") {
+          console.error("鐢熸垚澶辫触:", error);
+          this.messages[this.messages.length - 1].content += "锛堢敓鎴愬け璐ワ級";
+        }
+      } finally {
+        this.isGenerating = false;
+        this.controller = null;
+      }
+    },
+    // async startStream() {
+    //   if (!this.inputText.trim() || this.isGenerating) return;
+
+    //   this.messages.push({ role: "user", content: this.inputText });
+    //   const userMessage = this.inputText;
+    //   this.inputText = "";
+    //   this.messages.push({
+    //     role: "assistant",
+    //     content: "",
+    //     think: "",
+    //     isThinkExpanded: true,
+    //   });
+    //   // this.$nextTick(() => {
+    //   //   const container = this.$el.querySelector(".messages");
+    //   //   container.scrollTop = container.scrollHeight;
+    //   // });
+    //   this.isGenerating = true;
+
+    //   try {
+    //     this.controller = new AbortController();
+
+    //     //浼樺寲鐢ㄦ埛闂
+    //     const resstar =
+    //       "milvus鏁版嵁搴撲腑瀛樺偍浜唅d銆佹憚鍍忔満鎶撴媿鍥剧墖銆佸浘鐗囩殑鏂囨湰鎻忚堪锛屽浘鐗囨枃鏈弿杩版槸閫氳繃qwen妯″瀷鎶婂浘鐗囦腑鍖呭惈鐨勫唴瀹瑰舰鎴愪簡鏂囨湰鍐呭銆傜敤鎴蜂細杈撳叆浠巑ilvus鏁版嵁搴撲腑鏌ユ壘鍥剧墖鐨勯渶姹傦紝璇峰府鎴戞妸鐢ㄦ埛鐨勯棶棰樻敼鍐欎竴涓嬶紝浠ヤ究鍦╩ilvus鏁版嵁搴撲腑鏌ユ壘鍒版洿鍔犲噯纭殑涓旂鍚堢敤鎴锋湡鏈涚殑鏁版嵁銆備笉瑕佽緭鍑烘敼鍐欒鏄� /nothink";
+    //     const startRes = await fetch(this.chatUrl + "/chat", {
+    //       method: "POST",
+    //       headers: {
+    //         "Content-Type": "application/json",
+    //       },
+    //       body: JSON.stringify({
+    //         prompt: resstar,
+    //         llm_name: "qwen3:8b",//qwen2.5vl
+    //         messages: [
+    //           ...this.messages.slice(0, -1),
+    //           { role: "user", content: userMessage },
+    //         ],
+    //         stream: false,
+    //         gen_conf: {
+    //           temperature: 0.1,
+    //           max_tokens: 1000
+    //         }
+    //         // image:this.uploadedImages[0]?.base64 || ''
+    //       }),
+    //     });
+    //     // console.info("chat鍦板潃锛�"+"/api-AI" + "/chat")
+    //     if (!startRes.ok) throw new Error(`璇锋眰澶辫触: ${startRes.status}`);
+    //     const responseData = await startRes.json();
+
+
+    //      let res1 = responseData.data.split('\n\n')
+    //      let rescou = res1.length>1?res1[2]:""
+    //     //let rescou = responseData.data.match(/锛�(.*?)(?=\n锛亅$)/s)[1].trim();
+    //     console.info(rescou);
+    //     if (!rescou) {
+    //       rescou = userMessage;
+    //     }
+    //     //妫�绱㈠悜閲忔暟鎹簱
+    //     const res = await fetch(this.chatUrl + "/search", {
+    //       method: "POST",
+    //       headers: {
+    //         "Content-Type": "application/json",
+    //       },
+    //       body: JSON.stringify({
+    //         collection_name: "smartrag",
+    //         query_text: rescou,
+    //         search_mode: "hybrid",
+    //         limit: 20,
+    //         weight_dense: 0.7,
+    //         weight_sparse: 0.3,
+    //         filter_expr: "",
+    //         output_fields: [
+    //           "id",
+    //           "image_path",
+    //           "create_timestamp",
+    //           "task_name",
+    //           "event_level_name",
+    //           "rtsp_address",
+    //           "video_point_id",
+    //           "zh_desc_class",
+    //           "video_path",
+    //           "detect_time",
+    //         ],
+    //       }),
+    //     });
+
+    //     // console.info(res.json())
+    //     const text = await res.text();
+    //     const data = JSONbig({ storeAsString: true }).parse(text);
+    //     console.info(data);
+    //     let lists = [];
+    //     let ids = [];
+    //     let idsStr = "";
+    //     for (let i = 0; i < data.results.length; i++) {
+    //       // console.info(data.results[i].entity.id)
+    //       this.params +=
+    //         "淇℃伅id锛�" +
+    //         data.results[i].entity.id +
+    //         ",鍐呭锛�" +
+    //         data.results[i].entity.video_path +
+    //         "鎽勫儚澶村湪" +
+    //         data.results[i].entity.detect_time +
+    //         "鏃堕棿鎷嶆憚鐨勫浘鐗�" +
+    //         data.results[i].entity.zh_desc_class +
+    //         "\n";
+    //       lists.push(data.results[i].entity);
+    //     }
+
+    //     // const mes =
+    //     //   "鐢ㄦ埛璇㈤棶銆�" +
+    //     //   rescou +
+    //     //   "銆戙�俓n璇峰湪浠ヤ笅淇℃伅涓繘琛屽尮閰嶏紝淇℃伅涓篭n" +
+    //     //   this.params +
+    //     //   "銆俓n鍥炵瓟:銆怷XX淇℃伅id銆�";
+
+
+    //     const mes =
+    //       "鐢ㄦ埛璇㈤棶銆�" +
+    //       rescou +
+    //       "銆戙�俓n璇峰湪浠ヤ笅淇℃伅涓繘琛屽尮閰嶏紝淇℃伅涓篭n" +
+    //       this.params +
+    //       "銆俓n涓嶈繘琛屾帹鐞嗗拰瑙h瘧锛屽繀椤昏繑鍥炰袱閮ㄥ垎缁撴灉锛屼笖缁撴灉涓繀椤诲甫鏈夌涓�閮ㄥ垎鎴栫浜岄儴鍒嗗洓涓瓧锛岀涓�閮ㄥ垎涓烘�荤粨鍖归厤鍒板灏戞潯锛岀浜岄儴鍒嗙殑鏍煎紡蹇呴』鏄� 绗簩閮ㄥ垎锛歑XX,XXX鍏朵腑XXX涓烘暟鎹簱id";
+    //     this.params = "";
+    //     if (!res.ok) throw new Error(`璇锋眰澶辫触: ${res.status}`);
+
+    //     let contentMes =  mes.replace(/\s+/g, '')
+
+    //     //绛涢�夋渶缁堢粨鏋�
+    //     const response = await fetch(this.chatUrl + "/chat", {
+    //       method: "POST",
+    //       headers: {
+    //         "Content-Type": "application/json",
+    //       },
+    //       body: JSON.stringify({
+    //         prompt: "",
+    //         llm_name: "qwen3:8b",//qwen2.5vl
+    //         messages: [
+    //           ...this.messages.slice(0, -1),
+    //           { role: "user", content: contentMes },
+    //         ],
+    //         stream: true,
+    //         gen_conf: {
+    //           temperature: 0.7,
+    //           max_tokens: 4000,
+    //         },
+    //         // image:this.uploadedImages[0]?.base64 || ''
+    //       }),
+    //     });
+
+    //     if (!response.ok) throw new Error(`璇锋眰澶辫触: ${response.status}`);
+
+    //     const reader = response.body.getReader();
+    //     const decoder = new TextDecoder();
+    //     let boo = true;
+    //     // 淇敼鍚庣殑fetch澶勭悊閫昏緫
+    //     while (true) {
+    //       const { done, value } = await reader.read();
+    //       if (done) break;
+
+    //       const chunk = decoder.decode(value, { stream: true });
+    //       const lines = chunk.split("\n").filter((line) => line.trim());
+
+    //       // 淇濆瓨鏈�鏂版秷鎭殑寮曠敤
+    //       const lastMessage = this.messages[this.messages.length - 1];
+
+    //       for (const line of lines) {
+    //         try {
+    //           const json = JSON.parse(line.replace("data:", "").trim());
+    //           if (json.data === true) break;
+    //           // 鐩存帴鏇挎崲鑰屼笉鏄拷鍔�
+    //           if (json.data) {
+
+    //               // 浣跨敤姝e垯琛ㄨ揪寮忓尮閰嶆�濊�冨唴瀹�
+    //             const thoughtMatch = json.data.match(
+    //               /<think>(.*?)(?=\n<\/think>|$)/s
+    //             );
+    //             if (thoughtMatch) {
+    //               // 鏇存柊娑堟伅鍐呭 甯hink
+    //               lastMessage.think = thoughtMatch[1].trim();
+    //               let con = json.data //绗竴閮ㄥ垎锛�
+    //                 .match(/<\/think>([\s\S]*)/)[1]
+    //                 .trim();
+    //               // console.info('con='+con)
+    //               const rescou = con
+    //                 .match(/绗竴閮ㄥ垎锛�(.*?)(?=\n绗簩閮ㄥ垎锛殀$)/s)[1]
+    //                 .trim();
+
+    //               // console.info('rescou='+rescou)
+    //               if (rescou) {
+    //                 lastMessage.content = rescou;
+    //                 idsStr = con.match(/绗簩閮ㄥ垎锛�([\s\S]*)/)[1].trim();
+    //                 // console.info("idsStr=" + idsStr);
+    //                 boo = false;
+    //               }
+    //             } else {
+    //               // 鏇存柊娑堟伅鍐呭
+    //               lastMessage.think = json.data
+    //                 .match(/<think>([\s\S]*)/)[1]
+    //                 .trim();
+    //             }
+    //           }
+    //         } catch (e) {
+    //           // console.error("瑙f瀽閿欒:", e);
+    //         }
+    //       }
+    //       // this.$nextTick(() => {
+    //       //   const container = this.$el.querySelector(".messages");
+    //       //   container.scrollTop = container.scrollHeight;
+    //       // });
+    //     }
+
+    //     if (boo) {
+    //       this.messages[this.messages.length - 1].content = "鍖归厤鍒扮殑鏁版嵁涓�0鏉�";
+    //       lists = [];
+    //     } else {
+    //       ids = idsStr.split(",");
+    //     }
+    //     // this.handleItemSend(lists);//鍙戦�佹暟鎹睍绀哄埌椤甸潰
+    //     this.handleItemSend(ids);
+    //     // // 淇濆瓨鍒版暟鎹簱鐨勯�昏緫
+    //     // console.info("淇濆瓨鏃ф暟鎹�"+this.chatId)
+    //     if (this.messages.length >= 2) {
+    //       // console.info(this.messages)
+    //       const userMsg = this.messages[this.messages.length - 2];
+    //       const assistantMsg = this.messages[this.messages.length - 1];
+    //       this.saveToDatabase({
+    //         question: userMsg.content,
+    //         content: assistantMsg.content,
+    //         think: assistantMsg.think,
+    //         chatId: this.chatId,
+    //         // images: this.uploadedImages
+    //       });
+    //     }
+    //   } catch (error) {
+    //     if (error.name !== "AbortError") {
+    //       console.error("鐢熸垚澶辫触:", error);
+    //       this.messages[this.messages.length - 1].content += "锛堢敓鎴愬け璐ワ級";
+    //     }
+    //   } finally {
+    //     this.isGenerating = false;
+    //     this.controller = null;
+    //   }
+    // },
+    async saveToDatabase(chatData) {
+      // 瀹為檯璋冪敤API鎺ュ彛
+      try {
+        const response = await AiRetrieval.createChat(chatData);
+        // console.info(response.data);
+        this.chatId = response.data || null;
+      } catch (error) {
+        console.error("API Error:", error);
+      }
+    },
+    cancelGeneration() {
+      if (this.controller) this.controller.abort();
+    },
+  },
+};
+</script>
+
+<style scoped>
+/* 鏂板鎬濊�冨唴瀹规牱寮� */
+.message-bubble.assistant.with-think {
+  border-radius: 12px;
+}
+
+.think-section {
+  background: #f8f9fa;
+  padding: 12px;
+  border-bottom: 1px solid #e9ecef;
+  text-align: left;
+}
+
+.think-header {
+  font-size: 12px;
+  color: #6c757d;
+  margin-bottom: 8px;
+  display: flex;
+  align-items: center;
+  font-weight: 500;
+}
+
+.think-header::before {
+  content: "馃挕";
+  margin-right: 6px;
+}
+
+.think-content {
+  font-size: 10px;
+  color: #495057;
+  line-height: 1.6;
+  white-space: pre-wrap;
+}
+
+.generating-indicator {
+  color: #6c757d;
+  font-size: 0.9em;
+  margin-right: 8px;
+}
+
+/* 璋冩暣鍘熸湁鏍峰紡 */
+.message-bubble.assistant .content {
+  background: #f5f6f8;
+  padding: 12px 15px;
+  border-radius: 0 0 12px 12px;
+  text-align: left;
+}
+
+/* 鏂板鍥剧墖鐩稿叧鏍峰紡 */
+.preview-area {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  padding: 8px;
+  background: #f5f5f5;
+  border-radius: 4px;
+  margin-bottom: 8px;
+}
+
+.image-preview {
+  position: relative;
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  padding: 4px;
+  background: white;
+  border-radius: 4px;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.thumbnail {
+  width: 30px;
+  height: 30px;
+  object-fit: cover;
+  border-radius: 2px;
+}
+
+.image-name {
+  font-size: 12px;
+  max-width: 100px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.image-size {
+  font-size: 10px;
+  color: #666;
+}
+
+.remove-icon {
+  position: absolute;
+  top: -8px;
+  right: -8px;
+  font-size: 12px;
+  background: white;
+  border-radius: 50%;
+  cursor: pointer;
+}
+
+.action-img {
+  width: 20px;
+  height: 20px;
+  border-radius: 13px;
+  padding: 6px;
+  background-color: #f2f8ff;
+}
+
+.upload-icon {
+  font-size: 20px;
+  color: #7fade6;
+  cursor: pointer;
+}
+
+.chat-container {
+  position: relative;
+  width: 100%;
+  max-width: 500px;
+  height: 600px;
+  margin: 0 auto;
+  /* background: #f1f1f1; */
+  border-radius: 12px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+  display: flex;
+  flex-direction: column;
+}
+
+.close-button {
+  position: absolute;
+  right: 15px;
+  top: 15px;
+  font-size: 20px;
+  color: #999;
+  cursor: pointer;
+  z-index: 1;
+  transition: color 0.2s;
+}
+
+.close-button:hover {
+  color: #666;
+}
+
+.messages {
+  flex: 1;
+  padding: 20px;
+  overflow-y: auto;
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.message-bubble {
+  max-width: 80%;
+  position: relative;
+  font-size: 14px;
+  line-height: 1.5;
+}
+
+.message-bubble.user {
+  align-self: flex-end;
+}
+
+.message-bubble.assistant {
+  align-self: flex-start;
+}
+
+.content {
+  padding: 12px 15px;
+  border-radius: 5px;
+  word-break: break-word;
+}
+
+.user .content {
+  background: #cadcff;
+  color: #2e2f31;
+  border-radius: 12px 12px 0 12px;
+}
+
+.assistant .content {
+  background: white;
+  color: #2e2f31;
+  border-radius: 12px 12px 12px 0;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+}
+
+.input-area {
+  display: flex;
+  flex-direction: column;
+  /* 鏀逛负鍨傜洿甯冨眬 */
+  background: #fff;
+  border: 2px solid #1890ff;
+  border-radius: 10px;
+  padding-top: 8px;
+  gap: 8px;
+  /* 娣诲姞闂磋窛 */
+  min-height: 80px;
+  max-height: 200px;
+  align-items: center;
+  /* position: relative; */
+}
+
+.input-area2 {
+  width: 100%;
+  display: flex;
+  background: #fff;
+  min-height: 60px;
+  max-height: 180px;
+  /* border: 2px solid #1890ff; */
+}
+
+.input-textarea {
+  /* background: #0c0c0c; */
+  width: 100%;
+  border: none;
+  resize: none;
+  line-height: 24px;
+  /* 绮剧‘琛岄珮 */
+  font-size: 14px;
+  padding: 8px 15px;
+  min-height: 24px !important;
+  /* 寮哄埗鍗曡楂樺害 */
+  max-height: 152px !important;
+  /* 寮哄埗6琛岄珮搴� */
+  overflow-y: auto;
+  box-sizing: content-box;
+  /* 闃叉padding褰卞搷璁$畻 */
+}
+
+.input-textarea:focus {
+  outline: none;
+  box-shadow: none;
+}
+
+.wechat-input {
+  flex: 1;
+  min-height: 40px;
+  max-height: 144px;
+  /* 6琛� x 24px琛岄珮 */
+  padding: 8px 0;
+  line-height: 1.5;
+  border: 0;
+  background: transparent;
+  font-size: 16px;
+  color: #2c3e50;
+  resize: none;
+  overflow-y: auto;
+}
+
+.wechat-input:focus {
+  border-color: #07c160;
+  background: white;
+  box-shadow: 0 4px 12px rgba(7, 193, 96, 0.1);
+  /* 娣诲姞鑱氱劍闃村奖 */
+}
+
+.wechat-input::placeholder {
+  color: #a8c5e6;
+  /* 娴呰摑鑹插崰浣嶇 */
+}
+
+.microphone-icon {
+  font-size: 20px;
+  color: #7fade6;
+  cursor: pointer;
+}
+
+/* 鎿嶄綔鎸夐挳鍖哄煙 */
+.action-buttons {
+  width: 100%;
+  display: flex;
+  justify-content: flex-end;
+  /* 鍙冲榻愭寜閽� */
+  gap: 8px;
+  padding: 0 0 5px 0;
+  background: transparent;
+  /* border: 2px solid #1890ff; */
+}
+
+/* 鍙戦�佹寜閽敼閫� */
+.send-button {
+  width: 45px;
+  height: 25px;
+  border-radius: 10px;
+  background: #1890ff;
+  border: none;
+  padding: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  transition: all 0.3s ease;
+  margin: 2px 6px;
+}
+
+.send-icon {
+  color: white;
+  font-size: 16px;
+  /* transform: rotate(45deg); */
+}
+
+.send-button:disabled {
+  background: #b6d7ff;
+  cursor: not-allowed;
+}
+
+/* 鎻愮ず鏂囨湰 */
+.tip-text {
+  text-align: center;
+  font-size: 12px;
+  color: #95a5c6;
+  margin: 12px 0 10px 0;
+  letter-spacing: 0.5px;
+}
+
+/* 杈撳叆妗嗙鐢ㄧ姸鎬� */
+.wechat-input:disabled {
+  background: #f0f0f0;
+  opacity: 0.8;
+}
+
+.send-button:not(:disabled):hover {
+  background: #2482ff;
+}
+
+.cursor {
+  display: inline-block;
+  width: 8px;
+  height: 16px;
+  background: #666;
+  margin-left: 2px;
+  animation: blink 1s infinite;
+}
+
+@keyframes blink {
+
+  0%,
+  100% {
+    opacity: 1;
+  }
+
+  50% {
+    opacity: 0;
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/searchNew/components/ChatHistoryView.vue b/src/pages/searchNew/components/ChatHistoryView.vue
new file mode 100644
index 0000000..9247149
--- /dev/null
+++ b/src/pages/searchNew/components/ChatHistoryView.vue
@@ -0,0 +1,248 @@
+<template>
+  <div class="schedule-container">
+    <el-card class="schedule-card" shadow="never">
+      <div v-for="(item, index) in chatList" :key="index" class="chat-item" @mouseenter="showDelete = index" 
+           @mouseleave="showDelete = null">
+        <!-- 鏂板鍒犻櫎鎸夐挳 -->
+        <i class="el-icon-delete delete-button" 
+        v-show="showDelete === index" 
+           @click.stop="handleDelete(item.chatId, $event)"></i>
+        <div class="chat-header"></div>
+        <div class="chat-header">
+          <!-- <span class="chat-time">{{ formatDate(item.createTime) }}</span>
+          <span class="chat-id">#{{ item.chatId }}</span> -->
+        </div>
+        <div class="chat-content" @click="handleItemClick(item.chatId)">
+          {{ extractContent(item.title) }}
+        </div>
+
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import chatHistory from "@/api/ChatHistoryView"
+export default {
+  name: 'ChatHistory',
+  data() {
+    return {
+      showDelete: null, // 褰撳墠鏄剧ず鍒犻櫎鎸夐挳鐨勭储寮�
+      chatData: {
+        list: [],
+        pagination: {}
+      }
+    }
+  },
+  computed: {
+    chatList() {
+      return this.chatData.list || []
+    }
+  },
+  methods: {
+    // 鏂板鍒犻櫎澶勭悊鏂规硶
+    async handleDelete(chatId, index) {
+      try {
+        await this.$confirm('纭畾瑕佸垹闄ゆ鑱婂ぉ璁板綍鍚楋紵', '鎻愮ず', {
+          confirmButtonText: '纭畾',
+          cancelButtonText: '鍙栨秷',
+          type: 'warning'
+        })
+        
+        // 璋冪敤鍒犻櫎鎺ュ彛
+        await chatHistory.deleteChat({
+          chatId:chatId
+        })
+        
+        // 鍓嶇绔嬪嵆鏇存柊鍒楄〃
+        this.chatData.list.splice(index, 1)
+        this.$message.success('鍒犻櫎鎴愬姛')
+      } catch (error) {
+        if (error !== 'cancel') {
+          console.error('鍒犻櫎澶辫触:', error)
+          this.$message.error('鍒犻櫎澶辫触')
+        }
+      }
+    },
+    handleItemClick(chatId) {
+      // console.info("鐐瑰嚮"+chatId)
+      this.$emit('item-selected', chatId); // 瑙﹀彂鑷畾涔変簨浠�
+    },
+    async fetchChatHistory() {
+      try {
+        const tasks = await chatHistory.getChats({//妫�娴嬪璇濆巻鍙�
+          // page: 1,
+          // pageSize: 999
+        });
+        // console.info(tasks.data.list)
+        this.chatData.list = tasks.data.list
+        this.chatData.pagination = tasks.data.pagination
+      } catch (error) {
+        console.error('鑾峰彇绛涢�夐�夐」澶辫触:', error);
+        this.$message.error('绛涢�夐�夐」鍔犺浇澶辫触');
+      }
+    },
+    formatDate(dateString) {
+      return dateString.split(' ')[0] // 鎻愬彇鏃ユ湡閮ㄥ垎
+    },
+    extractContent(content) {
+      // 绉婚櫎<think>鏍囩鍐呭锛屾彁鍙栧疄闄呭唴瀹�
+      const cleanContent = content.replace(/<think>[\s\S]*?<\/think>\n*/g, '')
+      return cleanContent.trim()
+    }
+  },
+  mounted() {
+    // 妯℃嫙鎺ユ敹鍚庣鏁版嵁
+    this.fetchChatHistory()
+    // this.chatData = {
+    //   list: [
+    //     {
+    //       chatId: 19,
+    //       title: `<think>鎬濊�冭繃绋�...</think>\n\n浣犲ソ锛佹湁浠�涔堟垜鍙互甯綘鐨勫悧锛燄煒奰,
+    //       createTime: "2025-05-27 09:30:33.1284251+00:00"
+    //     }
+    //     // 鍏朵粬鏁版嵁椤�...
+    //   ],
+    //   pagination: {
+    //     page: 1,
+    //     total: 6
+    //   }
+    // }
+  }
+}
+</script>
+
+<style scoped>
+/* 浼樺寲鍚庣殑鏍峰紡 */
+.schedule-container {
+  height: 600px;
+  background: white;
+  padding: 0;
+  overflow-y: auto;
+}
+
+.schedule-card {
+  padding: 0;
+  border: none;
+  min-height: 100%;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+}
+
+.chat-item {
+  padding: 10px  0;
+  /* border-bottom: 1px solid #f0f0f0; */
+  cursor: pointer;
+  transition: background-color 0.3s;
+  position: relative; /* 涓虹粷瀵瑰畾浣嶆寜閽彁渚涘弬鑰� */
+  padding-right: 40px; /* 涓烘寜閽暀鍑虹┖闂� */
+}
+.delete-button {
+  position: absolute;
+  right: 8px;
+  top: 50%;
+  transform: translateY(-50%);
+  cursor: pointer;
+  color: #ff4d4f;
+  padding: 5px;
+  font-size: 16px;
+  transition: all 0.3s;
+  z-index: 2;
+}
+.delete-button:hover {
+  background-color: rgba(255,77,79,0.1);
+  border-radius: 50%;
+}
+
+/* 浼樺寲鎮仠鏁堟灉 */
+.chat-item:hover .delete-button {
+  display: block;
+}
+
+.chat-item:hover {
+  background-color: #f8f9fa;
+}
+
+.chat-header {
+  display: flex;
+  justify-content: space-between;
+  /* margin-bottom: 8px; */
+  font-size: 12px;
+  color: #666;
+}
+.item-container {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+  width: 100%;
+}
+.chat-content {
+  flex: 1;
+  cursor: pointer;
+  color: #1a1a1a;
+  font-size: 16px;
+  line-height: 1.6;
+  word-break: break-word;
+  text-align: left; /* 鏂板宸﹀榻� */
+
+  /* 鏂板鍗曡鐪佺暐鏍峰紡 */
+  display: block;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  
+  /* 纭繚瀹藉害闄愬埗 */
+  max-width: 100%;
+  width: 100%;
+}
+/* 鎮仠鏃舵樉绀哄畬鏁村唴瀹� */
+/* .chat-item:hover .chat-content {
+  white-space: normal;
+  overflow: visible;
+  text-overflow: initial;
+} */
+
+.loading-container {
+  padding: 40px;
+  text-align: center;
+  color: #666;
+  font-size: 14px;
+}
+
+.empty-state {
+  text-align: center;
+  padding: 40px;
+  color: #999;
+  
+  i {
+    font-size: 48px;
+    margin-bottom: 16px;
+  }
+}
+
+.pagination {
+  margin-top: auto;
+  padding: 16px;
+  justify-content: center;
+}
+
+/* 婊氬姩鏉′紭鍖� */
+::-webkit-scrollbar {
+  width: 6px;
+}
+
+::-webkit-scrollbar-track {
+  background: #f1f1f1;
+}
+
+::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+  background: #a8a8a8;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/searchNew/components/SurveyView.vue b/src/pages/searchNew/components/SurveyView.vue
new file mode 100644
index 0000000..4a21fc3
--- /dev/null
+++ b/src/pages/searchNew/components/SurveyView.vue
@@ -0,0 +1,1570 @@
+<template>
+  <div>
+    <!-- 鏂板瀹炴椂鐩戞帶寮圭獥 -->
+    <el-dialog title="瀹炴椂鐩戞帶" :visible.sync="realTimeVisible" width="60%" custom-class="resizable-dialog" :modal="true"
+      :lock-scroll="false" :close-on-click-modal="false">
+      <!-- <div class="dialog-content"> -->
+      <camera-video @close="realTimeVisible = false" />
+      <!-- <p>灏濊瘯鎷栨嫿杈圭紭鎴栬钀借皟鏁村ぇ灏�</p>
+                <div v-for="handle in handles" :key="handle.position" class="resize-handle" :class="handle.position"
+                    @mousedown.prevent="startResize(handle.position, $event)">
+                </div>
+            </div> -->
+    </el-dialog>
+    <!-- 璇︽儏寮圭獥 -->
+    <!-- 淇敼鍚庣殑璇︽儏寮圭獥 -->
+    <el-dialog :visible.sync="detailVisible" title="" width="660px" custom-class="detail-dialog right-aligned">
+      <!-- 椤堕儴鍒囨崲鎸夐挳 -->
+      <div class="media-switch">
+        <el-radio-group v-model="currentMediaType">
+          <el-radio-button label="image" class="media-tab">澶у浘</el-radio-button>
+          <el-radio-button label="video" class="media-tab">瑙嗛</el-radio-button>
+        </el-radio-group>
+      </div>
+      <el-divider></el-divider>
+      <!-- 涓婇儴濯掍綋鍖� -->
+      <div class="media-container">
+        <div v-if="currentMediaType === 'image'" class="main-image">
+          <el-image :src="detailItem.image_path" alt="浜嬩欢鎴浘" class="detail-img previewable-image"
+            :preview-src-list="[detailItem.image_path]" />
+        </div>
+        <div v-else class="video-section">
+          <div class="video-placeholder">
+            <!-- 淇敼video鏍囩閮ㄥ垎 -->
+            <video :src="detailItem.video_path" controls style="width: 100%; height: 100%; object-fit: contain"></video>
+            <!-- <wasm-player  style="width: 100%; height: 100%; object-fit: contain"></wasm-player> -->
+          </div>
+        </div>
+      </div>
+
+      <!-- 涓嬮儴淇℃伅鍖� -->
+      <div class="info-container">
+        <!-- <el-descriptions :column="2" border> -->
+        <el-descriptions :column="1">
+          <el-descriptions-item label="鏃堕棿" class="info-item">
+            <span style="width: 28px"></span>
+            <span class="info-value">{{
+              formatStartDateTime(detailItem.detect_time)
+            }}</span>
+          </el-descriptions-item>
+
+          <el-descriptions-item label="瑙嗛鐐逛綅" class="info-item">
+            <span class="info-value">{{ detailItem.video_name }}</span>
+          </el-descriptions-item>
+          <el-descriptions-item label="浠诲姟鍚嶇О" v-if="backendData">
+            <span class="multi-value">
+              {{ detailItem.task_names }}
+            </span>
+          </el-descriptions-item>
+
+          <el-descriptions-item label="浜嬩欢绛夌骇" v-if="backendData">
+            <span style="background-color: #f70713; width: 25px; height: 15px">
+            </span><span style="width: 5px"></span>{{ detailItem.event_levels }}
+          </el-descriptions-item>
+
+          <el-descriptions-item label="闅愭偅鎻忚堪" v-if="backendData">
+            <el-tooltip placement="top" :content="detailItem.risk_description" effect="light"
+              popper-class="my-tooltip">
+              <span class="multi-value ellipsis">{{ detailItem.risk_description }}</span>
+            </el-tooltip>
+
+          </el-descriptions-item>
+
+          <el-descriptions-item label="澶勭悊寤鸿" v-if="backendData">
+            <el-tooltip placement="top" :content="detailItem.suggestion" effect="light" popper-class="my-tooltip">
+              <span class="multi-value ellipsis">{{ detailItem.suggestion }}</span>
+            </el-tooltip>
+          </el-descriptions-item>
+          <el-descriptions-item label="鐩稿叧鏂囨。" v-if="backendData">
+            <div v-for="(doc, index) in detailItem.knowledge_documents || []" :key="index" class="multi-value">
+              <!-- <a :href="getPreviewUrl(doc)" target="_blank" class="doc-link" style="text-decoration: none;">
+                <span>銆妠{ doc.fileName }}銆�</span>
+              </a> -->
+              <span class="doc-link" @click="getPreviewUrl2(doc.id)">銆妠{ doc.fileName }}銆�</span>
+              <span v-if="index < detailItem.knowledge_documents.length - 1">, </span>
+            </div>
+          </el-descriptions-item>
+          <el-descriptions-item label="鍥剧墖鍐呭" style="">
+            <div class="desc_class">
+              <span class="multi-value2">
+                {{ detailItem.zh_desc_class }}
+              </span>
+            </div>
+          </el-descriptions-item>
+
+        </el-descriptions>
+      </div>
+    </el-dialog>
+
+    <div class="statistics-container">
+      <!-- 宸︿晶绛涢�夋爮 -->
+      <div class="left-sidebar" :class="{ collapsed: isSidebarCollapsed }">
+        <div class="stats-header">
+          <div class="ai-avatar">
+            <img :src="require('@/assets/img/AI-avatar.png')" class="avatar-img" />
+            <div class="header-text" v-show="!isSidebarCollapsed">
+              <h3 class="content-title header-gradient2">浣犲ソ锛屾垜鏄皬璐�</h3>
+              <div class="stats-numbers">
+                <span>寰堥珮鍏磋鍒颁綘锛�</span>
+              </div>
+            </div>
+            <div class="header-actions">
+              <img :src="require('@/assets/img/fold_up.png')" class="fold-icon" :class="{ reverse: isSidebarCollapsed }"
+                @click="toggleSidebar" />
+              <img v-if="isSidebarCollapsed" :src="require('@/assets/img/conversation.png')" class="fold-icon"
+                :class="{ reverse: isSidebarCollapsed }" @click="handleNewSession" />
+              <img v-if="isSidebarCollapsed" :src="require('@/assets/img/historical.png')" class="fold-icon"
+                :class="{ reverse: isSidebarCollapsed }" @click="handleHistoryClick" />
+            </div>
+          </div>
+        </div>
+        <div class="session-buttons" v-if="!isSidebarCollapsed">
+          <el-button @click="handleHistoryClick" type="primary" round class="history-btn"
+            style="flex: 1; margin-right: 10px">
+            鍘嗗彶浼氳瘽
+          </el-button>
+          <el-button @click="handleNewSession" type="primary" round class="new-session-btn"
+            style="flex: 1; position: relative">
+            寮�鍚柊浼氳瘽
+            <i class="el-icon-arrow-right" style="margin-left: 8px; font-size: 14px"></i>
+          </el-button>
+        </div>
+        <el-divider v-if="!isSidebarCollapsed"></el-divider>
+        <!-- AI妫�绱㈢粍浠� -->
+        <ai-retrieval @list-selected="handleAiRetrievalSelected" :current-chat-id="selectedChatId" ref="aiRetrieval"
+          class="ai-retrieval-container" v-show="showAIRetrieval && !isSidebarCollapsed" />
+        <chat-history @item-selected="handleHistorySelected" class="ai-retrieval-container"
+          v-show="!showAIRetrieval && !isSidebarCollapsed" />
+      </div>
+
+      <!-- 鍙充晶涓诲唴瀹� -->
+      <div class="right-content">
+        <div class="right-header">
+          <h2 class="content-title" >
+            <span class="header-gradient">AI</span><span style="margin-left: 15px;font-size: 30px">鏂囨悳涓囩墿</span>
+          </h2>
+          <div class="header-actions-right">
+            <el-button type="primary" class="action-btn" @click="handleRealTimeMonitor">
+              瀹炴椂鐩戞帶
+            </el-button>
+            <el-button type="primary" class="action-btn" @click="resetList()">
+              鍒锋柊鏁版嵁
+            </el-button>
+          </div>
+        </div>
+        <!-- 妫�娴嬬粨鏋滃睍绀� -->
+        <div class="content-wrapper">
+          <!-- 娣诲姞鏁版嵁鍔犺浇鐘舵�佹彁绀� -->
+          <div v-if="isLoading" class="loading-container">
+            <el-icon class="is-loading" size="24">
+              <Loading />
+            </el-icon>
+            <span>鏁版嵁鍔犺浇涓�...</span>
+          </div>
+          <!-- 鏃犻檺婊氬姩瀹瑰櫒 -->
+          <div class="results-container" @scroll="handleScroll">
+            <el-empty v-if="results.length === 0" description="鏆傛棤鏁版嵁" style="margin-top: 50px"></el-empty>
+            <div v-else class="gallery-section">
+              <div class="image-grid-container">
+                <div class="image-grid" ref="imageGrid">
+                  <div v-for="(item, index) in results" :key="index" class="image-card-wrapper"
+                    :style="{ width: cardWidth }">
+                    <el-card class="result-card" :class="{ 'selected-card': selectedItemId === item.id }"
+                      @click.native.stop="handleCardClick(item)">
+                      <div class="image-wrapper">
+                        <el-image slot="error" :src="item.image_path" class="result-image" alt="妫�娴嬬粨鏋�" />
+                        <!-- <img slot="error" src="@/assets/01.png" class="result-image" alt="妫�娴嬬粨鏋�" /> -->
+                        <div class="image-overlay" v-if="item.is_warning == 1">
+                          <span class="check-item">
+                            {{ item.task_names }}
+                          </span>
+                          <el-tag size="mini" class="level-tag">
+                            {{ item.event_levels }}
+                          </el-tag>
+                        </div>
+                      </div>
+                      <div class="card-content">
+                        <div class="meta-info">
+                          <div class="time-info">
+                            <img src="@/assets/img/time-fill@1x.png" alt="" class="time-icon">
+                            <span class="detect-time">{{ formatStartDateTime(item.detect_time) }}</span>
+                            <el-popover placement="bottom" width="300" trigger="click" v-model="popoverVisible[index]"
+                              v-if="item.is_desc === 2" class="right-btn2">
+                              <i class="el-icon-close" @click="closePopover(index)"></i>
+                              <span style="color: black; font-weight: 600">鍥剧墖鍐呭</span>
+                              <div class="task-popover-content">
+                                {{ item.zh_desc_class }}
+                              </div>
+                              <img src="@/assets/img/article-fill@1x.png" alt="" class="time-icon2" slot="reference"
+                                @click.stop="togglePopover(index)">
+                            </el-popover>
+                          </div>
+                          <div class="device-info">
+                            <div class="camera-info">
+                              <img src="@/assets/img/live-fill@1x.png" alt="" class="time-icon">
+                              <span>{{ item.video_name }}</span>
+                              <el-dropdown size="small" @command="handleCommand" class="right-btn">
+                                <img src="@/assets/img/modelTraining.png"
+                                  style="width: 16px;height: 16px;margin-left: 10px; vertical-align: middle">
+                                <el-dropdown-menu slot="dropdown">
+                                  <el-dropdown-item
+                                    :command="{ ruleName: item.rule_names ? item.rule_names[0].fileName : '', cameraId: item.video_point_id + '', cameraName: item.video_name, imagePath: item.image_path, status: 1 }">姝g‘</el-dropdown-item>
+                                  <el-dropdown-item
+                                    :command="{ ruleName: item.rule_names ? item.rule_names[0].fileName : '', cameraId: item.video_point_id + '', cameraName: item.video_name, imagePath: item.image_path, status: 2 }">閿欒</el-dropdown-item>
+                                  <el-dropdown-item
+                                    :command="{ ruleName: item.rule_names ? item.rule_names[0].fileName : '', cameraId: item.video_point_id + '', cameraName: item.video_name, imagePath: item.image_path, status: 0 }">涓嶇‘瀹�</el-dropdown-item>
+                                </el-dropdown-menu>
+                              </el-dropdown>
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </el-card>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <!-- 婊氬姩鍔犺浇鎻愮ず -->
+            <div v-if="isLoadingMore" class="loading-more">
+              <el-icon class="is-loading" size="16">
+                <Loading />
+              </el-icon>
+              <span>鍔犺浇鏇村...</span>
+            </div>
+            <div v-if="!hasMore && results.length > 0" class="no-more-data">
+              娌℃湁鏇村鏁版嵁浜�
+            </div>
+
+          </div>
+
+          <!-- 鍒嗛〉 -->
+          <!-- <div class="pagination-wrapper" v-if="results.length > 0">
+                    <el-pagination :current-page="currentPage" :page-size="16" :total="totalResults"
+                        layout="prev, pager, next" @current-change="handlePageChange">
+                    </el-pagination>
+                </div> -->
+        </div>
+      </div>
+    </div>
+    </div>
+</template>
+
+<script>
+import _ from 'lodash'; // 鐢ㄤ簬闃叉姈
+import surey from "@/api/SurveyView";
+import aiRetrieval from './AiRetrievalView';
+import chatHistory from './ChatHistoryView';
+import cameraVideo from './cameraVideo.vue';
+export default {
+    components: {
+        aiRetrieval,
+        chatHistory,
+        cameraVideo
+    },
+  data() {
+    return {
+      // 鏂板鍗$墖瀹藉害璁$畻鐩稿叧鏁版嵁
+      cardWidth: '300px', // 榛樿鍗$墖瀹藉害
+      minCardWidth: 300, // 鍗$墖鏈�灏忓搴�
+      margin: 20, // 鍗$墖闂磋窛
+      idsList: [],
+      pageSize: 30,          // 姣忛〉鍔犺浇鏁版嵁閲�
+      hasMore: true,          // 鏄惁鏈夋洿澶氭暟鎹�
+      isLoadingMore: false,   // 鏄惁姝e湪鍔犺浇鏇村
+      scrollTop: 0,           // 婊氬姩浣嶇疆璁板綍
+      docUrl: "",
+      isLoading: false, // 鏂板鍔犺浇鐘舵�佸彉閲�
+      backendData: true,
+      popoverVisible: {}, // 鐢ㄤ簬鎺у埗姣忎釜鍗$墖鐨勬皵娉℃樉绀虹姸鎬�
+      dialogVisible: true,
+      handles: [
+        { position: "top" },
+        { position: "bottom" },
+        { position: "left" },
+        { position: "right" },
+        { position: "top-left" },
+        { position: "top-right" },
+        { position: "bottom-left" },
+        { position: "bottom-right" },
+      ],
+      isResizing: false,
+      startX: 0,
+      startY: 0,
+      startWidth: 0,
+      startHeight: 0,
+      startLeft: 0,
+      startTop: 0,
+      realTimeVisible: false, // 鏂板寮圭獥鎺у埗鍙橀噺
+      selectedChatId: null,
+      showAIRetrieval: true,
+      isSidebarCollapsed: false,
+      selectedItemId: null, // 鏂板閫変腑椤笽D
+      filterOptions: {
+        tasks: [],
+        levels: [],
+        cameras: [],
+        rules: [],
+      },
+      currentMediaType: "image", // 褰撳墠濯掍綋绫诲瀷
+      detailVisible: false,
+      detailItem: {},
+      currentPage: 1,
+      totalResults: 40, // 鎬绘暟鎹噺
+      filter: {
+        keyword: "",
+        task: "",
+        timeRange: [],
+        level: "",
+        camera: "",
+        rules: "",
+      },
+      showWarningOnly: true,
+      results: [
+        {
+          // image_path: require("@/assets/01.png"),
+          // video_path: require("@/assets/video.mp4"),
+          risk_description: "闅愭偅鎻忚堪",
+          detect_time: "2021-12-09 20:23",
+          video_name: "鎽勫儚鏈篈",
+          event_level: "1",
+          is_warning: 1,
+          event_levels: "涓�绾�",
+          task_names: "鐢熶骇浠诲姟绠℃帶,鐢熶骇浠诲姟绠℃帶,鐢熶骇浠诲姟绠℃帶,鐢熶骇浠诲姟绠℃帶,鐢熶骇浠诲姟绠℃帶", // 鏀逛负鏁扮粍
+          suggestion: "澶勭悊寤鸿", // 澶勭悊寤鸿
+          video_point_id: 1,
+          rule_names: "",
+          knowledge_documents: [
+            { ruleId: 1, fileName: "瀹夊叏鍑嗗垯", file_url: "https://image.baidu.com/search/detail?z=0&word=%E5%9B%BE%E7%89%87&hs=0&pn=1&spn=0&di=7498023338351001601&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&ie=utf-8&oe=utf-8&lm=&cs=2629589424%2C2655723787&os=2900564191%2C785059641&simid=3974997321%2C325136453&adpicid=0&lpn=0&fr=click-pic&fm=&ic=&hd=&latest=&copyright=&isImgSet=&commodity=&hot=&imgratio=&imgformat=&sme=&width=0&height=0&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fww2.sinaimg.cn%2Fmw690%2F61d7678dgy1hvt194v9kqj20p00uuape.jpg&fromurl=ippr_z2C%24qAzdH3FAzdH3Fojtk5_z%26e3Bv54AzdH3F8m98cam0a8AzdH3FP81pPuN3N&gsm=1e&islist=&querylist=&lid=9dec68e500008991" },
+            { ruleId: 1, fileName: "瀹夊叏鍑嗗垯", file_url: "http://192.168.1.232:7010/home/debian/GroundingDINO/txt/zs/AI-avatar.png" },
+          ], // 棰勮瑙勫垯鏁扮粍
+          zh_desc_class: "鍥剧墖鏄剧ず鐨勬槸涓�涓鍐呭満鏅紝鏃堕棿鎴虫樉绀轰负2025骞�6鏈�27鏃ユ槦鏈熶簲16:57:12銆傜敾闈腑鍙互鐪嬪埌涓�涓蛋寤婅繃閬撶殑鐜锛屽彸渚ф湁涓�鎵囩幓鐠冮棬锛岄棬涓婅鐩栫潃钃濊壊鐨勯槻灏樺竷銆傚乏渚у涓婃湁涓�涓粦鏉匡紝涓婇潰鍐欐湁涓�浜涗腑鏂囧拰鑻辨枃鐨勬枃瀛楋紝鍐呭鍖呮嫭鈥滆帿浼熻揪鈥濄�佲�渋nt4鈥濄�佲�淎WQ鈥濄�佲��4G鈥濈瓑銆傞粦鏉挎梺杈规湁涓�涓櫧鑹茬殑鏌滃瓙锛屾煖瀛愪笂鏀剧潃涓�浜涚墿鍝併�傚瑙掑杩樻湁涓�鏍皬鏍戙�傛暣涓埧闂寸殑澧欏鏄櫧鑹茬殑锛屽ぉ鑺辨澘涔熸槸鐧借壊鐨勫浘鐗囨樉绀虹殑鏄竴涓鍐呭満鏅紝鏃堕棿鎴虫樉绀轰负2025骞�6鏈�27鏃ユ槦鏈熶簲16:57:12銆傜敾闈腑鍙互鐪嬪埌涓�涓蛋寤婅繃閬撶殑鐜锛屽彸渚ф湁涓�鎵囩幓鐠冮棬锛岄棬涓婅鐩栫潃钃濊壊鐨勯槻灏樺竷銆傚乏渚у涓婃湁涓�涓粦鏉匡紝涓婇潰鍐欐湁涓�浜涗腑鏂囧拰鑻辨枃鐨勬枃瀛楋紝鍐呭鍖呮嫭鈥滆帿浼熻揪鈥濄�佲�渋nt4鈥濄�佲�淎WQ鈥濄�佲��4G鈥濈瓑銆傞粦鏉挎梺杈规湁涓�涓櫧鑹茬殑鏌滃瓙锛屾煖瀛愪笂鏀剧潃涓�浜涚墿鍝併�傚瑙掑杩樻湁涓�鏍皬鏍戙�傛暣涓埧闂寸殑澧欏鏄櫧鑹茬殑锛屽ぉ鑺辨澘涔熸槸鐧借壊鐨�"
+        },
+        {
+          image_path: "",
+          risk_description: "闅愭偅鎻忚堪",
+          detect_time: "2021-12-09 21:15",
+          video_name: "鎽勫儚鏈築",
+          is_desc: 2,
+          zh_desc_class: "鍥剧墖鏄剧ず鐨勬槸涓�涓鍐呭満鏅紝鏃堕棿鎴虫樉绀轰负2025骞�6鏈�27鏃ユ槦鏈熶簲16:57:12銆傜敾闈腑鍙互鐪嬪埌涓�涓蛋寤婅繃閬撶殑鐜锛屽彸渚ф湁涓�鎵囩幓鐠冮棬锛岄棬涓婅鐩栫潃钃濊壊鐨勯槻灏樺竷銆傚乏渚у涓婃湁涓�涓粦鏉匡紝涓婇潰鍐欐湁涓�浜涗腑鏂囧拰鑻辨枃鐨勬枃瀛楋紝鍐呭鍖呮嫭鈥滆帿浼熻揪鈥濄�佲�渋nt4鈥濄�佲�淎WQ鈥濄�佲��4G鈥濈瓑銆傞粦鏉挎梺杈规湁涓�涓櫧鑹茬殑鏌滃瓙锛屾煖瀛愪笂鏀剧潃涓�浜涚墿鍝併�傚瑙掑杩樻湁涓�鏍皬鏍戙�傛暣涓埧闂寸殑澧欏鏄櫧鑹茬殑锛屽ぉ鑺辨澘涔熸槸鐧借壊鐨勫浘鐗囨樉绀虹殑鏄竴涓鍐呭満鏅紝鏃堕棿鎴虫樉绀轰负2025骞�6鏈�27鏃ユ槦鏈熶簲16:57:12銆傜敾闈腑鍙互鐪嬪埌涓�涓蛋寤婅繃閬撶殑鐜锛屽彸渚ф湁涓�鎵囩幓鐠冮棬锛岄棬涓婅鐩栫潃钃濊壊鐨勯槻灏樺竷銆傚乏渚у涓婃湁涓�涓粦鏉匡紝涓婇潰鍐欐湁涓�浜涗腑鏂囧拰鑻辨枃鐨勬枃瀛楋紝鍐呭鍖呮嫭鈥滆帿浼熻揪鈥濄�佲�渋nt4鈥濄�佲�淎WQ鈥濄�佲��4G鈥濈瓑銆傞粦鏉挎梺杈规湁涓�涓櫧鑹茬殑鏌滃瓙锛屾煖瀛愪笂鏀剧潃涓�浜涚墿鍝併�傚瑙掑杩樻湁涓�鏍皬鏍戙�傛暣涓埧闂寸殑澧欏鏄櫧鑹茬殑锛屽ぉ鑺辨澘涔熸槸鐧借壊鐨勫浘鐗囨樉绀虹殑鏄竴涓鍐呭満鏅紝鏃堕棿鎴虫樉绀轰负2025骞�6鏈�27鏃ユ槦鏈熶簲16:57:12銆傜敾闈腑鍙互鐪嬪埌涓�涓蛋寤婅繃閬撶殑鐜锛屽彸渚ф湁涓�鎵囩幓鐠冮棬锛岄棬涓婅鐩栫潃钃濊壊鐨勯槻灏樺竷銆傚乏渚у涓婃湁涓�涓粦鏉匡紝涓婇潰鍐欐湁涓�浜涗腑鏂囧拰鑻辨枃鐨勬枃瀛楋紝鍐呭鍖呮嫭鈥滆帿浼熻揪鈥濄�佲�渋nt4鈥濄�佲�淎WQ鈥濄�佲��4G鈥濈瓑銆傞粦鏉挎梺杈规湁涓�涓櫧鑹茬殑鏌滃瓙锛屾煖瀛愪笂鏀剧潃涓�浜涚墿鍝併�傚瑙掑杩樻湁涓�鏍皬鏍戙�傛暣涓埧闂寸殑澧欏鏄櫧鑹茬殑锛屽ぉ鑺辨澘涔熸槸鐧借壊鐨勫浘鐗囨樉绀虹殑鏄竴涓鍐呭満鏅紝鏃堕棿鎴虫樉绀轰负2025骞�6鏈�27鏃ユ槦鏈熶簲16:57:12銆傜敾闈腑鍙互鐪嬪埌涓�涓蛋寤婅繃閬撶殑鐜锛屽彸渚ф湁涓�鎵囩幓鐠冮棬锛岄棬涓婅鐩栫潃钃濊壊鐨勯槻灏樺竷銆傚乏渚у涓婃湁涓�涓粦鏉匡紝涓婇潰鍐欐湁涓�浜涗腑鏂囧拰鑻辨枃鐨勬枃瀛楋紝鍐呭鍖呮嫭鈥滆帿浼熻揪鈥濄�佲�渋nt4鈥濄�佲�淎WQ鈥濄�佲��4G鈥濈瓑銆傞粦鏉挎梺杈规湁涓�涓櫧鑹茬殑鏌滃瓙锛屾煖瀛愪笂鏀剧潃涓�浜涚墿鍝併�傚瑙掑杩樻湁涓�鏍皬鏍戙�傛暣涓埧闂寸殑澧欏鏄櫧鑹茬殑锛屽ぉ鑺辨澘涔熸槸鐧借壊鐨勫浘鐗囨樉绀虹殑鏄竴涓鍐呭満鏅紝鏃堕棿鎴虫樉绀轰负2025骞�6鏈�27鏃ユ槦鏈熶簲16:57:12銆傜敾闈腑鍙互鐪嬪埌涓�涓蛋寤婅繃閬撶殑鐜锛屽彸渚ф湁涓�鎵囩幓鐠冮棬锛岄棬涓婅鐩栫潃钃濊壊鐨勯槻灏樺竷銆傚乏渚у涓婃湁涓�涓粦鏉匡紝涓婇潰鍐欐湁涓�浜涗腑鏂囧拰鑻辨枃鐨勬枃瀛楋紝鍐呭鍖呮嫭鈥滆帿浼熻揪鈥濄�佲�渋nt4鈥濄�佲�淎WQ鈥濄�佲��4G鈥濈瓑銆傞粦鏉挎梺杈规湁涓�涓櫧鑹茬殑鏌滃瓙锛屾煖瀛愪笂鏀剧潃涓�浜涚墿鍝併�傚瑙掑杩樻湁涓�鏍皬鏍戙�傛暣涓埧闂寸殑澧欏鏄櫧鑹茬殑锛屽ぉ鑺辨澘涔熸槸鐧借壊鐨勫浘鐗囨樉绀虹殑鏄竴涓鍐呭満鏅紝鏃堕棿鎴虫樉绀轰负2025骞�6鏈�27鏃ユ槦鏈熶簲16:57:12銆傜敾闈腑鍙互鐪嬪埌涓�涓蛋寤婅繃閬撶殑鐜锛屽彸渚ф湁涓�鎵囩幓鐠冮棬锛岄棬涓婅鐩栫潃钃濊壊鐨勯槻灏樺竷銆傚乏渚у涓婃湁涓�涓粦鏉匡紝涓婇潰鍐欐湁涓�浜涗腑鏂囧拰鑻辨枃鐨勬枃瀛楋紝鍐呭鍖呮嫭鈥滆帿浼熻揪鈥濄�佲�渋nt4鈥濄�佲�淎WQ鈥濄�佲��4G鈥濈瓑銆傞粦鏉挎梺杈规湁涓�涓櫧鑹茬殑鏌滃瓙锛屾煖瀛愪笂鏀剧潃涓�浜涚墿鍝併�傚瑙掑杩樻湁涓�鏍皬鏍戙�傛暣涓埧闂寸殑澧欏鏄櫧鑹茬殑锛屽ぉ鑺辨澘涔熸槸鐧借壊鐨�"
+        },
+      ],
+    };
+  },
+  computed: {
+    normalizedPath() {
+      return (backendPath) => {
+        // 鏇挎崲閫昏緫
+        return require(backendPath
+          .replace(/^[a-zA-Z]:/, "") // 鍘婚櫎鐩樼
+          .replace(/\/+/g, "/") // 鍚堝苟澶氫綑鏂滄潬
+          .replace("/opt/smart", "@/assets")); // 鍏抽敭璺緞鏇挎崲
+      };
+    },
+    visibleResults() {
+      return this.results.slice(
+        (this.currentPage - 1) * 8,
+        this.currentPage * 8
+      );
+    },
+    boxHeight() {
+      // 鏍规嵁鍚庣鏁版嵁鍐冲畾楂樺害
+      //   if (!this.backendData) return "380px";
+      return this.backendData ? "160px" : "320px";
+    },
+  },
+  mounted() {
+    // this.fetchFilterOptions();//绛涢�夊垪琛�
+    this.handleSearch([]);
+    this.fetchCameraInfo();
+    this.resetList();
+    this.calculateCardWidth();
+    // 娣诲姞闃叉姈鐨剅esize鐩戝惉
+    window.addEventListener('resize', _.debounce(this.calculateCardWidth, 100));
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.calculateCardWidth);
+  },
+  methods: {
+    // 鏂板鍗$墖瀹藉害璁$畻鏂规硶
+    calculateCardWidth() {
+      if (this.$refs.imageGrid) {
+        const containerWidth = this.$refs.imageGrid.clientWidth;
+        // 璁$畻姣忚鍙互鏀剧疆鐨勫崱鐗囨暟閲忥紝鏈�灏�3鍒�
+        const cardsPerRow = Math.max(3, Math.floor(containerWidth / (this.minCardWidth + this.margin)));
+        
+        // 璁剧疆鍗$墖瀹藉害鍏紡
+        this.cardWidth = `calc(${100 / cardsPerRow}% - ${this.margin}px)`;
+      }
+    },
+    handleCommand(command) {
+      console.log(JSON.stringify(command))
+      surey.insertModelTraining(JSON.stringify(command)).then((res) => {
+        if (res && res.status === 200) {
+          this.$notify({
+            type: "success",
+            message: "娣诲姞鎴愬姛",
+          });
+        } else {
+          this.$notify({
+            type: "error",
+            message: "娣诲姞澶辫触锛�",
+          });
+        }
+      });
+    },
+    // 閲嶇疆鍒楄〃
+    resetList() {
+      this.idsList = [];
+      this.currentPage = 1;
+      this.hasMore = true;
+      this.results = [];
+      this.handleSearch([]);
+    },
+
+    // 婊氬姩浜嬩欢澶勭悊
+    handleScroll(event) {
+      const container = event.target;
+      // 璁板綍婊氬姩浣嶇疆
+      this.scrollTop = container.scrollTop;
+
+      // 妫�鏌ユ槸鍚︽粴鍔ㄥ埌搴曢儴
+      const isBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 50;
+
+      // 褰撴粴鍔ㄥ埌搴曢儴涓旀湁鏇村鏁版嵁锛屼笖褰撳墠娌℃湁鍔犺浇涓紝鍒欏姞杞芥洿澶�
+      if (isBottom && this.hasMore && !this.isLoading && !this.isLoadingMore) {
+        this.loadMoreData();
+      }
+    },
+    // 鍔犺浇鏇村鏁版嵁
+    async loadMoreData() {
+      if (this.isLoadingMore || !this.hasMore) return;
+
+      try {
+        this.isLoadingMore = true;
+        this.currentPage++;
+
+        const params = {
+          ids: [],
+          page: this.currentPage,
+          pageSize: this.pageSize
+        };
+
+        const response = await surey.getSurveys(params);
+        const lists = response.data.list || [];
+        if (lists) {
+          for (let i = 0; i < lists.length; i++) {
+            console.log("333:" + lists[i].video_point_id)
+            this.results.push({
+              task_names: lists[i].task_name,
+              video_name: lists[i].video_name,
+              image_path: "/api-img" + lists[i].image_path,
+              video_path: "/api-img" + lists[i].video_path,
+              detect_time: lists[i].detect_time,
+              event_levels: lists[i].event_level_name,
+              zh_desc_class: lists[i].zh_desc_class,
+              is_warning: lists[i].is_warning,
+              is_desc: lists[i].is_desc,
+              video_point_id: lists[i].video_point_id,
+              rule_names: lists[i].rule_names,
+              knowledge_documents: lists[i].knowledge_documents.map(file => {
+                return {
+                  ...file,
+                  file_url: "/api-img" + file.file_url,
+                  fileName: file.title
+                }
+              })
+            });
+          }
+        }
+
+        // 鍚堝苟缁撴灉
+        // this.results = [...this.results, ...lists];
+
+        // 鏇存柊鏄惁鏈夋洿澶氭暟鎹姸鎬�
+        this.hasMore = lists.length >= this.pageSize;
+
+      } catch (error) {
+        console.error("鍔犺浇鏇村澶辫触:", error);
+      } finally {
+        this.isLoadingMore = false;
+      }
+    },
+    async fetchCameraInfo() {
+      const response = await fetch("/config.json");
+      if (!response.ok) throw new Error(`璇锋眰澶辫触: ${response.status}`);
+      const responseData = await response.json();
+      this.docUrl = responseData.docUrl;
+      console.info("docUrl:" + this.docUrl)
+    },
+    closePopover(index) {
+      this.$set(this.popoverVisible, index, false);
+    },
+    startResize(position, e) {
+      this.isResizing = true;
+      const dialog = document.querySelector(".resizable-dialog");
+
+      this.startX = e.clientX;
+      this.startY = e.clientY;
+      this.startWidth = dialog.offsetWidth;
+      this.startHeight = dialog.offsetHeight;
+      this.startLeft = dialog.offsetLeft;
+      this.startTop = dialog.offsetTop;
+
+      document.addEventListener("mousemove", this.handleResize(position));
+      document.addEventListener("mouseup", this.stopResize);
+    },
+    handleResize(position) {
+      return (e) => {
+        if (!this.isResizing) return;
+
+        const dialog = document.querySelector(".resizable-dialog");
+        const deltaX = e.clientX - this.startX;
+        const deltaY = e.clientY - this.startY;
+
+        // 闄愬埗鏈�灏忓昂瀵�
+        const minWidth = 400;
+        const minHeight = 300;
+
+        switch (position) {
+          case "top":
+            dialog.style.height =
+              Math.max(minHeight, this.startHeight - deltaY) + "px";
+            dialog.style.top = `${this.startTop + deltaY}px`;
+            break;
+          case "bottom":
+            dialog.style.height =
+              Math.max(minHeight, this.startHeight + deltaY) + "px";
+            break;
+          case "left":
+            dialog.style.width =
+              Math.max(minWidth, this.startWidth - deltaX) + "px";
+            dialog.style.left = `${this.startLeft + deltaX}px`;
+            break;
+          case "right":
+            dialog.style.width =
+              Math.max(minWidth, this.startWidth + deltaX) + "px";
+            break;
+          case "top-left":
+            dialog.style.width =
+              Math.max(minWidth, this.startWidth - deltaX) + "px";
+            dialog.style.height =
+              Math.max(minHeight, this.startHeight - deltaY) + "px";
+            dialog.style.left = `${this.startLeft + deltaX}px`;
+            dialog.style.top = `${this.startTop + deltaY}px`;
+            break;
+          case "top-right":
+            dialog.style.width =
+              Math.max(minWidth, this.startWidth + deltaX) + "px";
+            dialog.style.height =
+              Math.max(minHeight, this.startHeight - deltaY) + "px";
+            dialog.style.top = `${this.startTop + deltaY}px`;
+            break;
+          case "bottom-left":
+            dialog.style.width =
+              Math.max(minWidth, this.startWidth - deltaX) + "px";
+            dialog.style.height =
+              Math.max(minHeight, this.startHeight + deltaY) + "px";
+            dialog.style.left = `${this.startLeft + deltaX}px`;
+            break;
+          case "bottom-right":
+            dialog.style.width =
+              Math.max(minWidth, this.startWidth + deltaX) + "px";
+            dialog.style.height =
+              Math.max(minHeight, this.startHeight + deltaY) + "px";
+            break;
+        }
+      };
+    },
+
+    stopResize() {
+      this.isResizing = false;
+      document.removeEventListener("mousemove", this.handleResize);
+      document.removeEventListener("mouseup", this.stopResize);
+    },
+    // 瀹炴椂鐩戞帶鏂规硶
+    handleRealTimeMonitor() {
+      this.realTimeVisible = true;
+    },
+    handleHistorySelected(chatId) {
+      this.showAIRetrieval = true; // 鍒囨崲缁勪欢
+      this.selectedChatId = chatId; // 淇濆瓨chatId
+      //   this.$nextTick(() => {
+      //     this.$refs.aiRetrieval.loadChat(); // 瑙﹀彂瀛愮粍浠跺姞杞�
+      //   });
+    },
+    handleAiRetrievalSelected(params) {
+      console.info("params:" + params)
+      //鏍规嵁id鏌ヨ鏁版嵁
+      this.idsList = params;
+      this.handleSearch()
+    },
+    handleHistoryClick() {
+      this.showAIRetrieval = false;
+      this.isSidebarCollapsed = false;
+    },
+    handleNewSession() {
+      // 璋冪敤AI妫�绱㈢粍浠剁殑閲嶇疆鏂规硶
+      if (
+        this.$refs.aiRetrieval &&
+        typeof this.$refs.aiRetrieval.reset === "function"
+      ) {
+        this.$refs.aiRetrieval.reset();
+      }
+      // 淇濇寔渚ц竟鏍忓睍寮�鐘舵��
+      this.isSidebarCollapsed = false;
+      this.showAIRetrieval = true;
+    },
+    toggleSidebar() {
+      this.isSidebarCollapsed = !this.isSidebarCollapsed;
+    },
+    // 淇敼鍚庣殑鐐瑰嚮澶勭悊鏂规硶
+    handleCardClick(item) {
+      this.selectedItemId = item.id;
+      this.showDetail(item);
+    },
+    // getLevelType(level) {
+    //     const typeMap = {
+    //         '1': 'danger',
+    //         '2': 'warning',
+    //         '3': 'primary',
+    //         '4': 'info',
+    //         '5': 'success'
+    //     }
+    //     return typeMap[level] || 'info'
+    // },
+    // 鑾峰彇绛涢�夋潯浠堕�夐」
+
+    async fetchFilterOptions() {
+      try {
+        const tasks = await surey.getTasks({
+          //妫�娴嬪唴瀹�
+          page: 1,
+          pageSize: 999,
+        });
+        this.filterOptions.tasks = tasks.data.list;
+        const cameras = await surey.getCameras(); //瑙嗛鐐逛綅
+        this.filterOptions.cameras = cameras.data;
+        const warnings = await surey.getWarnings({
+          //棰勮瑙勫垯
+          page: 1,
+          pageSize: 999,
+        });
+        this.filterOptions.rules = warnings.data.list;
+
+        const events = await surey.getEvents(); //浜嬩欢绛夌骇
+        this.filterOptions.levels = events.data;
+        // console.info(this.filterOptions.levels)
+      } catch (error) {
+        console.error("鑾峰彇绛涢�夐�夐」澶辫触:", error);
+        this.$message.error("绛涢�夐�夐」鍔犺浇澶辫触");
+      }
+    },
+    // 鏍煎紡鍖栧紑濮嬫椂闂达紙淇濇寔鍘熸椂闂达級
+    formatStartDateTime(date) {
+      if (!date) return null;
+      const d = new Date(date);
+      const pad = (num) => num.toString().padStart(2, "0");
+      return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
+        d.getDate()
+      )} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
+    },
+
+    // 鏍煎紡鍖栫粨鏉熸椂闂达紙鍥哄畾涓� 23:59:59锛�
+    formatEndDateTime(date) {
+      if (!date) return null;
+      const d = new Date(date);
+      d.setHours(23, 59, 59); // 寮哄埗璁剧疆涓哄綋澶╃殑 23:59:59
+      const pad = (num) => num.toString().padStart(2, "0");
+      return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
+        d.getDate()
+      )} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
+    },
+    // 鏌ヨ鏂规硶
+    async handleSearch() {
+      console.info("this.idsList:" + this.idsList)
+      this.isLoading = true; // 寮�濮嬪姞杞�
+      // console.info(ids)
+      try {
+        this.currentPage = 1;
+        const params = {
+          ids: this.idsList,
+          page: 1,
+          pageSize: this.pageSize,
+        };
+
+        const response = await surey.getSurveys(params);
+        const lists = response.data.list || [];
+        this.results = [];
+        if (lists) {
+          for (let i = 0; i < lists.length; i++) {
+            this.results.push({
+              task_names: lists[i].task_name,
+              video_name: lists[i].video_name,
+              image_path: "/api-img" + lists[i].image_path,
+              video_path: "/api-img" + lists[i].video_path,
+              detect_time: lists[i].detect_time,
+              event_levels: lists[i].event_level_name,
+              zh_desc_class: lists[i].zh_desc_class,
+              is_warning: lists[i].is_warning,
+              is_desc: lists[i].is_desc,
+              video_point_id: lists[i].video_point_id,
+              rule_names: lists[i].rule_names,
+              knowledge_documents: lists[i].knowledge_documents.map(file => {
+                return {
+                  ...file,
+                  file_url: "/api-img" + file.file_url,
+                  fileName: file.title
+                }
+              }),
+              risk_description: lists[i].risk_description,
+              suggestion: lists[i].suggestion
+            });
+          }
+        }
+        this.totalResults = response.data.pagination.total;
+        // 鏇存柊鏄惁鏈夋洿澶氭暟鎹姸鎬�
+        this.hasMore = lists.length >= this.pageSize;
+        // console.info(response.data)
+      } catch (error) {
+        console.error("鏌ヨ澶辫触:", error);
+        this.$message.error("鏌ヨ澶辫触锛岃绋嶅悗閲嶈瘯");
+      } finally {
+        this.isLoading = false; // 缁撴潫鍔犺浇
+      }
+    },
+    // 鏂板璇︽儏灞曠ず鏂规硶
+    showDetail(item) {
+      // console.info(item)
+      this.backendData = item.is_warning == 1 ? true : false;
+      //   console.info(item.is_warning)
+      this.currentMediaType = "image";
+      this.detailItem = {
+        ...item,
+        task: "鐢熶骇浠诲姟绠℃帶", // 鏍规嵁鍥剧墖淇℃伅娣诲姞浠诲姟鍚嶇О
+      };
+      // this.detailItem.image_path = 'http://192.168.1.232:7010/' + item.image_path
+      // this.detailItem.video_path = 'http://192.168.1.232:7010/' + item.video_path
+      this.detailItem.image_path = item.image_path;
+      this.detailItem.video_path = item.video_path;
+      this.detailItem.is_warning = item.is_warning;
+      this.detailItem.suggestion = item.suggestion;
+      this.detailItem.risk_description = item.risk_description;
+      this.detailVisible = true;
+      // console.info(item)
+    },
+    // 鍒嗛〉澶勭悊
+    handlePageChange(page) {
+      this.currentPage = page;
+      this.handleSearch([]);
+    },
+    // 閲嶇疆绛涢�夋潯浠�
+    resetFilter() {
+      this.filter = {
+        keyword: "",
+        task: "",
+        timeRange: [],
+        level: "",
+        camera: "",
+      };
+      this.currentPage = 1;
+      this.handleSearch([]);
+    },
+    // 鑾峰彇鏂囨。棰勮URL
+    getPreviewUrl(doc) {
+      // 鑾峰彇鏂囦欢鎵╁睍鍚�
+      const extension = this.getFileExtension(doc.fileName);
+
+      // PDF浣跨敤鐩存帴璁块棶
+      if (extension === 'pdf') {
+        return doc.file_url;
+      }
+
+      // Office鏂囨。浣跨敤寰蒋棰勮鏈嶅姟
+      // if (['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(extension)) {
+      //   return `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(doc.file_url)}`;
+      // }
+
+      // 鍏朵粬绫诲瀷鐩存帴杩斿洖
+      return doc.file_url;
+    },
+    getPreviewUrl2(id) {
+      window.location.href = "/api/v1/knowledge/download?id=" + id
+      // window.location.href="http://192.168.1.176:8088/v1/knowledge/download?id="+id
+    },
+
+    // 鑾峰彇鏂囦欢鎵╁睍鍚�
+    getFileExtension(filename) {
+      const parts = filename.split('.');
+      return parts.length > 1 ? parts.pop().toLowerCase() : '';
+    },
+  },
+  watch: {
+    detailVisible(newVal) {
+      if (!newVal) {
+        this.selectedItemId = null; // 鍏抽棴寮圭獥鏃舵竻闄ら�変腑鐘舵��
+      }
+    },
+  },
+};
+</script>
+<style>
+/* 鍏ㄥ眬鐢熸晥锛屽彲瑕嗙洊 tooltip */
+.my-tooltip {
+  max-width: 540px !important;
+  color: #606266 !important;
+}
+</style>
+<style lang="scss" scoped>
+
+/* 鏂板鍥剧墖缃戞牸甯冨眬鏍峰紡 */
+.image-grid-container {
+  width: 100%;
+  overflow: hidden; /* 瓒呭嚭閮ㄥ垎闅愯棌 */
+}
+
+.image-grid {
+  display: flex;
+  flex-wrap: wrap;
+  margin: -10px; /* 璐熻竟璺濇姷娑堝寘瑁瑰厓绱犵殑杈硅窛 */
+  width: 100%;
+}
+
+.image-card-wrapper {
+  margin: 10px; /* 璁剧疆鍗$墖闂磋窛 */
+  // box-sizing: border-box;
+  // transition: width 0.3s ease; /* 娣诲姞骞虫粦杩囨浮鏁堟灉 */
+  min-width: 300px; /* 鍗$墖鏈�灏忓搴� */
+  flex-shrink: 0; /* 闃叉鍗$墖缂╁皬 */
+}
+
+
+.right-btn {
+  position: absolute;
+  right: 8%;
+  top: 50%;
+  transform: translateY(-50%);
+  /* 鍨傜洿灞呬腑 */
+}
+.right-btn2 {
+  position: absolute;
+  right: 10.5%;
+  top: 74.5%;
+  transform: translateY(-50%);
+  /* 鍨傜洿灞呬腑 */
+}
+
+.time-icon {
+  width: 16px;
+  height: 16px;
+  margin-right: 20px;
+  vertical-align: middle;
+}
+
+.time-icon2 {
+  width: 16px;
+  height: 16px;
+  margin-right: 0px;
+  vertical-align: middle;
+}
+
+/* 鍏抽棴鎸夐挳鏍峰紡 */
+.el-icon-close {
+  position: absolute;
+  top: 10px;
+  right: 5px;
+  padding: 0;
+  width: 24px;
+  height: 24px;
+  font-size: 14px;
+  color: #909399;
+  background: none;
+  border: none;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+
+/* 鏂板姘旀场鍐呭鏍峰紡 */
+.task-popover-content {
+  max-height: 100px;
+  overflow-y: auto;
+  padding: 20px 15px 15px 15px;
+  /* 澧炲姞椤堕儴绌洪棿缁欏叧闂寜閽� */
+  line-height: 1.5;
+  word-break: break-word;
+  white-space: pre-line;
+  border-radius: 10px;
+
+  /* 鑷畾涔夋粴鍔ㄦ潯鏍峰紡 */
+  &::-webkit-scrollbar {
+    width: 4px;
+    /* 缂╁皬婊氬姩鏉″搴� */
+    background-color: transparent;
+  }
+
+  &::-webkit-scrollbar-track {
+    background: transparent;
+    /* 闅愯棌杞ㄩ亾 */
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background-color: #c0c4cc;
+    /* 璁剧疆婊戝潡棰滆壊 */
+    border-radius: 2px;
+  }
+
+  /* 绉婚櫎婊氬姩鏉$澶� */
+  &::-webkit-scrollbar-button {
+    display: none;
+    /* 闅愯棌涓婁笅绠ご */
+  }
+}
+
+.resizable-dialog {
+  position: fixed !important;
+  margin: 0 !important;
+  padding-top: 0px;
+  min-width: 200px;
+  min-height: 300px;
+  overflow: auto;
+  top: 50% !important;
+  left: 50% !important;
+  transform: translate(-50%, -50%) !important;
+}
+
+.resize-handle {
+  position: absolute;
+  background: #409eff !important;
+  z-index: 9999;
+  opacity: 0;
+  transition: opacity 0.2s;
+}
+
+.resize-handle:hover {
+  opacity: 1;
+}
+
+/* 鍚勬柟鍚戞墜鏌勫畾浣� */
+.top {
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 4px;
+  cursor: ns-resize;
+}
+
+.bottom {
+  bottom: 0;
+  left: 0;
+  right: 0;
+  height: 4px;
+  cursor: ns-resize;
+}
+
+.left {
+  top: 0;
+  left: 0;
+  width: 4px;
+  bottom: 0;
+  cursor: ew-resize;
+}
+
+.right {
+  top: 0;
+  right: 0;
+  width: 4px;
+  bottom: 0;
+  cursor: ew-resize;
+}
+
+.top-left {
+  top: 0;
+  left: 0;
+  width: 10px;
+  height: 10px;
+  cursor: nwse-resize;
+}
+
+.top-right {
+  top: 0;
+  right: 0;
+  width: 10px;
+  height: 10px;
+  cursor: nesw-resize;
+}
+
+.bottom-left {
+  bottom: 0;
+  left: 0;
+  width: 10px;
+  height: 10px;
+  cursor: nesw-resize;
+}
+
+.bottom-right {
+  bottom: 0;
+  right: 0;
+  width: 10px;
+  height: 10px;
+  cursor: nwse-resize;
+}
+
+.el-dialog__body {
+  height: calc(100% - 54px);
+  overflow: auto;
+}
+
+.fold-icon {
+  width: 24px;
+  height: 24px;
+  cursor: pointer;
+  transition: transform 0.3s ease;
+  margin: 8px;
+
+  &:hover {
+    opacity: 0.8;
+    filter: drop-shadow(0 0 2px rgba(11, 113, 216, 0.5));
+  }
+
+  &.reverse {
+    transform: rotate(180deg);
+  }
+}
+
+/* ai-retrieval瀹瑰櫒鏍峰紡 */
+.ai-retrieval-container {
+  position: absolute;
+  // left: 5px;
+  width: 360px;
+  // height: 1000px;
+  z-index: 1000;
+  background: rgb(245, 244, 244);
+  // box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
+}
+
+/* 鏂板澶氬�兼樉绀烘牱寮� */
+.multi-value {
+  display: inline-block;
+  max-width: 540px;
+  //   white-space: nowrap;
+  overflow: hidden;
+  //   text-overflow: ellipsis;
+}
+
+.desc_class {
+  //   max-height: 380px;
+  overflow-y: auto;
+}
+
+.multi-value2 {
+  display: inline-block;
+  //   max-height: 380px;
+}
+
+.stats-header {
+  margin-bottom: 20px;
+
+  .ai-avatar {
+    display: flex;
+    align-items: flex-start; // 椤堕儴瀵归綈
+
+    .header-text {
+      margin-left: 10px;
+
+      .content-title {
+        text-align: left;
+        margin: 5px 0 10px;
+        color: #0e3eaa;
+      }
+
+      .stats-numbers {
+        font-size: 12px;
+        text-align: left;
+      }
+    }
+
+    .header-actions {
+      flex: 1;
+      text-align: right;
+      margin-top: 10px;
+    }
+  }
+}
+
+.results-container {
+  padding: 0 15px;
+  //   min-height: 600px;
+  overflow-x: hidden; /* 闅愯棌妯悜婊氬姩鏉� */
+  overflow-y: auto; /* 淇濈暀绾靛悜婊氬姩 */
+  /* 鏂板婊氬姩鏉� */
+  height: 900px;
+
+
+
+  .result-card {
+    border-radius: 8px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+    border: none;
+    position: relative; // 涓虹粷瀵瑰畾浣嶆彁渚涘熀鍑�
+    overflow: visible; // 闃叉鎸夐挳琚鍓�
+
+    .image-wrapper {
+      position: relative;
+      //   height: 200px;
+      overflow: visible;
+      border-radius: 6px 6px 0 0;
+
+      .result-image {
+        width: 100%;
+        // height: 130px;
+        object-fit: cover;
+        transition: transform 0.3s;
+      }
+
+      .image-overlay {
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        background: rgba(0, 0, 0, 0.6);
+        /* 鍗婇�忔槑榛戣壊鑳屾櫙 */
+        padding: 5px 10px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        z-index: 2;
+        /* 纭繚鍦ㄥ浘鐗囦笂鏂� */
+      }
+
+      .check-item {
+        color: white;
+        font-size: 12px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        max-width: 70%;
+      }
+
+      .level-tag {
+        z-index: 3;
+        /* 纭繚鍦ㄨ鐩栧眰涓婃柟 */
+        transform: scale(0.9);
+        margin: 2px;
+        color: #fa0505;
+        background-color: #f3e1e1;
+      }
+    }
+
+    .card-content {
+      padding: 15px;
+
+      .meta-info {
+        .time-info {
+          display: flex;
+          text-align: left;
+          align-items: center;
+          margin-bottom: 10px;
+          color: #909399;
+          width: 100%;
+          margin-bottom: 10px;
+
+          .el-icon-time {
+            color: #409eff !important;
+            margin-right: 20px;
+            font-size: 16px;
+          }
+
+          span {
+            font-size: 13px;
+            margin-right: 20px;
+          }
+
+          .el-icon-document {
+            color: #034914;
+          }
+
+          .detect-time {
+            flex-shrink: 0;
+            color: #909399;
+            font-size: 13px;
+          }
+        }
+
+        .device-info {
+          //   display: flex;
+          justify-content: space-between;
+          align-items: center;
+
+          .camera-info {
+            // display: flex;
+            position: relative;
+            text-align: left;
+            align-items: center;
+
+            i {
+              color: #409eff !important;
+              margin-right: 20px;
+              font-size: 16px;
+            }
+
+            span {
+              font-size: 14px;
+              color: #303133;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+.pagination-wrapper {
+  //   position: fixed;
+  right: 30px;
+  bottom: 30px;
+  background: #fff;
+  padding: 10px 20px;
+  border-radius: 4px;
+  //   box-shadow: 0 2px 12px rgba(0,0,0,0.1);
+}
+
+// 璋冩暣甯冨眬缁撴瀯
+.statistics-container {
+  display: flex;
+  height: 98vh; // 鏂板
+
+  .left-sidebar {
+    width: 320px;
+    transition: all 0.3s ease;
+    left: 0;
+    // height: 100vh;
+    z-index: 1000;
+    background: #fff;
+    box-shadow: 1px 0 10px rgba(0, 0, 0, 0.1);
+
+    padding: 10px;
+    border-right: 1px solid #ebeef5;
+    position: relative;
+    padding-bottom: 40px;
+    /* 涓哄簳閮ㄦ寜閽暀鍑虹┖闂� */
+    /* 涓虹粷瀵瑰畾浣嶅垱寤哄弬鐓� */
+
+    .session-buttons {
+      // position: absolute;
+      bottom: 20px;
+      left: 20px;
+      right: 20px;
+      display: flex;
+      gap: 0;
+
+      .el-button {
+        height: 50px;
+        border-radius: 5px;
+        transition: all 0.3s ease;
+        background-color: #e1ebff !important;
+        color: #2482ff;
+        border: 1px solid #e1ebff !important;
+        font-size: 16px !important;
+        padding: 0 12px;
+      }
+
+      ::v-deep .el-button {
+        background-color: #e1ebff !important;
+      }
+    }
+
+    &.collapsed {
+      width: 40px;
+
+      .ai-avatar {
+        flex-direction: column;
+        align-items: center;
+        padding: 10px 0;
+
+        .avatar-img {
+          margin: 0;
+          width: 51px;
+          height: 35px;
+        }
+      }
+
+      .header-actions i {
+        transform: rotate(180deg);
+        margin-top: 10px;
+      }
+    }
+
+    .header-actions {
+      i {
+        transition: all 0.3s ease;
+        cursor: pointer;
+        font-size: 20px;
+        color: #666;
+
+        &:hover {
+          color: #0b71d8;
+        }
+
+        &.reverse {
+          transform: rotate(180deg);
+        }
+      }
+    }
+
+    .right-content {
+      transition: margin 0.3s ease;
+      padding: 20px;
+      min-height: 100vh;
+      background: #f5f6fa;
+    }
+
+    .ai-retrieval-container {
+      width: 100%;
+      height: calc(100% - 150px);
+      /* 鏍规嵁瀹為檯甯冨眬璋冩暣楂樺害 */
+      position: relative;
+      box-shadow: none;
+      background: #fff;
+    }
+
+    .el-checkbox {
+      margin-left: 15px;
+      display: block;
+      text-align: left;
+    }
+
+    .el-form-item__content {
+      margin-left: 0 !important;
+    }
+  }
+
+  .right-content {
+    flex: 1;
+    margin-left: 20px;
+    position: relative;
+    box-shadow: 1px 0 10px rgba(0, 0, 0, 0.1);
+    padding: 20px;
+    padding-top: 0px;
+    border-left: 1px solid #ebeef5;
+
+    .right-header {
+      display: flex;
+      margin-bottom: 20px;
+      border-bottom: 1px solid #ebeef5;
+      padding-bottom: 10px;
+      justify-content: space-between;
+      height: 70px;
+      /* 鏂板锛氬乏鍙充袱绔榻� */
+
+      .content-title{
+        text-align: left;
+        margin: 15px 0 0 0;
+      }
+      .header-actions-right {
+        margin-top: 20px;
+
+        .action-btn {
+          height: 40px;
+          margin-bottom: 0px;
+          padding: 10px 20px;
+          border-radius: 6px;
+          letter-spacing: 0.5px;
+        }
+      }
+    }
+  }
+}
+
+.form-actions {
+  margin-top: 50px;
+  display: flex;
+  gap: 10px; // 鎸夐挳闂磋窛
+
+  .full-width-btn {
+    flex: 1; // 绛夊垎鍓╀綑绌洪棿
+    margin-left: 0 !important;
+  }
+
+  // 娓呴櫎Element榛樿杈硅窛
+  ::v-deep .el-button {
+    margin-left: 0;
+    margin-right: 0;
+  }
+}
+
+// 璇︽儏寮圭獥鏍峰紡
+.detail-dialog {
+  .el-dialog__header {
+    border-bottom: 1px solid #ebeef5;
+  }
+
+  .media-switch {
+    margin: -50px 0 15px;
+    text-align: left;
+
+    .media-tab {
+      &.is-active {
+        background: #409eff !important;
+        border-color: #409eff !important;
+        color: white;
+      }
+    }
+  }
+
+  .media-container {
+    height: 350px;
+    border: 1px solid #ebeef5;
+    border-radius: 4px;
+    margin-bottom: 20px;
+    position: relative;
+    overflow: hidden; // 娣诲姞婧㈠嚭闅愯棌
+
+    .main-image {
+      height: 100%;
+      padding: 0px;
+
+      .detail-img {
+        width: 100%;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+
+    .video-section {
+      height: 100%;
+      width: 100%;
+
+      .video-placeholder {
+        width: 100%;
+        height: 100%;
+        position: relative;
+
+        video {
+          max-width: 100%;
+          max-height: 100%;
+          display: block;
+          margin: 0 auto;
+        }
+      }
+    }
+  }
+
+  .info-container {
+    height: 400px;
+    // overflow-y: auto;
+
+    ::v-deep .el-descriptions__body {
+      background: white;
+    }
+
+    .info-item {
+      padding: 12px 10px;
+
+      &>.el-descriptions-item__label {
+        color: #606266;
+        width: 90px;
+      }
+    }
+
+    .red-text {
+      color: #f56c6c !important;
+    }
+
+    .blue-text {
+      color: #409eff !important;
+    }
+
+    .doc-link {
+      padding-left: 10px;
+      text-decoration: none;
+      color: #1b50e4;
+      // display: inline-block;
+      // padding: 5px 8px;
+      // border-radius: 4px;
+      // transition: all 0.3s;
+      // color: #165DFF;
+
+      &:hover {
+        cursor: pointer;
+      }
+    }
+
+    ::v-deep .el-descriptions-item__label {
+      color: black !important;
+      font-weight: 600 !important;
+    }
+  }
+}
+
+/* 鍙充晶瀵归綈鏍峰紡 */
+.detail-dialog {
+  position: fixed !important;
+  top: 50% !important;
+  left: auto !important;
+  right: 20px !important;
+  transform: translateY(-50%) !important;
+  width: 660px !important;
+  margin: 0 !important;
+  z-index: 2000 !important;
+}
+
+::v-deep .el-dialog {
+
+  // margin-right: 0px;
+  .el-divider--horizontal {
+    margin: 12px 0;
+  }
+}
+
+/* 琛ㄦ牸琛ㄥご鏍峰紡 */
+.header-gradient {
+  background: radial-gradient(circle at 20% 30%, #0e5397, #2482FF);
+  -webkit-background-clip: text;
+  background-clip: text;
+  color: transparent;
+  font-weight: bold;
+  font-size: 35px;
+}
+
+.header-gradient2 {
+  font-size: 18px;
+  background: radial-gradient(circle at 20% 30%, #165DFF, #01040a);
+  -webkit-background-clip: text;
+  background-clip: text;
+}
+
+/* 鏂板鍔犺浇鐘舵�佹牱寮� */
+.loading-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 300px;
+  color: #606266;
+  font-size: 16px;
+
+  .el-icon {
+    margin-bottom: 15px;
+    animation: rotating 1.5s linear infinite;
+
+    @keyframes rotating {
+      0% {
+        transform: rotate(0deg);
+      }
+
+      100% {
+        transform: rotate(360deg);
+      }
+    }
+  }
+}
+
+.ellipsis {
+  display: inline-block;
+  /* 鎴� block */
+  // max-width: 100%;       /* 鏍规嵁瀹為檯瀹瑰櫒瀹藉害璋冩暣 */
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  /* 鍏抽敭锛氱姝㈡崲琛� */
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/searchNew/components/cameraVideo.vue b/src/pages/searchNew/components/cameraVideo.vue
new file mode 100644
index 0000000..eec1bb7
--- /dev/null
+++ b/src/pages/searchNew/components/cameraVideo.vue
@@ -0,0 +1,232 @@
+<template>
+  <div class="container">
+    <!-- 甯冨眬鎺у埗鍙婃挱鏀惧湴鍧�閫夋嫨 -->
+    <div class="layout-controls">
+      <el-select
+        v-model="selectedUrl"
+        placeholder="閫夋嫨鎾斁鍦板潃"
+        class="left-control"
+        style="width: 200px; margin-right: 20px"
+        @change="handleUrlChange"
+        :disabled="activeIndex === -1"
+      >
+        <el-option
+          v-for="item in playbackOptions"
+          :key="item.videoId"
+          :label="item.deviceName"
+          :value="item.videoId"
+        />
+      </el-select>
+      <el-button-group class="right-control">
+        <el-button 
+          :type="gridLayout === 1 ? 'primary' : ''" 
+          @click="changeLayout(1)"
+        >
+          鍗曟牸
+        </el-button>
+        <el-button 
+          :type="gridLayout === 4 ? 'primary' : ''" 
+          @click="changeLayout(4)"
+        >
+          鍥涙牸
+        </el-button>
+        <el-button 
+          :type="gridLayout === 9 ? 'primary' : ''" 
+          @click="changeLayout(9)"
+        >
+          涔濇牸
+        </el-button>
+      </el-button-group>
+    </div>
+
+    <!-- 瑙嗛缃戞牸甯冨眬 -->
+    <el-row :gutter="5">
+      <el-col 
+        v-for="(item, index) in showVideos" 
+        :key="index"
+        :span="colSpan"
+        class="video-col"
+        :class="{ active: activeIndex === index }"
+      >
+        <div class="video-container"
+        @click="handleGridClick(index)">
+          <!-- 绾粦鑳屾櫙灏侀潰 -->
+          <div 
+            class="video-cover" 
+            v-show="!item.playing"
+            style="pointer-events: none"
+          />
+          
+          <!-- 瑙嗛鎾斁鍣� -->
+          <iframe
+            v-show="item.playing"
+            class="video-iframe"
+            :src="item.url"
+            frameborder="0"
+            allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
+            allowfullscreen
+            style="pointer-events: none"
+          ></iframe>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import camera from "@/api/SurveyView"
+export default {
+  name: 'cameraVideo',
+  data() {
+    return {
+      iframeUrl:'',
+      gridLayout: 1,
+      activeIndex: -1,
+      selectedUrl: '',
+      playbackOptions: [
+        { 
+          label: '鎽勫儚澶�1', 
+          value: 'rtsp://Admin:1234@192.168.1.209/h264' 
+        },
+        {
+          label: '鎽勫儚澶�2',
+          value: 'http://example.com/another-video-source'
+        }
+      ],
+      allVideos: Array(9).fill(null).map((_, i) => ({
+        title: `瑙嗛 ${i + 1}`,
+        url: '',
+        playing: false
+      }))
+    }
+  },
+  computed: {
+    showVideos() {
+      return this.allVideos.slice(0, this.gridLayout)
+    },
+    colSpan() {
+      return 24 / Math.sqrt(this.gridLayout)
+    }
+  },
+  mounted() {
+        this.fetchSelect();
+    this.fetchCameraInfo()
+},
+  methods: {
+    async fetchCameraInfo() {
+    const response = await fetch('/config.json');
+    if (!response.ok) throw new Error(`璇锋眰澶辫触: ${response.status}`);
+        const responseData = await response.json();
+    this.iframeUrl = responseData.iframeUrl;
+    console.info(this.iframeUrl)
+  },
+    async fetchSelect(){
+        const cameras = await camera.getCameras();//瑙嗛鐐逛綅
+        this.playbackOptions = cameras.data
+    },
+    changeLayout(num) {
+      this.gridLayout = num
+      this.activeIndex = -1
+      this.resetAllVideos()
+    },
+    handleGridClick(index) {
+      this.activeIndex = index
+      console.info('鐐瑰嚮浜嬩欢鐢熸晥')
+    },
+    handleUrlChange(val) {
+        console.info(process.env.NODE_ENV)
+      if (this.activeIndex === -1) return
+    //   console.info('鐐瑰嚮閫変腑鐨勬暟鎹細'+this.playbackOptions.find(item => item.videoId === val).rtspAddress)
+      const currentVideo = this.allVideos[this.activeIndex]
+      currentVideo.url = this.iframeUrl+`/view/cameraPlayer/index.html?rtspUrl=${encodeURIComponent(this.playbackOptions.find(item => item.videoId === val).rtspAddress)}`
+      currentVideo.playing = true
+      
+        console.info("鍦板潃锛�"+currentVideo.url)
+    },
+    resetAllVideos() {
+      this.allVideos.forEach((video, index) => {
+        if (index >= this.gridLayout) {
+          video.playing = false
+          video.url = ''
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 绠�鍖栧悗鐨勬牱寮� */
+.container {
+  padding-top: 80px;
+  position: relative;
+}
+
+.layout-controls {
+  position: absolute;
+  left: 60px;
+  right: 60px; /* 鏂板鍙充晶瀵归綈 */
+  top: 20px;
+  z-index: 1000;
+  display: flex;
+  justify-content: space-between; /* 鍏抽敭灞炴�� */
+  align-items: center;
+}
+/* 绉婚櫎鍘熸湁鐨� margin-right */
+.el-select {
+  width: 200px;
+}
+/* 鍙�夛細闃叉鎸夐挳缁勬崲琛� */
+.el-button-group {
+  flex-shrink: 0;
+}
+
+.video-col {
+  position: relative;  
+  margin-bottom: 5px;
+  transition: all 0.3s;
+  min-height: 100px;  
+}
+
+.video-col.active::after {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  border: 3px solid #409EFF;
+  pointer-events: none;
+  z-index: 2;
+}
+
+.video-container {
+  position: relative;
+  width: 100%;
+  height: 0;
+  padding-top: 56.25%;
+  cursor: pointer;
+  background-color: #000;
+  overflow: hidden;
+}
+
+.video-cover {
+    pointer-events: none; /* 鍏佽浜嬩欢绌块�� */
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #000; /* 绾粦鑳屾櫙 */
+}
+
+.video-iframe {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: #000;
+  pointer-events: none;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/searchNew/index/App.vue b/src/pages/searchNew/index/App.vue
new file mode 100644
index 0000000..508ff07
--- /dev/null
+++ b/src/pages/searchNew/index/App.vue
@@ -0,0 +1,131 @@
+<template>
+  <div class="column">
+    <div class="column-right">
+       <survey-view ref="cardlist"/>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getUrlKey } from "@/api/utils";
+import surveyView from "../components/SurveyView";
+
+export default {
+  name: "VideoManage",
+  components: {
+    surveyView
+  },
+  computed: {
+    app() {
+      return getUrlKey("dataStack") !== null ? "DataStack" : "Camera";
+    },
+  },
+  data() {
+    return {
+      leftWith: 0,
+      screenHeight: 0,
+    };
+  },
+  mounted() {
+    this.screenHeight = document.documentElement.clientHeight;
+    window.onresize = () => {
+      return (() => {
+        this.screenHeight = document.documentElement.clientHeight;
+      })();
+    };
+
+    this.leftWith = this.$refs["left"].offsetWidth;
+    this.TreeDataPool.readonly = false;
+    this.TreeDataPool.gbReadonly = false;
+    this.DataStackPool.readonly = false;
+  },
+  methods: {
+    changeTrainId(trainId){
+      if (this.$refs.cardlist) {
+        this.$refs.cardlist.changeTrainId(trainId);
+      }
+    }
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.column {
+  overflow: hidden;
+  //min-width: 1399px;
+  //min-width: 1920px;
+  height: 100%;
+}
+.column-right {
+  padding: 5px;
+  height: 100vh;
+  // background-color: #eee;
+  box-sizing: border-box;
+  overflow: scroll;
+}
+.heigher-index {
+  position: absolute;
+  top: 0;
+  z-index: 10;
+  width: 100%;
+  height: 100%;
+}
+.resize-save {
+  position: absolute;
+  top: 0;
+  right: 5px;
+  bottom: 0;
+  left: 0;
+  padding: 16px;
+  padding-top: 8px;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+.resize-bar {
+  width: 338px;
+  height: inherit;
+  resize: horizontal;
+  cursor: ew-resize;
+  opacity: 0;
+  overflow: scroll;
+  max-width: 500px; //璁惧畾鏈�澶ф媺浼搁暱搴�
+  min-width: 33px; //璁惧畾鏈�灏忓搴�
+}
+/* 鎷栨嫿绾� */
+.resize-line {
+  position: absolute;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  border-right: 2px solid #efefef;
+  border-left: 1px solid #e0e0e0;
+  pointer-events: none;
+}
+.resize-bar:hover ~ .resize-line,
+.resize-bar:active ~ .resize-line {
+  border-left: 1px dashed skyblue;
+}
+.resize-bar::-webkit-scrollbar {
+  width: 200px;
+  height: inherit;
+}
+
+/* Firefox鍙湁涓嬮潰涓�灏忓潡鍖哄煙鍙互鎷変几 */
+@supports (-moz-user-select: none) {
+  .resize-bar:hover ~ .resize-line,
+  .resize-bar:active ~ .resize-line {
+    border-left: 1px solid #bbb;
+  }
+  .resize-bar:hover ~ .resize-line::after,
+  .resize-bar:active ~ .resize-line::after {
+    content: "";
+    position: absolute;
+    width: 16px;
+    height: 16px;
+    bottom: 0;
+    right: -8px;
+    // background: url(./resize.svg);
+    background-size: 100% 100%;
+  }
+}
+</style>
diff --git a/src/pages/searchNew/index/main.ts b/src/pages/searchNew/index/main.ts
new file mode 100644
index 0000000..aa3df71
--- /dev/null
+++ b/src/pages/searchNew/index/main.ts
@@ -0,0 +1,30 @@
+import Vue from "vue";
+import App from './App.vue';
+
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
+// import "@/assets/css/element-variables.scss";
+
+import ToggleButton from 'vue-js-toggle-button';
+import VueAwesomeSwiper from "vue-awesome-swiper";
+import "swiper/dist/css/swiper.css";
+import * as VueWindow from "@hscmap/vue-window";
+import moment from 'moment';
+import Mixin from "./mixins";
+
+Vue.prototype.$moment = moment;
+Vue.use(ElementUI);
+Vue.use(ToggleButton);
+Vue.use(VueAwesomeSwiper as any);
+Vue.use(VueWindow);
+Vue.filter('moment', function (value, formatString) {
+  formatString = formatString || 'YYYY-MM-DD HH:mm:ss';
+  return moment(value).format(formatString);
+
+});
+Vue.mixin(Mixin);
+
+new Vue({
+  el: '#app',
+  render: h => h(App)
+})
diff --git a/src/pages/searchNew/index/mixins.ts b/src/pages/searchNew/index/mixins.ts
new file mode 100644
index 0000000..52fb92b
--- /dev/null
+++ b/src/pages/searchNew/index/mixins.ts
@@ -0,0 +1,25 @@
+import TreeDataPool from "@/Pool/TreeData";
+import DataStackPool from "@/Pool/dataStack"
+import DataPool from "@/Pool/PollData"
+import VideoManageData from "@/Pool/VideoManageData";
+import TaskMange from '@/Pool/TaskMange'
+
+/* eslint-disable */
+const onlyTreeDataPool = new TreeDataPool
+const onlyDataStack = new DataStackPool
+const onlyDataPool = new DataPool
+const onlyVideoManageData = new VideoManageData
+const onlyTaskMange = new TaskMange
+
+const mixin = {
+  data() {
+    return {
+      TreeDataPool: onlyTreeDataPool,
+      DataStackPool: onlyDataStack,
+      VideoManageData: onlyVideoManageData,
+      TaskMange: onlyTaskMange,
+      PollData: onlyDataPool
+    };
+  },
+};
+export default mixin;
\ No newline at end of file

--
Gitblit v1.8.0