CN-1548 feat: 关系图right-box
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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') }}: <span>{{$_.get(node, 'sourceNode.myData.relatedEntity.' + $_.get(node, 'myData.entityType') + '.total', '-')}}</span>
|
{{ $t('entity.graph.associatedCount') }}: <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') }}: 
|
{{ $t('entity.graph.expandedEntityCount') }}: 
|
||||||
<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: {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user