From 7615bccf04b6d2dd11b5747155914ca2b6c9d200 Mon Sep 17 00:00:00 2001 From: zhongzm Date: Tue, 19 Nov 2024 17:20:49 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E6=97=A5=E6=9C=9F=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=99=A8=E6=B7=BB=E5=8A=A0=E5=BF=AB=E6=8D=B7=E9=80=89?= =?UTF-8?q?=E9=A1=B9=EF=BC=8Ctooltip=E6=98=BE=E7=A4=BA=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/perfManage/kpiOverView/index.vue | 101 ++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/src/views/perfManage/kpiOverView/index.vue b/src/views/perfManage/kpiOverView/index.vue index eaf8e7ed..8cb4715a 100644 --- a/src/views/perfManage/kpiOverView/index.vue +++ b/src/views/perfManage/kpiOverView/index.vue @@ -32,6 +32,7 @@ interface ChartDataItem { [kpiId: string]: string | number; // 动态指标 } const tableLoading = ref(false); +const rangeLoading = ref(false); //网元类型定义 const ALL_NE_TYPES = ['AMF','SMF','UPF','MME','IMS','SMSC'] as const; type NeType= typeof ALL_NE_TYPES[number]; @@ -47,6 +48,18 @@ echarts.use([ // WebSocket连接 const ws = ref(null); +//时间选择 +let ranges = ref>({ + [t('views.perfManage.customTarget.sixHoursAgo')]: [ + dayjs().subtract(6, 'hours'), + dayjs(), + ], + [t('views.perfManage.customTarget.threeHoursAgo')]: [ + dayjs().subtract(3, 'hours'), + dayjs(), + ], + [t('views.monitor.monitor.today')]: [dayjs().startOf('day'), dayjs()], +}); //日期范围响应式变量 const dateRange = ref<[string, string]>([ dayjs().startOf('hour').valueOf().toString(), @@ -168,8 +181,10 @@ const processChartData = (rawData: any[]) => { } Object.assign(groupedData.get(timeKey), item); }); + // 获取当前选择的结束时间 + const endTime = dateRange.value[1]; - return Array.from(groupedData.values()) + const processedData = Array.from(groupedData.values()) .sort((a, b) => Number(a.timeGroup) - Number(b.timeGroup)) .map(item => {//转换成图表需要的格式 const dataItem: ChartDataItem = { date: item.timeGroup.toString() }; @@ -178,6 +193,17 @@ const processChartData = (rawData: any[]) => { }); return dataItem; }); + // 如果有数据,且最后一个数据点的时间小于选择的结束时间 + if (processedData.length > 0 && Number(processedData[processedData.length - 1].date) < Number(endTime)) { + // 添加一个结束时间点,所有指标值设为0 + const endDataPoint: ChartDataItem = { date: endTime }; + selectedKPIs.value.forEach(kpiId => { + endDataPoint[kpiId] = 0; + }); + processedData.push(endDataPoint); + } + + return processedData; }; // 获取图表数据方法 const fetchChartData = async () => { @@ -185,6 +211,8 @@ const fetchChartData = async () => { updateChart(); return; } + tableLoading.value=true; + rangeLoading.value=true; try { const[startTime,endTime]=dateRange.value; if (!startTime || !endTime) { @@ -226,6 +254,9 @@ const fetchChartData = async () => { } catch (error) { console.error('Failed to fetch chart data:', error); message.error(t('common.getInfoFail')); + }finally { + tableLoading.value=false; + rangeLoading.value=false; } }; @@ -250,6 +281,26 @@ const updateChart = () => { const color = kpiColors.get(kpiId)||generateColorRGBA(); kpiColors.set(kpiId, color); + // 获取数据数组 + const data = chartData.value.map((item, index) => { + const value = item[kpiId] || 0; + // 如果是最后一个数据点,添加特殊样式 + if (index === chartData.value.length - 1) { + return { + value, + symbolSize: 12, // 更大的节点 + itemStyle: { + color, // 保持与线条相同的颜色 + borderWidth: 3, // 添加边框 + borderColor: color, // 边框颜色 + shadowBlur: 10, // 添加阴影效果 + shadowColor: color, + }, + }; + } + return value; + }); + return { name: kpi.title, type: 'line', @@ -266,6 +317,27 @@ const updateChart = () => { }, tooltip: { trigger: 'axis', + position: function (point: number[], params: any, dom: HTMLElement, rect: any, size: { viewSize: number[], contentSize: number[] }) { + const [x, y] = point; + const [viewWidth] = size.viewSize; + const [tooltipWidth, tooltipHeight] = size.contentSize; + + // 距离右侧的距离 + const rightSpace = viewWidth - x; + + // 计算垂直方向的居中位置 + // 将 tooltip 的中心点对齐到鼠标位置 + const verticalOffset = -tooltipHeight / 2; + + // 如果右侧空间不足以显示tooltip(假设需要20px的安全距离) + if (rightSpace < tooltipWidth + 20) { + // 向左显示,垂直居中 + return [x - tooltipWidth - 10, y + verticalOffset]; + } + + // 默认向右显示,垂直居中 + return [x + 10, y + verticalOffset]; + }, }, legend: { data: selectedKPIs.value.map(kpiId => @@ -309,6 +381,29 @@ const updateChart = () => { dayjs(Number(item.date)).format('YYYY-MM-DD HH:mm:ss') ), //设置坐标轴刻度标签的样式 + axisLabel: { + interval: function(index: number, value: string) { + const currentTime = dayjs(value); + const minutes = currentTime.minute(); + const seconds = currentTime.second(); + + // 始终显示小时的起始和结束时间点 + if ((minutes === 0 && seconds === 0) || + (minutes === 59 && seconds === 59)) { + return true; + } + + // 对于中间的时间点,使用 auto 的逻辑 + if (index % Math.ceil(chartData.value.length / 6) === 0) { + return true; + } + + return false; + }, + rotate: 0, + align: 'center', + hideOverlap: true + } }, yAxis: { // y轴配置 @@ -446,7 +541,7 @@ const updateChartData = (newData: ChartDataItem) => { return; } chartData.value.push(newData); - if (chartData.value.length > 50) {//100改为50 + if (chartData.value.length > 100) {//100改为50 chartData.value.shift();//大于100条时删除最早的数据 } //使用try-catch包裹图表更新逻辑 @@ -590,6 +685,8 @@ const updateChartLegendSelect = (selectedKpiId?: string) => { format="YYYY-MM-DD HH:mm:ss" :value-format="'x'" :disabled="isRealtime" + :ranges="ranges" + :loading="rangeLoading" @change="handleDateChange" />