Browse Source

修改bug添加ai相关链接

yangg 9 months ago
parent
commit
f3222c427a
35 changed files with 283 additions and 46 deletions
  1. 1 1
      .env.development
  2. 0 0
      dist/index.html
  3. 0 0
      dist/static/css/app.318934ec.css
  4. 0 0
      dist/static/css/chunk-051f6e78.ce959b8e.css
  5. 0 0
      dist/static/css/chunk-059ccbc0.d6fdc4e5.css
  6. 0 0
      dist/static/css/chunk-1b8f06f0.68741a84.css
  7. 0 0
      dist/static/css/chunk-23942cdd.8e7554c0.css
  8. 0 0
      dist/static/css/chunk-48e21f21.d6fdc4e5.css
  9. 0 0
      dist/static/js/app.50077183.js
  10. 0 0
      dist/static/js/app.c432131e.js
  11. 0 0
      dist/static/js/chunk-051f6e78.529b18e6.js
  12. 0 0
      dist/static/js/chunk-059ccbc0.7e7c15fb.js
  13. 0 0
      dist/static/js/chunk-1b8f06f0.3a0ee7a0.js
  14. 0 0
      dist/static/js/chunk-23942cdd.b2ff9aa9.js
  15. 1 0
      dist/static/js/chunk-2d0d3705.76834340.js
  16. 0 0
      dist/static/js/chunk-3d9675b3.510a3609.js
  17. 0 0
      dist/static/js/chunk-3d9675b3.be56236c.js
  18. 0 0
      dist/static/js/chunk-48e21f21.37c5febe.js
  19. 0 0
      dist/static/js/chunk-6155c71d.2d5026f1.js
  20. 0 0
      dist/static/js/chunk-6155c71d.bafee5e6.js
  21. 0 0
      dist/static/js/chunk-78bb5867.5e07752d.js
  22. 0 0
      dist/static/js/chunk-8e03009a.e87ca5f2.js
  23. 0 0
      dist/static/js/chunk-9962029e.3b420a14.js
  24. 0 0
      dist/static/js/chunk-b6791022.ffe50ca3.js
  25. 12 1
      src/api/api.js
  26. 17 0
      src/api/document.js
  27. 16 1
      src/components/webAi/css/ChatBox.css
  28. 1 0
      src/components/webAi/index.vue
  29. 118 14
      src/components/webAi/js/ChatBox.js
  30. 7 0
      src/router/index.js
  31. 4 3
      src/views/document/com/menus.vue
  32. 2 2
      src/views/document/components/dataList.vue
  33. 54 19
      src/views/document/create.vue
  34. 5 5
      src/views/document/temList/components/dataList.vue
  35. 45 0
      src/views/login/Preview.vue

+ 1 - 1
.env.development

@@ -2,5 +2,5 @@
 ENV = 'development'
 port = 8080
 # base api
-VUE_APP_BASE_API = 'http://192.168.1.199:8084'
+VUE_APP_BASE_API = 'http://58.246.234.210:8084'
 #192.168.1.199

File diff suppressed because it is too large
+ 0 - 0
dist/index.html


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.318934ec.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-051f6e78.ce959b8e.css


+ 0 - 0
dist/static/css/chunk-78bb5867.d6fdc4e5.css → dist/static/css/chunk-059ccbc0.d6fdc4e5.css


+ 0 - 0
dist/static/css/chunk-8e03009a.68741a84.css → dist/static/css/chunk-1b8f06f0.68741a84.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-23942cdd.8e7554c0.css


+ 0 - 0
dist/static/css/chunk-9962029e.d6fdc4e5.css → dist/static/css/chunk-48e21f21.d6fdc4e5.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.50077183.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.c432131e.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-051f6e78.529b18e6.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-059ccbc0.7e7c15fb.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-1b8f06f0.3a0ee7a0.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-23942cdd.b2ff9aa9.js


+ 1 - 0
dist/static/js/chunk-2d0d3705.76834340.js

@@ -0,0 +1 @@
+(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0d3705"],{"5d88":function(e,t,o){"use strict";o.r(t);var l=function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("div",[o("file-preview",{attrs:{"file-url":e.url,"file-type":"docx"}})],1)},n=[],r=o("3be9"),u={props:{},components:{FilePreview:r["default"]},data:function(){return{url:""}},computed:{},watch:{},mounted:function(){this.url=localStorage.getItem("href"),console.log(localStorage.getItem("href"))},methods:{}},c=u,a=o("2877"),i=Object(a["a"])(c,l,n,!1,null,"247a9e55",null);t["default"]=i.exports}}]);

File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-3d9675b3.510a3609.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-3d9675b3.be56236c.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-48e21f21.37c5febe.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-6155c71d.2d5026f1.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-6155c71d.bafee5e6.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-78bb5867.5e07752d.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-8e03009a.e87ca5f2.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-9962029e.3b420a14.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-b6791022.ffe50ca3.js


+ 12 - 1
src/api/api.js

@@ -74,4 +74,15 @@ export function pcInnerAi(data) {
     method: 'post',
     data
   })
-}
+}
+
+/* 获取文件名 milvus/getMinioURl*/
+
+export function getMinioURl(data) {
+  return request({
+    url: '/milvus/getMinioURl',
+    method: 'post',
+    data
+  })
+}
+

+ 17 - 0
src/api/document.js

@@ -133,5 +133,22 @@ export function deleteDocumentCategory(data) {
   })
 }
 
+/* 获取模版列表 */
 
+export function searchList(data) {
+  return request({
+    url: '/template/searchList',
+    method: 'post',
+    data
+  })
+}
+
+/* 获取文档列表 */
 
+export function searchlistDoc(data) {
+  return request({
+    url: '/document/searchlistDoc',
+    method: 'post',
+    data
+  })
+}

+ 16 - 1
src/components/webAi/css/ChatBox.css

@@ -118,7 +118,7 @@
     margin: 0;
     white-space: normal; /* 确保文本会换行 */
     word-wrap: break-word; /* 长单词或 URL 会被断开以适应容器宽度 */
-
+    overflow: auto;
 }
 .message-text ::v-deep p {
     font-size: 14px !important;
@@ -128,6 +128,21 @@
     line-height: 22px;
     font-weight: inherit;
   }
+  .message-text ::v-deep ol{
+    padding-bottom: 10px ;
+
+  }
+  .message-text ::v-deep .source-section h3 {
+    margin: 20px 0 3px;
+    color: #333;
+    font-size: 1.1em;
+  }
+  .message-text ::v-deep ol li{
+    padding-top:3px ;
+  }
+  .message-text ::v-deep ol li a{
+    color: #1296db;
+  }
 .input-container {
     position: absolute; /* 改为绝对定位 */
     bottom: 10px; /* 距离底部的距离 */

+ 1 - 0
src/components/webAi/index.vue

@@ -28,6 +28,7 @@
             <div
               class="message-text"
               v-html="renderMarkdown(message.message)"
+               @click="handleLinkClick"
             ></div>
           </div>
         </li>

+ 118 - 14
src/components/webAi/js/ChatBox.js

@@ -1,6 +1,7 @@
 import LoginModal from "@/components/LoginModal";
 import MarkdownIt from "markdown-it";
-import { pcInnerAi } from "@/api/api";
+import { pcInnerAi,getMinioURl } from "@/api/api";
+import axios from 'axios';
 const md = new MarkdownIt();
 
 export default {
@@ -28,6 +29,8 @@ export default {
       tweaks:{},
       showLoginModal: false,
       isLoggedIn: false, // 添加登录状态标志
+      idArray: [],
+      minioUrls: [], // 新增:用于存储 Minio URL
     };
   },
   created() {
@@ -51,6 +54,17 @@ export default {
     }
   },
   methods: {
+    handleLinkClick(event) {
+      if (event.target.tagName === 'A') {
+        localStorage.setItem('href',event.target.href)
+        let _this = this;
+        let a = document.createElement("a");
+        a.href = "#/preview"; // 使用 hash
+        a.target = "_blank";
+        a.click();
+      }
+    },
+
     handleLoginSuccess() {
       this.showLoginModal = false;
       this.isLoggedIn = true;
@@ -164,14 +178,14 @@ export default {
               tweaks:this.tweaks /* {
                 "ChatInput-U82Vu": {},
                 "Prompt-b8Z1E": {},
-                "ChatOutput-Yf4KV": {},
                 "OllamaModel-z9SVx": {},
                 "Milvus-l0vvr": {},
                 "OllamaEmbeddings-4Ml5q": {},
-                "APIRequest-lH4wg": {},
                 "ParseData-LM8yW": {},
                 "ParseData-jVoZg": {},
-                "Memory-3IxGM": {}
+                "APIRequest-OnZHl": {},
+                "ParseData-fH1vY": {},
+                "ChatOutput-ybzb9": {}
               } */,
             }),
           });
@@ -186,7 +200,22 @@ export default {
           const result = await response.json();
          // 等待思考动画完成
          await thinkingPromise;
-          
+          // 提取 additional_input 数据
+        const additionalInput = result.outputs[0].outputs[0].results.message.data.additional_input;
+        
+        // 处理字符串,提取 ID 值
+        this.idArray = additionalInput.split('\n')  // 按换行符分割
+          .map(line => line.trim())  // 去除每行首尾空白
+          .filter(line => line.startsWith('ID:'))  // 只保留以 'ID:' 开头的行
+          .map(line => line.substring(3).trim());  // 提取 'ID:' 后面的内容并去除空白
+
+        // 创建符合要求格式的对象
+        const idObject = { ids: this.idArray };
+
+        console.log("ID Object:", idObject);
+
+        // 调用方法来获取 Minio URL,传递新的 idObject
+        await this.getMinioUrls(idObject);
          this.handleResponse(result, botMessage);
        } catch (error) {
          console.error("Error sending message:", error);
@@ -196,6 +225,37 @@ export default {
        }
       }
     },
+    async getMinioUrls(idObject) {
+      this.minioUrls = []; // 清空之前的 URL
+
+      try {
+        console.log("Sending to backend:", JSON.stringify(idObject));
+
+        const response = await axios.post('http://58.246.234.210:8084/milvus/getMinioURl', idObject, {
+          headers: {
+            'Content-Type': 'application/json'
+          }
+        });
+
+        if (response.status === 200 && response.data) {
+          this.minioUrls = response.data.data; // 假设返回的是 URL 数组
+          console.log("Received Minio URLs:", this.minioUrls);
+        } else {
+          console.error('Failed to get Minio URLs');
+        }
+      } catch (error) {
+        console.error('Error fetching Minio URLs:', error);
+        if (error.response) {
+          console.error('Response data:', error.response.data);
+          console.error('Response status:', error.response.status);
+          console.error('Response headers:', error.response.headers);
+        } else if (error.request) {
+          console.error('No response received:', error.request);
+        } else {
+          console.error('Error message:', error.message);
+        }
+      }
+    },
     async simulateThinking(message) {
       this.isThinking = true;
       const thinkingTime = Math.random() * 1000 + 500; // 思考时间为 0.5-1.5 秒
@@ -222,22 +282,35 @@ export default {
     async handleResponse(value, existingMessage) {
       const data = value.outputs[0].outputs[0].results.message;
       
-      // 更新现有的消息对象
       existingMessage.messageType = data.text_key;
       existingMessage.time = data.timestamp;
-      
-      // 移除思考动画
       existingMessage.message = '';
       
-      // 开始打字效果
-      await this.typeMessage(existingMessage, data.text);
+      let mainText = data.text;
+      let sourceText = '';
+
+      if (this.$route.name !== 'ai' && this.minioUrls && this.minioUrls.length > 0) {
+        sourceText = "\n\n<div class='source-section'><h3>相关资料来源:</h3><ol>";
+        this.minioUrls.forEach((url, index) => {
+          sourceText += `<li><a href="${url.url}" target="_blank" class="source-link">${url.object_name}</a></li>`;
+        });
+        sourceText += "</ol></div>";
+      }
+
+      // 先进行主要内容的打字效果
+      await this.typeMessage(existingMessage, mainText);
+
+      // 直接添加资料来源部分
+      if (sourceText) {
+        existingMessage.message += sourceText;
+        existingMessage.html = this.renderMarkdown(existingMessage.message);
+      }
     },
-  
+
     typeMessage(message, fullText) {
       return new Promise(resolve => {
-        const delay = 30; // 每个字符之间的延迟时间(毫秒)
+        const delay = 30;
         let i = 0;
-        
         const typeChar = () => {
           if (i < fullText.length) {
             message.message += fullText[i];
@@ -245,6 +318,7 @@ export default {
             setTimeout(typeChar, delay);
           } else {
             message.done = true;
+            message.html = this.renderMarkdown(message.message);
             resolve();
           }
         };
@@ -253,7 +327,37 @@ export default {
       });
     },
     renderMarkdown(rawMarkdown) {
-      return md.render(rawMarkdown);
+      const md = new MarkdownIt({
+        html: true,
+        breaks: true,
+        linkify: true
+      });
+
+      // 自定义链接渲染规则
+      md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
+        const token = tokens[idx];
+        const hrefIndex = token.attrIndex('href');
+        const href = token.attrs[hrefIndex][1];
+        return `<span class="custom-link" data-href="${href}">`;
+      };
+
+      md.renderer.rules.link_close = () => '</span>';
+
+      const renderedHtml = md.render(rawMarkdown);
+
+      // 使用 setTimeout 来确保 DOM 更新后再添加事件监听器
+      setTimeout(() => {
+        const links = document.querySelectorAll('.custom-link');
+        links.forEach(link => {
+          link.addEventListener('click', (e) => {
+            e.preventDefault();
+            const href = link.getAttribute('data-href');
+            window.open(href, '_blank');
+          });
+        });
+      }, 0);
+
+      return renderedHtml;
     },
     handleKeydown(event) {
       // Check if 'Enter' is pressed without the 'Alt' key

+ 7 - 0
src/router/index.js

@@ -119,6 +119,13 @@ export const constantRoutes = [
     hidden:true,
     meta: { title: 'ai',  noCache: true }
   },
+  {
+    path: '/preview',
+    component: () => import('@/views/login/Preview.vue'),
+    name: 'preview',
+    hidden:true,
+    meta: { title: 'preview',  noCache: true }
+  },
   {
     path: '/error',
     component: Layout,

+ 4 - 3
src/views/document/com/menus.vue

@@ -17,7 +17,7 @@
               :class="{
                 disabled:
                   (type === 'document' && item.key !== 'ai') ||
-                  (item.key === 'article' && type === 'module'),
+                  (item.key === 'article' && (type === 'module' || type === undefined)),
               }"
             >
               <div class="icon">
@@ -185,7 +185,7 @@ export default {
               key: "article",
               name: "图文",
               icon: "图文",
-              disabled: () => this.type === "module",
+              disabled: () =>this.type === "module" || this.type === undefined,
             },
 
             /* {
@@ -286,6 +286,7 @@ export default {
   },
   mounted() {
     this.type = this.$route.query.type;
+    console.log(this.type);
   },
   methods: {
     /* 变量变动 */
@@ -340,7 +341,7 @@ export default {
     onClickMenus(e) {
       if (
         (this.type === "document" && e.key !== "ai") ||
-        (e.key === "article" && this.type === "module")
+        (e.key === "article" && (this.type === "module" || this.type === undefined))
       ) {
         return; // Exit the method if the item is disabled
       }

+ 2 - 2
src/views/document/components/dataList.vue

@@ -81,7 +81,7 @@
 </template>
 
 <script>
-import { pageDocument, deleteDocument } from "@/api/document";
+import { pageDocument, deleteDocument,searchlistDoc } from "@/api/document";
 export default {
   props: {
     queryForm: {
@@ -199,7 +199,7 @@ export default {
     search() {
       let _this = this;
       _this.loading = true; // Set loading to true before API call
-      pageDocument(_this.queryForm)
+      searchlistDoc(_this.queryForm)
         .then((res) => {
           if (!res) {
             _this.loading = false; // Set loading to false if no response

+ 54 - 19
src/views/document/create.vue

@@ -711,7 +711,12 @@ export default {
     articleId: {
       handler(val) {
         if (val == null || val == undefined || val <= 0) return;
-        this.loadArticle(val);
+        if (this.$route.query.type == "document") {
+          this.loadArticle(val);
+        }else{
+          this.onTemplateInfo(val)
+        }
+        //
       },
       immediate: true,
       deep: true,
@@ -1210,6 +1215,7 @@ export default {
         const {
           data: { dataList },
         } = await searchFormula({ page: 1, pageSize: 999 });
+        /* console.log(data); */
         data.attrs = data.attrs.map((item) => {
           const formula = dataList.find((el) => el.id === item.id);
           return formula
@@ -1325,12 +1331,14 @@ export default {
                 : templateInfo.data.attrs || []; // Add a fallback empty array */
 
             attrs.forEach((item) => {
-              const matchedFormula = formulaData.data.dataList.find(
-                (ite) => ite.id === item.data.id
-              );
-              if (matchedFormula) {
-                item.data = matchedFormula;
-                item.formula = matchedFormula.formula;
+              if (item && item.data && item.data.id) {
+                const matchedFormula = formulaData.data.dataList.find(
+                  (ite) => ite.id === item.data.id
+                );
+                if (matchedFormula) {
+                  item.data = matchedFormula;
+                  item.formula = matchedFormula.formula;
+                }
               }
             });
 
@@ -1354,7 +1362,7 @@ export default {
     },
     /* 加载模版信息 */
     async onTemplateInfo(id) {
-      console.log("模版");
+     
       try {
         this.loading = true;
         const res = await getDocumentInfo({ id });
@@ -1363,29 +1371,49 @@ export default {
           throw new Error("Invalid response status");
         }
 
+        // 确保 res.data 存在
+        if (!res.data) {
+          throw new Error("No data received from getDocumentInfo");
+        }
+
         this.docAttr = {
           id: this.docAttr.id,
           category_id: Number(this.docAttr.category_id),
-          title: this.docAttr.title,
+          title: res.data.title,
           content: "",
           status: res.data.status,
           is_template: res.data.is_template,
-          linkProduct: res.data.linkProduct,
-          links: res.data.links,
-          linkProject: res.data.linkProject,
-          projects: res.data.projects,
+          linkProduct: res.data.linkProduct || [],
+          links: res.data.links || "",
+          linkProject: res.data.linkProject || [],
+          projects: res.data.projects || "",
         };
 
-        const templateData = JSON.parse(res.data.data);
+        // 确保 res.data.data 是有效的 JSON 字符串
+        const templateData = res.data.data ? JSON.parse(res.data.data) : [];
 
         const updatedComs = await Promise.all(
           templateData.map(async (el) => {
+            if (!el || !el.id) {
+              console.warn("Invalid template item:", el);
+              return null; // 跳过无效的项
+            }
+
             const templateInfo = await getTemplateInfo({ id: el.id });
             const formulaData = await searchFormula({ page: 1, pageSize: 999 });
 
-            let attrs = JSON.parse(templateInfo.data.attrs);
+            // 确保 templateInfo.data 和 templateInfo.data.attrs 存在
+            let attrs =
+              templateInfo.data && templateInfo.data.attrs
+                ? JSON.parse(templateInfo.data.attrs)
+                : [];
 
             attrs = attrs.map((item) => {
+              if (!item || !item.data || !item.data.id) {
+                console.warn("Invalid attribute item:", item);
+                return item; // 保留原始项,即使它可能是无效的
+              }
+
               const matchedFormula = formulaData.data.dataList.find(
                 (ite) => ite.id === item.data.id
               );
@@ -1399,16 +1427,22 @@ export default {
               return item;
             });
 
-            return { ...el, ...templateInfo.data, attrs };
+            return { ...el, ...(templateInfo.data || {}), attrs };
           })
         );
 
-        this.coms = updatedComs;
-        console.log("coms", updatedComs);
-
+        // 过滤掉 null 值
+        this.coms = updatedComs.filter(Boolean);
+        console.log("coms", this.coms);
+        console.log("模版",this.docAttr);
+        if (this.articleId !== undefined) {
+          document.title = `${this.docAttr.title}-轻良实业`;
+        }
         this.uptadeSearch();
       } catch (error) {
         console.error("Error in onTemplateInfo:", error);
+        // 可以在这里添加用户友好的错误提示
+        this.$message.error("加载模板信息时出错,请稍后重试");
       } finally {
         this.loading = false;
       }
@@ -1596,6 +1630,7 @@ export default {
       createDocument(_this.docAttr).then((res) => {
         if (res.status != 200) return; //保存文档
         _this.docAttr.id = res.data;
+        _this.articleId=res.data
         _this.$alert("模版保存成功");
         _this.searchArticle();
       });

+ 5 - 5
src/views/document/temList/components/dataList.vue

@@ -61,7 +61,7 @@
 
     <div class="page-info">
       <el-pagination
-        v-model:currentPage="queryForm.page"
+       :currentPage="queryForm.page"
         :page-size="queryForm.pageSize"
         :total="recordCount"
         :page-count="pageTotal"
@@ -75,7 +75,7 @@
 </template>
 
 <script>
-import { pageDocument, deleteDocument } from "@/api/document";
+import { pageDocument, deleteDocument,searchList } from "@/api/document";
 export default {
   props: {
     queryForm: {
@@ -193,12 +193,12 @@ export default {
     search() {
       let _this = this;
       _this.loading = true; // Set loading to true before API call
-      pageDocument(_this.queryForm)
+      searchList(_this.queryForm)
         .then((res) => {
           if (!res) return;
-          _this.dataList = res.data.dataList.filter(
+          _this.dataList = res.data.dataList/* .filter(
             (el) => el.is_template == 1
-          );
+          ); */
           _this.recordCount = res.data.totalRecord;
           _this.pageTotal = res.data.pageTotal;
           _this.loading = false; // Set loading to false after data is processed

+ 45 - 0
src/views/login/Preview.vue

@@ -0,0 +1,45 @@
+<template>
+   <div>
+    <!-- 文件预览组件 -->
+    <file-preview :file-url="url" file-type="docx" />
+   </div>
+</template>
+
+<script>
+import FilePreview from "@/components/FilePreview/index.vue"; // 新增文件预览组件
+export default {
+  /*组件参数 接收来自父组件的数据*/
+  props: {},
+  /*局部注册的组件*/
+  components: {
+    FilePreview, // 注册文件预览组件
+  },
+  /*组件状态值*/
+   data () {
+      return {
+        url:'',
+      };
+   },
+
+  /*计算属性*/
+  computed: {},
+
+  /*侦听器*/
+  watch: {},
+
+  /*
+  * el 被新创建的 vm.$ el 替换,并挂载到实例上去之后调用该钩子。
+  * 如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$ el 也在文档内。
+  */
+  mounted () {
+    this.url=localStorage.getItem('href')
+    console.log(localStorage.getItem('href'));
+  },
+
+  /*组件方法*/
+   methods: {}
+}
+</script>
+<style lang='css' scoped>
+
+</style>

Some files were not shown because too many files changed in this diff