1.4.5.2
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
<first-menu>
|
||||
<menu-item code="index" href=".">用量统计</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item code="setting" href=".setting">设置</menu-item>
|
||||
</first-menu>
|
||||
13
EdgeAdmin/web/views/@default/servers/traffic-stats/index.css
Normal file
13
EdgeAdmin/web/views/@default/servers/traffic-stats/index.css
Normal file
@@ -0,0 +1,13 @@
|
||||
.grid .small {
|
||||
font-size: 0.8em !important;
|
||||
}
|
||||
.table-box {
|
||||
width: 40em;
|
||||
max-height: 40em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.chart-box {
|
||||
height: 20em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,KAAM;EACL,gBAAA;;AAGD;EACC,WAAA;EACA,gBAAA;EACA,gBAAA;;AAGD;EACC,YAAA;EACA,eAAA","file":"index.css"}
|
||||
103
EdgeAdmin/web/views/@default/servers/traffic-stats/index.html
Normal file
103
EdgeAdmin/web/views/@default/servers/traffic-stats/index.html
Normal file
@@ -0,0 +1,103 @@
|
||||
{$layout}
|
||||
{$template "/echarts"}
|
||||
{$template "menu"}
|
||||
|
||||
<div style="margin-top: 0.6em"></div>
|
||||
<form class="ui form">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<datepicker name="dayFrom" placeholder="开始日期" v-model="dayFrom" @change="changeDayFrom"></datepicker>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<datepicker name="dayTo" placeholder="结束日期" v-model="dayTo" @change="changeDayTo"></datepicker>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<user-selector :v-user-id="userId" @change="changeUser"></user-selector>
|
||||
</div>
|
||||
<div class="ui field" v-if="userId > 0">
|
||||
<span v-if="servers.length == 0" class="disabled">暂无网站</span>
|
||||
<div v-else>
|
||||
<combo-box :v-items="servers" name="serverId" @change="changeServer" :placeholder="'全部网站(' + (servers.length-1) + ')'"></combo-box>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field" v-if="userId > 0 && serverId == 0 && regions.length > 0">
|
||||
<select class="ui dropdown" name="regionId" v-model="regionId" @change="changeRegion">
|
||||
<option value="0">所有区域</option>
|
||||
<option v-for="region in regions" :value="region.id">{{region.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click.prevent="startSearch">查询</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="margin"></div>
|
||||
|
||||
<div class="ui message" v-if="isLoading">加载中...</div>
|
||||
|
||||
<columns-grid v-if="result != null">
|
||||
<div class="ui column">
|
||||
<h4>带宽峰值</h4>
|
||||
<div class="value">
|
||||
<span>{{result.maxBandwidthBitsFormat[0]}}</span>
|
||||
{{result.maxBandwidthBitsFormat[1]}}
|
||||
<br/>
|
||||
<span v-if="result.maxBandwidthTime.length > 0" class="small grey">{{result.maxBandwidthTime}}:00</span>
|
||||
<span v-else> <!-- placeholder --></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui column">
|
||||
<h4>95th带宽</h4>
|
||||
<div class="value">
|
||||
<span>{{result.bandwidth95thBitsFormat[0]}}</span>
|
||||
{{result.bandwidth95thBitsFormat[1]}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui column">
|
||||
<h4>总流量</h4>
|
||||
<div class="value">
|
||||
<span>{{result.totalTrafficBytesFormat[0]}}</span>
|
||||
{{result.totalTrafficBytesFormat[1]}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui column with-border">
|
||||
<h4>总请求数</h4>
|
||||
<div class="value"><span>{{result.totalTrafficRequests}}</span>次</div>
|
||||
</div>
|
||||
</columns-grid>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<div v-if="result != null" style="margin-top: 0.6em">
|
||||
<!-- 菜单 -->
|
||||
<first-menu >
|
||||
<menu-item :class="{active: tab == 'chart'}" @click.prevent="selectTab('chart')">图表 <i class="icon chart area small"></i></menu-item>
|
||||
<menu-item :class="{active: tab == 'table'}" @click.prevent="selectTab('table')">表格 <i class="icon table small"></i></menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item :href="'.download?dayFrom=' + dayFrom + '&dayTo=' + dayTo + '&userId=' + userId + '&serverId=' + serverId" target="_blank">下载 <i class="icon download small"></i></menu-item>
|
||||
<menu-item v-for="(r, index) in dayRanges" :class="{active: dayFrom == r.dayFrom && dayTo == r.dayTo, right: index == 0}" @click.prevent="selectDay(r.dayFrom, r.dayTo)">{{r.name}}</menu-item>
|
||||
</first-menu>
|
||||
|
||||
<!-- 表格 -->
|
||||
<div class="table-box scroll-box" v-if="result != null" v-show="tab == 'table'">
|
||||
<table class="ui table selectable celled">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>时间</th>
|
||||
<th>带宽(Mbps)</th>
|
||||
<th>带宽(Gbps)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="stat in result.bandwidthStats">
|
||||
<td>{{stat.day.substring(0, 4)}}-{{stat.day.substring(4, 6)}}-{{stat.day.substring(6)}} {{stat.time.substring(0, 2)}}:{{stat.time.substring(2)}}</td>
|
||||
<td>{{stat.mbps}}</td>
|
||||
<td>{{stat.gbps}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 图表 -->
|
||||
<div class="chart-box" id="bandwidth-chart" v-show="result != null && tab == 'chart'"></div>
|
||||
</div>
|
||||
|
||||
<p class="comment" v-if="userId == 0">请选择要查看的用户。</p>
|
||||
183
EdgeAdmin/web/views/@default/servers/traffic-stats/index.js
Normal file
183
EdgeAdmin/web/views/@default/servers/traffic-stats/index.js
Normal file
@@ -0,0 +1,183 @@
|
||||
Tea.context(function () {
|
||||
this.servers = []
|
||||
this.result = null
|
||||
this.isLoading = false
|
||||
this.regionId = 0
|
||||
this.serverId = 0
|
||||
|
||||
this.changeDayFrom = function (v) {
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(v)) {
|
||||
this.search()
|
||||
}
|
||||
}
|
||||
|
||||
this.changeDayTo = function (v) {
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(v)) {
|
||||
this.search()
|
||||
}
|
||||
}
|
||||
|
||||
this.changeUser = function (userId) {
|
||||
this.userId = userId
|
||||
this.servers = []
|
||||
this.serverId = 0
|
||||
this.regionId = 0
|
||||
this.searchUser(userId)
|
||||
}
|
||||
|
||||
this.changeServer = function (result) {
|
||||
if (result != null) {
|
||||
this.serverId = result.value
|
||||
this.search()
|
||||
}
|
||||
}
|
||||
|
||||
this.changeRegion = function () {
|
||||
this.search()
|
||||
}
|
||||
|
||||
if (this.userId > 0) {
|
||||
this.$delay(function () {
|
||||
this.searchUser(this.userId)
|
||||
})
|
||||
}
|
||||
|
||||
this.searchUser = function (userId) {
|
||||
if (userId > 0) {
|
||||
this.$post(".serverOptions")
|
||||
.params({
|
||||
userId: userId
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.servers = resp.data.servers
|
||||
})
|
||||
}
|
||||
|
||||
this.search()
|
||||
}
|
||||
|
||||
this.startSearch = function () {
|
||||
if (this.userId == 0) {
|
||||
teaweb.warn("请选择要查询的用户")
|
||||
return
|
||||
}
|
||||
this.search()
|
||||
}
|
||||
|
||||
this.search = function () {
|
||||
this.isLoading = true
|
||||
|
||||
this.result = null
|
||||
|
||||
if (this.userId == 0) {
|
||||
this.isLoading = false
|
||||
return
|
||||
}
|
||||
|
||||
this.$post("$")
|
||||
.params({
|
||||
userId: this.userId,
|
||||
serverId: this.serverId,
|
||||
regionId: this.regionId,
|
||||
dayFrom: this.dayFrom,
|
||||
dayTo: this.dayTo
|
||||
})
|
||||
.success(function (resp) {
|
||||
let totalTrafficBytesFormat = teaweb.splitFormat(teaweb.formatBytes(resp.data.totalTrafficBytes))
|
||||
let maxBandwidthBitsFormat = teaweb.splitFormat(teaweb.formatBits(resp.data.maxBandwidthBits))
|
||||
let bandwidth95thBitsFormat = teaweb.splitFormat(teaweb.formatBits(resp.data.bandwidth95thBits))
|
||||
|
||||
this.result = {
|
||||
bandwidthStats: resp.data.bandwidthStats,
|
||||
reversedBandwidthStats: resp.data.bandwidthStats.$copy().reverse(),
|
||||
maxBandwidthBitsFormat: maxBandwidthBitsFormat,
|
||||
maxBandwidthTime: resp.data.maxBandwidthTime,
|
||||
bandwidth95thBitsFormat: bandwidth95thBitsFormat,
|
||||
totalTrafficBytesFormat: totalTrafficBytesFormat,
|
||||
totalTrafficRequests: teaweb.formatCount(resp.data.totalTrafficRequests)
|
||||
}
|
||||
|
||||
this.reloadChart(resp.data.bandwidthStats, resp.data.bandwidth95thBits)
|
||||
})
|
||||
.done(function () {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* tab set
|
||||
*/
|
||||
this.tab = "chart"
|
||||
this.selectTab = function (tab) {
|
||||
this.tab = tab
|
||||
}
|
||||
|
||||
this.reloadChart = function (stats, nthBits) {
|
||||
let box = document.getElementById("bandwidth-chart")
|
||||
if (box == null || box.offsetHeight <= 0) {
|
||||
this.$delay(function () {
|
||||
this.reloadChart(stats, nthBits)
|
||||
}, 100)
|
||||
return
|
||||
}
|
||||
|
||||
let axis = teaweb.bitsAxis(stats, function (stat) {
|
||||
return stat.bits
|
||||
})
|
||||
|
||||
teaweb.renderLineChart({
|
||||
id: "bandwidth-chart",
|
||||
values: stats,
|
||||
axis: axis,
|
||||
x: function (stat) {
|
||||
return stat.day.substring(0, 4) + "-" + stat.day.substring(4, 6) + "-" + stat.day.substring(6) + " " + stat.time.substring(0, 2) + ":" + stat.time.substring(2)
|
||||
},
|
||||
xColor: function (text) {
|
||||
let currentTime = new Date().format("Y-m-d H:i")
|
||||
if (currentTime < text) {
|
||||
return "#cccccc"
|
||||
}
|
||||
return "default"
|
||||
},
|
||||
value: function (stat) {
|
||||
if (typeof(stat.isNull) == "boolean" && stat.isNull) {
|
||||
return null
|
||||
}
|
||||
return stat.bits / axis.divider
|
||||
},
|
||||
tooltip: function (args, values) {
|
||||
if (args.componentType == "markLine") {
|
||||
return args.name
|
||||
}
|
||||
|
||||
let index = args.dataIndex
|
||||
let stat = values[index]
|
||||
|
||||
return stat.day.substring(0, 4) + "-" + stat.day.substring(4, 6) + "-" + stat.day.substring(6) + " " + stat.time.substring(0, 2) + ":" + stat.time.substring(2) + "<br/>带宽:" + teaweb.formatBits(values[index].bits)
|
||||
},
|
||||
left: 30,
|
||||
right: 40,
|
||||
cache: false,
|
||||
markLine: {
|
||||
precision: 4,
|
||||
data: [{
|
||||
name: this.percentile + "th",
|
||||
yAxis: nthBits/axis.divider
|
||||
}],
|
||||
symbol: "none",
|
||||
lineStyle: {
|
||||
color: teaweb.chartColor("red")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* select day
|
||||
*/
|
||||
this.selectDay = function (dayFrom, dayTo) {
|
||||
this.dayFrom = dayFrom
|
||||
this.dayTo = dayTo
|
||||
this.search()
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
.grid .small {
|
||||
font-size: 0.8em!important;
|
||||
}
|
||||
|
||||
.table-box {
|
||||
width: 40em;
|
||||
max-height: 40em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.chart-box {
|
||||
height: 20em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<form class="ui form" data-tea-success="success" data-tea-action="$">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">带宽百分位</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" maxlength="3" size="3" style="width: 4em" name="bandwidthPercentile" v-model="config.bandwidthPercentile"/>
|
||||
<span class="ui label">th</span>
|
||||
</div>
|
||||
<p class="comment">取值在1-100之间。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>默认日期范围</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="defaultBandwidthDateRange" v-model="config.defaultBandwidthDateRange">
|
||||
<option v-for="dateRange in dateRanges" :value="dateRange.code">{{dateRange.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>带宽算法</td>
|
||||
<td>
|
||||
<select class="ui dropdown auto-width" name="bandwidthAlgo" v-model="config.bandwidthAlgo">
|
||||
<option value="secondly">峰值带宽</option>
|
||||
<option value="avg">平均带宽</option>
|
||||
</select>
|
||||
<p class="comment" v-if="config.bandwidthAlgo == 'secondly'">按在计时时间段内(5分钟)最高带宽峰值计算,比如5分钟内最高的某个时间点带宽为100Mbps,那么就认为此时间段内的峰值带宽为100Mbps。修改此选项会同时影响到带宽计费。</p>
|
||||
<p class="comment" v-if="config.bandwidthAlgo == 'avg'">按在计时时间段内(5分钟)平均带宽计算,即此时间段内的总流量除以时间段的秒数,比如5分钟(300秒)内总流量600MiB,那么带宽即为<code-label>600MiB * 8bit/300s = 16Mbps</code-label>;通常平均带宽算法要比峰值带宽要少很多。修改此选项会同时影响到带宽计费。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
Reference in New Issue
Block a user