仪表板
DeviceChain 包含可嵌入、支持版本管理的仪表板系统,用于可视化实时设备数据。仪表板是你在控制台编写的租户作用域资源。它根据可移植 JSON 定义渲染,同一定义可以在控制台、独立参考查看器,或任何安装 npm 运行时包的 React 应用中渲染。
已提供:画布编辑器、内置组件集(遥测、告警和命令/控制组件)、实时订阅、组件动作(确认/解除告警、发送命令,由服务器授权)、版本管理(发布 / 回滚)、合成数据预览、命名插槽和绑定清单、导出、独立 /dash 参考查看器,以及发布于 npm 的运行时包。
计划中:更丰富的数据源选择器(关系图遍历、下钻)、按断点编辑布局,以及更多组件。
画布
仪表板在流式 CSS 网格中布置组件。网格提供:
- 高精度列网格:按列/行跨度放置组件,而不是固定像素;
- z 顺序和分层;
- 可选的逐组件像素偏移,用于微调或重叠;
- 可选背景图片或颜色。
列采用比例尺寸,因此仪表板填满其挂载容器的宽度,无论是面板、固定宽度框架还是整页。挂载时的尺寸选项(fill、固定宽度或固定高度)由宿主选择。
网格本身具有吸附能力。组件仍可重叠,因为它们可以共享单元格并按 z 分层,例如在平面图上放置卡片。
定义格式和渲染器为每个组件保存各断点的布局框,因此仪表板可以在不同屏幕尺寸使用不同排列。但画布编辑器只写入基础断点,所以目前在控制台编写的仪表板只有一个布局。
组件
内置组件覆盖五个通道:遥测、告警、控制、选择和位置。时序图与仪表使用 Apache ECharts 渲染,地图使用 MapLibre GL,其余使用普通 DOM。
| 组件 | 通道 | 显示内容 |
|---|---|---|
| 时序图 | telemetry | 时间窗口内的一个或多个测量序列 |
| 仪表 | telemetry | 对照范围/阈值显示单个最新值 |
| 最新值卡片 | telemetry | 单个当前读数及其时间戳 |
| 表格 | telemetry | 设备或锚点的最近记录 |
| 标签 | telemetry | 静态文本 |
| 图片 | telemetry | 静态图像,例如其他组件下方的平面图 |
| 告警表格 | alarm | 设备或锚点的实时告警 |
| 告警计数 | alarm | 未关闭告警的汇总数量 |
| 命令 / 控制 | control | 带类型的参数表单,用于派发命令并显示实时投递生命周期 |
| 实体选择器 | selection | 重新绑定命名插槽的选择器,让查看者选择仪表板或其中单个组件显示哪个实体 |
| 地图 | location | 已绑定设备的最新已知位置 |
组件使用 CSS 自定义属性设置主题,因此嵌入应用无需修改组件代码即可控制外观。
地图瓦片与位置访问
选择哪个瓦片提供方是租户级决定,而不是逐组件决定。参见底图。
地图组件在租户底图上渲染设备位置。新实例已配置底图,因此地图组件无需额外设置即可绘制瓦片。组件自身的 tileUrl 和 attribution 选项可以只为该仪表板覆盖底图,适合在租户范围启用之前试用提供方。
如果任何层级都没有瓦片来源——运维人员将实例默认值设为 {},租户也没有设置——组件仍会绘制真正的地图,使用内置的公共领域大陆与国界世界底图。只有地图渲染器本身完全无法加载或启动时,例如代理阻止加载,或浏览器没有可用 WebGL,才会退回显示相对位置的平面面板。
读取位置还需要 location:read 权限。每个成员默认获得的只读基础权限不包含它,参见设备位置。没有该权限的查看者会收到说明,而不是看到空地图。
动作与权限
组件可以携带动作:确认或解除告警,或者发送命令。服务器根据调用方自己的租户作用域权限授权每个动作。例如,需要 alarm:write 的动作对只读查看者不可用。
打开仪表板需要 dashboard:read,每个启用的租户成员都拥有该权限。它属于只读基础权限,与读取设备、事件、状态、命令和告警并列。仪表板是对这些权限已能访问的数据进行保存的排列,因此能读取数据的成员也能打开相应视图。
dashboard:write 控制创建、更新、发布、回滚和删除,仍需通过角色授予。
数据源
组件不内嵌查询,而是内嵌由运行时解析的带类型选择器:
device:通过令牌选择单台设备。anchor:限定于组织实体(客户、区域或资产)的遥测,由被跟踪关系指定。运行时在客户端将它展开为当前关联到该实体的设备,并流式读取各成员的原始样本:每台设备一个流,最多 500 个成员。服务器端将锚点事件聚合为单个序列的能力仍保留待实现。选择器的aggregation字段会保存并原样返回,但尚未读取使用。slot:命名占位符,由宿主在挂载时从绑定清单解析(见下文嵌入)。目前控制台写入这种类型:加载仪表板时,它将具体device和anchor选择器重写为插槽,因此编写的仪表板默认是可复用模板。
另外两种类型 devices 和 relatedTraversal 为存储定义的前向兼容而保留。在实现之前,运行时会拒绝它们。
选择器通过客户端 SDK 针对 GraphQL API 解析,因此解析具有以下特点:
- 实时:设备新分配到区域后,无需编辑仪表板就会出现在该区域仪表板中;
- 权限检查:使用调用方自己的、经过认证的租户作用域 API 访问。
实时值的到达方式取决于通道:
| 通道 | 值如何到达 |
|---|---|
| telemetry | GraphQL 订阅,经多路复用,使组件较多的仪表板每台设备只打开一个流,而不是每个组件一个流 |
| alarm | 由实时告警流触发重新查询,并通过 30 秒轮询补充 |
| control | 只使用轮询,因为 command-delivery 不提供订阅 |
告警和控制组件各自持有自己的流和计时器。只有遥测通道会多路复用。
订阅连接在建立连接时使用的访问令牌到期后关闭(参见 WebSocket 订阅)。独立 /dash 查看器不会刷新令牌,因此实时组件到时会停止,直到用户重新登录。
编写、版本管理与预览
你在控制台中编写仪表板:
- 画布编辑器:拖动和调整尺寸,提供真实设备/锚点选择器。
- 版本管理:当前定义是可变的草稿。发布将其捕获为不可变版本;回滚到任意旧版本会将该版本重新写为当前草稿。历史记录是已发布快照列表,不是差异列表。
- 合成数据预览:将实时数据替换为客户端生成器(正弦 / 斜坡 / 随机游走),在任何设备上报前验证布局、刻度和阈值。
- 导出:下载或复制定义,以便共享或在其他地方嵌入。
已发布版本的定义不能独立读取。版本列表只提供编号、可选标签和描述,以及谁在何时发布。只有作为写入操作的回滚,才能重新获取其内容。
嵌入:定义、插槽与绑定清单
仪表板定义可移植,也可作为模板复用。组件绑定到命名插槽,而不是硬编码读取哪台设备。挂载时,宿主提供绑定清单,将每个插槽映射到具体设备或锚点。因此,一份定义加上两份清单,就能为两台不同设备提供两个实时仪表板,无需修改定义本身。
运行时分层组织为以下包:
| 包 | 职责 |
|---|---|
@devicechain/client | TypeScript SDK:认证、GraphQL 操作、实时订阅 |
@devicechain/widgets | React 组件(输入数据源,输出像素),以及布局渲染器 |
@devicechain/dashboards | DashboardHub(管理连接、解析选择器、多路复用遥测订阅),以及定义、选择器、插槽和绑定清单类型 |
React 应用使用解析器构造一个 hub,再结合绑定清单渲染定义,即可嵌入实时仪表板。渲染器通过绑定清单解析每个插槽,因此重新指向某个插槽(例如查看者下钻到某条告警)时,只有绑定到该插槽的组件会重新订阅,仪表板其余部分保留其实时值。仓库中的控制台与独立 /dash 应用都采用此路径,构建时使用与外部使用者下载的相同产物。这些包发布在 npm,外部应用以相同方式安装。参见 npm 包,了解安装命令、版本与 dist-tag 策略,以及地图组件需要的宿主配置。
/dash 参考查看器
独立 /dash 应用是参考外部嵌入应用。它有自己的登录,接受导出的定义与绑定清单,并渲染仪表板。
它在编写方面只提供查看:没有编辑器、没有保存功能,也从不向服务获取仪表板。不过组件动作仍然可用。持有 alarm:write 或 command:write 的查看者,可以通过其渲染的仪表板确认/解除告警,并向真实设备派发命令;服务器始终执行这些权限检查。
另请参见架构概览和 GraphQL API 参考。