1- import { useMemo , useEffect , type FC } from 'react' ;
1+ import { useMemo , useEffect , type FC , useRef } from 'react' ;
22import TreeGraphComponent from '@/compoments/AntdCharts/G6Tree' ;
33import { Empty , Radio , Steps } from 'antd' ;
44import { targetRouteMap } from './compoments/utils' ;
5- import { useRequest } from 'ahooks' ;
5+ import { useRequest , useUpdateEffect } from 'ahooks' ;
66import { getAttackPath } from '@/apis/MessageCollectApi' ;
77import type { TTaskDetailHeaderGroups } from './types' ;
8+ import type { TreeGraphData } from '@antv/g6' ;
89
910interface TTaskRoadmpProps {
1011 setHeaderGroupValue : ( value : TTaskDetailHeaderGroups ) => void ;
@@ -17,13 +18,81 @@ interface TTaskRoadmpProps {
1718 } [ ] ;
1819}
1920
21+ export const mergeTree = (
22+ oldNode : TreeGraphData ,
23+ newNode : TreeGraphData ,
24+ ) : TreeGraphData => {
25+ const oldChildren = oldNode . children ?? [ ] ;
26+ const newChildren = newNode . children ?? [ ] ;
27+
28+ const newMap = new Map ( newChildren . map ( ( c ) => [ c . id , c ] ) ) ;
29+
30+ const mergedChildren = oldChildren . map ( ( oldChild , index , arr ) => {
31+ const newChild = newMap . get ( oldChild . id ) ;
32+ let merged : TreeGraphData = newChild
33+ ? mergeTree ( oldChild , newChild )
34+ : { id : oldChild . id , children : oldChild . children ?? [ ] } ;
35+
36+ // 上一节点和上上节点
37+ const prev1 = index > 0 ? arr ?. [ index - 1 ] : undefined ;
38+ const prev2 = index > 1 ? arr ?. [ index - 2 ] : undefined ;
39+
40+ [ 'x' , 'y' , 'depth' , 'size' ] . forEach ( ( key ) => {
41+ const k = key as keyof TreeGraphData ;
42+ const val = merged [ k ] ;
43+
44+ if ( val === null || val === undefined ) {
45+ const p1 = prev1 ?. [ k ] ?? 40 ;
46+ const p2 = prev2 ?. [ k ] ?? 0 ;
47+
48+ if ( typeof p1 === 'number' && typeof p2 === 'number' ) {
49+ merged [ k ] = p1 + ( p1 - p2 ) ; // 线性推算
50+ } else if ( typeof p1 === 'number' ) {
51+ merged [ k ] = p1 + 40 ; // 简单增量
52+ } else {
53+ merged [ k ] = 0 ; // 默认值
54+ }
55+ }
56+ } ) ;
57+
58+ if ( ! merged . type ) merged . type = 'collapse-node' ;
59+ if ( ! merged . size ) merged . size = 26 ;
60+
61+ // 递归处理 children
62+ if ( merged . children && merged . children . length ) {
63+ merged . children = merged . children . map ( ( c ) =>
64+ mergeTree ( c , newMap . get ( c . id ) ?? c ) ,
65+ ) ;
66+ }
67+
68+ return merged ;
69+ } ) ;
70+
71+ // 补充 newChildren 中不存在于 oldChildren 的节点
72+ const oldIds = new Set ( oldChildren . map ( ( c ) => c . id ) ) ;
73+ const additional = newChildren
74+ . filter ( ( c ) => ! oldIds . has ( c . id ) )
75+ . map ( ( c ) => mergeTree ( { id : c . id , children : [ ] } , c ) ) ;
76+
77+ return {
78+ id : oldNode . id ,
79+ children : [ ...mergedChildren , ...additional ] ,
80+ x : oldNode . x ?? 0 ,
81+ y : oldNode . y ?? 0 ,
82+ depth : oldNode . depth ?? 0 ,
83+ type : oldNode . type ?? 'collapse-node' ,
84+ size : oldNode . size ?? 26 ,
85+ } ;
86+ } ;
87+
2088const TaskRoadmap : FC < TTaskRoadmpProps > = ( {
2189 headerGroupValue,
2290 headerGroupValueOptions,
2391 setHeaderGroupValue,
2492 task_id,
2593 script_type,
2694} ) => {
95+ const oldAttackPathDataRef = useRef < TreeGraphData > ( ) ;
2796 const stepsList = useMemo ( ( ) => {
2897 const targetList =
2998 targetRouteMap [ script_type as keyof typeof targetRouteMap ] . list ;
@@ -36,19 +105,31 @@ const TaskRoadmap: FC<TTaskRoadmpProps> = ({
36105 task_id,
37106 script_type,
38107 } ) ;
39-
40- return data ;
108+ const resultData = oldAttackPathDataRef . current
109+ ? mergeTree ( oldAttackPathDataRef . current , data )
110+ : data ;
111+ return resultData ;
41112 } ,
42113 {
43114 manual : true ,
44- pollingInterval : 8000 ,
115+ pollingInterval : 10000 ,
45116 } ,
46117 ) ;
47118
48119 useEffect ( ( ) => {
49120 run ( ) ;
50121 } , [ ] ) ;
51122
123+ useUpdateEffect ( ( ) => {
124+ if (
125+ typeof data === 'object' &&
126+ data !== null &&
127+ Object . keys ( data ) ?. length !== 0
128+ ) {
129+ oldAttackPathDataRef . current = data ;
130+ }
131+ } , [ data ] ) ;
132+
52133 const StepsCurrentMemo = useMemo ( ( ) => {
53134 const targetList =
54135 targetRouteMap [ script_type as keyof typeof targetRouteMap ] . list ;
0 commit comments