mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-11 22:50:42 +08:00
✨ 监控图表添加断线显示
This commit is contained in:
parent
9aaa5b0cc3
commit
0a33582541
@ -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);
|
||||
|
||||
@ -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 = `<p style="font-weight: bold; color: #ff6;">${time}</p>`;
|
||||
if (params.length < 10) {
|
||||
params.forEach((i) => {
|
||||
res += `${i.marker} ${i.seriesName}: ${i.value[1]}ms<br>`;
|
||||
res += i.value[1] ? `${i.marker} ${i.seriesName}: ${i.value[1]}ms<br>` : '';
|
||||
});
|
||||
} else {
|
||||
res += '<table>';
|
||||
@ -45,7 +47,9 @@ export default (
|
||||
if (index % 2 === 0) {
|
||||
res += '<tr>';
|
||||
}
|
||||
res += `<td style="padding: 0 4px;">${i.marker} ${i.seriesName}: ${i.value[1]}ms</td>`;
|
||||
res += i.value[1]
|
||||
? `<td style="padding: 0 4px;">${i.marker} ${i.seriesName}: ${i.value[1]}ms</td>`
|
||||
: '<td style="padding: 0 4px;"></td>';
|
||||
if (index % 2 === 1) {
|
||||
res += '</tr>';
|
||||
trEnd = true;
|
||||
@ -108,7 +112,7 @@ export default (
|
||||
...i,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
connectNulls: true,
|
||||
connectNulls,
|
||||
legendHoverLink: false,
|
||||
symbol: 'none',
|
||||
})),
|
||||
|
||||
@ -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;
|
||||
});
|
||||
|
||||
@ -118,10 +118,10 @@
|
||||
{{ cateItem.avg }}ms
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="cate-avg-ms"
|
||||
v-if="cateItem.over !== 0"
|
||||
class="cate-over-rate"
|
||||
>
|
||||
-ms
|
||||
{{ cateItem.over }}%
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@ -131,6 +131,7 @@
|
||||
:date-list="monitorChartData.dateList"
|
||||
:value-list="[monitorChartData.valueList[index]]"
|
||||
:size="240"
|
||||
:connect-nulls="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -168,12 +169,6 @@
|
||||
>
|
||||
{{ cateItem.avg }}ms
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="cate-avg-ms"
|
||||
>
|
||||
-ms
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</popover>
|
||||
@ -183,6 +178,7 @@
|
||||
<line-chart
|
||||
:date-list="monitorChartData.dateList"
|
||||
:value-list="monitorChartData.valueList"
|
||||
:connect-nulls="false"
|
||||
/>
|
||||
</template>
|
||||
</dot-dot-box>
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
// 计算过滤后数据的最大值
|
||||
|
||||
Loading…
Reference in New Issue
Block a user