
在实际的工控项目中SCADA 监控界面的开发往往是整个实施周期里最耗时的环节之一。工艺画面中的反应釜、离心泵、阀门、管道和电机每个设备图元都要绘制测点绑定、量程转换、告警闪烁和趋势曲线又要分别实现。更麻烦的是这类工作在不同项目里高度重复组态工程师很难从中积累出高效率的通用方法。Claude Code 这类 AI Agent 工具出现后这个环节开始有了明显变化它可以直接读取项目目录、生成 SVG 图元、编写数据绑定逻辑并按照自然语言描述逐步调整界面。下面用一个完整的中控 SCADA 监控界面案例演示如何用 Claude Code 从无到有建立图元库、测点服务、页面渲染和告警功能同时说明哪些代码可以直接复用哪些地方在实际生产中必须继续加固。这个案例面向三类读者正在做 Web 化 SCADA 或物联网监控平台的开发人员想用 Claude Code 提升组态效率的工控工程师以及刚开始接触 AI Agent 编程、需要一个完整练习项目的学习者。案例最终产出的不是商业级 SCADA而是一个能演示完整数据链路的最小监控系统读者可以在此基础上替换数据源、扩充图元库逐步变成自己的工程模板。1. 先理解 SCADA、HMI、PLC 的区别才知道 AI 该介入哪个环节1.1 三者的角色和协作关系SCADASupervisory Control and Data Acquisition监视控制与数据采集系统、HMIHuman Machine Interface人机界面和 PLCProgrammable Logic Controller可编程序控制器是工控行业最常一起出现的三个词但分工完全不同。PLC 是底层控制设备。它采集现场开关量和模拟量执行逻辑控制输出给执行机构。它是“干活”的那一层。HMI 是单机界面通常挂在控制柜或操作台旁边与一台或几台 PLC 直接通信显示局部设备状态供操作员就地操作。SCADA 是厂级或区域级集中监控系统它聚合多套 PLC、RTU 或其他采集站的数据提供统一画面、历史存储、趋势分析、告警管理和报表功能通常运行在调度中心或工程师站。层次典型设备/系统核心功能数据范围典型使用者PLC西门子 S7-1500、三菱 FX、施耐德 M580逻辑控制、IO 采集、回路调节单台设备或单条产线控制工程师、维护电工HMI触摸屏、工控一体机就地显示与操作单台设备或局部流程现场操作员SCADAWinCC、组态王、InTouch、自研平台集中监控、历史库、告警、报表全厂或全区域调度员、值班长SCADA 不等于 HMI。SCADA 通常包含 HMI 的显示能力但还要承担数据采集、历史存储、告警分析和管理功能。近年越来越多的轻量级 SCADA 采用 Web 架构浏览器直接打开监控画面这也是本案例选型的切入点。1.2 监控界面开发的真实工作量在哪里做一个监控画面不只是“画一张流程图”。完整的组态工作包括梳理工艺流程图PID和测点清单绘制反应釜、储罐、泵、阀门、管道、搅拌器、换热器等设备图元建立测点标签Tag与图元的绑定关系编写量程转换、报警上下限、单位显示规则实现设备状态颜色、动画和告警闪烁再补充趋势曲线、历史查询和报表导出最后接入 OPC UA、Modbus TCP、MQTT 或自定义数据服务。这几项里图元绘制、数据绑定、量程转换、告警闪烁在项目里高度重复。每个项目都要重画类似图元都要重写“数值-图元-颜色”的绑定逻辑。这些恰恰是 AI 生成效率最高的部分。真正需要工程师介入的是工艺理解的确认、测点清单的准确性和数据来源的连通性而不是反复画同一个离心泵。1.3 为什么这个场景适合 Claude CodeClaude Code 是 Anthropic 推出的命令行 AI Agent它可以直接读取项目文件、生成和修改代码、执行命令。与网页端对话不同它工作在真实的项目目录里一次对话可以跨多个文件改动。对 SCADA 界面这种“图画 数据 逻辑”的混合体它的能力匹配度很高。图元可以用 SVG 描述AI 对 SVG 结构处理得比较稳定数据绑定是标准 JavaScript 逻辑AI 生成后可以直接运行工艺画面有明确测点清单把需求拆成小轮次对话AI 可以逐步完成。这个案例的核心目标是用 Claude Code 生成一套完整的 Web 版 SCADA 监控界面SVG 图元库、测点数据服务、画面渲染、告警闪烁和简单趋势展示并且全部在本地可运行。2. 准备 Claude Code 运行环境先把工具链路跑通2.1 前置要求与环境确认使用 Claude Code 生成项目需要先准备以下环境项要求说明Node.js18.0 或更高Claude Code 本体运行在 Node 环境npm随 Node 安装用于安装 Claude Code 和 mock 服务依赖访问凭据Claude 账号或 ANTHROPIC_API_KEY首次启动需要登录编辑器VS Code、终端均可本项目主要使用终端操作先检查 Node 版本node -v npm -v两条命令都正常输出版本号后再继续安装。版本过旧时建议先升级 Node 到 LTS 版本否则 Claude Code 可能出现运行时异常。2.2 安装 Claude Code使用 npm 全局安装npm install -g anthropic-ai/claude-code安装结束后验证版本claude --version首次运行claude终端进入交互模式首次启动会引导完成登录或配置 API Key。登录成功后可以在任意项目目录运行claude开始对话。如果是自动化脚本可以用非交互模式claude -p 列出当前目录下的所有文件并说明用途-p表示非交互式输出模式适合在脚本或 CI 中调用。日常开发建议使用交互模式因为 Claude Code 会请求文件修改权限交互模式下可以直接确认允许或拒绝。注意Claude Code 操作文件前会请求权限。第一次使用时遇到工具调用提示可以逐个确认熟悉后再用--allowedTools或权限模式统一授权避免每次都在终端反复按确认键。2.3 建立项目目录和 CLAUDE.md先在本地创建项目目录mkdir scada-demo cd scada-demo npm init -y然后创建CLAUDE.md。这个文件会被 Claude Code 自动读取作为项目的长期记忆。内容写得越清楚AI 生成的代码越符合项目约定# SCADA Demo 项目说明 ## 项目目标 用纯 HTML/CSS/JavaScript 实现一个轻量级 Web SCADA 监控界面。 ## 技术约定 - 页面使用原生 JavaScript不引入前端框架。 - 所有设备图元使用 SVG 绘制保留元素 id 用于数据绑定。 - 测点数据统一格式{ tagId, name, value, unit, quality, alarmHigh, alarmLow, timestamp }。 - 数值显示保留一位小数单位显示在数值右侧。 - 告警状态使用 CSS 类 .alarm-blink 触发闪烁。 ## 常用命令 - 启动 mock 数据服务node mock/server.js - 页面通过浏览器打开 index.html ## 目录结构 - svg/图元源文件 - js/tags.js测点定义 - js/devices.js设备与图元映射 - js/render.jsSVG 渲染 - js/data-service.js数据刷新 - js/alarm.js告警判定 - mock/server.js模拟数据接口CLAUDE.md 不需要写得长关键是让每次会话开始时不重复解释项目背景。后续项目约定有变化记得同步更新这个文件否则 AI 会一直按旧约定生成代码。2.4 先做一个最小验证在开始写监控界面之前先验证 Claude Code 是否真的能读写项目文件。在项目目录里运行claude -p 创建 index.html 文件内容为一个空白的 HTML 页面通过 css/style.css 和 js/app.js 引入样式与脚本并创建这两个文件。命令结束后检查目录ls -l index.html css js能正常生成文件说明安装、登录、权限链路都没有问题。这一步的价值是提前暴露环境问题而不是等到生成大量代码之后才发现工具不可用。3. 先定数据模型再让 AI 画界面SCADA 界面看起来是“画”本质是“数据绑定”。如果测点结构、设备 ID、渲染规则没有统一AI 生成的每一轮代码都可能互相冲突。因此进入 Claude Code 之前先把数据模型写清楚。3.1 测点Tag数据结构单个测点定义{ tagId: T-1001, name: 1号反应釜温度, description: 反应釜内介质温度, device: R-1001, unit: ℃, value: 86.5, quality: GOOD, alarmHigh: 95, alarmLow: 10, alarmState: NORMAL, timestamp: 2025-01-15T14:30:0008:00 }字段含义如下字段含义取值示例tagId测点唯一标识T-1001、PUMP-01.OUT_PRESSdevice所属设备 IDR-1001、PUMP-01value当前数值86.5quality数据质量GOOD / BAD / STALEalarmHigh / alarmLow报警上下限95 / 10alarmState报警状态NORMAL / HIGH / LOW / OVERRIDEalarmState可以前端根据 value 与 alarmHigh/alarmLow 计算也可以在服务端算好后下发。演示项目放在前端计算简单直观生产风格建议服务端计算并下发这样权限判断、历史记录和画面端展示共用同一套告警结果避免前端逻辑被绕过导致显示不一致。3.2 设备与图元映射SCADA 画面里一个设备可能包含多个测点。例如一台离心泵有运行状态、出口压力、电机电流、轴承温度四个测点。在代码里用一个设备对象统一描述const DEVICES { PUMP-01: { name: 冷却水泵A, type: centrifugal-pump, svgId: dev-pump-01, position: { x: 320, y: 180 }, tags: { status: PUMP-01.RUN, pressure: PUMP-01.OUT_PRESS, current: PUMP-01.MOTOR_CURRENT, bearingTemp: PUMP-01.BEARING_TEMP } } };这种结构做好后Claude Code 只需要按相同结构扩展新设备不需要每次重新设计设备模型。设备 ID、SVG 元素 ID、测点 ID 形成三层映射画面层找 svgId 定位图元数据层找 tagId 关联测点设备层把二者串起来。3.3 先搭一个 Node Mock 数据服务页面需要一个数据来源。真实项目会接 OPC UA 或 Modbus但演示阶段用 Mock 服务可以快速把画面和数据链路串起来。在mock/server.js中const http require(http); const tags { PUMP-01.OUT_PRESS: { value: 0.42, unit: MPa, alarmHigh: 0.6, alarmLow: 0.1 }, PUMP-01.MOTOR_CURRENT: { value: 38.2, unit: A, alarmHigh: 45, alarmLow: 5 }, PUMP-01.BEARING_TEMP: { value: 61.3, unit: ℃, alarmHigh: 75, alarmLow: 0 }, T-1001: { value: 86.5, unit: ℃, alarmHigh: 95, alarmLow: 10 } }; const server http.createServer((req, res) { if (req.url /api/tags/latest) { res.setHeader(Content-Type, application/json); res.end(JSON.stringify(tags)); return; } res.statusCode 404; res.end(Not Found); }); server.listen(3100, () { console.log(mock data server running at http://localhost:3100); });这里故意使用 Node 原生 http 模块不引入 Express减少依赖。启动命令node mock/server.js接口返回 JSON前端按 tagId 更新对应页面元素。生产环境替换这个接口时只需要保持响应格式不变画面层无需改动。4. 用 Claude Code 生成监控界面的三轮迭代过程数据模型准备完成后进入核心环节让 Claude Code 生成界面。建议分三轮对话每轮聚焦一个目标避免一次生成过多文件导致结构混乱。每轮结束后都实际运行一遍确认没有错误再进入下一轮。4.1 第一轮生成页面骨架和 SVG 图元库在项目目录运行交互模式claude输入第一条需求在项目中创建一套工业监控页面。 1. 新建 index.html、css/style.css、js/app.js。 2. 页面左侧是设备列表中间是工艺流程画面顶部显示系统标题和当前时间。 3. 在 svg/ 目录下创建离心泵、闸阀、储罐、电机四个 SVG 图元文件。 4. 图元要元素化每个图元保留 id如 pump-body、pump-impeller便于 JavaScript 控制颜色和动画。Claude Code 会读取 CLAUDE.md然后创建文件。生成的离心泵图元大致如下svg viewBox0 0 120 120 xmlnshttp://www.w3.org/2000/svg circle idpump-body cx60 cy60 r42 fill#e2e8f0 stroke#334155 stroke-width3/ circle idpump-inlet cx18 cy60 r10 fill#94a3b8/ circle idpump-outlet cx102 cy60 r10 fill#94a3b8/ path idpump-impeller dM60 60 L75 45 A25 25 0 0 1 75 75 Z fill#64748b/ /svg这里的关键不是图元画得多精细而是每个关键部位都有 id。后续数据绑定时JavaScript 通过这些 id 改变填充颜色、旋转角度或显示文本。可以在 SVG 外层包一个g idpump-symbol方便外部用use引用。4.2 第二轮绑定测点数据和运行状态页面骨架就绪后继续对话把 mock/server.js 的测点数据显示到页面上。 1. 读取 js/tags.js 中的测点定义。 2. 按设备位置把数值显示在对应图元下方。 3. 泵运行时泵体显示为绿色停止时显示为灰色告警时显示为红色。 4. 增加一个 2 秒一次的轮询调用 /api/tags/latest 更新数值。Claude Code 会生成render.js和>async function refreshTags() { const res await fetch(http://localhost:3100/api/tags/latest); const data await res.json(); for (const [tagId, tag] of Object.entries(data)) { updateDeviceView(tagId, tag); } } function updateDeviceView(tagId, tag) { const device findDeviceByTag(tagId); if (!device) return; const valueEl document.getElementById(value-${tagId}); if (valueEl) { valueEl.textContent ${tag.value.toFixed(1)} ${tag.unit}; } const body document.getElementById(device.svgId); if (body) { body.classList.toggle(run, tag.value 0); body.classList.toggle(alarm, tag.value tag.alarmHigh || tag.value tag.alarmLow); } } setInterval(refreshTags, 2000); refreshTags();第一版可能把逻辑都写在 app.js 里不用急着拆分。跑通后再让 Claude Code 按 CLAUDE.md 的目录约定拆文件。如果接口地址因前端打开方式不同出现跨域问题需要在 mock 服务里加跨域响应头或者让前端也通过同源静态服务器访问。4.3 第三轮加入告警闪烁、趋势曲线和设备操作数据绑定跑通后继续叠加功能增加三个功能 1. 告警闪烁处于告警状态的测点数值文字和对应图元周期闪烁。 2. 趋势曲线点击测点后弹出一个显示最近 10 分钟近似实时曲线的窗口。 3. 点击泵图元弹出操作确认框显示“启动/停止”按钮按钮点击后向 mock 接口 POST /api/devices/PUMP-01/command。告警闪烁的实现.alarm-blink { animation: alarmBlink 1s steps(2, start) infinite; } keyframes alarmBlink { 0% { opacity: 1; } 50% { opacity: 0.15; } 100% { opacity: 1; } }这里使用steps(2, start)制造顿挫感比线性淡入淡出更符合工业告警的视觉习惯。实际项目中操作员点“确认”后通常要求闪烁停止但告警色保留这需要在 alarm.js 里增加acknowledged状态字段。4.4 让 Claude Code 按反馈迭代如果生成的界面不符合预期直接用自然语言提修改意见设备列表里的“冷却水泵A”点开没有反应检查一下 DEVICES 配置和点击事件是否注册成功。修复后把原因写进 CLAUDE.md 的问题记录里。这种“现象 期望 自查方向”的反馈方式比直接说“不对”有效得多。Claude Code 会定位到对应文件修改后通常会说明它认为的根因。一轮对话解决一个问题避免一次反馈五六个问题导致改动互相干扰。注意AI 生成的代码不是一次到位。每一轮功能合并后都要实际跑一遍把错误信息和界面现象带进下一轮对话它才能准确修复。只口头描述“界面不对”容易让 AI 猜测越具体越好。5. 关键代码和参数怎么理解才能自己改得动5.1 SVG 图元坐标系、锚点和缩放SCADA 图元最容易踩的坑是坐标错位。SVG 的viewBox决定坐标系图元文件内部使用相对坐标放进工艺流程画布时要通过x、y或transform定位。推荐每个图元文件独立使用viewBox0 0 120 120外部使用时用use引用svg classdevice x320 y180 width80 height80 use hrefsvg/pump.svg#pump-symbol/ /svg如果直接把所有设备画在一个大 SVG 里图元之间坐标会互相影响AI 后续增删设备时容易改乱。按设备拆分成独立符号再用use复用是更稳妥的结构。另一个注意点是使用时给容器设置了width和height后SVG 内部会按viewBox等比缩放不要把外部宽高和内部坐标混在一起计算。5.2 数据刷新轮询与 WebSocket 的选择演示项目用 2 秒轮询最简单。但生产环境要按实时性和并发数选择模式实时性服务端压力实现复杂度适用场景定时轮询秒级高请求数与客户端数成正比低测点少、刷新频率要求不高WebSocket 推送毫秒级低只推变更中中大型 SCADA、操作频繁SSEServer-Sent Events亚秒级中低单向推送不需要客户端上行真实 SCADA 系统测点可能上万轮询会放大数据库和网络压力。建议初期用轮询跑通链路接入生产数据后改为 WebSocket 按订阅推送或通过中间数据网关统一做状态更新广播。5.3 告警判定死区、延时和确认位简单比较value alarmHigh会产生边界抖动。生产环境的告警判定至少包括三部分死区、延时和确认位。死区示例function isAlarm(tag) { const high tag.alarmHigh; const low tag.alarmLow; const deadband tag.deadband || 0.5; if (tag.alarmState NORMAL) { if (tag.value high) return HIGH; if (tag.value low) return LOW; } else { if (tag.alarmState HIGH tag.value high - deadband) return NORMAL; if (tag.alarmState LOW tag.value low deadband) return NORMAL; } return tag.alarmState; }死区的作用是防止数值在上限附近反复越过阈值造成告警抖动。不同测点的死区不一样压力测点可能 0.05温度测点可能 1。延时是指持续超限一定时间才触发告警避免瞬时扰动误报确认位是操作员处理告警后置位的标记。这些规则在最初向 Claude Code 提需求时就应该包含否则后面加会改动多处逻辑。5.4 数值格式化单位、量程、精度SCADA 界面最常见的显示错误是数值格式不统一。推荐在前端统一格式化函数function formatTagValue(value, unit, decimals 1) { if (value null || value undefined) return --; return ${Number(value).toFixed(decimals)} ${unit}; }量程转换要在数据进入画面之前完成。例如 4-20mA 信号转换成工程值function scaleRawToEng(raw, rawMin, rawMax, engMin, engMax) { return engMin ((raw - rawMin) / (rawMax - rawMin)) * (engMax - engMin); }这些函数让 Claude Code 直接复用能减少大量“数字对不上”的返工。精度也要按测点类型区分温度一位小数流量两位小数压力可能三位。可以在测点定义里增加decimals字段格式化函数按字段取值而不是全局写死。6. 运行验证和常见问题排查6.1 本地启动步骤完整启动流程cd scada-demo node mock/server.js然后另开一个终端用静态服务器打开页面npx serve .浏览器访问http://localhost:3000或npx serve输出的地址。如果页面能显示设备图元、数值每 2 秒刷新、模拟告警时能闪烁说明主链路已经跑通。6.2 验证清单把下面的检查项过一遍能避免大多数“看起来能用但实际有问题”的情况检查项预期结果mock 服务返回 JSON浏览器直接访问接口能看到测点数据页面无 Console 错误开发者工具 Console 无红色报错数值和单位显示每个测点都有数值和单位缺失显示 --告警状态变化人为改 mock 值超过上下限图元和数值出现告警色告警闪烁告警期间数值文字周期性闪烁图元位置泵、罐、阀门位置符合工艺流程布局管道连接正确点击事件点击设备能弹出操作或详情窗口6.3 常见问题排查结合这个项目的实际运行常见问题如下问题现象可能原因检查方式处理建议页面空白图元不显示JS 报错中断渲染Console 第一条报错优先修复第一个报错后续问题往往都由它引起数值一直不刷新接口地址或跨域配置错误Network 面板看请求是否 200mock 服务加跨域头或用同源静态服务器图元颜色不变化SVG id 与 JS 取到的 id 不一致Console 打印 getElementById 结果统一 ID 命名检查use内外 id 作用域告警闪烁不生效CSS 动画类未触发或类名不一致Elements 面板看是否有 alarm-blink 类确认类名与 CSS 定义一致数值显示 NaNvalue 为字符串或空值检查接口返回字段类型使用 Number() 转换空值显示 --Claude Code 无法修改文件权限未允许查看终端权限提示按 y 允许目标工具操作排查顺序建议先看 Console再看 Network最后看 Elements。Console 报错优先修复因为它通常阻断后续脚本执行。Network 面板能区分是接口没返回、返回格式不对还是前端渲染失败这一步比盲目改代码更有效率。7. 从 AI 生成到生产环境落地7.1 AI 生成的代码要先过这几关Claude Code 生成的监控界面可以快速演示但不能直接部署到生产控制网络。落地前至少要补齐以下内容维度需要补的工作认证与授权页面登录、角色权限只读/操作/管理操作审计设备启停指令记录操作人和时间可靠性接口异常重试、断线重连、数据缓存历史库用时序数据库存储测点历史替代内存数组部署形态HTTPS、反向代理、进程守护可观测性前端错误上报、接口耗时统计、告警日志学习环境跑通后至少要按这个清单逐项确认生产差异。特别是操作审计和外层认证ACADA 系统处在工控网络核心位置权限薄弱比界面卡顿问题严重得多。7.2 对接真实数据采集演示项目的 Mock 接口要替换为真实数据服务。常见接入方式有三种OPC UA西门子、罗克韦尔等 PLC 生态常用服务端暴露节点前端或中间层通过 OPC UA 客户端订阅。Modbus TCP老设备常见通常写一个网关服务把 Modbus 寄存器映射成 JSON 接口。MQTT设备或采集网关向 Broker 上报数据前端通过 WebSocket 订阅。无论哪种方式建议中间加一层数据网关对外统一输出本案例的测点 JSON 格式。这样画面层不需要因为更换数据源而重写。网关内先做量程转换、单位统一、质量戳标记和数据缓存画面只消费标准测点结构。7.3 沉淀可复用资产如果团队要长期用 Claude Code 做 SCADA 界面可以把这次生成的内容沉淀成专用资产SVG 图元库泵、阀、罐、电机、管道、仪表按设备类型整理后续项目直接复用。CLAUDE.md 模板把测点格式、图元 id 规则、告警样式约定写成通用模板。提示词模板把“生成页面骨架”“绑定测点”“加告警”写成标准化 Prompt。代码评审清单AI 每完成一轮用固定清单检查坐标、单位、告警和错误处理。沉淀之后下一个新项目可以在更短时间内跑出完整原型工程师把时间花在工艺确认和数据接入上而不是反复画图元、反复调绑定。对于新人建议从一个小型水处理或泵站画面开始练三个罐、两个泵、六条管道、十来个测点跑通后再扩展到多画面切换、历史趋势、权限管理。这个案例本身也可以继续加画面导航、报表导出和设备联锁提示逐步接近完整 SCADA 的功能边界。使用 AI Agent 做组态的核心价值不是让 AI 替代工程师而是把重复劳动压缩到最低让工程师把精力放到真正需要工艺判断和数据理解的部分。