293 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			HTML
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			293 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			HTML
		
	
	
	
		
			Vendored
		
	
	
	
{{define "theme-mdui/home"}}
 | 
						|
<!doctype html>
 | 
						|
<html lang="zh-CN">
 | 
						|
 | 
						|
<head>
 | 
						|
  <meta charset="utf-8">
 | 
						|
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
 | 
						|
  <title>{{.Title}}</title>
 | 
						|
  <link rel="shortcut icon" type="image/png" href="/static/logo.svg?v20210804" />
 | 
						|
 | 
						|
  <!-- MDUI CSS -->
 | 
						|
  <link rel="stylesheet" href="https://fastly.jsdelivr.net/npm/mdui@1.0.2/dist/css/mdui.min.css"/>
 | 
						|
  <link rel="stylesheet" href="/static/theme-mdui/mdui.css" type="text/css">
 | 
						|
  <style>
 | 
						|
	.mdui-table td, .mdui-table th{padding: 6px;}
 | 
						|
	.progress{width: 10%;min-width: 75px;}
 | 
						|
	.progress-text{font-size: 16px;font-weight: 800;position: relative;top: 4px;left: 6px;}
 | 
						|
	.offline st,.offline at,.offline gt,.offline .progress-text{color: grey;}
 | 
						|
	a{text-decoration:none;color:#333;}.mdui-theme-layout-dark a{color:#fff;}
 | 
						|
  </style>
 | 
						|
  {{if ts .CustomCode}}
 | 
						|
  {{.CustomCode|safe}}
 | 
						|
  {{end}}
 | 
						|
</head>
 | 
						|
 | 
						|
<body>
 | 
						|
{{template "theme-mdui/menu" .}}
 | 
						|
 | 
						|
  <div id="app">
 | 
						|
  <div id="container" class="mdui-container">
 | 
						|
    <button @click="toggleView" class="mdui-fab mdui-fab-wrapper mdui-fab-fixed mdui-ripple mdui-color-pink-accent">
 | 
						|
      <i v-if="showCard" class="mdui-icon material-icons">list</i>
 | 
						|
      <i v-else class="mdui-icon material-icons">apps</i>
 | 
						|
    </button>
 | 
						|
    <div v-if="showCard" class="mdui-row-xs-1 mdui-row-sm-2 mdui-row-md-3 mdui-row-lg-4">
 | 
						|
      <div id="servers">
 | 
						|
        <div class="mdui-col" v-for='server in servers' :id="server.ID">
 | 
						|
          <div :class="'mdui-card mt' + (server.live?'':' offline')">
 | 
						|
            <div class="mdui-card-primary">
 | 
						|
              <div class="mdui-card-primary-title mdui-text-truncate">@#server.Name#@</div>
 | 
						|
            </div>
 | 
						|
            <div v-if="server.live" class="mdui-card-menu">
 | 
						|
              <i :id="'info-' + server.ID" class="mdui-icon material-icons">info_outline</i>
 | 
						|
            </div>
 | 
						|
            <div v-else class="mdui-card-menu mdui-typo-title mdui-text-color-grey">Offline</div>
 | 
						|
            <div class="mdui-card-content">
 | 
						|
              <ul class="mdui-list">
 | 
						|
                <li class="mdui-list-item">
 | 
						|
                  <i class="mdui-list-item-icon mdui-icon material-icons">memory</i>
 | 
						|
                  <div class="mdui-list-item-content">
 | 
						|
                    <st class="mdui-list-item-title mdui-list-item-one-line">CPU <span>@#server.live?parseInt(server.State.CPU):'NaN'#@%</span></st>
 | 
						|
                    <div class="mdui-list-item-text" style="opacity:1;">
 | 
						|
                      <div class="mdui-progress">
 | 
						|
                        <div class="mdui-progress-determinate mdui-color-indigo-400" :style="'width: ' + (server.live?server.State.CPU:'0') + '%;'"></div>
 | 
						|
                      </div>
 | 
						|
                    </div>
 | 
						|
                  </div>
 | 
						|
                </li>
 | 
						|
                <li class="mdui-list-item" :id="'mem-' + server.ID">
 | 
						|
                  <i class="mdui-list-item-icon mdui-icon material-icons">straighten</i>
 | 
						|
                  <div class="mdui-list-item-content">
 | 
						|
                    <at class="mdui-list-item-title mdui-list-item-one-line">MEM <span>@#server.live?parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0):'NaN'#@%</span></at>
 | 
						|
                    <div class="mdui-progress">
 | 
						|
                      <div class="mdui-progress-determinate mdui-color-pink-400" :style="'width: ' + (server.live?parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0):'0') + '%;'"></div>
 | 
						|
                    </div>
 | 
						|
                  </div>
 | 
						|
                </li>
 | 
						|
                <li class="mdui-list-item">
 | 
						|
                  <i class="mdui-list-item-icon mdui-icon material-icons">swap_vert</i>
 | 
						|
                  <div class="mdui-list-item-content">
 | 
						|
                    <div class="mdui-list-item-title">{{tr "UpNetTransfer"}}</div>
 | 
						|
                    <div class="mdui-list-item-text mdui-list-item-one-line" style="opacity:1;">
 | 
						|
                      <at><span>@#formatNetByteSize(server.State.NetOutSpeed)#@</span></at>
 | 
						|
                    </div>
 | 
						|
                  </div>
 | 
						|
                  <div class="mdui-list-item-content">
 | 
						|
                    <div class="mdui-list-item-title">{{tr "DownNetTransfer"}}</div>
 | 
						|
                    <div class="mdui-list-item-text mdui-list-item-one-line" style="opacity:1;">
 | 
						|
                      <st><span>@#formatNetByteSize(server.State.NetInSpeed)#@</span></st>
 | 
						|
                    </div>
 | 
						|
                  </div>
 | 
						|
                </li>
 | 
						|
                <li class="mdui-list-item">
 | 
						|
                  <i class="mdui-list-item-icon mdui-icon material-icons">swap_horiz</i>
 | 
						|
                  <div class="mdui-list-item-content">
 | 
						|
                    <div class="mdui-list-item-title">{{tr "TotalUpNetTransfer"}}</div>
 | 
						|
                    <div class="mdui-list-item-text mdui-list-item-one-line" style="opacity:1;">
 | 
						|
                      <at><span>@#formatByteSize(server.State.NetOutTransfer)#@</span></at>
 | 
						|
                    </div>
 | 
						|
                  </div>
 | 
						|
                  <div class="mdui-list-item-content">
 | 
						|
                    <div class="mdui-list-item-title">{{tr "TotalDownNetTransfer"}}</div>
 | 
						|
                    <div class="mdui-list-item-text mdui-list-item-one-line" style="opacity:1;">
 | 
						|
                      <st><span>@#formatByteSize(server.State.NetInTransfer)#@</span></st>
 | 
						|
                    </div>
 | 
						|
                  </div>
 | 
						|
                </li>
 | 
						|
              </ul>
 | 
						|
            </div>
 | 
						|
          </div>
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </div>
 | 
						|
 | 
						|
    <div v-else class="mdui-table-fluid mdui-m-t-1">
 | 
						|
      <table class="mdui-table mdui-table-hoverable">
 | 
						|
		<thead>
 | 
						|
		  <tr>
 | 
						|
		    <th class="mdui-text-center">ID</th>
 | 
						|
		    <th class="mdui-text-center">{{tr "Name"}}</th>
 | 
						|
		    <th class="mdui-text-center">{{tr "UpNetTransfer"}}</th>
 | 
						|
		    <th class="mdui-text-center">{{tr "DownNetTransfer"}}</th>
 | 
						|
		   	<th class="mdui-text-center">{{tr "TotalUpNetTransfer"}}</th>
 | 
						|
		    <th class="mdui-text-center">{{tr "TotalDownNetTransfer"}}</th>
 | 
						|
		    <th class="mdui-text-center">CPU</th>
 | 
						|
		    <th class="mdui-text-center">RAM</th>
 | 
						|
		    <th class="mdui-text-center">{{tr "Uptime"}}</th>
 | 
						|
		  </tr>
 | 
						|
		</thead>
 | 
						|
		<tbody>
 | 
						|
		  <tr :class="(server.live?'':'offline')" v-for="server in servers">
 | 
						|
		    <td class="mdui-text-center">@#server.ID#@</td>
 | 
						|
		    <td class="mdui-text-center">@#server.Name#@</td>
 | 
						|
		    <td class="mdui-text-center"><at>@#formatNetByteSize(server.State.NetOutSpeed)#@</at></td>
 | 
						|
		    <td class="mdui-text-center"><st>@#formatNetByteSize(server.State.NetInSpeed)#@</st></td>
 | 
						|
		    <td class="mdui-text-center"><at>@#formatByteSize(server.State.NetOutTransfer)#@</at></td>
 | 
						|
		    <td class="mdui-text-center"><st>@#formatByteSize(server.State.NetInTransfer)#@</st></td>
 | 
						|
		    <td class="progress">
 | 
						|
		      <div class="mdui-progress" style="height: 30px; background-color: #edbbd2;">
 | 
						|
		        <div class="mdui-progress-determinate mdui-color-pink-a400" :style="'width: ' + (server.live?server.State.CPU:'0') + '%;'">
 | 
						|
                    <span class="mdui-text-truncate progress-text">@#server.live?parseInt(server.State.CPU):'NaN'#@%</span>
 | 
						|
                </div>
 | 
						|
		      </div>
 | 
						|
		    </td>
 | 
						|
		    <td class="progress">
 | 
						|
		      <div class="mdui-progress" style="height: 30px;">
 | 
						|
		        <div class="mdui-progress-determinate mdui-color-indigo-400" :style="'width: ' + parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0) + '%;'">
 | 
						|
                    <span class="mdui-text-truncate progress-text">@#parseInt(server.State?server.State.MemUsed/server.Host.MemTotal*100:0)#@%</span>
 | 
						|
                </div>
 | 
						|
		      </div>
 | 
						|
		    </td>
 | 
						|
		    <td class="mdui-text-center">@#secondToDate(server.State.Uptime)#@</td>
 | 
						|
		  </tr>
 | 
						|
		</tbody>
 | 
						|
	  </table>
 | 
						|
	</div>
 | 
						|
 | 
						|
  </div>
 | 
						|
  </div>
 | 
						|
 | 
						|
{{template "theme-mdui/footer" .}}
 | 
						|
 | 
						|
  <script src="/static/theme-mdui/mdui.js"></script>
 | 
						|
  <script src="https://fastly.jsdelivr.net/npm/mdui@1.0.2/dist/js/mdui.min.js"></script>
 | 
						|
  <script src="https://fastly.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
 | 
						|
  <script src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.12/vue.min.js"></script>
 | 
						|
 | 
						|
  <script>
 | 
						|
    var container=document.querySelector("#container");
 | 
						|
    container.style.minHeight=window.innerHeight-document.body.clientHeight+container.clientHeight+'px';
 | 
						|
    mdui.mutation();
 | 
						|
    const initData = JSON.parse('{{.Servers}}').servers;
 | 
						|
    var statusCards = new Vue({
 | 
						|
        el: '#app',
 | 
						|
        delimiters: ['@#', '#@'],
 | 
						|
        data: {
 | 
						|
            servers: initData,
 | 
						|
            cache: [],
 | 
						|
            showCard: true
 | 
						|
        },
 | 
						|
        methods: {
 | 
						|
            toggleView() {
 | 
						|
              this.showCard = !this.showCard
 | 
						|
            },
 | 
						|
            toFixed2(f) {
 | 
						|
              return f.toFixed(2)
 | 
						|
            },
 | 
						|
            secondToDate(s) {
 | 
						|
                var d = Math.floor(s / 3600 / 24);
 | 
						|
                if (d > 0) {
 | 
						|
                    return d + " {{tr "Day"}}"
 | 
						|
                }
 | 
						|
                var h = Math.floor(s / 3600 % 24);
 | 
						|
                var m = Math.floor(s / 60 % 60);
 | 
						|
                var s = Math.floor(s % 60);
 | 
						|
                return h + ":" + ("0" + m).slice(-2) + ":" + ("0" + s).slice(-2);
 | 
						|
            },
 | 
						|
            readableBytes(bytes) {
 | 
						|
              if (!bytes) {
 | 
						|
                return '0B'
 | 
						|
              }
 | 
						|
              var i = Math.floor(Math.log(bytes) / Math.log(1024)),
 | 
						|
                sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
 | 
						|
              return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + sizes[i];
 | 
						|
            },
 | 
						|
            readableNetBytes(bytes) {
 | 
						|
              if (!bytes) {
 | 
						|
                return '0B'
 | 
						|
              }
 | 
						|
              var Kbps=125, Mbps=Kbps*1000, Gbps=Mbps*1000, Tbps=Gbps*1000;
 | 
						|
              if (bytes < Kbps) return (bytes * 8).toFixed(2) + 'bps';
 | 
						|
              if (bytes < Mbps) return (bytes / Kbps).toFixed(2) + 'Kbps';
 | 
						|
              if (bytes < Gbps) return (bytes / Mbps).toFixed(2) + 'Mbps';
 | 
						|
              if (bytes < Tbps) return (bytes / Gbps).toFixed(2) + 'Gbps';
 | 
						|
              else return (bytes / Tbps).toFixed(2) + 'Tbps';
 | 
						|
            },
 | 
						|
            formatTimestamp(t) {
 | 
						|
                return new Date(t * 1000).toLocaleString()
 | 
						|
            },
 | 
						|
            formatByteSize(bs) {
 | 
						|
                const x = this.readableBytes(bs)
 | 
						|
                return x != "NaN undefined" ? x : 'NaN'
 | 
						|
            },
 | 
						|
            formatNetByteSize(bs) {
 | 
						|
                const x = this.readableNetBytes(bs)
 | 
						|
                return x != "NaN undefined" ? x : 'NaN'
 | 
						|
            },
 | 
						|
            formatTooltip(server) {
 | 
						|
              var disk = this.formatByteSize(server.State.DiskUsed) + '/' + this.formatByteSize(server.Host.DiskTotal);
 | 
						|
              var upTime = this.secondToDate(server.State.Uptime);
 | 
						|
              var tooltip =
 | 
						|
`{content: 'System: ${server.Host.Platform}-${server.Host.PlatformVersion}[${server.Host.Arch}]<br>CPU: ${server.Host.CPU}<br>Disk: ${disk}<br>Online: ${upTime}<br>Version: ${server.Host.Version}'}`;
 | 
						|
              return tooltip
 | 
						|
            }
 | 
						|
        }
 | 
						|
    })
 | 
						|
 | 
						|
    const wsProtocol = window.location.protocol == "https:" ? "wss" : "ws"
 | 
						|
    const ws = new WebSocket(wsProtocol + '://' + window.location.host + '/ws');
 | 
						|
    ws.onopen = function (evt) {
 | 
						|
        mdui.snackbar({
 | 
						|
          message: '{{tr "RealtimeChannelEstablished"}}',
 | 
						|
          timeout: 2000,
 | 
						|
          position: 'top',
 | 
						|
          onClosed: function(){
 | 
						|
            mdui.mutation();
 | 
						|
          }
 | 
						|
        });
 | 
						|
    }
 | 
						|
    var infoTooltip = {}, memTooltip = {};
 | 
						|
    ws.onmessage = function (evt) {
 | 
						|
        const data = JSON.parse(evt.data)
 | 
						|
        statusCards.servers = data.servers
 | 
						|
        for (let i = 0; i < statusCards.servers.length; i++) {
 | 
						|
            const ns = statusCards.servers[i];
 | 
						|
            if (!ns.Host) ns.live = false
 | 
						|
            else {
 | 
						|
                const lastActive = new Date(ns.LastActive).getTime()
 | 
						|
                if (data.now - lastActive > 10 * 1000) {
 | 
						|
                    ns.live = false
 | 
						|
                } else {
 | 
						|
                    ns.live = true
 | 
						|
                    if (statusCards.showCard) {
 | 
						|
                      if (infoTooltip[ns.ID]) {
 | 
						|
                        var disk =  statusCards.formatByteSize(ns.State.DiskUsed) + '/' + statusCards.formatByteSize(ns.Host.DiskTotal);
 | 
						|
                        var upTime = statusCards.secondToDate(ns.State.Uptime);
 | 
						|
                        var content =
 | 
						|
  `System: ${ns.Host.Platform}-${ns.Host.PlatformVersion}[${ns.Host.Arch}]
 | 
						|
  CPU: ${ns.Host.CPU}
 | 
						|
  Disk: ${disk}
 | 
						|
  Online: ${upTime}
 | 
						|
  Version: ${ns.Host.Version}`;
 | 
						|
                        infoTooltip[ns.ID].$element[0].innerText = content;
 | 
						|
                      }
 | 
						|
                      else {
 | 
						|
                        if (document.getElementById(`info-${ns.ID}`)) infoTooltip[ns.ID] = new mdui.Tooltip(`#info-${ns.ID}`, {});
 | 
						|
                      }
 | 
						|
 | 
						|
                      if (memTooltip[ns.ID]) {
 | 
						|
                        var content = `${statusCards.formatByteSize(ns.State.MemUsed)}/${statusCards.formatByteSize(ns.Host.MemTotal)}`;
 | 
						|
                        memTooltip[ns.ID].$element[0].innerText = content;
 | 
						|
                      }
 | 
						|
                      else {
 | 
						|
                        if (document.getElementById(`mem-${ns.ID}`)) memTooltip[ns.ID] = new mdui.Tooltip(`#mem-${ns.ID}`, {});
 | 
						|
                      }
 | 
						|
                    } else {mdui.$('div').remove('.mdui-tooltip'); infoTooltip = {}; memTooltip = {};}
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        mdui.mutation();
 | 
						|
    }
 | 
						|
    ws.onclose = function () {
 | 
						|
        mdui.snackbar({
 | 
						|
          message: '{{tr "RealtimeChannelDisconnect"}}',
 | 
						|
          timeout: 2000,
 | 
						|
          position: 'top',
 | 
						|
        });
 | 
						|
    }
 | 
						|
  </script>
 | 
						|
</body>
 | 
						|
</html>
 | 
						|
{{end}}
 |