左屏服务器运行流程图
@ -11,6 +11,8 @@
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/x6": "^2.18.1",
|
||||
"@antv/x6-vue-shape": "^2.1.2",
|
||||
"@turf/turf": "^7.1.0",
|
||||
"@visactor/vtable": "^1.13.2",
|
||||
"@visactor/vtable-gantt": "^1.13.2",
|
||||
@ -24,6 +26,7 @@
|
||||
"chroma-js": "^3.1.2",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.5.1",
|
||||
"elkjs": "^0.10.0",
|
||||
"es-toolkit": "^1.32.0",
|
||||
"lodash": "^4.17.21",
|
||||
"maplibre-gl": "^5.0.1",
|
||||
|
BIN
public/images/topology/a.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
public/images/topology/arrow-bottom.png
Normal file
After Width: | Height: | Size: 512 B |
BIN
public/images/topology/arrow-left.png
Normal file
After Width: | Height: | Size: 553 B |
BIN
public/images/topology/com.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
public/images/topology/cpu.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
public/images/topology/duankai.png
Normal file
After Width: | Height: | Size: 918 B |
BIN
public/images/topology/fwq.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
public/images/topology/hezi.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
public/images/topology/xinhao.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/images/topology/yp.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
public/images/topology/zhuji.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
1512
public/json/topology.json
Normal file
BIN
src/assets/image/topology/cpuicon.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
src/assets/image/topology/neicun.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
src/assets/image/topology/topology_bg.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
src/assets/image/topology/ypkj.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
@ -46,6 +46,11 @@ const router = createRouter({
|
||||
name: 'Test',
|
||||
component: () => import('@/views/Test/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/TopologyMap',
|
||||
name: 'TopologyMap',
|
||||
component: () => import('@/views/TopologyMap/index.vue'),
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
97
src/views/TopologyMap/components/dialogNode.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div class="dialog" :style="{ width: width + 'px' }" v-if="id.indexOf('cpu') != -1">
|
||||
<span class="arrow-bottom" :style="{ left: (width - 17) / 2 + 'px' }"></span>
|
||||
<p>CPU:{{ cpu }}</p>
|
||||
<p>内存:{{ neicun }}</p>
|
||||
<p>硬盘:{{ yingpan }}</p>
|
||||
</div>
|
||||
<div class="dialog" :style="{ width: width + 'px' }" v-if="id.indexOf('yp2') != -1">
|
||||
<span class="arrow-left" :style="{ top: (height - 17) / 2 + 'px' }"></span>
|
||||
<p>数据:{{ shuju }}</p>
|
||||
<p>CPU:{{ cpu }}</p>
|
||||
<p>内存:{{ neicun }}</p>
|
||||
<p>硬盘:{{ yingpan }}</p>
|
||||
</div>
|
||||
<div class="dialog" :style="{ width: width + 'px' }" v-if="id.indexOf('yp1') != -1">
|
||||
<span class="arrow-bottom" :style="{ left: (width - 17) / 2 + 'px' }"></span>
|
||||
<p>数据:{{ shuju }}</p>
|
||||
<p>CPU:{{ cpu }}</p>
|
||||
<p>内存:{{ neicun }}</p>
|
||||
<p>硬盘:{{ yingpan }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import { defineComponent, toRefs, reactive, onMounted } from 'vue'
|
||||
// import { useRoute, useRouter } from 'vue-router';
|
||||
export default defineComponent({
|
||||
name: '',
|
||||
inject: ['getNode'],
|
||||
components: {},
|
||||
setup() {
|
||||
// const route = useRoute();
|
||||
// const router = useRouter();
|
||||
const state = reactive({
|
||||
id: "",
|
||||
"width": 70,
|
||||
"height": 55,
|
||||
"cpu": "80%",
|
||||
"neicun": "70%",
|
||||
"yingpan": "50%",
|
||||
"shuju": "128G/520G"
|
||||
})
|
||||
const getNode: Function | undefined = inject('getNode');
|
||||
onMounted(() => {
|
||||
const node = getNode();
|
||||
let info = node.getData();
|
||||
if (node) {
|
||||
console.log(info, 'info')
|
||||
state.id = info.id;
|
||||
state.width = info.width;
|
||||
state.height = info.height;
|
||||
state.shuju = info.shuju;
|
||||
state.cpu = info.cpu;
|
||||
state.neicun = info.neicun;
|
||||
state.yingpan = info.yingpan;
|
||||
}
|
||||
})
|
||||
return { ...toRefs(state) };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
.dialog {
|
||||
background: #001232;
|
||||
border: 0.4px solid rgba(22, 238, 243, 1);
|
||||
box-shadow: inset 0px 0px 13px 0px rgba(22, 238, 243, 1);
|
||||
border-radius: 4px 4px 4px 0px 0px 0px 4px;
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
padding: 3px 5px;
|
||||
z-index: 999;
|
||||
|
||||
.arrow-bottom {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 17px;
|
||||
height: 8px;
|
||||
bottom: -7px;
|
||||
background: url("./images/topology/arrow-bottom.png") no-repeat;
|
||||
}
|
||||
|
||||
.arrow-left {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 17px;
|
||||
left: -7px;
|
||||
background: url("./images/topology/arrow-left.png") no-repeat;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #16EEF3;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
886
src/views/TopologyMap/index.vue
Normal file
@ -0,0 +1,886 @@
|
||||
<template>
|
||||
<div class="topology-map">
|
||||
<div class="top">
|
||||
<div class="left"><span>互联网</span></div>
|
||||
<div class="center"><span>办公网</span></div>
|
||||
<div class="right"><span>高密网</span></div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div id="container"></div>
|
||||
<TeleportContainer />
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="left">
|
||||
<i class="triangle"></i>
|
||||
<i class="rectangle"></i>
|
||||
<div class="b-con">
|
||||
<div class="b-left yingpan">
|
||||
<span>硬盘空间</span>
|
||||
</div>
|
||||
<div class="b-right">
|
||||
<div class="box">
|
||||
<p class="text">服务器1</p>
|
||||
<p class="line"><i class="jd" :style="{ 'width': 127 / 1942 * 100 + '%' }"></i></p>
|
||||
<p class="text">1942T<span class="yy">已用127T</span></p>
|
||||
</div>
|
||||
<div class="box">
|
||||
<p class="text">服务器2</p>
|
||||
<p class="line"><i class="jd" :style="{ 'width': 127 / 1942 * 100 + '%' }"></i></p>
|
||||
<p class="text">1942T<span class="yy">已用127T</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center">
|
||||
<i class="triangle"></i>
|
||||
<i class="rectangle"></i>
|
||||
<div class="b-con">
|
||||
<div class="b-left neicun">
|
||||
<span>内存</span>
|
||||
</div>
|
||||
<div class="b-right">
|
||||
<div class="box">
|
||||
<p class="text">服务器1</p>
|
||||
<p class="line"><i class="jd" :style="{ 'width': 27 / 194 * 100 + '%' }"></i></p>
|
||||
<p class="text">194T<span class="yy">已用27T</span></p>
|
||||
</div>
|
||||
<div class="box">
|
||||
<p class="text">服务器2</p>
|
||||
<p class="line"><i class="jd" :style="{ 'width': 89 / 123 * 100 + '%' }"></i></p>
|
||||
<p class="text">123T<span class="yy">已用89T</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<i class="triangle"></i>
|
||||
<i class="rectangle"></i>
|
||||
<div class="b-con">
|
||||
<div class="b-left cpu">
|
||||
<span>CPU</span>
|
||||
</div>
|
||||
<div class="b-right chart-box">
|
||||
<div ref="chart1Ref" class="chart"></div>
|
||||
<div ref="chart2Ref" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import { defineComponent, toRefs, reactive, onMounted } from 'vue'
|
||||
import axios from 'axios'
|
||||
import DialogNode from './components/dialogNode.vue';
|
||||
import { Graph, Cell } from '@antv/x6'
|
||||
import { register, getTeleport } from '@antv/x6-vue-shape'
|
||||
import * as echarts from 'echarts';
|
||||
Graph.registerNode('elk-node',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'rect',
|
||||
selector: 'body',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
fill: 'rgba(255,255,255,0.02)',
|
||||
stroke: 'rgba(142,255,253,0.25)',
|
||||
strokeWidth: 1,
|
||||
}
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('rect-node',
|
||||
{
|
||||
inherit: 'rect',
|
||||
attrs: {
|
||||
body: {
|
||||
fill: 'none',
|
||||
stroke: 'none',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
tools: [
|
||||
{
|
||||
name: 'boundary',
|
||||
args: {
|
||||
padding: 5,
|
||||
attrs: {
|
||||
fill: 'none',
|
||||
stroke: 'rgba(142,248,255,0.25)',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-a',
|
||||
{
|
||||
width: 48,
|
||||
height: 39,
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'rect',
|
||||
selector: 'body',
|
||||
},
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
fill: 'rgba(255,255,255,0)',
|
||||
strokeWidth: 0
|
||||
},
|
||||
img: {
|
||||
'xlink:href': "./images/topology/a.png", // 设置图片路径
|
||||
width: 48,
|
||||
height: 39,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-cpu',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
// {
|
||||
// tagName: 'rect',
|
||||
// selector: 'bg',
|
||||
// },
|
||||
// {
|
||||
// tagName: 'text',
|
||||
// selector: 'label',
|
||||
// },
|
||||
],
|
||||
attrs: {
|
||||
img: {
|
||||
'xlink:href': "./images/topology/cpu.png", // 设置图片路径
|
||||
width: 74,
|
||||
height: 86,
|
||||
},
|
||||
// bg: {
|
||||
// stroke: '#5F95FF',
|
||||
// strokeWidth: 1,
|
||||
// fill: 'rgba(0,0,0,0.5)',
|
||||
// refWidth: -10,
|
||||
// refHeight: -20,
|
||||
// rx: 5,
|
||||
// ry: 5,
|
||||
// refX: 5,
|
||||
// refY: -80,
|
||||
// },
|
||||
// label: {
|
||||
// refX: 20,
|
||||
// refY: -70,
|
||||
// fontSize: 10,
|
||||
// fill: '#fff',
|
||||
// },
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-fs',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
img: {
|
||||
'xlink:href': "./images/topology/fs.png", // 设置图片路径
|
||||
width: 48,
|
||||
height: 86,
|
||||
}
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-fwq',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
img: {
|
||||
'xlink:href': "./images/topology/fwq.png", // 设置图片路径
|
||||
width: 36,
|
||||
height: 86,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-yp',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
img: {
|
||||
'xlink:href': "./images/topology/yp.png", // 设置图片路径
|
||||
width: 48,
|
||||
height: 86,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-com',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
img: {
|
||||
'xlink:href': "./images/topology/com.png", // 设置图片路径
|
||||
width: 64,
|
||||
height: 52,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-zhuji',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
img: {
|
||||
'xlink:href': "./images/topology/zhuji.png", // 设置图片路径
|
||||
width: 53,
|
||||
height: 81,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-xinhao',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'rect',
|
||||
selector: 'body',
|
||||
},
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
fill: 'rgba(255,255,255,0)',
|
||||
strokeWidth: 0,
|
||||
},
|
||||
img: {
|
||||
'xlink:href': "./images/topology/xinhao.png", // 设置图片路径
|
||||
width: 27,
|
||||
height: 28,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
Graph.registerNode('node-hezi',
|
||||
{
|
||||
inherit: 'rect',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'rect',
|
||||
selector: 'body',
|
||||
},
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
body: {
|
||||
fill: 'rgba(255,255,255,0)',
|
||||
strokeWidth: 0
|
||||
},
|
||||
img: {
|
||||
'xlink:href': "./images/topology/hezi.png", // 设置图片路径
|
||||
width: 55,
|
||||
height: 56,
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
Graph.registerEdge('elk-edge',
|
||||
{
|
||||
inherit: 'edge',
|
||||
markup: [
|
||||
{
|
||||
tagName: 'path',
|
||||
selector: 'p1',
|
||||
},
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
],
|
||||
attrs: {
|
||||
p1: {
|
||||
connection: true,
|
||||
fill: 'none',
|
||||
stroke: '#16EEF3',
|
||||
strokeWidth: 1,
|
||||
targetMarker: {
|
||||
name: 'block',
|
||||
width: 6,
|
||||
height: 6,
|
||||
},
|
||||
},
|
||||
img: {
|
||||
'xlink:href': "./images/topology/duankai.png", // 设置图片路径
|
||||
width: 16,
|
||||
height: 16,
|
||||
r: 10,
|
||||
y: -8,
|
||||
atConnectionRatio: 0.2,
|
||||
},
|
||||
},
|
||||
// attrs: {
|
||||
// line: {
|
||||
// stroke: '#16EEF3',
|
||||
// strokeWidth: 1,
|
||||
// targetMarker: {
|
||||
// name: 'block',
|
||||
// width: 6,
|
||||
// height: 6,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
zIndex: 1,
|
||||
},
|
||||
true,
|
||||
)
|
||||
register({
|
||||
shape: 'node-dialog',
|
||||
component: DialogNode,
|
||||
zIndex: 15,
|
||||
})
|
||||
|
||||
interface Position {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
let graph: Graph;
|
||||
const TeleportContainer = getTeleport()
|
||||
|
||||
export default defineComponent({
|
||||
name: '',
|
||||
components: { TeleportContainer },
|
||||
setup() {
|
||||
// const route = useRoute();
|
||||
// const router = useRouter();
|
||||
// const elk = new ELK()
|
||||
const portIdToNodeIdMap: Record<string, string> = {}
|
||||
const cells: Cell[] = []
|
||||
const chart1Ref = ref(null);
|
||||
const chart2Ref = ref(null);
|
||||
const state = reactive({
|
||||
json: [],
|
||||
|
||||
})
|
||||
onMounted(async () => {
|
||||
graph = new Graph({
|
||||
container: document.getElementById('container'),
|
||||
width: 1795,
|
||||
height: 700,
|
||||
// background: {
|
||||
// color: 'rgba(255, 255, 255, 1)',
|
||||
// },
|
||||
router: { name: 'manhattan' },
|
||||
connector: { name: 'rounded' },
|
||||
// interacting: {
|
||||
// nodeMovable: false,
|
||||
// edgeMovable: false,
|
||||
// },
|
||||
translating: {
|
||||
restrict(view) {
|
||||
if (view) {
|
||||
const cell = view.cell
|
||||
if (cell.isNode()) {
|
||||
const parent = cell.getParent()
|
||||
if (parent) {
|
||||
return parent.getBBox()
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
},
|
||||
})
|
||||
await getData().then(data => {
|
||||
addChildren(data.children || [])
|
||||
addEdges(data.edges || [])
|
||||
graph.zoomTo(1)
|
||||
// graph.centerContent()
|
||||
})
|
||||
|
||||
getCharts();
|
||||
})
|
||||
|
||||
const addChildren = (children, pos?: Position) => {
|
||||
let leftParentNode = graph.addNode({
|
||||
shape: 'elk-node',
|
||||
id: "left",
|
||||
label: "互联网",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
size: {
|
||||
"width": 347,
|
||||
"height": 666,
|
||||
},
|
||||
zIndex: 1,
|
||||
})
|
||||
let centerParentNode = graph.addNode({
|
||||
shape: 'elk-node',
|
||||
id: "center",
|
||||
label: "办公网",
|
||||
"x": 366,
|
||||
"y": 0,
|
||||
size: {
|
||||
"width": 595,
|
||||
"height": 666,
|
||||
},
|
||||
zIndex: 1,
|
||||
})
|
||||
let rightParentNode = graph.addNode({
|
||||
shape: 'elk-node',
|
||||
id: "right",
|
||||
label: "高密网",
|
||||
"x": 981,
|
||||
"y": 0,
|
||||
size: {
|
||||
"width": 814,
|
||||
"height": 666,
|
||||
},
|
||||
zIndex: 1,
|
||||
})
|
||||
children.forEach((child) => {
|
||||
const position = {
|
||||
x: (child.x || 0) + (pos ? pos.x : 0),
|
||||
y: (child.y || 0) + (pos ? pos.y : 0),
|
||||
}
|
||||
let label: string = ''
|
||||
if (typeof child.labels === 'string') {
|
||||
label = child.labels
|
||||
} else if (Array.isArray(child.labels) && child.labels[0]) {
|
||||
label = child.labels[0].text
|
||||
}
|
||||
let type = "elk-node"
|
||||
if (child.type && child.type === 'a') {
|
||||
type = 'node-a'
|
||||
} else if (child.type && child.type === 'cpu') {
|
||||
type = 'node-cpu'
|
||||
} else if (child.type && child.type === 'fwq') {
|
||||
type = 'node-fwq'
|
||||
} else if (child.type && child.type === 'yp') {
|
||||
type = 'node-yp'
|
||||
} else if (child.type && child.type === 'com') {
|
||||
type = 'node-com'
|
||||
} else if (child.type && child.type === 'rect') {
|
||||
type = 'rect-node'
|
||||
} else if (child.type && child.type === 'zhuji') {
|
||||
type = 'node-zhuji'
|
||||
} else if (child.type && child.type === 'xinhao') {
|
||||
type = 'node-xinhao'
|
||||
} else if (child.type && child.type === 'hezi') {
|
||||
type = 'node-hezi'
|
||||
}
|
||||
const node = graph.addNode({
|
||||
shape: type,
|
||||
id: child.id,
|
||||
position,
|
||||
label,
|
||||
body: {
|
||||
width: child.width || 0,
|
||||
height: child.height || 0,
|
||||
},
|
||||
size: {
|
||||
width: child.width || 0,
|
||||
height: child.height || 0,
|
||||
},
|
||||
zIndex: 2,
|
||||
})
|
||||
if (child.infos) {
|
||||
console.log(child.infos)
|
||||
const dialog = graph.createNode({
|
||||
shape: 'node-dialog',
|
||||
data: {
|
||||
id: child.id,
|
||||
...child.infos
|
||||
},
|
||||
x: child.infos.x || 0,
|
||||
y: child.infos.y || 0,
|
||||
zIndex: 3
|
||||
})
|
||||
node.addChild(dialog)
|
||||
}
|
||||
if (child.parentId === 'left') {
|
||||
leftParentNode.addChild(node)
|
||||
} else if (child.parentId === 'center') {
|
||||
centerParentNode.addChild(node)
|
||||
} else if (child.parentId === 'right') {
|
||||
rightParentNode.addChild(node)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
cells.push(leftParentNode)
|
||||
cells.push(centerParentNode)
|
||||
cells.push(rightParentNode)
|
||||
}
|
||||
const addEdges = (edges) => {
|
||||
edges.forEach((edge) => {
|
||||
let edgeline = {}
|
||||
let markup = []
|
||||
if (edge.isTrue !== undefined && edge.isTrue === false) {
|
||||
markup = [
|
||||
{
|
||||
tagName: 'path',
|
||||
selector: 'p1',
|
||||
},
|
||||
{
|
||||
tagName: 'image',
|
||||
selector: 'img',
|
||||
},
|
||||
]
|
||||
} else {
|
||||
markup = [
|
||||
{
|
||||
tagName: 'path',
|
||||
selector: 'p1',
|
||||
}
|
||||
]
|
||||
}
|
||||
if (edge.vertices) {
|
||||
edgeline = {
|
||||
shape: 'elk-edge',
|
||||
source: edge.sources,
|
||||
target: edge.targets,
|
||||
vertices: edge.vertices,
|
||||
markup: markup,
|
||||
}
|
||||
} else {
|
||||
edgeline = {
|
||||
shape: 'elk-edge',
|
||||
source: edge.sources,
|
||||
target: edge.targets,
|
||||
router: {
|
||||
name: 'er',
|
||||
args: {
|
||||
offset: 'center'
|
||||
}
|
||||
},
|
||||
markup: markup,
|
||||
}
|
||||
}
|
||||
graph.addEdge(edgeline)
|
||||
})
|
||||
}
|
||||
|
||||
const getData = () => {
|
||||
return axios.get("./json/topology.json").then(res => {
|
||||
if (res.status === 200) {
|
||||
return Promise.resolve(res.data)
|
||||
} else {
|
||||
console.log('获取TLE失败')
|
||||
return Promise.reject(res.statusText)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getCharts = () => {
|
||||
const chart1 = echarts.init(chart1Ref.value);
|
||||
const chart2 = echarts.init(chart2Ref.value);
|
||||
let option1 = getOption('服务器1', 46)
|
||||
let option2 = getOption('服务器2', 23)
|
||||
|
||||
// 设置配置项并渲染图表
|
||||
chart1.setOption(option1);
|
||||
chart2.setOption(option2);
|
||||
}
|
||||
const getOption = (title, num) => {
|
||||
// 配置项
|
||||
const option = {
|
||||
title: {
|
||||
text: title,
|
||||
left: 'center',
|
||||
textStyle:
|
||||
{
|
||||
color: "#fff",
|
||||
fontSize: 14
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['45%', '60%'], // 内外半径,形成环形图
|
||||
center: ['50%', '60%'],
|
||||
data: [
|
||||
{// 背景部分
|
||||
value: 100 - num, name: '未完成值',
|
||||
itemStyle: { color: 'rgba(22, 238, 243,0.3)' },
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
{ // 值部分
|
||||
value: num, name: '完成值',
|
||||
itemStyle: { color: '#16EEF3' },
|
||||
label: {
|
||||
show: true, // 不显示标签
|
||||
position: 'center',
|
||||
fontSize: 16,
|
||||
formatter: '{d}%',
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
],
|
||||
labelLine: {
|
||||
show: false, // 不显示标签线
|
||||
},
|
||||
emphasis: {
|
||||
scale: false, // 禁用高亮放大效果
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
return option;
|
||||
}
|
||||
|
||||
return { ...toRefs(state), chart1Ref, chart2Ref };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
.topology-map {
|
||||
height: 100%;
|
||||
background-color: #082857;
|
||||
overflow: auto;
|
||||
|
||||
.top {
|
||||
width: 1795px;
|
||||
display: flex;
|
||||
padding-top: 52px;
|
||||
margin: 0 auto 30px;
|
||||
|
||||
.left {
|
||||
width: 347px;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 595px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 814px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.left,
|
||||
.center,
|
||||
.right {
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
width: 262px;
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
color: #fff;
|
||||
background: url("@/assets/image/topology/topology_bg.png") no-repeat center center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: block;
|
||||
min-width: 1800px;
|
||||
// height: 666px;
|
||||
// margin: 0 auto;
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.left,
|
||||
.center,
|
||||
.right {
|
||||
width: 477px;
|
||||
height: 160px;
|
||||
// border-top: 4px solid rgba(22, 238, 243, 0.6);
|
||||
// border-bottom: 4px solid rgba(22, 238, 243, 0.3);
|
||||
position: relative;
|
||||
overflow-y: hidden;
|
||||
|
||||
.b-con {
|
||||
display: flex;
|
||||
|
||||
.b-left {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
color: #16EEF3;
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-top: 35px;
|
||||
}
|
||||
|
||||
&.yingpan {
|
||||
background: url("@/assets/image/topology/ypkj.png") no-repeat center bottom;
|
||||
}
|
||||
|
||||
&.neicun {
|
||||
background: url("@/assets/image/topology/neicun.png") no-repeat center bottom;
|
||||
}
|
||||
|
||||
&.cpu {
|
||||
height: 135px;
|
||||
background: url("@/assets/image/topology/cpuicon.png") no-repeat center bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.b-right {
|
||||
flex: 1;
|
||||
margin-right: 40px;
|
||||
|
||||
.box {
|
||||
margin-top: 17px;
|
||||
|
||||
.text {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #fff;
|
||||
|
||||
.yy {
|
||||
color: #F5A623;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
display: block;
|
||||
height: 5px;
|
||||
background: rgba(22, 238, 243, 0.5);
|
||||
border-radius: 5px;
|
||||
margin: 2px 0;
|
||||
|
||||
.jd {
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 5px;
|
||||
background: #16EEF3;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.chart-box {
|
||||
display: flex;
|
||||
margin-top: 30px;
|
||||
|
||||
.chart {
|
||||
width: 50%;
|
||||
height: 110px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.triangle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: rgba(22, 238, 243, 0.6);
|
||||
}
|
||||
|
||||
.triangle::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-right: 22px solid rgba(22, 238, 243, 1);
|
||||
border-bottom: 22px solid transparent;
|
||||
}
|
||||
|
||||
.rectangle {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: rgba(22, 238, 243, 1);
|
||||
}
|
||||
|
||||
.rectangle:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 0 solid transparent;
|
||||
border-right: 50px solid #149eb5;
|
||||
border-bottom: 25px solid transparent;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|