yangg 1 dia atrás
pai
commit
22ca74a620
1 arquivos alterados com 157 adições e 9 exclusões
  1. 157 9
      src/components/SystemGraph/index.vue

+ 157 - 9
src/components/SystemGraph/index.vue

@@ -1,5 +1,15 @@
 <template>
   <div class="system-graph">
+    <div class="system-list">
+      <div 
+        class="system-item" 
+        v-for="item in systemList" 
+        :key="item.id"
+        :style="{ backgroundColor: item.color || '#f0f0f0' }"
+      >
+        <div class="system-item-label">{{ item.name }}</div>
+      </div>
+    </div>
     <div id="container" ref="container"></div>
    <!--  <div class="control-panel">
       <button @click="handleMatch">匹配模式</button>
@@ -17,7 +27,7 @@ const container = ref(null);
 let graph = null;
 
 // 系统集成数据
-const systemData = {
+/* const systemData = {
   nodes: [
     {
       id: 'ERP',
@@ -268,9 +278,13 @@ const systemData = {
       id: 'edge-pms-wms1'
     }
   ]
-};
+}; */
+const systemData = ref({
+  nodes: [],
+  edges: []
+});
 
-const graphData = ref(systemData);
+// 移除不必要的 graphData ref
 
 // 处理窗口大小变化
 const handleResize = () => {
@@ -288,6 +302,11 @@ const getGraphOptions = () => {
     width,
     height,
     autoFit: 'view',
+    animate: true, // 开启动画
+    animateCfg: {
+      duration: 1000, // 动画时长
+      easing: 'easeInOutQuad', // 动画曲线
+    },
     modes: {
       default: ['drag-canvas', 'zoom-canvas', 'drag-node', 'click-select'],
     },
@@ -397,9 +416,9 @@ const getGraphOptions = () => {
 };
 
 const handleMatch = () => {
-  if (!graphData.value || !graph) return;
+  if (!systemData.value || !graph) return;
   
-  const matches = GADDI(graphData.value, pattern, true, undefined, undefined, 'cluster', 'cluster');
+  const matches = GADDI(systemData.value, pattern, true, undefined, undefined, 'cluster', 'cluster');
   matches.forEach((match, i) => {
     graph.updatePlugin({
       key: `hull-${i}`,
@@ -409,13 +428,96 @@ const handleMatch = () => {
   graph.render();
 };
 
-onMounted(() => {
+const systemList = ref([]);
+
+const transformSystemsToArray = (systems) => {
+  return Object.entries(systems).map(([name, data]) => ({
+    id: name,
+    name: name,
+    color: data.color,
+    modules: data.modules,
+    connections: data.connections
+  }));
+};
+
+const getData = async () => {
   try {
+    const res = await fetch(`${import.meta.env.VITE_BASE_AI_API}/api/agents/system-integration/`);
+    const data = await res.json();
+    systemData.value = {
+      nodes: data.data.nodes,
+      edges: data.data.edges
+    };
+    
+    // 转换系统数据为数组格式
+    systemList.value = transformSystemsToArray(data.data.systems);
+    console.log('转换后的系统列表:', systemList.value);
+    
+    // 如果图表已经初始化,更新数据
+    if (graph) {
+      graph.changeData(systemData.value);
+      graph.render();
+    }
+  } catch (error) {
+    console.error('获取数据失败:', error);
+  }
+}
+
+// 节点入场动画
+const nodeAnimateConfig = {
+  enter: {
+    style: {
+      opacity: 0,
+      size: 0,
+    },
+    animate: {
+      size: {
+        value: 30,
+        duration: 1000,
+        easing: 'easeInOutQuad',
+      },
+      opacity: {
+        value: 1,
+        duration: 1000,
+        easing: 'easeInOutQuad',
+      },
+    },
+  },
+};
+
+// 边入场动画
+const edgeAnimateConfig = {
+  enter: {
+    style: {
+      opacity: 0,
+      lineWidth: 0,
+    },
+    animate: {
+      opacity: {
+        value: 1,
+        duration: 1000,
+        delay: 800, // 延迟执行,等节点动画开始后
+        easing: 'easeInOutQuad',
+      },
+      lineWidth: {
+        value: 2,
+        duration: 1000,
+        delay: 800,
+        easing: 'easeInOutQuad',
+      },
+    },
+  },
+};
+
+onMounted(async () => {
+  try {
+    // 先获取数据
+    await getData();
     // 初始化图形
     graph = new Graph({
       ...getGraphOptions(),
       container: container.value,
-      data: graphData.value,
+      data: systemData.value,  // 使用 systemData.value 
       autoFit: 'view',
       behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element'],
       layout: {
@@ -423,7 +525,7 @@ onMounted(() => {
         preventOverlap: true,
         nodeStrength: -100,
         edgeStrength: 0.1,
-        nodeSize: 60,
+        nodeSize: 30,
         nodeSpacing: 100,
         linkDistance: 200,
         gravity: 1,
@@ -434,13 +536,16 @@ onMounted(() => {
         center: [400, 300]
       },
       node: {
+        ...nodeAnimateConfig,
         style: {
           labelPlacement: 'center',
           labelText: (d) => d.label,
           stroke: '#61DDAA',
           lineWidth: 1,
           labelFontSize: 6,
-          labelFill: '#fff',
+          // labelOverflow: 'truncate',
+          
+         /*  labelFill: '#fff', */
         },
         labelCfg: {
           style: {
@@ -456,6 +561,7 @@ onMounted(() => {
         },
       },
       edge: {
+        ...edgeAnimateConfig,
         style: {
           endArrow: true,
         },
@@ -482,6 +588,12 @@ onMounted(() => {
           members: [],
         },
       ],
+      layout: {
+        type: 'd3-force',
+        collide: {
+          strength: 0.5,
+        },
+      },
     });
     
     graph.render();
@@ -520,7 +632,43 @@ onUnmounted(() => {
   display: flex;
   flex-direction: column;
   align-items: center;
+}
 
+.system-list {
+  width: 100%;
+  padding: 20px;
+  display: flex;
+  
+  gap: 10px;
+  justify-content: flex-start;
+  flex-wrap: wrap;
+}
+
+.system-item {
+  padding: 10px 10px;
+  border-radius: 6px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  min-width: 120px;
+  justify-content: center;
+}
+
+.system-item:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 4px 8px rgba(0,0,0,0.15);
+  opacity: 0.9;
+}
+
+.system-item-label {
+  color: #fff;
+  font-size: 14px;
+  font-weight: 500;
+  text-shadow: 0 1px 2px rgba(0,0,0,0.1);
+  text-align: center;
 }
 
 #container {