Explorar o código

Merge branch 'master' of http://173.18.12.196:3000/front/self-constructing_graph

cynthia-qin hai 1 mes
pai
achega
44fb6ce017

+ 2 - 1
.env.development

@@ -1,3 +1,4 @@
 NODE_ENV = development
-# VITE_API_URL = http://173.18.12.205:8005
+# # VITE_API_URL = http://173.18.12.205:8005
 VITE_API_URL = http://192.18.1.242:8000
+# VITE_API_URL = http://192.18.1.235:8000

+ 2 - 2
src/components/EditKBDialog.vue

@@ -67,14 +67,14 @@ const updateKB = async (formData) => {
 
 <style lang="less" scoped>
 .edit-kb-dialog {
-  ::v-deep .el-dialog {
+  :deep(.el-dialog) {
     label {
       margin: 20px 0px 10px;
       display: block;
     }
   }
 
-  ::v-deep .el-form {
+  :deep(.el-form) {
 
     .el-textarea__inner,
     .el-input__wrapper {

+ 2 - 2
src/components/EditKBFileDialog.vue

@@ -119,7 +119,7 @@ function updateInputBox(e, index, key, valueType = 'string') {
 
 <style lang="less" scoped>
 .add-kb-file-dialog {
-  ::v-deep .el-dialog {
+  :deep(.el-dialog) {
     label {
       margin: 20px 0px 10px;
       display: block;
@@ -140,7 +140,7 @@ function updateInputBox(e, index, key, valueType = 'string') {
     }
   }
 
-  ::v-deep .el-form {
+  :deep(.el-form) {
     .input-box {
       &:focus {
         outline: none;

+ 1 - 1
src/components/FileViewer/FileViewer.vue

@@ -180,7 +180,7 @@ onBeforeUnmount(() => {
     z-index: 60;
 
     // overflow: auto;
-    &::v-deep .vue-office-pptx {
+    &:deep(.vue-office-pptx) {
       height: auto;
 
       .vue-office-pptx-main {

+ 6 - 3
src/components/LayoutHeader.vue

@@ -3,8 +3,9 @@
     <div class="logo"></div>
     <div class="menu">
       <el-menu :default-active="currentPath" ref="menuRef" class="el-menu-demo" mode="horizontal">
-        <el-menu-item :index="item.path" v-for="item in routeList" :key="item.name" :class="{ 'external-link-item': isExternalLink(item.path) }"
-          @click="handleMenuClick(item.path)">{{ item.title }}</el-menu-item>
+        <el-menu-item :index="item.path" v-for="item in routeList" :key="item.name"
+          :class="{ 'external-link-item': isExternalLink(item.path) }" @click="handleMenuClick(item.path)">{{ item.title
+          }}</el-menu-item>
       </el-menu>
     </div>
     <!-- 机构切换下拉 -->
@@ -198,12 +199,14 @@ onBeforeUnmount(() => {
       border: none;
     }
 
-    ::v-deep .el-menu {
+    :deep(.el-menu) {
       .el-menu-item {
         font-size: 20px;
       }
     }
+
     .external-link-item {
+
       // 覆盖激活效果
       &.is-active {
         background-color: transparent !important;

+ 25 - 24
src/components/SideMenu.vue

@@ -1,8 +1,6 @@
 <template>
   <div class="left-nav">
-    <el-menu
-      default-active="1-1"
-      class="el-menu-vertical-demo">
+    <el-menu default-active="1-1" class="el-menu-vertical-demo">
       <el-sub-menu index="1">
         <template #title>
           <i class="el-icon-location"></i>
@@ -12,46 +10,47 @@
           <el-menu-item @click="router.push({ name: 'home' })" index="1-1">工作台概览</el-menu-item>
         </el-menu-item-group>
       </el-sub-menu>
-            <el-sub-menu index="2">
+      <el-sub-menu index="2">
         <template #title>
           <i class="el-icon-location"></i>
           <span>工作队列({{ queues.length }})</span>
         </template>
         <el-menu-item-group>
-          <template v-for="(queue,index) in queues" :key="queue.id">
-          <el-menu-item :index="'2' + '-' + index" @click="queueClicked(queue)" >
-            <!-- <template #title> -->
+          <template v-for="(queue, index) in queues" :key="queue.id">
+            <el-menu-item :index="'2' + '-' + index" @click="queueClicked(queue)">
+              <!-- <template #title> -->
               <span>{{ queue.name }}</span>
               <el-tag v-if="queue.type == 'input'" effect="light" round>START</el-tag>
-            <!-- </template> -->
-          </el-menu-item>
-        </template>
+              <!-- </template> -->
+            </el-menu-item>
+          </template>
         </el-menu-item-group>
       </el-sub-menu>
-       <el-sub-menu index="3">
+      <el-sub-menu index="3">
         <template #title>
           <i class="el-icon-location"></i>
           <span>知识图谱</span>
         </template>
         <el-menu-item-group>
-          <el-menu-item index="3-1"  @click="handleMenuClick('graph')">全部图谱</el-menu-item>
+          <el-menu-item index="3-1" @click="handleMenuClick('graph')">全部图谱</el-menu-item>
         </el-menu-item-group>
       </el-sub-menu>
-       <el-sub-menu index="4">
+      <el-sub-menu index="4">
         <template #title>
           <i class="el-icon-location"></i>
           <span>工作人员({{ workers.length }})</span>
         </template>
         <el-menu-item-group>
-        <el-menu-item v-for="worker in workers" :key="worker.id" @click="selectWorker(worker)" :index="'4-' + worker.id">
-          <el-icon>
-            <User />
-          </el-icon>
-          <span>{{ worker.name }}</span>
-          <el-tag :type="worker.status === '空闲' ? 'success' : 'warning'" size="small">
-            {{ worker.status }}
-          </el-tag>
-        </el-menu-item>
+          <el-menu-item v-for="worker in workers" :key="worker.id" @click="selectWorker(worker)"
+            :index="'4-' + worker.id">
+            <el-icon>
+              <User />
+            </el-icon>
+            <span>{{ worker.name }}</span>
+            <el-tag :type="worker.status === '空闲' ? 'success' : 'warning'" size="small">
+              {{ worker.status }}
+            </el-tag>
+          </el-menu-item>
         </el-menu-item-group>
       </el-sub-menu>
     </el-menu>
@@ -115,7 +114,7 @@
 
 <script setup lang="ts">
 
-import { ref, onMounted, defineEmits } from 'vue'
+import { ref, onMounted } from 'vue'
 import { useRouter } from 'vue-router'
 import { User } from '@element-plus/icons-vue'
 import type { WorkQueue, Worker } from '../libs/dataset.ts'
@@ -180,7 +179,7 @@ const workers = ref<Worker[]>(Array.from({ length: 2 }, (_, i) => ({
 })))
 
 const selectedQueue = ref(null)
-const selectedWorker = ref(null)
+const selectedWorker = ref<Worker | null>(null)
 
 const queueClicked = (queue: any) => {
   selectedQueue.value = queue;
@@ -203,6 +202,7 @@ const selectWorker = (worker: Worker) => {
 .left-nav {
   // width: 280px;
   height: 100vh;
+
   // border-right: 0px solid #e4e7ed;
   // padding: 20px;
   // overflow: auto;
@@ -218,6 +218,7 @@ const selectWorker = (worker: Worker) => {
     }
   }
 }
+
 .el-menu-vertical-demo {
   height: 100%;
 }

+ 172 - 177
src/dialogs/GraphNodeDialog.vue

@@ -2,185 +2,179 @@
   <el-dialog v-model="dialogFormVisible" title="图谱节点详情" width="1100" height="600">
     <div id="graph" class="graph">
 
-        <svg id="mindSvg" ref="svgContainer" viewBox="0 0 900 600" width="900" height="600" >                
-              <!-- 定义箭头 -->
-              <defs>
-                <marker id="arrow"
-                        viewBox="0 -5 10 10"
-                        refX="8"
-                        refY="0"
-                        markerWidth="6"
-                        markerHeight="6"
-                        orient="auto">
-                  <path d="M 0,-5 L 10,0 L 0,5" fill="rgb(65, 143, 146)"/>
-                </marker>
-                <pattern id="crossHatch" patternUnits="userSpaceOnUse" width="10" height="10" patternTransform="rotate(45)">
-                  <line x1="0" y1="0" x2="0" y2="10" stroke="lightgrey" stroke-width="1"/>
-                  <line x1="0" y1="0" x2="10" y2="0" stroke="lightgrey" stroke-width="1"/>
-                </pattern>
-              </defs>
-       
-            </svg>
+      <svg id="mindSvg" ref="svgContainer" viewBox="0 0 900 600" width="900" height="600">
+        <!-- 定义箭头 -->
+        <defs>
+          <marker id="arrow" viewBox="0 -5 10 10" refX="8" refY="0" markerWidth="6" markerHeight="6" orient="auto">
+            <path d="M 0,-5 L 10,0 L 0,5" fill="rgb(65, 143, 146)" />
+          </marker>
+          <pattern id="crossHatch" patternUnits="userSpaceOnUse" width="10" height="10" patternTransform="rotate(45)">
+            <line x1="0" y1="0" x2="0" y2="10" stroke="lightgrey" stroke-width="1" />
+            <line x1="0" y1="0" x2="10" y2="0" stroke="lightgrey" stroke-width="1" />
+          </pattern>
+        </defs>
+
+      </svg>
     </div>
   </el-dialog>
 </template>
 
 <script setup lang="ts">
 
-import { ref, onMounted, defineEmits ,nextTick} from 'vue'
+import { ref, onMounted, defineEmits, nextTick } from 'vue'
 import { getNodeNeighbors } from '@/api/GraphApi'
-import svgPanZoom  from 'svg-pan-zoom';
+import svgPanZoom from 'svg-pan-zoom';
 import { ElMessageBox } from 'element-plus';
 const dialogFormVisible = ref(false)
-const nodesData = ref([{ id: 1, label: 'Node 1', direction:"in"}])
-const edgesData = ref([{ from: 1, to: 2 ,fromPos: {x:100,y:100}, toPos: {x:100,y:100}}])
+const nodesData = ref([{ id: 1, label: 'Node 1', direction: "in" }])
+const edgesData = ref([{ from: 1, to: 2, fromPos: { x: 100, y: 100 }, toPos: { x: 100, y: 100 } }])
 const svgContainer = ref()
 const props = defineProps({
-    title: { type: String, required: true, default: '图谱节点详情'},
-    nodeId: { type: Number, required: true, default: 0},
-    graphId: { type: Number, required: true, default: 0}
-  
+  title: { type: String, required: true, default: '图谱节点详情' },
+  nodeId: { type: Number, required: true, default: 0 },
+  graphId: { type: Number, required: true, default: 0 }
+
 })
-const loadNodeNeighbors = (node_id:number) => {
+const loadNodeNeighbors = (node_id: number) => {
   nodesData.value.length = 0
   edgesData.value.length = 0
-    getNodeNeighbors(node_id, props.graphId).then((res:any) => {
-      for (let i = 0; i < res.records.length; i++) {
-        const element = res.records[i];
-        console.log(element)
-        nodesData.value.push({id:element.id, label:element.name, direction:element.direction})   
-
-      }        
-      drawGraph(node_id)
-    })
+  getNodeNeighbors(node_id, props.graphId).then((res: any) => {
+    for (let i = 0; i < res.records.length; i++) {
+      const element = res.records[i];
+      console.log(element)
+      nodesData.value.push({ id: element.id, label: element.name, direction: element.direction })
+
+    }
+    drawGraph(node_id)
+  })
 }
-function handleNodeClick(nodeId){
-  loadNodeNeighbors(Number(nodeId)) 
+function handleNodeClick(nodeId: any) {
+  loadNodeNeighbors(Number(nodeId))
   // var result = ElMessageBox.confirm('是否加载该节点的邻居节点?', '提示', )
   // result.then(() => {
-    
+
   // })
 }
-const drawGraph = (node_id:number) => {
-    const svg = svgContainer.value //document.getElementById('mindSvg') as SVGElement | null;
-    if (svg == null) {
-        console.log("svg is null")
-        console.log(svgContainer.value)
-        return; 
+const drawGraph = (node_id: number) => {
+  const svg = svgContainer.value //document.getElementById('mindSvg') as SVGElement | null;
+  if (svg == null) {
+    console.log("svg is null")
+    console.log(svgContainer.value)
+    return;
+  }
+  svg.innerHTML = '';
+  console.log("drawGraph", svg)
+  const svgWidth = svg.width.baseVal.value
+  const svgHeight = svg.height.baseVal.value
+  console.log("svgWidth", svgWidth, "svgHeight", svgHeight)
+  // 计算左边,中间,和右边的节点数量
+  var totalNodes = nodesData.value.length
+  var leftNodesCount = 0
+  var rightNodesCount = 0
+  nodesData.value.forEach(node => {
+    if (node.direction == 'in') {
+      leftNodesCount += 1
+    } else if (node.direction == 'out') {
+      rightNodesCount += 1
     }
-    svg.innerHTML = '';
-    console.log("drawGraph", svg)
-    const svgWidth = svg.width.baseVal.value
-    const svgHeight = svg.height.baseVal.value
-    console.log("svgWidth", svgWidth, "svgHeight", svgHeight)
-    // 计算左边,中间,和右边的节点数量
-    var totalNodes = nodesData.value.length    
-    var leftNodesCount = 0
-    var rightNodesCount = 0
-    nodesData.value.forEach(node => {
-     if (node.direction=='in') {
-        leftNodesCount += 1
-     } else if (node.direction=='out') {
-        rightNodesCount += 1
-     }
-    })
-    var rectHeight = 40
-    var rectWidth = 120
-    var rectMargin = 20
-    var totalLeftHeight = leftNodesCount * (rectHeight + rectMargin) - rectMargin
-    var totalRightHeight = rightNodesCount * (rectHeight + rectMargin) - rectMargin
-    var leftTop = [svgWidth / 4, (svgHeight - totalLeftHeight) / 2] // 左边顶部节点的位置    
-    var rightTop = [svgWidth * 3 / 4, (svgHeight - totalRightHeight) / 2] // 左边顶部节点的位置    
-    const centerPos = {x:svgWidth / 2 , y:svgHeight / 2 }
-    var gLinesGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g')
-    var gRectsGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g')
-    svg.appendChild(gLinesGroup)
-    svg.appendChild(gRectsGroup)
-    // 绘制节点
-    var left_index = 1
-    var right_index = 1
-    nodesData.value.forEach(node => {
-        console.log("draw node:",node)
-        const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
-        if (node.direction=="in") {
-          var pos = {x:leftTop[0]- rectWidth/2 , y:leftTop[1] + (left_index - 1) * (rectHeight + rectMargin) }
-          g.setAttribute('transform', `translate(${pos.x}, ${pos.y})`);
-          left_index += 1
-          pos.x = pos.x + rectWidth/2
-          pos.y = pos.y + rectHeight/2
-          edgesData.value.push({from:node.id, to:node_id, fromPos: pos, toPos: centerPos})
-        } else if (node.direction=="out") {
-          var pos ={x:rightTop[0]- rectWidth/2 ,y:rightTop[1] + (right_index - 1) * (rectHeight + rectMargin)}
-          g.setAttribute('transform', `translate(${pos.x}, ${pos.y})`); 
-          right_index += 1        
-          pos.x = pos.x + rectWidth/2
-          pos.y = pos.y + rectHeight/2  
-          edgesData.value.push({from:node_id, to:node.id, fromPos: centerPos, toPos: pos})
-        } else if (node.direction=="self") {
-          g.setAttribute('transform', `translate(${svgWidth / 2 - rectWidth/2}, ${svgHeight / 2 - rectHeight/2})`);
-        }
-        const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
-        rect.setAttribute('width', '120');
-        rect.setAttribute('height', '40');
-        rect.setAttribute('data-node-id', node.id.toString());
-        if (node.direction=="self") {
-          rect.setAttribute('fill', '#418f92'); 
-        } else {
-          
-          rect.setAttribute('fill', '#f0f0f0');
-        }
-        //rect.setAttribute('stroke', '#418f92');
-        rect.setAttribute('rx', '5');
-        rect.setAttribute('class', 'node_rect');
-        
-        const link = document.createElementNS('http://www.w3.org/2000/svg', 'a')
-        
-        link.setAttribute('data-node-id', node.id.toString())
-        link.setAttribute('class', 'node_text')
-        const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
-        text.setAttribute('x', '60');
-        text.setAttribute('y', '25');
-        text.setAttribute('text-anchor', 'middle');     
-  
-        text.textContent = node.label;
-        link.appendChild(text)
-        
-        g.appendChild(rect);
-        g.appendChild(link);
-        gRectsGroup.appendChild(g);
-        
-        console.log("draw node finished")
-        
-    });
-    // 绘制边
-    edgesData.value.forEach(edge => {
-        const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
-        line.setAttribute('x1', `${edge.fromPos.x}`);
-        line.setAttribute('y1', `${edge.fromPos.y}`);
-        line.setAttribute('x2', `${edge.toPos.x}`);
-        line.setAttribute('y2', `${edge.toPos.y}`);
-        line.setAttribute('stroke', '#418f92');
-        line.setAttribute('stroke-width', '2');
-
-        line.setAttribute('style', 'z-index:0');
-        gLinesGroup.appendChild(line);
+  })
+  var rectHeight = 40
+  var rectWidth = 120
+  var rectMargin = 20
+  var totalLeftHeight = leftNodesCount * (rectHeight + rectMargin) - rectMargin
+  var totalRightHeight = rightNodesCount * (rectHeight + rectMargin) - rectMargin
+  var leftTop = [svgWidth / 4, (svgHeight - totalLeftHeight) / 2] // 左边顶部节点的位置    
+  var rightTop = [svgWidth * 3 / 4, (svgHeight - totalRightHeight) / 2] // 左边顶部节点的位置    
+  const centerPos = { x: svgWidth / 2, y: svgHeight / 2 }
+  var gLinesGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g')
+  var gRectsGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g')
+  svg.appendChild(gLinesGroup)
+  svg.appendChild(gRectsGroup)
+  // 绘制节点
+  var left_index = 1
+  var right_index = 1
+  nodesData.value.forEach(node => {
+    console.log("draw node:", node)
+    const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
+    if (node.direction == "in") {
+      var pos = { x: leftTop[0] - rectWidth / 2, y: leftTop[1] + (left_index - 1) * (rectHeight + rectMargin) }
+      g.setAttribute('transform', `translate(${pos.x}, ${pos.y})`);
+      left_index += 1
+      pos.x = pos.x + rectWidth / 2
+      pos.y = pos.y + rectHeight / 2
+      edgesData.value.push({ from: node.id, to: node_id, fromPos: pos, toPos: centerPos })
+    } else if (node.direction == "out") {
+      var pos = { x: rightTop[0] - rectWidth / 2, y: rightTop[1] + (right_index - 1) * (rectHeight + rectMargin) }
+      g.setAttribute('transform', `translate(${pos.x}, ${pos.y})`);
+      right_index += 1
+      pos.x = pos.x + rectWidth / 2
+      pos.y = pos.y + rectHeight / 2
+      edgesData.value.push({ from: node_id, to: node.id, fromPos: centerPos, toPos: pos })
+    } else if (node.direction == "self") {
+      g.setAttribute('transform', `translate(${svgWidth / 2 - rectWidth / 2}, ${svgHeight / 2 - rectHeight / 2})`);
+    }
+    const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
+    rect.setAttribute('width', '120');
+    rect.setAttribute('height', '40');
+    rect.setAttribute('data-node-id', node.id.toString());
+    if (node.direction == "self") {
+      rect.setAttribute('fill', '#418f92');
+    } else {
+
+      rect.setAttribute('fill', '#f0f0f0');
+    }
+    //rect.setAttribute('stroke', '#418f92');
+    rect.setAttribute('rx', '5');
+    rect.setAttribute('class', 'node_rect');
+
+    const link = document.createElementNS('http://www.w3.org/2000/svg', 'a')
+
+    link.setAttribute('data-node-id', node.id.toString())
+    link.setAttribute('class', 'node_text')
+    const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
+    text.setAttribute('x', '60');
+    text.setAttribute('y', '25');
+    text.setAttribute('text-anchor', 'middle');
+
+    text.textContent = node.label;
+    link.appendChild(text)
+
+    g.appendChild(rect);
+    g.appendChild(link);
+    gRectsGroup.appendChild(g);
+
+    console.log("draw node finished")
+
+  });
+  // 绘制边
+  edgesData.value.forEach(edge => {
+    const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
+    line.setAttribute('x1', `${edge.fromPos.x}`);
+    line.setAttribute('y1', `${edge.fromPos.y}`);
+    line.setAttribute('x2', `${edge.toPos.x}`);
+    line.setAttribute('y2', `${edge.toPos.y}`);
+    line.setAttribute('stroke', '#418f92');
+    line.setAttribute('stroke-width', '2');
+
+    line.setAttribute('style', 'z-index:0');
+    gLinesGroup.appendChild(line);
+  });
+  // document.querySelectorAll('.node_rect').forEach((rect:any) => {
+  //     rect.addEventListener('click', () => {
+  //       const nodeId = rect.getAttribute('data-node-id');
+  //       console.log('Node clicked:', nodeId);
+  //       handleNodeClick(nodeId)
+  //     });
+  //   }) 
+
+  document.querySelectorAll('.node_text').forEach((rect: any) => {
+    rect.addEventListener('click', () => {
+      const nodeId = rect.getAttribute('data-node-id');
+      console.log('Node clicked:', nodeId);
+      handleNodeClick(nodeId)
     });
-    // document.querySelectorAll('.node_rect').forEach((rect:any) => {
-    //     rect.addEventListener('click', () => {
-    //       const nodeId = rect.getAttribute('data-node-id');
-    //       console.log('Node clicked:', nodeId);
-    //       handleNodeClick(nodeId)
-    //     });
-    //   }) 
-      
-    document.querySelectorAll('.node_text').forEach((rect:any) => {
-        rect.addEventListener('click', () => {
-          const nodeId = rect.getAttribute('data-node-id');
-          console.log('Node clicked:', nodeId);
-          handleNodeClick(nodeId)
-        });
-      }) 
-    
+  })
+
 }
 let panZoomController: any = null;
 
@@ -189,33 +183,34 @@ onMounted(() => {
 
   });
 });
-const showDialog = (visible:boolean = true, nodeId:number) => {
-    dialogFormVisible.value = visible
-    
-    loadNodeNeighbors(nodeId)
+const showDialog = (visible: boolean = true, nodeId: number) => {
+  dialogFormVisible.value = visible
+
+  loadNodeNeighbors(nodeId)
 }
 defineExpose({ showDialog })
 </script>
 <style scoped>
 .graph {
-    background-color:rgb(255, 255, 255);
-    position: relative;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
+  background-color: rgb(255, 255, 255);
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
 }
-  
+
 .edge_line {
-    stroke: #418f92;
-    stroke-width: 20;
-    marker-end: url(#arrow);
-    z-index: 1;
+  stroke: #418f92;
+  stroke-width: 20;
+  marker-end: url(#arrow);
+  z-index: 1;
 }
+
 .node_rect {
-    font-size: 14px;
-    font-weight: bold;
-    background-color: #cecece;
-    z-index: 10;
+  font-size: 14px;
+  font-weight: bold;
+  background-color: #cecece;
+  z-index: 10;
 }
 </style>

+ 32 - 21
src/dialogs/OCRDialog.vue

@@ -63,7 +63,7 @@
             </div>
             <el-scrollbar class="management-content-middle">
               <el-table :data="knowledgeBase.filesList" ref="KBTableRef">
-                <el-table-column type="selection" width="30" />
+                <el-table-column :selectable="handleSelectable" type="selection" width="30" />
                 <el-table-column label="#" prop="index" width="50" />
                 <el-table-column prop="file_name" min-width="150" label="标题">
                   <template #default="{ row }">
@@ -85,20 +85,21 @@
                 <el-table-column prop="created_at" label="上传时间" width="150" />
                 <el-table-column prop="" label="状态" width="80">
                   <template #default="{ row }">
-                    <span v-if="row.isValid">
+                    <span v-if="row.status">
                       <i class="circle" type="success"></i>
                       <el-text type="success">可用</el-text>
                     </span>
                     <span v-else>
-                      <i class="circle" type="warning"></i>
-                      <el-text type="warning">异常</el-text>
+                      <i class="circle" type="danger"></i>
+                      <el-text type="danger">禁用</el-text>
                     </span>
                   </template>
                 </el-table-column>
                 <el-table-column fixed="right" label="操作" min-width="55">
                   <template #default="{ row }">
                     <div class="operation">
-                      <el-button link type="primary" @click="handleImportFiles([toRaw(row)])">导入</el-button>
+                      <el-button link type="primary" :disabled="!row.status"
+                        @click="handleImportFiles([toRaw(row)])">导入</el-button>
                     </div>
                   </template>
                 </el-table-column>
@@ -233,7 +234,7 @@ const props = defineProps({
   job_creator: { type: String, required: false, default: 'admin' },
   status: { type: Number, required: false, default: 0 },
 })
-const emit = defineEmits(['update:modelValue', 'success', 'cancel','closed'])
+const emit = defineEmits(['update:modelValue', 'success', 'cancel', 'closed'])
 const showDialog = (visible: boolean = true) => {
   // console.log("OCRDialog showDialog")
   if (upload.value) {
@@ -244,11 +245,11 @@ const showDialog = (visible: boolean = true) => {
 
 // 清除上传文件列表
 const clearFileList = () => {
-    fileList.value = []
-    if (upload.value) {
-        upload.value.clearFiles()
-    }
-    importedFileHashes.value = [] // 清空已导入文件的哈希值记录
+  fileList.value = []
+  if (upload.value) {
+    upload.value.clearFiles()
+  }
+  importedFileHashes.value = [] // 清空已导入文件的哈希值记录
 }
 function handleGetKnowledgeBase() {
   getKnowledgeBase().then((response: any) => {
@@ -304,6 +305,10 @@ function fetchFile(fileName: string, fileUrl: string) {
       console.log(error);
     });
 }
+function handleSelectable(row: any, index: number) {
+  // console.log(row, index)
+  return row.status
+}
 function handleSelectedImport() {
   const SelectionRows = KBTableRef.value.getSelectionRows()
   handleImportFiles(toRaw(SelectionRows))
@@ -423,7 +428,7 @@ async function calculateFileHash(file: File) {
   // const hashArray = Array.from(new Uint8Array(hashBuffer));
   // const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
   // return hashHex;
-    // 使用 crypto-js 计算哈希值
+  // 使用 crypto-js 计算哈希值
   return new Promise((resolve, reject) => {
     const reader = new FileReader();
     reader.readAsArrayBuffer(file);
@@ -447,7 +452,7 @@ function handleImportFiles(filesList: any[]) {
       const rawFile = new File([response.data], file_name, { type: response.data.type });
       const fileHash = await calculateFileHash(rawFile);
 
-      if (importedFileHashes.value.includes(fileHash)) {
+      if (importedFileHashes.value.includes(fileHash as string)) {
         ElMessage({
           message: `文件“${file_name}”已导入过,不能重复导入`,
           type: 'info',
@@ -459,7 +464,7 @@ function handleImportFiles(filesList: any[]) {
       const file = rawFile as UploadRawFile;
       file.uid = genFileId();
       upload.value!.handleStart(file);
-      importedFileHashes.value.push(fileHash);
+      importedFileHashes.value.push(fileHash as string);
       ElMessage({
         message: `文件“${file_name}”导入成功`,
         type: 'success',
@@ -508,18 +513,18 @@ const handleConfirm = () => {
     }
   })
 }
-defineExpose({ showDialog,clearFileList })
+defineExpose({ showDialog, clearFileList })
 
 function handleClosed() {
   knowledgeBase.value.visible = false
-  clearFileList ()
+  clearFileList()
 }
 
 watch(() => knowledgeBase.value.activeId, (newValue) => {
   debounceGetKBfileList()
   // console.log('activeId', newValue)
 })
-watch(() =>knowledgeBase.value.visible, (newValue) => {
+watch(() => knowledgeBase.value.visible, (newValue) => {
   if (!newValue) {
     KBTableRef.value.clearSelection() // 清除选择
   }
@@ -707,7 +712,7 @@ onMounted(() => {
       // overflow: auto;
       padding-right: 10px;
 
-      ::v-deep .el-scrollbar {
+      :deep(.el-scrollbar) {
         .el-table__header-wrapper {
           position: sticky;
           top: 0;
@@ -721,7 +726,7 @@ onMounted(() => {
     }
   }
 
-  &::v-deep .el-table {
+  &:deep(.el-table) {
     min-width: 0px;
     max-width: 100%;
 
@@ -748,6 +753,10 @@ onMounted(() => {
       &:is([type='warning']) {
         background-color: #E6A23C;
       }
+
+      &:is([type='danger']) {
+        background-color: #F56C6C;
+      }
     }
 
     .operation {
@@ -782,7 +791,7 @@ onMounted(() => {
     background: white;
     display: inline-block;
 
-    ::v-deep .el-input__wrapper {
+    :deep(.el-input__wrapper) {
       background-color: #EFF1F5;
       border-radius: 10px;
     }
@@ -797,8 +806,10 @@ onMounted(() => {
     // background-color: @bgColor;
     display: flex;
     padding: 0px 5px;
+    justify-content: end;
+    margin: 10px 0px 5px;
 
-    ::v-deep.el-pagination {
+    :deep(.el-pagination) {
       background-color: #fff;
       // justify-content: end;
       margin-left: auto;

+ 34 - 34
src/dialogs/QueueSelectDialog.vue

@@ -1,23 +1,23 @@
 <template>
     <el-dialog :title="title" v-model="dialogFormVisible">
-    <el-form :model="form">
-        <el-form-item label="任务名称" :label-width="formLabelWidth">
-        <el-input v-model="form.job_name" autocomplete="off" :readonly="true"></el-input>
-        </el-form-item>
-        <el-form-item label="选择队列" :label-width="formLabelWidth">
-        <el-select v-model="form.selectedQueue" placeholder="请选择任务的新队列">
-            <template v-for="queue in props.queue_data">
-                <el-option :label="queue.title" :value="queue.id"></el-option>
-            </template>
+        <el-form :model="form">
+            <el-form-item label="任务名称" :label-width="formLabelWidth">
+                <el-input v-model="form.job_name" autocomplete="off" :readonly="true"></el-input>
+            </el-form-item>
+            <el-form-item label="选择队列" :label-width="formLabelWidth">
+                <el-select v-model="form.selectedQueue" placeholder="请选择任务的新队列">
+                    <template v-for="queue in props.queue_data">
+                        <el-option :label="queue.title" :value="queue.id"></el-option>
+                    </template>
 
-        </el-select>
-        </el-form-item>
-    </el-form>
-    <div slot="footer">
-        <el-button type="primary" @click="handleConfirm">确 定</el-button>
-        <el-button @click="dialogFormVisible = false">取 消</el-button>
-    </div>
-</el-dialog>
+                </el-select>
+            </el-form-item>
+        </el-form>
+        <div slot="footer">
+            <el-button type="primary" @click="handleConfirm">确 定</el-button>
+            <el-button @click="dialogFormVisible = false">取 消</el-button>
+        </div>
+    </el-dialog>
 
 </template>
 
@@ -26,28 +26,28 @@
 
 
 import { readonly, ref } from 'vue'
-import {  putQueueJob } from '@/api/AgentApi'
+import { putQueueJob } from '@/api/AgentApi'
 import type { JobData } from '@/api/AgentApi'
 const dialogFormVisible = ref(false)
-const formLabelWidth= ref('120px')
+const formLabelWidth = ref('120px')
 const form = ref({
-  job_id: 0,
-  job_category: '',
-  job_name: '',
-  queue_category: '',
-  queue_name: '',
-  selectedQueue: '',
+    job_id: 0,
+    job_category: '',
+    job_name: '',
+    queue_category: '',
+    queue_name: '',
+    selectedQueue: '',
 })
 const props = defineProps({
-    title: { type: String, required: true , default: '工作'},
-    queue_data: { type: Object, required: true, default: {id:"0",  queue_category:"", queue_name:""}}
+    title: { type: String, required: true, default: '工作' },
+    queue_data: { type: Object, required: true, default: { id: "0", queue_category: "", queue_name: "" } }
 })
-const emit = defineEmits(['update:modelValue','success','cancel'])
-const showDialog = (data:JobData, visible:boolean = true) => {
+const emit = defineEmits(['update:modelValue', 'success', 'cancel'])
+const showDialog = (data: JobData, visible: boolean = true) => {
     console.log("OCRDialog showDialog")
     dialogFormVisible.value = visible
     if (data == null) {
-      return
+        return
     }
     form.value.job_name = data.job_name;
     form.value.job_category = data.job_category;
@@ -55,17 +55,17 @@ const showDialog = (data:JobData, visible:boolean = true) => {
 }
 const handleConfirm = () => {
     console.log('submit', form.value)
-    props.queue_data.forEach(element => {
+    props.queue_data.forEach((element: any) => {
         if (element.id == form.value.selectedQueue) {
             form.value.queue_category = element.category;
-            form.value.queue_name = element.name; 
+            form.value.queue_name = element.name;
         }
     });
 
 
     var params = { job_id: form.value.job_id, queue_category: form.value.queue_category, queue_name: form.value.queue_name }
-    
-    putQueueJob(params).then((res:any) => {
+
+    putQueueJob(params).then((res: any) => {
         emit('success', res.records[0])
     })
 }

+ 25 - 21
src/dialogs/TextViewDialog.vue

@@ -1,54 +1,58 @@
 <template>
     <el-dialog v-model="dialogVisible" style="width:1200px;height:600px;" :title="props.title">
-        
+
         <template #header>
-        <div class="dialog-header">
-            <span class="dialog-title">{{props.title}}</span>
-        </div>
+            <div class="dialog-header">
+                <span class="dialog-title">{{ props.title }}</span>
+            </div>
         </template>
         <div class="dialog-body">
-            <pre>{{props.content}}</pre>
+            <pre>{{ props.content }}</pre>
         </div>
         <template #footer>
-        <div class="dialog-footer">
-            <el-button @click="dialogVisible = false">取消</el-button>
-            <el-button type="primary" @click="dialogVisible = false">
-            确定
-            </el-button>
-        </div>
+            <div class="dialog-footer">
+                <el-button @click="dialogVisible = false">取消</el-button>
+                <el-button type="primary" @click="dialogVisible = false">
+                    确定
+                </el-button>
+            </div>
         </template>
     </el-dialog>
 </template>
 <script setup lang="ts">
-import { ref, defineProps, defineEmits, watch } from 'vue'
+import { ref, watch } from 'vue'
 const props = defineProps({
-    title: { type: String, required: true, default: '文件内容'},
-    content: { type: String, required: true, default: '文件内容'},
+    title: { type: String, required: true, default: '文件内容' },
+    content: { type: String, required: true, default: '文件内容' },
 })
 const emit = defineEmits(['update:modelValue'])
 const dialogVisible = ref(false)
 
-const showDialog = (visible:boolean = true) => {
-    dialogVisible.value = visible 
+const showDialog = (visible: boolean = true) => {
+    dialogVisible.value = visible
 }
-defineExpose({ showDialog})
+defineExpose({ showDialog })
 </script>
 <style scoped>
 .dialog-header {
     display: flex;
     justify-content: space-between;
-    align-items: center; 
+    align-items: center;
 }
 
 .dialog-body {
     width: 100%;
-    height: 450px; /* 可以根据需要调整 */
-    overflow-y: auto; /* 当内容超出时显示滚动条 */ 
+    height: 450px;
+    /* 可以根据需要调整 */
+    overflow-y: auto;
+    /* 当内容超出时显示滚动条 */
     text-wrap: wrap;
     word-wrap: normal;
 }
+
 .dialog-footer {
     display: flex;
-    justify-content: flex-end; /* 按钮靠右对齐 */ 
+    justify-content: flex-end;
+    /* 按钮靠右对齐 */
 }
 </style>

+ 1 - 1
src/views/KMPlatform/Home/Home.vue

@@ -104,7 +104,7 @@ function handleModuleClick(path: string) {
 function handleLogin(event: any) {
   const { type, status } = event.data
   if (type === 'login' && status === 'ok') {
-    // alert('登录成功')
+    console.log('登录成功')
     clearInterval(timer)
   }
 }

+ 8 - 8
src/views/KMPlatform/KGBuilder/ETM/EntityTypeManagement.vue

@@ -60,7 +60,7 @@ function handleNewlyAdd() {
   // margin: 5px;
   background: white;
 
-  ::v-deep .el-input__wrapper {
+  :deep(.el-input__wrapper) {
     background-color: #EFF1F5;
     border-radius: 10px;
   }
@@ -99,19 +99,19 @@ function handleNewlyAdd() {
   footer {}
 
 
-  .elTable ::v-deep .el-table__header-wrapper table,
-  .elTable ::v-deep .el-table__body-wrapper table {
+  .elTable :deep(.el-table__header-wrapper table),
+  .elTable :deep(.el-table__body-wrapper table) {
     width: 100% !important;
   }
 
-  .elTable ::v-deep .el-table__body,
-  .elTable ::v-deep .el-table__footer,
-  .elTable ::v-deep .el-table__header {
+  .elTable :deep(.el-table__body),
+  .elTable :v-deep(.el-table__footer),
+  .elTable :v-deep(.el-table__header) {
     table-layout: auto;
   }
 
-  .elTable ::v-deep .el-table__empty-block,
-  .elTable ::v-deep .el-table__body {
+  .elTable :v-deep(.el-table__empty-block),
+  .elTable :v-deep(.el-table__body) {
     width: 100% !important;
   }
 }

+ 12 - 10
src/views/KMPlatform/KnowledgeBase/KM/KnowledgeManagement.vue

@@ -7,7 +7,7 @@
     <main>
       <div class="aside">
         <div class="name">{{ KBData.name }}</div>
-        <div class="tags">{{ KBData.tags }}</div>
+        <div class="tags">{{ Array.isArray(KBData.tags) && KBData.tags.join("、") }}</div>
         <div class="description">{{ KBData.description }}</div>
         <!-- <div class="other">无关联应用ⓘ</div> -->
       </div>
@@ -61,7 +61,7 @@
                     <i class="circle" type="danger"></i>
                     <el-text type="danger">禁用</el-text>
                   </span>
-                  <el-switch v-model="row.status" @change="handleStatusChange(row.id,row.status)"></el-switch>
+                  <el-switch v-model="row.status" @change="handleStatusChange(row.id, row.status)"></el-switch>
                 </div>
               </template>
             </el-table-column>
@@ -171,23 +171,25 @@ const handleCloseViewer = () => {
   viewFileData.value.show = false;
 };
 // 修改状态
-const handleStatusChange = async (id,status) => {
+const handleStatusChange = async (id, status) => {
   console.log('handleStatusChange', status)
-  try{
-   await proxy.$http.get(api.files + `${id}/changeStatus`, {   params: {
-      status: status 
-      }})
+  try {
+    await proxy.$http.get(api.files + `${id}/changeStatus`, {
+      params: {
+        status: status
+      }
+    })
     ElMessage({
       message: '状态修改成功',
       type: 'success',
     })
   }
   catch (e) {
-    console.log(e)  
+    console.log(e)
     ElMessage({
       message: '状态修改失败',
       type: 'error',
-    })  
+    })
     let index = filesList.value.findIndex(item => item.id === id)
     filesList.value[index].status = !status // 恢复原状态
   }
@@ -392,7 +394,7 @@ onMounted(() => {
       }
     }
 
-    &::v-deep .el-table {
+    &:v-deep(.el-table) {
       min-width: 0px;
       max-width: 100%;