James Iter преди 9 години
родител
ревизия
9197fd82ef
променени са 6 файла, в които са добавени 395 реда и са изтрити 2 реда
  1. 4 0
      main.py
  2. 225 0
      static/css/host-table.css
  3. 102 0
      templates/hosts_show.html
  4. 2 1
      templates/layout.html
  5. 60 0
      views/host.py
  6. 2 1
      views_route_table.py

+ 4 - 0
main.py

@@ -51,6 +51,8 @@ from views.boot_job import blueprint as view_boot_job_blueprint
 from views.boot_job import blueprints as view_boot_job_blueprints
 from views.operate_rule import blueprint as view_operate_rule_blueprint
 from views.operate_rule import blueprints as view_operate_rule_blueprints
+from views.host import blueprint as view_host_blueprint
+from views.host import blueprints as view_host_blueprints
 
 from websockify.websocketproxy import WebSocketProxy
 
@@ -131,6 +133,8 @@ try:
     app.register_blueprint(view_boot_job_blueprints)
     app.register_blueprint(view_operate_rule_blueprint)
     app.register_blueprint(view_operate_rule_blueprints)
+    app.register_blueprint(view_host_blueprint)
+    app.register_blueprint(view_host_blueprints)
 
 except:
     logger.error(traceback.format_exc())

+ 225 - 0
static/css/host-table.css

@@ -0,0 +1,225 @@
+/* Pricing tables */
+
+.host-box {
+    text-align: center;
+}
+.host-box .host-title,
+.host-box .host-specs {
+    margin: -1px -1px 0;
+}
+.host-box .host-title {
+    font-weight: normal;
+    padding: 15px;
+}
+.host-box ul {
+    margin: 0;
+    padding: 0;
+    list-style: none;
+}
+.host-box .host-specs {
+    padding: 10px 15px 20px;
+}
+.host-box .host-specs span {
+    font-size: 50px;
+}
+.host-box .host-specs span sup {
+    font-size: 30px;
+    margin-left: -20px;
+    padding-right: 5px;
+}
+.host-box .host-specs i {
+    font-size: 14px;
+    font-style: normal;
+    display: block;
+    color: rgba(255, 255, 255, .6);
+}
+.host-box ul li {
+    font-size: 14px;
+    line-height: 48px;
+    height: 48px;
+    padding: 0 10px;
+    border-bottom: #eee solid 1px;
+}
+.host-box ul li:nth-child(even) {
+    background: #fafafa;
+}
+/* Pricing table alternate style */
+
+.host-table .host-box {
+    padding: 0;
+}
+.host-table .host-box + .host-box {
+    border-width: 1px 1px 1px 0;
+    border-radius: 0;
+}
+.host-table .host-box + .host-box:nth-child(2):last-child {
+    border-width: 1px 1px 1px;
+}
+.host-table .host-box .host-title,
+.host-table .host-box .host-specs {
+    margin: 0;
+    border-bottom: #eee solid 1px;
+    border-radius: 0;
+}
+.host-table .host-box .host-specs span {
+    font-size: 40px;
+}
+.host-table .host-box .host-specs span sup {
+    font-size: 20px;
+    margin-left: -10px;
+    padding-right: 5px;
+}
+.host-table .host-box .host-specs i {
+    color: rgba(0, 0, 0, .5);
+}
+.host-table .host-best {
+    position: relative;
+    z-index: 15;
+    margin-right: -1px;
+    margin-left: -1px;
+    box-shadow: 0 0 10px 0 rgba(0, 0, 0, .1);
+}
+.host-table .host-best .host-specs {
+    background: #fafafa;
+}
+.host-table .host-best .host-title {
+    font-size: 28px;
+    line-height: 60px;
+    height: 90px;
+    margin: -25px -1px 0;
+}
+
+/* Pricing alternate */
+
+.host-box-alt {
+    position: relative;
+}
+
+.host-box-alt .col-md-3 {
+    padding: 0;
+    border: #c6c6c6 solid 1px;
+    border-width: 1px 1px 1px 0;
+    width: 26%;
+    text-align: center;
+}
+
+.host-box-alt .plans-features {
+    width: 22%;
+    text-align: right;
+    border-color: transparent #c6c6c6 transparent transparent;
+}
+
+.host-box-alt .plans-features .plan-header {
+    height: 170px;
+}
+
+.host-box-alt .plans-features ul li {
+    border-left: #f0f0f0 solid 1px;
+}
+
+.host-box-alt ul {
+    list-style: none;
+    margin: 0;
+    padding: 0;
+}
+
+.host-box-alt .plan-header {
+    padding: 15px;
+    border-bottom: #f0f0f0 solid 1px;
+}
+
+.host-box-alt .plan-header h4 {
+    margin: 0;
+    color: #f26b33;
+    text-transform: uppercase;
+    font-size: 17px;
+    font-weight: bold;
+    height: 40px;
+    line-height: 30px;
+    border-bottom: #F3F3F3 solid 1px;
+}
+
+.host-box-alt .plan-header .plan-price {
+    font-size: 45px;
+    font-weight: 100;
+    height: 60px;
+    line-height: 65px;
+    margin: 0 0 5px;
+}
+
+.host-box-alt .plan-header .plan-price small {
+    font-size: 30px;
+    opacity: 0.4;
+    padding-right: 3px;
+}
+
+.host-box-alt .studio-plan .plan-header h4 {
+    color: #32cf4e;
+}
+
+.host-box-alt .unlimited-plan .plan-header h4 {
+    color: #3792f2;
+}
+
+.host-box-alt ul li {
+    height: 32px;
+    line-height: 32px;
+    padding: 0 10px;
+    border-bottom: #f0f0f0 solid 1px;
+    color: #0093d9;
+    font-size: 14px;
+    font-weight: bold;
+}
+
+.host-box-alt .plans-features ul li {
+    color: #6f6f6f;
+    font-weight: normal;
+}
+
+.host-box-alt ul li .feature-included,
+.host-box-alt ul li .feature-excluded {
+    border-radius: 30px;
+    width: 12px;
+    height: 12px;
+    display: inline-block;
+}
+
+.host-box-alt ul li .feature-excluded {
+    background: #e6e6e6;
+}
+
+.host-box-alt .host-btn {
+    padding: 15px;
+    background: #fafafa;
+}
+
+.host-box-alt .host-btn .btn {
+    padding: 15px 0;
+    font-weight: bold;
+    font-size: 16px;
+    box-sizing: initial;
+    display: block;
+    line-height: 1;
+}
+
+.host-box-alt .host-btn .btn b {
+    opacity: 0.6;
+    display: block;
+    padding: 6px 0 0;
+    font-size: 13px;
+    font-weight: normal;
+}
+
+.individual-plan .host-btn {
+    border-left: #c6c6c6 solid 1px;
+    margin-left: -1px;
+}
+
+.host-box-alt ul li.header {
+    background: #f9f9f9;
+    text-transform: uppercase;
+    font-weight: bold;
+    text-align: right;
+    font-size: 12px;
+    color: #000;
+}

+ 102 - 0
templates/hosts_show.html

@@ -0,0 +1,102 @@
+{% extends "layout.html" %}
+{% block head %}
+    {{ super() }}
+{% endblock head %}
+{% block content %}
+
+<script type="text/javascript">
+    var page = 1;
+    var page_size = 10;
+    var keyword = '';
+    var resource_path = window.location.pathname;
+    var cur_url = resource_path;
+
+    $(document).ready(function() {
+        page_size = $('#page_size').val();
+        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
+
+        var last_ready = null;
+        $('#content_search').keydown(function() {
+            if (last_ready !== null) {
+                clearTimeout(last_ready);
+            }
+            last_ready = setTimeout(function () {
+                keyword = $('#content_search').val();
+                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
+                if (keyword.length > 0) {
+                    cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
+                }
+                window.location.href=cur_url;
+            }, 1000);
+        });
+
+        $('#page_size').change(function () {
+            keyword = $('#content_search').val();
+            page_size = $('#page_size').val();
+            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
+            if (keyword.length > 0) {
+                cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
+            }
+            window.location.href=cur_url;
+        });
+
+        $('body').addClass('add-transition');
+        $('.add-page-transition').on('click', function(){
+            var transAttr = $(this).attr('data-transition');
+            $('.add-transition').attr('class', 'add-transition');
+            $('.add-transition').addClass(transAttr);
+        });
+    });
+
+    function refresh() {
+        keyword = $('#content_search').val();
+        page = $('#pagination li.active a').text();
+        page_size = $('#page_size').val();
+        cur_url = resource_path + '?page=' + page + '&page_size=' + page_size;
+        if (keyword.length > 0) {
+            cur_url = resource_path + '?page=' + page + '&page_size=' + page_size + '&keyword=' + keyword;
+        }
+        window.location.href=cur_url;
+    }
+
+</script>
+    <div class="panel">
+        <div class="panel-body">
+            <h3 class="title-hero" style="font-size: 24px;">
+                宿主机
+            </h3>
+            <div>
+                <div id="datatable-row-highlight_wrapper" class="dataTables_wrapper form-inline">
+                    <div class="row" style="padding: 10px 10px 10px 0; width: 100%;">
+                        <div class="col-sm-12" style="padding-right: 0;">
+                            <div id="datatable-row-highlight_filter" class="dataTables_filter" style="display: inline-block;">
+                                <input id="content_search" type="search" class="form-control" placeholder="模糊搜索..." value="{%- if keyword -%} {{ keyword }} {%- endif -%}" style="margin-left: 0; border-radius: 0;">
+                            </div>
+                            <div class="pull-right">
+                                <button class="btn btn-default" onclick="refresh()" style="border-radius: 0;"><span class="glyph-icon icon-elusive-arrows-cw"></span></button>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="row">
+                    {% for item in hosts_ret.data %}
+                    <div class="col-md-4">
+                        <div class="host-box content-box">
+                            <h3 class="bg-black host-title">{{ item.hostname }}</h3>
+                            <div class="bg-blue host-specs">
+                                <span><sup>$</sup>1.5</span>
+                                <i>当前负载</i>
+                            </div>
+                            <ul>
+                                <li>CPU: {{ item.cpu }}核</li>
+                                <li>内存: {{ item.memory / 1024 / 1024 / 1024 }}</li>
+                                <li><i class="glyph-icon icon-circle font-size-23 {% if item.alive == true %}font-green{% else %}font-red{% endif %}"></i></li>
+                            </ul>
+                        </div>
+                    </div>
+                    {% endfor %}
+                </div>
+            </div>
+        </div>
+    </div>
+{% endblock content %}

+ 2 - 1
templates/layout.html

@@ -167,6 +167,7 @@
 
     <!-- JimV -->
     <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/icons.css') }}">
+    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/host-table.css') }}">
 
     <!-- JS Core -->
     <script type="text/javascript" src="{{ url_for('static', filename='js-core-min/jquery-core.js') }}"></script>
@@ -315,7 +316,7 @@
                             </a>
                         </li>
                         <li>
-                            <a href="#" title="宿主机列表">
+                            <a href="{{ url_for('v_hosts.show') }}" title="宿主机列表">
                                 <i class="glyph-icon icon-linecons-desktop"></i>
                                 <span>宿主机</span>
                             </a>

+ 60 - 0
views/host.py

@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+
+import json
+from flask import Blueprint, render_template, url_for, request
+import requests
+from math import ceil
+
+
+__author__ = 'James Iter'
+__date__ = '2017/8/10'
+__contact__ = 'james.iter.cn@gmail.com'
+__copyright__ = '(c) 2017 by James Iter.'
+
+
+blueprint = Blueprint(
+    'v_host',
+    __name__,
+    url_prefix='/host'
+)
+
+blueprints = Blueprint(
+    'v_hosts',
+    __name__,
+    url_prefix='/hosts'
+)
+
+
+def show():
+    args = list()
+    page = int(request.args.get('page', 1))
+    page_size = int(request.args.get('page_size', 10))
+    keyword = request.args.get('keyword', None)
+    resource_path = request.path
+
+    if page is not None:
+        args.append('page=' + page.__str__())
+
+    if page_size is not None:
+        args.append('page_size=' + page_size.__str__())
+
+    if keyword is not None:
+        args.append('keyword=' + keyword.__str__())
+
+    host_url = request.host_url.rstrip('/')
+
+    hosts_url = host_url + url_for('api_hosts.r_get_by_filter')
+    if keyword is not None:
+        hosts_url = host_url + url_for('api_hosts.r_content_search')
+
+    if args.__len__() > 0:
+        hosts_url = hosts_url + '?' + '&'.join(args)
+
+    hosts_ret = requests.get(url=hosts_url)
+    hosts_ret = json.loads(hosts_ret.content)
+
+    return render_template('hosts_show.html', hosts_ret=hosts_ret, resource_path=resource_path, keyword=keyword)
+
+

+ 2 - 1
views_route_table.py

@@ -3,7 +3,7 @@
 
 
 from models.utils import add_rule_views
-from views import guest, disk, log, os_template, boot_job, operate_rule
+from views import guest, disk, log, os_template, boot_job, operate_rule, host
 
 
 __author__ = 'James Iter'
@@ -35,3 +35,4 @@ add_rule_views(boot_job.blueprint, '', views_func='boot_job.create', methods=['P
 add_rule_views(operate_rule.blueprints, '', views_func='operate_rule.show', methods=['GET'])
 add_rule_views(operate_rule.blueprint, '', views_func='operate_rule.create', methods=['POST'])
 
+add_rule_views(host.blueprints, '', views_func='host.show', methods=['GET'])