网络监控添加最近时间筛选功能

This commit is contained in:
hi2hi 2024-12-12 16:10:53 +00:00
parent d134e7f2a3
commit 7e416a6f16
2 changed files with 165 additions and 8 deletions

View File

@ -18,6 +18,7 @@ import {
const defaultState = () => ({ const defaultState = () => ({
init: false, init: false,
serverTime: 0,
serverGroup: [], serverGroup: [],
serverList: [], serverList: [],
serverCount: { serverCount: {
@ -50,6 +51,9 @@ let firstSetServers = true;
const store = createStore({ const store = createStore({
state: defaultState(), state: defaultState(),
mutations: { mutations: {
SET_SERVER_TIME(state, time) {
state.serverTime = time;
},
SET_SERVER_GROUP(state, serverGroup) { SET_SERVER_GROUP(state, serverGroup) {
state.serverGroup = serverGroup; state.serverGroup = serverGroup;
}, },
@ -153,6 +157,9 @@ const store = createStore({
}) { }) {
msg.on('servers', (res) => { msg.on('servers', (res) => {
if (res) { if (res) {
if (res.now) {
commit('SET_SERVER_TIME', res.now);
}
const servers = res.servers?.map?.((i) => { const servers = res.servers?.map?.((i) => {
const item = { const item = {
...i, ...i,

View File

@ -16,6 +16,7 @@
title="是否自动刷新" title="是否自动刷新"
@click="switchRefresh" @click="switchRefresh"
> >
<span class="label-text">刷新</span>
<div <div
class="switch-box" class="switch-box"
:class="{ :class="{
@ -24,13 +25,13 @@
> >
<span class="switch-dot" /> <span class="switch-dot" />
</div> </div>
<span class="label-text">刷新</span>
</div> </div>
<div <div
class="peak-shaving-group" class="peak-shaving-group"
title="过滤太高或太低的数据" title="过滤太高或太低的数据"
@click="switchPeakShaving" @click="switchPeakShaving"
> >
<span class="label-text">削峰</span>
<div <div
class="switch-box" class="switch-box"
:class="{ :class="{
@ -39,7 +40,28 @@
> >
<span class="switch-dot" /> <span class="switch-dot" />
</div> </div>
<span class="label-text">削峰</span> </div>
<div class="last-update-time-group">
<span class="last-update-time-label">
最近
</span>
<div class="minutes">
<div
v-for="minuteItem in minutes"
:key="minuteItem.value"
class="minute-item"
:class="{
active: minuteItem.value === minute,
}"
@click="toggleMinute(minuteItem.value)"
>
<span>{{ minuteItem.label }}</span>
</div>
<div
class="active-arrow"
:style="minuteActiveArrowStyle"
/>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -97,6 +119,7 @@ import {
onMounted, onMounted,
onUnmounted, onUnmounted,
} from 'vue'; } from 'vue';
import { useStore } from 'vuex';
import config from '@/config'; import config from '@/config';
import request from '@/utils/request'; import request from '@/utils/request';
import validate from '@/utils/validate'; import validate from '@/utils/validate';
@ -115,12 +138,46 @@ const props = defineProps({
}, },
}); });
const store = useStore();
const minute = ref(1440);
const minutes = [{
label: '30分钟',
value: 30,
}, {
label: '1小时',
value: 60,
}, {
label: '3小时',
value: 180,
}, {
label: '6小时',
value: 360,
}, {
label: '12小时',
value: 720,
}, {
label: '24小时',
value: 1440,
}];
const refreshData = ref(true); const refreshData = ref(true);
const peakShaving = ref(false); const peakShaving = ref(false);
const showCates = ref({}); const showCates = ref({});
const monitorData = ref([]); const monitorData = ref([]);
const accpetShowTime = computed(() => {
const now = store.state.serverTime || Date.now();
return now - (minute.value * 60 * 1000);
});
const minuteActiveArrowStyle = computed(() => {
const index = minutes.findIndex((i) => i.value === minute.value);
return {
left: `calc(${index} * var(--minute-item-width))`,
};
});
const monitorChartData = computed(() => { const monitorChartData = computed(() => {
/** /**
* 处理监控数据以生成分类的平均延迟随时间变化的列表 * 处理监控数据以生成分类的平均延迟随时间变化的列表
@ -149,17 +206,25 @@ const monitorChartData = computed(() => {
avgs: [], avgs: [],
}; };
} }
const showAvgDelay = [];
const showCreateTime = i.created_at.filter((o, index) => {
const status = o >= accpetShowTime.value;
if (status) {
showAvgDelay.push(i.avg_delay[index]);
}
return status;
});
const { const {
threshold, threshold,
mean, mean,
max, max,
min, min,
} = peakShaving.value ? getThreshold(i.avg_delay, 2) : {}; } = peakShaving.value ? getThreshold(showAvgDelay, 2) : {};
i.created_at.forEach((o, index) => { showCreateTime.forEach((o, index) => {
if (dateMap[o]) { if (dateMap[o]) {
return; return;
} }
const avgDelay = i.avg_delay[index]; const avgDelay = showAvgDelay[index];
if (peakShaving.value) { if (peakShaving.value) {
if (avgDelay === 0) { if (avgDelay === 0) {
return; return;
@ -238,6 +303,10 @@ function switchRefresh() {
refreshData.value = !refreshData.value; refreshData.value = !refreshData.value;
} }
function toggleMinute(value) {
minute.value = value;
}
function toggleShowCate(id) { function toggleShowCate(id) {
showCates.value[id] = !showCates.value[id]; showCates.value[id] = !showCates.value[id];
} }
@ -299,12 +368,14 @@ onUnmounted(() => {
.module-head-group { .module-head-group {
display: flex; display: flex;
flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 10px; gap: 10px;
height: 30px;
.module-title { .module-title {
width: max-content;
height: 30px;
line-height: 30px; line-height: 30px;
font-size: 16px; font-size: 16px;
color: #eee; color: #eee;
@ -312,15 +383,16 @@ onUnmounted(() => {
.right-box { .right-box {
display: flex; display: flex;
flex-wrap: wrap;
align-items: center; align-items: center;
gap: 10px; gap: 12px;
} }
.peak-shaving-group, .peak-shaving-group,
.refresh-data-group { .refresh-data-group {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 4px;
cursor: pointer; cursor: pointer;
@media screen and (max-width: 1024px) { @media screen and (max-width: 1024px) {
@ -351,6 +423,7 @@ onUnmounted(() => {
.switch-dot { .switch-dot {
left: 16px; left: 16px;
box-shadow: 1px 1px 2px #000;
} }
} }
} }
@ -360,6 +433,83 @@ onUnmounted(() => {
font-size: 12px; font-size: 12px;
} }
} }
.last-update-time-group {
--minute-item-width: 50px;
--minute-item-height: 20px;
display: flex;
align-items: center;
gap: 4px;
.last-update-time-label {
color: #ddd;
height: var(--minute-item-height);
line-height: var(--minute-item-height);
font-size: 12px;
}
@media screen and (max-width: 660px) {
--minute-item-width: 46px;
}
@media screen and (max-width: 600px) {
--minute-item-width: 46px;
}
@media screen and (max-width: 400px) {
.last-update-time-label {
display: none;
}
}
@media screen and (max-width: 330px) {
margin-left: -12px;
}
@media screen and (max-width: 320px) {
margin-left: -18px;
}
}
.minutes {
position: relative;
display: flex;
align-items: center;
// padding: 0 10px;
height: var(--minute-item-height);
background: rgba(#fff, 0.1);
border-radius: calc(var(--minute-item-height) / 2);
.minute-item {
position: relative;
z-index: 10;
width: var(--minute-item-width);
height: var(--minute-item-height);
line-height: var(--minute-item-height);
font-size: 12px;
text-align: center;
cursor: pointer;
color: #aaa;
transition: color 0.3s;
&.active {
color: #fff;
text-shadow: 1px 1px 2px #000;
}
}
.active-arrow {
position: absolute;
top: 0;
left: 0;
width: var(--minute-item-width);
height: var(--minute-item-height);
border-radius: calc(var(--minute-item-height) / 2);
background: #4caf50;
// opacity: 0.5;
transition: left 0.3s;
z-index: 1;
}
}
} }
.monitor-cate-group { .monitor-cate-group {