From 45d8314e290b502056b71c1a4ec062ca2daf7a94 Mon Sep 17 00:00:00 2001 From: zhongzm Date: Fri, 22 Nov 2024 15:43:00 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E6=9A=97=E8=89=B2=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E6=A0=B7=E5=BC=8F=E9=80=82=E5=BA=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/perfManage/kpiOverView/index.vue | 178 ++++++++++++++++++++- 1 file changed, 174 insertions(+), 4 deletions(-) diff --git a/src/views/perfManage/kpiOverView/index.vue b/src/views/perfManage/kpiOverView/index.vue index da865a72..3ab8f8b6 100644 --- a/src/views/perfManage/kpiOverView/index.vue +++ b/src/views/perfManage/kpiOverView/index.vue @@ -14,6 +14,7 @@ import { OptionsType, WS } from '@/plugins/ws-websocket'; import { generateColorRGBA } from '@/utils/generate-utils'; import { LineOutlined } from '@ant-design/icons-vue'; import { TableColumnType } from 'ant-design-vue'; +import { viewTransitionTheme } from 'antdv-pro-layout'; const { t, currentLocale } = useI18n(); //定义KPI接口 interface KPIBase{ @@ -69,8 +70,8 @@ const ranges = ref([ ]) //日期范围响应式变量 const dateRange = ref<[string, string]>([ - dayjs().startOf('hour').valueOf().toString(), - dayjs().endOf('hour').valueOf().toString(), + dayjs().subtract(1, 'hour').startOf('hour').valueOf().toString(), // 上一小时开始 + dayjs().startOf('hour').add(1, 'hour').valueOf().toString(), // 当前小时结束 ]); //实时数据状态 const isRealtime = ref(false); @@ -265,6 +266,134 @@ const getSeriesConfig = () => ({ smooth:0.6, showSymbol: true, }); +// 添加一个函数来获取当前主题下的网格线颜色 +const getSplitLineColor = () => { + return document.documentElement.getAttribute('data-theme') === 'dark' + ? '#333333' + : '#E8E8E8'; // 亮色模式返回 undefined,使用默认颜色 +}; + +// 添加主题变化的观察器 +const themeObserver = new MutationObserver(() => { + if (chart) { + // 获取当前的主题色 + const splitLineColor = getSplitLineColor(); + + // 重新设置完整的图表配置并触发重新渲染 + requestAnimationFrame(() => { + const option = { + title: { + text: t('views.perfManage.kpiOverView.kpiChartTitle'), + left: 'center', + textStyle: { + color: document.documentElement.getAttribute('data-theme') === 'dark' + ? '#CACADA' + : '#333' + } + }, + xAxis: { + // 保持现有的 xAxis 配置 + type: 'category', + boundaryGap: false, + data: chartData.value.map(item => + dayjs(Number(item.date)).format('YYYY-MM-DD HH:mm:ss') + ), + axisLabel: { + color: document.documentElement.getAttribute('data-theme') === 'dark' + ? '#CACADA' + : '#333' + }, + splitLine: { + show: true, + lineStyle: { + color: splitLineColor + } + } + }, + yAxis: { + type: 'value', + axisLabel: { + formatter: '{value}', + color: document.documentElement.getAttribute('data-theme') === 'dark' + ? '#CACADA' + : '#333' + }, + splitNumber: 5, + scale: true, + splitLine: { + show: true, + lineStyle: { + color: splitLineColor + } + } + }, + legend: { + show: false, + selected: Object.fromEntries( + selectedKPIs.value.map(kpiId => [ + kpiColumns.value.find(col => col.kpiId === kpiId)?.title || kpiId, + selectedRow.value ? kpiId === selectedRow.value : true + ]) + ) + }, + 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]; + }, + 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' + }, + extraCssText: 'box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);' + }, + // 重新设置系列数据 + series: selectedKPIs.value.map(kpiId => { + const kpi = kpiColumns.value.find(col => col.kpiId === kpiId); + if (!kpi) return null; + const color = kpiColors.get(kpiId) || generateColorRGBA(); + return { + name: kpi.title, + type: 'line', + data: chartData.value.map(item => item[kpiId] || 0), + itemStyle: { color }, + ...getSeriesConfig(), + }; + }).filter(Boolean) + }; + + // 使用新的配置更新图表 + chart!.setOption(option, true); + // 强制重新渲染 + chart!.resize(); + }); + } +}); const updateChart = () => { if (!chart || !kpiColumns.value.length) return; @@ -299,6 +428,12 @@ const updateChart = () => { title: { text: t('views.perfManage.kpiOverView.kpiChartTitle'), left: 'center', + // 添加文字颜色配置,根据主题切换 + textStyle: { + color: document.documentElement.getAttribute('data-theme') === 'dark' + ? '#CACADA' + : '#333' + } }, tooltip: { trigger: 'axis', @@ -323,6 +458,18 @@ const updateChart = () => { // 默认向右显示,垂直居中 return [x + 10, y + verticalOffset]; }, + 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' + }, + extraCssText: 'box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);' }, legend: { data: selectedKPIs.value.map(kpiId => @@ -356,11 +503,16 @@ const updateChart = () => { xAxis: { // 指定x轴类型为类目轴,适用于离散的类目数据 type: 'category', + axisLabel: { + formatter: '{value}', + color: document.documentElement.getAttribute('data-theme') === 'dark' + ? '#CACADA' + : '#333' + }, splitLine: { show: true, lineStyle: { - // 使用深浅的间隔色 - color: '#aaa', + color: getSplitLineColor() } }, //控制坐标轴两边留白 @@ -402,11 +554,20 @@ const updateChart = () => { type: 'value', axisLabel: { formatter: '{value}', + color: document.documentElement.getAttribute('data-theme') === 'dark' + ? '#CACADA' + : '#333' }, // 添加自���计算的分割段数 splitNumber: 5, // 添加自动计算的最小/最大值范围 scale: true, + splitLine: { + show: true, + lineStyle: { + color: getSplitLineColor() + } + } }, series: series, //配置数据 }; @@ -435,6 +596,8 @@ const updateChart = () => { } }; + + //钩子函数 onMounted(async () => { try { @@ -457,6 +620,11 @@ onMounted(async () => { } else { console.error('Chart container not found'); } + // 添加主题观察器 + themeObserver.observe(document.documentElement, { + attributes: true, + attributeFilter: ['data-theme'] + }); } catch (error) { console.error('Failed to initialize:', error); message.error(t('common.initFail')); @@ -525,6 +693,8 @@ onUnmounted(() => { chart.dispose(); chart = null; } + // 断开主题观察器 + themeObserver.disconnect(); }); // 实时数据更新图表数据方法