ECharts + Flask 实时生产大屏源码:从跑通到避坑的工程实践

发布时间:2026/10/9 14:48:49
ECharts + Flask 实时生产大屏源码:从跑通到避坑的工程实践 简介本资源是一套面向制造业生产管理场景的数据可视化大屏源码基于 Echarts 与 Python Flask 构建适合具备一定 Python 与前端基础、希望快速搭建动态实时监控看板的开发者与数据分析人员参考学习。压缩包共 142 个文件约 9.96MB其中 60 个 js 文件承担图表渲染与交互逻辑20 个 css 与 9 个 html 构成页面布局与样式另有 9 个 json 提供数据配置、8 个 png 作为视觉素材3 个 py 文件负责 Flask 后端服务与数据接口整体结构清晰、前后端分离。资源围绕生产管理看板主题涵盖实时数据刷新、多图表联动与响应式布局等实现思路读者可据此理解 Echarts 与 Flask 的整合方式并在此基础上替换数据源、调整指标模块快速落地属于自己的可视化大屏。目前已有 2611 人学习下载可作为制造业数字化看板项目的实用参考。1. 制造业大屏不是拼图表这套 ECharts Flask 源码到底能跑出什么很多团队做生产管理看板第一反应是堆图表折线、柱状、饼图全往上怼结果上线三天就被车间主任吐槽“看不出哪条线卡了”。这套基于 ECharts Python Flask 的动态实时大屏源码解决的不是“画得好看”而是“数据怎么从后端流到前端、怎么定时刷新、怎么在浏览器里稳住不崩”。它适合两类人一类是手里有 MES 或设备日志数据、需要快速搭一个可视化入口的工程师另一类是课程设计或内部 Demo 阶段想拿一套能跑通前后端链路的最小闭环。源码包里通常包含 Flask 路由、模拟数据接口、ECharts 配置项和静态页面你拿到手改的是数据源和图表映射不是从零写 WebSocket。下面按“能跑起来 → 改得动 → 不翻车”的顺序拆一遍。2. 先跑通再谈改Flask 接口与 ECharts 配置的对接逻辑2.1 为什么选 Flask 做实时大屏的后端制造业看板的数据源往往很杂有的来自数据库定时查询有的来自设备网关推送还有的干脆是 Excel 手工导入。Flask 的优势在于轻一个app.py加几个路由就能把数据吐成 JSON前端 ECharts 拿到就能渲染。相比 Django它没有 ORM 和 Admin 的包袱改起来快相比 FastAPI它对老版本 Python 和 Windows 环境的兼容性更稳车间工控机上跑 Python 3.6 的情况并不少见。常见做法是Flask 只负责“取数 转 JSON”不做复杂计算计算逻辑放到 SQL 或单独脚本里这样接口响应能压在 200ms 以内大屏刷新才不会卡顿。源码里一般会有一个/api/production之类的路由返回结构类似# app.py 片段模拟生产数据接口 from flask import Flask, jsonify import random, datetime app Flask(__name__) app.route(/api/production) def production_data(): # 实际项目中这里换成数据库查询或 MES 接口调用 lines [线体A, 线体B, 线体C, 线体D] data [] for line in lines: data.append({ name: line, output: random.randint(800, 1200), # 当日产量 target: 1000, # 计划产量 rate: round(random.uniform(0.75, 0.98), 2), # 达成率 status: random.choice([运行, 待机, 故障]) }) return jsonify({ time: datetime.datetime.now().strftime(%Y-%m-%d %H:%M:%S), data: data }) if __name__ __main__: app.run(host0.0.0.0, port5000, debugTrue)这段代码的逻辑很直白每次请求生成一组模拟数据字段包括线体名、产量、目标、达成率和状态。参数说明host0.0.0.0让局域网内其他机器能访问大屏机器不用装 PythondebugTrue只在开发阶段开上线要关掉否则改代码自动重启会打断前端轮询。random部分替换成真实查询时注意把target从数据库配置表里读不要写死。2.2 ECharts 怎么接住这个接口前端页面通常是一个index.html里面用fetch或setInterval定时拉数据。关键点是不要每次刷新都dispose重建图表而是用setOption更新数据否则大屏跑一晚上内存就爆了。源码里一般会封装一个refresh()函数// static/js/dashboard.js 片段 function refreshData() { fetch(/api/production) .then(res res.json()) .then(res { const lines res.data.map(item item.name); const outputs res.data.map(item item.output); const rates res.data.map(item item.rate); // 更新柱状图只改 series.data不重建实例 barChart.setOption({ xAxis: { data: lines }, series: [{ data: outputs }] }); // 更新仪表盘或折线图 lineChart.setOption({ xAxis: { data: lines }, series: [{ data: rates }] }); document.getElementById(update-time).innerText res.time; }) .catch(err console.error(数据拉取失败, err)); } // 每 5 秒刷新一次车间看板不需要毫秒级 setInterval(refreshData, 5000); refreshData();逻辑说明fetch拿到 JSON 后用map抽出 ECharts 需要的数组再通过setOption增量更新。参数上setInterval的 5000ms 是经验值——低于 3 秒对数据库压力大高于 10 秒车间主任会觉得“卡住了”。catch里一定要打日志否则接口挂了页面只是不动排查时两眼一抹黑。2.3 静态文件目录怎么摆才不 404Flask 默认静态目录是static模板目录是templates。源码包解压后常见结构是project/ ├── app.py ├── templates/ │ └── index.html └── static/ ├── js/ │ ├── echarts.min.js │ └── dashboard.js └── css/ └── style.cssindex.html里引用路径要写成{{ url_for(static, filenamejs/echarts.min.js) }}或者直接/static/js/echarts.min.js。常见翻车点是把echarts.min.js放在templates里或者用相对路径../static/...Flask 渲染后路径就乱了。我一般会先跑python app.py浏览器开F12看 Network 里哪个文件 404比猜快得多。3. 把模拟数据换成真实产线数据三个必须改的配置点3.1 数据源从 random 换成 SQL 查询模拟数据只能看效果真上线必须接数据库。假设产线数据存在 MySQL 的production_log表里字段有line_name、output、target、log_time。改法是把random那段替换成查询# app.py 片段接 MySQL 查询 import pymysql from flask import Flask, jsonify app Flask(__name__) def get_conn(): return pymysql.connect( host127.0.0.1, userboard_user, passwordyour_password, # 实际项目用环境变量别硬编码 databasemes_db, charsetutf8mb4, cursorclasspymysql.cursors.DictCursor ) app.route(/api/production) def production_data(): conn get_conn() try: with conn.cursor() as cur: # 取每个线体最新一条记录 sql SELECT line_name, output, target, status, log_time FROM production_log WHERE log_time DATE_SUB(NOW(), INTERVAL 1 DAY) GROUP BY line_name HAVING log_time MAX(log_time) cur.execute(sql) rows cur.fetchall() return jsonify({time: rows[0][log_time].strftime(%H:%M:%S) if rows else , data: rows}) finally: conn.close()参数说明charsetutf8mb4防止中文线体名乱码DictCursor让结果直接是字典省去手动拼字段DATE_SUB(NOW(), INTERVAL 1 DAY)限制只查最近一天避免全表扫描。注意GROUP BY和HAVING的写法在不同 MySQL 版本下行为有差异如果报错就改成子查询取MAX(log_time)。3.2 前端刷新频率与后端缓存怎么配合如果每条线体数据都实时查库10 个大屏同时刷数据库压力不小。常见做法是加一层缓存Flask 端用cachetools或简单的全局变量每 3 秒才真正查一次库其他请求直接返回缓存。前端setInterval保持 5 秒这样数据库每秒最多承受 0.33 次查询。源码里如果没带缓存可以自己加from cachetools import TTLCache cache TTLCache(maxsize1, ttl3) # 3 秒过期 app.route(/api/production) def production_data(): if data in cache: return jsonify(cache[data]) # ... 查库逻辑 ... result {time: ..., data: rows} cache[data] result return jsonify(result)ttl3表示 3 秒内重复请求直接走缓存maxsize1因为只有一份全量数据。注意多进程部署时TTLCache不共享Flask 开发服务器单进程没问题上 gunicorn 多 worker 就要换 Redis。3.3 大屏分辨率适配1920×1080 之外的坑车间大屏不一定是标准 1080P有的拼接屏是 3840×2160有的老屏是 1366×768。ECharts 默认按容器大小渲染但字体和间距会乱。源码里一般用rem或vw做适配我习惯在dashboard.js开头加一段function setRootFontSize() { const width document.documentElement.clientWidth; // 以 1920 为基准1rem 16px const fontSize (width / 1920) * 16; document.documentElement.style.fontSize fontSize px; } window.addEventListener(resize, setRootFontSize); setRootFontSize();这样 CSS 里用rem写尺寸换分辨率时整体缩放。ECharts 的fontSize也要跟着改可以在setOption前读一下document.documentElement.style.fontSize动态设置。注意resize事件要防抖否则拖动窗口时图表会疯狂重绘。4. 避坑排查大屏跑一晚上就白屏的五个原因4.1 现象页面凌晨自动白屏刷新后恢复原因setInterval在浏览器标签页休眠后会被节流但更常见的是接口返回了null或空数组EChartssetOption收到undefined数据直接报错后续刷新全部中断。解决在refreshData里加数据校验if (!res.data || res.data.length 0) return;同时用try/catch包住setOption。4.2 现象中文线体名显示成方块原因Flask 返回 JSON 时默认ensure_asciiTrue中文被转成\uXXXX如果前端页面编码不是 UTF-8 就乱码。解决app.config[JSON_AS_ASCII] False并在 HTMLhead里加meta charsetUTF-8。数据库连接也要确认charsetutf8mb4。4.3 现象图表数据更新了但数字没变原因ECharts 的setOption默认合并模式如果series里没写data字段旧数据不会被覆盖。解决确保每次setOption都传完整的series.data或者用setOption(option, true)强制不合并。但强制不合并会丢失动画我一般只传数据数组。4.4 现象Flask 启动报Address already in use原因5000 端口被占常见于上次debugTrue的进程没退干净。解决Windows 用netstat -ano | findstr :5000找 PID 再taskkillLinux 用lsof -i:5000后kill -9。改端口也行app.run(port5001)但前端fetch路径要同步改。4.5 现象大屏机器浏览器版本老ECharts 5 不兼容原因车间工控机可能还在用 Chrome 60 或 IE 内核。ECharts 5 要求 ES6老浏览器直接白屏。解决换 ECharts 4.9 的echarts.min.js或者用 Babel 转译。更稳的办法是装一个便携版 Chrome别动系统浏览器。5. 进阶把轮询换成 SSE以及一个验证数据准确性的笨办法轮询用久了会发现两个问题一是延迟固定数据变了要等下一个周期二是每次请求都带 HTTP 头浪费带宽。如果 Flask 版本在 2.0 以上可以试试 SSEServer-Sent Events服务端推、前端EventSource接延迟能压到 1 秒内。改法是在 Flask 里加一个生成器路由import time, json from flask import Response app.route(/api/stream) def stream(): def event_stream(): while True: # 这里复用之前的查库逻辑 data {time: time.strftime(%H:%M:%S), data: query_production()} yield fdata: {json.dumps(data, ensure_asciiFalse)}\n\n time.sleep(2) # 服务端控制推送间隔 return Response(event_stream(), mimetypetext/event-stream)前端对应改成const source new EventSource(/api/stream); source.onmessage function(e) { const res JSON.parse(e.data); // 同样的 setOption 更新逻辑 updateCharts(res); }; source.onerror function() { console.error(SSE 断开浏览器会自动重连); };注意 SSE 是单向的且每个连接占一个 Flask 线程开发服务器默认单线程会阻塞需要threadedTrue或上 gunicorn。如果产线数据源本身是 MQTT 推送那更合适的是 WebSocket但复杂度也更高Demo 阶段 SSE 够用。最后说一个验证数据准确性的笨办法拿大屏上的产量数字跟车间纸质报表或 MES 导出 Excel 对一遍连续对三天。我见过太多看板因为 SQL 里GROUP BY取错了记录导致数字比实际少一个班次。从那以后我每次接新数据源都强制走一遍“手工对账”流程宁可上线晚半天也不让车间主任在早会上指着大屏说“这数不对”。希望帮到你。本文还有配套的精品资源点击获取