(function () {
|
"use strict";
|
|
function nowDate() {
|
return new Date();
|
}
|
|
function minutesAgo(minutes) {
|
return new Date(Date.now() - minutes * 60 * 1000);
|
}
|
|
function createEmptyOverviewSummary() {
|
return {
|
totalDevices: 0,
|
okDevices: 0,
|
unstableDevices: 0,
|
offlineDevices: 0,
|
noDataDevices: 0,
|
avgLatencyMs: null,
|
maxLatencyMs: null
|
};
|
}
|
|
function createEmptyDetailSummary() {
|
return {
|
totalSamples: 0,
|
successSamples: 0,
|
failSamples: 0,
|
successRate: 0,
|
avgLatencyMs: null,
|
minLatencyMs: null,
|
maxLatencyMs: null,
|
packetSize: -1,
|
latestStatus: "",
|
latestTimeLabel: ""
|
};
|
}
|
|
function createEmptySamplingConfig() {
|
return {
|
intervalMs: 1000,
|
timeoutMs: 800,
|
probeCount: 3,
|
packetSize: -1
|
};
|
}
|
|
new Vue({
|
el: "#app",
|
data: function () {
|
return {
|
overviewLoading: false,
|
detailLoading: false,
|
devices: [],
|
availableDays: [],
|
samplingConfig: createEmptySamplingConfig(),
|
overviewSummary: createEmptyOverviewSummary(),
|
overviewRows: [],
|
overviewFilters: {
|
deviceType: "",
|
keyword: ""
|
},
|
detailFilters: {
|
deviceKey: "",
|
range: [minutesAgo(30), nowDate()]
|
},
|
detailSummary: createEmptyDetailSummary(),
|
series: [],
|
alerts: [],
|
charts: {
|
latency: null,
|
availability: null
|
},
|
resizeHandler: null
|
};
|
},
|
computed: {
|
currentDevice: function () {
|
var key = this.detailFilters.deviceKey;
|
if (!key) {
|
return null;
|
}
|
for (var i = 0; i < this.devices.length; i++) {
|
var item = this.devices[i];
|
if ((item.deviceType + "#" + item.deviceNo) === key) {
|
return item;
|
}
|
}
|
for (var j = 0; j < this.overviewRows.length; j++) {
|
var row = this.overviewRows[j];
|
if ((row.deviceType + "#" + row.deviceNo) === key) {
|
return row;
|
}
|
}
|
return null;
|
},
|
filteredOverviewRows: function () {
|
var type = this.overviewFilters.deviceType;
|
var keyword = (this.overviewFilters.keyword || "").toLowerCase();
|
return this.overviewRows.filter(function (item) {
|
if (type && item.deviceType !== type) {
|
return false;
|
}
|
if (!keyword) {
|
return true;
|
}
|
var deviceText = (item.deviceType + "-" + item.deviceNo).toLowerCase();
|
var ipText = (item.ip || "").toLowerCase();
|
return deviceText.indexOf(keyword) >= 0 || ipText.indexOf(keyword) >= 0;
|
});
|
},
|
samplingConfigText: function () {
|
var config = this.samplingConfig || createEmptySamplingConfig();
|
return "采样 " + config.intervalMs + " ms / 超时 " + config.timeoutMs + " ms / 每样本 " + config.probeCount + " 次";
|
}
|
},
|
mounted: function () {
|
var self = this;
|
this.$nextTick(function () {
|
self.loadOptions();
|
self.loadOverview();
|
self.resizeHandler = function () {
|
self.resizeCharts();
|
};
|
window.addEventListener("resize", self.resizeHandler);
|
});
|
},
|
beforeDestroy: function () {
|
if (this.resizeHandler) {
|
window.removeEventListener("resize", this.resizeHandler);
|
}
|
this.disposeCharts();
|
},
|
methods: {
|
loadOptions: function () {
|
var self = this;
|
$.ajax({
|
url: baseUrl + "/devicePingLog/options/auth",
|
headers: { token: localStorage.getItem("token") },
|
method: "GET",
|
success: function (res) {
|
if (res && res.code === 200) {
|
var data = res.data || {};
|
self.devices = data.devices || [];
|
self.availableDays = data.days || [];
|
self.samplingConfig = Object.assign(createEmptySamplingConfig(), data.samplingConfig || {});
|
return;
|
}
|
self.$message.error((res && res.msg) || "设备配置加载失败");
|
},
|
error: function () {
|
self.$message.error("设备配置加载失败");
|
}
|
});
|
},
|
loadOverview: function () {
|
var self = this;
|
this.overviewLoading = true;
|
$.ajax({
|
url: baseUrl + "/devicePingLog/overview/auth",
|
headers: { token: localStorage.getItem("token") },
|
method: "GET",
|
success: function (res) {
|
if (res && res.code === 200) {
|
var data = res.data || {};
|
self.overviewSummary = Object.assign(createEmptyOverviewSummary(), data.summary || {});
|
self.overviewRows = data.devices || [];
|
return;
|
}
|
self.overviewSummary = createEmptyOverviewSummary();
|
self.overviewRows = [];
|
self.$message.error((res && res.msg) || "总览数据加载失败");
|
},
|
error: function () {
|
self.overviewSummary = createEmptyOverviewSummary();
|
self.overviewRows = [];
|
self.$message.error("总览数据加载失败");
|
},
|
complete: function () {
|
self.overviewLoading = false;
|
}
|
});
|
},
|
openDetail: function (row) {
|
var self = this;
|
if (!row) {
|
return;
|
}
|
this.detailFilters.deviceKey = row.deviceType + "#" + row.deviceNo;
|
this.setQuickRange(30, false);
|
this.$nextTick(function () {
|
self.ensureCharts();
|
self.queryTrend();
|
});
|
},
|
setQuickRange: function (minutes, autoQuery) {
|
this.detailFilters.range = [minutesAgo(minutes), nowDate()];
|
if (autoQuery !== false && this.currentDevice) {
|
this.queryTrend();
|
}
|
},
|
queryTrend: function () {
|
if (!this.currentDevice) {
|
return;
|
}
|
if (!this.detailFilters.range || this.detailFilters.range.length !== 2) {
|
this.$message.warning("请选择时间范围");
|
return;
|
}
|
var parts = this.detailFilters.deviceKey.split("#");
|
if (parts.length !== 2) {
|
this.$message.warning("设备信息无效");
|
return;
|
}
|
var self = this;
|
this.detailLoading = true;
|
$.ajax({
|
url: baseUrl + "/devicePingLog/trend/auth",
|
headers: { token: localStorage.getItem("token") },
|
method: "GET",
|
data: {
|
deviceType: parts[0],
|
deviceNo: parts[1],
|
startTime: this.detailFilters.range[0].getTime(),
|
endTime: this.detailFilters.range[1].getTime()
|
},
|
success: function (res) {
|
if (res && res.code === 200) {
|
var data = res.data || {};
|
self.detailSummary = Object.assign(createEmptyDetailSummary(), data.summary || {});
|
self.series = data.series || [];
|
self.alerts = data.alerts || [];
|
self.updateCharts();
|
return;
|
}
|
self.detailSummary = createEmptyDetailSummary();
|
self.series = [];
|
self.alerts = [];
|
self.updateCharts();
|
self.$message.error((res && res.msg) || "设备详情加载失败");
|
},
|
error: function () {
|
self.detailSummary = createEmptyDetailSummary();
|
self.series = [];
|
self.alerts = [];
|
self.updateCharts();
|
self.$message.error("设备详情加载失败");
|
},
|
complete: function () {
|
self.detailLoading = false;
|
}
|
});
|
},
|
ensureCharts: function () {
|
if (this.$refs.latencyChart && !this.charts.latency) {
|
this.charts.latency = echarts.init(this.$refs.latencyChart);
|
}
|
if (this.$refs.availabilityChart && !this.charts.availability) {
|
this.charts.availability = echarts.init(this.$refs.availabilityChart);
|
}
|
},
|
disposeCharts: function () {
|
if (this.charts.latency) {
|
this.charts.latency.dispose();
|
this.charts.latency = null;
|
}
|
if (this.charts.availability) {
|
this.charts.availability.dispose();
|
this.charts.availability = null;
|
}
|
},
|
resizeCharts: function () {
|
if (this.charts.latency) {
|
this.charts.latency.resize();
|
}
|
if (this.charts.availability) {
|
this.charts.availability.resize();
|
}
|
},
|
updateCharts: function () {
|
this.ensureCharts();
|
if (!this.charts.latency || !this.charts.availability) {
|
return;
|
}
|
if (!this.series.length) {
|
this.charts.latency.clear();
|
this.charts.availability.clear();
|
return;
|
}
|
this.charts.latency.setOption(this.buildLatencyOption(), true);
|
this.charts.availability.setOption(this.buildAvailabilityOption(), true);
|
this.resizeCharts();
|
},
|
buildLatencyOption: function () {
|
var xAxisData = this.series.map(function (item) { return item.timeLabel; });
|
return {
|
color: ["#1f6fb2", "#2fa38e", "#f59a4a"],
|
tooltip: {
|
trigger: "axis"
|
},
|
legend: {
|
top: 0,
|
textStyle: { color: "#5e738a" }
|
},
|
grid: {
|
left: 54,
|
right: 18,
|
top: 40,
|
bottom: 54
|
},
|
xAxis: {
|
type: "category",
|
data: xAxisData,
|
boundaryGap: false,
|
axisLine: { lineStyle: { color: "#d5dfeb" } },
|
axisLabel: {
|
color: "#74879a",
|
formatter: function (value) {
|
return value.slice(11);
|
}
|
}
|
},
|
yAxis: {
|
type: "value",
|
name: "ms",
|
splitLine: { lineStyle: { color: "#edf2f7" } },
|
axisLine: { show: false },
|
axisTick: { show: false },
|
axisLabel: { color: "#7f92a5" }
|
},
|
dataZoom: [{
|
type: "inside"
|
}, {
|
type: "slider",
|
height: 18,
|
bottom: 10
|
}],
|
series: [{
|
name: "平均",
|
type: "line",
|
showSymbol: false,
|
sampling: "lttb",
|
data: this.series.map(function (item) { return item.avgLatencyMs; }),
|
lineStyle: { width: 2 }
|
}, {
|
name: "最小",
|
type: "line",
|
showSymbol: false,
|
sampling: "lttb",
|
data: this.series.map(function (item) { return item.minLatencyMs; }),
|
lineStyle: { width: 1.5 }
|
}, {
|
name: "最大",
|
type: "line",
|
showSymbol: false,
|
sampling: "lttb",
|
data: this.series.map(function (item) { return item.maxLatencyMs; }),
|
lineStyle: { width: 1.5, type: "dashed" }
|
}]
|
};
|
},
|
buildAvailabilityOption: function () {
|
var xAxisData = this.series.map(function (item) { return item.timeLabel; });
|
return {
|
color: ["#de5c5c", "#2fa38e"],
|
tooltip: {
|
trigger: "axis"
|
},
|
legend: {
|
top: 0,
|
textStyle: { color: "#5e738a" }
|
},
|
grid: {
|
left: 48,
|
right: 50,
|
top: 40,
|
bottom: 54
|
},
|
xAxis: {
|
type: "category",
|
data: xAxisData,
|
axisLine: { lineStyle: { color: "#d5dfeb" } },
|
axisLabel: {
|
color: "#74879a",
|
formatter: function (value) {
|
return value.slice(11);
|
}
|
}
|
},
|
yAxis: [{
|
type: "value",
|
name: "失败",
|
splitLine: { lineStyle: { color: "#edf2f7" } },
|
axisLine: { show: false },
|
axisTick: { show: false },
|
axisLabel: { color: "#7f92a5" }
|
}, {
|
type: "value",
|
name: "成功率%",
|
min: 0,
|
max: 100,
|
splitLine: { show: false },
|
axisLine: { show: false },
|
axisTick: { show: false },
|
axisLabel: { color: "#7f92a5" }
|
}],
|
dataZoom: [{
|
type: "inside"
|
}, {
|
type: "slider",
|
height: 18,
|
bottom: 10
|
}],
|
series: [{
|
name: "失败次数",
|
type: "bar",
|
yAxisIndex: 0,
|
barMaxWidth: 18,
|
data: this.series.map(function (item) { return item.failProbeCount; }),
|
itemStyle: {
|
borderRadius: [6, 6, 0, 0]
|
}
|
}, {
|
name: "成功率",
|
type: "line",
|
yAxisIndex: 1,
|
showSymbol: false,
|
sampling: "lttb",
|
data: this.series.map(function (item) { return item.successRate; }),
|
lineStyle: { width: 2 }
|
}]
|
};
|
},
|
statusClass: function (status) {
|
if (status === "OK") {
|
return "ok";
|
}
|
if (status === "UNSTABLE") {
|
return "unstable";
|
}
|
if (status === "NO_DATA") {
|
return "nodata";
|
}
|
return "offline";
|
},
|
formatLatency: function (value) {
|
if (value === null || value === undefined || value === "") {
|
return "--";
|
}
|
return value + " ms";
|
},
|
formatPercent: function (value) {
|
if (value === null || value === undefined || value === "") {
|
return "--";
|
}
|
return value + "%";
|
},
|
formatPacketSize: function (value) {
|
if (value === null || value === undefined || value === "" || value < 0) {
|
return "系统默认";
|
}
|
return value + " B";
|
}
|
}
|
});
|
})();
|