mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-17 17:50:43 +08:00
✨ 监控图表添加断线显示
This commit is contained in:
parent
9aaa5b0cc3
commit
0a33582541
@ -42,10 +42,9 @@ provide('currentTime', currentTime);
|
|||||||
*/
|
*/
|
||||||
function refreshTime() {
|
function refreshTime() {
|
||||||
currentTime.value = Date.now();
|
currentTime.value = Date.now();
|
||||||
setTimeout(() => {
|
window.requestAnimationFrame(refreshTime);
|
||||||
refreshTime();
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
refreshTime();
|
||||||
|
|
||||||
// 是否为Windows系统
|
// 是否为Windows系统
|
||||||
const isWindows = /windows|win32/i.test(navigator.userAgent);
|
const isWindows = /windows|win32/i.test(navigator.userAgent);
|
||||||
|
|||||||
@ -18,11 +18,13 @@ use([
|
|||||||
DataZoomComponent,
|
DataZoomComponent,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export default (
|
export default (options) => {
|
||||||
dateList,
|
const {
|
||||||
valueList,
|
dateList,
|
||||||
mode = 'dark',
|
valueList,
|
||||||
) => {
|
mode = 'dark',
|
||||||
|
connectNulls = true,
|
||||||
|
} = options || {};
|
||||||
const fontFamily = config.nazhua.disableSarasaTermSC === true ? undefined : 'Sarasa Term SC';
|
const fontFamily = config.nazhua.disableSarasaTermSC === true ? undefined : 'Sarasa Term SC';
|
||||||
const option = {
|
const option = {
|
||||||
darkMode: mode === 'dark',
|
darkMode: mode === 'dark',
|
||||||
@ -36,7 +38,7 @@ export default (
|
|||||||
let res = `<p style="font-weight: bold; color: #ff6;">${time}</p>`;
|
let res = `<p style="font-weight: bold; color: #ff6;">${time}</p>`;
|
||||||
if (params.length < 10) {
|
if (params.length < 10) {
|
||||||
params.forEach((i) => {
|
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 {
|
} else {
|
||||||
res += '<table>';
|
res += '<table>';
|
||||||
@ -45,7 +47,9 @@ export default (
|
|||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
res += '<tr>';
|
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) {
|
if (index % 2 === 1) {
|
||||||
res += '</tr>';
|
res += '</tr>';
|
||||||
trEnd = true;
|
trEnd = true;
|
||||||
@ -108,7 +112,7 @@ export default (
|
|||||||
...i,
|
...i,
|
||||||
type: 'line',
|
type: 'line',
|
||||||
smooth: true,
|
smooth: true,
|
||||||
connectNulls: true,
|
connectNulls,
|
||||||
legendHoverLink: false,
|
legendHoverLink: false,
|
||||||
symbol: 'none',
|
symbol: 'none',
|
||||||
})),
|
})),
|
||||||
|
|||||||
@ -38,15 +38,20 @@ const props = defineProps({
|
|||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
connectNulls: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const chartRef = ref();
|
const chartRef = ref();
|
||||||
const option = computed(() => {
|
const option = computed(() => {
|
||||||
if (props.dateList && props.valueList) {
|
if (props.dateList && props.valueList) {
|
||||||
return lineChart(
|
return lineChart({
|
||||||
props.dateList,
|
dateList: props.dateList,
|
||||||
props.valueList,
|
valueList: props.valueList,
|
||||||
);
|
connectNulls: props.connectNulls,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -118,10 +118,10 @@
|
|||||||
{{ cateItem.avg }}ms
|
{{ cateItem.avg }}ms
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-else
|
v-if="cateItem.over !== 0"
|
||||||
class="cate-avg-ms"
|
class="cate-over-rate"
|
||||||
>
|
>
|
||||||
-ms
|
{{ cateItem.over }}%
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -131,6 +131,7 @@
|
|||||||
:date-list="monitorChartData.dateList"
|
:date-list="monitorChartData.dateList"
|
||||||
:value-list="[monitorChartData.valueList[index]]"
|
:value-list="[monitorChartData.valueList[index]]"
|
||||||
:size="240"
|
:size="240"
|
||||||
|
:connect-nulls="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -168,12 +169,6 @@
|
|||||||
>
|
>
|
||||||
{{ cateItem.avg }}ms
|
{{ cateItem.avg }}ms
|
||||||
</span>
|
</span>
|
||||||
<span
|
|
||||||
v-else
|
|
||||||
class="cate-avg-ms"
|
|
||||||
>
|
|
||||||
-ms
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</popover>
|
</popover>
|
||||||
@ -183,6 +178,7 @@
|
|||||||
<line-chart
|
<line-chart
|
||||||
:date-list="monitorChartData.dateList"
|
:date-list="monitorChartData.dateList"
|
||||||
:value-list="monitorChartData.valueList"
|
:value-list="monitorChartData.valueList"
|
||||||
|
:connect-nulls="false"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</dot-dot-box>
|
</dot-dot-box>
|
||||||
@ -263,8 +259,9 @@ const monitorChartType = computed(() => {
|
|||||||
return config.nazhua.monitorChartType;
|
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 minuteActiveArrowStyle = computed(() => {
|
||||||
const index = minutes.findIndex((i) => i.value === minute.value);
|
const index = minutes.findIndex((i) => i.value === minute.value);
|
||||||
@ -302,13 +299,25 @@ const monitorChartData = computed(() => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const showAvgDelay = [];
|
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;
|
const status = o >= accpetShowTime.value;
|
||||||
if (status) {
|
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 {
|
const {
|
||||||
threshold,
|
threshold,
|
||||||
mean,
|
mean,
|
||||||
@ -316,19 +325,21 @@ const monitorChartData = computed(() => {
|
|||||||
min,
|
min,
|
||||||
} = peakShaving.value ? getThreshold(showAvgDelay, 2) : {};
|
} = peakShaving.value ? getThreshold(showAvgDelay, 2) : {};
|
||||||
showCreateTime.forEach((o, index) => {
|
showCreateTime.forEach((o, index) => {
|
||||||
if (dateMap[o]) {
|
if (Object.prototype.hasOwnProperty.call(dateMap, o)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const avgDelay = showAvgDelay[index];
|
const avgDelay = showAvgDelay[index];
|
||||||
if (peakShaving.value) {
|
if (peakShaving.value) {
|
||||||
if (avgDelay === 0) {
|
if (avgDelay === 0) {
|
||||||
|
dateMap[o] = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Math.abs(avgDelay - mean) > threshold && max / min > 2) {
|
if (Math.abs(avgDelay - mean) > threshold && max / min > 2) {
|
||||||
|
dateMap[o] = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dateMap[o] = (avgDelay).toFixed(2) * 1;
|
dateMap[o] = avgDelay ? (avgDelay).toFixed(2) * 1 : null;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
let dateList = [];
|
let dateList = [];
|
||||||
@ -351,9 +362,9 @@ const monitorChartData = computed(() => {
|
|||||||
showCates.value[id] = true;
|
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 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 = {
|
const cateItem = {
|
||||||
id,
|
id,
|
||||||
name: i,
|
name: i,
|
||||||
@ -384,8 +395,7 @@ const monitorChartData = computed(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 去重
|
dateList = dateList.sort((a, b) => a - b);
|
||||||
dateList = Array.from(new Set(dateList)).sort((a, b) => a - b);
|
|
||||||
valueList = valueList.filter((i) => showCates.value[i.id]);
|
valueList = valueList.filter((i) => showCates.value[i.id]);
|
||||||
return {
|
return {
|
||||||
dateList,
|
dateList,
|
||||||
@ -410,7 +420,6 @@ function switchChartType() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleMinute(value) {
|
function toggleMinute(value) {
|
||||||
now.value = store.state.serverTime || Date.now();
|
|
||||||
minute.value = value;
|
minute.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +463,6 @@ async function loadMonitor() {
|
|||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
now.value = store.state.serverTime || Date.now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let loadMonitorTimer = null;
|
let loadMonitorTimer = null;
|
||||||
@ -539,8 +547,15 @@ onUnmounted(() => {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cate-over-rate {
|
||||||
|
height: var(--cate-item-height);
|
||||||
|
line-height: calc(var(--cate-item-height) + 2px);
|
||||||
|
text-align: right;
|
||||||
|
color: #fffbd8;
|
||||||
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
filter: grayscale(1);
|
filter: grayscale(1) brightness(0.8);
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,15 +11,15 @@ import uniqolor from 'uniqolor';
|
|||||||
*/
|
*/
|
||||||
export function getThreshold(data, tolerance = 2) {
|
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 stdDev = Math.sqrt(variance);
|
||||||
// 计算阈值
|
// 计算阈值
|
||||||
const threshold = tolerance * stdDev;
|
const threshold = tolerance * stdDev;
|
||||||
// 过滤掉值为0的数据
|
// 过滤掉值为0的数据
|
||||||
const filteredData = data.filter((value) => value !== 0);
|
const filteredData = data.filter((value) => value !== 0 && value !== null);
|
||||||
// 计算过滤后数据的最小值
|
// 计算过滤后数据的最小值
|
||||||
const min = Math.min(...filteredData);
|
const min = Math.min(...filteredData);
|
||||||
// 计算过滤后数据的最大值
|
// 计算过滤后数据的最大值
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user