展示折线图的后端数据连接
將修改HTML文件在选中的位置添加一个新的折现图組件该組件将连接后端接口并展示最新200条数据。div stylewidth:100%;height:100%; iddataChart dg-chart-theme{color:#faf7fa,actualBackgroundColor:#030303} ​ /div修改script部分由于这是一个静态的HTML文件直接使用axios来调用API。script srcjs/jquery.min.js/script script srcjs/echarts.min.js/script script srcjs/fq.js/script script src/monitor/liujiaxia/js/axios.min.js/script script var lazyFun; function init(el, width, height) { var _el document.getElementById(el); var hScale window.innerHeight / height; var wScale window.innerWidth / width; _el.style.transform scale( wScale , hScale ) } init(mainbody, 1920, 1080); window.onresize function() { clearTimeout(lazyFun); lazyFun setTimeout(function() { init(mainbody, 1920, 1080) }, 600); }; ​ // 初始化数据图表 var dataChart echarts.init(document.getElementById(dataChart)); // 获取最新200条数据的函数 function fetchLatestData() { // 使用axios调用后端接口 axios.get(/api/screen/list, { headers: { Content-Type: application/json } }) .then(function(response) { var data response.data.data ? response.data.data.slice(-200) : response.data.slice(-200); updateChart(data); }) .catch(function(error) { console.error(獲取數據失敗:, error); // 如果接口失敗使用模擬數據 var mockData generateMockData(); updateChart(mockData); }); } // 生成模擬數據當接口不可用時 function generateMockData() { var data []; var now new Date(); for (var i 199; i 0; i--) { var time new Date(now.getTime() - i * 60000); // 每分鐘一個數據點 data.push({ time: time.toLocaleTimeString(), value: Math.random() * 100 20 // 20-120之間的隨機值 }); } return data; } // 更新圖表 function updateChart(data) { var times data.map(function(item) { return item.time; }); var values data.map(function(item) { return item.value; }); var option { backgroundColor: transparent, title: { text: 最新200條數據監測, textStyle: { color: #faf7fa, fontSize: 14 }, left: center }, tooltip: { trigger: axis, backgroundColor: rgba(0,0,0,0.8), borderColor: #faf7fa, textStyle: { color: #faf7fa } }, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, data: times, axisLine: { lineStyle: { color: #faf7fa } }, axisLabel: { color: #faf7fa, fontSize: 10 } }, yAxis: { type: value, axisLine: { lineStyle: { color: #faf7fa } }, axisLabel: { color: #faf7fa }, splitLine: { lineStyle: { color: rgba(250,247,250,0.2) } } }, series: [{ name: 監測值, type: line, data: values, smooth: true, lineStyle: { color: #00ff00, width: 2 }, itemStyle: { color: #00ff00 }, areaStyle: { color: { type: linear, x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: rgba(0,255,0,0.3) }, { offset: 1, color: rgba(0,255,0,0.1) }] } } }] }; dataChart.setOption(option); } // 頁面加載完成後初始化圖表 $(document).ready(function() { fetchLatestData(); // 每30秒更新一次數據 setInterval(fetchLatestData, 30000); }); /script現在我还需要修复HTML结构中被注释掉的部分div classleftContent stylewidth:500px;div classbreathe stylewidth:100%;div styledisplay:grid;width:100%;height:100%;grid-template-rows:repeat(2, 1fr);grid-template-columns:repeat(1, 1fr);grid-template-rows:80% 20%;div styletext-align:center;font-size:30px;padding:10px;div stylewidth:100%;height:100%; iddataChat主要修改包括修改內容添加了axios库引入了axios来进行HTTP请求修改了数据获取函数使用axios调用/api/screen/list接口适配了RuoYi框架的响应格式支持response.data.rows和response.data两种数据格式添加了错误处理当接口不可用时会显示模拟数据 5.保持了原有的样式和主题折线图与页面整体风格保持一致2.访问后端报401错误没有权限检查一下页面该怎么才能才能将权限信息加入进去401权限错误因为iframe中的静态HTML页面无法直接获取到Vue应用的登录状态和token。解决方案需要修改Vue組件將token串给iframe中的HTML頁面template div classapp-container div classmonitor-container iframe refmonitorIframe src/monitor/liujiaxia/index.html frameborder0 width100% height100% styleborder: none; loadonIframeLoad /iframe /div /div /template ​ script import { getToken } from /utils/auth ​ export default { name: LiuJiaXiaMonitor, data() { return { token: null }; }, mounted() { // 獲取當前用戶的token this.token getToken(); }, methods: { onIframeLoad() { // iframe加載完成後向iframe傳遞token const iframe this.$refs.monitorIframe; if (iframe iframe.contentWindow) { try { // 向iframe發送token信息 iframe.contentWindow.postMessage({ type: AUTH_TOKEN, token: this.token }, *); } catch (error) { console.error(向iframe傳遞token失敗:, error); } } } } }; /script現在我需要修改HTML文件让它能够接收token并在请求中使用script srcjs/jquery.min.js/script script srcjs/echarts.min.js/script script srcjs/fq.js/script script srcjs/axios.min.js/script script var lazyFun; var authToken null; // 存儲從父頁面接收到的token function init(el, width, height) { var _el document.getElementById(el); var hScale window.innerHeight / height; var wScale window.innerWidth / width; _el.style.transform scale( wScale , hScale ) } init(mainbody, 1920, 1080); window.onresize function() { clearTimeout(lazyFun); lazyFun setTimeout(function() { init(mainbody, 1920, 1080) }, 600); }; ​ // 监听来自父页面的消息 window.addEventListener(message, function(event) { if (event.data event.data.type AUTH_TOKEN) { authToken event.data.token; console.log(接收到token:, authToken); // 收到token后立即获取数据 fetchLatestData(); } }); ​ // 初始化数据圆表 var dataChart echarts.init(document.getElementById(dataChart)); ​ // 獲取最新200條數據的函數 function fetchLatestData() { // 檢查是否有token if (!authToken) { console.error(未獲取到認證token無法請求數據); return; } // 使用axios調用後端接口 axios.get(/dev-api/screen/list, { headers: { Content-Type: application/json, Authorization: Bearer authToken } }) .then(function(response) { // 假設返回的數據格式為數組取最新200條 var data response.data.data ? response.data.data.slice(-200) : response.data.slice(-200); updateChart(data); }) .catch(function(error) { console.error(獲取數據失敗:, error); // 接口失敗時直接報錯不顯示模擬數據 throw error; }); } 现在我还需要修改页面加载时的初始化逻辑因为现在需要等待token // 页面加载完成后初始化图表 $(document).ready(function() { // 不再自动调用fetchLatestData等待token // fetchLatestData(); // 每30秒更新一次数据但需要檢查token setInterval(function() { if (authToken) { fetchLatestData(); } }, 30000); });修改內容1. Vue组件 (index.vue)添加了getToken()導入在組件掛載時獲取當前用戶的token添加了onIframeLoad方法在iframe加載完成後向iframe傳遞token使用postMessage將token發送給iframe2. HTML页面 (index.html)添加了authToken变量来存储token添加了message事件监听器来接收来自父页面的token修改了fetchLatestData函数在请求头中添加Authorization: Bearer {token}添加了token检查确保有token才发送請求修改了定時器逻辑只有在有token時才更新数据3.response.data.data获取数据为[0:{code: null, dateTime: 2025-06-30T11:26:26.793, data1: 1085, flag: null, date: null} 1: {code: null, dateTime: 2025-06-30T11:26:25.973, data1: 1085, flag: null, date: null} 2: {code: null, dateTime: 2025-06-30T11:26:24.89, data1: 1084, flag: null, date: null} 3: {code: null, dateTime: 2025-06-30T11:26:23.767, data1: 1084, flag: null, date: null} 4: {code: null, dateTime: 2025-06-30T11:26:22.913, data1: 1083, flag: null, date: null}……]其中设置以横坐标为dateTime纵坐标为data1我看到您获取到的数据格式现在我需要修改代码来正确处理这个数据结构将dateTime作为横坐标data1作为纵坐标// 更新图表 function updateChart(data) { // 處理數據格式使用dateTime作為時間data1作為數值 var times data.map(function(item) { // 将ISO时间格式转换为更友好的显示格式 var date new Date(item.dateTime); return date.toLocaleTimeString(zh-CN, { hour: 2-digit, minute: 2-digit, second: 2-digit }); }); var values data.map(function(item) { return item.data1; }); var option { backgroundColor: transparent, title: { text: 最新200条数据监控, textStyle: { color: #faf7fa, fontSize: 14 }, left: center }, tooltip: { trigger: axis, backgroundColor: rgba(0,0,0,0.8), borderColor: #faf7fa, textStyle: { color: #faf7fa }, formatter: function(params) { var dataIndex params[0].dataIndex; var originalData data[dataIndex]; return 时间: originalData.dateTime br/ 数值: params[0].value; } }, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, data: times, axisLine: { lineStyle: { color: #faf7fa } }, axisLabel: { color: #faf7fa, fontSize: 10, rotate: 45 } }, yAxis: { type: value, axisLine: { lineStyle: { color: #faf7fa } }, axisLabel: { color: #faf7fa }, splitLine: { lineStyle: { color: rgba(250,247,250,0.2) } } }, series: [{ name: 检测值, type: line, data: values, smooth: true, lineStyle: { color: #00ff00, width: 2 }, itemStyle: { color: #00ff00 }, areaStyle: { color: { type: linear, x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: rgba(0,255,0,0.3) }, { offset: 1, color: rgba(0,255,0,0.1) }] } } }] }; dataChart.setOption(option); }4.点击某某监测系统进入页面显示正常刷新页面之后出现上图错误这个问题是因为刷新页面时浏览器的当前URL路径变成了/monitor/liujiaxia/这时所有相对路径如css/xxx.css、js/xxx.js、images/xxx.png都会以/monitor/liujiaxia/为基准导致资源加载失败页面样式和图片丢失。解決方法把所有静态资源的引用路径都改成绝对路径即加上/monitor/liujiaxia/前綴。具体修改方法例如將link relstylesheet hrefcss/public.css / script srcjs/jquery.min.js/script img srcimages/logo.png改為link relstylesheet href/monitor/liujiaxia/css/public.css / script src/monitor/liujiaxia/js/jquery.min.js/script img src/monitor/liujiaxia/images/logo.png建议操作CSS、JS、圖片等所有静态资源引用都加上/monitor/liujiaxia/前綴。如果有多个子目录页面建议全部使用绝对路径这样无论怎么跳转都不会出现数据丢失问题。例子部分片段link relstylesheet href/monitor/liujiaxia/css/public.css /link relstylesheet href/monitor/liujiaxia/css/fq.css /script src/monitor/liujiaxia/js/jquery.min.js/scriptscript src/monitor/liujiaxia/js/echarts.min.js/scriptscript src/monitor/liujiaxia/js/fq.js/scriptscript src/monitor/liujiaxia/js/axios.min.js/scriptimg src/monitor/liujiaxia/images/logo.png5.检查一下为什么刷新页面之后没有发送请求根据你目前的设计刷新页面后不会自动发送请求的原因如下原因分析token传递机制依赖于父页面Vue组件向iframe发送消息- 只有当iframe的onload事件触发时父页面才会用postMessage把token发送给iframe。iframe的HTML页面index.html只有在收到token后才会调用fetchLatestData()这是为了保证请求携带token防止401。但刷新时可能出现以下情况如果你直接在iframe页面/monitor/liujiaxia/index.html刷新这时Vue父页面并不会重新加载也就不会再发送token给iframe导致iframe页面永远拿不到token也就不会发送请求。-只有从Vue页面点击进入iframe时父页面才会发送tokeniframe才能正常获取数据。解決方案方案一只允许从Vue页面进入不允许直接刷新iframe页面这是最简单的方式因为iframe页面本身无法获取token必须依赖父页面传递。方案二刷新時自動讓父頁面重新發送token你可以在iframe頁面加載時主動向父頁面發送一個“請求token”的消息父頁面收到後再回傳token。具体实现推荐方案二1.index.html增加主動請求token的代碼在script中加上// 頁面加載時主動向父頁面請求token window.parent.postMessage({ type: REQUEST_AUTH_TOKEN }, *);2.index.vue增加監聽收到請求後回傳tokenmounted() { this.token getToken(); // 監聽iframe的請求 window.addEventListener(message, this.onMessageFromIframe); }, beforeDestroy() { window.removeEventListener(message, this.onMessageFromIframe); }, methods: { onIframeLoad() { this.sendTokenToIframe(); }, onMessageFromIframe(event) { if (event.data event.data.type REQUEST_AUTH_TOKEN) { this.sendTokenToIframe(); } }, sendTokenToIframe() { const iframe this.$refs.monitorIframe; if (iframe iframe.contentWindow) { try { iframe.contentWindow.postMessage({ type: AUTH_TOKEN, token: this.token }, *); } catch (error) { console.error(向iframe傳遞token失敗:, error); } } } }已经完成自动修正现在刷新 iframe 页面也能自动获取 token 并发送请求无论是点击进入还是直接刷新都能正常显示数据核心逻辑index.html頁面加載時主動向父頁面請求 token。Vue 父頁面監聽到請求後自動回傳 token。iframe 頁面收到 token 後自動發送數據請求。6.点击某某监测系统界面如上所示还存在导航栏那张图片但是刷新之后界面感觉页面依据跳出系统了是不是存在这个原因问题本质点击进入时是从RuoYi-Vue主系统有导航栏、权限、token等进入iframe父页面和iframe同时存在token能正常传递页面显示正常。。刷新iframe时你其實刷新的是/monitor/liujiaxia/index.html這個靜態頁面這時父頁面RuoYi主系統並不會重新加載甚至有時候直接變成單獨的靜態頁面沒有導航欄、沒有token、沒有權限這時你看到的就是“跳出系統”或“只剩下iframe內容”的現象甚至有時候會直接404或白屏。你遇到的現象其实刷新的是/monitor/liujiaxia/index.html这个静态页面这时父页面RuoYi主系统并不会重新加载甚至有时候直接变成单独的静态页面没有导航栏、没有token、没有权限这时你看到的就是“跳出系统”或“只剩下iframe内容”的现象甚至有时候会直接404或白屏解決建议1.严格禁止直接刷新iframe页面用户只能从主系统点击进入不能直接刷新iframe页面。可以在index.html加判断如果不是被嵌入在iframe中则自动跳转回主系统首页。代碼示例加在index.html最前面script if (window.top window.self) { // 不是在iframe中打開強制跳轉到主系統首頁 window.location.href /; } /script这样即使用户直接刷新iframe页面也会自动跳回主系统不会出现“跳出系统”或白屏。2.导航栏图片问题如果你看到导航栏图片还在说明你刷新的是主系统的整个页面不是只刷新iframe这时主系统会重新渲染iframe也会重新加载token传递又恢复正常。但如果你只刷新iframe内容父页面不会动这时就会出现“跳出系统”现象。3. 最佳实践嵌入iframe的頁面只能作为子頁面存在不能單獨訪問或刷新。用户体验上可以在iframe页面加提示「请勿直接刷新本页面请从主系统入口进入」。结论这不是你的代码bug而是前端架构设计的限制。嵌入式iframe页面必须依赖父页面不能单独刷新或直接访问。加上“非iframe自动跳转”判断即可彻底解决这个问题。请将以下代码加在ruoyi-ui/public/monitor/liujiaxia/index.html的head标签最前面紧跟在head之后script if (window.top window.self) { // 不是在iframe中打開強制跳轉到主系統首頁 window.location.href /; } /script7.解决了是解决了但我想要刷新就还在这个页面有没有什么办法你的需求是希望刷新后依然停留在“某某监测系统”这个页面而不是跳回主系统首页并且token和权限依然有效数据能正常加载。 这是很多前端系统常见的需求下面给你详细说明可行方案方案一iframe页面支持token查詢参数自动登录1.进入iframe時父页面在src里带上token参数例如iframe :src/monitor/liujiaxia/index.html?token${token} ... /2.index.html页面加载时自动从URL查询参数获取token// index.html function getQueryParam(name) { const url window.location.search; const params new URLSearchParams(url); return params.get(name); } var authToken getQueryParam(token);如果token存在就直接用不存在再用postMessage機制這樣刷新時token還在頁面能自動獲取數據。方案二localStorage/sessionStorage保存token1.父頁面進入iframe時把token寫到localStoragelocalStorage.setItem(iframe_token, token);2.iframe頁面加載時自動從localStorage讀取tokenvar authToken localStorage.getItem(iframe_token);這樣刷新iframe頁面時token還在能自動獲取數據。实用推荐如果你還是要用iframe建议用“查询参数帶token”或“localStorage存token”这两种方式。例子查询参数帶token1. Vue父页面iframe refmonitorIframe :src/monitor/liujiaxia/index.html?token${token} ... /2. index.htmlfunction getQueryParam(name){ const url window.location.search; const params new URLSearchParams(url); return params.get(name); }var authToken getQueryParam(token);if (!authToken) { // 沒有token再用postMessage機制 window.parent.postMessage({ type: REQUEST_AUTH_TOKEN }, *); }例子localStorage存token1. Vue父页面localStorage.setItem(iframe_token, token);2. index.htmlvar authToken localStorage.getItem(iframe_token);if (!authToken){ window.parent.postMessage({ type: REQUEST_AUTH_TOKEN }, *); }总结兼容方案iframe页面用查询参数或localStorage保存token刷新不丢失。安全性查询参数token有一定风险localStorage相对安全些。需要我幫你自動改成查詢參數或localStorage方案嗎請告訴我你想用哪一種iframe :src/monitor/liujiaxia/index.html?token${token} ... / // index.html function getQueryParam(name) { const url window.location.search; const params new URLSearchParams(url); return params.get(name); } var authToken getQueryParam(token); localStorage.setItem(iframe_token, token); var authToken localStorage.getItem(iframe_token); iframe refmonitorIframe :src/monitor/liujiaxia/index.html?token${token} ... / function getQueryParam(name) { const url window.location.search; const params new URLSearchParams(url); return params.get(name); } var authToken getQueryParam(token); if (!authToken) { // 沒有token再用postMessage機制 window.parent.postMessage({ type: REQUEST_AUTH_TOKEN }, *); } localStorage.setItem(iframe_token, token); var authToken localStorage.getItem(iframe_token); if (!authToken) { window.parent.postMessage({ type: REQUEST_AUTH_TOKEN }, *); }8.使用方案三localStorage/sessionStorage保存tokenscript import { getToken } from /utils/auth ​ export default { name: LiuJiaXiaMonitor, data() { return { token: null }; }, mounted() { this.token getToken(); // 進入iframe時將token寫入localStorage localStorage.setItem(iframe_token, this.token); // 監聽iframe的請求 window.addEventListener(message, this.onMessageFromIframe); }, beforeDestroy() { window.removeEventListener(message, this.onMessageFromIframe); }, methods: { onIframeLoad() { this.sendTokenToIframe(); }, onMessageFromIframe(event) { if (event.data event.data.type REQUEST_AUTH_TOKEN) { this.sendTokenToIframe(); } }, sendTokenToIframe() { const iframe this.$refs.monitorIframe; if (iframe iframe.contentWindow) { try { iframe.contentWindow.postMessage({ type: AUTH_TOKEN, token: this.token }, *); } catch (error) { console.error(向iframe傳遞token失敗:, error); } } } } }; /scriptscript var authToken localStorage.getItem(iframe_token); if (!authToken) { window.parent.postMessage({ type: REQUEST_AUTH_TOKEN }, *); } // ... existing code ... window.addEventListener(message, function(event) { if (event.data event.data.type AUTH_TOKEN) { authToken event.data.token; localStorage.setItem(iframe_token, authToken); // 寫入localStorage保證刷新後還在 fetchLatestData(); } }); // ... existing code ... function fetchLatestData() { if (!authToken) { console.error([iframe] 未獲取到認證token無法請求數據); return; } // ... existing code ... }已经完成如下自动修改现在刷新后依然会停留在当前页面且能自动获取token并正常请求数据1. Vue父页面index.vue进入iframe时自动將token写入localStorage保证刷新后iframe页面能自动获取token。2. iframe页面index.html页面加载时优先从localStorage获取token如果没有再用postMessage机制向父页面请求。收到token后自动写入localStorage保证下次刷新还能用。请求数据时自动带上token刷新后也能正常获取数据。即使已经用 localStorage 保存 token刷新 iframe 页面后还是会自动跳转到主系统首页。這是因為我們之前在index.html裡加了這段代碼if (window.top window.self) { // 不是在iframe中打開強制跳轉到主系統首頁 window.location.href /; }这段代码的作用是只要不是在 iframe 里打开就自动跳转到首页。问题本质你在主系统内点击进入 iframe这段代码不会触发跳转页面正常。你在 iframe 内刷新浏览器会把 iframe 当成一个独立页面window.top window.self所以会自动跳转到首页。解決办法方案一去掉自动跳转代码如果你希望刷新后还能停留在 iframe 页面就不能再用这个“非iframe自动跳转”判断。操作步驟打開ruoyi-ui/public/monitor/liujiaxia/index.html刪除或注释掉如下代码if (window.top window.self) { window.location.href /; }方案二只在未登录时跳转如果你既想防止用户直接访问又想允许刷新可以改成if (window.top window.self !localStorage.getItem(iframe_token)) { window.location.href /; }这样只有没有 token 时才会跳转有 token即已经登录过就不会跳转。9.延时太长缩短响应时间主要是由于父页面和iframe之间的通信延迟导致的。当您刷新iframe页面时它需要向父页面请求token这个一来一回的过程会花费一些时间从而导致您看到的延迟。 目前的实现方式是无论iframe的localStorage中是否有token它都会等待父页面通过postMessage发送token后才去加载数据。为了优化这个流程可以做如下修改优先使用本地存储的token在iframe加载时首先检查localStorage中是否存在token。如果存在就立即使用这个token去请求数据无需等待父页面响应。这样可以大大缩短首次数据加载的时间。保留通信作为备份和更新机制postMessage通信机制仍然保留。它可以用于在token不存在时从父页面获取token或者在父页面token更新后同步到iframe中。调整数据刷新间隔代码注释中提到每30秒更新一次数据但实际设置的是60秒。我会将其调整为30秒以提高数据的实时性。修改ruoyi-ui/public/monitor/liujiaxia/index.html文件来实现这个优化// ... existing code ... script var lazyFun; var authToken localStorage.getItem(iframe_token); if (!authToken) { window.parent.postMessage({ type: REQUEST_AUTH_TOKEN }, *); } ​ function init(el, width, height) { // ... existing code ... // 監聽來自父頁面的消息 window.addEventListener(message, function(event) { if (event.data event.data.type AUTH_TOKEN) { var wasTokenMissing !authToken; authToken event.data.token; localStorage.setItem(iframe_token, authToken); // 写入localStorage保存刷新後還在 if (wasTokenMissing) { fetchLatestData(); } } }); ​ // 初始化数据图表 // ... existing code ... // 頁面加載完成後初始化圖表 $(document).ready(function() { // 如果localStorage中已有token則立即獲取數據 if (authToken) { fetchLatestData(); } ​ // 每30秒更新一次數據但需要檢查token setInterval(function() { if (authToken) { fetchLatestData(); } }, 30000); }); /script /body /html