zhuliu 4 hónapja
szülő
commit
716513e018

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 18057 - 565
package-lock.json


+ 9 - 2
package.json

@@ -7,21 +7,27 @@
     "lint": "vue-cli-service lint",
     "dev": "vue-cli-service serve"
   },
-  
   "dependencies": {
+    "@highlightjs/vue-plugin": "^2.1.0",
     "@riophae/vue-treeselect": "^0.4.0",
     "core-js": "^3.6.5",
     "crypto-js": "^4.2.0",
+    "dompurify": "^3.2.4",
     "driver.js": "^1.3.0",
     "echarts": "^5.2.2",
     "el-table-infinite-scroll": "^1.0.0",
     "element-ui": "^2.15.7",
+    "file-saver": "^2.0.5",
     "flowchart-vue": "^0.30.0",
+    "github-markdown-css": "^5.8.1",
+    "highlight.js": "^11.11.1",
+    "html-docx-js": "^0.3.1",
     "html2canvas": "^1.3.3",
     "intro.js": "^7.2.0",
     "js-cookie": "^3.0.1",
     "less": "^4.1.2",
     "less-loader": "^5.0.0",
+    "markdown-it": "^14.1.0",
     "mockjs": "^1.1.0",
     "moment": "^2.29.1",
     "sass": "^1.43.4",
@@ -32,7 +38,8 @@
     "vue-router": "^3.2.0",
     "vuedraggable": "^2.24.3",
     "vuex": "^3.4.0",
-    "vuex-persistedstate": "^4.1.0"
+    "vuex-persistedstate": "^4.1.0",
+    "xlsx": "^0.18.5"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "~4.5.0",

+ 4 - 2
src/api/index.js

@@ -25,7 +25,8 @@ import examine from "./newApi/examine";
 import IPREmail from "./newApi/IPREmail";
 import litigation from "./newApi/litigation";
 import reportAffair from "./newApi/reportAffair";
-import technicalDisclosure from './newApi/technicalDisclosure'
+import technicalDisclosure from './newApi/technicalDisclosure';
+import AI from './newApi/AI'
 
 export default {
   ...client,
@@ -52,5 +53,6 @@ export default {
   ...IPREmail,
   ...litigation,
   ...reportAffair,
-  ...technicalDisclosure
+  ...technicalDisclosure,
+  ...AI,
 }

+ 15 - 0
src/api/newApi/AI.js

@@ -0,0 +1,15 @@
+import axios from "@/utils/axios";
+export default {
+    /**
+     * 根据标题和摘要获取翻译内容接口
+     */
+    sendOADefense(data) {
+        return axios.post("/xiaoshi/dify/sendOADefense", data);
+    },
+    /**
+     * 保存AI会话的结果文件
+     */
+    addConfessionSessionFile(data) {
+        return axios.post("/xiaoshi/confessionSession/addConfessionSessionFile", data);
+    },
+}

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

@@ -494,6 +494,7 @@ export default {
                 })
             ]).then(() => {
                 console.log('内容已复制到剪贴板');
+                this.$message.success('复制成功');
             });
             return
         }

+ 11 - 0
src/router/index.js

@@ -554,6 +554,17 @@ const routes = [
             },
             component: () => import('@/views/AITools/claimsExplain/index.vue'),
           },
+          //OA答辩
+          {
+            path: '/OADefense',
+            name: 'OADefense',
+            meta: {
+              title: 'OA答辩',
+              sign: 'OADefense',
+              belong: 'AI',
+            },
+            component: () => import('@/views/AITools/OADefense/index.vue'),
+          },
         ]
       },
       //任务模块

+ 43 - 0
src/utils/common.js

@@ -6,9 +6,12 @@ import showPermissionDialog from "@/utils/model/noPermission/index";
 import { Base64 } from 'js-base64';
 import Config from '@/config'
 import moment from "moment";
+import constants from '@/utils/constants'
 
 import * as XLSX from 'xlsx';
 import { saveAs } from 'file-saver';
+
+import htmlDocx from "html-docx-js/dist/html-docx";
 export default {
   //滚动到顶部
   scrollToTop(){
@@ -232,6 +235,46 @@ treeToArray(data,prop={children:children}){
     })
     return str
   },
+  /**
+   * 导出为word
+   * @param {String} html html格式内容
+   * @param {String} name 文件名称
+   * @param {Boolean} autoUpload 是否上传文件
+   */
+  async exportToWordByHtml(html,name,autoUpload = false){
+    if(!html){
+      return
+    }
+    if(!name){
+      name = new Date().getTime()
+    }
+    // 将 HTML 转换为 Word 文档
+    const converted = await htmlDocx.asBlob(html);
+    
+    // 创建一个下载链接
+    const url = await URL.createObjectURL(converted);
+    const link = document.createElement("a");
+    link.href = url;
+    link.download = name+".docx";
+    link.click();
+
+    // 清理
+    URL.revokeObjectURL(url);
+
+    if(!autoUpload){
+      return ''
+    }
+    const formData = new FormData();
+    formData.append('sourceId',constants.sourceId)
+    formData.append("files", converted, name + ".docx")
+    var guid = ''
+    await api.uploadFile(formData).then(response=>{
+        if(response.code == 200){
+            guid = response.data[0]
+        }
+    })
+    return guid
+  },
 
   /**
    * 导出为excel

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 441 - 0
src/views/AITools/OADefense/OADefense.vue


+ 26 - 0
src/views/AITools/OADefense/index.vue

@@ -0,0 +1,26 @@
+<template>
+    <div class="height_100">
+      <OADefense></OADefense>
+    </div>
+</template>
+  
+<script>
+import OADefense from './OADefense.vue'
+export default {
+    components: {
+        OADefense
+    },
+    props: {},
+    data() {
+      return {
+      };
+    },
+    watch: {},
+    computed: {},
+    created() {},
+    mounted() {},
+    methods: {},
+};
+</script>
+<style lang="scss" scoped>
+</style>

+ 219 - 0
src/views/AITools/OADefense/mixins/index.js

@@ -0,0 +1,219 @@
+
+export default {
+    data() {
+        return {
+            controller:null
+        }
+    },
+    computed:{
+        userinfo(){
+            return this.$s.getObj('userinfo')
+        }
+    },
+    methods: {
+        async getResult(){
+            if(!this.confession.guid){
+                this.$message.warning('请先上传审查意见书')
+                return
+            }
+            if(this.loading){
+                this.$message.warning('请等当前执行完成')
+                return
+            }
+            this.loading = true
+            this.result = null
+            this.controller = new AbortController();
+            const response = await fetch('/api/xiaoshi/dify/sendOADefense?confessionSessionId='+this.currentConversation.id, {
+              method: 'GET',
+              headers: {
+                'Content-Type': 'application/json',
+                'Accept': 'text/event-stream',
+              },
+              signal: this.controller.signal
+            });
+            if (!response.ok) throw new Error('AI API 调用失败');
+            this.finish = false
+            const reader = response.body.getReader();
+            const decoder = new TextDecoder('utf-8');
+            let noFinishMessage = ''
+            while (true) {
+                const { done, value } = await reader.read();
+                if (done){
+                    this.finish = true
+                    this.loading = false
+                    break;
+                } 
+                const chunk = decoder.decode(value);
+                const lines2 = chunk.split('\n\n').filter(line => line.trim() !== '' && line.trim() !== 'data:event: ping')
+                for(const line of lines2){
+                    const jsonStr1 = line.replace(/^data:\s{0,}/, '');
+                    const jsonStr = jsonStr1.trim()
+                    if(jsonStr == 'event: ping' || jsonStr ==''){
+                        continue;
+                    }
+                    try {
+                        const json = JSON.parse(jsonStr);
+                        if(json.event == 'message'){
+                            this.result += json.answer;
+                        }else if(json.event == 'message_replace'){
+                            this.result = json.answer
+                        }else if(json.event == 'text_chunk'){
+                            if(json.data){
+                               this.result += json.data.text; 
+                            }
+                            
+                        }
+                        
+                    } catch (e) {
+                        if(jsonStr.indexOf('{') == 0){
+                            noFinishMessage = jsonStr
+                        }else{
+                            noFinishMessage += jsonStr
+                            if(jsonStr.lastIndexOf('}') == jsonStr.length - 1){
+                                try{
+                                    const json = JSON.parse(noFinishMessage);
+                                    if(json.event == 'message'){
+                                        this.result += json.answer;
+                                    }else if(json.event == 'message_replace'){
+                                        this.result = json.answer
+                                    }else if(json.event == 'text_chunk'){
+                                        if(json.data){
+                                            this.result += json.data.text; 
+                                         }
+                                    }
+                                }
+                                catch(e){
+                                    console.error('解析响应数据出错:', e);
+                                }finally{
+                                    noFinishMessage = ''
+                                }
+                            }
+                        }
+                    }
+                    
+                }
+            }
+        },
+        cancelRun(){
+            if (this.controller) {
+                this.controller.abort();
+            }
+            this.loading = false
+        },
+        //格式化AI答复
+        formateAIAnswer(chat){
+            let answer = chat
+            let len = answer.length
+
+            let signs = [
+                {
+                    start:'<think>',
+                    end:'</think>'
+                },
+                {
+                    start:'<details style="color:gray;background-color: #f8f8f8;padding: 8px;border-radius: 4px;" open> <summary> Thinking... </summary>',
+                    end:'</details>'
+                },
+            ]
+            let sign_obj = {}
+            let start_index = -1
+            let end_index = -1
+
+            for(let i = 0;i<signs.length;i++){
+                let item = signs[i]
+                let index = answer.indexOf(item.start)
+                if(index!=-1){
+                    sign_obj = item
+                    start_index = index
+                    end_index = answer.indexOf(item.end)
+                    break;
+                }
+            }
+
+            var arr = []
+            if(start_index == -1){
+                let obj = {
+                    type:'text',
+                    content:answer.trim()
+                }
+                arr.push(obj)
+                return arr
+            }
+            if(end_index == -1){
+                let obj = {
+                    type:'text',
+                    content:answer.substring(0, start_index).trim()
+                }
+                arr.push(obj)
+                obj = {
+                    type:'think',
+                    content:answer.substring(start_index + sign_obj.start.length,len).trim(),
+                    show:false
+                }
+                if(chat.id == this.currentMessage.id){
+                    obj.show = true
+                }
+                arr.push(obj)
+                return arr
+            }
+            let obj = {
+                type:'text',
+                content:answer.substring(0, start_index).trim()
+            }
+            arr.push(obj)
+            obj = {
+                type:'think',
+                show:false,
+                content:answer.substring(start_index + sign_obj.start.length, end_index).trim()
+            }
+            arr.push(obj)
+            obj = {
+                type:'text',
+                content:answer.substring(end_index + sign_obj.end.length,len).trim()
+            }
+            arr.push(obj)
+            return arr
+
+        },
+        async copy(chat){
+            let answerDomList = document.querySelectorAll('#answer')
+    
+            if(answerDomList.length == 0){
+                return
+            }
+            let answerDom = answerDomList[answerDomList.length - 1]
+            let answerHtml = answerDom.innerHTML
+            let answer_text = answerDom.textContent || answerDom.innerText;
+            if(navigator.clipboard && navigator.clipboard.write){
+                // 复制复杂内容(纯文本 + HTML)
+                navigator.clipboard.write([
+                    new ClipboardItem({
+                        'text/html': new Blob([answerHtml], { type: 'text/html' }),
+                        'text/plain': new Blob([answer_text], { type: 'text/plain' })
+                    })
+                ]).then(() => {
+                    console.log('内容已复制到剪贴板');
+                    this.$message.success('复制成功');
+                });
+                return
+            }
+            
+            let textArea = document.createElement("textarea");
+            textArea.value = answer_text;
+            // 防止滚动到页面底部
+            textArea.style.top = "0";
+            textArea.style.left = "0";
+            textArea.style.position = "fixed";
+            textArea.style.opacity = "0";
+            document.body.appendChild(textArea);
+            textArea.select();
+            try {
+                document.execCommand('copy');
+                this.$message.success('复制成功');
+            } catch (err) {
+                this.$message.error('复制失败');
+            }
+            document.body.removeChild(textArea);
+        },
+    },
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 8 - 2
src/views/AITools/components/conversationRecords.vue


+ 4 - 1
src/views/AITools/technicalDisclosure/technicalDisclosure.vue

@@ -284,7 +284,8 @@ export default {
               let guid = response.data[0]
               this.$refs.uploadConfession.clearFiles()
               var params = {
-                fileGuid:guid
+                fileGuid:guid,
+                type:0
               }
               this.$api.addConfessionSession(params).then(response=>{
                 if(response.code == 200){
@@ -598,6 +599,8 @@ export default {
       }
       .confessionSessionList{
         padding:.5rem 0rem 1rem 0;
+        height:calc(100% - 155px);
+        overflow-y: auto;
         .chat_item{
           color: rgb(71 84 103 / 1);
           font-weight: 500;

+ 2 - 1
src/views/layout/components/UserBar.vue

@@ -9,7 +9,8 @@
             </el-link>
           <el-dropdown-menu slot="dropdown">
             <el-dropdown-item command="/technicalDisclosure">技术交底书解析</el-dropdown-item>
-            <el-dropdown-item command="claimsExplain">权利要求解释及有益效果</el-dropdown-item>
+            <el-dropdown-item command="/claimsExplain">权利要求解释及有益效果</el-dropdown-item>
+            <el-dropdown-item command="/OADefense">OA答辩</el-dropdown-item>
           </el-dropdown-menu>
         </el-dropdown>
       </span>