记录一次车间实时看板调试(2026-05-19)
记录一次车间实时看板调试(2026-05-19)
这天最关键的判断:改了后端代码不重启 Flask,页面永远还是旧数据。
上午接到的需求是把一张静态的 factory_dashboard_dark.html 塞进真实数据库里的产线工时数据,还要动态实时刷新。最后折腾到傍晚,主要精力没花在写 SQL 上,全花在“我以为改了就应该生效”上了。
一、从一张静态 HTML 到一个 Flask API 服务
原始素材很明确:数据库在 100.64.0.2:3306,账号 ***(空密码,内网测试库),库名 m3_ai_data,表 work_load,字段有开始时间、结束时间、worker_num 人数、worktime 工时、workload 总工时。area 字段里五个工位代码分别是 SCBX(上层布线)、SCZZ(上次组装,素材里是打字笔误,我直接按原文记录)、DCZZBX(底层组装布线)、GJQ(工具区)、ZCZZ(中层组装),总区域 main_area 的 TST1 代表 M3 手工流水线。
浏览器本身不能直连 MySQL,所以当天定下的架构就是两文件方案:
factory_api_server.py:Flask 本地服务,端口 8765,负责查 MySQL 并返回 JSON;factory_dashboard_dark.html:纯前端,每 30 秒fetch('/api/data')拉一次数据自动刷新;- 顺手加了一个
start_dashboard.bat,双击启动后打开http://localhost:8765/。
12:18 第一版快照跑起来的时候,在岗总人数 4 人(SCBX:1、SCZZ:1、DCZZBX:1、GJQ:1、ZCZZ:0),今日累计工时 31928 秒(约 532 分钟),今日有效工时 21988 人·秒。看板做了四个标签页:总览、实时、时间轴、分析。
二、第一轮 UI 文字去代码化与工时格式修复
用户看完第一版直接提了三点:所有 UI 文字里不能体现 SCBX、SCZZ、DCZZBX、GJQ、ZCZZ 这些代码;总览里各工位今日累计工时的秒数显示不全;分析里的累计工时和有效工时定义要写清楚。
第一点就是“工位名称中文化”。工位人数卡片原来会把 area-code 元素显示出来,我直接隐藏掉,只留彩色中文名。实时数据流水、实时汇总表、分析详细表全都去掉代码列或代码显示。时间轴筛选按钮改成“上层布线 / 上层组装 / 底层组装布线 / 工具区 / 中层组装”,但按钮的 id 和 onclick 参数保留原代码,不然筛选逻辑全断。
第二点加了个 secToHMS() 函数,把秒数转成 Xh XXm XXs 格式,比如 8h53m48s,KPI 卡片和柱状图标注统一用它,秒数不再被容器截断。
第三点在分析页图表上方加了说明栏,把定义写死在前端:
- 累计工时 = 工位有人在岗的时段之和(秒),反映工位实际开机时长;
- 有效工时 = 在岗人数 × 在岗时长(人·秒),多人同时在岗叠加计算,反映实际总人力投入;
- 利用率 = 有效工时 ÷ 累计工时 ≈ 平均在岗人数。
三、改图与半小时粒度热力图
用户又发来截图,指出三个问题:柱状图文字显示不全;各工位当前在岗人数用饼图不好,全为 0 时很难看;热力图最小颗粒度改成半小时。
文字截断我把图表高度从 280px 拉到 340px,y 轴加 automargin:true,bar trace 加 cliponaxis:false,顶部 margin 设成 t:40。饼图先改成了水平柱状图,后来用户还是不满意,最终改成多工位折线图,每个工位一条彩色折线加数据标注,全 0 也能正常显示。
热力图半小时粒度这个改动在前后端同时动。后端保留原来每小时查询给折线图用,另外新增半小时查询,核心算式是 HOUR*2 + FLOOR(MINUTE/30),把一天切成 slot 0~47,新增字段 heatmap_matrix_halfhour,是一个 5×48 矩阵。前端 x 轴改成 48 个半时标签(00:00, 00:30, 01:00, ... 23:30),用 tickvals/ticktext 每 2 小时显示一个标签避免重叠,下方折线图仍然保持每小时粒度。
四、两个 bug:柱状图反轴和热力图空白
改完还没消停,用户又丢来两张截图:人数和柱子长度不符;热力图里部分没有数据填充。
第一个 bug 是 Plotly 水平柱状图在纯整数数据时,x 轴 autorange 可能异常反转,0 跑到右侧,条长度错乱。修复方式是显式计算 maxWorkers = Math.max(...workers, 3),x 轴强制 range: [0, maxWorkers],再加 side: 'bottom' 把 x 轴位置锁死。
第二个 bug 更隐蔽:热力图里 0 值单元格的颜色 #161B22 和深色主题 card 背景色完全一样,导致空白时段直接隐形。深色模式把 0 值改成 #1A2332,浅色模式改成 #E8ECF0。顺手还发现 x 轴 dtick 对 categorical 字符串轴根本无效,改成 tickvals/ticktext 每 2 小时显示一个标签。
五、重启服务才能生效的教训
用户回了一句“还是没有修改好啊”,说 9 点以后没有数据填充,和数据库实际数据不符,让我看以前连接实际数据的代码。
我查了一下,heatmap_matrix_halfhour 返回了 0 行(空数组),而 24 小时矩阵有数据。这说明运行中的 Flask 进程是旧版本,API 响应里根本没有这个字段。**debug=False 模式下,factory_api_server.py 改了不会自动重载,必须 kill 旧进程后重跑。** 当天就因为这个原因,热力图数据一直是旧的。重启服务后,API 正确返回 5×48 半小时矩阵,slot 20-34(10:00-17:00)全部有数据,覆盖所有 5 个工位。
以后改这个文件,要用 start_dashboard.bat 重启,别再指望浏览器刷新能解决问题。
六、视频流封面图与静态路由冲突
最后加的需求是实时选项卡里放一个视频播放器画面,4:3 比例,先用 D 盘里的 aaa.png 作为封面图始终展示。做完之后切换到「实时」页能看到产线监控画面,左上角红色 LIVE 标识带脉冲动画,右上角时间戳每秒刷新,右下角绿色“监控在线”状态。
这里也踩了个小坑:Flask 默认自带 /static/ 路由指向 static/ 子目录,我自定义的路由直接被覆盖,图片怎么都出不来。最后直接改 Flask 的 static_folder 指向 D:\,通过 /static/aaa.png 提供图片访问,干净利落。
七、遗留与下一步
当天收尾时看板已经能反映真实数据库的实时数据,但视频流本身还没接,只是先展示封面图占位。另外半小时粒度的热力图数据量比原来多一倍,前端每 30 秒轮询时会一起拉回来,后续如果工位或时间范围扩大,就得考虑 API 加缓存或减少轮询频率,不然 Flask 那台小服务扛不住。
还有一个没验证的地方:多工位折线图在人数突增时的数据标注会不会重叠,需要等明天实际产线人数波动起来再看一眼。