Browse Source

修改内容

yangg 3 ngày trước cách đây
mục cha
commit
86ddde5dfb

+ 1 - 1
.env.development

@@ -3,7 +3,7 @@ ENV = 'development'
 port = 8080
 # base api https://qlaiapi.raycos.com.cn
 VUE_APP_BASE_AI_API='https://qlaiapi.raycos.com.cn'
-VUE_APP_BASE_API = 'http://58.246.234.210:8084'
+VUE_APP_BASE_API = 'http://192.168.100.101:8084'
 #192.168.1.199
 
 #58.246.234.210

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/index.html


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/css/app.854334d7.css


+ 0 - 0
dist/static/css/chunk-23d4d74d.e30e9787.css → dist/static/css/chunk-10bfc27e.6044f932.css


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/css/chunk-3777bfcd.f5399100.css


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/css/chunk-752ddf6e.91d739fd.css


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/app.1f4a633e.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/app.6be96a2d.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-00d3f6c2.4cfff979.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-00d3f6c2.b2b122ce.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-04c39295.df5e4f49.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-04c39295.e709b7e5.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-10bfc27e.f7bd24a2.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-138f7583.83859b96.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-3777bfcd.58bd7d05.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-4ac7f82e.24fa4477.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-4ac7f82e.95eb13c8.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-6711f3a4.d5109ae1.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-7150dcbc.7b77f272.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-752ddf6e.3ff6dbd2.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-77e7ad00.5ca70d94.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-9235c1ae.cbf7e640.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-9235c1ae.d2dc41f3.js


+ 21 - 0
src/api/document.js

@@ -163,3 +163,24 @@ export function exportToPDF(data) {
     data
   })
 }
+
+/* 获取文档内容查询 - 问答对 */
+export function queryDocumentContent(data) {
+  return request({
+    url: '/document/content/query',
+    method: 'get',
+    params: data
+  })
+}
+
+/* 导出问答对到Excel */
+export function exportQaToExcel(data) {
+  return request({
+    url: '/document/content/export_qa_to_excel/',
+    method: 'post',
+    data,
+    headers: {
+      'Content-Type': 'application/json'
+    }
+  })
+}

+ 9 - 0
src/api/knowledge.js

@@ -771,4 +771,13 @@ export function getSotaDetails(data) {
     method: 'post',
     data
   })
+}
+
+/* 获取进度 */
+export function getProgress(data) {
+  return request({
+    url: `/api/literature/progress/?literature_ids=${data}`,
+    method: 'get',
+    data
+  })
 }

+ 1 - 1
src/components/FilePreview/index.vue

@@ -264,7 +264,7 @@ export default {
     console.log(this.isWord);
     if (this.fileType === "txt") {
       this.loadTextContent();
-    } else if (this.isWord) {
+    } else if (this.$route.query.type == "docx") {
       this.loadWordContent();
     } else if (this.$route.query.type == "xlsx") {
       this.loadExcelContent();

+ 103 - 0
src/utils/data-validator.js

@@ -0,0 +1,103 @@
+/**
+ * 数据验证和格式化工具
+ */
+
+/**
+ * 清理对象中的空值
+ * @param {Object} obj - 需要清理的对象
+ * @param {Boolean} removeEmptyArrays - 是否移除空数组
+ * @returns {Object} - 清理后的对象
+ */
+export function cleanEmptyValues(obj, removeEmptyArrays = false) {
+  const cleaned = {};
+  
+  Object.keys(obj).forEach(key => {
+    const value = obj[key];
+    
+    if (value === null || value === undefined || value === '') {
+      // 跳过空值
+      return;
+    }
+    
+    if (removeEmptyArrays && Array.isArray(value) && value.length === 0) {
+      // 可选:跳过空数组
+      return;
+    }
+    
+    // 递归处理嵌套对象
+    if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
+      const cleanedNested = cleanEmptyValues(value, removeEmptyArrays);
+      if (Object.keys(cleanedNested).length > 0) {
+        cleaned[key] = cleanedNested;
+      }
+    } else {
+      cleaned[key] = value;
+    }
+  });
+  
+  return cleaned;
+}
+
+/**
+ * 验证导出参数格式
+ * @param {Object} params - 导出参数
+ * @returns {Object} - 包含验证结果和清理后的参数
+ */
+export function validateExportParams(params) {
+  const errors = [];
+  const warnings = [];
+  
+  // 必填字段验证
+  if (!params.kb_id) {
+    errors.push('kb_id 是必填字段');
+  }
+  
+  // 类型验证
+  if (params.document_ids && !Array.isArray(params.document_ids)) {
+    errors.push('document_ids 必须是数组类型');
+  }
+  
+  if (params.doc_type_id !== undefined && params.doc_type_id !== null && typeof params.doc_type_id !== 'number') {
+    warnings.push('doc_type_id 应该是数字类型');
+  }
+  
+  // 清理参数
+  const cleanedParams = cleanEmptyValues(params);
+  
+  return {
+    isValid: errors.length === 0,
+    errors,
+    warnings,
+    cleanedParams
+  };
+}
+
+/**
+ * 格式化JSON用于日志输出
+ * @param {Object} data - 要格式化的数据
+ * @param {String} title - 日志标题
+ */
+export function logJSON(data, title = 'Data') {
+  console.group(`📋 ${title}`);
+  console.log('JSON字符串:', JSON.stringify(data, null, 2));
+  console.log('对象结构:', data);
+  console.groupEnd();
+}
+
+/**
+ * 检查JSON数据大小
+ * @param {Object} data - 要检查的数据
+ * @returns {Object} - 包含大小信息的对象
+ */
+export function checkJSONSize(data) {
+  const jsonString = JSON.stringify(data);
+  const sizeInBytes = new Blob([jsonString]).size;
+  const sizeInKB = (sizeInBytes / 1024).toFixed(2);
+  
+  return {
+    bytes: sizeInBytes,
+    kb: sizeInKB,
+    string: jsonString,
+    isLarge: sizeInBytes > 1024 * 1024 // 超过1MB认为是大数据
+  };
+} 

+ 381 - 67
src/views/knowledgeMenu/category/knowledgeSet.vue

@@ -89,6 +89,9 @@
             <i data-feather="stop-circle" class="icons"></i>
             终止所有任务
           </el-button>
+          <el-button type="primary" @click="exportData()">
+            <i data-feather="download" class="icons"></i> 导出问答对
+          </el-button>
         </div>
         <div class="selection-control" v-if="selectedRows.length > 0">
           <el-alert
@@ -155,18 +158,22 @@
                 effect="dark"
                 placement="top"
                 :disabled="
-                  Number(scope.row.run) !== 1 && Number(scope.row.run) !== 4
+                 ![1, 4, 7].includes(Number(scope.row.run))
                 "
               >
                 <template #content>
                   <div style="padding: 5px">
                     <div style="margin-top: 5px; font-size: 12px">
-                      {{ scope.row.progress_msg || "正在解析中..." }}
+                    {{ 
+                        Number(scope.row.run) === 7 
+                          ? (scope.row.progress_msg || "正在生成问答对...") 
+                          : (scope.row.progress_msg || "正在解析中...") 
+                      }}
                     </div>
                   </div>
                 </template>
                 <div class="status-wrapper">
-                  <template v-if="Number(scope.row.run) === 1">
+                  <template v-if="Number(scope.row.run) === 1||Number(scope.row.run) === 6">
                     <div class="progress-wrapper">
                       <el-progress
                         type="circle"
@@ -272,6 +279,21 @@
                       >
                       </el-button>
                     </el-tooltip>
+                    <el-tooltip
+                      class="item"
+                      effect="dark"
+                      content="查看问答对"
+                      placement="top"
+                    >
+                      <el-button
+                        type="text"
+                        size="small"
+                        circle
+                        icon="el-icon-receiving"
+                        @click="getQa(scope.row.id)"
+                        style="font-size: 15px"
+                      ></el-button>
+                    </el-tooltip>
                     <el-tooltip
                       class="item"
                       effect="dark"
@@ -463,6 +485,66 @@
             >
           </span>
         </el-dialog>
+         <!-- 问答对弹窗 -->
+        <el-dialog
+          title="问答对"
+          :visible.sync="qaDialogVisible"
+          width="80%"
+          :before-close="handleQaDialogClose"
+        >
+          <div class="qa-dialog-content">
+            <div class="qa-dialog-header">
+              <el-tag>文档ID: {{ currentDocumentId }}</el-tag>
+              <el-tag type="success" v-if="qaList.length">
+                共 {{ qaList.length }} 个问答对
+              </el-tag>
+            </div>
+
+            <div class="qa-content" v-loading="qaLoading">
+              <div v-if="qaList.length === 0 && !qaLoading" class="empty-state">
+                <i class="el-icon-document"></i>
+                <p>暂无问答对数据</p>
+              </div>
+
+              <div v-else class="qa-list">
+                <div 
+                  v-for="(item, index) in qaList" 
+                  :key="index" 
+                  class="qa-item"
+                >
+                  <div class="qa-question">
+                    <div class="qa-label">问:</div>
+                    <div class="qa-text">{{ item.question }}</div>
+                  </div>
+                  <div class="qa-answer">
+                    <div class="qa-label">答:</div>
+                    <div class="qa-text">{{ item.answer }}</div>
+                  </div>
+                  <div class="qa-meta" v-if="item.confidence || item.source">
+                    <el-tag size="mini" v-if="item.confidence">
+                      置信度: {{ item.confidence }}
+                    </el-tag>
+                    <el-tag size="mini" type="info" v-if="item.source">
+                      来源: {{ item.source }}
+                    </el-tag>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <span slot="footer" class="dialog-footer">
+            <el-button 
+              type="primary" 
+              icon="el-icon-refresh" 
+              @click="fetchQAData"
+              :loading="qaLoading"
+            >
+              刷新数据
+            </el-button>
+            <el-button @click="handleQaDialogClose">关闭</el-button>
+          </span>
+        </el-dialog>
       </div>
     </div>
   </div>
@@ -492,6 +574,10 @@ import {
   resultTask,
   endClear,
 } from "@/api/knowledge";
+
+import { exportQaToExcel,queryDocumentContent } from "@/api/document";
+import { validateExportParams, logJSON, checkJSONSize } from "@/utils/data-validator";
+
 export default {
   components: {
     dataSearch,
@@ -574,6 +660,11 @@ export default {
       selectedRows: [], // 已选择的行
       allSelectedRows: new Map(), // 存储所有选中的行
       isAllDataSelected: false, // 是否选中所有数据
+        /* 问答对弹窗 */
+      qaDialogVisible: false,
+      currentDocumentId: null,
+      qaList: [],
+      qaLoading: false,
     };
   },
   mounted() {
@@ -589,6 +680,158 @@ export default {
     Object.values(this.analysisStatusCheckers).forEach(clearTimeout);
   },
   methods: {
+      /* 导出 */
+    async exportData() {
+      try {
+        // 显示加载状态
+        const loading = this.$loading({
+          lock: true,
+          text: '正在导出,请稍候...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)'
+        });
+
+        // 准备导出参数
+        const exportParams = {
+          kb_id: this.queryForm.bucket_id, // 知识库ID
+          doc_type_id: this.queryForm.doc_type_id === 0 ? null : this.queryForm.doc_type_id, // 目录ID,0表示全部
+        };
+
+        // 如果有选中的文档,只导出选中的
+        if (this.selectedRows.length > 0) {
+          exportParams.document_ids = this.selectedRows.map(row => row.id);
+        }
+
+        // 验证和清理导出参数
+        const validation = validateExportParams(exportParams);
+        
+        if (!validation.isValid) {
+          loading.close();
+          this.$message.error(`参数验证失败: ${validation.errors.join(', ')}`);
+          return;
+        }
+
+        if (validation.warnings.length > 0) {
+          console.warn('参数警告:', validation.warnings);
+        }
+
+        // 使用清理后的参数
+        const finalParams = validation.cleanedParams;
+        
+        // 检查JSON数据大小
+        const sizeInfo = checkJSONSize(finalParams);
+        if (sizeInfo.isLarge) {
+          console.warn(`导出数据较大: ${sizeInfo.kb}KB`);
+        }
+
+        // 日志输出
+        logJSON(finalParams, '最终导出参数');
+
+        // 调用导出接口
+        const response = await exportQaToExcel(finalParams);
+       console.log(response);
+        
+        // 检查响应格式
+        if (response.status === 200) {
+          const { data } = response;
+          const { message, data: exportData } = data;
+          
+          // 如果有下载链接,直接使用浏览器下载
+          if (exportData && exportData.download_url) {
+            // 直接打开新窗口下载
+            window.open(exportData.download_url, '_blank');
+            loading.close();
+            this.$message.success(message || '导出成功!');
+          } else {
+            loading.close();
+            this.$message.error('获取下载链接失败');
+          }
+        } else {
+          loading.close();
+          this.$message.error('导出请求失败');
+        }
+        
+      } catch (error) {
+        console.error('导出失败:', error);
+        this.$message.error('导出失败,请稍后重试');
+        if (loading) loading.close();
+      }
+    },
+
+    // 下载文件的通用方法
+    downloadFile(downloadUrl, fileName) {
+      try {
+        const link = document.createElement('a');
+        link.href = downloadUrl;
+        link.download = fileName || `问答对导出_${new Date().toISOString().slice(0, 10)}.xlsx`;
+        link.target = '_blank'; // 在新窗口打开,避免跨域问题
+        
+        // 触发下载
+        document.body.appendChild(link);
+        link.click();
+        document.body.removeChild(link);
+        
+        this.$message.success('文件下载已开始!');
+      } catch (error) {
+        console.error('下载失败:', error);
+        this.$message.error('文件下载失败,请稍后重试');
+      }
+    },
+    /* 查看问答对 */
+    getQa(id) {
+      this.currentDocumentId = id;
+      this.qaDialogVisible = true;
+      this.fetchQAData();
+    },
+    
+    /* 获取问答对数据 */
+    async fetchQAData() {
+      if (!this.currentDocumentId) return;
+      
+      this.qaLoading = true;
+      try {
+        const response = await queryDocumentContent({
+          document_id: this.currentDocumentId
+        });
+        
+        if (response.status === 200 ) {
+          // 根据接口返回的数据结构调整
+          this.qaList = response.data[0].qa_pairs || response.result || [];
+          
+          // 如果接口返回的不是数组格式,进行处理
+          if (!Array.isArray(this.qaList)) {
+            if (this.qaList.items) {
+              this.qaList = this.qaList.items;
+            } else if (this.qaList.qa_pairs) {
+              this.qaList = this.qaList.qa_pairs;
+              console.log(this.qaList);
+            } else {
+              this.qaList = [];
+            }
+          }
+          
+          if (this.qaList.length === 0) {
+            this.$message.info('该文档暂无问答对数据');
+          }
+        } else {
+          this.$message.error(response.message || '获取问答对数据失败');
+          this.qaList = [];
+        }
+      } catch (error) {
+        console.error('获取问答对数据失败:', error);
+        this.$message.error('获取问答对数据失败,请稍后重试');
+        this.qaList = [];
+      } finally {
+        this.qaLoading = false;
+      }
+    },
+    
+    /* 关闭问答对弹窗 */
+    handleQaDialogClose() {
+      this.qaDialogVisible = false;
+      this.currentDocumentId = null;
+      this.qaList = [];
+    },
     // 获取行的唯一标识
     getRowKey(row) {
       return row.id;
@@ -635,12 +878,13 @@ export default {
     /* 状态展示 */
     getStatusType(status) {
       const statusMap = {
-        0: "info", // 未解析
+        0: "info",    // 未解析
         1: "warning", // 解析中
-        3: "success", // 成功
-        4: "danger", // 失败
-        5: "info", // 待解析
-        6: "danger", // 文件异常
+        3: "success", // 解析成功,问答对生成成功
+        4: "danger",  // 解析失败
+        5: "info",    // 待解析
+        6: "warning", // 待生成问答对
+        7: "danger"   // 解析成功,问答对生成失败
       };
       return statusMap[status] || "info";
     },
@@ -649,10 +893,11 @@ export default {
       const statusMap = {
         0: "未解析",
         1: "解析中",
-        3: "解析成功",
+        3: "处理成功",
         4: "解析失败",
-        5: "待解析",
-        6: "文件异常",
+        5: "待解析", 
+        6: "待生成问答对",
+        7: "处理失败"
       };
       return statusMap[status] || "未知状态";
     },
@@ -1124,7 +1369,7 @@ export default {
     },
     /* 解析 */
     analysis(row) {
-      if (row.run == 1 || row.run == 5) return;
+      if (row.run == 1 || row.run == 5|| row.run == 6) return;
 
       // Set the status to "解析中" (1) immediately
       this.$set(row, "run", 1);
@@ -1165,71 +1410,50 @@ export default {
       if (this.analysisStatusCheckers[row.id]) {
         clearTimeout(this.analysisStatusCheckers[row.id]);
       }
-      /* 获取token数 */
-      /*  const checkStatus = () => {
-        getdocpro({ document_id: row.id })
-          .then((res) => {
-            if (res.status === 200) {
-              const newStatus = Number(res.data.status);
-              const newProgress = Number(res.data.total_tasks);
-              this.$set(row, "run", newStatus);
-              this.$set(row, "progress", newProgress);
-
-              if (newStatus === 3) {
-                this.$message.success("解析成功");
-                delete this.analysisStatusCheckers[row.id];
-                // 在这里添加刷新列表的逻辑
-                this.refreshCurrentList();
-              } else if (newStatus === 4) {
-                this.$message.error("解析失败");
-                delete this.analysisStatusCheckers[row.id];
-              } else if (newStatus === 1 || newStatus === 5) {
-                // Continue checking
-                this.analysisStatusCheckers[row.id] = setTimeout(
-                  checkStatus,
-                  15000
-                );
-              }
-            } else {
-              this.$message.error("获取解析状态失败");
-              delete this.analysisStatusCheckers[row.id];
-            }
-          })
-          .catch((error) => {
-            console.error("获取解析状态错误:", error);
-            this.$message.error("获取解析状态时出现错误");
-            delete this.analysisStatusCheckers[row.id];
-          });
-      }; */
       /* 监控任务 */
       const checkStatus = () => {
         resultTask(row.id)
           .then((res) => {
             if (res.status === 200) {
               const newStatus = Number(res.data.document_status);
-              const newProgress =
-                Number(res.data.progress) == 100
-                  ? 0
-                  : Number(res.data.progress);
+              const newProgress =Number(res.data.progress) === 100 ? 0 : Number(res.data.progress);
               const newProgressMsg = res.data.progress_msg;
+              // 更新状态和进度
               this.$set(row, "run", newStatus);
               this.$set(row, "progress", newProgress);
               this.$set(row, "progress_msg", newProgressMsg);
 
-              if (newStatus === 3) {
-                this.$message.success("解析成功");
-                delete this.analysisStatusCheckers[row.id];
-                // 在这里添加刷新列表的逻辑
-                this.refreshCurrentList();
-              } else if (newStatus === 4) {
-                this.$message.error("解析失败");
-                delete this.analysisStatusCheckers[row.id];
-              } else if (newStatus === 1 || newStatus === 5) {
-                // Continue checking
-                this.analysisStatusCheckers[row.id] = setTimeout(
-                  checkStatus,
-                  15000
-                );
+            // 根据不同状态处理
+              switch (newStatus) {
+                case 3: // 解析成功
+                  this.$message.success("解析成功");
+                  delete this.analysisStatusCheckers[row.id];
+                  this.refreshCurrentList();
+                  break;
+                  
+                case 4: // 解析失败
+                  this.$message.error(newProgressMsg || "解析失败");
+                  delete this.analysisStatusCheckers[row.id];
+                  break;
+                  
+                case 1: // 解析中
+                case 5: // 待解析
+                case 6: // 待生成问答对
+                case 7: // 解析成功,问答对生成失败
+                  // 设置检查间隔
+                  const checkInterval = newStatus === 6 ? 5000 : 15000;
+                  
+                  // 更新进度信息
+                  if (newStatus === 6) {
+                    this.$set(row, "progress_msg", "正在生成问答对...");
+                  } else if (newStatus === 7) {
+                    const progressMsg = res.data.Result?.message || "问答对生成失败";
+                    this.$set(row, "progress_msg", progressMsg);
+                  }
+                  
+                  // 继续检查状态
+                  this.analysisStatusCheckers[row.id] = setTimeout(checkStatus, checkInterval);
+                  break;
               }
             } else {
               this.$message.error("获取解析状态失败");
@@ -1466,7 +1690,7 @@ export default {
 
             // Initialize the analysis status for each row
             _this.dataList.forEach((row) => {
-              if (row.run == 1 || row.run == 5) {
+              if (row.run == 1 || row.run == 5|| row.run == 6) {
                 _this.startAnalysisStatusChecker(row);
               }
             });
@@ -1723,5 +1947,95 @@ export default {
     padding: 8px 16px;
   }
 }
+/* 问答对弹窗样式 */
+.qa-dialog-content {
+  padding: 0;
+}
+
+.qa-dialog-header {
+  margin-bottom: 20px;
+  padding-bottom: 12px;
+  border-bottom: 1px solid #e8e8e8;
+  display: flex;
+  gap: 8px;
+  align-items: center;
+}
+
+.qa-content {
+  min-height: 300px;
+  max-height: 500px;
+  overflow-y: auto;
+}
+
+.empty-state {
+  text-align: center;
+  padding: 60px 0;
+  color: #999;
+}
+
+.empty-state i {
+  font-size: 48px;
+  color: #ddd;
+  margin-bottom: 16px;
+  display: block;
+}
+
+.empty-state p {
+  margin: 0;
+  font-size: 16px;
+}
+
+.qa-list {
+  space-y: 20px;
+}
+
+.qa-item {
+  background: #f8f9fa;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 16px;
+  border-left: 4px solid #409eff;
+  transition: all 0.3s ease;
+}
+
+.qa-item:hover {
+  box-shadow: 0 2px 12px rgba(64, 158, 255, 0.1);
+}
+
+.qa-question, .qa-answer {
+  display: flex;
+  margin-bottom: 12px;
+  align-items: flex-start;
+}
+
+.qa-answer {
+  margin-bottom: 16px;
+}
+
+.qa-label {
+  flex-shrink: 0;
+  width: 40px;
+  font-weight: bold;
+  color: #409eff;
+  margin-right: 8px;
+}
+
+.qa-question .qa-label {
+  color: #e6a23c;
+}
+
+.qa-text {
+  flex: 1;
+  line-height: 1.6;
+  color: #333;
+  word-break: break-word;
+}
+
+.qa-meta {
+  display: flex;
+  gap: 8px;
+  padding-top: 8px;
+  border-top: 1px solid #eee;
+}
 </style>
     

+ 218 - 0
src/views/knowledgeMenu/category/qa.vue

@@ -0,0 +1,218 @@
+<template>
+  <div class="qa-container">
+    <div class="qa-header">
+      <h1>问答对</h1>
+      <div class="header-info">
+        <el-tag>文档ID: {{ documentId }}</el-tag>
+        <el-tag type="success" v-if="qaList.length">
+          共 {{ qaList.length }} 个问答对
+        </el-tag>
+      </div>
+    </div>
+
+    <div class="qa-content" v-loading="loading">
+      <div v-if="qaList.length === 0 && !loading" class="empty-state">
+        <i class="el-icon-document"></i>
+        <p>暂无问答对数据</p>
+      </div>
+
+      <div v-else class="qa-list">
+        <div 
+          v-for="(item, index) in qaList" 
+          :key="index" 
+          class="qa-item"
+        >
+          <div class="qa-question">
+            <div class="qa-label">问:</div>
+            <div class="qa-text">{{ item.question }}</div>
+          </div>
+          <div class="qa-answer">
+            <div class="qa-label">答:</div>
+            <div class="qa-text">{{ item.answer }}</div>
+          </div>
+          <div class="qa-meta" v-if="item.confidence || item.source">
+            <el-tag size="mini" v-if="item.confidence">
+              置信度: {{ item.confidence }}
+            </el-tag>
+            <el-tag size="mini" type="info" v-if="item.source">
+              来源: {{ item.source }}
+            </el-tag>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 刷新按钮 -->
+    <div class="qa-actions">
+      <el-button 
+        type="primary" 
+        icon="el-icon-refresh" 
+        @click="fetchQAData"
+        :loading="loading"
+      >
+        刷新数据
+      </el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { queryDocumentContent } from '@/api/document'
+
+export default {
+  name: "Qa",
+  data() {
+    return {
+      documentId: 8559, // 文档ID
+      qaList: [], // 问答对列表
+      loading: false // 加载状态
+    }
+  },
+  mounted() {
+    this.fetchQAData()
+  },
+  methods: {
+    // 获取问答对数据
+    async fetchQAData() {
+      this.loading = true
+      try {
+        const response = await queryDocumentContent({
+          document_id: this.documentId
+        })
+        
+        if (response.code === 20000 || response.success) {
+          // 根据接口返回的数据结构调整
+          this.qaList = response.data || response.result || []
+          
+          // 如果接口返回的不是数组格式,进行处理
+          if (!Array.isArray(this.qaList)) {
+            if (this.qaList.items) {
+              this.qaList = this.qaList.items
+            } else if (this.qaList.qa_pairs) {
+              this.qaList = this.qaList.qa_pairs
+            } else {
+              this.qaList = []
+            }
+          }
+        } else {
+          this.$message.error(response.message || '获取问答对数据失败')
+        }
+      } catch (error) {
+        console.error('获取问答对数据失败:', error)
+        this.$message.error('获取问答对数据失败,请稍后重试')
+        this.qaList = []
+      } finally {
+        this.loading = false
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+.qa-container {
+  padding: 20px;
+  background: #fff;
+  min-height: 100vh;
+}
+
+.qa-header {
+  margin-bottom: 24px;
+  padding-bottom: 16px;
+  border-bottom: 1px solid #e8e8e8;
+}
+
+.qa-header h1 {
+  margin: 0 0 12px 0;
+  color: #333;
+  font-size: 24px;
+  font-weight: 500;
+}
+
+.header-info {
+  display: flex;
+  gap: 8px;
+  align-items: center;
+}
+
+.qa-content {
+  min-height: 300px;
+}
+
+.empty-state {
+  text-align: center;
+  padding: 60px 0;
+  color: #999;
+}
+
+.empty-state i {
+  font-size: 48px;
+  color: #ddd;
+  margin-bottom: 16px;
+}
+
+.empty-state p {
+  margin: 0;
+  font-size: 16px;
+}
+
+.qa-list {
+  space-y: 20px;
+}
+
+.qa-item {
+  background: #f8f9fa;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 16px;
+  border-left: 4px solid #409eff;
+  transition: all 0.3s ease;
+}
+
+.qa-item:hover {
+  box-shadow: 0 2px 12px rgba(64, 158, 255, 0.1);
+}
+
+.qa-question, .qa-answer {
+  display: flex;
+  margin-bottom: 12px;
+  align-items: flex-start;
+}
+
+.qa-answer {
+  margin-bottom: 16px;
+}
+
+.qa-label {
+  flex-shrink: 0;
+  width: 40px;
+  font-weight: bold;
+  color: #409eff;
+  margin-right: 8px;
+}
+
+.qa-question .qa-label {
+  color: #e6a23c;
+}
+
+.qa-text {
+  flex: 1;
+  line-height: 1.6;
+  color: #333;
+  word-break: break-word;
+}
+
+.qa-meta {
+  display: flex;
+  gap: 8px;
+  padding-top: 8px;
+  border-top: 1px solid #eee;
+}
+
+.qa-actions {
+  margin-top: 24px;
+  text-align: center;
+  padding-top: 20px;
+  border-top: 1px solid #e8e8e8;
+}
+</style>

+ 17 - 5
src/views/middPage/list.vue

@@ -244,7 +244,7 @@
                   <div style="padding: 5px">
                     <div style="margin-top: 5px; font-size: 12px">
                       {{
-                        row.progress_msg ||
+                        row.progress_msg + " " + row.progress + "%" ||
                         (row.processing_status === 3
                           ? "处理失败"
                           : "正在处理中...")
@@ -466,7 +466,8 @@ import {
   categories,
   literResult,
   getSotaDetails,
-  exportOutcoms
+  exportOutcoms,
+  getProgress
 } from "@/api/knowledge";
 import axios from "axios";
 // 状态映射表
@@ -1269,14 +1270,25 @@ export default {
 
       const checkStatus = async () => {
         try {
-          const response = await literResult(id);
-          if (response.status === 200) {
+        const [statusResponse, progressResponse] = await Promise.all([
+            literResult(id),
+            getProgress([id])
+          ]);
+
+          if (statusResponse.status === 200) {
             const item = this.gpuList.find((item) => item.id === id);
             if (item) {
               // 获取状态信息
-              const literatureInfo = response.data.data.literature_info;
+              const literatureInfo = statusResponse.data.data.literature_info;
               const newStatus = Number(literatureInfo.processing_status);
               const newProgressMsg = literatureInfo.status_description;
+              // 获取进度信息
+              if (progressResponse.status === 200) {
+                const progressInfo = progressResponse.data.data.literature_progress[0];
+                if (progressInfo && progressInfo.literature_id === id) {
+                  this.$set(item, "progress", progressInfo.current_progress || 0);
+                }
+              }
 
               // 更新状态相关数据
               this.$set(item, "processing_status", newStatus);

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác