CN-1548 feat: 关系图right-box

This commit is contained in:
chenjinsong
2024-06-14 14:59:01 +08:00
parent d63f8a7827
commit a73c9f18cd
7 changed files with 237 additions and 226 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "cn", "name": "cn",
"version": "24.04", "version": "24.4.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",

View File

@@ -19,7 +19,7 @@ $color-regular: var(--el-text-color-regular);
.graph-list-header-icon { .graph-list-header-icon {
font-size: 21px; font-size: 21px;
color: $color-regular; color: #778391;
margin-right: 9px; margin-right: 9px;
} }
} }
@@ -50,13 +50,10 @@ $color-regular: var(--el-text-color-regular);
border-radius: 3px; border-radius: 3px;
font-size: 12px; font-size: 12px;
color: var(--el-color-white); color: var(--el-color-white);
display: flex; padding: 8px 10px;
align-items: center;
justify-content: center;
font-weight: 500;
padding: 14px 10px;
cursor: pointer; cursor: pointer;
border: 1px solid rgba(46, 136, 166, 0.85); border: 1px solid var(--el-color-business);
text-align: center;
i { i {
font-size: 16px; font-size: 16px;

View File

@@ -5,7 +5,7 @@
<el-drawer <el-drawer
v-model="rightBox.show" v-model="rightBox.show"
direction="rtl" direction="rtl"
custom-class="entity-graph__detail" class="entity-graph__detail"
:close-on-click-modal="true" :close-on-click-modal="true"
:modal="false" :modal="false"
:size="400" :size="400"
@@ -48,6 +48,7 @@ import GraphEntityDetail from '@/views/entityExplorer/entityGraph/GraphEntityDet
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { ref, shallowRef } from 'vue' import { ref, shallowRef } from 'vue'
import ForceGraph from 'force-graph' import ForceGraph from 'force-graph'
import { Algorithm } from '@antv/g6'
// import ForceGraph3D from '3d-force-graph' // import ForceGraph3D from '3d-force-graph'
import * as d3 from 'd3' import * as d3 from 'd3'
import Node, { nodeType } from './entityGraph/node' import Node, { nodeType } from './entityGraph/node'
@@ -82,12 +83,11 @@ export default {
try { try {
this.currentNodeData = await this.generateInitialData() this.currentNodeData = await this.generateInitialData()
this.initialData = _.cloneDeep(this.currentNodeData) // 初始化数据 this.initialData = _.cloneDeep(this.currentNodeData) // 初始化数据
const _this = this
let hoverNode = null let hoverNode = null
this.graph = ForceGraph()(document.getElementById('entityGraph')) this.graph = ForceGraph()(document.getElementById('entityGraph'))
.graphData(_this.currentNodeData) .graphData(this.currentNodeData)
.nodeCanvasObject((node, ctx) => { .nodeCanvasObject((node, ctx) => {
const nodeStyle = _this.getNodeStyle(node.type, node.data.entityType) const nodeStyle = this.getNodeStyle(node.type, node.data.entityType)
const iconWidth = nodeStyle.iconWidth / 2 const iconWidth = nodeStyle.iconWidth / 2
const iconHeight = nodeStyle.iconHeight / 2 const iconHeight = nodeStyle.iconHeight / 2
const x = node.x - iconWidth / 2 const x = node.x - iconWidth / 2
@@ -180,14 +180,14 @@ export default {
} }
}) })
.nodePointerAreaPaint((node, color, ctx) => { // 鼠标hover起作用的范围 .nodePointerAreaPaint((node, color, ctx) => { // 鼠标hover起作用的范围
const nodeStyle = _this.getNodeStyle(node.type, node.data.entityType) const nodeStyle = this.getNodeStyle(node.type, node.data.entityType)
const size = nodeStyle.innerR const size = nodeStyle.innerR
ctx.fillStyle = color ctx.fillStyle = color
ctx.fillRect(node.x - size / 2, node.y - size / 2, size, size) // draw square as pointer trap ctx.fillRect(node.x - size / 2, node.y - size / 2, size, size) // draw square as pointer trap
}) })
.linkCanvasObject((link, ctx) => { .linkCanvasObject((link, ctx) => {
if (link.source.x !== undefined && link.source.y !== undefined && link.target.x !== undefined && link.target.y !== undefined) { if (link.source.x !== undefined && link.source.y !== undefined && link.target.x !== undefined && link.target.y !== undefined) {
const nodeStyle = _this.getNodeStyle(link.target.type, link.target.data.entityType) const nodeStyle = this.getNodeStyle(link.target.type, link.target.data.entityType)
ctx.lineWidth = 0.5 ctx.lineWidth = 0.5
ctx.beginPath() ctx.beginPath()
@@ -200,9 +200,9 @@ export default {
const lineDash = link.target.type === nodeType.tempNode ? [2, 2] : [] const lineDash = link.target.type === nodeType.tempNode ? [2, 2] : []
ctx.setLineDash(lineDash) ctx.setLineDash(lineDash)
ctx.moveTo(link.source.x, link.source.y) ctx.moveTo(link.source.x, link.source.y)
const xy = _this.findCircleLineIntersection(link.target.x, link.target.y, nodeStyle.innerR / 2, link.source.x, link.source.y) const xy = this.findCircleLineIntersection(link.target.x, link.target.y, nodeStyle.innerR / 2, link.source.x, link.source.y)
ctx.lineTo(xy[0].x, xy[0].y) ctx.lineTo(xy[0].x, xy[0].y)
_this.drawArrow(ctx, link.source.x, link.source.y, xy[0].x, xy[0].y, 40, 3) this.drawArrow(ctx, link.source.x, link.source.y, xy[0].x, xy[0].y, 40, 3)
// 圆角三角形 // 圆角三角形
if (this.clickNode && (this.clickNode.id === link.source.id || this.clickNode.id === link.target.id)) { if (this.clickNode && (this.clickNode.id === link.source.id || this.clickNode.id === link.target.id)) {
@@ -226,13 +226,12 @@ export default {
.centerAt(0, 30)// 设置中心节点位置 .centerAt(0, 30)// 设置中心节点位置
.onNodeClick(async (nodeModel, e) => { .onNodeClick(async (nodeModel, e) => {
this.clickNode = nodeModel || null this.clickNode = nodeModel || null
const newLevel = nodeModel.level + 1
if (nodeModel.type !== 'tempNode') { if (nodeModel.type !== 'tempNode') {
// _this.rightBox.show = true this.rightBox.show = true
_this.cleanTempNodesAndTempEdges() this.cleanTempItems()
// 点击entityNode查询数据并根据数据生成tempNode // 点击entityNode查询数据并根据数据生成tempNode
if (nodeModel.type === nodeType.entityNode) { if (nodeModel.type === nodeType.entityNode) {
// _this.rightBox.loading = true this.rightBox.loading = true
try { try {
// 若已查过数据,不重复查询 // 若已查过数据,不重复查询
if (!nodeModel.data.relatedEntities) { if (!nodeModel.data.relatedEntities) {
@@ -251,12 +250,11 @@ export default {
`${nodeModel.id}__${k}__temp`, `${nodeModel.id}__${k}__temp`,
{ {
entityType: k, entityType: k,
..._this.generateTempNodeCoordinate(nodeModel.getSourceNode(_this.currentNodeData), e) ...this.generateTempNodeCoordinate(nodeModel.getSourceNode(this.currentNodeData), e)
}, },
nodeModel, nodeModel,
this.defaultChargeStrength, this.defaultChargeStrength,
this.getIconUrl(k, false, false), this.getIconUrl(k, false, false)
newLevel
) )
this.$nextTick(() => { this.$nextTick(() => {
tempNode.fx = tempNode.x tempNode.fx = tempNode.x
@@ -264,34 +262,34 @@ export default {
}) })
const tempEdge = new Link(nodeModel, tempNode, 'temp', this.defaultLinkDistance, 3) const tempEdge = new Link(nodeModel, tempNode, 'temp', this.defaultLinkDistance, 3)
_this.currentNodeData.nodes.push(tempNode) this.currentNodeData.nodes.push(tempNode)
_this.currentNodeData.links.push(tempEdge) this.currentNodeData.links.push(tempEdge)
_this.graph.graphData(_this.currentNodeData) this.graph.graphData(this.currentNodeData)
} }
} }
}) })
// change && _this.graph.layout()//????????????? // change && this.graph.layout()//?????????????
_this.rightBox.node = _.cloneDeep(nodeModel) this.rightBox.node = _.cloneDeep(nodeModel)
_this.rightBox.mode = 'detail' this.rightBox.mode = 'detail'
} catch (e) { } catch (e) {
console.log(e) console.error(e)
_this.$message.error(_this.errorMsgHandler(e)) this.$message.error(this.errorMsgHandler(e))
} finally { } finally {
_this.rightBox.loading = false this.rightBox.loading = false
} }
} else if (nodeModel.type === nodeType.listNode) { } else if (nodeModel.type === nodeType.listNode) {
_this.rightBox.node = _.cloneDeep(nodeModel) this.rightBox.node = _.cloneDeep(nodeModel)
_this.rightBox.mode = 'list' this.rightBox.mode = 'list'
} else if (nodeModel.type === nodeType.rootNode) { } else if (nodeModel.type === nodeType.rootNode) {
_this.rightBox.node = _.cloneDeep(nodeModel) this.rightBox.node = _.cloneDeep(nodeModel)
_this.rightBox.mode = 'detail' this.rightBox.mode = 'detail'
} }
} else { } else {
// 点击tempNode根据source生成listNode和entityNode以及对应的edge。查完entityNode的接口再删除临时node和edge。 // 点击tempNode根据source生成listNode和entityNode以及对应的edge。查完entityNode的接口再删除临时node和edge。
// 若已达第六层则只生成listNode不再展开entityNode // 若已达第六层则只生成listNode不再展开entityNode
const nodes = [] const nodes = []
const edges = [] const edges = []
const sourceNode = nodeModel.getSourceNode(_this.currentNodeData) const sourceNode = nodeModel.getSourceNode(this.currentNodeData)
const listNode = new Node( const listNode = new Node(
nodeType.listNode, nodeType.listNode,
`${sourceNode.id}__${nodeModel.data.entityType}-list`, `${sourceNode.id}__${nodeModel.data.entityType}-list`,
@@ -302,16 +300,15 @@ export default {
}, },
sourceNode, sourceNode,
this.defaultChargeStrength, this.defaultChargeStrength,
this.getIconUrl(nodeModel.data.entityType, false, false), this.getIconUrl(nodeModel.data.entityType, false, false)
newLevel
) )
nodes.push(listNode) nodes.push(listNode)
edges.push(new Link(sourceNode, listNode, null, this.defaultLinkDistance, 2)) edges.push(new Link(sourceNode, listNode, null, this.defaultLinkDistance, 2))
// 判断listNode的sourceNode层级若大于等于10即第6层listNode则不继续拓展entity node并给用户提示。否则拓展entity node // 判断listNode的sourceNode层级若大于等于10即第6层listNode则不继续拓展entity node并给用户提示。否则拓展entity node
const level = _this.getNodeLevel(listNode.sourceNode.id) const level = this.getNodeLevel(listNode.sourceNode.id)
if (level < 10) { if (level < 10) {
// _this.rightBox.loading = true // this.rightBox.loading = true
try { try {
const entities = await sourceNode.queryRelatedEntities(listNode.data.entityType) const entities = await sourceNode.queryRelatedEntities(listNode.data.entityType)
sourceNode.data.relatedEntities[listNode.data.entityType].list.push(...entities.list) sourceNode.data.relatedEntities[listNode.data.entityType].list.push(...entities.list)
@@ -321,37 +318,37 @@ export default {
entityName: entity.vertex, entityName: entity.vertex,
x: e.x + Math.random() * 100 - 50, x: e.x + Math.random() * 100 - 50,
y: e.y + Math.random() * 100 - 50 y: e.y + Math.random() * 100 - 50
}, listNode, this.defaultChargeStrength, this.getIconUrl(listNode.data.entityType, true, false), newLevel) }, listNode, this.defaultChargeStrength, this.getIconUrl(listNode.data.entityType, true, false))
nodes.push(entityNode) nodes.push(entityNode)
edges.push(new Link(listNode, entityNode, null, this.defaultLinkDistance, 2)) edges.push(new Link(listNode, entityNode, null, this.defaultLinkDistance, 2))
}) })
} catch (e) { } catch (e) {
console.log(e) console.error(e)
_this.$message.error(_this.errorMsgHandler(e)) this.$message.error(this.errorMsgHandler(e))
} finally { } finally {
_this.rightBox.loading = false this.rightBox.loading = false
} }
} else { } else {
this.$message.warning(this.$t('tip.maxExpandDepth')) this.$message.warning(this.$t('tip.maxExpandDepth'))
} }
_this.addItems(nodes, edges) this.addItems(nodes, edges)
_this.cleanTempNodesAndTempEdges() this.cleanTempItems()
// _this.graph.layout() // this.graph.layout()
// 手动高亮listNode // 手动高亮listNode
/* const _listNode = _this.graph.findById(listNode.id) /* const _listNode = this.graph.findById(listNode.id)
_this.graph.emit('node:click', { item: _listNode, target: _listNode.getKeyShape() }) this.graph.emit('node:click', { item: _listNode, target: _listNode.getKeyShape() })
if (_this.stackData.justUndo) { if (this.stackData.justUndo) {
_this.stackData.justUndo = false this.stackData.justUndo = false
_this.stackData.redo = [] this.stackData.redo = []
} }
if (_this.stackData.justRedo) { if (this.stackData.justRedo) {
_this.stackData.justRedo = false this.stackData.justRedo = false
_this.stackData.redo = [] this.stackData.redo = []
} */ } */
} }
// _this.graph.zoom(1,0)//缩放画布 // this.graph.zoom(1,0)//缩放画布
/* if(node.type !== nodeType.listNode && node.type !== nodeType.rootNode) { /* if(node.type !== nodeType.listNode && node.type !== nodeType.rootNode) {
let clickNodeData = await this.generateInitialData(node) let clickNodeData = await this.generateInitialData(node)
@@ -375,7 +372,7 @@ export default {
}))// 设置线对点的力? }))// 设置线对点的力?
.d3Force('center', d3.forceCenter().strength(0))// 设置力导图点阵中心位置, 向心力设置为0以后d3.forceCenter(-50,-70)不起作用了 .d3Force('center', d3.forceCenter().strength(0))// 设置力导图点阵中心位置, 向心力设置为0以后d3.forceCenter(-50,-70)不起作用了
.d3Force('charge', d3.forceManyBody().strength(node => { // 电荷力吸引力或排斥力。forceManyBody使所有元素相互吸引或排斥。可以设置吸引或排斥的强度.strength()其中正值导致元素相互吸引,而负值将导致元素相互排斥。 .d3Force('charge', d3.forceManyBody().strength(node => { // 电荷力吸引力或排斥力。forceManyBody使所有元素相互吸引或排斥。可以设置吸引或排斥的强度.strength()其中正值导致元素相互吸引,而负值将导致元素相互排斥。
const strength = node.level === 0 ? -350 : node.strength// 中心节点的排斥力要设置的比较大(-300-200-100这样中心节点的子节点的子节点就会是远离中心节点的状态进行聚集。 const strength = node.type === nodeType.rootNode ? -350 : node.strength// 中心节点的排斥力要设置的比较大(-300-200-100这样中心节点的子节点的子节点就会是远离中心节点的状态进行聚集。
return strength return strength
})) }))
.onNodeDrag((node, translate) => { .onNodeDrag((node, translate) => {
@@ -413,7 +410,7 @@ export default {
if (this.stackData.justRedo) { if (this.stackData.justRedo) {
this.stackData.justRedo = false this.stackData.justRedo = false
} }
// this.cleanTempNodesAndTempEdges() // this.cleanTempItems()
this.graph.layout() this.graph.layout()
this.onCloseBlock() this.onCloseBlock()
} else if (code === 'redo') { } else if (code === 'redo') {
@@ -424,7 +421,7 @@ export default {
if (this.stackData.justUndo) { if (this.stackData.justUndo) {
this.stackData.justUndo = false this.stackData.justUndo = false
} }
// this.cleanTempNodesAndTempEdges() // this.cleanTempItems()
this.graph.layout() this.graph.layout()
this.onCloseBlock() this.onCloseBlock()
} else if (code === 'autoZoom') { } else if (code === 'autoZoom') {
@@ -447,19 +444,18 @@ export default {
}, },
getNodeStyle (curNodeType, entityType) { getNodeStyle (curNodeType, entityType) {
const _this = this
switch (curNodeType) { switch (curNodeType) {
case nodeType.rootNode: { case nodeType.rootNode: {
return _this.getRootNodeStyle(entityType) return this.getRootNodeStyle(entityType)
} }
case nodeType.listNode: { case nodeType.listNode: {
return _this.getListNodeStyle(entityType) return this.getListNodeStyle(entityType)
} }
case nodeType.entityNode: { case nodeType.entityNode: {
return _this.getEntityNodeStyle(entityType) return this.getEntityNodeStyle(entityType)
} }
case nodeType.tempNode: { case nodeType.tempNode: {
return _this.getTempNodeStyle(entityType) return this.getTempNodeStyle(entityType)
} }
} }
}, },
@@ -733,8 +729,15 @@ export default {
ctx.lineTo(toX + topX, toY + topY) ctx.lineTo(toX + topX, toY + topY)
}, },
getNodeLevel (id) { getNodeLevel (id) {
// this.graph.d3AlphaTarget() const { findShortestPath } = Algorithm
return 2 const { nodes, links } = this.graph.graphData()
const g6FormatData = { nodes: _.cloneDeep(nodes), edges: _.cloneDeep(links) }
g6FormatData.edges.forEach(l => {
l.source = l.source.id
l.target = l.target.id
})
const info = findShortestPath(g6FormatData, this.entity.entityName, id)
return info.length
}, },
generateTempNodeCoordinate (sourceNode, event) { generateTempNodeCoordinate (sourceNode, event) {
const sx = sourceNode.x const sx = sourceNode.x
@@ -746,42 +749,26 @@ export default {
y: cy + cy - sy + Math.random() * 30 - 15 y: cy + cy - sy + Math.random() * 30 - 15
} }
}, },
addItems (nodes = [], edges = [], stack = true) { addItems (toAddNodes, toAddLinks) {
// 过滤掉已经存在的node if (toAddNodes.length || toAddLinks.length) {
const _nodes = nodes.filter(n => { const { nodes, links } = this.graph.graphData()
return !this.currentNodeData.nodes.find(node => node.id === n.id)// ??????????? const nodes2 = toAddNodes.filter(n => !nodes.some(n2 => n.id === n2.id))
}) nodes.push(...nodes2)
_nodes.forEach(n => { links.push(...toAddLinks)
this.currentNodeData.nodes.push(n) this.graph.graphData({ nodes, links })
})
edges.forEach(e => {
this.currentNodeData.links.push(e)
})
if (_nodes.length > 0 || edges.length > 0) {
this.graph.graphData(this.currentNodeData)
} }
}, },
cleanTempNodesAndTempEdges () { cleanTempItems () {
// 清除现有tempNode和tempEdge let { nodes, links } = this.graph.graphData()
const tempNodes = this.currentNodeData.nodes.filter(node => node.type === nodeType.tempNode) nodes = nodes.filter(n => n.type !== nodeType.tempNode)
tempNodes.forEach(n => { links = links.filter(l => l.level !== 3)
const tempNodeIndex = this.currentNodeData.nodes.indexOf(n) this.graph.graphData({ nodes, links })
this.currentNodeData.nodes.splice(tempNodeIndex, 1)
})
const tempEdges = this.currentNodeData.links.filter(edge => edge.type === 'temp')
tempEdges.forEach(n => {
const tempEdgeIndex = this.currentNodeData.links.indexOf(n)
this.currentNodeData.links.splice(tempEdgeIndex, 1)
})
if (tempNodes.length > 0 || tempEdges.length > 0) {
this.graph.graphData(this.currentNodeData)
}
}, },
async generateInitialData (clickNode) { async generateInitialData (clickNode) {
const nodes = [] const nodes = []
const links = [] const links = []
const rootNode = clickNode || new Node(nodeType.rootNode, this.entity.entityName, this.entity, null, this.defaultChargeStrength, this.getIconUrl(this.entity.entityType, true, true), 0) const rootNode = clickNode || new Node(nodeType.rootNode, this.entity.entityName, this.entity, null, this.defaultChargeStrength, this.getIconUrl(this.entity.entityType, true, true))
await rootNode.queryDetailData() await rootNode.queryDetailData()
nodes.push(rootNode) nodes.push(rootNode)
this.clickNode = rootNode this.clickNode = rootNode
@@ -802,8 +789,7 @@ export default {
}, },
rootNode, rootNode,
this.defaultChargeStrength, this.defaultChargeStrength,
this.getIconUrl(k, false, false), this.getIconUrl(k, false, false)
1
) )
listNodes.push(listNode) listNodes.push(listNode)
links.push(new Link(rootNode, listNode, null, 60, 1)) links.push(new Link(rootNode, listNode, null, 60, 1))
@@ -824,8 +810,7 @@ export default {
}, },
listNode, listNode,
this.defaultChargeStrength, this.defaultChargeStrength,
this.getIconUrl(listNode.data.entityType, true, false), this.getIconUrl(listNode.data.entityType, true, false)
2
) )
entityNodes.push(entityNode) entityNodes.push(entityNode)
links.push(new Link(listNode, entityNode, null, this.defaultLinkDistance, 2)) links.push(new Link(listNode, entityNode, null, this.defaultLinkDistance, 2))
@@ -839,38 +824,34 @@ export default {
} }
}, },
async expandList (nodeId) { async expandList (nodeId) {
const node = this.graph.findById(nodeId) const { nodes } = this.graph.graphData()
const model = node.getModel() const node = nodes.find(n => n.id === nodeId)
const sourceNode = this.graph.findById(model.sourceNode.id) const sourceNode = nodes.find(n => n.id === node.sourceNode.id)
const sourceModel = sourceNode.getModel() const expandType = node.data.entityType
const expandType = model.myData.entityType if (sourceNode.data.relatedEntities[expandType].list.length >= sourceNode.data.relatedEntities[expandType].total) {
if (sourceModel.myData.relatedEntity[expandType].list.length >= sourceModel.myData.relatedEntity[expandType].total) {
return return
} }
if (sourceModel.myData.relatedEntity[expandType].list.length < 50) { if (sourceNode.data.relatedEntities[expandType].list.length < 50) {
this.rightBox.loading = true this.rightBox.loading = true
try { try {
const entities = await queryRelatedEntity(sourceModel, expandType) const entities = await sourceNode.queryRelatedEntities(expandType)
sourceModel.myData.relatedEntity[expandType].list.push(...entities.list) sourceNode.data.relatedEntities[expandType].list.push(...entities.list)
const entityNodeModels = [] const toAddNodes = []
const edgeModels = [] const toAddLinks = []
entities.list.forEach(entity => { entities.list.forEach(entity => {
const entityNodeModel = new Node(nodeType.entityNode, entity.vertex, { const toAddNode = new Node(nodeType.entityNode, entity.vertex, {
entityType: expandType, entityType: expandType,
entityName: entity.vertex, entityName: entity.vertex
x: model.x + Math.random() * 500 - 250, }, node, this.defaultChargeStrength, this.getIconUrl(node.data.entityType, true, false))
y: model.y + Math.random() * 500 - 250 toAddNodes.push(toAddNode)
}, model)
entityNodeModels.push(entityNodeModel)
const edge = new Edge(model, entityNodeModel) const toAddLink = new Link(node, toAddNode, null, this.defaultLinkDistance)
edgeModels.push(edge) toAddLinks.push(toAddLink)
}) })
this.addItems(entityNodeModels, edgeModels) this.addItems(toAddNodes, toAddLinks)
this.setItemsStata(edgeModels, 'mySelected', true) this.rightBox.node = _.cloneDeep(node)
this.graph.layout()
this.rightBox.node = _.cloneDeep(model)
} catch (e) { } catch (e) {
console.error(e)
this.$message.error(this.errorMsgHandler(e)) this.$message.error(this.errorMsgHandler(e))
} finally { } finally {
this.rightBox.loading = false this.rightBox.loading = false
@@ -880,55 +861,43 @@ export default {
} }
}, },
async expandDetailList (nodeId, expandType) { async expandDetailList (nodeId, expandType) {
const node = this.graph.findById(nodeId) const { nodes } = this.graph.graphData()
const node = nodes.find(n => n.id === nodeId)
if (node) { if (node) {
const nodeModel = node.getModel() if (node.data.relatedEntities[expandType].list.length >= node.data.relatedEntities[expandType].total) {
if (nodeModel.myData.relatedEntity[expandType].list.length >= nodeModel.myData.relatedEntity[expandType].total) {
return return
} }
if (nodeModel.myData.relatedEntity[expandType].list.length < 50) { if (node.data.relatedEntities[expandType].list.length < 50) {
const toAddNodeModels = [] const toAddNodes = []
const toAddEdgeModels = [] const toAddLinks = []
this.rightBox.loading = true this.rightBox.loading = true
try { try {
const entities = await queryRelatedEntity(nodeModel, expandType) const entities = await node.queryRelatedEntities(expandType)
nodeModel.myData.relatedEntity[expandType].list.push(...entities.list) node.data.relatedEntities[expandType].list.push(...entities.list)
const neighbors = node.getNeighbors('target') // 移除 tempNode 和 tempEdge
const listNode = neighbors.find(n => n.getModel().myData.entityType === expandType) this.cleanTempItems()
let listNodeModel = listNode.getModel()
let listEdgeModel
// 如果listNode是tempNode移除并新建listNode
if (listNodeModel.type === nodeType.tempNode) {
// 移除tempNode和tempEdge
const tempEdges = listNode.getInEdges()
tempEdges.forEach(edge => {
this.graph.removeItem(edge)
})
this.graph.removeItem(listNode)
listNodeModel = new Node(nodeType.listNode, `${nodeModel.id}__${expandType}-list`, { entityType: expandType, x: listNodeModel.x, y: listNodeModel.y }, nodeModel) const neighbors = this.getNeighborItems(node)
listEdgeModel = new Edge(nodeModel, listNodeModel) let listNode = neighbors.targetNodes.find(n => n.data.entityType === expandType)
toAddNodeModels.push(listNodeModel) if (!listNode) {
toAddEdgeModels.push(listEdgeModel) listNode = new Node(nodeType.listNode, `${node.id}__${expandType}-list`, { entityType: expandType }, node, this.defaultChargeStrength, this.getIconUrl(expandType, false, false))
const link = new Link(node, listNode, null, this.defaultLinkDistance)
toAddNodes.push(listNode)
toAddLinks.push(link)
} }
entities.list.forEach(entity => { entities.list.forEach(entity => {
const entityNodeModel = new Node(nodeType.entityNode, entity.vertex, { const entityNode = new Node(nodeType.entityNode, entity.vertex, {
entityType: expandType, entityType: expandType,
entityName: entity.vertex, entityName: entity.vertex
x: listNodeModel.x + Math.random() * 500 - 250, }, listNode, this.defaultChargeStrength, this.getIconUrl(expandType, true, false))
y: listNodeModel.y + Math.random() * 500 - 250 toAddNodes.push(entityNode)
}, listNodeModel) toAddLinks.push(new Link(listNode, entityNode, null, this.defaultLinkDistance))
toAddNodeModels.push(entityNodeModel)
toAddEdgeModels.push(new Edge(listNodeModel, entityNodeModel))
}) })
this.addItems(toAddNodeModels, toAddEdgeModels) this.addItems(toAddNodes, toAddLinks)
if (listEdgeModel) { this.rightBox.node = _.cloneDeep(node)
this.graph.setItemState(this.graph.findById(listEdgeModel.id), 'mySelected', true)
}
this.graph.layout()
this.rightBox.node = _.cloneDeep(nodeModel)
} catch (e) { } catch (e) {
console.error(e)
this.$message.error(this.errorMsgHandler(e)) this.$message.error(this.errorMsgHandler(e))
} finally { } finally {
this.rightBox.loading = false this.rightBox.loading = false
@@ -946,22 +915,47 @@ export default {
}, },
getIconUrl (entityType, colored, isRoot) { getIconUrl (entityType, colored, isRoot) {
let suffix const suffix = colored ? '-colored' : ''
if (entityType === 'domain' && isRoot) {
suffix = '-colored2'
} else {
suffix = colored ? '-colored' : ''
}
const img = new Image() const img = new Image()
img.src = require(`@/assets/img/entity-symbol2/${entityType}${suffix}.svg`) img.src = require(`@/assets/img/entity-symbol2/${entityType}${suffix}.svg`)
return img return img
},
getNeighborItems (node) {
const { links } = this.graph.graphData()
const neighboringNodes = []
const neighboringTargetNodes = []
const neighboringSourceNodes = []
const neighboringTargetLinks = []
const neighboringSourceLinks = []
const neighboringLinks = links.filter(l => {
if (l.target === node || l.source === node) {
neighboringNodes.push(l.target === node ? l.source : l.target)
if (l.target === node) {
neighboringSourceNodes.push(l.source)
neighboringSourceLinks.push(l)
} else {
neighboringTargetNodes.push(l.target)
neighboringTargetLinks.push(l)
}
return true
}
return false
})
return {
nodes: neighboringNodes,
targetNodes: neighboringTargetNodes,
sourceNodes: neighboringSourceNodes,
links: neighboringLinks,
targetLinks: neighboringTargetLinks,
sourceLinks: neighboringSourceLinks
}
} }
}, },
watch: { watch: {
}, },
async mounted () { async mounted () {
if (this.entity.entityType && this.entity.entityName) { if (this.entity.entityType && this.entity.entityName) {
this.init() await this.init()
this.debounceFunc = this.$_.debounce(this.resize, 300) this.debounceFunc = this.$_.debounce(this.resize, 300)
window.addEventListener('resize', this.debounceFunc) window.addEventListener('resize', this.debounceFunc)
} }

View File

@@ -75,7 +75,7 @@
</div> </div>
<!--标签--> <!--标签-->
<div v-if="$_.get(node, 'myData.tags', []).length > 0" class="digital-certificate graph-basic-info__block"> <div v-if="$_.get(node, 'data.tags', []).length > 0" class="digital-certificate graph-basic-info__block">
<div class="digital-certificate-header padding-b-10"> <div class="digital-certificate-header padding-b-10">
<div class="digital-certificate-header__icon graph-header__icon"></div> <div class="digital-certificate-header__icon graph-header__icon"></div>
<div class="graph-basic-info__block-title"> <div class="graph-basic-info__block-title">
@@ -85,7 +85,7 @@
<div class="entity-detail graph-basic-info__block-content"> <div class="entity-detail graph-basic-info__block-content">
<div class="graph-tag-list"> <div class="graph-tag-list">
<div v-for="ic in $_.get(node, 'myData.tags', [])" :key="ic.value"> <div v-for="ic in $_.get(node, 'data.tags', [])" :key="ic.value">
<div class="entity-tag graph-tag-item" :class="`entity-tag--level-two-${ic.type}`" :style="getTagColor(ic.color)"> <div class="entity-tag graph-tag-item" :class="`entity-tag--level-two-${ic.type}`" :style="getTagColor(ic.color)">
<span>{{ic.value}}</span> <span>{{ic.value}}</span>
</div> </div>
@@ -126,13 +126,13 @@ export default {
computed: { computed: {
iconClass () { iconClass () {
let className let className
switch (_.get(this.node, 'myData.entityType', '')) { switch (_.get(this.node, 'data.entityType', '')) {
case ('ip'): { case ('ip'): {
className = 'cn-icon cn-icon-ip2' className = 'cn-icon cn-icon-ip2'
break break
} }
case ('domain'): { case ('domain'): {
className = 'cn-icon cn-icon-domain2' className = 'cn-icon cn-icon-subdomain'
break break
} }
case ('app'): { case ('app'): {
@@ -145,7 +145,7 @@ export default {
return className return className
}, },
entityTypeName () { entityTypeName () {
const type = _.get(this.node, 'myData.entityType', '') const type = _.get(this.node, 'data.entityType', '')
let entityTypeName = '-' let entityTypeName = '-'
switch (type) { switch (type) {
case ('ip'): { case ('ip'): {
@@ -176,6 +176,7 @@ export default {
node: { node: {
deep: true, deep: true,
handler (n) { handler (n) {
console.info(n)
this.handleDetailData(n) this.handleDetailData(n)
} }
} }
@@ -270,59 +271,59 @@ export default {
}, },
handleDetailData (node) { handleDetailData (node) {
const n = node const n = node
const type = _.get(n, 'myData.entityType', '') const type = _.get(n, 'data.entityType', '')
switch (type) { switch (type) {
case 'ip': { case 'ip': {
this.detailCards = [ this.detailCards = [
{ name: 'asn', label: this.$t('entities.asNumber'), value: _.get(n, 'myData.basicInfo.asn.asn', '-') }, { name: 'asn', label: this.$t('entities.asNumber'), value: _.get(n, 'data.basicInfo.asn.asn', '-') },
{ {
name: 'asOrg', name: 'asOrg',
label: this.$t('entities.asOrg'), label: this.$t('entities.asOrg'),
value: _.get(n.myData, 'basicInfo.asn.organization', '-') value: _.get(n.data, 'basicInfo.asn.organization', '-')
}, },
{ {
name: 'isp', name: 'isp',
label: this.$t('entities.graph.isp'), label: this.$t('entities.graph.isp'),
value: _.get(n.myData, 'basicInfo.location.isp', '-') value: _.get(n.data, 'basicInfo.location.isp', '-')
}, },
{ name: 'location', label: this.$t('overall.location'), value: this.location(n.myData) } { name: 'location', label: this.$t('overall.location'), value: this.location(n.data) }
] ]
this.relationList = [ this.relationList = [
{ {
icon: 'cn-icon cn-icon-subdomain', icon: 'cn-icon cn-icon-subdomain',
name: 'domain', name: 'domain',
label: this.$t('entity.graph.resolveDomain'), label: this.$t('entity.graph.resolveDomain'),
value: _.get(n.myData, 'relatedEntity.domain.list', []).length, value: _.get(n.data, 'relatedEntities.domain.list', []).length,
total: _.get(n.myData, 'relatedEntity.domain.total', 0) || 0 total: _.get(n.data, 'relatedEntities.domain.total', 0) || 0
}, },
{ {
icon: 'cn-icon cn-icon-app-name', icon: 'cn-icon cn-icon-app-name',
name: 'app', name: 'app',
label: this.$t('entities.tab.relatedApp'), label: this.$t('entities.tab.relatedApp'),
value: _.get(n.myData, 'relatedEntity.app.list', []).length, value: _.get(n.data, 'relatedEntities.app.list', []).length,
total: _.get(n.myData, 'relatedEntity.app.total', '0') || 0 total: _.get(n.data, 'relatedEntities.app.total', '0') || 0
} }
] ]
break break
} }
case 'domain': { case 'domain': {
const expireDate = _.get(n.myData, 'basicInfo.whois.expireDate', '') const expireDate = _.get(n.data, 'basicInfo.whois.expireDate', '')
const createDate = _.get(n.myData, 'basicInfo.whois.createDate', '') const createDate = _.get(n.data, 'basicInfo.whois.createDate', '')
this.detailCards = [ this.detailCards = [
{ {
name: 'categoryName', name: 'categoryName',
label: this.$t('entities.category'), label: this.$t('entities.category'),
value: _.get(n.myData, 'basicInfo.category.categoryName', '-') value: _.get(n.data, 'basicInfo.category.categoryName', '-')
}, },
{ {
name: 'categoryGroup', name: 'categoryGroup',
label: this.$t('entities.group'), label: this.$t('entities.group'),
value: _.get(n.myData, 'basicInfo.category.categoryGroup', '-') value: _.get(n.data, 'basicInfo.category.categoryGroup', '-')
}, },
{ {
name: 'reputationLevel', name: 'reputationLevel',
label: this.$t('entities.creditLevel2'), label: this.$t('entities.creditLevel2'),
value: _.get(n.myData, 'basicInfo.category.reputationLevel', '-') value: _.get(n.data, 'basicInfo.category.reputationLevel', '-')
}, },
{ {
name: 'expireDate', name: 'expireDate',
@@ -332,17 +333,17 @@ export default {
{ {
name: 'registrarName', name: 'registrarName',
label: this.$t('entities.registrar'), label: this.$t('entities.registrar'),
value: _.get(n.myData, 'basicInfo.whois.registrarName', '-') value: _.get(n.data, 'basicInfo.whois.registrarName', '-')
}, },
{ {
name: 'registrantOrg', name: 'registrantOrg',
label: this.$t('entities.registry'), label: this.$t('entities.registry'),
value: _.get(n.myData, 'basicInfo.whois.registrantOrg', '-') value: _.get(n.data, 'basicInfo.whois.registrantOrg', '-')
}, },
{ {
name: 'registrantCountry', name: 'registrantCountry',
label: this.$t('entities.registrationCountry'), label: this.$t('entities.registrationCountry'),
value: _.get(n.myData, 'basicInfo.whois.registrantCountry', '-') value: _.get(n.data, 'basicInfo.whois.registrantCountry', '-')
}, },
{ {
name: 'createDate', name: 'createDate',
@@ -352,7 +353,7 @@ export default {
{ {
name: 'email', name: 'email',
label: this.$t('entities.registryEmail'), label: this.$t('entities.registryEmail'),
value: _.get(n.myData, 'basicInfo.whois.email', '-') value: _.get(n.data, 'basicInfo.whois.email', '-')
} }
] ]
this.relationList = [ this.relationList = [
@@ -360,22 +361,22 @@ export default {
icon: 'cn-icon cn-icon-resolve-ip', icon: 'cn-icon cn-icon-resolve-ip',
name: 'ip', name: 'ip',
label: this.$t('entities.graph.resolveIp'), label: this.$t('entities.graph.resolveIp'),
value: _.get(n.myData, 'relatedEntity.ip.list', []).length, value: _.get(n.data, 'relatedEntities.ip.list', []).length,
total: _.get(n.myData, 'relatedEntity.ip.total', '0') || 0 total: _.get(n.data, 'relatedEntities.ip.total', '0') || 0
}, },
{ {
icon: 'cn-icon cn-icon-subdomain', icon: 'cn-icon cn-icon-subdomain',
name: 'domain', name: 'domain',
label: this.$t('entities.subdomain'), label: this.$t('entities.subdomain'),
value: _.get(n.myData, 'relatedEntity.domain.list', []).length, value: _.get(n.data, 'relatedEntities.domain.list', []).length,
total: _.get(n.myData, 'relatedEntity.domain.total', '0') || 0 total: _.get(n.data, 'relatedEntities.domain.total', '0') || 0
}, },
{ {
icon: 'cn-icon cn-icon-app-name', icon: 'cn-icon cn-icon-app-name',
name: 'app', name: 'app',
label: this.$t('entities.tab.relatedApp'), label: this.$t('entities.tab.relatedApp'),
value: _.get(n.myData, 'relatedEntity.app.list', []).length, value: _.get(n.data, 'relatedEntities.app.list', []).length,
total: _.get(n.myData, 'relatedEntity.app.total', 0) || 0 total: _.get(n.data, 'relatedEntities.app.total', 0) || 0
} }
] ]
break break
@@ -385,32 +386,32 @@ export default {
{ {
name: 'appCategory', name: 'appCategory',
label: this.$t('entities.category'), label: this.$t('entities.category'),
value: _.get(n.myData, 'basicInfo.category.appCategory', '-') value: _.get(n.data, 'basicInfo.category.appCategory', '-')
}, },
{ {
name: 'appSubcategory', name: 'appSubcategory',
label: this.$t('entities.subcategory'), label: this.$t('entities.subcategory'),
value: _.get(n.myData, 'basicInfo.category.appSubcategory', '-') value: _.get(n.data, 'basicInfo.category.appSubcategory', '-')
}, },
{ {
name: 'appRisk', name: 'appRisk',
label: this.$t('entities.riskLevel'), label: this.$t('entities.riskLevel'),
value: this.appRisk(_.get(n.myData, 'basicInfo.category.appRisk', '-')) value: this.appRisk(_.get(n.data, 'basicInfo.category.appRisk', '-'))
}, },
{ {
name: 'appTechnology', name: 'appTechnology',
label: this.$t('overall.technology'), label: this.$t('overall.technology'),
value: _.get(n.myData, 'basicInfo.category.appTechnology', '-') value: _.get(n.data, 'basicInfo.category.appTechnology', '-')
}, },
{ {
name: 'appLongname', name: 'appLongname',
label: this.$t('overall.appFullName'), label: this.$t('overall.appFullName'),
value: _.get(n.myData, 'basicInfo.category.appLongname', '-') value: _.get(n.data, 'basicInfo.category.appLongname', '-')
}, },
{ {
name: 'appDescription', name: 'appDescription',
label: this.$t('config.dataSource.description'), label: this.$t('config.dataSource.description'),
value: _.get(n.myData, 'basicInfo.category.appDescription', '-') value: _.get(n.data, 'basicInfo.category.appDescription', '-')
} }
] ]
@@ -419,15 +420,15 @@ export default {
icon: 'cn-icon cn-icon-resolve-ip', icon: 'cn-icon cn-icon-resolve-ip',
name: 'ip', name: 'ip',
label: this.$t('entities.tab.relatedIp'), label: this.$t('entities.tab.relatedIp'),
value: _.get(n.myData, 'relatedEntity.ip.list', []).length, value: _.get(n.data, 'relatedEntities.ip.list', []).length,
total: _.get(n.myData, 'relatedEntity.ip.total', '0') || 0 total: _.get(n.data, 'relatedEntities.ip.total', '0') || 0
}, },
{ {
icon: 'cn-icon cn-icon-subdomain', icon: 'cn-icon cn-icon-subdomain',
name: 'domain', name: 'domain',
label: this.$t('entities.graph.relatedDomain'), label: this.$t('entities.graph.relatedDomain'),
value: _.get(n.myData, 'relatedEntity.domain.list', []).length, value: _.get(n.data, 'relatedEntities.domain.list', []).length,
total: _.get(n.myData, 'relatedEntity.domain.total', '0') || 0 total: _.get(n.data, 'relatedEntities.domain.total', '0') || 0
} }
] ]
} }

View File

@@ -4,11 +4,11 @@
<div class="graph-list-header"> <div class="graph-list-header">
<div> <div>
<div class="graph-list-header-title"> <div class="graph-list-header-title">
<i class="cn-icon cn-icon-resolve-ip graph-list-header-icon"></i> <i :class="`${iconClass} graph-list-header-icon`"></i>
<span>{{ title }}</span> <span>{{ title }}</span>
</div> </div>
<div class="graph-list-header-number"> <div class="graph-list-header-number">
{{ $t('entity.graph.associatedCount') }}:&nbsp;<span>{{$_.get(node, 'sourceNode.myData.relatedEntity.' + $_.get(node, 'myData.entityType') + '.total', '-')}}</span> {{ $t('entity.graph.associatedCount') }}:&nbsp;<span>{{$_.get(node, 'sourceNode.data.relatedEntities.' + $_.get(node, 'data.entityType') + '.total', '-')}}</span>
</div> </div>
</div> </div>
@@ -16,10 +16,10 @@
</div> </div>
<div class="graph-list-expand-btn-block"> <div class="graph-list-expand-btn-block">
<div class="graph-list-expand-btn graph-list-expand-btn__display" :class="{ 'graph-list-expand-btn--disabled': expandBtnDisable }" @click="expandList"> <span class="graph-list-expand-btn" :class="{ 'graph-list-expand-btn--disabled': expandBtnDisable }" @click="expandList">
<i class="cn-icon cn-icon-expand-continue graph-expand-continue"></i> <i class="cn-icon cn-icon-expand-continue graph-expand-continue"></i>
{{ $t('entity.graph.continueToExpand') }} {{ $t('entity.graph.continueToExpand') }}
</div> </span>
</div> </div>
<div> <div>
@@ -28,14 +28,14 @@
<div class="digital-certificate-header__icon graph-header__icon"></div> <div class="digital-certificate-header__icon graph-header__icon"></div>
<div class="graph-list-content-header "> <div class="graph-list-content-header ">
{{ $t('entity.graph.expandedEntityCount') }}:&nbsp {{ $t('entity.graph.expandedEntityCount') }}:&nbsp
<span>{{$_.get(node, 'sourceNode.myData.relatedEntity.' + $_.get(node, 'myData.entityType') + '.list', []).length}}</span> <span>{{$_.get(node, 'sourceNode.data.relatedEntities.' + $_.get(node, 'data.entityType') + '.list', []).length}}</span>
</div> </div>
</div> </div>
<div class="graph-list-content"> <div class="graph-list-content">
<div v-for="(item, index) in $_.get(node, 'sourceNode.myData.relatedEntity.' + $_.get(node, 'myData.entityType') + '.list', [])" :key="index"> <div v-for="(item, index) in $_.get(node, 'sourceNode.data.relatedEntities.' + $_.get(node, 'data.entityType') + '.list', [])" :key="index">
<div class="graph-list-item-ip"><span @click="expandDetail">{{ item.vertex }}</span></div> <div class="graph-list-item-ip"><span @click="expandDetail">{{ item.vertex }}</span></div>
<template v-if="$_.get(node, 'myData.entityType', '') === 'ip'"> <template v-if="$_.get(node, 'data.entityType', '') === 'ip'">
<div class="graph-list-item-block"> <div class="graph-list-item-block">
<div class="graph-list-item padding-b-4"> <div class="graph-list-item padding-b-4">
<div class="graph-list-item-label">{{ $t('overall.location') }}:</div> <div class="graph-list-item-label">{{ $t('overall.location') }}:</div>
@@ -54,7 +54,7 @@
</div> </div>
</div> </div>
</template> </template>
<template v-else-if="$_.get(node, 'myData.entityType', '') === 'domain'"> <template v-else-if="$_.get(node, 'data.entityType', '') === 'domain'">
<div class="graph-list-item-block"> <div class="graph-list-item-block">
<div class="graph-list-item__app"> <div class="graph-list-item__app">
<div class="graph-list-item-label__app">{{$t('entities.category')}}:</div> <div class="graph-list-item-label__app">{{$t('entities.category')}}:</div>
@@ -74,7 +74,7 @@
</div> </div>
</div> </div>
</template> </template>
<template v-else-if="$_.get(node, 'myData.entityType', '') === 'app'"> <template v-else-if="$_.get(node, 'data.entityType', '') === 'app'">
<div class="graph-list-item-block"> <div class="graph-list-item-block">
<div class="graph-list-item__app"> <div class="graph-list-item__app">
<div class="graph-list-item-label__app">APP ID:</div> <div class="graph-list-item-label__app">APP ID:</div>
@@ -98,7 +98,7 @@
</div> </div>
</div> </div>
</template> </template>
<div class="graph-list-dividing-line" v-if="index !== $_.get(node, 'sourceNode.myData.relatedEntity.' + $_.get(node, 'myData.entityType') + '.list', []).length - 1"></div> <div class="graph-list-dividing-line" v-if="index !== $_.get(node, 'sourceNode.data.relatedEntities.' + $_.get(node, 'data.entityType') + '.list', []).length - 1"></div>
</div> </div>
</div> </div>
</div> </div>
@@ -132,8 +132,8 @@ export default {
}, },
computed: { computed: {
expandBtnDisable () { expandBtnDisable () {
const loaded = _.get(this.node, 'sourceNode.myData.relatedEntity.' + _.get(this.node, 'myData.entityType') + '.list', []).length const loaded = _.get(this.node, 'sourceNode.data.relatedEntities.' + _.get(this.node, 'data.entityType') + '.list', []).length
const total = _.get(this.node, 'sourceNode.myData.relatedEntity.' + _.get(this.node, 'myData.entityType') + '.total', 0) const total = _.get(this.node, 'sourceNode.data.relatedEntities.' + _.get(this.node, 'data.entityType') + '.total', 0)
return !(loaded < total && total > 10 && (loaded && loaded < 50)) return !(loaded < total && total > 10 && (loaded && loaded < 50))
}, },
appRisk () { appRisk () {
@@ -147,9 +147,9 @@ export default {
title () { title () {
let title = '' let title = ''
if (this.node) { if (this.node) {
const entityType = _.get(this.node, 'myData.entityType', '') const entityType = _.get(this.node, 'data.entityType', '')
if (entityType) { if (entityType) {
const sourceType = _.get(this.node, 'sourceNode.myData.entityType', '') const sourceType = _.get(this.node, 'sourceNode.data.entityType', '')
switch (entityType) { switch (entityType) {
case 'ip': { case 'ip': {
if (sourceType === 'domain') { if (sourceType === 'domain') {
@@ -177,6 +177,26 @@ export default {
} }
} }
return title return title
},
iconClass () {
let className
switch (_.get(this.node, 'data.entityType', '')) {
case ('ip'): {
className = 'cn-icon cn-icon-ip2'
break
}
case ('domain'): {
className = 'cn-icon cn-icon-subdomain'
break
}
case ('app'): {
className = 'cn-icon cn-icon-app2'
break
}
default:
break
}
return className
} }
}, },
methods: { methods: {

View File

@@ -1,4 +1,4 @@
export default class Edge { export default class Link {
constructor (sourceNode, targetNode, type = linkType.normal, distance, level = 1) { constructor (sourceNode, targetNode, type = linkType.normal, distance, level = 1) {
this.source = sourceNode.id this.source = sourceNode.id
this.target = targetNode.id this.target = targetNode.id

View File

@@ -10,14 +10,13 @@ export default class Node {
* type: 对应nodeType * type: 对应nodeType
* cfg: { entityType, entityName } * cfg: { entityType, entityName }
* */ * */
constructor (type, id, data, sourceNode, strength, img, level) { constructor (type, id, data, sourceNode, strength, img) {
this.id = id this.id = id
this.type = type this.type = type
this.vx = 0 this.vx = 0
this.vy = 0 this.vy = 0
this.fx = level === 0 ? 0 : null// 设置为0即可固定中心节点。0为中心节点1为中心节点的子节点2为第三级节点 this.fx = sourceNode ? null : 0// 设置为0即可固定中心节点。0为中心节点1为中心节点的子节点2为第三级节点
this.fy = level === 0 ? 0 : null// 设置为0即可固定中心节点。0为中心节点1为中心节点的子节点2为第三级节点 this.fy = sourceNode ? null : 0// 设置为0即可固定中心节点。0为中心节点1为中心节点的子节点2为第三级节点
this.level = level
this.img = img this.img = img
this.strength = strength || -10 this.strength = strength || -10
this.sourceNode = sourceNode this.sourceNode = sourceNode
@@ -25,7 +24,6 @@ export default class Node {
this.data = { this.data = {
entityType: data.entityType, entityType: data.entityType,
entityName: data.entityName entityName: data.entityName
// img:data.img
} }
this.label = generateLabel(type, id, data, sourceNode) this.label = generateLabel(type, id, data, sourceNode)
this.name = builtTooltip(this) this.name = builtTooltip(this)
@@ -73,6 +71,7 @@ export default class Node {
if (this.data.entityType === entityType.domain && targetEntityType === entityType.domain) { if (this.data.entityType === entityType.domain && targetEntityType === entityType.domain) {
_targetEntityType = 'subdomain' _targetEntityType = 'subdomain'
} }
console.info(this.data, targetEntityType)
const url = `${api.entity.entityGraph[`${this.data.entityType}Related${_.upperFirst(_targetEntityType)}`]}?resource=${this.data.entityName}&pageSize=10&pageNo=${this.data.relatedEntities[targetEntityType].pageNo + 1}` const url = `${api.entity.entityGraph[`${this.data.entityType}Related${_.upperFirst(_targetEntityType)}`]}?resource=${this.data.entityName}&pageSize=10&pageNo=${this.data.relatedEntities[targetEntityType].pageNo + 1}`
const response = await axios.get(url).catch(e => { const response = await axios.get(url).catch(e => {
console.error(e) console.error(e)