☰
Web组态设计器FUXA:中小型SCADA项目的开源替代方案与部署实践
2026/10/15 1:14:19 网站建设 项目流程

简介:Web组态设计器FUXA是一套面向工业Web应用开发的开源工具,适合希望以低代码方式搭建工业控制系统界面的工程师与前端开发者。它基于Vue.js与Node.js技术栈,通过拖放式图形界面完成控制逻辑配置,支持远程访问、实时数据监控,并可对接OPC UA、MODBUS等工业协议,让不熟悉编程的工程师也能完成复杂组态设计。资源包共1195个文件,约13.92MB,以423个svg图标、271个ts脚本、117个html页面、107个js文件及96个css样式为主,另含字体、json配置、scss源码与dockerfile等,覆盖前端界面、后端服务与部署配置的完整工程结构。目前已有2649人学习下载。借助这套源码,读者可研究Vue组件化与Node后端API的协作方式,理解组态编辑器的图形化交互、脚本逻辑与实时通信实现,并参考其目录组织与构建配置,快速搭建属于自己的Web工业设计器原型。

1. Web组态设计器FUXA:为什么它成了中小型SCADA项目的替代方案

做过工业上位机的人大概都有这种体会:一套正版组态软件授权费动辄几万起步,项目还没开工,预算先被砍掉一大块。更麻烦的是,很多传统组态工具是桌面端绑定授权,部署到现场工控机上要装加密狗、要配运行环境,远程维护时只能干瞪眼。Web组态设计器FUXA 这类开源方案之所以最近被反复提起,核心就一句话:用浏览器就能画工艺流程画面、连设备数据、跑在任意一台能开浏览器的机器上,而且源码可控。

FUXA 的定位是一个基于 Web 技术的可视化组态平台,前端用 SVG 画图元、后端用 Node.js 做数据采集与转发,支持 Modbus、OPC UA、MQTT、S7 等常见工业协议。它解决的不是"我要做一个媲美商业组态的全功能平台",而是"我有个中小型监控需求,几十个点位、几幅画面,想快速上线、低成本维护"。适合谁?做设备配套上位机的小团队、做产线数据看板的集成商、以及想自己搭一套内部监控系统的工厂自动化工程师。如果你手上正好有这类需求,往下看,我把选型理由、部署步骤、参数配置和踩过的坑都摊开讲。

2. FUXA 的架构拆解与本地部署:从源码到能打开的画面编辑器

2.1 前后端分离的架构决定了它的能力边界

FUXA 的架构不复杂,但理解它才能知道哪些事它能干、哪些事别指望。前端是一个单页应用,核心是 SVG 画布加一套图元库,所有画面元素都是矢量图形,缩放不失真,导出也方便。后端是一个 Node.js 服务,负责三件事:托管前端静态资源、管理项目文件(画面、设备、脚本的 JSON 配置)、跑数据采集引擎。采集引擎通过插件化的驱动去连 PLC、传感器或网关,把读到的值推给前端做实时刷新。

这个架构带来两个直接结论。第一,它天然适合远程访问,因为前端就是网页,你在办公室和在中控室看到的是同一套东西,不需要装客户端。第二,它的实时性受限于 Web 通信和采集轮询周期,做毫秒级联锁控制不现实,但做秒级、亚秒级的数据监控完全够用。我一般会跟团队说清楚:FUXA 是监控层工具,不是控制层工具,别拿它去替代 PLC 里的安全逻辑。

项目文件是纯 JSON 存储的,这点很关键。意味着你可以用 Git 做版本管理,画面改动能 diff、能回滚,比传统组态软件的二进制工程文件友好太多。多人协作时,谁改了哪条设备连接、哪个图元绑定,一目了然。

2.2 用 Docker 在本地跑通最小实例

部署 FUXA 最省事的方式是 Docker,避免 Node 版本和依赖的玄学问题。下面是我常用的最小启动命令,直接抄:

# 拉取镜像并启动,映射 1881 端口作为 Web 访问入口 docker run -d \ --name fuxa \ -p 1881:1881 \ -v /opt/fuxa/appdata:/usr/src/app/FUXA/server/_appdata \ -v /opt/fuxa/logs:/usr/src/app/FUXA/server/_logs \ -v /opt/fuxa/images:/usr/src/app/FUXA/server/_images \ --restart unless-stopped \ frangoteam/fuxa:latest

这段命令的逻辑说明:-p 1881:1881把容器内的 Web 服务端口映射到宿主机,浏览器访问http://你的IP:1881就能打开编辑器。三个-v挂载是血泪经验——_appdata存项目配置,_logs存运行日志,_images存上传的图片资源,不挂载的话容器一删项目全没。--restart unless-stopped保证工控机意外重启后服务自动拉起,现场无人值守时这个参数必加。

参数怎么改:如果你的 1881 端口被占用,把冒号前的数字换成别的,比如-p 8080:1881,容器内部端口不用动。镜像标签建议固定到具体版本号而不是latest,生产环境用latest等于给自己埋雷,某次更新可能就改了配置格式。

启动后打开浏览器,默认账号密码都是admin,第一件事就是改密码。进去之后你会看到左侧是图元库和设备树,中间是画布,右侧是属性面板。先别急着画复杂画面,新建一个项目,拖一个矩形、一个文本、一个按钮,把按钮的点击事件绑一个脚本弹个提示,确认整条链路通了,再去连真实设备。

2.3 源码方式部署与开发模式启动

如果你要改源码或者做二次开发,就得走源码部署。Node 版本建议 18 LTS,别用太新的,某些原生依赖编译会翻车。

# 克隆源码后进入目录,安装依赖 git clone <你的仓库地址> fuxa-dev cd fuxa-dev # 安装前端和后端依赖,分开装更清晰 cd client && npm install cd ../server && npm install # 开发模式启动:前端热更新,后端自动重启 # 终端一:启动前端开发服务器 cd client && npm run serve # 终端二:启动后端 cd server && npm run start

逻辑说明:开发模式下前端跑在另一个端口(通常是 8080 或 4200),通过代理把 API 请求转发到后端。这样你改前端代码浏览器自动刷新,改后端代码服务自动重启,调试效率比每次重新构建镜像高得多。参数上,前端vue.config.js里的devServer.proxy要指向后端地址,默认配置一般已经写好,如果后端端口改了记得同步。

生产构建用npm run build,产物在client/dist目录,后端会把它当静态资源托管。我一般会在构建前把server/_appdata里的示例项目清掉,避免把测试数据带到生产。

3. 设备连接与数据绑定:让画面上的数字真正动起来

3.1 配置 Modbus TCP 设备连接的完整步骤

画面画得再漂亮,数据不动就是一张图。FUXA 连设备的核心入口在左侧设备树,右键新增设备,选驱动类型。以最常见的 Modbus TCP 为例,步骤如下。

第一步,填连接参数。设备名称随便起但要有意义,比如产线A-温控表。类型选Modbus TCP。地址填 PLC 或网关的 IP,端口默认 502。从站 ID 按现场实际填,很多网关默认是 1,但串口服务器转出来的可能不是,填错就是连不上,这个坑后面还会说。

第二步,配轮询参数。FUXA 的采集是轮询式的,Polling间隔决定多久读一次。默认 1000 毫秒,做温度、液位这类慢变量够用。如果你要读电机转速这种快变量,可以调到 200 到 500 毫秒,但别低于 100 毫秒,否则 Modbus 请求会把网络和 PLC 的通信口压满,反而导致丢包。Timeout设 1000 到 2000 毫秒,现场网络抖动时给点余量。

第三步,定义标签。每个标签要指定寄存器类型和地址。保持寄存器用Holding Register,输入寄存器用Input Register,线圈用Coil。地址是从 0 开始还是从 1 开始,取决于设备手册,这是最容易翻车的地方。同一个地址,有的 PLC 手册写 40001,实际要填偏移 0;有的写 40001 就要填 1。我的习惯是先用 Modbus 调试工具单独读一次,确认地址偏移,再往 FUXA 里填。

// FUXA 脚本示例:在设备连接成功后做一次初始化 // 这段脚本挂在设备的 onConnect 事件上 console.log('设备已连接,开始初始化标签映射'); // 假设我们要把读到的原始值做线性变换 // 原始 0-27648 对应实际 0-100 摄氏度 const rawValue = $getTag('产线A-温控表/温度原始值'); const scaled = (rawValue / 27648) * 100; // 把变换后的值写到一个内部标签,供画面绑定 $setTag('内部变量/温度显示', scaled.toFixed(1));

逻辑说明:FUXA 支持在设备事件和画面事件里写 JavaScript 脚本,$getTag和$setTag是读写标签的接口。上面这段做的是工程量变换,很多 PLC 的模拟量输入是 0 到 27648 的整数,要转成实际物理量才能显示。参数上,toFixed(1)保留一位小数,避免画面上出现一长串浮点数。注意脚本执行频率别太高,挂在onConnect上只跑一次没问题,如果挂在周期事件上要控制好间隔。

3.2 画面图元绑定标签的三种方式

标签配好了,接下来是让画面元素跟标签关联。FUXA 里绑定方式主要有三种,各有适用场景。

第一种是直接绑定。选中一个文本图元,在右侧属性面板找到Text或Value属性,点旁边的绑定图标,选标签。这种方式最简单,适合显示数值、状态文字。刷新频率跟随设备的轮询周期,不用额外配置。

第二种是通过动画属性绑定。比如一个矩形要随液位高低改变高度,就绑定Height属性到液位标签,再配一个范围映射。范围映射的意思是标签值 0 到 100 对应矩形高度 0 到 200 像素,这个映射关系在绑定对话框里设。做动态液位、进度条、指针仪表都用这种方式。

第三种是通过脚本动态控制。复杂交互比如点击按钮弹出一个确认框、根据多个标签的组合状态改变颜色,就得写脚本。脚本挂在图元的onClick或画面的周期事件上。

// 画面周期事件脚本:根据温度值改变矩形填充色 // 挂在画面的 onPeriodic 事件上,间隔 1000ms const temp = $getTag('内部变量/温度显示'); // 获取画面上的矩形图元 const rect = $getElement('温度指示块'); if (temp > 80) { // 超温,红色告警 rect.setAttribute('fill', '#ff4d4f'); } else if (temp > 60) { // 偏高,黄色预警 rect.setAttribute('fill', '#faad14'); } else { // 正常,绿色 rect.setAttribute('fill', '#52c41a'); }

逻辑说明:$getElement按图元名称拿到 DOM 对象,直接改 SVG 属性。这种方式的灵活性最高,但要注意性能——周期事件里别做太重的计算,也别频繁操作大量图元,否则浏览器会卡。参数上,onPeriodic的间隔建议跟设备轮询周期对齐或略长,避免无意义的重复渲染。

三种方式我的使用习惯是:能用直接绑定就不用动画,能用动画就不用脚本。脚本是最后的手段,因为它把逻辑藏在了代码里,后期维护的人不看脚本就不知道画面为什么变色,这就是典型的黑匣子。

3.3 用 MQTT 接入物联网网关的数据

现在很多现场用物联网网关做协议转换,对上走 MQTT。FUXA 连 MQTT 设备跟 Modbus 类似,但订阅方式有区别。

新增设备选MQTT驱动,填 Broker 地址、端口、客户端 ID、用户名密码。然后定义标签时,每个标签要指定订阅的 Topic 和解析方式。Topic 支持通配符,比如factory/lineA/+/temperature能匹配多个设备的温度。解析方式选 JSON 的话,要填 JSON Path,比如$.value从消息体里取值。

这里有个容易忽略的点:MQTT 是推送模式,不是轮询,所以设备配置里的Polling间隔对 MQTT 无效,实际刷新频率取决于网关多久发一次。如果网关发得太快,前端渲染跟不上,可以在标签上配一个死区(Deadband),值变化超过阈值才更新画面,减少无谓刷新。

4. 避坑与排查:那些让项目卡住的真实问题

4.1 设备连不上但 ping 得通

现象:设备树里连接状态一直是红色,日志报 timeout,但用 ping 命令能通。

原因:九成是端口或从站 ID 不对。Modbus TCP 默认 502,但有些网关改成了 5020 或别的;从站 ID 填错也会导致请求被忽略。还有一种情况是防火墙只放行了 ICMP 没放行 TCP 502。

解决:先用 Modbus Poll 这类调试工具,用同样的 IP、端口、从站 ID、寄存器地址读一次。调试工具能读到,FUXA 就一定能读到,读不到就是参数没对齐。防火墙问题找网络管理员开端口,别自己瞎试。

4.2 画面数值刷新一顿一顿的

现象:数据能读到,但画面上数字跳变不流畅,有时候还卡住几秒。

原因:轮询间隔设太短,或者标签数量太多,单次轮询请求超时导致后续请求堆积。FUXA 的采集引擎是串行发请求的,一个超时会拖累整条队列。

解决:把轮询间隔从 100 毫秒放宽到 500 毫秒或 1000 毫秒,观察是否改善。如果标签有几百个,考虑分组,把不同设备的轮询错开,或者用网关做边缘聚合,减少 FUXA 直接读的点位数量。另外检查Timeout是不是设得太小,现场网络有抖动时 500 毫秒不够,设 2000 毫秒。

4.3 项目文件丢失或配置回滚

现象:重启容器后画面没了,或者设备配置变回旧版本。

原因:Docker 部署时没挂载_appdata目录,容器重建后数据丢失。或者多人同时编辑,后保存的覆盖了先保存的。

解决:部署时三个挂载目录一个都不能少,这是硬性要求。多人协作的话,用 Git 管理_appdata里的 JSON 文件,每次改完提交,冲突了能合并能回滚。FUXA 本身没有细粒度的权限控制,别指望它做协同编辑的冲突解决。

4.4 脚本报错但画面不提示

现象:绑了脚本的按钮点了没反应,画面也不报错,打开浏览器控制台才看到红色报错。

原因:FUXA 的脚本运行在沙箱里,异常不会弹窗,只打到控制台。标签名写错、图元名写错、类型不匹配都会静默失败。

解决:养成开浏览器开发者工具的习惯,F12 看 Console。脚本里关键步骤加console.log,确认执行到哪一步。标签名和图元名建议用复制粘贴,别手敲,大小写和空格都可能是坑。

4.5 生产环境用 latest 标签导致升级翻车

现象:某次重启后容器拉取了新镜像,配置格式变了,项目打不开。

原因:docker run时用了frangoteam/fuxa:latest,每次重启都可能拉到新版本,而新版本可能有不兼容的配置变更。

解决:生产环境固定版本号,比如frangoteam/fuxa:1.2.0。升级前先在测试环境跑一遍,确认项目能正常打开、设备能连上、画面显示正常,再改生产环境的标签。升级前备份_appdata目录,这是后悔药。

5. 进阶技巧:用脚本做数据聚合与自定义图元

5.1 在 FUXA 里做简单的数据聚合计算

FUXA 的脚本能力不止于改颜色。我经常用它做轻量级的数据聚合,省得再搭一个中间服务。比如要计算一条产线三台设备的平均温度,或者统计某个标签当天的最大值,都可以在画面脚本里做。

// 画面初始化脚本:建立聚合变量 // 挂在画面的 onStart 事件上 window.aggData = { tempSum: 0, tempCount: 0, tempMax: -999, lastReset: new Date().toDateString() }; // 画面周期脚本:每秒聚合一次 // 挂在 onPeriodic 事件上,间隔 1000ms const t1 = $getTag('产线A-温控表/温度显示'); const t2 = $getTag('产线B-温控表/温度显示'); const t3 = $getTag('产线C-温控表/温度显示'); // 过滤掉无效值(null 或 undefined) const validTemps = [t1, t2, t3].filter(t => t !== null && t !== undefined && !isNaN(t)); if (validTemps.length > 0) { const avg = validTemps.reduce((a, b) => a + b, 0) / validTemps.length; const max = Math.max(...validTemps); // 更新聚合标签 $setTag('聚合变量/平均温度', avg.toFixed(1)); $setTag('聚合变量/最高温度', max.toFixed(1)); // 跨天重置最大值 const today = new Date().toDateString(); if (today !== window.aggData.lastReset) { window.aggData.tempMax = -999; window.aggData.lastReset = today; } if (max > window.aggData.tempMax) { window.aggData.tempMax = max; $setTag('聚合变量/当日最高温度', max.toFixed(1)); } }

逻辑说明:window对象在 FUXA 脚本里是持久的,可以用来存跨周期状态。filter那一步很关键,设备断线时标签可能是 null,不过滤会导致 NaN 污染整个计算。参数上,聚合周期跟设备轮询周期对齐即可,没必要更快。跨天重置用日期字符串比较,简单可靠,不用引入日期库。

这个技巧的价值在于:很多中小项目不需要时序数据库,但需要"当前平均值""当日峰值"这类简单统计,用脚本在 FUXA 内部解决,少一个组件少一个故障点。

5.2 自定义 SVG 图元并复用

FUXA 自带的图元库覆盖了常见需求,但做行业专用画面时往往不够。比如做水处理项目,需要特定的泵、阀、池体图元。我的做法是用外部工具画好 SVG,导入 FUXA 作为自定义图元。

步骤是:用任意矢量工具画好图形,导出 SVG,注意把需要动态绑定的部分(比如泵的叶轮、阀的开度指示)单独打组并命名。然后在 FUXA 里通过图元管理导入,导入后这些命名组会变成可绑定的子元素。之后每次用这个图元,直接拖出来,绑标签就行,不用重复画。

这里有个参数要注意:SVG 的viewBox要设好,否则缩放时图元会变形。我一般把图元画在 100x100 的 viewBox 里,导入后按需缩放,保持比例。另外颜色尽量用currentColor或 CSS 变量,这样在 FUXA 里改填充色时能统一生效,不用逐个元素改。

5.3 用外部脚本做数据转发与告警

FUXA 本身有告警功能,但比较基础。如果要做复杂的告警逻辑,比如多条件组合、告警升级、发到企业微信或钉钉,我一般会在 FUXA 外面挂一个轻量脚本,通过 FUXA 的 REST API 读数据,自己判断后转发。

FUXA 的 API 可以读标签当前值,也可以订阅变化。用 Node.js 写一个几十行的服务,定时拉取关键标签,满足条件就调 Webhook。这样做的好处是告警逻辑跟画面解耦,改告警规则不用动 FUXA 项目,重启转发服务也不影响监控画面。

参数上,拉取频率别太高,30 秒到 60 秒一次足够,告警不是控制,不需要秒级响应。API 认证用 FUXA 的用户 token,别把密码硬编码在脚本里,用环境变量传。

5.4 验证部署是否可靠的三个检查点

做完部署别急着交付,我一般会过三个检查点。第一,断网重连测试:拔掉设备网线,等 30 秒插回,看 FUXA 是否自动重连、画面是否恢复刷新。第二,重启测试:重启工控机,看容器是否自动拉起、项目是否完整加载、设备是否自动连接。第三,长时间运行测试:挂 24 小时,看内存是否持续增长、日志是否有异常报错。这三个过了,基本能扛住现场环境。

我自己的习惯是,每次改完配置先导出项目 JSON 备份,命名带上日期和改动说明。这个习惯救过我两次——一次是误删了设备配置,一次是升级后格式不兼容,都是靠备份快速恢复的。FUXA 这类开源工具给了我们低成本方案,但低成本不等于低维护,该做的备份和测试一步都不能省。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询