From 87cfc2ed7984dc1de2b627cbc261e661e4ff79ad Mon Sep 17 00:00:00 2001 From: zhongzm Date: Fri, 27 Jun 2025 16:56:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E9=BB=84=E9=87=91=E6=8C=87=E6=A0=87?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E6=8C=87=E6=A0=87=E6=98=BE=E7=A4=BAbug?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/perfManage/goldTarget/index.vue | 593 +++++++++++----------- 1 file changed, 309 insertions(+), 284 deletions(-) diff --git a/src/views/perfManage/goldTarget/index.vue b/src/views/perfManage/goldTarget/index.vue index a1829b78..b5c9c61d 100644 --- a/src/views/perfManage/goldTarget/index.vue +++ b/src/views/perfManage/goldTarget/index.vue @@ -443,17 +443,13 @@ function fnGetListTitle() { // 获取表头文字,只传递纯网元类型 getKPITitle(state.neType) .then(res => { - //处理getKPITitle返回的结果 if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) { - //检查值 tableColumns.value = []; //设为空数组 - const columns: any[] = []; //初始化,构建新表头 + const columns: any[] = []; for (const item of res.data) { - //遍历res.data - const kpiDisplay = item[`${language}Title`]; //提取标题kpiDisplay和ID标识kpiValue + const kpiDisplay = item[`${language}Title`]; const kpiValue = item[`kpiId`]; columns.push({ - // title: kpiDisplay, dataIndex: kpiValue, align: 'left', @@ -482,6 +478,9 @@ function fnGetListTitle() { }); nextTick(() => { tableColumns.value = columns; + nextTick(() => { + fnGetList(); + }); }); return true; } else { @@ -491,10 +490,6 @@ function fnGetListTitle() { }); return false; } - }) - .then(result => { - //result是前一个.then返回的值(true or false) - result && fnGetList(); }); } @@ -504,7 +499,10 @@ async function fnGetList() { tableState.loading = true; try { - // 获取所有网元数据 + // 第一步:根据指标信息和网元数量,创建完整的默认数据结构 + fnCreateDefaultDataStructure(); + + // 第二步:获取所有网元数据 let allNeData: any[] = []; // 每个选中的网元ID发送一个请求 @@ -537,55 +535,8 @@ async function fnGetList() { tablePagination.total = allNeData.length; tableState.data = allNeData; - // 调用图表渲染函数 - fnRanderChartData(); - - // 封装legend表格数据 - kpiStats.value = []; - - // 为每个指标和每个网元创建统计数据 - for (const columns of tableColumns.value) { - if ( - columns.key === 'neName' || - columns.key === 'startIndex' || - columns.key === 'timeGroup' - ) { - continue; - } - - // 处理每个网元 - for (const neId of state.neIds) { - // 过滤该网元的数据 - const neData = tableState.data.filter(item => item._neId === neId); - - if (neData.length === 0) continue; - - const values = neData.map((item: any) => { - return item[columns.key] ? Number(item[columns.key]) : 0; - }); - - // 计算总值 - const total = Number( - values.reduce((sum, val) => sum + val, 0).toFixed(2) - ); - - // 计算平均值 - const avg = - values.length > 0 ? Number((total / values.length).toFixed(2)) : 0; - - kpiStats.value.push({ - kpiId: `${columns.key}_${neId}`, // 使用组合ID来唯一标识指标-网元对 - title: `${columns.title}(${neId})`, // 在标题中显示网元ID - rawKpiId: columns.key, - rawKpiTitle: columns.title, - neId: neId, - max: values.length > 0 ? Math.max(...values) : 0, - min: values.length > 0 ? Math.min(...values) : 0, - avg: avg, - total: total, - }); - } - } + // 第三步:用真实数据更新默认值 + fnUpdateDataWithRealValues(allNeData); return true; } catch (error) { @@ -600,6 +551,260 @@ async function fnGetList() { } } +/**创建默认数据结构 */ +function fnCreateDefaultDataStructure() { + // 重置 + chartLegendSelected = {}; + chartDataXAxisData = []; + chartDataYSeriesData = []; + kpiStats.value = []; + + // 创建默认的时间点(当前时间) + const defaultTimePoint = Date.now(); + chartDataXAxisData = [parseDateToStr(defaultTimePoint)]; + + // 为每个网元的每个指标创建默认数据结构 + for (const columns of tableColumns.value) { + if ( + columns.key === 'neName' || + columns.key === 'startIndex' || + columns.key === 'timeGroup' + ) { + continue; + } + for (const neId of state.neIds) { + const kpiId = `${columns.key}_${neId}`; + const seriesName = `${columns.title}(${neId})`; + // 获取或生成颜色 + const color = kpiColors.get(kpiId) || generateColorRGBA(); + kpiColors.set(kpiId, color); + // 创建图表系列,包含默认数据点 + const seriesData = { + name: seriesName, + key: kpiId, + type: 'line', + symbol: 'none', + symbolSize: 6, + smooth: 0.6, + showSymbol: true, + sampling: 'lttb', + itemStyle: { + color: color, + }, + areaStyle: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: color.replace(')', ',0.8)'), + }, + { + offset: 1, + color: color.replace(')', ',0.3)'), + }, + ]), + }, + data: [0], // 默认值为0,确保tooltip能显示指标信息 + }; + chartDataYSeriesData.push(seriesData); + chartLegendSelected[seriesName] = true; + // 创建统计表格项,默认值为0 + kpiStats.value.push({ + kpiId: `${columns.key}_${neId}`, + title: `${columns.title}(${neId})`, + rawKpiId: columns.key, + rawKpiTitle: columns.title, + neId: neId, + max: 0, + min: 0, + avg: 0, + total: 0, + }); + } + } + + // 创建默认的原始数据(用于表格显示) + const defaultTableData: any[] = []; + for (const neId of state.neIds) { + const defaultRow: any = { + _neId: neId, + neName: `${state.neType}-${neId}`, + timeGroup: defaultTimePoint, + }; + + // 为每个指标添加默认值0 + for (const columns of tableColumns.value) { + if ( + columns.key === 'neName' || + columns.key === 'startIndex' || + columns.key === 'timeGroup' + ) { + continue; + } + defaultRow[columns.key] = 0; + } + + defaultTableData.push(defaultRow); + } + + tableState.data = defaultTableData; + tablePagination.total = defaultTableData.length; + + // 渲染默认的图表和表格 + if (kpiChart.value && kpiChartDom.value) { + kpiChart.value.setOption( + { + legend: { + selected: chartLegendSelected, + }, + xAxis: { + type: 'category', + boundaryGap: false, + axisLabel: { + color: + document.documentElement.getAttribute('data-theme') === 'dark' + ? '#CACADA' + : '#333', + }, + splitLine: { + show: true, + lineStyle: { + color: getSplitLineColor(), + }, + }, + data: chartDataXAxisData, + }, + series: chartDataYSeriesData, + }, + { + replaceMerge: ['xAxis', 'series'], + } + ); + } +} + +/**用真实数据更新默认值 */ +function fnUpdateDataWithRealValues(allNeData: any[]) { + if (allNeData.length === 0) { + // 如果没有真实数据,保持默认值 + return; + } + + // 更新原始数据表格 + tableState.data = allNeData; + tablePagination.total = allNeData.length; + + // 获取所有时间点并格式化 + const timePoints = [ + ...new Set(allNeData.map(item => item.timeGroup)), + ].sort(); + chartDataXAxisData = timePoints.map(time => parseDateToStr(+time)); + + // 更新图表数据 + for (const series of chartDataYSeriesData) { + const [kpiKey, neId] = series.key.split('_'); + const neData = allNeData.filter(item => item._neId === neId); + + // 为每个时间点填充数据 + series.data = timePoints.map(time => { + const dataPoint = neData.find(item => item.timeGroup === time); + return dataPoint ? +dataPoint[kpiKey] : null; + }); + } + + // 更新统计数据 + for (const columns of tableColumns.value) { + if ( + columns.key === 'neName' || + columns.key === 'startIndex' || + columns.key === 'timeGroup' + ) { + continue; + } + + // 处理每个网元 + for (const neId of state.neIds) { + // 过滤该网元的数据 + const neData = allNeData.filter(item => item._neId === neId); + + // 找到对应的统计项并更新 + const statsItem = kpiStats.value.find( + (item: KPIStats) => item.kpiId === `${columns.key}_${neId}` + ); + + if (statsItem) { + if (neData.length === 0) { + // 没有数据时保持默认值0 + statsItem.max = 0; + statsItem.min = 0; + statsItem.avg = 0; + statsItem.total = 0; + } else { + // 有数据时计算统计值 + const values = neData.map((item: any) => { + return item[columns.key] ? Number(item[columns.key]) : 0; + }); + + const total = Number( + values.reduce((sum, val) => sum + val, 0).toFixed(2) + ); + const avg = + values.length > 0 ? Number((total / values.length).toFixed(2)) : 0; + + statsItem.max = values.length > 0 ? Math.max(...values) : 0; + statsItem.min = values.length > 0 ? Math.min(...values) : 0; + statsItem.avg = avg; + statsItem.total = total; + } + } + } + } + + // 更新图表 + if (kpiChart.value && kpiChartDom.value) { + // 如果有选中的行,只显示选中的指标 + if (selectedRows.value.length > 0) { + Object.keys(chartLegendSelected).forEach(key => { + chartLegendSelected[key] = false; + }); + + kpiStats.value.forEach((item: KPIStats) => { + if (selectedRows.value.includes(item.kpiId)) { + chartLegendSelected[item.title] = true; + } + }); + } + + kpiChart.value.setOption( + { + legend: { + selected: chartLegendSelected, + }, + xAxis: { + type: 'category', + boundaryGap: false, + axisLabel: { + color: + document.documentElement.getAttribute('data-theme') === 'dark' + ? '#CACADA' + : '#333', + }, + splitLine: { + show: true, + lineStyle: { + color: getSplitLineColor(), + }, + }, + data: chartDataXAxisData, + }, + series: chartDataYSeriesData, + }, + { + replaceMerge: ['xAxis', 'series'], + } + ); + } +} + /**切换显示类型 图或表格 */ function fnChangShowType() { tableState.showTable = !tableState.showTable; @@ -696,11 +901,13 @@ function fnRanderChart() { }, series: [], // 数据y轴 }; - kpiChart.value.setOption(option); //设置图表配置项,应用到kpiChart实例上 + if (kpiChart.value && kpiChartDom.value) { + kpiChart.value.setOption(option); //设置图表配置项,应用到kpiChart实例上 + } // 创建 ResizeObserver 实例 监听图表容器大小变化,并在变化时调整图表大小 var observer = new ResizeObserver(entries => { - if (kpiChart.value) { + if (kpiChart.value && kpiChartDom.value) { kpiChart.value.resize(); } }); @@ -717,125 +924,10 @@ let chartDataYSeriesData: Record[] = []; /**图表数据渲染 */ function fnRanderChartData() { - if (kpiChart.value == null || tableState.data.length <= 0) { + if (!kpiChart.value || !kpiChartDom.value || tableState.data.length <= 0) { return; } - - // 重置 - chartLegendSelected = {}; - chartDataXAxisData = []; - chartDataYSeriesData = []; - - // 为每个网元的每个指标创建一条线 - for (const neId of state.neIds) { - for (const columns of tableColumns.value) { - if ( - columns.key === 'neName' || - columns.key === 'startIndex' || - columns.key === 'timeGroup' - ) { - continue; - } - - const kpiId = `${columns.key}_${neId}`; - const seriesName = `${columns.title}(${neId})`; - - // 获取或生成颜色 - const color = kpiColors.get(kpiId) || generateColorRGBA(); - kpiColors.set(kpiId, color); - - const seriesData = { - name: seriesName, - key: kpiId, - type: 'line', - symbol: 'none', - symbolSize: 6, - smooth: 0.6, - showSymbol: true, - sampling: 'lttb', - itemStyle: { - color: color, - }, - areaStyle: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ - { - offset: 0, - color: color.replace(')', ',0.8)'), - }, - { - offset: 1, - color: color.replace(')', ',0.3)'), - }, - ]), - }, - data: [] as (number | null)[], - }; - - chartDataYSeriesData.push(seriesData); - - // 默认所有指标都显示 - chartLegendSelected[seriesName] = true; - } - } - - // 获取所有时间点并格式化 - const timePoints = [ - ...new Set(tableState.data.map(item => item.timeGroup)), - ].sort(); - chartDataXAxisData = timePoints.map(time => parseDateToStr(+time)); - - // 填充数据 - for (const series of chartDataYSeriesData) { - const [kpiKey, neId] = series.key.split('_'); - const neData = tableState.data.filter(item => item._neId === neId); - series.data = timePoints.map(time => { - const dataPoint = neData.find(item => item.timeGroup === time); - return dataPoint ? +dataPoint[kpiKey] : null; - }); - } - - // 如果有选中的行,只显示选中的指标 - if (selectedRows.value.length > 0) { - Object.keys(chartLegendSelected).forEach(key => { - chartLegendSelected[key] = false; - }); - - kpiStats.value.forEach((item: KPIStats) => { - if (selectedRows.value.includes(item.kpiId)) { - chartLegendSelected[item.title] = true; - } - }); - } - - // 更新图表 - kpiChart.value.setOption( - { - legend: { - selected: chartLegendSelected, - }, - xAxis: { - type: 'category', - boundaryGap: false, - axisLabel: { - color: - document.documentElement.getAttribute('data-theme') === 'dark' - ? '#CACADA' - : '#333', - }, - splitLine: { - show: true, - lineStyle: { - color: getSplitLineColor(), - }, - }, - data: chartDataXAxisData, - }, - series: chartDataYSeriesData, - }, - { - replaceMerge: ['xAxis', 'series'], - } - ); + fnUpdateDataWithRealValues(tableState.data); } /**图表折线显示全部 */ @@ -865,89 +957,8 @@ function fnRealTimeSwitch(bool: any) { chartDataXAxisData = []; chartDataYSeriesData = []; - // 重新初始化图表配置 - const option = { - tooltip: { - trigger: 'axis', - position: function (pt: any) { - return [pt[0], '10%']; - }, - confine: true, - backgroundColor: - document.documentElement.getAttribute('data-theme') === 'dark' - ? 'rgba(48, 48, 48, 0.8)' - : 'rgba(255, 255, 255, 0.9)', - borderColor: - document.documentElement.getAttribute('data-theme') === 'dark' - ? '#555' - : '#ddd', - textStyle: { - color: - document.documentElement.getAttribute('data-theme') === 'dark' - ? '#CACADA' - : '#333', - }, - }, - xAxis: { - type: 'category', - boundaryGap: false, - data: [], - axisLabel: { - color: - document.documentElement.getAttribute('data-theme') === 'dark' - ? '#CACADA' - : '#333', - }, - splitLine: { - show: true, - lineStyle: { - color: getSplitLineColor(), - }, - }, - }, - yAxis: { - type: 'value', - boundaryGap: [0, '100%'], - axisLabel: { - formatter: '{value}', - color: - document.documentElement.getAttribute('data-theme') === 'dark' - ? '#CACADA' - : '#333', - }, - splitNumber: 5, - scale: true, - splitLine: { - show: true, - lineStyle: { - color: getSplitLineColor(), - }, - }, - }, - legend: { - show: false, - type: 'scroll', - orient: 'vertical', - top: 40, - right: 20, - itemWidth: 20, - itemGap: 25, - textStyle: { - color: '#646A73', - }, - icon: 'circle', - selected: {}, - }, - grid: { - left: '3%', - right: '4%', - bottom: '3%', - containLabel: true, - }, - series: [], - }; - - kpiChart.value.setOption(option); + // 先创建默认数据结构 + fnCreateDefaultDataStructure(); // 建立链接 const options: OptionsType = { @@ -1047,7 +1058,7 @@ function wsMessage(res: Record) { // 使用 requestAnimationFrame 更新图表 requestAnimationFrame(() => { - if (!kpiChart.value) return; + if (!kpiChart.value || !kpiChartDom.value) return; // 重新生成 series 数据 const series = []; @@ -1135,6 +1146,7 @@ function wsMessage(res: Record) { // 添加更新统计数据的函数 function updateKpiStats() { + // 清空现有统计数据 kpiStats.value = []; // 为每个指标和每个网元创建统计数据 @@ -1152,32 +1164,41 @@ function updateKpiStats() { // 过滤该网元的数据 const neData = tableState.data.filter(item => item._neId === neId); - if (neData.length === 0) continue; - - const values = neData.map((item: any) => { - return item[columns.key] ? Number(item[columns.key]) : 0; - }); - - // 计算总值 - const total = Number( - values.reduce((sum, val) => sum + val, 0).toFixed(2) - ); - - // 计算平均值 - const avg = - values.length > 0 ? Number((total / values.length).toFixed(2)) : 0; - - kpiStats.value.push({ + // 创建统计项(即使没有数据也创建) + const statsItem = { kpiId: `${columns.key}_${neId}`, title: `${columns.title}(${neId})`, rawKpiId: columns.key, rawKpiTitle: columns.title, neId: neId, - max: values.length > 0 ? Math.max(...values) : 0, - min: values.length > 0 ? Math.min(...values) : 0, - avg: avg, - total: total, - }); + max: 0, + min: 0, + avg: 0, + total: 0, + }; + + if (neData.length > 0) { + // 有数据时计算统计值 + const values = neData.map((item: any) => { + return item[columns.key] ? Number(item[columns.key]) : 0; + }); + + // 计算总值 + const total = Number( + values.reduce((sum, val) => sum + val, 0).toFixed(2) + ); + + // 计算平均值 + const avg = + values.length > 0 ? Number((total / values.length).toFixed(2)) : 0; + + statsItem.max = values.length > 0 ? Math.max(...values) : 0; + statsItem.min = values.length > 0 ? Math.min(...values) : 0; + statsItem.avg = avg; + statsItem.total = total; + } + + kpiStats.value.push(statsItem); } } } @@ -1414,6 +1435,10 @@ onMounted(() => { onBeforeUnmount(() => { ws.close(); + if (kpiChart.value) { + kpiChart.value.dispose(); + kpiChart.value = null; + } });