工业组态可视化这件事,干过的人都知道痛点有多深。传统组态软件(WinCC、组态王那一票)功能确实强,但部署方式还停留在客户端安装、厂商排期、版权授权那一套,改一个点位要停工半天,加一个新画面要重新编译下发。这几年Web组态慢慢火起来,大家开始把目光转向Vue3、ThingsBoard这样的开源生态,想用低代码的方式把组态可视化的交付成本真正压下来。SceneV这个项目就是在这个背景下冒出来的——它把一个工业组态平台的核心能力拆开重组:用Vue3做画布渲染和低代码组件体系,用ThingsBoard做设备接入、遥测存储和指令下发,两端拼起来,形成一条从设备数据到可视化大屏的完整链路。
这篇文章适合正在做Web SCADA、物联网可视化平台、数字孪生低代码产品的人参考。我会从选型理由讲到架构设计,再给出可直接落地的对接代码和踩坑记录,最后聊一聊AI自动化和3D扩展方向。整个项目我自己从零搭过一版,跑了几个月的生产环境,后面写的内容都是实践里真刀真枪趟出来的,不是那种贴概念的空文章。
1. 为什么是SceneV:组态可视化的选型逻辑
1.1 传统组态软件的痛,Web组态的机会
工业组态软件的老用户应该都体会过这些场景:某个车间主任要改一个报警阈值,流程要走"操作员→车间技术员→信息化部门→厂商驻场工程师",平均一个改动三天下发;服务器装的是Windows Server加专用运行库,加一台设备就要停机重启;画面稍微复杂一点,曲线、报表、历史数据全部绑在单体应用里,想拆成微服务是无从下手的。
Web组态想解决的就是这些问题。浏览器打开即用、服务端集中部署、改动实时生效,这些特性天然适合现代工厂的快速响应需求。但Web组态自己做起来工程量非常大:底层画布要支持拖拽、缩放、连线、图元变形,上层要管理成百上千种组件,再往上还要接实时数据库、告警引擎、权限模型,任何一个环节都是硬骨头。我见过不少团队用SVG加一堆乱糟糟的JavaScript硬写,结果维护半年就废了——组件之间的数据流全靠全局变量传递,状态稍微复杂一点就出bug。
所以SceneV做了个更务实的决定:画布和组件体系用Vue3重写,设备接入和数据存储不重复造轮子,直接站在ThingsBoard的肩膀上。这样一来,团队真正要投入精力打磨的,就只剩下"组态"本身这个最有产品价值的环节。
1.2 为什么底座选Vue3而不是React或Vue2
组态画布最核心的痛点是什么?是数据流。一个电机组件的转速数值每秒钟可能刷新十几次,同时还要根据数值范围切换颜色、触发动画、推动关联设备动作。这类高频、多维、联动的状态变更,恰好是Vue3响应式系统的强项。
相比Vue2,Vue3的Composition API让组态组件内部逻辑可以做真正的复用——我写设备图元的时候,把"数据订阅、状态映射、动画控制"拆成独立的composable函数,不同组件之间可以直接组合这些逻辑,不用再走mixins那种命名空间混乱的老路。而且Vue3的Proxy响应式比Vue2的Object.defineProperty快得多,组件数量上到几百个之后差距非常明显。实测同一份画布在Chrome里拖拽图元,Vue3版本的操作延迟比Vue2版本低大概30%到40%,体感是"能感觉到跟手"和"总觉得慢半拍"的区别。
至于为什么不选React,不是React不好,而是组态平台这种强数据驱动、强响应式绑定的场景,Vue3的心智模型更贴合——模板写DOM、响应式写数据流,不需要为了性能去手写shouldComponentUpdate或者memo依赖数组。
1.3 ThingsBoard在SceneV里的角色,比"数据中台"更接地气
ThingsBoard本身是个完整的开源IoT平台,设备管理、数据采集、遥测存储、告警规则、可视化仪表盘它都有。但它的仪表盘偏通用展示,做复杂工艺流程图、电气一次系统图、管网拓扑这种专业组态非常吃力。SceneV不重复做ThingsBoard已有的数据能力,而是把ThingsBoard抽象成"数据源"——设备影子、遥测历史、RPC指令全部通过标准API暴露给组态画布。
这样做有一个特别大的好处:组态画面和设备接入解耦。今天SceneV接的是ThingsBoard,明天如果要换成JetLinks或者其他IoT平台,只要替换适配层的数据源实现,画布里的几百个组件一行代码都不用改。这也是为什么现在很多原本用ThingsBoard的老用户切换到JetLinks时会考虑SceneV这类方案——画布层和平台层分离之后,平台替换的迁移成本被大大压缩了。
2. 整体架构设计与核心模块拆解
2.1 分层架构:画布组件和数据源之间别搞成乱麻
SceneV的前端架构我按五层拆的:渲染层、组件层、数据流层、配置层、持久层。
渲染层就是画布本身,负责图元的坐标计算、缩放平移、选中高亮和撤销重做。组件层是各种组图元:设备图标、管道、阀门、曲线、仪表盘、表格、告警灯,每种组件都是独立的Vue3单文件组件。数据流层负责从ThingsBoard拉数据,统一转成组件可以绑定的数据模型。配置层就是右侧那个属性面板,改组件颜色、改数据源Key、改告警阈值。持久层把画布结构序列化成JSON存到后端,下次打开直接恢复。
五层之间我用类型定义硬性约束接口,尤其是数据流层和组件层之间的数据模型,全部用TypeScript的interface定义清楚。组件只认数据模型,不关心数据从哪来——是从ThingsBoard WebSocket推过来的,还是从历史库SQL查出来的,组件层一概不管。这个设计看着简单,实际执行的时候特别容易跑偏,因为很多人写着写着就把HTTP请求直接写进了组件代码里。我在SceneV里用ESLint规则约束这个边界,一旦发现组件文件里有fetch或者axios调用直接报错,强制大家走数据流层。
2.2 画布引擎:拖拽、缩放、连线背后的坐标系统
画布引擎是整个组态平台的"物理引擎",煤气管网、电气拓扑、水处理流程都靠它支撑。SceneV的画布没有用第三方拖拽库,而是基于Vue3的自定义指令实现了一套轻量引擎。
核心逻辑是一个画布坐标系和缩放比例的映射关系。组件在画布上存的是逻辑坐标(比如x=200, y=150表示在画布坐标系的位置),渲染时通过transform: scale(zoom)转换成屏幕坐标。拖拽时用pointerdown记录起始坐标,pointermove里把鼠标移动的像素距离除以缩放比例,换算成逻辑坐标的移动量,这样无论画布放大缩小,组件都能精确跟着鼠标走。注意这里必须用pointer事件而不是mouse事件,原因很简单:工业现场很多工程师用的是触控一体机,pointer事件能同时兼容鼠标和触摸。
连线计算是另一个容易翻车的地方。管道类组件和线缆类组件需要把两个设备图元的连接点找出来,画一条折线。SceneV的做法是给每个设备图元声明连接点锚位(上下左右四个方向),连线时自动计算两个锚点的最短折线路径,拐点数量不超过两段。电网拓扑那种复杂图不追求自动避障,人工拖拽拐点反而更可控,这也是组态软件和通用绘图工具的一个明显差异。
2.3 设备与数据链路:WebSocket的心跳比你想的重要
SceneV的实时数据链路长这样:ThingsBoard的Transport层通过MQTT协议接入设备数据,存到Cassandra或PostgreSQL,然后前端通过ThingsBoard的WebSocket API订阅遥测更新。整个链路看起来是四跳,实际在生产环境里影响体验的就是最后一跳——前端和ThingsBoard之间的WebSocket连接稳不稳。
WebSocket连接不稳定,最常见的原因是网关层对长连接有闲置超时配置,Nginx默认的proxy_read_timeout是60秒,而ThingsBoard的WebSocket如果不做心跳保活,超过60秒就会被Nginx掐断。SceneV前端实现了一个15秒一次的PING心跳,服务端收到PING回PONG,这样连接永远不会闲置。这个改动在测试环境根本暴露不出来,但真实工厂的网络环境里跑了三天就会出现遥测"断一会又自己好"的现象,排查半天最后发现是网关超时搞的鬼。
RPC指令下发走的是另一条链路:前端调用ThingsBoard的RPC API(POST /api/rpc/oneway),指定设备名和请求方法,设备收到后执行动作并返回结果。SceneV把RPC调用封装成一个可复用的数据流层方法,组件里"点击按钮→下发停机指令"这种交互就直接调用这个方法,不用关心HTTP细节。
2.4 低代码能力:组件面板、属性配置与数据绑定的三层抽象
低代码组态的"低代码"体现在三个层面:搭页面不用写代码(拖拽组件)、改样式不用写代码(属性面板)、绑数据不用写代码(数据源选择器)。
SceneV的属性面板是基于Schema自动生成的。每个组件注册的时候声明一份属性Schema:颜色、尺寸、文字、数据源Key、告警阈值、动画开关等属性全部用JSON描述,属性面板拿到Schema后自动渲染对应的输入控件。这个设计让新增组件的成本大幅降低——写一个Vue组件,配一份JSON Schema,组件面板和属性面板就都有了。
数据源绑定也走Schema:属性面板里有一个"数据源"下拉框,里面列出当前画布绑定的设备以及设备的实时属性(转速、温度、电流等)。选好之后,SceneV生成一个绑定关系(比如"电机01.转速 → MotorSpeed"),运行时数据流层把ThingsBoard推来的遥测数据按绑定关系分发到各个组件的props上。开发新的组态画面,从头到尾不需要打开代码编辑器,这是组态交付的核心价值。
3. 实操:从零搭建SceneV的核心链路
3.1 初始化Vue3工程,先把环境弄干净
如果你打算照着SceneV的思路自己搭一版,第一步是初始化Vue3工程。我用的是Vite而不是Webpack,原因不复杂:Vite的按需编译在大型组态项目里体验好太多,改一个组件保存后热更新基本在200毫秒以内,Webpack那种全量rebuild在画布组件多了之后能等得人想摔键盘。
初始化命令:
npm create vite@latest scenev-frontend -- --template vue-ts cd scenev-frontend npm install pinia vue-router@4 axios echarts npm install -D sass unplugin-auto-import unplugin-vue-components几个工程化配置建议:路径别名必须配,不然组件里"../../../types"这种相对路径后期会把人逼疯;环境变量按场景分文件(.env.development、.env.production),ThingsBoard的地址和租户凭据放环境变量里,绝不要写死在代码里;全局组件注册用unplugin-vue-components的自动导入,避免main.ts里import几百个组件。
3.2 对接ThingsBoard:动态创建设备和订阅遥测
SceneV经常需要动态创建设备——比如用户在画布上拖了一个新电机图元,他希望图元绑定的设备是真实存在的,而ThingsBoard的设备往往是提前预置好的。SceneV的做法是提供一个"设备同步"按钮,把画布里的设备清单批量同步到ThingsBoard。
用Node.js写一段批量创建设备的脚本,通过ThingsBoard REST API实现:
const axios = require('axios'); const baseUrl = 'https://your-thingsboard-server/api'; // 先登录获取JWT Token const loginRes = await axios.post(`${baseUrl}/auth/login`, { username: 'tenant@example.com', password: 'your-password' }); const token = loginRes.data.token; // 动态创建设备:批量创建10台电机设备 const devices = Array.from({ length: 10 }, (_, i) => ({ name: `motor_${String(i + 1).padStart(2, '0')}`, type: 'motor' })); for (const device of devices) { await axios.post(`${baseUrl}/device`, device, { headers: { 'X-Authorization': `Bearer ${token}` } }); // 给设备设置访问凭证(Access Token),后续设备端接入要用 const credentials = await axios.post(`${baseUrl}/device/credentials`, { deviceId: {}, credentialsType: 'ACCESS_TOKEN' }, { headers: { 'X-Authorization': `Bearer ${token}` } }); console.log(`设备 ${device.name} 创建成功,接入Token:${credentials.data.credentialsId}`); }前端订阅实时遥测,我用的是ThingsBoard的WebSocket API。先获取设备列表,订阅设备遥测更新:
// 订阅指定设备的遥测数据,实时刷新组件状态 const ws = new WebSocket(`${wsBaseUrl}/api/ws/telemetry`); ws.onopen = () => { // 订阅设备motor_01的实时遥测 ws.send(JSON.stringify({ tsSubCmds: [{ entityType: 'DEVICE', entityId: 'motor_01_id', scope: 'LATEST_TELEMETRY', cmdId: 1 }] })); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); // 解析遥测数据,更新数据流层对应的响应式变量 updateTelemetryStore(data); };这个段落的价值在于:很多人以为对接ThingsBoard很麻烦,实际上核心就是"登录拿Token→调REST做设备管理→开WebSocket做遥测订阅"三件事。生产环境里建议把WebSocket连接封装成一个单例服务,避免每个组件各开一个连接把服务端打爆。
3.3 搭第一个组态页面:从拖一个电机到看到实时转速
环境通了之后,搭第一个组态页面就完全是配置活。打开SceneV画布,左侧组件面板搜"电机",拖一个电机图元到画布上,右侧属性面板出现电机的属性:名称、颜色、尺寸、数据源、转速阈值、动画开关。
数据源那里点开下拉框,选择"motor_01.转速"。画布工具栏点"预览",预览模式下电机图元开始接收ThingsBoard推来的实时遥测,转速数字每一秒跳动一次。如果转速超过阈值,图元颜色自动变红,并且弹出一个告警提示。
整个流程下来可能不到十分钟,这就是SceneV这类低代码组态平台在交付端的价值——以前要用代码写半天的实时数据绑定,现在配置几下就完成了。
3.4 工程化性能调优:首屏加载和构建分包
组态平台的用户对性能要求很苛刻,打开一个上百个图元的画面,转圈超过三秒就会被投诉。SceneV做的第一个优化是路由懒加载——画布路由用动态import,首屏只加载登录页和框架壳,画布代码按需下载。第二个优化是ECharts等图表库不要全量引入,按组件需要用哪个图表就import哪个模块:
import { LineChart, PieChart } from 'echarts/charts'; import { GridComponent, TooltipComponent } from 'echarts/components'; import { use } from 'echarts/core'; use([LineChart, PieChart, GridComponent, TooltipComponent]);还有一个容易被忽略的点:组件注册信息包含组件缩略图,缩略图是Base64图片字符串,如果几百个组件的缩略图全打进主包里,主包体积直接膨胀两三兆。SceneV的做法是把缩略图挪到静态资源目录,注册表里只存路径,运行时按需加载。构建结果从差不多1.2MB的首屏JS降到了480KB,这个优化效果比武器库分包还明显。
4. 核心机制深入:低代码组态的关键实现
4.1 页面即JSON:拖拽出来的画面如何变成可存储的结构
SceneV画布里的每个页面,最终都序列化成一个JSON对象。结构大致如下:
{ "pageId": "page_boiler_room", "pageName": "锅炉房工艺监控", "width": 1920, "height": 1080, "components": [ { "id": "comp_001", "type": "motor", "x": 320, "y": 200, "zIndex": 5, "scaleX": 1.2, "scaleY": 1.2, "props": { "title": "1号循环泵", "color": "#2196F3", "dataSource": { "device": "motor_01", "telemetryKey": "speed", "threshold": 1500 } } } ] }这个JSON是运行时的唯一信源。打开页面时读取JSON,渲染器遍历components数组,用动态组件标签把每个组件渲染出来;拖拽结束、属性修改时反向更新JSON;保存按钮把JSON提交给后端。整套逻辑就是一个"渲染器+状态库"的双向同步,复用Vue3的响应式系统做状态追踪,比传统组态软件那种二进制画布文件要灵活得多,也天然支持版本管理——把JSON放进Git仓库里,每次改动都有diff记录。
4.2 拖拽坐标、吸附与对齐,细节都在数学里
拖拽坐标的基础实现前面提过,用pointer事件加上缩放换算。生产环境里真正难用的是对齐辅助线。用户拖一个阀门的图元,总希望它能和旁边的管道端点对齐,这就需要画布引擎实时计算"吸附目标"。
SceneV的实现思路是:当drag中的组件与画布上其他组件的某个关键坐标点(中心点、边缘点)的差值小于6像素时,吸附线出现,同时把组件坐标强制修正到目标坐标上。计算时机放在pointermove事件里,每帧对画布所有组件做一次坐标遍历,几十个组件完全没压力,几百个组件会有一点掉帧。做性能优化时把坐标遍历放到requestAnimationFrame里以30fps的频率节流,视觉上依然顺滑,CPU占用率降了一半。
多选对齐也是重要功能:用户框选多个设备图元后,工具栏提供左对齐、右对齐、垂直居中、水平分布、等间距排列。这些操作的本质都是数学计算——先把选中组件的坐标收集起来,算出目标基准值,再统一改写每个组件的x或y坐标。
4.3 数据源绑定与实时刷新的响应式魔法
数据源绑定的核心是一个数据字典Map:Map<绑定标识符, 最新值>。ThingsBoard WebSocket推来一条遥测,数据流层解析设备名和遥测Key,写入这个Map,同时触发Vue3的响应式更新。
组件侧的数据绑定是这样工作的:每个组件的dataSource配置里声明了"监听哪个设备的哪个遥测Key",组件在onMounted时注册监听器,把数据字典的对应值映射到自己的一个data属性上。Vue3的响应式系统会自动把数据字典做成reactive,子组件对数据的读取建立依赖追踪,数据一更新,所有依赖它的组件自动重渲染。
这里有个细节坑:不要用props层层传递数据,也不要每次WebSocket消息到了就深拷贝整个数据字典然后强制触发全画布重渲染。正确处理方式是让每个组件自己声明依赖的Key,只有依赖的Key变了才触发自己更新。这个用Vue3的computed属性实现最干净——computed里读取数据字典的Key,只有这个Key发生变更,computed才会重新计算,组件才重渲染。没有依赖关系的组件完全不会被波及,画布性能就有了基本保障。
4.4 保存、回显与版本管理的坑
页面JSON的保存看起来简单,实际上有一个很隐蔽的坑:组件props里如果存了函数或Date对象,JSON.stringify会把它们丢得干干净净。SceneV的组态组件在设计时就做了约束,props只允许存基本类型、普通对象和数组,函数一律不存进页面JSON里。组件的交互逻辑(点按钮触发RPC等)通过事件配置表达,比如"onClick": {"action": "rpc", "target": "motor_01", "method": "stop"},运行时事件引擎负责解析执行。
版本管理方面,我强烈建议把页面JSON存进Git而不是数据库的text字段。数据库存text字段也可以,但"这个画面上周还能打开,这周怎么报错了"——很难回答。Git里存JSON,每一版改动都有diff,哪个组件的属性被改过一目了然。SceneV在保存按钮旁边放了一个"提交记录"入口,点开直接调后端Git服务看历史版本,需要回退就checkout某个历史版本再重新保存。
组件升级带来的兼容问题也要提前想好。加了新字段、改了默认值之后,老页面的JSON里没有这个字段,渲染器要处理"缺省字段回退默认值"的逻辑。SceneV在渲染器里做了一层propsMerge:组件注册时声明默认props,渲染时把页面JSON里的用户配置覆盖到默认值上。这个合并操作保证新增字段不会导致老页面白屏或者布局错乱。
5. 常见问题与排查技巧实录
5.1 实时数据不刷新?先查WebSocket心跳
组态页面画完了,预览一看,设备图元的数值一动不动。这种情况十有八九不是画布的问题,而是WebSocket链路断了。排查步骤是:打开浏览器F12,Network面板切到WS标签,看连接状态。如果连接显示closed,那就在代码里加上心跳日志,看PING有没有正常发出、服务端有没有回PONG。
还有一种情况是连接没断,但数据不更新——那就去ThingsBoard的消息日志里查,看设备端有没有真实上报数据。很多时候不是前端的问题,是设备端的网关程序挂了或者Modbus采集器掉线了。我在一个水处理项目里就遇到过:PLC的数据采集程序跑得好好的,但网络交换机的一个端口松了,整个车间上百个点位全变灰色。排查半天最后发现是物理链路的问题,这类问题只能靠"从数据源头往上游逐级排查"的思路来解决。
5.2 画布拖拽卡顿?性能优化三板斧
画布一卡,用户第一反应就是"这平台不行"。SceneV性能优化三板斧,亲测有效。
第一板斧是组件懒渲染。画布可视区域是1920x1080,但实际画布可能很大,一次渲染几百个组件,其实只有屏幕上那二三十个是用户关心的。SceneV实现了一个简单的视口裁剪:根据当前缩放比例和滚动偏移,计算出可视区域,只挂载在可视区域内的组件,离开视口的组件卸载或者进入休眠。这个优化让超大画布的帧率从17fps直接干到接近60fps。
第二板斧是拖拽时局部更新。在拖拽过程中,被拖拽的组件高频率更新坐标,其他组件完全不需要参与重渲染。SceneV的做法是给被拖拽组件设置一个isDragging状态,拖拽期间只有这个组件响应坐标变化,其他组件保持静态渲染,松手后再做一次全量位置重排。
第三板斧是节流。WebSocket消息可能每秒钟推几十条遥测过来,如果每条都触发组件更新,前端会被打爆。SceneV在数据流层加了一个30Hz的节流器,合并同一毫秒内的所有遥测更新,统一触发一次响应式变更。每秒30次刷新对视觉来说已经完全流畅,CPU占用率能降下来一大截。
5.3 Vue3框架坑:UI库不生效、Edge浏览器抽风、TS类型报错
组态项目里除了画布本身,还会有很多外围页面——设备管理列表、告警记录、用户权限等等。很多人发现Vue3引入UI框架(Element Plus、Ant Design Vue)不生效,原因多半是全局注册和按需导入混用了。unplugin-vue-components的自动导入和手动全量注册只能选一种,混用会导致组件样式丢失或者重复注册报错。
Edge浏览器右上角最小化按钮偶尔没反应的问题,我在一个客户现场遇到过。排查到最后是页面上有一个全屏遮罩层在作怪——组态预览模式下某个弹窗组件挂载后没销毁,z-index覆盖到了浏览器的标题栏区域。这类问题的通用解法是在弹窗关闭时彻底销毁DOM,而不是简单隐藏。
TS类型报错主要集中在动态组件上。SceneV的渲染器用<component :is="componentType">动态渲染组件,TypeScript对componentType的类型推断会很模糊。解法是把组件注册表做成类型映射,用一个强类型Map把组件名映射到组件类,再通过泛型组件封装一层,参数透传时做类型校验。
5.4 从ThingsBoard迁移JetLinks的思考
这个圈子最近有个明显的趋势:一些ThingsBoard老用户在评估切换到JetLinks,原因不外乎本地化支持、规则引擎的灵活性、以及国内部署环境的适配。SceneV这类画布层和数据层解耦的设计,恰好降低了这种迁移的摩擦成本。
具体到技术上,迁移的主要工作量在数据流层。ThingsBoard的API路径、Token认证机制、WebSocket消息格式和JetLinks都不一样,但SceneV的数据流层把平台差异封装在适配器里——只要实现同一个接口,返回统一的数据模型,上层的画布组件根本感觉不到底层平台换了。我在一个实验项目里把ThingsBoard换成JetLinks,流量入口的路由改一行配置,画布和组件全部原样运行。这是架构设计带来的红利,比把API调用到处散落在组件代码里要好维护一个数量级。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查思路 | 推荐解法 |
|---|---|---|---|
| 实时遥测不刷新 | WebSocket被网关切断 | 看Network面板WS状态 | 加15秒心跳PING |
| 部分图元空白 | 组件未注册或注册名不匹配 | 打开注册表看type字段 | 统一组件注册名和页面JSON的type |
| 拖拽不跟手 | 坐标没有除以缩放比例 | 在pointermove里打印换算后的坐标 | 像素位移除以zoom再写入逻辑坐标 |
| 保存后打开布局乱 | JSON字段缺省无默认值 | console里看合并后的props对象 | 渲染器增加propsMerge合并默认值 |
| 告警不触发 | 阈值字段和数据源Key拼写不一致 | 查看属性面板里的绑定关系 | 用下拉选择器代替手写Key |
| 大画布掉帧 | 全量组件参与重渲染 | Performance面板看渲染耗时 | 做视口裁剪+拖拽局部更新 |
| 首屏加载慢 | 图表库全量打包 | 看包体积分析报告 | 用echarts/core按需引入 |
| UI库样式错乱 | 自动导入和全量注册混用 | 检查main.ts | 统一用unplugin-vue-components |
6. 下一步扩展:从SCADA到数字孪生的路径
6.1 为组态系统集成AI自动操作
热词里有一条"为web组态系统集成自动操作系统的AI",这个方向我现在正在做。场景是这样的:组态画布上有一台泵,传统运营模式是工程师看到温度超标,手动点击按钮下发停机指令,或者依赖预先写死的规则链自动停机。这中间有两个问题——规则链是静态的,没法根据复杂的工况组合来动态决策;工程师手动操作有延迟,半夜三更一个小故障就可能扩大成大事故。
SceneV的扩展思路是把AI决策引擎作为数据流层的一个独立模块插进来。AI模块接收遥测流、工况配置、历史数据,输出决策信号(比如"建议降低泵转速至80%"),数据流层再把决策信号映射成设备RPC指令下发。画布组件上新增一个"AI建议"状态位,用户可以看到AI建议的操作和设备自动执行的结果。整个链路不需要改画布渲染逻辑,只是数据流层多了一个决策消费者。
实现上,前端用WebSocket把实时数据转发到本地的Python推理服务(或者调用远程推理API),推理服务返回结构化决策结果。这里有个安全边界要把握好:AI决策建议模式改为自动执行模式时,必须有严格的权限审批和操作审计,工业自动化场景里"自动操作"一定要有回退机制,手动干预永远是最高优先级。
6.2 从2D组态到3D组态的自然过渡
热词里的"vue3 + three.js + typescript 机房"说明很多人在探索3D可视化。SceneV的路线图里,3D并不是推翻2D重做,而是把3D场景作为一个特殊的组态组件嵌入画布——在2D页面上放一个"3D场景"组件,组件内部用Three.js渲染机房的三维空间,设备位置和状态通过同一个数据流层从ThingsBoard拉取。
这个方案的工程量可控,而且复用了2D组态的数据绑定和低代码配置能力。3D场景里设备的拾取、高亮、弹窗信息,和2D组件的行为模式完全一致,用户可以在一张页面上同时看到2D工艺流程图和3D空间展示,两种视角互相联动——这是工业可视化里用户体验最好的一种方式,也是数字孪生落地的一个比较实际的状态。
实现的第一版建议用three.js的CSS2DRenderer做设备标签,这样3D场景里的设备名称、状态值可以用DOM元素渲染,改样式方便,也天然支持中文排版。TypeScript的好处这时候就体现出来了——场景里的设备类型、坐标、状态枚举全部走类型定义,比起纯JavaScript裸写Three.js,代码的健壮性会高很多。
6.3 我个人在实际搭建中的体会
做了SceneV这大半年,我最大的感受是:不要把"低代码"理解成一个花哨的面子工程,它的本质是把重复劳动沉淀成可复用的能力。组态交付里90%的重复工作——设备接线、数据绑定、样式调整、页面跳转——都值得被抽象成配置,而不是每次用代码重新写一遍。真正有创造力的那10%(复杂联动逻辑、新组件开发、异常处理策略),留在代码里让高级工程师去打磨,这才是低代码平台该有的边界感。
如果你正在考虑自研或者引入一套Web组态方案,我建议别一上来就追求"全功能",先把"拖一个设备图元、绑一个实时数据、出一个报警画面"这条最小闭环跑通。场景跑通了,后面加组件、加动画、加联动,都是水到渠成的事。架构上记得把画布层和数据层拆开,这个决定会在你以后换IoT平台、接AI模块、做3D扩展的时候,让你少走很多弯路。