CN-1548 feat: 关系图用force-graph重新开发
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cn",
|
"name": "cn",
|
||||||
"version": "0.1.0",
|
"version": "24.04",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
@@ -18,10 +18,12 @@
|
|||||||
"babel-plugin-lodash": "~3.3.0",
|
"babel-plugin-lodash": "~3.3.0",
|
||||||
"codemirror": "^5.65.1",
|
"codemirror": "^5.65.1",
|
||||||
"core-js": "~3.31.0",
|
"core-js": "~3.31.0",
|
||||||
|
"d3": "^7.9.0",
|
||||||
"dayjs": "^1.10.5",
|
"dayjs": "^1.10.5",
|
||||||
"dexie": "~3.2.0",
|
"dexie": "~3.2.0",
|
||||||
"echarts": "^5.1.1",
|
"echarts": "^5.1.1",
|
||||||
"element-plus": "^2.5.1",
|
"element-plus": "^2.5.1",
|
||||||
|
"force-graph": "^1.43.5",
|
||||||
"h3-js": "~3.7.2",
|
"h3-js": "~3.7.2",
|
||||||
"lib-flexible": "^0.3.2",
|
"lib-flexible": "^0.3.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +0,0 @@
|
|||||||
import G6 from '@antv/g6'
|
|
||||||
|
|
||||||
export default class Edge {
|
|
||||||
constructor (sourceNode, targetNode, type) {
|
|
||||||
this.id = sourceNode.id + '__' + targetNode.id
|
|
||||||
this.source = sourceNode.id
|
|
||||||
this.target = targetNode.id
|
|
||||||
this.isTemp = type === 'temp'
|
|
||||||
this.style = type === 'temp' ? tempStyles.style : normalStyles.style
|
|
||||||
this.stateStyles = type === 'temp' ? tempStyles.stateStyles : normalStyles.stateStyles
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalStyles = {
|
|
||||||
style: {
|
|
||||||
stroke: '#BEBEBE',
|
|
||||||
endArrow: {
|
|
||||||
path: G6.Arrow.triangle(5, 5),
|
|
||||||
fill: '#BEBEBE'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stateStyles: {
|
|
||||||
mySelected: {
|
|
||||||
stroke: '#778391',
|
|
||||||
endArrow: {
|
|
||||||
path: G6.Arrow.triangle(5, 5),
|
|
||||||
fill: '#778391'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tempStyles = {
|
|
||||||
style: {
|
|
||||||
endArrow: {
|
|
||||||
path: G6.Arrow.triangle(5, 5),
|
|
||||||
fill: '#DDD'
|
|
||||||
},
|
|
||||||
stroke: '#DDD',
|
|
||||||
lineDash: [3, 2]
|
|
||||||
},
|
|
||||||
stateStyles: {
|
|
||||||
mySelected: {
|
|
||||||
stroke: '#DDD',
|
|
||||||
endArrow: {
|
|
||||||
path: G6.Arrow.triangle(5, 5),
|
|
||||||
fill: '#DDD'
|
|
||||||
},
|
|
||||||
lineDash: [3, 2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
8
src/views/entityExplorer/entityGraph/link.js
Normal file
8
src/views/entityExplorer/entityGraph/link.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default class Link {
|
||||||
|
constructor (sourceNode, targetNode, type) {
|
||||||
|
this.id = sourceNode.id + '__' + targetNode.id
|
||||||
|
this.source = sourceNode.id
|
||||||
|
this.target = targetNode.id
|
||||||
|
this.isTemp = type === 'temp'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,10 @@ export default class Node {
|
|||||||
this.sourceNode = sourceNode
|
this.sourceNode = sourceNode
|
||||||
}
|
}
|
||||||
this.label = this.generateLabel()
|
this.label = this.generateLabel()
|
||||||
|
|
||||||
|
const img = new Image()
|
||||||
|
img.src = this.getIconUrl(cfg.entityType, type === nodeType.rootNode)
|
||||||
|
this.img = img
|
||||||
}
|
}
|
||||||
|
|
||||||
generateLabel () {
|
generateLabel () {
|
||||||
@@ -34,7 +38,7 @@ export default class Node {
|
|||||||
return this.id
|
return this.id
|
||||||
}
|
}
|
||||||
case nodeType.listNode: {
|
case nodeType.listNode: {
|
||||||
return `${this.getLabelText()}(${_.get(this.sourceNode.myData, 'relatedEntity.' + this.myData.entityType + '.total', 0)})`
|
return `${this.getLabelText()}(${_.get(this.sourceNode.myData, 'relatedEntities.' + this.myData.entityType + '.total', 0)})`
|
||||||
}
|
}
|
||||||
case nodeType.tempNode: {
|
case nodeType.tempNode: {
|
||||||
return this.getLabelText()
|
return this.getLabelText()
|
||||||
@@ -64,6 +68,11 @@ export default class Node {
|
|||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getIconUrl (entityType, colored) {
|
||||||
|
const suffix = colored ? '-colored' : ''
|
||||||
|
return require(`@/assets/img/entity-symbol2/${entityType}${suffix}.svg`)
|
||||||
|
}
|
||||||
|
|
||||||
isSubdomain () {
|
isSubdomain () {
|
||||||
if (this.sourceNode) {
|
if (this.sourceNode) {
|
||||||
return this.sourceNode.myData.entityType === 'domain' && this.myData.entityType === 'domain'
|
return this.sourceNode.myData.entityType === 'domain' && this.myData.entityType === 'domain'
|
||||||
@@ -87,11 +96,11 @@ export default class Node {
|
|||||||
}
|
}
|
||||||
this.myData.tags = _tags
|
this.myData.tags = _tags
|
||||||
|
|
||||||
const relatedEntityTotalCount = await this.queryRelatedEntityCount(entityType, entityName)
|
const relatedEntityTotalCount = await this.queryRelatedEntitiesCount(entityType, entityName)
|
||||||
this.myData.relatedEntity = {
|
this.myData.relatedEntities = {
|
||||||
ip: { total: relatedEntityTotalCount.ipCount, list: [] },
|
ip: { total: relatedEntityTotalCount.ipCount, loadedCount: 0 },
|
||||||
domain: { total: this.myData.entityType === 'domain' ? relatedEntityTotalCount.subDomainCount : relatedEntityTotalCount.domainCount, list: [] },
|
domain: { total: this.myData.entityType === 'domain' ? relatedEntityTotalCount.subDomainCount : relatedEntityTotalCount.domainCount, loadedCount: 0 },
|
||||||
app: { total: relatedEntityTotalCount.appCount, list: [] }
|
app: { total: relatedEntityTotalCount.appCount, loadedCount: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +130,7 @@ export default class Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async queryRelatedEntityCount (entityType, entityName) {
|
async queryRelatedEntitiesCount (entityType, entityName) {
|
||||||
const response = await axios.get(`${api.entity.entityGraph.relatedEntityCount}/${entityType}?resource=${entityName}`).catch(e => {
|
const response = await axios.get(`${api.entity.entityGraph.relatedEntityCount}/${entityType}?resource=${entityName}`).catch(e => {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
throw e
|
throw e
|
||||||
@@ -137,7 +146,7 @@ export default class Node {
|
|||||||
export const nodeType = {
|
export const nodeType = {
|
||||||
rootNode: 'rootNode',
|
rootNode: 'rootNode',
|
||||||
listNode: 'listNode',
|
listNode: 'listNode',
|
||||||
entityNode: 'entityNode',
|
entityNode: 'en-tityNode',
|
||||||
tempNode: 'tempNode'
|
tempNode: 'tempNode'
|
||||||
}
|
}
|
||||||
export async function queryRelatedEntity (node, targetEntityType) {
|
export async function queryRelatedEntity (node, targetEntityType) {
|
||||||
@@ -146,7 +155,7 @@ export async function queryRelatedEntity (node, targetEntityType) {
|
|||||||
_targetEntityType = 'subdomain'
|
_targetEntityType = 'subdomain'
|
||||||
}
|
}
|
||||||
let url = `${api.entity.entityGraph[`${node.myData.entityType}Related${_.upperFirst(_targetEntityType)}`]}?resource=${node.myData.entityName}&pageSize=10`
|
let url = `${api.entity.entityGraph[`${node.myData.entityType}Related${_.upperFirst(_targetEntityType)}`]}?resource=${node.myData.entityName}&pageSize=10`
|
||||||
const current = node.myData.relatedEntity[targetEntityType].list.length
|
const current = node.myData.relatedEntities[targetEntityType].loadedCount
|
||||||
const pageNo = parseInt(current / 10) + 1
|
const pageNo = parseInt(current / 10) + 1
|
||||||
url += `&pageNo=${pageNo}`
|
url += `&pageNo=${pageNo}`
|
||||||
const response = await axios.get(url).catch(e => {
|
const response = await axios.get(url).catch(e => {
|
||||||
|
|||||||
Reference in New Issue
Block a user