授之以漁-運維平臺應用模塊一(應用樹篇)

寫在片頭:乾的是運維工作,愛好動手。純屬個人項目,身兼業務需求人員,產品經理,前端,後端,測試於一體,代碼層面會有邏輯問題,請各位看官見諒,下文只是記錄我一個10手碼農在前端踩過的坑和一些思路。

###應用樹: 爲了方便管理以業務爲單位的服務集羣,利用樹形結構建立起了一種服務組織關係,方便運維日常管理。先上一張效果圖:
授之以漁-運維平臺應用模塊一(應用樹篇)

#一、 Jstree
看過XX公司的運維平臺的應用樹後,從此不能自拔,勵志也要寫出一樣效果的東東。採用的jsTree,是基於javascript的一個跨瀏覽器樹控件樹行,功能強大,最重要的是免費,
左側的樹列表的生成因爲會用到mysql的group by,所以採用了redis存儲,需要的時候才更新服務樹,減少對數據庫的壓力,項目用到了根據選擇樹節點點擊事件功能。
既點擊項目名稱的紅×××標時,會加載整個項目涉及到的服務器,效果圖:
image.png
點擊項目下單個主機時,會加載這個服務器的應用情況,效果圖:
image.png

代碼如下:

("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(一個批量繪圖按鈕),效果圖如下:
image.png

#三、 Multiselect
接上文,這裏平臺是結合了openfalcon做的監控,點擊上文的監控指標項按鈕,會彈出一個multiselect層,用過openfalcon的都知道,監控指標多是他的特色之一,所以在選型的時候第一個就想到得需要一個帶filter功能的select控件,效果圖如下:
image.png
代碼如下:

            $('#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');
                            });
                        }
                    }
            });

撿重要的說:
用到了multiselectonDropdownShowonChange兩個回調函數,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可以理解成點擊事件,監控指標這塊還是怕傳多了,壓垮了openfalcongraph的,所以限制最多傳6個,超過的話會禁用所有選項。
#四、 繪圖
最後就是一些繪圖了,結合着openfalcon的API做的,下篇文章再議,效果圖:
image.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章