Index: /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/templates/monitoring/gslb/monitor/monitor.html
===================================================================
--- /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/templates/monitoring/gslb/monitor/monitor.html	(revision 39203)
+++ /branches/rel_apv_10_7/usr/click/webui/htdocs/new/src/apv/templates/monitoring/gslb/monitor/monitor.html	(working copy)
@@ -92,7 +92,9 @@
                                         <el-table ref="serviceListTable" :data="host_list.tableData" v-loading="host_list.tableLoading" :empty-text="gettext('No Data')" stripe style="width: 100%">
                                             <el-table-column min-width="120" show-overflow-tooltip="true" class-name="my-table">
                                                 <template slot-scope="scope">
-                                                    {[scope.row.name]}
+                                                    <span class="click-title" @click="openDetails(scope.row, scope.row.name, 1)">
+                                                        {[scope.row.name]}
+                                                    </span>
                                                 </template>
                                             </el-table-column>
                                             <el-table-column min-width="50" show-overflow-tooltip="true">
@@ -107,7 +109,7 @@
                                                     <span>{[scope.row.hits]}</span>
                                                 </template>
                                             </el-table-column>
-                                            <el-table-column min-width="90"> 
+                                            <el-table-column min-width="90">
                                                 <template slot-scope="scope">
                                                     <el-row :gutter="20">
                                                         {[gettext('Default Pool')]}
@@ -161,7 +163,9 @@
                                         <el-table :data="service_list.tableData" v-loading="service_list.tableLoading" :empty-text="gettext('No Data')" stripe style="width: 100%">
                                             <el-table-column :label="gettext('Name')">
                                                 <template slot-scope="scope">
-                                                    {[scope.row.service_name]}
+                                                    <span class="click-title" @click="openDetails(scope.row, scope.row.service_name, 2)">
+                                                        {[scope.row.service_name]}
+                                                    </span>
                                                 </template>
                                             </el-table-column>
                                             <el-table-column prop="ip" :label="gettext('IP')">
@@ -196,6 +200,151 @@
                 </el-col>
             </el-row>
         </el-main>
+        <el-drawer title="Detail" :visible.sync="drawer" :with-header="false" size="70%" custom-class="custom-drawer" :modal="false" >
+            <div class="row" style="width: 100%;">
+                <div class="" style="padding: 0; float: left; width: 100%;">
+                    <el-container>
+                        <el-header style="text-align: center; padding-top: 30px;">
+                            <el-radio-group v-model="detail.radio" @change="reloadTimer">
+                                <el-radio-button label="Topology">{[gettext('Topology')]}</el-radio-button>
+                                <el-radio-button label="Charts">{[gettext('Charts')]}</el-radio-button>
+                            </el-radio-group>
+                        </el-header>
+                        <el-main>
+                            <el-container v-if="detail.radio == 'Topology'">
+                                <el-main style="overflow-x: hidden;">
+                                    <div class="row">
+                                        <div class="col-md-12" style="padding: 0">
+                                            <div class="topology">
+                                                <div id="over-container" style="overflow-x: scroll;">
+                                                    <div id="canvas_container">
+                                                        <canvas id="canvas"></canvas>
+                                                    </div>
+                                                    <div v-if="detail.basic" style="position: relative;">
+                                                        <div class="topology-container" id="topology-container" style="position: absolute; left: 0; right: 15px;">
+                                                            <div class="vs-instance">
+                                                                <div class="vs-container" @click="vsDetail(topology.name)" style="float: left;"><i class="fa icon-vs"></i><i class="fa icon-vsnew"></i></div>
+                                                                <div class="vs-name" @click="vsDetail(topology.name)"><span>{[ topology.name ]}</span><i class="fa fa-cog"></i></div>
+                                                                <div class="vs-info">
+                                                                    <ul v-if="detail.basic.ttl || detail.basic.forward_only || detail.statictics.hit">
+                                                                        <li v-if="detail.basic.ttl">
+                                                                            <span>{[gettext('ttl')]}:</span>
+                                                                            <span>{[ detail.basic.ttl ]}</span>
+                                                                        </li>
+                                                                        <li v-if="detail.basic.forward_only !== undefined">
+                                                                            <span>Forward Only</span>
+                                                                            <span v-if="detail.basic.forward_only">
+                                                                                <img src="{{ MEDIA }}img/icons/Enable.png">
+                                                                            </span>
+                                                                            <span v-if="!detail.basic.forward_only">
+                                                                                <img src="{{ MEDIA }}img/icons/unenable.png">
+                                                                            </span>
+                                                                        </li>
+                                                                        <li v-if="detail.statictics.hit">
+                                                                            <span>Hit:</span>
+                                                                            <span>{[ detail.statictics.hit ]}</span>
+                                                                        </li>
+                                                                    </ul>
+                                                                    <ul v-if="detail.statictics.default_pool || detail.statictics.default_policy_hit">
+                                                                        <li v-if="detail.statictics.default_pool">
+                                                                            <span>Default Pool:</span>
+                                                                            <span>{[ detail.statictics.default_pool ]}</span>
+                                                                        </li>
+                                                                        <li v-if="detail.statictics.default_policy_hit">
+                                                                            <span>Default Policy Hit:</span>
+                                                                            <span>{[ detail.statictics.default_policy_hit ]}</span>
+                                                                        </li>
+                                                                    </ul>
+                                                                    <ul v-if="detail.statictics.resort_pool || detail.statictics.resort_policy_hit">
+                                                                        <li v-if="detail.statictics.resort_pool">
+                                                                            <span>Resort Pool:</span>
+                                                                            <span>{[ detail.statictics.resort_pool ]}</span>
+                                                                        </li>
+                                                                        <li v-if="detail.statictics.resort_policy_hit">
+                                                                            <span>Resort Policy Hit:</span>
+                                                                            <span>{[ detail.statictics.resort_policy_hit ]}</span>
+                                                                        </li>
+                                                                    </ul>
+                                                                    <ul v-if="detail.statictics.region_policy_count || detail.statictics.region_hit">
+                                                                        <li v-if="detail.statictics.region_policy_count">
+                                                                            <span>Region Policy Count:</span>
+                                                                            <span>{[ detail.statictics.region_policy_count ]}</span>
+                                                                        </li>
+                                                                        <li v-if="detail.statictics.region_hit">
+                                                                            <span>Region Policy Hit:</span>
+                                                                            <span>{[ detail.statictics.region_hit ]}</span>
+                                                                        </li>
+                                                                    </ul>
+                                                                </div>
+                                                            </div>
+                                                            <div class="vs-policy">
+                                                                <div
+                                                                    v-if="detail.topology && detail.topology.policies.length > 0"
+                                                                    v-for="policy in detail.topology.policies"
+                                                                    style="float: left; margin-right: 20px;"
+                                                                    class="policy"
+                                                                >
+                                                                    <div style="margin-bottom: 55px">
+                                                                        <div class="policy-container">
+                                                                            <i class="fa icon-policy"></i>
+                                                                            <i class="fa icon-policynew"></i>
+                                                                        </div>
+                                                                        <div class="policy-name">
+                                                                            <span>{[ policy.name ]}</span>
+                                                                        </div>
+                                                                    </div>
+                                                                    <div class="vs-dst">
+                                                                        <div>
+                                                                            <div>
+                                                                                <div class="dst-container" rel="popover" data-html="true" data-trigger="hover">
+                                                                                    <i class="fa icon-groupnew" style="padding-left: 15px;"></i>
+                                                                                </div>
+                                                                                <div class="dst-title"><span>{[ gettext(policy.pool.name) ]}</span></div>
+                                                                            </div>
+                                                                            <div class="groupmember">
+                                                                                <div style="float: left; max-width: 260px; display: flex; margin-right: 20px;">
+                                                                                    <div class="service_list" v-for="service in policy.pool.services" style="float: left;">
+                                                                                        <div class="member-container" rel="popover" data-html="true">
+                                                                                            <i class="fa icon-rs"></i>
+                                                                                            <i class="fa icon-rsnew"></i>
+                                                                                        </div>
+                                                                                        <div class="member-title" style="text-align: center;"><span>{[ service.name ]}</span></div>
+                                                                                    </div>
+                                                                                </div>
+                                                                            </div>
+                                                                        </div>
+                                                                    </div>
+                                                                </div>
+                                                            </div>
+                                                        </div>
+                                                    </div>
+                                                </div>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </el-main>
+                            </el-container>
+                            <el-container v-if="detail.radio == 'Charts'">
+                                <el-main style="overflow-x: auto; height: 90vh;">
+                                    <el-row :gutter="20">
+                                        <el-col>
+                                            <el-card>
+                                                <div slot="header">
+                                                    <span>{[widgets['hits'].title]}</span>
+                                                </div>
+                                                <div ref="chartContainer" style="width: 100%; height: 300px;">
+                                                    <custom-chart :propoption="widgets['hits'].option" ref="chartComponent"></custom-chart>
+                                                </div>
+                                            </el-card>
+                                        </el-col>
+                                    </el-row>
+                                </el-main>
+                            </el-container>
+                        </el-main>
+                    </el-container>
+                </div>
+            </div>
+        </el-drawer>
     </el-container>
 </div>
 
@@ -205,6 +354,7 @@
         $HIVE.set_help_link("{{ lang }}/app.html#id585379");
         var system_timezone = 0;
         var theme = localStorage.getItem("theme");
+        var left_width = $(window).width()*0.3 - 30;
         var loadingConfig = {
             text: 'loading',
             color: '#c23531',
@@ -224,18 +374,426 @@
         } else {
             theme = 'white'
         }
+        var number = 0;
+        function addHtml(data) {
+            _.each(data, function(policy) {
+                if (policy.dst.out_policies && policy.dst.out_policies != []) {
+                setTimeout(function () {
+                    number += 1;
+                    if (number >= 2) {
+                        var number_old = number -1;
+                        var old = ".vlink" + number_old;
+                        var new_name = "outPolicy vlink" + number;
+                        var text = "<div style='float:left' class='" + new_name + "'>";
+                        _.each(policy.dst.out_policies, function(policy, index){
+                            if (policy.dst.type == 'vlink') {
+                                var class1 = "out" + number;
+                                if (policy.dst.out_policies !=[]){
+                                    var class2 = "addhtml vlink-dst" + number;
+                                } else {
+                                    var class2 = "vlink-dst" + number;
+                                }
+                                var text1 = "<div style='float: left; margin-right: 20px;'>" +
+                                                "<div class='" + class1 + "'>" +
+                                                    "<div rel='popover' data-html='true' data-content='" + policy.content + "' data-trigger='hover' data-original-title='" + policy.type + "' class='outPolicy-container'><i class='fa icon-policy'></i><i class='fa icon-policynew'></i></div>" +
+                                                    "<div class='dst-title'><span>" + policy.type + " policy</span></div>" +
+                                                "</div>" +
+                                                "<div class='" + class2 + "' style='float: left;'>" +
+                                                    "<div>" +
+                                                        "<div style='float: left; margin-right: 65px;'>" +
+                                                            "<div rel='popover' data-html='true' data-content='" + policy.dst.content + "' data-trigger='hover' data-original-title='" + policy.dst.type + "' class='dst-container vlink'><i class='fa icon-vlink'></i><i class='fa icon-vlinknew'></i></div> " +
+                                                            "<div class='dst-title'><span>" + policy.dst.name + "</span></div>"+
+                                                        "</div>"+
+                                                    "</div>" +
+                                                "</div>" +
+                                            "</div>";
+                                text = text + text1;
+                            } else if (policy.dst.type == 'rs') {
+                                var class1 = "out" + number;
+                                var class2 = "vlink-dst" + number;
+                                policy.dst.content = policy.dst.content.replace("<img src='/media/img/icons/Enable.png'>", "<img src=\"/media/img/icons/Enable.png\">");
+                                policy.dst.content = policy.dst.content.replace("<img src='/media/img/icons/unenable.png'>", "<img src=\"/media/img/icons/unenable.png\">");
+                                if (policy.dst.enable == 1) {
+                                    var msg = "<img  src={{ MEDIA }}img/icons/green.png style='margin-left: -80px; margin-top: -20px; height: 85px; width: 85px;'>"
+                                    var alert = "";
+                                } else {
+                                    var msg = "<img  src={{ MEDIA }}img/icons/alert.png style='margin-left: -80px; margin-top: -20px; height: 85px; width: 85px;'>"
+                                    var alert = "red";
+                                }
+                                var text1 = "<div style='float: left; margin-right: 20px;'>" +
+                                                "<div class='" + class1 + "'>" +
+                                                    "<div rel='popover' data-html='true' data-content='" + policy.content + "data-trigger='hover' data-original-title='" + policy.type + "' class='outPolicy-container'><i class='fa icon-policy'></i><i class='fa icon-policynew'></i></div>" +
+                                                    "<div class='dst-title'><span>" + policy.type + " policy</span></div>" +
+                                                "</div>" +
+                                                "<div class='" + class2 + "' style='float: left;'>" +
+                                                    "<div>" +
+                                                        "<div style='float: left; margin-right: 65px;'>" +
+                                                            "<div rel='popover' data-html='true' data-content='" + policy.dst.content + "' data-trigger='hover' data-original-title='" + policy.dst.type + "' class='dst-container rs " + alert + "'><i class='fa icon-rs'></i><i class='fa icon-rsnew'></i></div> " +
+                                                            // msg +
+                                                            "<div class='dst-title'><span>" + policy.dst.name + "</span></div>"+
+                                                        "</div>"+
+                                                    "</div>" +
+                                                "</div>" +
+                                            "</div>";
+                                text = text + text1
+                            } else if (policy.dst.type == "group") {
+                                var class1 = "out" + number;
+                                var class2 = "vlink-dst" + number;
+                                if (policy.dst.members.length > 0) {
+                                    policy.dst.content = policy.dst.content.replace("<img src='/media/img/icons/Enable.png'>", "<img src=\"/media/img/icons/Enable.png\">");
+                                    policy.dst.content = policy.dst.content.replace("<img src='/media/img/icons/unenable.png'>", "<img src=\"/media/img/icons/unenable.png\">");
+                                    var text1 = "<div style='float: left; margin-right: 20px;'>" +
+                                                "<div class='" + class1 + "'>" +
+                                                    "<div rel='popover' data-html='true' data-content='" + policy.content + "' data-trigger='hover' data-original-title='" + policy.type + "' class='outPolicy-container'><i class='fa icon-policy'></i><i class='fa icon-policynew'></i></div>" +
+                                                    "<div class='dst-title'><span>" + policy.type + " policy</span></div>" +
+                                                "</div>" +
+                                                "<div class='" + class2 + "' style='float: left;'>" +
+                                                    "<div>" +
+                                                        "<div class='groupcontainer1' style='float: left; margin-right: 65px;'>" +
+                                                            "<div rel='popover' data-html='true' data-content='" + policy.dst.content + "' data-trigger='hover' data-original-title='" + policy.dst.type + "' class='dst-container group'><i class='fa icon-group'></i><i class='fa icon-groupnew'></i></div> " +
+                                                            "<div class='dst-title'><span>" + policy.dst.name + "</span></div>"+
+                                                        "</div>"+
+                                                        "<i title='点击展开group' class='fa fa-angle-double-right' @click='expand(" + policy.dst.name + ")' style='position: absolute; margin-top:25px; margin-left: -70px; font-size: 24px; color: rgb(27, 54, 86); cursor: pointer;'></i> " +
+                                                        "<div class='groupmember1 hide'>" +
+                                                            "<div style='float: left; border: 2px dashed rgb(27, 54, 86); max-width: 250px; overflow-x: scroll; display: flex; margin-right: 65px;'>"
+                                    text = text + text1;
+                                    _.each(policy.dst.members, function(meb) {
+                                        if (meb.enable == 1) {
+                                            var msg = "<img  src={{ MEDIA }}img/icons/green.png style='margin-left: -78px; margin-top: -20px; height: 85px; width: 85px;'>"
+                                            var alert = "";
+                                        } else {
+                                            var msg = "<img  src={{ MEDIA }}img/icons/alert.png style='margin-left: -78px; margin-top: -20px; height: 85px; width: 85px;'>"
+                                            var alert = "red"
+                                        }
+                                        text2 = "<div class='rs' style='float: left;'>" +
+                                                    " <div rel='popover' data-html='true' data-content='" + policy.dst.content + "' data-trigger='hover' data-original-title='" + policy.dst.type + "'class='member-container " + alert + "'><i class='fa icon-rs'></i><i class='fa icon-rsnew'></i></div> " +
+                                                    // msg +
+                                                    "<div class='member-title' style='text-align: center;'><span>" + meb.name + "</span></div>" +
+                                                "</div>";
+                                        text = text + text2;
+                                    });
+                                    var text3 = "<i title='点击收缩group' class='fa fa-angle-double-left' style='position: absolute; margin-top: 30px; margin-left: -30px; font-size: 24px; color: rgb(27, 54, 86); cursor: pointer;'></i>" +
+                                                "</div> " +
+                                                    "<div style='text-align: center; line-height: 30px;'><span>" + policy.dst.name + ":" + policy.dst.members.length + "real service</span></div>" +
+                                                    "</div>\
+                                                </div>\
+                                            </div>\
+                                        </div>"
+                                    text = text + text3;
+
+                                } else if (policy.dst.members.length == 0) {
+                                    policy.dst.content = policy.dst.content.replace("<img src='/media/img/icons/Enable.png'>", "<img src=\"/media/img/icons/Enable.png\">");
+                                    policy.dst.content = policy.dst.content.replace("<img src='/media/img/icons/unenable.png'>", "<img src=\"/media/img/icons/unenable.png\">");
+                                    var text1 = "<div style='float: left;'>" +
+                                                    "<div class='" + class1 + "'>" +
+                                                        "<div rel='popover' data-html='true' data-content='" + policy.content + "' data-trigger='hover' data-original-title='" + policy.type + "' class='outPolicy-container'><i class='fa icon-policy'></i><i class='fa icon-policynew'></i></div>" +
+                                                        "<div class='dst-title'><span>" + policy.name + "</span></div>" +
+                                                    "</div>" +
+                                                    "<div class='" + class2 + "' style='float: left;'>" +
+                                                        "<div>" +
+                                                            "<div class='groupcontainer1' style='float: left; margin-right: 65px;'>" +
+                                                            "<div rel='popover' data-html='true' data-content='" + policy.dst.content + "' data-trigger='hover' data-original-title='" + policy.dst.type + "'class='dst-container group'><i class='fa icon-group'></i></div> " +
+                                                            // msg +
+                                                            "<div class='dst-title'><span>" + policy.dst.name + "</span></div>"+
+                                                        "</div>"+
+                                                        "<i title='点击展开group' class='fa fa-angle-double-right' style='position: absolute; margin-top: 25px; margin-left: -70px; font-size: 24px; color: rgb(27, 54, 86); cursor: pointer;'></i>" +
+                                                        "<div class='groupmember1 hide'>" +
+                                                                "<div style='line-height: 60px; border: 2px dashed rgb(27, 54, 86); text-align: center; font-size: 15px;'><i title='点击收缩group' class='fa fa-angle-double-left' style='position: absolute; margin-top: 16px; margin-left: -60px; font-size: 24px; color: rgb(27, 54, 86); cursor: pointer;'></i>N/A</div> " +
+                                                                "<div style='text-align: center; line-height: 30px;'><span>" + policy.dst.name + ": 0 real service</span></div>" +
+                                                                "</div>"+
+                                                            "</div>"+
+                                                        "</div>" +
+                                                    "</div>";
+                                    text = text + text1;
+                                }
+                            }
+                        })
+                        var text_last = "</div>"
+                        text = text + text_last;
+                        $(old).find(".addhtml").append(text);
+                    }
+                    addHtml(policy.dst.out_policies);
+                }, 1)
+                }
+            })
+        }
+        function expand_group(data, name) {
+            _.each(data, function (policy) {
+                if (policy.dst.name == name) {
+                    policy.dst.expand = true;
+                } else {
+                    policy.dst.expand = false;
+                }
+                if (policy.dst.out_policies) {
+                    expand_group(policy.dst.out_policies, name);
+                }
+            })
+        }
+        function collapse_group(data) {
+            _.each(data, function (policy) {
+                policy.dst.expand = false;
+                if (policy.dst.out_policies) {
+                    collapse_group(policy.dst.out_policies);
+                }
+            })
+        }
+
+        function getVlink(vlink) {
+            var scrollTop = document.documentElement.scrollTop;
+            var out_position = [];
+            var middle_position = [];
+            var dst_position = [];
+            var vlink_left = vlink.offset().left - left_width;
+            var vlink_top = vlink.offset().top - 140 - scrollTop;
+            vlink.find(".out1").find(".outPolicy-container").each(function () {
+                var data = $(this);
+                out_position.push([data.offset().left - left_width, data.offset().top - 90 - scrollTop]);
+                middle_position.push([data.offset().left - left_width, vlink_top + 25]);
+            });
+            vlink.find(".vlink-dst1").each(function () {
+                var data = $(this);
+                dst_position.push([data.offset().left - left_width, data.offset().top - 90 - scrollTop]);
+            });
+            var c = document.getElementById("canvas");
+            var ctx = c.getContext("2d");
+            for (var i = 0; i < out_position.length; i++) {
+                if (i == 0) {
+                    ctx.moveTo(out_position[i][0], vlink_top);
+                    ctx.lineTo(out_position[i][0], out_position[i][1]);
+                    ctx.stroke();
+                } else {
+                    ctx.moveTo(middle_position[i][0], middle_position[i][1]);
+                    ctx.lineTo(middle_position[i - 1][0], middle_position[i - 1][1]);
+                    ctx.stroke();
+                    ctx.moveTo(middle_position[i][0], middle_position[i][1]);
+                    ctx.lineTo(out_position[i][0], out_position[i][1]);
+                    ctx.stroke();
+                }
+                ctx.moveTo(out_position[i][0], out_position[i][1] + 95);
+                ctx.lineTo(dst_position[i][0], dst_position[i][1]);
+                ctx.stroke();
+            }
+        }
+
+        function getServiceConnections() {
+            const connections = [];
+
+            $(".vs-dst").each(function () {
+                const vsDst = $(this);
+                const vsDstLeft = vsDst.offset().left;
+                const vsDstTop = vsDst.offset().top;
+
+                vsDst.find(".service_list").each(function (index) {
+                    const serviceList = $(this);
+                    const serviceLeft = serviceList.offset().left;
+                    const serviceTop = serviceList.offset().top;
+
+                    connections.push({
+                        vsDst: [vsDstLeft, vsDstTop],
+                        serviceList: [serviceLeft, serviceTop],
+                        isFirst: index === 0
+                    });
+                });
+            });
+
+            return connections;
+        }
+
+        function getPosition() {
+            var data = document.getElementById("over-container");
+            if (!data) {
+                return [[],[],[]]
+            }
+            var width_old = document.getElementById("over-container").offsetWidth;
+            var width_new = (400 + 30 * number);
+            var height_count = [];
+            $(".policy").each(function () {
+                width_new += ($(this).width() + 20)
+                height_count.push($(this).height())
+            });
+            if (height_count.length > 0) {
+                var height = Math.max.apply(Math, height_count) + 210;
+            } else {
+                var height = 600;
+            }
+
+            if ( width_new >= width_old ) {
+                var width = width_new;
+
+            } else {
+                var width = width_old;
+            };
+            var c = document.getElementById("canvas");
+            c.width = width;
+            c.height = height;
+            $('#topology-container').css('width', width);
+            $('#topology-container').css('height', height);
+            $('#topology-container').css('top', - height);
+            $('#canvas_container').css('width', width);
+            $('#canvas_container').css('height', height);
+
+            var scrollTop = document.documentElement.scrollTop;
+            var vs_left = $('.vs-container').offset().left - left_width;
+            var vs_top = $('.vs-container').offset().top - 25 - scrollTop;
+            var policy_position = [];
+            var middle_position = [
+                [vs_left, vs_top + 35]
+            ];
+            var dst_position = [];
+            $(".policy").each(function () {
+                var index = $(this).index();
+                var data = $(this).find(".policy-container");
+
+                if (index == 0) {
+                    var policy_left = data.offset().left - left_width;
+                    var policy_top = data.offset().top - 105 - scrollTop;
+                    policy_position.push([policy_left, policy_top]);
+                } else {
+                    var policy_left = data.offset().left - left_width;
+                    var policy_top = data.offset().top - 105 - scrollTop;
+                    policy_position.push([policy_left, policy_top]);
+                    var middle_left = policy_left;
+                    var middle_top = vs_top + 35;
+                    middle_position.push([middle_left, middle_top])
+                }
+            })
+            $(".vs-dst").each(function () {
+                var data = $(this);
+                var dst_left = data.offset().left - left_width;
+                var dst_top = data.offset().top - 105 - scrollTop;
+                dst_position.push([dst_left, dst_top]);
+            });
+
+            return [policy_position, middle_position, dst_position];
+        }
+
+        function click() {
+            $(".fa-angle-double-left").each(function () {
+                var data = $(this);
+                data.on('click', function() {
+                    $("#over-container").scrollLeft(0);
+                    $("#over-container").scrollTop(0);
+                    $(".groupcontainer1").removeClass("hide");
+                    $(".groupcontainer").removeClass("hide");
+                    data.parent().parent().parent().find(".fa-angle-double-right").removeClass("hide");
+                    data.addClass("hide");
+                    $(".groupmember1").addClass("hide");
+                    $(".groupmember").addClass("hide");
+                    setTimeout(function () {
+                        var c = document.getElementById("canvas")
+                        if ( isIE() || isIE11() ) {
+                            c.removeNode(true);
+                        } else {
+                            c.remove();
+                        }
+                        $("#canvas_container").append("<canvas id='canvas'></canvas>");
+                        var Position = getPosition();
+                        draw(Position[0], Position[1], Position[2]);
+                    }, 5);
+                })
+            });
+            $(".fa-angle-double-right").each(function() {
+                var data = $(this);
+                data.on('click', function() {
+
+                    $("#over-container").scrollLeft(0);
+                    $("#over-container").scrollTop(0);
+                    $(".groupmember").addClass("hide");
+                    $(".groupmember1").addClass("hide");
+                    $(".groupcontainer").removeClass("hide");
+                    $(".groupcontainer1").removeClass("hide");
+                    $(".fa-angle-double-left").addClass("hide");
+                    $(".fa-angle-double-right").removeClass("hide");
+
+                    data.parent().parent().find(".groupcontainer1").addClass("hide");
+                    data.parent().parent().find(".groupmember1").removeClass("hide");
+                    data.parent().parent().find(".groupcontainer").addClass("hide");
+                    data.parent().parent().find(".groupmember").removeClass("hide");
+                    data.addClass("hide");
+                    data.parent().parent().find(".fa-angle-double-left").removeClass("hide");
+                    setTimeout(function () {
+                        var c = document.getElementById("canvas");
+                        if ( isIE() || isIE11() ) {
+                            c.removeNode(true);
+                        } else {
+                            c.remove();
+                        }
+                        $("#canvas_container").append("<canvas id='canvas'></canvas>")
+                        var Position = getPosition();
+                        draw(Position[0], Position[1], Position[2]);
+                    }, 5);
+                })
+            });
+        }
+
+        function draw(policy_position, middle_position, dst_position, ) {
+
+            $(function () {
+                $(".policy-container").popover();
+                $(".dst-container").popover();
+                $(".member-container").popover();
+                $(".outPolicy-container").popover();
+            });
+            click();
+            var scrollTop = document.documentElement.scrollTop;
+            var vs_left = $('.vs-container').offset().left - left_width;
+            var vs_top = $('.vs-container').offset().top - 25 - scrollTop;
+
+            var c = document.getElementById("canvas");
+            var ctx = c.getContext("2d");
+            ctx.lineWidth = '1';
+            ctx.strokeStyle = '#1b3656';
+            for (var i = 0; i < policy_position.length; i++) {
+                if (i == 0) {
+                    ctx.moveTo(vs_left, vs_top);
+                    ctx.lineTo(policy_position[i][0], policy_position[i][1]);
+                    ctx.stroke();
+                } else {
+                    ctx.moveTo(middle_position[i][0], middle_position[i][1]);
+                    ctx.lineTo(middle_position[i - 1][0], middle_position[i - 1][1]);
+                    ctx.stroke();
+                    ctx.moveTo(middle_position[i][0], middle_position[i][1]);
+                    ctx.lineTo(policy_position[i][0], policy_position[i][1]);
+                    ctx.stroke();
+                }
+
+                ctx.moveTo(policy_position[i][0], policy_position[i][1] + 80);
+                ctx.lineTo(dst_position[i][0], dst_position[i][1]);
+                ctx.stroke();
+            }
+
+
+            const connections = getServiceConnections();
+
+            connections.forEach((connection) => {
+                const [vsDstLeft, vsDstTop] = connection.vsDst;
+                const [serviceLeft, serviceTop] = connection.serviceList;
+
+                if (connection.isFirst) {
+                    ctx.moveTo(vsDstLeft - left_width, vsDstTop - 25 - scrollTop);
+                    ctx.lineTo(serviceLeft - left_width, serviceTop - 100);
+                    ctx.stroke();
+                } else {
+                    ctx.moveTo(vsDstLeft - left_width, vsDstTop - scrollTop);
+                    ctx.lineTo(serviceLeft - left_width, vsDstTop - scrollTop);
+                    ctx.moveTo(serviceLeft - left_width, vsDstTop - scrollTop);
+                    ctx.lineTo(serviceLeft - left_width, serviceTop - 100);
+                    ctx.stroke();
+                }
+            });
+        }
 
         document.getElementById("app").style.display = "block";
 
-        Date.prototype.Format = function (fmt) { //author: meizz 
+        Date.prototype.Format = function (fmt) {
             var o = {
-                "M+": this.getUTCMonth() + 1, //月份 
-                "d+": this.getUTCDate(), //日 
-                "h+": this.getUTCHours(), //小时 
-                "m+": this.getUTCMinutes(), //分 
-                "s+": this.getUTCSeconds(), //秒 
-                "q+": Math.floor((this.getUTCMonth() + 3) / 3), //季度 
-                "S": this.getUTCMilliseconds() //毫秒 
+                "M+": this.getUTCMonth() + 1,
+                "d+": this.getUTCDate(),
+                "h+": this.getUTCHours(),
+                "m+": this.getUTCMinutes(),
+                "s+": this.getUTCSeconds(),
+                "q+": Math.floor((this.getUTCMonth() + 3) / 3),
+                "S": this.getUTCMilliseconds()
             };
             if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getUTCFullYear() + "").substr(4 - RegExp.$1.length));
             for (var k in o)
@@ -280,6 +838,99 @@
             }
         });
 
+        Vue.component('customChart', {
+            data:function() {
+                return {
+                    screenWidth: document.body.clientWidth,
+                    option: this.propoption,
+                    old_option:null,
+                    mychart: null
+                }
+            },
+            props: {
+                propoption: {
+                    type: Object,
+                    default: function() {
+                        return {};
+                    }
+                }
+            },
+            template: '<div ref="echarts" style="height: 300px; width: 100%;"></div>',
+            mounted: function () {
+                this.$nextTick(() => {
+                    this.drawLineGraph();
+                });
+                let that = this
+                window.addEventListener("resize", function () {
+                    return (function() {
+                        window.screenWidth = document.body.clientWidth
+                        that.screenWidth = window.screenWidth
+                    })()
+                })
+            },
+            watch: {
+                propoption: {
+                    handler:function(newValue) {
+                        this.old_option = this.option;
+                        this.option = newValue;
+                        this.redrawChart();
+                        this.old_option = null;
+                    },
+                    deep: true,
+                },
+                screenWidth:function() {
+                    this.mychart.resize()
+                }
+            },
+            methods: {
+                drawLineGraph:function() {
+                    if (this.mychart == null) {
+                        let myEcharts = echarts.init(this.$refs.echarts, theme, {
+                            renderer: 'canvas'
+                        })
+                        this.mychart = myEcharts;
+                    }
+                    let option = this.option;
+                    if (this.option.series && this.option.series[0].data) {
+                        this.mychart.hideLoading();
+                        if (this.option.series[0].data.length == 0) {
+                            this.mychart.clear();
+                            this.mychart.setOption({
+                                title: {
+                                    show: true,
+                                    textStyle: {
+                                        color: 'grey',
+                                        fontSize: 20
+                                    },
+                                    text: gettext('No Data'),
+                                    left: 'center',
+                                    top: 'center'
+                                },
+                                series: []
+                            })
+                        } else {
+                            this.mychart.setOption(option);
+                            if (this.old_option != null && this.old_option.event_handler) {
+                                for (let key in this.old_option.event_handler) {
+                                    this.mychart.off(key);
+                                }
+                            }
+                            if (this.option.event_handler) {
+                                for (let key in this.option.event_handler) {
+                                    this.mychart.on(key, this.option.event_handler[key]);
+                                }
+                            }
+                        }
+                    } else {
+                        this.mychart.clear();
+                        this.mychart.showLoading('default', loadingConfig);
+                    }
+                },
+                redrawChart:function() {
+                    this.drawLineGraph();
+                }
+            }
+        })
         var v = new Vue({
             delimiters: ['{[', ']}'],
             el: "#app",
@@ -346,16 +997,87 @@
                         "loc_dns_request_drop":0
                     },
                     detail: {
-                        healthLoading: true,
                         radio: '',
-                        chart_radio:'',
-                        activeItem: "",
-                        itemType: "",
-                        itemProtocol: "",
-                        rsHealthCheck: [],
-                        message: {}
+                        statictics: {
+                            region_policy_count: 4,
+                            hit: 0,
+                            resort_policy_hit: 0,
+                            default_pool: "",
+                            default_policy_hit: 0,
+                            resort_pool: "",
+                            region_hit: 0
+                        },
+                        topology: {
+                            policies: [
+                            ]
+                        },
+                        basic: {
+                            forward_only: false,
+                            ttl: 1
+                        }
                     },
-                    widgets: {}
+                    topology: {
+                        name: "",
+                    },
+                    widgets: {
+                        "hits": {
+                            title: gettext("Hits(Top 10)"),
+                            option: {
+                                title: {
+                                    show: false
+                                },
+                                grid: {
+                                    left: '2%',
+                                    right: '5%',
+                                    bottom: '2%',
+                                    top: '5%',
+                                    containLabel: true
+                                },
+                                tooltip: {
+                                    trigger: 'item',
+                                    formatter: function(params, ticket, callback) {
+                                        return params.data.name + ': ' + params.data.value + ' (' + params.percent + '%)'
+                                    },
+                                    confine: true
+                                },
+                                legend: {
+                                    type: 'scroll',
+                                    bottom: 0,
+                                    data: [],
+                                },
+                                series: [{
+                                    name: '',
+                                    type: 'pie',
+                                    radius: ['50%', '70%'],
+                                    avoidLabelOverlap: false,
+                                    data: [],
+                                    label: {
+                                        normal: {
+                                            show: false,
+                                            position: 'center'
+                                        },
+                                        emphasis: {
+                                            show: true,
+                                            textStyle: {
+                                                fontSize: '16',
+                                                fontWeight: 'bold'
+                                            }
+                                        }
+                                    },
+                                    labelLine: {
+                                        normal: {
+                                            show: false
+                                        }
+                                    },
+                                    itemStyle: {
+                                        shadowBlur: 6,
+                                        shadowColor: 'rgba(0, 0, 0, 1)'
+                                    },
+                                }],
+                                color: ['#bd3e40', '#47bf7f', '#fab469', '#518fdd', '#715c87','#2f4554', '#61a0a8', '#d48265', '#ca8622', '#bda29a','#6e7074', '#546570', '#c4ccd3', '#c23531', '#91c7ae','#749f83']
+                            }
+                        },
+                    }
                 };
             },
             created: function () {
@@ -383,7 +1105,6 @@
                 if (list_name) {
                     this.detail.activeItem = list_name
                     this.drawer = true;
-                    //this.handleSelectTree(list_name)
                 }
                 const noWarning = $.cookie('no_warning');
                 {% if webui_graph_disable %}
@@ -403,14 +1124,47 @@
             destroyed: function () {
                 this.clearTimer()
             },
-            watch: {},
+            watch: {
+                "detail.topology.policies": {
+                    handler:function(newValue, oldVlaue) {
+                        if (this.detail.radio == "Topology") {
+                            var message = JSON.parse(JSON.stringify(this.detail.topology_message));
+                            if (message.topology.policies) {
+                                getJson(message.topology.policies);
+                                number = 0;
+                                addHtml(message.topology.policies);
+                            }
+                        }
+                    },
+                    deep: true,
+                },
+                drawer: function (newVal, oldVal) {
+                    if (newVal) {
+                        setTimeout(function () {
+                            var Position = getPosition();
+                            draw(Position[0], Position[1], Position[2]);
+                        }, 500);
+                    }
+                },
+                "detail.radio": function (newVal, oldVal) {
+                    if (newVal == 'Topology') {
+                        setTimeout(function () {
+                            var c = document.getElementById("canvas");
+                            c.remove();
+                            $("#canvas_container").append("<canvas id='canvas'></canvas>")
+                            var Position = getPosition();
+                            draw(Position[0], Position[1], Position[2]);
+                        }, 5);
+                    }
+                },
+            },
             methods: {
                 idle_notification: function() {
                     let that = this;
                     $.ajax({
-                            url: '/idle_notification',
-                            type: "get"
-                        });
+                        url: '/idle_notification',
+                        type: "get"
+                    });
                 },
                 handleClick: function(tab, event) {
                     this.initServiceList();
@@ -421,6 +1175,137 @@
                 handleCurrentChange:function(val) {
                     this.initServiceList();
                 },
+                handleSelectTree:function(service_name, type, protocol) {
+                    this.detail.activeItem = service_name;
+                    this.detail.itemType = type;
+                    this.detail.radio = 'Topology'
+                    this.detail.itemProtocol = protocol;
+                    this.detail.chart_radio = 'Normal'
+                    this.reloadTimer();
+                },
+                openDetails:function(row, name, type) {
+                    this.drawer = true;
+                    this.topology.name = name;
+                    if(type == '1') {
+                        this.getTopologyDatByHost(name);
+                    } else {
+                        this.getTopologyDatByService(name);
+                    }
+                    this.getHitsChartData(type)
+                    this.handleSelectTree(row.name, this.service_list.type, row.type);
+                    this.setPositionForCanvas();
+                },
+                getTopologyDatByHost(name) {
+                    $.ajax({
+                        url: '/apv/gslb/get_topology?host=' + name,
+                        type: "get",
+                        success: (res) => {
+                            this.detail.basic = res.data.basic;
+                            this.detail.statictics = res.data.statictics;
+                            this.detail.topology = res.data.topology;
+                        }
+                    })
+                },
+                getTopologyDatByService(name) {
+                    $.ajax({
+                        url: '/apv/gslb/get_topology?service=' + name,
+                        type: "get",
+                        success: (res) => {
+                            this.detail.basic = res.data.basic;
+                            this.detail.statictics = res.data.statictics;
+                            this.detail.topology = res.data.topology;
+                        }
+                    })
+                },
+                topologyTimer: function(host_name) {
+                    $.ajax({
+                        url: '/apv/gslb/get_topology?service=' + host_name,
+                        type: "get",
+                        success: function (res) {
+                            var response = JSON.parse(res)
+                            if (response.result == 1) {
+                                that.detail.topology_message = response.data;
+                                if (that.detail.radio == "Charts" && that.detail.chart_radio == "Normal") {
+                                    let policy_list = []
+                                    let rs_list = []
+                                    let rs_list_str = '';
+                                    _.each(response.data.topology.policies, function (policy) {
+                                        if (policy.type == "static") {
+                                            policy_list.push({
+                                                name: "{\"src\": \"" + that.detail.activeItem + "\"}",
+                                                type: "static",
+                                                display_name: "static"
+                                            })
+
+                                            if (!rs_list.some(function(item) {
+                                                    if (item.name == policy.dst.name) {
+                                                        return true
+                                                    }
+                                                })) {
+                                                rs_list.push({
+                                                    name: policy.dst.name,
+                                                    protocol: policy.dst.protocol
+                                                })
+                                                if (rs_list_str) {
+                                                    rs_list_str += ",";
+                                                }
+                                                rs_list_str += "'"+policy.dst.name+"'";
+                                            }
+                                        } else {
+                                            if (!policy_list.some(function(item) {
+                                                    if (item.name == policy.name) {
+                                                        return true
+                                                    }
+                                                })) {
+                                                if (policy.type == 'default' || policy.type == 'backup' || policy.type == 'doh') {
+                                                    var display_name = policy.type;
+                                                } else {
+                                                    var display_name = policy.type + '(' + policy.name +')';
+                                                }
+                                                policy_list.push({
+                                                    name: "{\"name\": \"" + policy.name + "\", \"type\": \"" + policy.type + "\"}",
+                                                    type: policy.type,
+                                                    display_name: display_name
+                                                })
+                                            }
+                                            _.each(policy.dst.members, function (member) {
+                                                if (!rs_list.some(function(item) {
+                                                        if (item.name == member.name) {
+                                                            return true
+                                                        }
+                                                    })) {
+                                                    rs_list.push({
+                                                        name: member.name,
+                                                        protocol: member.protocol
+                                                    })
+                                                    if (rs_list_str) {
+                                                        rs_list_str += ",";
+                                                    }
+                                                    rs_list_str += "'"+member.name+"'";
+                                                }
+                                            })
+                                        }
+                                    })
+
+                                    let policy_request = [];
+                                    _.each(policy_list, function (p) {
+                                        policy_request.push({
+                                            "from": from_condition,
+                                            "to": to_condition,
+                                            "format": 'cluster',
+                                            "rawSql": "select '" + p.display_name + "', INCREMENT(hits) from " + policytype2table[p.type] + " WHERE $__timeFilter(time) and pk = '" + p.name + "'",
+                                        })
+                                    })
+
+                                    var numberorder = function (a, b) {
+                                        return b['value'] - a['value'];
+                                    }
+                                }
+                            }
+                        }
+                    });
+                },
+
                 initServiceList:function() {
                     let that = this;
                     let flushing = 30000;
@@ -554,7 +1439,68 @@
                 setTimer:function() {
                     this.CardTimer();
                     this.initServiceList();
-                }
+                },
+                setPositionForCanvas: function () {
+                    var Position = getPosition();
+                },
+                reloadTimer:function() {
+                    this.clearTimer();
+                    this.setTimer();
+                    this.idle_notification();
+                },
+                expand: function (name) {
+                    $("#over-container").scrollLeft(0);
+                    $("#over-container").scrollTop(0);
+                    setTimeout(function () {
+                        var c = document.getElementById("canvas");
+                        c.remove();
+                        $("#canvas_container").append("<canvas id='canvas'></canvas>")
+                        var Position = getPosition();
+                        draw(Position[0], Position[1], Position[2]);
+                    }, 5);
+                },
+                collapse: function () {
+                    $("#over-container").scrollLeft(0);
+                    $("#over-container").scrollTop(0);
+                    setTimeout(function () {
+                        var c = document.getElementById("canvas");
+                        c.remove();
+                        $("#canvas_container").append("<canvas id='canvas'></canvas>")
+                        var Position = getPosition();
+                        draw(Position[0], Position[1], Position[2]);
+                    }, 5);
+                },
+                getHitsChartData: function (type) {
+                    const param = {
+                        "type": type,
+                        "from": "now-30m",
+                        "to": "now",
+                        "count": 10
+                    }
+                    let that = this;
+                    $.ajax({
+                        headers: {
+                            "Content-Type": "application/json"
+                        },
+                        url: "/apv/gslb/get_top_chart_data",
+                        type: "post",
+                        data: JSON.stringify(param),
+                        success: function (res) {
+                            const res_sort = res.data.sort((a, b) => b[1] - a[1]);
+                            let series_data = [];
+                            let xaxis_data = [];
+                            res_sort.forEach(item => {
+                                series_data.push({
+                                    name: item[0],
+                                    value: item[1]
+                                });
+                                xaxis_data.push(item[0]);
+                            })
+                            that.widgets['hits'].option.series[0].data = series_data;
+                            that.widgets['hits'].option.legend.data = xaxis_data;
+                        }
+                    });
+                },
             }
         });
     });
@@ -605,8 +1551,8 @@
 }
 
 .el-card .el-card__header {
-    background: #0f1b29;
-    background-color: #0f1b29;
+    background: #02022f;
+    background-color: #02022f;
 }
 
 
@@ -716,7 +1662,7 @@
 }
 .icon-vs, .icon-policy, .icon-group, .icon-rs, .icon-vlink, .icon-vsnew, .icon-policynew, .icon-groupnew, .icon-rsnew, .icon-vlinknew {
     font-size: 45px;
-} 
+}
 .icon-vsnew, .icon-policynew, .icon-groupnew, .icon-rsnew, .icon-vlinknew {
     color: #fff;
 }
@@ -745,6 +1691,13 @@
 .my-table .cell.el-tooltip {
     white-space: normal;
 }
+.click-title:hover {
+    cursor: pointer;
+    text-decoration: underline;
+}
+.custom-drawer {
+    outline: none;
+}
 </style>
 
 {% endblock %}
\ No newline at end of file
