内容简介:写在片头:干的是运维工作,爱好动手。纯属个人项目,身兼业务需求人员,产品经理,前端,后端,测试于一体,代码层面会有逻辑问题,请各位看官见谅,下文只是记录我一个10手码农在前端踩过的坑和一些思路。代码如下:捡一些重要的说:
写在片头:干的是运维工作,爱好动手。纯属个人项目,身兼业务需求人员,产品经理,前端,后端,测试于一体,代码层面会有逻辑问题,请各位看官见谅,下文只是记录我一个10手 码农 在前端踩过的坑和一些思路。
###应用树: 为了方便管理以业务为单位的服务集群,利用树形结构建立起了一种服务组织关系,方便运维日常管理。先上一张效果图:
#一、 Jstree
看过XX公司的运维平台的应用树后,从此不能自拔,励志也要写出一样效果的东东。采用的 jsTree
,是基于javascript的一个跨浏览器树控件树行,功能强大,最重要的是免费,
左侧的树列表的生成因为会用到 mysql 的group by,所以采用了 redis 存储,需要的时候才更新服务树,减少对数据库的压力,项目用到了根据选择树节点点击事件功能。
既点击项目名称的红×××标时,会加载整个项目涉及到的服务器,效果图:
点击项目下单个主机时,会加载这个服务器的应用情况,效果图:
代码如下:
("changed.jstree", function (e, data) { var items = data.node.text; var icon = data.node.icon; if (icon == "fa fa-building-o font-blue"){ document.getElementById("group1").style.display="none"; document.getElementById("group2").style.display="block"; $.ajax({ type: "GET", url: "../cmdb_app_info_ajax/?ip="+items, dataType:'json', async: false, beforeSend:function(){ Metronic.blockUI({animate: true}); }, complete: function() { Metronic.unblockUI(); }, success: function(data){ var sOut= ''; sOut += '<tr>' sOut += '<td>' + data['设备 PHP 版本号:'] + '</td>'; sOut += '<td>' + data['设备PHP路径:'] + '</td>'; sOut += '<td>' + data['设备PHP端口号:'] + '</td>'; sOut += '<tr>' sOut += '<th><b>TOMCAT版本号</b></th>'; sOut += '<th><b>TOMCAT路径</b></th>'; sOut += '<th><b>TOMCAT端口号</b></th>'; sOut += '</tr>' sOut += '<td>' + data['设备TOMCAT版本号:'] + '</td>'; sOut += '<td>' + data['设备TOMCAT路径:'] + '</td>'; sOut += '<td>' + data['设备TOMCAT端口号:'] + '</td>'; sOut += '<tr>' sOut += '<th><b>NGINX版本号</b></th>'; sOut += '<th><b>NGINX路径</b></th>'; sOut += '<th><b>NGINX端口号</b></th>'; sOut += '</tr>' sOut += '<td>' + data['设备NGINX版本号:'] + '</td>'; sOut += '<td>' + data['设备NGINX路径:'] + '</td>'; sOut += '<td>' + data['设备NGINX端口号:'] + '</td>'; sOut += '<tr>' sOut += '<th><b>MYSQL版本号</b></th>'; sOut += '<th><b>MYSQL路径</b></th>'; sOut += '<th><b>MYSQL端口号</b></th>'; sOut += '<th><b>MYSQL数据库</b></th>'; sOut += '</tr>' sOut += '<td>' + data['设备MYSQL版本号:'] + '</td>'; sOut += '<td>' + data['设备MYSQL路径:'] + '</td>'; sOut += '<td>' + data['设备MYSQL端口号:'] + '</td>'; sOut += '<td>' + data['设备MYSQL数据库:'] + '</td>'; sOut += '<tr>' sOut += '<th><b>定时任务</b></th>'; sOut += '</tr>' sOut += '<td>' + data['设备定时任务:'] + '</td>'; sOut += '</tr>' $("#cmdb_app_info_get").html(sOut); }, error: function (data) { toastr.error('没有数据可以加载') } }); }else if (icon == "fa fa-folder icon-state-warning icon-lg"){ document.getElementById("group1").style.display="block"; document.getElementById("group2").style.display="none"; $.ajax({ type: "GET", url: "../cmdb_subtitle_info_ajax/?subtitle="+items, dataType:'json', async: false, beforeSend:function(){ Metronic.blockUI({animate: true}); }, complete: function() { Metronic.unblockUI(); }, success: function(data){ if ($('#product_tree').hasClass('dataTable')) { console.log('重新加载datatable,准备初始化................') $('#product_tree').dataTable().fnClearTable(false) //清空一下table $('#product_tree').dataTable().fnDestroy();//还原初始化datatable } $("#cmdb_subtitle_info_get").html(""); $.each(data,function() { var sOut= ''; sOut += '<tr>' sOut += '<td><input type="checkbox" class="checkboxes" value="1"/></td>' sOut += '<td id='+this['fields']['unit_title']+'>' + '<a href="../cmdb_assets_list/?place=&status=&year=&type=&model=&search='+ this['fields']['unit_ip'] +'">' + this['fields']['unit_title'] + '</a>' + '</td>'; sOut += '<td>' + this['fields']['unit_subtitle'] + '</td>'; sOut += '<td id='+this['fields']['unit_ip']+'>' + this['fields']['unit_ip'] + '</td>'; sOut += '<td>' + this['fields']['unit_use_type'] + '</td>'; sOut += '<td><a class="fa fa-eye" href="#responsives" data-toggle="modal"></a></td>'; sOut += '</tr>' $("#cmdb_subtitle_info_get").append(sOut); }); }, error: function (data) { toastr.error('没有数据可以加载') } }); } $(document).ready(function(){ eyeClick(); TableManaged.init() //初始化datatables }) }
捡一些重要的说:
var items = data.node.text; //获取图标名称 var icon = data.node.icon; //获取图标
我是通过判断图标的样式来获取用户点击的是哪里,没办法,谁叫咱是10手码农。同时有group1和gourp2两个tables,选择哪个图标就弹出哪个tables,隐藏另外的,在通过ajax后台获取数据,利用each循环获得的结果,构建出一个tr的内容,最后在添加到tables里,以此实现“山寨版”的数据加载。
####这里踩过的坑:
因为我要先加载完数据,然后才是初始化datatables表格。当点击到别的业务图标时,又要经历一次加载数据,然后初始化表格。结果datatables报错了.... cannot reinitialise datatable
,大概意思就是datatables不能重复初始化。
最后只能通过判断加载后的tables是否被加载后,如果加载过,先销毁,在初始化。
if ($('#product_tree').hasClass('dataTable')) { console.log('重新加载datatable,准备初始化................') $('#product_tree').dataTable().fnClearTable(false) //清空一下table $('#product_tree').dataTable().fnDestroy();//还原初始化datatable }
#二、 Datatable
右边就是数据展示采用datatables,可以将任何HTML表格添加高级的交互功能,这里用到了checkbox的单选和多选。
datatables代码如下:
var TableManaged = function () { var initTable2 = function () { var table = $('#product_tree'); table.dataTable({ "bDestroy": true, "language": { "aria": { "sortAscending": ": activate to sort column ascending", "sortDescending": ": activate to sort column descending" }, "emptyTable": "未有相关数据", "info": "当前显示 _START_ 到 _END_ 条,共 _TOTAL_ 条记录。", "infoEmpty": "当前显示0到0条,共0条记录", "infoFiltered": "(数据库中共为 _MAX_ 条记录)", "lengthMenu": "显示 _MENU_ 记录", "search": "模糊查询:", "zeroRecords": "对不起,查询不到任何相关数据", "oPaginate": { "sFirst": "首页", "sPrevious": " 上一页 ", "sNext": " 下一页 ", "sLast": " 尾页 " } }, "bStateSave": true, // save datatable state(pagination, sort, etc) in cookie. "lengthMenu": [ [5, 15, 20, -1], [5, 15, 20, "All"] // change per page values here ], // set the initial value "pageLength": 5, "columnDefs": [{ // set default column settings 'orderable': false, 'targets': [0] }, { "searchable": false, "targets": [0] }], "order": [ [1, "asc"] ] // set first column as a default sort by asc }); var tableWrapper = jQuery('#product_tree_wrapper'); var host_list = []; var release_build_job = ''; //全选 table.find('.group-checkable').change(function () { var set = jQuery(this).attr("data-set"); var checked = jQuery(this).is(":checked"); host_list.length = 0; jQuery(set).each(function () { if (checked) { $(this).attr("checked", true); var hosts = $(this).parent().parent().find('td').eq(1).attr("id"); host_list.push(hosts); document.getElementById("group3").style.display="block"; } else { $(this).attr("checked", false); host_list.length = 0; document.getElementById("group3").style.display="none"; } }); jQuery.uniform.update(set); }); //单选 table.on('change', 'tbody tr .checkboxes', function () { var hosts = $(this).parent().parent().find('td').eq(1).attr("id"); var checked = jQuery(this).is(":checked"); if (checked) { $(this).attr("checked", true); host_list.push(hosts); if (host_list.length > 1) { document.getElementById("group3").style.display="block"; }else { document.getElementById("group3").style.display="none"; } } else { $(this).attr("checked", false); host_list.pop(hosts); if (host_list.length > 1) { document.getElementById("group3").style.display="block"; }else { document.getElementById("group3").style.display="none"; } } }); tableWrapper.find('.dataTables_length select').select2(); // initialize select2 dropdown return { //main function to initiate the module init: function () { if (!jQuery().dataTable) { return; } initTable2(); } }; }();
捡一些重要的说:
if (host_list.length > 1) { document.getElementById("group3").style.display="block"; }else { document.getElementById("group3").style.display="none"; }
判断了checkbox选择的数量,大于1个的话,弹出gourp3(一个批量绘图按钮),效果图如下:
#三、 Multiselect
接上文,这里平台是结合了 openfalcon
做的监控,点击上文的监控指标项按钮,会弹出一个 multiselect
层,用过 openfalcon
的都知道,监控指标多是他的特色之一,所以在选型的时候第一个就想到得需要一个带 filter
功能的 select
控件,效果图如下:
代码如下:
$('#get_hostlist_counter_select').multiselect({ buttonWidth: '500px',//按钮宽度 nonSelectedText: '---- 请选择监控指标 ----', nSelectedText: '个被选中', enableCaseInsensitiveFiltering: true,//不区分大小写 filterPlaceholder: '模糊查询', enableFiltering: true, onDropdownShow: function(event) { get_hostlist_counter() }, onChange: function (option, checked, select) { var selectedOptions = $('#get_hostlist_counter_select option:selected'); if (selectedOptions.length >= 6) { // 禁用选项 toastr.error('监控指标最多同时选取6个') var nonSelectedOptions = $('#get_hostlist_counter_select option').filter(function() { return !$(this).is(':selected'); }); nonSelectedOptions.each(function() { var input = $('input[value="' + $(this).val() + '"]'); input.prop('disabled', true); input.parent('li').addClass('disabled'); }); } else { // 启动选项 $('#get_hostlist_counter_select option').each(function() { var input = $('input[value="' + $(this).val() + '"]'); input.prop('disabled', false); input.parent('li').addClass('disabled'); }); } } });
捡重要的说:
用到了 multiselect
的 onDropdownShow
和 onChange
两个回调函数, onDropdownShow
可以理解成就是点击菜单下拉事件,触发了 get_hostlist_counter()
通过ajax取数据填充 options
,代码如下:
function get_hostlist_counter(){ var options_list = [] var obj2 = new Object(); var jsonData ={ 'unit_title': host_list.join(','), }; $("#get_hostlist_counter_select").empty(); $.ajax({ async: false, type: "POST", url : "../openfalcon_get_endpoint_counter_ajax/", data: jsonData, cache: false, dataType: "json", beforeSend:function(){ Metronic.blockUI({animate: true}); }, complete: function() { Metronic.unblockUI(); }, success: function(obj) { if (obj['counter'] == ''){ toastr.error('获取监控指标为空或者异常') }else{ for (var id in obj['counter']){ obj2 = { label : obj['counter'][id], value : obj['counter'][id], }; options_list.push(obj2) } $('#get_hostlist_counter_select').multiselect('dataprovider', options_list); } } }); }
onChange
可以理解成点击事件,监控指标这块还是怕传多了,压垮了 openfalcon
的 graph
的,所以限制最多传6个,超过的话会禁用所有选项。
#四、 绘图
最后就是一些绘图了,结合着 openfalcon
的API做的,下篇文章再议,效果图:
以上所述就是小编给大家介绍的《授之以渔-运维平台应用模块一(应用树篇)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 一看就懂,Python 日志模块详解及应用
- 真棒:使用Java 11实现应用的模块化
- 如何将 Elixir 模块风格应用在 JS 中
- [译] 依赖注入在多模块工程中的应用
- WebAssembly应用到前端工程(上)—— webassembly模块的编写
- 使用Java 9的模块化来构建零依赖的原生应用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
鸟哥的Linux私房菜 基础学习篇(第二版)
鸟哥 / 人民邮电出版社 / 2007-9 / 65.00元
《鸟哥的Linux私房菜基础学习篇(第二版)》全面而详细地介绍了Linux操作系统。全书分为5个部分:第一部分着重说明Linux的起源及功能,如何规划和安装Linux主机;第二部分介绍Linux的文件系统、文件、目录与磁盘的管理;第三部分介绍文字模式接口shell和管理系统的好帮手shell脚本,另外还介绍了文字编辑器vi和vim的使用方法;第四部分介绍了对于系统安全非常重要的Linux账号的管理......一起来看看 《鸟哥的Linux私房菜 基础学习篇(第二版)》 这本书的介绍吧!
JSON 在线解析
在线 JSON 格式化工具
Base64 编码/解码
Base64 编码/解码