diff --git a/src/i18n/locales/en-US.ts b/src/i18n/locales/en-US.ts index 379f6281..4771a6da 100644 --- a/src/i18n/locales/en-US.ts +++ b/src/i18n/locales/en-US.ts @@ -1086,6 +1086,7 @@ export default { "layout3": "Layout 3" }, kpiOverView:{ + "kpiChartTitle":"Overview of NE metrics", "changeLine":"Change to Line Charts", "changeBar":"Change to Bar Charts", "chooseShowMetrics":"Select the metric you want to display", diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index ffc19f58..6c3e1b80 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -1086,6 +1086,7 @@ export default { "layout3": "布局3" }, kpiOverView:{ + "kpiChartTitle":"网元指标概览", "changeLine":"切换为折线图", "changeBar":"切换为柱状图", "chooseShowMetrics":"选择需要显示的指标", diff --git a/src/views/perfManage/kpiOverView/index.vue b/src/views/perfManage/kpiOverView/index.vue index e8914166..57d4cc45 100644 --- a/src/views/perfManage/kpiOverView/index.vue +++ b/src/views/perfManage/kpiOverView/index.vue @@ -13,12 +13,12 @@ import type { Dayjs } from 'dayjs'; import dayjs from 'dayjs'; import { OptionsType, WS } from '@/plugins/ws-websocket'; import { generateColorRGBA } from '@/utils/generate-utils'; -import { BarChartOutlined, LineChartOutlined, UnorderedListOutlined } from '@ant-design/icons-vue'; +import { BarChartOutlined, LineChartOutlined, UnorderedListOutlined, DownOutlined, MoreOutlined } from '@ant-design/icons-vue'; // 在这里定义 ChartDataItem 接口 interface ChartDataItem { date: string; // 将存储完整的时间字符串,包含时分秒 - [kpiId: string]: string | number; // 动态指标值 + [kpiId: string]: string | number; // 动态指标 } echarts.use([ @@ -49,7 +49,7 @@ let chart: echarts.ECharts | null = null; //observer 变量 监听图表容器大小 let observer: ResizeObserver | null = null; -//日期变化时触发数据变化时触发 +//日期变化时更新图表数据 const handleDateChange = ( value: [string, string] | [Dayjs, Dayjs], dateStrings: [string, string] @@ -63,12 +63,10 @@ const handleDateChange = ( dayjs(dateStrings[0]).valueOf().toString(), dayjs(dateStrings[1]).valueOf().toString() ]; - - fetchChartData(); }; -//切换实时数据方法 +//切换实时数据 const toggleRealtime = () => { fnRealTimeSwitch(isRealtime.value); }; @@ -115,7 +113,7 @@ const wsError = () => { message.error(t('common.websocketError')); } -// 收数据回调 +// 接收数据后回调 const wsMessage = (res: Record) => { const { code, data } = res; if (code === RESULT_CODE_ERROR) { @@ -139,7 +137,7 @@ const wsMessage = (res: Record) => { : Date.now().toString() }; - // 只添加已选中的指标数据 + // 只添加已选中的指标的数据 selectedKPIs.value.forEach(kpiId => { if (kpiEvent[kpiId] !== undefined) { newData[kpiId] = Number(kpiEvent[kpiId]); @@ -152,7 +150,7 @@ const wsMessage = (res: Record) => { updateChartData(newData); }; -// 取图表数据 +// 获取图表数据方法 const fetchChartData = async () => { if (kpiColumns.value.length === 0) { console.warn('No KPI columns available'); @@ -191,7 +189,7 @@ const fetchChartData = async () => { } } - // 按时间分组合并数据 + // 按时间分组合数据 const groupedData = new Map(); allData.forEach(item => { const timeKey = item.timeGroup; @@ -215,7 +213,6 @@ const fetchChartData = async () => { return dataItem; }); - updateChart(); } catch (error) { console.error('Failed to fetch chart data:', error); @@ -223,10 +220,10 @@ const fetchChartData = async () => { } }; -// 添加一个 Map 来存储每个指标的固定颜色 +// 添加一个 Map 来存储每个指标的临时固定颜色 const kpiColors = new Map(); -// 加图表类型的响应式变量 +// 定义图表类型的响应式变量 const chartType = ref<'line' | 'bar'>('line'); // 添加切换图表类型的方法 @@ -235,17 +232,17 @@ const toggleChartType = () => { updateChart(); }; -// 修改 updateChart 函数中的系列配置 +// 更新图表 const updateChart = () => { - if (!chart || !kpiColumns.value.length) return; - + if (!chart || !kpiColumns.value.length) return;//首先检查图表实例和指标是否存在 + //过滤出已选择的指标列 const filteredColumns = kpiColumns.value.filter(col => selectedKPIs.value.includes(col.kpiId)); - const legendData = filteredColumns.map(item => item.title); - + const legendData = filteredColumns.map(item => item.title);//创建图例数据数组,包含所有选中的指标的标题 + //为每个选中的指标创建一个系列配置 const series = filteredColumns.map(item => { const color = kpiColors.get(item.kpiId) || generateColorRGBA(); if (!kpiColors.has(item.kpiId)) { - kpiColors.set(item.kpiId, color); + kpiColors.set(item.kpiId, color);//保持指标颜色的临时一致性 } return { @@ -261,10 +258,10 @@ const updateChart = () => { itemStyle: { color } }; }); - +//图表配置对象 const option = { title: { - text: '网元指标概览', + text: t('views.perfManage.kpiOverView.kpiChartTitle'), left: 'center' }, tooltip: { @@ -273,7 +270,7 @@ const updateChart = () => { return [pt[0], '10%']; }, }, - legend: { + legend: {//图例配置 data: legendData, type: 'scroll', orient: 'horizontal', @@ -288,14 +285,14 @@ const updateChart = () => { height: 50, padding: [5, 10], }, - grid: { + grid: { //网格配置 left: '3%', right: '4%', bottom: '3%', top: 100, containLabel: true }, - xAxis: { + xAxis: { //x轴配置 type: 'category', boundaryGap: false, data: chartData.value.length > 0 @@ -314,7 +311,7 @@ const updateChart = () => { align: 'right' } }, - yAxis: { + yAxis: { // y轴配置 type: 'value', axisLabel: { formatter: '{value}' @@ -324,11 +321,11 @@ const updateChart = () => { // 添加自动计算的最小/最大值围 scale: true }, - series: series + series: series //配置数据 }; - chart.setOption(option); - chart.resize(); + chart.setOption(option);//使用新的配置更新图表 + chart.resize();//调整图表大小以适应容器 // 如果已经有 observer,先断开连接 if (observer) { @@ -378,40 +375,77 @@ onMounted(async () => { } }); -// 定义指标列类型 +// 定义指列类型 interface KPIColumn { title: string; dataIndex: string; key: string; kpiId: string; + neType: string; // 添加网元类型字段 } // 存储指标列信 const kpiColumns = ref([]); -// 添加选中标的的状态 +// 添加选中指标的的状态 const selectedKPIs = ref([]); // 添加对话框可见性状态 const isModalVisible = ref(false); +// 添加临时存储下拉框选择的数组 +const tempSelectedKPIs = ref([]); -// 打开对话框 +// 添加一个变量保存打开对话框时的选择状态 +const originalSelectedKPIs = ref([]); + +// 打开对话框的方法 const showKPISelector = () => { + // 保存当前的选择状态 + originalSelectedKPIs.value = [...selectedKPIs.value]; + + // 初始化临时选择为当前已选择的其他指标 + const primaryKPIs = Object.values(TARGET_KPI_IDS).flat(); + tempSelectedKPIs.value = selectedKPIs.value.filter(kpiId => + !primaryKPIs.includes(kpiId) + ); isModalVisible.value = true; }; -// 添加保存选中指标到 localStorage 的方法 +// 保存选中指标到 localStorage 的方法 const saveSelectedKPIs = () => { localStorage.setItem('selectedKPIs', JSON.stringify(selectedKPIs.value)); }; -// 窗口确认按钮 -const handleModalOk = () => { - saveSelectedKPIs(); // 保存选择 - updateChart(); +// 取消按钮的处理方法 +const handleModalCancel = () => { + // 恢复到打开对话框时的选择状态 + selectedKPIs.value = [...originalSelectedKPIs.value]; + // 清空临时选择 + tempSelectedKPIs.value = []; isModalVisible.value = false; }; -// 取消按钮 -const handleModalCancel = () => { +// 确认按钮的处理方法 +const handleModalOk = () => { + // 获取主要指标列表 + const primaryKPIs = Object.values(TARGET_KPI_IDS).flat(); + + // 获取当前在主界面选中的主要指标 + const selectedPrimaryKPIs = selectedKPIs.value.filter(kpiId => + primaryKPIs.includes(kpiId) + ); + + // 合并选中的主要指标和临时选中的其他指标 + selectedKPIs.value = Array.from(new Set([ + ...selectedPrimaryKPIs, // 只包含已选中的主要指标 + ...tempSelectedKPIs.value // 临时选中的其他指标 + ])); + + // 清空临时选择和原始选择 + tempSelectedKPIs.value = []; + originalSelectedKPIs.value = []; + + // 保存选择并更新图表 + saveSelectedKPIs(); + updateChart(); isModalVisible.value = false; }; @@ -422,57 +456,50 @@ const fetchSpecificKPI = async () => { try { let allKPIs: KPIColumn[] = []; - // 使用 ALL_NE_TYPES 遍历网元类型 + // 1. 获取所有网元的全部指标 for (const neType of ALL_NE_TYPES) { - - const res = await getKPITitle(neType); + const res = await getKPITitle(neType.toUpperCase()); if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) { - // 过滤当前网元类型的指标 - const filteredKPIs = res.data.filter(item => - TARGET_KPI_IDS[neType].some(targetId => - item.kpiId === targetId || // 完全匹配 - item.kpiId.startsWith(targetId) // 前缀匹配 - ) - ); - - // 转换并添加到总指标列表 - const formattedKPIs = filteredKPIs.map(item => ({ + // 转换指标格式 + const formattedKPIs = res.data.map(item => ({ title: item[`${language}Title`], dataIndex: item.kpiId, key: item.kpiId, - kpiId: item.kpiId + kpiId: item.kpiId, + neType: neType // 添加网元类型信息 })); + + // 添加到所有指标数组 allKPIs = [...allKPIs, ...formattedKPIs]; } } - // 更新指标列信息 + // 2. 更新所有指标到 kpiColumns kpiColumns.value = allKPIs; - // 尝试加载保存的选择 + // 3. 尝试加载保存的选择 const savedKPIs = localStorage.getItem('selectedKPIs'); if (savedKPIs) { - // 确保保存的选择仍然存在于前指标中 + // 确保保存的选择仍然存在于当前指标中 const validSavedKPIs = JSON.parse(savedKPIs).filter( (kpiId: string) => kpiColumns.value.some(col => col.kpiId === kpiId) ); if (validSavedKPIs.length > 0) { selectedKPIs.value = validSavedKPIs; } else { - // 如果没有有效的保存选择,则默认全选 - selectedKPIs.value = kpiColumns.value.map(col => col.kpiId); + // 如果没有有效的保存选择,则默认选择��要指标 + selectedKPIs.value = Object.values(TARGET_KPI_IDS).flat(); } } else { - // 如果没有保存的选择,则默认全选 - selectedKPIs.value = kpiColumns.value.map(col => col.kpiId); + // 如果没有保存的选择,则默认选择重要指标 + selectedKPIs.value = Object.values(TARGET_KPI_IDS).flat(); } if (kpiColumns.value.length === 0) { - console.warn('No matching KPIs found'); + console.warn('No KPIs found'); } else { - console.log(`Found ${kpiColumns.value.length} total KPIs:`, - kpiColumns.value.map(kpi => kpi.kpiId)); + console.log(`Found ${kpiColumns.value.length} total KPIs`); } return kpiColumns.value; @@ -483,7 +510,7 @@ const fetchSpecificKPI = async () => { } }; -// 确保只保留一个 onUnmounted 钩子 +// onUnmounted 钩子 onUnmounted(() => { if(ws.value && ws.value.state() === WebSocket.OPEN) { ws.value.close(); @@ -502,7 +529,7 @@ onUnmounted(() => { const { t, currentLocale } = useI18n(); -// 修改 updateChartData 方法,只更新数据而不重新渲染整个图表 +// 更新图表数据方法 const updateChartData = (newData: ChartDataItem) => { chartData.value.push(newData); if (chartData.value.length > 100) { @@ -524,7 +551,7 @@ const updateChartData = (newData: ChartDataItem) => { } }; -// 修改 groupedKPIs 计算属性,使用 TARGET_KPI_IDS 来分组 +// groupedKPIs 计算属性,使用 TARGET_KPI_IDS 来分组过滤 const groupedKPIs = computed(() => { const groups: Record = {}; @@ -532,15 +559,53 @@ const groupedKPIs = computed(() => { // 使用 TARGET_KPI_IDS 中定义的指标 ID 来过滤 const targetIds = TARGET_KPI_IDS[neType]; groups[neType] = kpiColumns.value.filter(kpi => - targetIds.some(targetId => - kpi.kpiId === targetId || // 完全匹配 - kpi.kpiId.startsWith(targetId) // 前缀匹配 - ) + targetIds.includes(kpi.kpiId) ); }); return groups; }); +// 计算其他指标 +const secondaryKPIs = computed(() => { + const groups: Record = {}; + + if (kpiColumns.value.length === 0) { + console.warn('No KPI columns available'); + return groups; + } + + ALL_NE_TYPES.forEach(neType => { + // 获取当前网元类型的主要指标 ID + const primaryIds = TARGET_KPI_IDS[neType]; + + // 从所有指标中筛选出当前网元其他指标 + groups[neType] = kpiColumns.value.filter(kpi => { + // 检查是否不在主要指标列表中 + const isNotPrimary = !primaryIds.includes(kpi.kpiId); + + // 检查是否属于当前网元类型 + // 使用 getKPITitle API 返回的原始数据中的网元类型信息 + const isCurrentNeType = kpi.neType === neType; + + return isCurrentNeType && isNotPrimary; + }); + }); + return groups; +}); + +// 添加处理其他指标选择变化的方法 +const handleSecondaryKPIChange = (kpiId: string, checked: boolean) => { + if (checked) { + // 如果选中,将指标 ID 添加到临时列表 + if (!tempSelectedKPIs.value.includes(kpiId)) { + tempSelectedKPIs.value = [...tempSelectedKPIs.value, kpiId]; + } + } else { + // 如果取消选中,从临时列表中移除指标 ID + tempSelectedKPIs.value = tempSelectedKPIs.value.filter(id => id !== kpiId); + } +}; +