Browse Source

模拟流式输出、输出自动定位到底部、自定义加载中效果

songxy 1 month ago
parent
commit
734bfba46d

+ 1 - 1
web_ui/config/index.js

@@ -13,7 +13,7 @@ module.exports = {
     proxyTable: {
       '/landsiteai': {
         // target: 'http://lq.lianqiai.cn:23001',
-        target: 'https://ai.zrzyt.zj.gov.cn/landsiteai/land_analysis',
+        target: 'https://ai.zrzyt.zj.gov.cn/landsiteai/',
         // target: 'http://localhost:8511',
         changeOrigin: true,
         pathRewrite: {

+ 38 - 0
web_ui/src/components/ALoading.vue

@@ -0,0 +1,38 @@
+<template>
+  <div class="dots">
+    <div class="wave-dot dot1"></div>
+    <div class="wave-dot dot2"></div>
+    <div class="wave-dot dot3"></div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "ALoading"
+};
+</script>
+
+<style lang='scss' scoped>
+.dots {
+  width: 100%;
+  text-align: center;
+  padding: 10px 0px;
+  opacity: 0.6;
+  .wave-dot {
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    display: inline-block;
+    animation: wave 1.2s ease-in-out infinite;
+    margin: 0 3px;
+  }
+  .dot1 { animation-delay: 0s; background: #2879e7 }
+  .dot2 { animation-delay: 0.2s; background: #2879e7 }
+  .dot3 { animation-delay: 0.4s; background: #2879e7 }
+
+  @keyframes wave {
+    0%, 100% { transform: translateY(0) }
+    50% { transform: translateY(-12px) }
+  }
+}
+</style>

+ 23 - 7
web_ui/src/views/industrial-land/AiIndustriaLandDetail.vue

@@ -158,7 +158,7 @@
           class="left-panel"
           v-if="showQuery"
         >
-          <div class="left-panel-content">
+          <div class="left-panel-content" ref="container">
             <span class="back_icon" @click="onBackHandle"></span>
             <div class="title" @click="resetAnswer()">
               {{ inputText }}
@@ -275,7 +275,7 @@
                 </div>
               </div>
             </template>
-            <Spin size="large" class="span" fix v-if="loading"></Spin>
+            <a-loading v-if="loading"></a-loading>
           </div>
           <div class="m-textarea-panel">
             <textarea
@@ -383,6 +383,7 @@ import wkt from "wellknown";
 import VueMarkdownIt from "vue-markdown-it";
 import landMethods from "@/api/land";
 import AIBtn from "@/components/AIBtn.vue";
+import ALoading from "@/components/ALoading.vue";
 
 const _timers = []
 export default {
@@ -396,6 +397,7 @@ export default {
     FeekBack,
     VueMarkdownIt,
     AIBtn,
+    ALoading,
   },
   data() {
     return {
@@ -1810,8 +1812,6 @@ export default {
           }),
           signal: this.ctrlAbout.signal
         });
-        console.log("result------------------")
-        console.log(response)
         await this.handleStreamResponse(response);
         const timer = setTimeout(async () => {
           _timers.push(timer)
@@ -1831,7 +1831,6 @@ export default {
         }
       }
     }, 500),
-
     async handleStreamResponse(response) {
       const reader = response.body.getReader();
       const decoder = new TextDecoder();
@@ -1846,10 +1845,9 @@ export default {
 
         const chunk = decoder.decode(value);
         const lines = chunk.split('\n').filter(line => line.trim());
-        console.log("lines--------------------")
-        console.log(lines)
         for (const line of lines) {
           try {
+            await this.sleep(30)
             const data = JSON.parse(line);
             let contentToAdd = '';
             switch (data.type) {
@@ -1904,6 +1902,11 @@ export default {
                 this.btnSendDisabled = false;
                 break;
             }
+            let timer = setTimeout(() => {
+              this.scrollToBottom()
+              clearTimeout(timer)
+              timer = null
+            }, 200)
           } catch (e) {
             console.error('Error parsing stream data:', e);
           }
@@ -1911,6 +1914,19 @@ export default {
       }
     },
 
+    sleep (time) {
+      return new Promise((resolve, reject) => {
+        let timer = setTimeout(() => {
+          resolve(true)
+          clearTimeout(timer)
+          timer = null;
+        }, time)
+      })
+    },
+    scrollToBottom () {
+      const container = this.$refs['container']
+      container.scrollTop = container.scrollHeight;
+    },
     /**
      * 添加多轮对话效果
      * @param question