diff --git a/src/App.vue b/src/App.vue
index 0be9a15..98c0518 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -42,10 +42,9 @@ provide('currentTime', currentTime);
*/
function refreshTime() {
currentTime.value = Date.now();
- setTimeout(() => {
- refreshTime();
- }, 1000);
+ window.requestAnimationFrame(refreshTime);
}
+refreshTime();
// 是否为Windows系统
const isWindows = /windows|win32/i.test(navigator.userAgent);
diff --git a/src/components/charts/line.js b/src/components/charts/line.js
index 5abcf89..f2c2ffe 100644
--- a/src/components/charts/line.js
+++ b/src/components/charts/line.js
@@ -18,11 +18,13 @@ use([
DataZoomComponent,
]);
-export default (
- dateList,
- valueList,
- mode = 'dark',
-) => {
+export default (options) => {
+ const {
+ dateList,
+ valueList,
+ mode = 'dark',
+ connectNulls = true,
+ } = options || {};
const fontFamily = config.nazhua.disableSarasaTermSC === true ? undefined : 'Sarasa Term SC';
const option = {
darkMode: mode === 'dark',
@@ -36,7 +38,7 @@ export default (
let res = `
${time}
`;
if (params.length < 10) {
params.forEach((i) => {
- res += `${i.marker} ${i.seriesName}: ${i.value[1]}ms
`;
+ res += i.value[1] ? `${i.marker} ${i.seriesName}: ${i.value[1]}ms
` : '';
});
} else {
res += '';
@@ -45,7 +47,9 @@ export default (
if (index % 2 === 0) {
res += '';
}
- res += `| ${i.marker} ${i.seriesName}: ${i.value[1]}ms | `;
+ res += i.value[1]
+ ? `${i.marker} ${i.seriesName}: ${i.value[1]}ms | `
+ : ' | ';
if (index % 2 === 1) {
res += '
';
trEnd = true;
@@ -108,7 +112,7 @@ export default (
...i,
type: 'line',
smooth: true,
- connectNulls: true,
+ connectNulls,
legendHoverLink: false,
symbol: 'none',
})),
diff --git a/src/components/charts/line.vue b/src/components/charts/line.vue
index 3d8d997..f9d1297 100644
--- a/src/components/charts/line.vue
+++ b/src/components/charts/line.vue
@@ -38,15 +38,20 @@ const props = defineProps({
type: [Number, String],
default: null,
},
+ connectNulls: {
+ type: [Boolean, String],
+ default: true,
+ },
});
const chartRef = ref();
const option = computed(() => {
if (props.dateList && props.valueList) {
- return lineChart(
- props.dateList,
- props.valueList,
- );
+ return lineChart({
+ dateList: props.dateList,
+ valueList: props.valueList,
+ connectNulls: props.connectNulls,
+ });
}
return null;
});
diff --git a/src/views/components/server-detail/server-monitor.vue b/src/views/components/server-detail/server-monitor.vue
index 83e454b..dc493c7 100644
--- a/src/views/components/server-detail/server-monitor.vue
+++ b/src/views/components/server-detail/server-monitor.vue
@@ -118,10 +118,10 @@
{{ cateItem.avg }}ms
- -ms
+ {{ cateItem.over }}%
@@ -131,6 +131,7 @@
:date-list="monitorChartData.dateList"
:value-list="[monitorChartData.valueList[index]]"
:size="240"
+ :connect-nulls="false"
/>
@@ -168,12 +169,6 @@
>
{{ cateItem.avg }}ms
-
- -ms
-
@@ -183,6 +178,7 @@
@@ -263,8 +259,9 @@ const monitorChartType = computed(() => {
return config.nazhua.monitorChartType;
});
-const now = ref(Date.now());
-const accpetShowTime = computed(() => now.value - (minute.value * 60 * 1000));
+// 服务器时间(后面来自接口)
+const nowServerTime = computed(() => store.state.serverTime || Date.now());
+const accpetShowTime = computed(() => (Math.floor(nowServerTime.value / 60000) - minute.value) * 60000);
const minuteActiveArrowStyle = computed(() => {
const index = minutes.findIndex((i) => i.value === minute.value);
@@ -302,13 +299,25 @@ const monitorChartData = computed(() => {
};
}
const showAvgDelay = [];
- const showCreateTime = i.created_at.filter((o, index) => {
+ const showCreateTime = [];
+ const accpeTimeMap = {};
+ i.created_at.forEach((o, index) => {
const status = o >= accpetShowTime.value;
if (status) {
- showAvgDelay.push(i.avg_delay[index]);
+ accpeTimeMap[o] = i.avg_delay[index];
}
- return status;
});
+ const allMintues = Math.floor((Date.now() - accpetShowTime.value) / 60000);
+ for (let j = 0; j < allMintues; j += 1) {
+ const time = accpetShowTime.value + j * 60000;
+ showCreateTime.push(time);
+ const timeProp = accpeTimeMap[time];
+ if (timeProp) {
+ showAvgDelay.push(timeProp);
+ } else {
+ showAvgDelay.push(null);
+ }
+ }
const {
threshold,
mean,
@@ -316,19 +325,21 @@ const monitorChartData = computed(() => {
min,
} = peakShaving.value ? getThreshold(showAvgDelay, 2) : {};
showCreateTime.forEach((o, index) => {
- if (dateMap[o]) {
+ if (Object.prototype.hasOwnProperty.call(dateMap, o)) {
return;
}
const avgDelay = showAvgDelay[index];
if (peakShaving.value) {
if (avgDelay === 0) {
+ dateMap[o] = null;
return;
}
if (Math.abs(avgDelay - mean) > threshold && max / min > 2) {
+ dateMap[o] = null;
return;
}
}
- dateMap[o] = (avgDelay).toFixed(2) * 1;
+ dateMap[o] = avgDelay ? (avgDelay).toFixed(2) * 1 : null;
});
});
let dateList = [];
@@ -351,9 +362,9 @@ const monitorChartData = computed(() => {
showCates.value[id] = true;
}
// 计算平均延迟和成功率
- const validAvgs = avgs.filter((a) => a[1] !== 0);
+ const validAvgs = avgs.filter((a) => a[1] !== 0 && a[1] !== null);
const avg = validAvgs.reduce((a, b) => a + b[1], 0) / validAvgs.length;
- const over = avgs.filter((a) => a[1] !== 0).length / avgs.length;
+ const over = avgs.filter((a) => a[1] !== 0 && a[1] !== null).length / avgs.length;
const cateItem = {
id,
name: i,
@@ -384,8 +395,7 @@ const monitorChartData = computed(() => {
});
}
});
- // 去重
- dateList = Array.from(new Set(dateList)).sort((a, b) => a - b);
+ dateList = dateList.sort((a, b) => a - b);
valueList = valueList.filter((i) => showCates.value[i.id]);
return {
dateList,
@@ -410,7 +420,6 @@ function switchChartType() {
}
function toggleMinute(value) {
- now.value = store.state.serverTime || Date.now();
minute.value = value;
}
@@ -454,7 +463,6 @@ async function loadMonitor() {
}).catch((err) => {
console.error(err);
});
- now.value = store.state.serverTime || Date.now();
}
let loadMonitorTimer = null;
@@ -539,8 +547,15 @@ onUnmounted(() => {
color: #fff;
}
+ .cate-over-rate {
+ height: var(--cate-item-height);
+ line-height: calc(var(--cate-item-height) + 2px);
+ text-align: right;
+ color: #fffbd8;
+ }
+
&.disabled {
- filter: grayscale(1);
+ filter: grayscale(1) brightness(0.8);
opacity: 0.5;
}
}
diff --git a/src/views/composable/server-monitor.js b/src/views/composable/server-monitor.js
index 0d62c1a..71a2ba1 100644
--- a/src/views/composable/server-monitor.js
+++ b/src/views/composable/server-monitor.js
@@ -11,15 +11,15 @@ import uniqolor from 'uniqolor';
*/
export function getThreshold(data, tolerance = 2) {
// 计算数据的平均值
- const mean = data.reduce((sum, value) => sum + value, 0) / data.length;
+ const mean = data.reduce((sum, value) => sum + (value || 0), 0) / data.length;
// 计算数据的方差
- const variance = data.reduce((sum, value) => sum + (value - mean) ** 2, 0) / data.length;
+ const variance = data.reduce((sum, value) => sum + ((value || 0) - mean) ** 2, 0) / data.length;
// 计算标准差
const stdDev = Math.sqrt(variance);
// 计算阈值
const threshold = tolerance * stdDev;
// 过滤掉值为0的数据
- const filteredData = data.filter((value) => value !== 0);
+ const filteredData = data.filter((value) => value !== 0 && value !== null);
// 计算过滤后数据的最小值
const min = Math.min(...filteredData);
// 计算过滤后数据的最大值