AdvisorServer/html/monitor.html
2025-04-30 10:07:11 +08:00

332 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link href="https://cdn.staticfile.org/element-ui/2.15.14/theme-chalk/index.min.css" rel="stylesheet">
<title>Interface Monitor</title>
<script src="https://cdn.staticfile.org/vue/2.7.14/vue.min.js"></script>
<script src="https://cdn.staticfile.org/blueimp-md5/2.19.0/js/md5.min.js"></script>
<script src="https://cdn.staticfile.org/axios/1.6.5/axios.js"></script>
<script src="https://cdn.staticfile.org/element-ui/2.15.14/index.js"></script>
<script src="https://cdn.staticfile.net/dayjs/1.11.10/dayjs.min.js"></script>
<script src="https://cdn.staticfile.net/echarts/5.4.3/echarts.min.js"></script>
<style>
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 0;
}
.el-form-item {
display: flex;
height: 50px;
width: 100%;
align-items: center;
justify-content: flex-start;
}
.el-form-item__content {
margin-left: 6px !important;
}
.resu {
margin-left: 360px;
width: 1152px;
min-height: 700px;
}
.line {
width: 1152px;
height: 300px;
}
</style>
</head>
<body>
<div id="app">
<div style="width:320px; position: fixed; padding: 20px 0 0 30px;">
<el-form label-width="80px">
<el-form-item label="Host:">
<div style="width: 108%;">
<el-select @change="init()" placeholder="请选择" v-model="query.host">
<el-option :key="item" :label="item" :value="item" v-for="item in data.host"></el-option>
</el-select>
</div>
</el-form-item>
<el-form-item label="开始时间:">
<el-date-picker @change="init()" placeholder="选择开始时间" type="datetime" v-model="query.startTime">
</el-date-picker>
</el-form-item>
<el-form-item label="结束时间:">
<el-date-picker @change="init()" placeholder="选择结束时间" type="datetime" v-model="query.endTime">
</el-date-picker>
</el-form-item>
<el-form-item label="IP:">
<el-select placeholder="请选择" v-model="query.ip">
<el-option :key="item" :label="item" :value="item" @change="init()" v-for="item in data.ip">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="接口:">
<el-select @change="init(false)" placeholder="请选择" v-model="query.name">
<el-option :key="item" :label="item" :value="item" v-for="item in data.name">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="分组方式:">
<el-radio :label="item" @change="groupData()" v-for="item in data.groupBy" v-model="query.groupBy">{{ item }}</el-radio>
</el-form-item>
<el-form-item>
<div style="margin-left: 20%; display: flex;">
<el-button @click="listData()" type="primary">查询曲线</el-button>
<el-button @click="groupData()" type="primary">查询分组</el-button>
</div>
</el-form-item>
</el-form>
</div>
<div class="resu">
<div id="line" v-show="data.showLine">
<div class="line" id="total"></div>
<div class="line" id="average"></div>
<div class="line" id="failure"></div>
<div class="line" id="timeout"></div>
</div>
<div id="table" v-show="data.showTable">
<el-table :data="data.groupData" :default-sort = "{prop: 'total', order: 'descending'}" @sort-change="sortChange" height="700" >
<el-table-column label="IP" prop="ip" v-if="query.groupBy === 'ip'" width="120"></el-table-column>
<el-table-column label="接口" prop="interfaceName" v-if="query.groupBy === 'name'" width="230"></el-table-column>
<el-table-column label="数量" prop="total" width="78" sortable='custom'></el-table-column>
<el-table-column label="失败" prop="failure" width="78" sortable='custom'></el-table-column>
<el-table-column label="平均" prop="averageTime" width="78" sortable='custom'></el-table-column>
<el-table-column label="最大" prop="maxTime" width="78" sortable='custom'></el-table-column>
<el-table-column label="最小" prop="minTime" width="78" sortable='custom'></el-table-column>
<el-table-column label="10ms" prop="over10ms" width="80" sortable='custom'></el-table-column>
<el-table-column label="50ms" prop="over50ms" width="80" sortable='custom'></el-table-column>
<el-table-column label="100ms" prop="over100ms" width="88" sortable='custom'></el-table-column>
<el-table-column label="500ms" prop="over500ms" width="88" sortable='custom'></el-table-column>
<el-table-column label="1000ms" prop="over1000ms" width="96" sortable='custom'></el-table-column>
<el-table-column label="5000ms" prop="over5000ms" width="96" sortable='custom'></el-table-column>
</el-table>
</div>
</div>
</div>
<script>
const HttpReq = axios.create({
// baseURL, // api的base_url
timeout: 10000, // 请求超时时间,
method: "post"
});
HttpReq.interceptors.request.use(config => {
config.data = config.data || {}
config.data.ticket = md5(`hello_syzb_${dayjs().format('YYYYMMDD')}`)
if(config.data.ip == '全部'){
config.data.ip = ''
}
if(config.data.name == '全部'){
config.data.name = ''
}
return config;
}, error => {
return Promise.reject(error);
});
HttpReq.interceptors.response.use(resp => {
if (resp.code) {
console.log({
title: "HttpRequestError-" + resp.code,
content: resp.message,
});
}
return resp.data.data;
})
function post(host, url, data) {
if (!host) {
return;
}
const targetUrl = (host + url)
return HttpReq({
url: targetUrl,
data,
})
}
function fillTimeData(startTime, endTime, data) {
const result = [];
const timeMap = new Map();
// 建立已有数据的映射key 是时间字符串
data.forEach(item => {
timeMap.set(item.time, item);
});
let current = dayjs(startTime).second(0);
console.log(current.minute());
while (current.minute() % 5 !== 0) {
current = current.add(1, 'minute');
}
const end = dayjs(endTime);
console.log(current.isSameOrBefore);
while (current.isBefore(end) || current.isSame(end)) {
const timeStr = current.format('YYYY-MM-DD HH:mm:ss');
if (timeMap.has(timeStr)) {
result.push(timeMap.get(timeStr));
} else {
result.push({
averageTime: 0,
failure: 0,
interfaceName: null,
ip: null,
maxTime: 0,
minTime: 0,
over1000ms: 0,
over100ms: 0,
over10ms: 0,
over5000ms: 0,
over500ms: 0,
over50ms: 0,
time: timeStr,
total: 0
});
}
current = current.add(5, 'minute');
}
return result;
}
function drawLine(data, title, div, field, filter) {
if (data && data.length) {
const xyData = data.map(v => [v.time, v[field]]);
const chart = echarts.init(document.getElementById(div));
chart.setOption({
title: {
text: title
},
xAxis: {
type: 'time',
// data: xDate
},
yAxis: {
type: 'value'
},
tooltip: {
trigger: 'axis'
},
series: [
{
type: 'line',
data: xyData,
showSymbol: false,
lineStyle: {
color: '#409eff' // 设置折线的颜色为红色
},
}
]
})
}
}
const API = {
listIP: function (host, data) {
return post(host, '/admin/monitor/listIP', data);
},
listInterface: function (host, data) {
return post(host, '/admin/monitor/listInterface', data);
},
listData: function (host, data) {
return post(host, '/admin/monitor/listData', data);
},
groupData: function (host, data) {
return post(host, '/admin/monitor/groupData', data);
},
}
new Vue({
el: '#app',
data() {
return {
query: {
host: "https://do.tgsys.sztg.com",
// startTime: dayjs().format('YYYY-MM-DD 00:00:00'),
// endTime: dayjs().add(1, 'day').format('YYYY-MM-DD 00:00:00'),
startTime: dayjs().format('YYYY-MM-DD 00:00:00'),
endTime: dayjs().add(1, 'day').format('YYYY-MM-DD 00:00:00'),
ip: "",
name: "",
groupBy: "name",
orderBy: "",
},
data: {
host: ["https://do.tgsys.sztg.com", "http://8.138.144.54:8080", "http://127.0.0.1:8080"],
ip: [],
name: [],
groupBy: ["name", "ip"],
groupData: [],
showLine: false,
showTable: false,
},
monitor: [],
interval: null,
};
},
methods: {
async init(loadName = true) {
const ip = await API.listIP(this.query.host, this.query)
if (ip) {
ip.unshift("全部")
this.data.ip = ip;
this.query.ip = ip[0];
}
if (loadName) {
const name = await API.listInterface(this.query.host, this.query)
if(name){
name.unshift("全部")
this.data.name = name;
this.query.name = name[0];
}
}
},
async listData() {
let data = await API.listData(this.query.host, this.query);
// console.log('before', data);
data = fillTimeData(this.query.startTime, this.query.endTime, data);
// console.log('after', data);
drawLine(data, '总流量', 'total', 'total');
drawLine(data, '平均耗时', 'average', 'averageTime');
drawLine(data, '失败流量', 'failure', 'failure');
drawLine(data, '超时流量', 'timeout', 'over5000ms');
this.data.showLine = true;
this.data.showTable = false;
},
async groupData() {
let groupData = await API.groupData(this.query.host, this.query);
groupData = groupData.filter(data => data.interfaceName && data.interfaceName.indexOf('/admin/monitor') === -1);
this.data.groupData = groupData;
this.data.showLine = false;
this.data.showTable = true;
},
async sortChange({column, prop, order}) {
console.log('sortChange', column, prop, order);
this.query.orderBy = prop;
this.query.order = order;
console.log(this.query);
this.groupData();
}
},
async mounted() {
this.init();
},
watch: {
},
});
</script>
</body>
</html>