跳到主要内容

HMI 脚本 API

Darra HMI 在运行时向页面注入全局对象 window.Darra(定义在 /static/darra-plc.js),封装了 WebSocket 通信、变量订阅、页面导航、系统信息查询等全部运行时能力。所有自定义 JS 脚本必须通过 Darra.* 访问 PLC 数据,严禁直接操作 WebSocket。

Darradarra 是同一个全局对象。文档中 Darra.xxx()darra.xxx() 等价。推荐使用大写 Darra 以区别于 Alpine.js 的 $data 约定。


一、变量读写 API

Darra.readVariable(varName) — 读取单变量

const value = Darra.readVariable('DB1.Temperature')
console.log(value) // 25.3

从本地缓存同步读取(不走 WebSocket),未订阅的变量返回 undefined

参数类型说明
varNamestringPLC 变量地址,IEC 61131-3 语法
返回值说明
number | boolean | string | undefined变量当前缓存值

Darra.writeVariable(varName, value, options?) — 写入单变量

// 基础写入
Darra.writeVariable('M0.0', true)
Darra.writeVariable('DB2.Setpoint', 75.5)

// 带选项
Darra.writeVariable('DB2.Setpoint', 80.0, {
reason: '操作员调整',
requireSignature: false
})

异步写入,不等待响应。关心结果请监听 error 事件。

参数类型说明
varNamestring变量地址
valuenumber | boolean | string写入值
options.reasonstring写入原因(审计日志用)
options.requireSignatureboolean是否需要电子签名

行为

  • 发送到 Service,Service 校验 WriteWhitelist,未通过返回 error 事件
  • 写入后下一次推送会带新值,绑定的回调自动触发
  • options.requireSignature === true 且当前用户未签名,Service 会先弹电子签名对话框

Darra.writeGroup(values) — 批量写入

Darra.writeGroup({
'DB2.Setpoint': 75.5,
'M0.1': false,
'MW100': 1234
})

一次 WebSocket 帧完成所有写入,性能优于多次 writeVariable。返回值与单变量写入相同。


Darra.subscribeVariable(varName, callback) — 订阅变量变化

const unsubscribe = Darra.subscribeVariable('DB1.Temperature', (value, meta) => {
console.log(`温度: ${value} ℃, 质量: ${meta.quality}`)
})
// 取消订阅
unsubscribe()
参数类型说明
varNamestring变量地址
callback(value, meta)function值变化回调
meta 属性类型说明
meta.timestampnumber服务端采集时间 (ms since epoch)
meta.quality'good' | 'bad' | 'cached'数据质量
meta.type'number' | 'boolean' | 'string'数据类型

行为

  • 订阅自动发送到 Service;断线重连后自动重新订阅
  • 如果已有缓存值,立即回调一次(quality='cached'
  • 返回 unsubscribe 函数,调用后停止接收更新
  • 同一变量可多次订阅,每个 callback 独立触发

Darra.subscribeGroup(vars, callback) — 订阅变量组

Darra.subscribeGroup(['DB1.T1', 'DB1.T2', 'M0.0'], (values) => {
// values = { 'DB1.T1': 25, 'DB1.T2': 26, 'M0.0': true }
console.log('任一变化:', values)
})

任一变量变化时整组回调。values 包含所有组内变量的最新值(不只是变化的)。


Darra.subscribeDB(dbName, callback) — 订阅整个 DB

Darra.subscribeDB('DB1', (values) => {
// values = { Temperature: 25.3, Pressure: 1.2, Level: 80.5 }
})

整个 DB 块任一字段变化触发一次 callback,参数是增量字段的对象(只含变化的字段)。


Darra.unsubscribeAll() — 取消所有订阅

Darra.unsubscribeAll()

清除当前页面的所有变量订阅。常用于页面销毁时的清理。


二、页面管理 API

Darra.navigateTo(route) — 页面导航

Darra.navigateTo('/reactor')
Darra.navigateTo('/alarm')
Darra.navigateTo('/') // 回到首页

切换到指定路由的 HMI 页面。

参数类型说明
routestring目标页面路由,如 /reactor

行为

  • 向 Service 发送导航请求,Service 返回新页面的 HTML/CSS/JS
  • 当前页面触发 pageLeave 事件,新页面触发 pageEnter 事件
  • 如果目标页面已加载过,默认走 Suspend/Resume 而非重新渲染

Darra.showPopup(html, options?) — 显示弹出窗口

Darra.showPopup('<h2>确认停车?</h2><button onclick="Darra.closePopup(true)">确认</button>', {
width: 400,
height: 300,
modal: true,
title: '停车确认'
})

在当前页面之上弹出一个模态或非模态窗口。

参数类型默认值说明
htmlstring弹出窗口的 HTML 内容
options.widthnumberauto窗口宽度 (px)
options.heightnumberauto窗口高度 (px)
options.modalbooleantrue是否模态(阻止背景交互)
options.titlestring''标题栏文字
options.closeOnEscbooleantrue是否允许 ESC 关闭
options.onClosefunction关闭时的回调

返回值:弹出窗口的引用,可用于编程关闭。


Darra.closePopup(result?) — 关闭弹出窗口

Darra.closePopup(true)   // 关闭当前最上层弹出窗口
Darra.closePopup() // 不带返回值关闭

Darra.getCurrentRoute() — 获取当前路由

const route = Darra.getCurrentRoute()
console.log(route) // '/reactor'

三、系统 API

Darra.getSystemInfo() — 获取系统信息

const info = Darra.getSystemInfo()
// {
// "version": "1.0.5",
// "runtimeMode": "Production",
// "uptime": 3600,
// "projectName": "ReactorControl",
// "plcCycleTime": 5,
// "memoryUsage": 45,
// "cpuLoad": 32
// }
返回值类型说明
versionstringService 版本号
runtimeMode'Dev' | 'Test' | 'Production'当前运行模式
uptimenumberService 已运行秒数
projectNamestring当前加载的项目名称
plcCycleTimenumberPLC 扫描周期 (ms)
memoryUsagenumber内存使用百分比
cpuLoadnumberCPU 负载百分比

Darra.getAlarms(filter?) — 获取报警列表

// 获取所有报警
const allAlarms = Darra.getAlarms()

// 获取未确认的报警
const activeAlarms = Darra.getAlarms({ acknowledged: false })

// 按严重度筛选
const criticalAlarms = Darra.getAlarms({ severity: 'Critical' })
参数类型说明
filter.acknowledgedbooleantrue 只返回已确认,false 只返回未确认
filter.severitystring'Critical' | 'Warning' | 'Info'
filter.sourcestring按来源筛选(如 'DB1'
filter.limitnumber最大返回条数,默认 100
返回值说明
Array<{ id, severity, source, message, timestamp, acknowledged, ackUser }>报警数组

Darra.acknowledgeAlarm(alarmId, reason?) — 确认报警

Darra.acknowledgeAlarm('alarm-001', '已确认,安排处理')
参数类型说明
alarmIdstring报警 ID
reasonstring确认原因(可选,审计用)

Darra.getUserInfo() — 获取当前用户信息

const user = Darra.getUserInfo()
// {
// "username": "wang",
// "role": "engineer",
// "displayName": "王工",
// "permissions": ["read", "write", "recipe", "alarm_ack"]
// }
返回值类型说明
usernamestring登录用户名
role'admin' | 'engineer' | 'operator' | 'viewer'当前角色
displayNamestring显示名称
permissionsstring[]权限列表

Darra.logout() — 登出

Darra.logout()

清除当前登录会话,页面跳转到登录页。


四、数据绑定 API

Darra.bindElement(element, varName) — 绑定 DOM 元素

const el = document.getElementById('temp-display')
Darra.bindElement(el, 'DB1.Temperature')
// 元素 textContent 会自动更新为变量值

将 DOM 元素的 textContent 自动绑定到 PLC 变量。元素值随变量更新自动变化,无需手动写回调。

参数类型说明
elementHTMLElement要绑定的 DOM 元素
varNamestring变量地址

Darra.bindElementAttribute(element, varName, attribute) — 绑定元素属性

const led = document.getElementById('status-led')
Darra.bindElementAttribute(led, 'M0.0', 'class')
// M0.0 = true → led.className = 'on'
// M0.0 = false → led.className = 'off'

将 DOM 元素的任意属性绑定到 PLC 变量。

参数类型说明
elementHTMLElement要绑定的 DOM 元素
varNamestring变量地址
attributestring要更新的属性名(如 'class', 'style', 'src'

变量值到属性值的映射

  • boolean → 自动转为 'true' / 'false'
  • number → 自动转为字符串
  • string → 直接使用

Darra.bindElementStyle(element, varName, cssProperty, thresholds?) — 绑定样式

const bar = document.getElementById('level-bar')
Darra.bindElementStyle(bar, 'DB1.Level', 'width', {
min: 0,
max: 100,
unit: '%'
})
// DB1.Level = 75 → bar.style.width = '75%'

带阈值映射的样式绑定。

参数类型默认值说明
elementHTMLElementDOM 元素
varNamestring变量地址
cssPropertystringCSS 属性名(如 'width', 'opacity', 'background'
thresholds.minnumber0变量最小值
thresholds.maxnumber100变量最大值
thresholds.unitstring''单位后缀(如 '%', 'px'

Darra.unbindElement(element) — 解除元素绑定

Darra.unbindElement(document.getElementById('temp-display'))

解除之前通过 bindElement / bindElementAttribute / bindElementStyle 建立的绑定。


五、事件与生命周期 API

Darra.on(event, callback) — 事件监听

Darra.on('ready', () => console.log('WebSocket 已连接'))
Darra.on('offline', () => console.warn('连接断开'))
Darra.on('error', (err) => console.error(err.type, err.var, err.error))
Darra.on('alarm', (alarm) => {
if (alarm.severity === 'Critical') {
showAlarmPopup(alarm)
}
})
事件名触发时机参数
readyWebSocket 首次连上或重连成功
offlineWebSocket 断开
error写入失败 / 订阅失败{ type, var, error }
alarmService 推送报警{ id, severity, source, message, timestamp }
auth_ok登录成功{ user, role, token }
pageEnter页面激活(首次加载或 Resume){ route, prevRoute }
pageLeave页面离开(被 Suspend 或关闭){ route, nextRoute }
themeChangedsetTheme 调用后'modern' | 'industrial'
connectionQuality连接质量变化{ rtt, quality }

Darra.off(event, callback) — 移除事件监听

const handler = () => console.log('ready')
Darra.on('ready', handler)
// ...
Darra.off('ready', handler)

Darra.getConnectionStatus() — 获取连接状态

const status = Darra.getConnectionStatus()
// 'connected' | 'connecting' | 'offline' | 'reconnecting'

六、主题 API

Darra.setTheme(name) — 切换主题

Darra.setTheme('industrial')
Darra.setTheme('brandRed') // 自定义皮肤

切换 <body class="theme-xxx"> 并存入 localStorage['darra-hmi-theme']。详见主题系统


Darra.getTheme() — 获取当前主题

const current = Darra.getTheme()
console.log(current) // 'industrial'

七、工具函数

Darra.formatNumber(value, format) — 数字格式化

Darra.formatNumber(25.333, '0.00')  // '25.33'
Darra.formatNumber(1234.5, '#,##0') // '1,235'
Darra.formatNumber(0.85, '0%') // '85%'

底层使用 Chart.js 的格式化引擎,支持所有 Chart.js 格式模式。


Darra.formatTimestamp(ms, format?) — 时间戳格式化

Darra.formatTimestamp(Date.now())                 // '2026-07-26 14:30:00'
Darra.formatTimestamp(Date.now(), 'HH:mm:ss') // '14:30:00'
Darra.formatTimestamp(Date.now(), 'MM-dd') // '07-26'
参数类型默认值说明
msnumber毫秒时间戳
formatstring'YYYY-MM-DD HH:mm:ss'输出格式

Darra.showToast(message, options?) — 显示 Toast 通知

Darra.showToast('配方加载成功', {
type: 'success', // 'success' | 'warning' | 'error' | 'info'
duration: 3000, // 自动关闭时间 (ms),0 为不自动关闭
position: 'bottom-right' // 'top' | 'bottom' | 'top-right' | 'bottom-right'
})

在页面角落显示短暂的通知消息,不打断用户操作流。适用于操作反馈而非报警。


八、完整 API 函数签名表

函数签名说明
readVariable(varName: string) => value读取缓存值
writeVariable(varName: string, value, options?) => void写入变量
writeGroup(values: Record<string, any>) => void批量写入
subscribeVariable(varName: string, cb: (value, meta) => void) => unsubscribe订阅变量
subscribeGroup(vars: string[], cb: (values) => void) => unsubscribe订阅变量组
subscribeDB(dbName: string, cb: (values) => void) => unsubscribe订阅 DB
unsubscribeAll() => void取消所有订阅
navigateTo(route: string) => void页面导航
showPopup(html: string, options?) => popupRef显示弹出窗口
closePopup(result?: any) => void关闭弹出窗口
getCurrentRoute() => string获取当前路由
getSystemInfo() => SystemInfo获取系统信息
getAlarms(filter?: AlarmFilter) => Alarm[]获取报警列表
acknowledgeAlarm(alarmId: string, reason?: string) => void确认报警
getUserInfo() => UserInfo获取当前用户
logout() => void登出
bindElement(el: HTMLElement, varName: string) => void绑定 DOM 元素
bindElementAttribute(el: HTMLElement, varName: string, attr: string) => void绑定元素属性
bindElementStyle(el: HTMLElement, varName: string, prop: string, thresholds?) => void绑定样式
unbindElement(el: HTMLElement) => void解除元素绑定
on(event: string, cb: Function) => void事件监听
off(event: string, cb: Function) => void移除监听
getConnectionStatus() => string获取连接状态
setTheme(name: string) => void切换主题
getTheme() => string获取当前主题
formatNumber(value: number, format: string) => string数字格式化
formatTimestamp(ms: number, format?: string) => string时间戳格式化
showToast(message: string, options?) => voidToast 通知

最佳实践

  • 优先使用 <darra-*> 控件:控件内置了 bind / write / 主题适配,比手写 API 更简洁
  • 页面销毁时清理订阅:在 pageLeave 事件中调用 unsubscribeAll(),防止内存泄漏
  • 写入操作加防抖:滑块拖动时 debounce(300ms) 后再调用 writeVariable,避免洪泛
  • 始终监听 offline:断开时禁用所有写入按钮,避免用户误以为写成功
  • bindElementStyle 配合 CSS transition:给绑定元素加 transition: width 0.3s 即可实现平滑动画
  • 错误友好提示on('error', ...)showToast 展示而非静默 log

排错表

现象原因排查
subscribeVariable 回调不触发变量未订阅成功F12 Network → WS → 看 subscribe 帧是否发出
写入无效白名单未通过监听 error 事件,检查 WriteWhitelist
getAlarms 返回空当前无报警或筛选条件过严去掉 filter 参数重试
页面导航后 JS 状态丢失未在 pageEnter 中恢复状态将初始化逻辑放在 pageEnter 而非页面加载时
bindElementStyle 不生效CSS 属性名拼写错误检查 CSS 属性名(backgroundColor 而非 background-color

相关文档