后端数据的获取
public void dashboard() {
Record user = getSessionAttr("user");
//获得设备数据
List<Map<String, Object>> roomAndDeviceList = IndexService.service.getRoomAndDevice();
setAttr("roomAndDeviceListJson", JsonKit.toJson(roomAndDeviceList));
render("dashboard.html");
}
获取列表数据roomAndDeviceList内的每个map的keys(机房room和该机房下的设备devices)
public List<Map<String, Object>> getRoomAndDevice(){
List<Map<String, Object>> list = new ArrayList<>();
List<Record> rooms = Db.find(Db.getSql("room.queryPageList"));
for(Record room : rooms){
Map<String, Object> map = new HashMap<>();
String roomId = room.getStr("room_id");
List<Record> devices = Db.find(Db.getSqlPara("device.getDeviceByRoomId", roomId));
map.put("room", room);
map.put("devices", devices);
list.add(map);
}
return list;
}
前段页面的数据渲染
目前还双击根节点后隐藏/显示 所有下级的连线和节点 还没完全弄好,待改善
#define room_topology(id)
<script type="text/javascript" src="assets/lib/jtopo/jtopo-0.4.8-min.js" ></script>
<div style="height:100%;width:100%;">
<canvas id="topology_#(id)" :width="canvasWidth" :height="canvasHeight" style="border: 1px solid rgb(68, 68, 68);background: rgb(32, 95, 181); cursor: default;"></canvas>
<ul id="contextmenu" style="display:none;">
<li><a>顺时针旋转</a></li>
<li><a>逆时针旋转</a></li>
<li><a>更改颜色</a></li>
<li><a>放大</a></li>
<li><a>缩小</a></li>
<li><a>删除该节点</a></li>
</ul>
</div>
<script>
$(function(){
var dtVue = new Vue({
el: "#topology_#(id)",
data: {
canvasWidth: 0,
canvasHeight: 0
},
computed: {
},
mounted: function (){
var $parent = $(this.$el.parentNode);
this.canvasWidth = $parent.width();
this.canvasHeight = $parent.height();
$parent.css("overflow", "hidden");
},
methods: {
renderTopology: function () {
var vThis = this;
var canvas = document.getElementById('topology_#(id)');
var stage = new JTopo.Stage(canvas);
//显示工具栏
var scene = new JTopo.Scene(stage);
var root = new JTopo.Node("政务数据安全管制系统管控中心");
root.font = '14px 微软雅黑'; // 字体
var x = this.canvasWidth/2-50;
var y = this.canvasHeight/2-50;;
root.setLocation(x, y);
root.setSize(100, 100);
root.setImage("assets/lib/jtopo/icon/vr-selfdefined.png");
root.layout = {type: 'circle', radius: 250};
root.addEventListener('mouseup', function(event){
if(event.button == 2){// 右键
// 当前位置弹出菜单(div)
$("#contextmenu").css({
top: event.pageY,
left: event.pageX
}).show();
}
});
//root节点双击后将所有连线和子节点设置显示/隐藏 TODO 二级节点device还未设置
root.dbclick(function(event){
if (root.layout.radius == 0) {
root.layout.radius = 250;
root.outLinks.forEach(function(item){
item.visible = true;
item.nodeZ.visible = true;
})
} else {
root.layout.radius = 0;
root.outLinks.forEach(function(item){
item.visible = false;
item.nodeZ.visible = false;
})
}
JTopo.layout.layoutNode(scene, root, true);
})
scene.add(root);
//一级节点 rooms
var roomAndDeviceList = #(roomAndDeviceListJson);
for(var i=0; i<roomAndDeviceList.length; i++){
var room = roomAndDeviceList[i].room;
var node = new JTopo.Node(room.room_name);
node.setImage("assets/lib/jtopo/icon/mypc.png");
node.layout = {type: 'circle', radius: 100};
node.setSize(50, 50);
node.setLocation(scene.width * Math.random(), scene.height * Math.random());
scene.add(node);
var link = new JTopo.Link(root, node);
scene.add(link);
//二级节点 devices
var devices = roomAndDeviceList[i].devices;
for(var j=0; j<devices.length; j++){
var device = devices[j];
var deviceNode = new JTopo.Node(device.device_name);
deviceNode.setImage("assets/lib/jtopo/icon/py_VM.png");
deviceNode.layout = {type: 'circle', radius: 50};
deviceNode.setSize(30, 30);
deviceNode.setLocation(scene.width * Math.random(), scene.height * Math.random());
scene.add(deviceNode);
scene.add(new JTopo.Link(node, deviceNode));
(function(device){
deviceNode.mouseover(function(deviceTarget){
vThis.showDeviceTip(deviceTarget, device)
});
deviceNode.mouseout(function(){
$("#"+device.device_id).remove();
layer.closeAll();
})
})(device)
}
(function(room){
node.mouseover(function(event){
vThis.showRoomTip(event, room)
});
node.mouseout(function(){
$("#"+room.room_id).remove();
layer.closeAll();
})
})(room)
}
// 重新渲染拓扑图布局
JTopo.layout.layoutNode(scene, root, true);
scene.addEventListener('mouseup', function(e){
if(e.target && e.target.layout){
JTopo.layout.layoutNode(scene, e.target, true);
}
});
},
showRoomTip: function (event, room){
var target = $("<div style='width:50px;height:50px;position:fixed;'></div>").attr("id", room.room_id)
.css({
top: event.target.y + 160,
left: event.target.x + 260
});
$("body").append(target);
var content = `<div style="min-width:200px;">
服务器名: ${room.room_name} <br>
省: ${room.province_name} <br>
市: ${room.city_name} <br>
区: ${room.area_name} <br>
具体地址: ${room.room_address} <br>
负责人姓名: ${room.room_contacts} <br>
负责人电话: ${room.room_contacts_phone} <br>
</div>`;
layer.tips(content, "#"+room.room_id, {
tips: [1, '#3595CC'],
time: 0
});
},
showDeviceTip: function (deviceTarget, device){
var deviceTarget = $("<div style='width:50px;height:50px;position:fixed;'></div>").attr("id", device.device_id)
.css({
top: deviceTarget.target.y + 160,
left: deviceTarget.target.x + 260
});
$("body").append(deviceTarget);
var content = `<div style="min-width:200px;">
设备名: ${device.device_name} <br>
设备类型: ${device.device_type_tag} <br>
设备IP: ${device.ip} <br>
设备MAC: ${device.mac} <br>
维护人员姓名: ${device.maintainer_name} <br>
维护人员电话: ${device.maintainer_phone} <br>
所属单位: ${device.maintainer_org_name} <br>
</div>`;
layer.tips(content, "#"+device.device_id, {
tips: [1, '#3595CC'],
time: 0
});
}
},
watch: {
canvasheight: function(){
this.renderTopology();
},
canvasWidth: function(){
this.renderTopology();
}
}
})
})
</script>
#end
页面效果
鼠标悬停到具体设备上时会出现一个小窗体展示详细信息
jTopo参考网址:http://www.jtopo.cn/demo/layout-circle.html
具体相关的jTopo用法和文档可到上面官网查看