From a5beddb872d08e9f738702f4613d5545c6d58ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E6=9D=B0?= Date: Sat, 28 Jun 2025 14:46:57 +0800 Subject: [PATCH] =?UTF-8?q?=E8=82=A1=E7=A5=A8=E6=95=B0=E6=8D=AE=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E5=88=B0=E4=BC=9A=E8=AF=9D=EF=BC=9B=E9=87=8D=E6=96=B0?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=9B=BE=E8=A1=A8=E7=9A=84=E6=96=B9=E6=B3=95?= =?UTF-8?q?=EF=BC=9B=E6=83=85=E7=BB=AA=E5=A4=A7=E6=A8=A1=E5=9E=8B=E5=8F=96?= =?UTF-8?q?=E6=B6=88=E8=87=AA=E5=8A=A8=E6=BB=9A=E5=8A=A8=EF=BC=9B=E5=9B=BE?= =?UTF-8?q?=E8=A1=A8=E8=B6=85=E5=87=BA=E5=AE=B9=E5=99=A8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/emotion.ts | 2 +- src/utils/chartResize.js | 131 +++++++ src/views/AiEmotion.vue | 474 +++++++++++++++++++++----- src/views/components/emoEnergyConverter.vue | 79 ++++- src/views/components/emotionDecod.vue | 100 +++++- src/views/components/emotionalBottomRadar.vue | 56 ++- src/views/components/marketTemperature.vue | 67 +++- 7 files changed, 773 insertions(+), 136 deletions(-) create mode 100644 src/utils/chartResize.js diff --git a/src/store/emotion.ts b/src/store/emotion.ts index a44ca17..8435fee 100644 --- a/src/store/emotion.ts +++ b/src/store/emotion.ts @@ -10,7 +10,7 @@ export const useEmotionStore = defineStore('emotion', { }), persist: { key: 'emotion-store', - storage: localStorage, + storage: sessionStorage, paths: ['history', 'stockList', 'activeStockIndex'] }, getters: { diff --git a/src/utils/chartResize.js b/src/utils/chartResize.js new file mode 100644 index 0000000..ef0623c --- /dev/null +++ b/src/utils/chartResize.js @@ -0,0 +1,131 @@ +/** + * 图表响应式工具函数 + * 统一处理ECharts图表的响应式调整 + */ + +/** + * 防抖函数 + * @param {Function} func 要防抖的函数 + * @param {number} wait 防抖延迟时间(毫秒) + * @returns {Function} 防抖后的函数 + */ +export function debounce(func, wait = 100) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} + +/** + * 创建图表响应式处理器 + * @param {Object} options 配置选项 + * @param {Object} options.chart ECharts图表实例 + * @param {Object} options.container 图表容器DOM元素 + * @param {Object} options.option 图表配置项 + * @param {Function} options.beforeResize 在resize前执行的回调函数 + * @param {string} options.name 图表名称(用于日志) + * @returns {Object} 包含清理函数的对象 + */ +export function createChartResizeHandler(options) { + const { chart, container, option, beforeResize, name = '图表' } = options; + + if (!chart || !container) { + console.warn(`${name}: 图表实例或容器不存在`); + return { cleanup: () => {} }; + } + + // 图表resize处理函数 + const handleResize = debounce(() => { + if (chart && !chart.isDisposed()) { + try { + // 执行resize前的回调 + if (typeof beforeResize === 'function') { + beforeResize(); + } + + // 如果有配置项,重新设置以确保布局更新 + if (option) { + chart.setOption(option, true); + } + + // 调用图表resize方法 + chart.resize(); + + console.log(`${name}响应式调整完成`); + } catch (error) { + console.error(`${name}响应式调整失败:`, error); + } + } + }, 100); + + // 窗口resize监听器 + const windowResizeHandler = handleResize; + + // 容器resize观察器 + let containerObserver = null; + if (window.ResizeObserver) { + containerObserver = new ResizeObserver(handleResize); + containerObserver.observe(container); + } + + // 添加窗口resize监听 + window.addEventListener('resize', windowResizeHandler); + + // 返回清理函数 + return { + cleanup: () => { + // 移除窗口resize监听 + window.removeEventListener('resize', windowResizeHandler); + + // 断开容器观察器 + if (containerObserver) { + containerObserver.disconnect(); + containerObserver = null; + } + + console.log(`${name}响应式监听器已清理`); + }, + + // 手动触发resize + triggerResize: handleResize + }; +} + +/** + * 为图表容器添加响应式样式 + * @param {HTMLElement} container 图表容器元素 + */ +export function applyResponsiveStyles(container) { + if (!container) return; + + const styles = { + width: '100%', + boxSizing: 'border-box', + overflow: 'hidden', + margin: '0', + padding: '0' + }; + + Object.assign(container.style, styles); +} + +/** + * 检查图表容器是否具有响应式样式 + * @param {HTMLElement} container 图表容器元素 + * @returns {boolean} 是否具有响应式样式 + */ +export function checkResponsiveStyles(container) { + if (!container) return false; + + const computedStyle = window.getComputedStyle(container); + const hasResponsiveWidth = computedStyle.width === '100%' || computedStyle.width.includes('%'); + const hasBoxSizing = computedStyle.boxSizing === 'border-box'; + const hasOverflowHidden = computedStyle.overflow === 'hidden'; + + return hasResponsiveWidth && hasBoxSizing && hasOverflowHidden; +} \ No newline at end of file diff --git a/src/views/AiEmotion.vue b/src/views/AiEmotion.vue index ec7cb85..2ecbbee 100644 --- a/src/views/AiEmotion.vue +++ b/src/views/AiEmotion.vue @@ -53,7 +53,7 @@
温度计图标 - 股票温度计 + 股市温度计
股票温度:{{ data2 ?? "NA" }}
@@ -1185,54 +1185,11 @@ function isDataLoaded() { return true; } -// 自动滚动函数 +// 自动滚动函数(已禁用) function startAutoScroll() { - if (isAutoScrolling.value) return; - - // 检查数据是否已加载完成 - if (!isDataLoaded()) { - console.log('数据尚未加载完成,延迟1秒后重试'); - setTimeout(() => { - startAutoScroll(); - }, 1000); - return; - } - - isAutoScrolling.value = true; - console.log('开始流畅自动滚动'); - - // 获取页面总高度 - const documentHeight = document.documentElement.scrollHeight; - const windowHeight = window.innerHeight; - const maxScrollTop = documentHeight - windowHeight; - - // 滚动参数 - const scrollDuration = 15000; // 总滚动时间15秒 - const scrollStep = maxScrollTop / (scrollDuration / 50); // 每50ms滚动的距离 - let currentScrollTop = 0; - - function smoothScroll() { - if (currentScrollTop < maxScrollTop) { - currentScrollTop += scrollStep; - if (currentScrollTop > maxScrollTop) { - currentScrollTop = maxScrollTop; - } - - window.scrollTo({ - top: currentScrollTop, - behavior: 'auto' // 使用auto而不是smooth,因为我们自己控制滚动 - }); - - // 继续滚动 - setTimeout(smoothScroll, 50); - } else { - console.log('流畅自动滚动完成'); - isAutoScrolling.value = false; - } - } - - // 延迟1秒开始滚动 - setTimeout(smoothScroll, 1000); + // 自动滚动功能已被禁用 + console.log('自动滚动功能已被禁用'); + return; } // 设置Intersection Observer监听场景应用部分 @@ -1325,23 +1282,11 @@ function setupIntersectionObserver() { intersectionObserver.value = observer; } -// 手动触发自动滚动 +// 手动触发自动滚动(已禁用) function triggerAutoScroll() { - // 检查是否正在滚动 - if (isAutoScrolling.value) { - console.log('自动滚动正在进行中,请稍候'); - return; - } - - // 检查数据是否已准备好 - if (!isDataLoaded()) { - console.log('数据尚未准备完成,请等待数据加载后再试'); - // 可以显示提示信息给用户 - return; - } - - console.log('手动触发自动滚动'); - startAutoScroll(); + // 自动滚动功能已被禁用 + console.log('自动滚动功能已被禁用'); + return; } // 页面挂载完成后触发图片旋转和设置滚动监听 @@ -1349,10 +1294,77 @@ onMounted(async () => { // 确保获取用户次数 try { await chatStore.getUserCount(); - console.log('情绪大模型页面:用户次数获取成功'); + console.log('情绪大模型页面:用户次数获取成功'); } catch (error) { console.error('情绪大模型页面:获取用户次数失败', error); } + + // 添加全局resize监听器,确保所有图表和容器响应页面宽度变化 + const globalResizeHandler = debounce(() => { + console.log('AiEmotion页面:窗口大小变化,触发容器和图表resize'); + + // 强制重新计算容器布局 + const mainContainer = document.querySelector('.class01'); + if (mainContainer) { + // 触发重排,确保容器尺寸正确更新 + mainContainer.style.display = 'none'; + mainContainer.offsetHeight; // 强制重排 + mainContainer.style.display = ''; + } + + // 触发所有图表组件的resize + const resizeHandlers = [ + window.emoEnergyConverterResizeHandler, + window.marketTempResizeHandler, + window.emotionalBottomRadarResizeHandler, + window.emotionDecodResizeHandler + ]; + + resizeHandlers.forEach(handler => { + if (typeof handler === 'function') { + try { + handler(); + } catch (error) { + console.error('AiEmotion页面:图表resize失败', error); + } + } + }); + + // 延迟再次触发图表resize,确保容器尺寸稳定后图表能正确适配 + setTimeout(() => { + resizeHandlers.forEach(handler => { + if (typeof handler === 'function') { + try { + handler(); + } catch (error) { + console.error('AiEmotion页面:延迟图表resize失败', error); + } + } + }); + }, 100); + }, 150); // 150ms防抖延迟 + + // 移除之前的监听器(如果存在) + if (window.aiEmotionGlobalResizeHandler) { + window.removeEventListener('resize', window.aiEmotionGlobalResizeHandler); + } + + // 添加新的监听器 + window.addEventListener('resize', globalResizeHandler); + window.aiEmotionGlobalResizeHandler = globalResizeHandler; + + // 防抖函数定义 + function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + } startImageRotation(); @@ -1406,6 +1418,12 @@ onUnmounted(() => { intersectionObserver.value.disconnect(); intersectionObserver.value = null; } + + // 清理全局resize监听器 + if (window.aiEmotionGlobalResizeHandler) { + window.removeEventListener('resize', window.aiEmotionGlobalResizeHandler); + window.aiEmotionGlobalResizeHandler = null; + } }); // 声明组件可以触发的事件 @@ -1432,6 +1450,26 @@ defineExpose({ .class003 { padding-top: 8%; padding-left: 10%; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.div00 { + display: flex; + flex-direction: row; + gap: 2%; + justify-content: flex-start; + align-items: center; + flex-wrap: wrap; + width: 100%; + box-sizing: border-box; +} + +.div00::after { + content: ""; + display: table; + clear: both; } .class003 .div02 { @@ -1439,16 +1477,15 @@ defineExpose({ background-repeat: no-repeat; background-size: 100% 100%; width: 35%; + min-width: 200px; min-height: 40px; - float: left; - margin-left: 9%; - margin-top: 2%; text-align: center; font-size: 24px; color: white; display: flex; justify-content: center; align-items: center; + flex-shrink: 0; } .class003 .div01 { @@ -1456,15 +1493,15 @@ defineExpose({ background-repeat: no-repeat; background-size: 100% 100%; width: 35%; + min-width: 200px; min-height: 40px; - float: left; - margin-left: 9%; text-align: center; font-size: 24px; color: white; display: flex; justify-content: center; align-items: center; + flex-shrink: 0; } .golden-wheel { @@ -1516,7 +1553,6 @@ defineExpose({ background: linear-gradient(135deg, rgba(0, 212, 255, 0.15) 0%, rgba(0, 100, 200, 0.15) 100%); border: 2px solid rgba(0, 212, 255, 0.4); box-shadow: 0 8px 25px rgba(0, 212, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1); - backdrop-filter: blur(15px); .conclusion-item { margin-bottom: 20px; @@ -1624,7 +1660,6 @@ defineExpose({ background: linear-gradient(135deg, rgba(0, 212, 255, 0.15) 0%, rgba(0, 100, 200, 0.15) 100%); border: 2px solid rgba(0, 212, 255, 0.4); box-shadow: 0 8px 25px rgba(0, 212, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1); - backdrop-filter: blur(15px); } .text-container p { @@ -1854,13 +1889,19 @@ defineExpose({ /* 确保背景图片完整显示 */ background-repeat: no-repeat; /* 防止背景图片重复 */ - width: 95%; - /* 设置容器宽度 */ + width: 100%; + /* 响应式容器宽度 */ + max-width: 100%; + /* 确保不超出父容器 */ height: auto; /* 高度根据内容动态变化 */ min-height: 69rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; + box-sizing: border-box; + /* 包括内边距在宽度计算中 */ + transition: all 0.3s ease; + /* 添加平滑过渡效果 */ } .class05 { @@ -1870,13 +1911,19 @@ defineExpose({ /* 确保背景图片完整显示 */ background-repeat: no-repeat; /* 防止背景图片重复 */ - width: 95%; - /* 设置容器宽度 */ + width: 100%; + /* 响应式容器宽度 */ + max-width: 100%; + /* 确保不超出父容器 */ height: auto; /* 高度根据内容动态变化 */ min-height: 90rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; + box-sizing: border-box; + /* 包括内边距在宽度计算中 */ + transition: all 0.3s ease; + /* 添加平滑过渡效果 */ } .class04 { @@ -1886,13 +1933,19 @@ defineExpose({ /* 确保背景图片完整显示 */ background-repeat: no-repeat; /* 防止背景图片重复 */ - width: 95%; - /* 设置容器宽度 */ + width: 100%; + /* 响应式容器宽度 */ + max-width: 100%; + /* 确保不超出父容器 */ height: auto; /* 高度根据内容动态变化 */ min-height: 75rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; + box-sizing: border-box; + /* 包括内边距在宽度计算中 */ + transition: all 0.3s ease; + /* 添加平滑过渡效果 */ } .class03 { @@ -1903,17 +1956,18 @@ defineExpose({ background-repeat: no-repeat; /* 防止背景图片重复 */ width: 100%; - /* 设置容器宽度 */ + /* 响应式容器宽度 */ + max-width: 100%; + /* 确保不超出父容器 */ height: auto; /* 高度根据内容动态变化 */ min-height: 70rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; - /* display: flex; - flex-direction:row; - align-items: center; - padding: 1rem; - gap: 1rem; */ + box-sizing: border-box; + /* 包括内边距在宽度计算中 */ + transition: all 0.3s ease; + /* 添加平滑过渡效果 */ } .class00 { @@ -1921,13 +1975,19 @@ defineExpose({ /* 确保背景图片完整显示 */ background-repeat: no-repeat; /* 防止背景图片重复 */ - width: 95%; - /* 设置容器宽度 */ + width: 100%; + /* 响应式容器宽度 */ + max-width: 100%; + /* 确保不超出父容器 */ height: auto; /* 高度根据内容动态变化 */ min-height: 55rem; /* 设置最小高度,确保图片显示 */ margin: 0 auto; + box-sizing: border-box; + /* 包括内边距在宽度计算中 */ + transition: all 0.3s ease; + /* 添加平滑过渡效果 */ } .content1 { @@ -1955,7 +2015,7 @@ defineExpose({ display: flex; flex-direction: column; /* 竖向排列元素 */ - margin-left: 37%; + margin-left: 15%; gap: 1rem; margin-top: -12%; width: 100%; @@ -1992,18 +2052,25 @@ defineExpose({ } .class01 { - width: 100%; - /* 固定容器宽度 */ + width: 90%; + /* 响应式容器宽度 */ + max-width: 1400px; + /* 设置最大宽度,避免在大屏幕上过度拉伸 */ + min-width: 320px; + /* 设置最小宽度,确保在小屏幕上可用 */ min-height: 100px; /* 设置最小高度,确保初始显示 */ height: auto; /* 高度根据内容动态变化 */ + padding: 1rem; /* 添加内边距,确保内容与边界有间距 */ box-sizing: border-box; /* 包括内边距在宽度和高度计算中 */ - background-color: #02107d; + background-color: #2b378d; margin: 0 auto; /* 居中容器 */ + transition: width 0.3s ease; + /* 添加平滑过渡效果 */ margin-bottom: 10rem; } @@ -2095,8 +2162,115 @@ defineExpose({ background-color: #0056b3; } +/* 响应式布局媒体查询 */ +@media only screen and (max-width: 1200px) { + .class01 { + width: 95%; + padding: 0.8rem; + } + + .span01 { + width: 40%; + font-size: 1.3rem; + } + + .span02 { + font-size: 1.3rem; + } + + /* 调整图表容器高度 */ + .class00 { + min-height: 45rem; + } + + .class03 { + min-height: 60rem; + } + + .class04 { + min-height: 65rem; + } + + .class05 { + min-height: 75rem; + } + + .class06 { + min-height: 58rem; + } + + .class08 { + min-height: 42rem; + } + + .scaled-img { + height: 350px; + min-height: 30rem; + } +} + +@media only screen and (max-width: 992px) { + .class01 { + width: 98%; + padding: 0.6rem; + } + + .class003 { + padding-top: 6%; + padding-left: 5%; + } + + .div00 { + gap: 1%; + justify-content: center; + } + + .class003 .div01, + .class003 .div02 { + width: 45%; + min-width: 180px; + font-size: 20px; + } + + /* 调整图表容器高度 */ + .class00 { + min-height: 40rem; + } + + .class03 { + min-height: 55rem; + } + + .class04 { + min-height: 55rem; + } + + .class05 { + min-height: 65rem; + } + + .class06 { + min-height: 50rem; + } + + .class08 { + min-height: 35rem; + } + + .scaled-img { + height: 300px; + min-height: 25rem; + } +} + /* 手机端适配样式 */ @media only screen and (max-width: 768px) { + .class01 { + width: 100%; + padding: 0.5rem; + margin-bottom: 5rem; + } + .container { padding-top: 2%; } @@ -2232,6 +2406,23 @@ defineExpose({ /* margin-left: -39px; */ /* min-height: 38rem; */ } + + /* 调整其他图表容器高度 */ + .class00 { + min-height: 35rem; + } + + .class03 { + min-height: 45rem; + } + + .class05 { + min-height: 48rem; + } + + .class06 { + min-height: 35rem; + } .class02 .container img { width: 68%; @@ -2543,6 +2734,108 @@ defineExpose({ .class0601 { padding-top: 10%; } + + .class003 { + padding-top: 4%; + padding-left: 2%; + } + + .div00 { + flex-direction: column; + gap: 1rem; + align-items: center; + } + + .class003 .div01, + .class003 .div02 { + width: 80%; + min-width: 250px; + font-size: 16px; + min-height: 35px; + } + + .span01 { + width: 60%; + font-size: 1.2rem; + padding: 8px; + } + + .span02 { + font-size: 1.2rem; + margin-top: -3%; + } + + .title1, .title2, .title3, .title4 { + font-size: 18px; + margin-left: 0; + } +} + +/* 超小屏幕设备 */ +@media only screen and (max-width: 480px) { + .class01 { + width: 100%; + padding: 0.3rem; + margin-bottom: 3rem; + } + + .div00 { + flex-direction: column; + gap: 0.8rem; + align-items: center; + } + + .class003 .div01, + .class003 .div02 { + width: 90%; + min-width: 200px; + font-size: 14px; + min-height: 30px; + } + + .span01 { + width: 70%; + font-size: 1rem; + padding: 6px; + } + + .span02 { + font-size: 1rem; + } + + .golden-wheel-img { + width: 80%; + } + + /* 调整图表容器高度适配超小屏幕 */ + .class00 { + min-height: 25rem; + } + + .class03 { + min-height: 35rem; + } + + .class04 { + min-height: 30rem; + } + + .class05 { + min-height: 35rem; + } + + .class06 { + min-height: 25rem; + } + + .class08 { + min-height: 15rem; + } + + .scaled-img { + height: 150px; + min-height: 150px; + } } /* 加载提示样式 */ @@ -2560,7 +2853,6 @@ defineExpose({ border: 2px solid rgba(0, 212, 255, 0.4); border-radius: 20px; padding: 40px; - backdrop-filter: blur(15px); box-shadow: 0 8px 25px rgba(0, 212, 255, 0.3); } diff --git a/src/views/components/emoEnergyConverter.vue b/src/views/components/emoEnergyConverter.vue index 286e30b..cf98511 100644 --- a/src/views/components/emoEnergyConverter.vue +++ b/src/views/components/emoEnergyConverter.vue @@ -538,33 +538,96 @@ function initQXNLZHEcharts(kline, qxnlzhqData) { }; // 应用配置 qxnlzhqEchartsInstance.setOption(option); + + // 防抖函数,避免频繁触发resize + const debounce = (func, wait) => { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + // 监听窗口大小变化,调整图表尺寸 - window.addEventListener('resize', () => { - qxnlzhqEchartsInstance.resize() - }) + const resizeHandler = debounce(() => { + if (qxnlzhqEchartsInstance && !qxnlzhqEchartsInstance.isDisposed()) { + try { + qxnlzhqEchartsInstance.resize(); + console.log('情绪能量转化器图表已重新调整大小'); + } catch (error) { + console.error('情绪能量转化器图表resize失败:', error); + } + } + }, 100); // 100ms防抖延迟 + + // 移除之前的监听器(如果存在) + if (window.emoEnergyConverterResizeHandler) { + window.removeEventListener('resize', window.emoEnergyConverterResizeHandler); + } + + // 添加新的监听器 + window.addEventListener('resize', resizeHandler); + + // 存储resize处理器以便后续清理 + window.emoEnergyConverterResizeHandler = resizeHandler; + + // 添加容器大小监听器 + if (qxnlzhqEchartsRef.value && window.ResizeObserver) { + const containerObserver = new ResizeObserver(debounce(() => { + if (qxnlzhqEchartsInstance && !qxnlzhqEchartsInstance.isDisposed()) { + try { + qxnlzhqEchartsInstance.resize(); + console.log('情绪能量转化器容器大小变化,图表已调整'); + } catch (error) { + console.error('情绪能量转化器容器resize失败:', error); + } + } + }, 100)); + + containerObserver.observe(qxnlzhqEchartsRef.value); + window.emoEnergyConverterContainerObserver = containerObserver; + } } onBeforeUnmount(() => { // 组件卸载时销毁图表 if (qxnlzhqEchartsInstance) { qxnlzhqEchartsInstance.dispose(); + qxnlzhqEchartsInstance = null; + } + + // 移除窗口resize监听器 + if (window.emoEnergyConverterResizeHandler) { + window.removeEventListener('resize', window.emoEnergyConverterResizeHandler); + window.emoEnergyConverterResizeHandler = null; + } + + // 清理容器观察器 + if (window.emoEnergyConverterContainerObserver) { + window.emoEnergyConverterContainerObserver.disconnect(); + window.emoEnergyConverterContainerObserver = null; } }); \ No newline at end of file diff --git a/src/views/components/marketTemperature.vue b/src/views/components/marketTemperature.vue index f5f5d40..f83f0ed 100644 --- a/src/views/components/marketTemperature.vue +++ b/src/views/components/marketTemperature.vue @@ -375,18 +375,61 @@ function initChart(raw, klineDataRawValue, WDRLValue) { filterMode: 'filter' }] }) + // 防抖函数,避免频繁触发resize + const debounce = (func, wait) => { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + // 监听窗口大小变化 - const resizeHandler = () => { - if (chartInstance) { - chartInstance.resize() + const resizeHandler = debounce(() => { + if (chartInstance && !chartInstance.isDisposed()) { + try { + chartInstance.resize(); + adjustCellFontSize(); // 同时调整表格字体大小 + console.log('股市温度计图表已重新调整大小'); + } catch (error) { + console.error('股市温度计图表resize失败:', error); + } } + }, 100); // 100ms防抖延迟 + + // 移除之前的监听器(如果存在) + if (window.marketTempResizeHandler) { + window.removeEventListener('resize', window.marketTempResizeHandler); } - window.addEventListener('resize', resizeHandler) - + + // 添加新的监听器 + window.addEventListener('resize', resizeHandler); + // 存储resize处理器以便后续清理 - if (!window.marketTempResizeHandler) { - window.marketTempResizeHandler = resizeHandler + window.marketTempResizeHandler = resizeHandler; + + // 添加容器大小监听器 + const chartContainer = document.querySelector('.KlineClass'); + if (chartContainer && window.ResizeObserver) { + const containerObserver = new ResizeObserver(debounce(() => { + if (chartInstance && !chartInstance.isDisposed()) { + try { + chartInstance.resize(); + console.log('股市温度计容器大小变化,图表已调整'); + } catch (error) { + console.error('股市温度计容器resize失败:', error); + } + } + }, 100)); + + containerObserver.observe(chartContainer); + window.marketTempContainerObserver = containerObserver; } + // 初始调整字体大小 adjustCellFontSize() } @@ -420,6 +463,12 @@ onBeforeUnmount(() => { window.removeEventListener('resize', window.marketTempResizeHandler) window.marketTempResizeHandler = null } + + // 清理容器观察器 + if (window.marketTempContainerObserver) { + window.marketTempContainerObserver.disconnect(); + window.marketTempContainerObserver = null; + } }) defineExpose({ initChart }) @@ -476,9 +525,11 @@ defineExpose({ initChart }) margin-top: 40px; border-radius: 8px; padding: 20px; - margin-left: -2rem; + margin-left: 0; width: 100%; height: 100%; + box-sizing: border-box; + overflow: hidden; } .border4 {