掉线记录,是根据数据库中行记录的上传时间计算的,首先根据上传时间排序,然后时间差分(每条记录的上传时间减去上一记录的上传时间)。过滤时间差分间隔大于一定数值(可以灵活设置)视为掉线,当前记录的上传时间视为掉线时间,下一条记录的上传时间视为重连时间。
前端页面offline.html的代码如下:
{% extends "base.html" %}
{% block css %}
<!-- DataTables -->
<link rel="stylesheet" href="../../plugins/datatables-bs4/css/dataTables.bootstrap4.css">
{% end %}
{% block body %}
<div class="content-wrapper" data-menu="status offline">
<!-- Content Header (Page header) -->
<section class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1>掉线记录</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="#">状态</a></li>
<li class="breadcrumb-item active">掉线记录</li>
</ol>
</div>
</div>
</div><!-- /.container-fluid -->
</section>
<!-- Main content -->
<section class="content">
<div class="row">
<div class="col-12">
<!-- /.card -->
<div class="row" style="width: 450px;">
<div class="col-3">
<label>掉线时间间隔</label>
</div>
<div class="col-7">
<select class="form-control select2" style="width: 100%;" id="selectMinutes">
<option {% if minutes==16 %} selected {% else %}{% end %} value="16">15分钟</option>
<option {% if minutes==31 %} selected {% else %}{% end %} value="31">半小时</option>
<option {% if minutes==61 %} selected {% else %}{% end %} value="61">1小时</option>
<option {% if minutes==121 %} selected {% else %}{% end %} value="121">2小时</option>
<option {% if minutes==181 %} selected {% else %}{% end %} value="181">3小时</option>
<option {% if minutes==361 %} selected {% else %}{% end %} value="361">6小时</option>
<option {% if minutes==721 %} selected {% else %}{% end %} value="721">12小时</option>
<option {% if minutes==1441 %} selected {% else %}{% end %} value="1441">1天</option>
</select>
</div>
<div class="col-2">
<button class="btn btn-navbar" type="button" id="btnMinutes">
<i class="fas fa-search"></i>
</button>
</div>
</div>
{%if ids==[] %}
<div class="card">
<div class="card-header">
<h3 class="card-title">掉线记录</h3>
</div>
<!-- /.card-header -->
<div class="card-body">
<table id="table" class="table table-bordered table-striped" data-filter-control="true" data-show-search-clear-button="true">
<thead>
<tr>
<th>设备ID</th>
<th>掉线时间</th>
<th>重连时间</th>
<th>掉线时长</th>
</tr>
</thead>
<tbody>
{%for i in range(len(df0)) %}
{%set row=df0.iloc[i] %}
<tr>
<td>{{row['DevID']}}</td>
<td>{{row['start']}}</td>
<td>{{row['end']}}</td>
<td>{{str(row['end']-row['start'])}}</td>
</tr>
{%end%}
</tbody>
<tfoot>
<tr>
<th>设备ID</th>
<th>掉线时间</th>
<th>重连时间</th>
<th>掉线时长</th>
</tr>
</tfoot>
</table>
</div>
<!-- /.card-body -->
</div>
{%else%}
<div class="card-body">
<h4>掉线记录</h4>
{%set ts=list(df0.groupby("DevID")) %}
<ul class="nav nav-tabs" id="custom-content-below-tab" role="tablist">
{%for k,(i,j) in enumerate(ts) %}
<li class="nav-item">
<a class="nav-link {%if k==0%}active{%else%}{%end%}" id="custom-content-below-{{i}}-tab" data-toggle="pill" href="#custom-content-below-{{i}}" role="tab" aria-controls="custom-content-below-{{i}}" aria-selected="true">{{i}}</a>
</li>
{%end%}
</ul>
<div class="tab-content" id="custom-content-below-tabContent">
{%for k,(i,j) in enumerate(ts) %}
<div class="tab-pane fade {%if k==0%}show active{%else%}{%end%}" id="custom-content-below-{{i}}" role="tabpanel" aria-labelledby="custom-content-below-{{i}}-tab">
<table id="table" class="table table-bordered table-striped" data-filter-control="true" data-show-search-clear-button="true">
<thead>
<tr>
<th>设备ID</th>
<th>掉线时间</th>
<th>重连时间</th>
<th>掉线时长</th>
</tr>
</thead>
<tbody>
{%for i in range(len(j)) %}
{%set row=j.iloc[i] %}
<tr>
<td>{{row['DevID']}}</td>
<td>{{row['start']}}</td>
<td>{{row['end']}}</td>
<td>{{str(row['end']-row['start'])}}</td>
</tr>
{%end%}
</tbody>
<tfoot>
<tr>
<th>设备ID</th>
<th>掉线时间</th>
<th>重连时间</th>
<th>掉线时长</th>
</tr>
</tfoot>
</table>
</div>
{%end%}
</div>
</div>
{%end%}
<!-- /.card -->
</div>
<!-- /.col -->
</div>
<div class="row" {%if df0.empty %} style="display: none;" {%end%}>
<div class="col-md-12">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title">设备分布</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i>
</button>
<button type="button" class="btn btn-tool" data-card-widget="remove"><i class="fas fa-times"></i></button>
</div>
</div>
<div class="card-body">
<div class="chart">
<canvas id="barChart1" style="height:230px; min-height:230px"></canvas>
</div>
</div>
<!-- /.card-body -->
</div>
</div>
</div>
<div class="row" {%if df0.empty %} style="display: none;" {%end%}>
<div class="col-md-12">
<div class="card card-success">
<div class="card-header">
<h3 class="card-title">小时分布</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i>
</button>
<button type="button" class="btn btn-tool" data-card-widget="remove"><i class="fas fa-times"></i></button>
</div>
</div>
<div class="card-body">
<div class="chart">
<canvas id="barChart2" style="height:230px; min-height:230px"></canvas>
</div>
</div>
<!-- /.card-body -->
</div>
</div>
</div>
<div class="row" {%if df0.empty %} style="display: none;" {%end%}>
<div class="col-md-12">
<div class="card card-primary">
<div class="card-header">
<h3 class="card-title">日期分布</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i>
</button>
<button type="button" class="btn btn-tool" data-card-widget="remove"><i class="fas fa-times"></i></button>
</div>
</div>
<div class="card-body">
<div class="chart">
<canvas id="barChart3" style="height:230px; min-height:230px"></canvas>
</div>
</div>
<!-- /.card-body -->
</div>
</div>
</div>
<!-- /.row -->
</section>
<!-- /.content -->
</div>
{% from pandas import date_range %}
{%set hours=list(range(24)) %}
{% if not df0.empty %}
{%set df00=df0.reset_index(drop=True).set_index('start').sort_index() %}
{%set start=df00.index[0].strftime('%Y-%m-%d') %}
{%set end=df00.index[-1].strftime('%Y-%m-%d') %}
{%set dates=date_range(start,end).astype('S16').values.tolist() %}
{%set g1=df00.groupby("DevID")['DevID'].count().sort_values(ascending=False)[:20] %}
{%set g2=df00.groupby(lambda x:int(x.strftime('%H')))['DevID'].count().sort_values(ascending=False) %}
{%set g3=df00.groupby(lambda x:x.strftime('%Y-%m-%d'))['DevID'].count().sort_values(ascending=False) %}
<input id="barChartLabels1" type="hidden" value="{%raw g1.index.to_list() %}">
<input id="barChartValues1" type="hidden" value="{% raw g1.values.tolist() %}">
<input id="barChartLabels2" type="hidden" value="{%raw hours %}">
<input id="barChartValues2" type="hidden" value="{% raw list(map(lambda x:g2.get(x,0),hours)) %}">
<input id="barChartLabels3" type="hidden" value="{%raw dates %}">
<input id="barChartValues3" type="hidden" value="{% raw list(map(lambda x:g3.get(x,0),dates)) %}">
{% end %}
{% end %}
{% block script %}
<!-- DataTables -->
<script src="../../plugins/datatables/jquery.dataTables.js"></script>
<script src="../../plugins/datatables-bs4/js/dataTables.bootstrap4.js"></script>
<script src="static/js/offline.js"></script>
{% end %}
前端页面对应的offline.js的代码如下:
$(function () {
$('.table').DataTable({
"paging": true,
"lengthChange": true,
"searching": true,
"ordering": true,
"info": true,
"autoWidth": false,
});
var baseUrl = document.location.pathname;
$('#btnMinutes').click(function () {
var minutes = $('#selectMinutes').val();
var ids = $('#selectNames').val();
if (ids.length > 0) {
document.location = baseUrl + "?ids=" + ids.toString() + "&minutes=" + minutes;
} else {
document.location = baseUrl + "?minutes=" + minutes;
}
});
var barChartOptions = {
responsive: true,
legend: {
display: false
},
maintainAspectRatio: false,
datasetFill: false
}
var barChartData1 = {
labels: eval($("#barChartLabels1").val()),
datasets: [
{
label: '设备分布',
backgroundColor: 'rgba(188, 60, 129, 0.9)',
borderColor: 'rgba(60,141,188,0.8)',
pointRadius: false,
pointColor: '#3b8bba',
pointStrokeColor: 'rgba(60,141,188,1)',
pointHighlightFill: '#fff',
pointHighlightStroke: 'rgba(60,141,188,1)',
data: eval($("#barChartValues1").val())
}
]
}
var barChartCanvas1 = $('#barChart1').get(0).getContext('2d')
var barChart1 = new Chart(barChartCanvas1, {
type: 'bar',
data: barChartData1,
options: barChartOptions
})
var barChartData2 = {
labels: eval($("#barChartLabels2").val()),
datasets: [
{
label: '小时分布',
backgroundColor: 'rgb(138, 26, 221)',
borderColor: 'rgba(210, 214, 222, 1)',
pointRadius: false,
pointColor: 'rgba(210, 214, 222, 1)',
pointStrokeColor: '#c1c7d1',
pointHighlightFill: '#fff',
pointHighlightStroke: 'rgba(220,220,220,1)',
data: eval($("#barChartValues2").val())
}
]
}
var barChartCanvas2 = $('#barChart2').get(0).getContext('2d')
var barChart2 = new Chart(barChartCanvas2, {
type: 'bar',
data: barChartData2,
options: barChartOptions
})
var barChartData3 = {
labels: eval($("#barChartLabels3").val()),
datasets: [
{
label: '日期分布',
backgroundColor: 'rgba(33, 219, 33, 0.9)',
borderColor: 'rgba(60,141,188,0.8)',
pointRadius: false,
pointColor: '#3b8bba',
pointStrokeColor: 'rgba(60,141,188,1)',
pointHighlightFill: '#fff',
pointHighlightStroke: 'rgba(60,141,188,1)',
data: eval($("#barChartValues3").val())
}
]
}
var barChartCanvas3 = $('#barChart3').get(0).getContext('2d')
var barChart3 = new Chart(barChartCanvas3, {
type: 'bar',
data: barChartData3,
options: barChartOptions
})
});
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。