物联网平台设备规则配置按钮开发实录

在物联网平台中,设备规则的可视化配置是一个核心功能。本文记录了为设备规则页面新增”配置”按钮的完整实现过程,通过 iframe 嵌入外部规则引擎,实现拖拽式流程编排。

背景与需求

在物联网平台中,设备规则的数据处理流程通常需要在独立的规则引擎管理页面进行配置。为了提升用户体验,产品同学提出在设备规则列表的操作列中直接添加”配置”按钮,点击即可打开可视化流程编排界面。

核心需求

  • 在设备规则列表操作列新增”配置”按钮
  • 点击按钮通过 iframe 弹窗打开外部规则引擎(Node-RED 风格)
  • 通过规则 ID 定位流程,用户 token 进行身份鉴权
  • 确保弹窗关闭时正确释放 iframe 资源

技术选型

  • 前端框架:Vue 3
  • UI 组件库:Avue(用于表格操作列)
  • 嵌入方式:iframe
  • 认证方式:Token 鉴权

架构设计

整体交互流程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
用户点击"配置"按钮
|
v
handleFlowConfig(row)
|
+--> 拼接 URL: {edgeUrl}/#flow/{row.id}?token={getToken()}
|
v
dialogFlowVisible = true
|
v
el-dialog 渲染 iframe (src = ruleEngineSrc)
|
v
外部规则引擎服务加载并渲染流程编辑器
|
v
用户关闭弹窗 --> handleDialogClosed() --> ruleEngineSrc = ''
--> destroy-on-close 销毁 DOM

关键设计点

  • 复用已有 website.links.edgeUrl 配置,无需新增配置项
  • 使用 destroy-on-close 确保关闭时销毁 DOM
  • 通过 @closed 事件清理 iframe src,防止内存泄漏

架构流程图
图1:iframe 嵌入弹窗交互流程


核心实现

1. 自定义操作列插槽

使用 Avue 的 #menu 插槽替换默认操作按钮,新增四个功能按钮:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template #menu="{ row, index }">
<el-button text type="primary" icon="el-icon-view"
v-if="permission.engine_device_view"
@click="$refs.crud.rowView(row, index)">查看</el-button>
<el-button text type="primary" icon="el-icon-setting"
v-if="permission.engine_device_edit"
@click="handleFlowConfig(row)">配置</el-button>
<el-button text type="primary" icon="el-icon-edit"
v-if="permission.engine_device_edit"
@click="$refs.crud.rowEdit(row, index)">编辑</el-button>
<el-button text type="primary" icon="el-icon-delete"
v-if="permission.engine_device_delete"
@click="$refs.crud.rowDel(row, index)">删除</el-button>
</template>

权限策略:配置按钮复用 engine_device_edit 权限,与编辑按钮保持一致的权限级别。

权限控制按钮组
图2:四个操作按钮(查看、配置、编辑、删除)

2. iframe 弹窗组件

1
2
3
4
5
6
7
<el-dialog v-model="dialogFlowVisible" title="物联感知模型设计" width="90%" top="3vh"
:close-on-click-modal="false"
class="flow-dialog"
:destroy-on-close="true"
@closed="handleDialogClosed">
<iframe :src="ruleEngineSrc" class="flow-engine-iframe" />
</el-dialog>

关键参数说明

参数 作用
destroy-on-close true 关闭时销毁 DOM,释放 iframe 内存
close-on-click-modal false 防止误触遮罩导致编辑内容丢失
width 90% 弹窗宽度占屏幕 90%
height 85vh 确保充足的编辑空间

3. 核心方法实现

1
2
3
4
5
6
7
handleFlowConfig(row) {
this.ruleEngineSrc = `${website.links.edgeUrl}/#flow/${row.id}?token=${getToken()}`;
this.dialogFlowVisible = true;
},
handleDialogClosed() {
this.ruleEngineSrc = '';
},

URL 格式{edgeUrl}/#flow/{规则ID}?token={用户token}

组成部分 来源 说明
website.links.edgeUrl src/config/website.js 规则引擎服务地址,默认 http://localhost:1880
/#flow/ 路由路径 Node-RED 风格的流程编辑页面路由
{row.id} 当前行数据 设备规则的唯一标识
getToken() src/utils/auth.js 从本地存储获取当前用户 token

4. Avue 配置调整

使用 #menu 自定义插槽后,需要禁用 Avue 默认按钮:

1
2
3
viewBtn: false,
editBtn: false,
delBtn: false,

同时将 menuWidth 设置为 300,以容纳新增的”配置”按钮。


风险与应对

跨域限制风险

[!danger] iframe 嵌入受限
如果外部规则引擎服务设置了 X-Frame-Options: DENY/SAMEORIGINContent-Security-Policy: frame-ancestors 'none',iframe 将无法加载。

降级方案:将 iframe 嵌入改为 window.open 新窗口打开:

1
2
3
4
handleFlowConfig(row) {
const url = `${website.links.edgeUrl}/#flow/${row.id}?token=${getToken()}`;
window.open(url, '_blank');
}

内存泄漏风险

长时间打开多个 iframe 弹窗可能导致浏览器内存增长。已通过以下措施缓解:

  • destroy-on-close: true 关闭时销毁 DOM
  • @closed 事件清理 ruleEngineSrc,停止 iframe 后台请求

权限一致性

使用 #menu 插槽后,Avue 内置的 permissionList 不再自动控制按钮显隐。操作列按钮的显隐完全由模板中的 v-if="permission.xxx" 控制。


经验总结

  • 最小侵入原则:只修改 src/views/iot/engine/device.vue 一个文件,通过插槽和配置扩展现有功能
  • 复用优先:复用了 website.links.edgeUrlgetToken(),无需新增配置
  • 防御式编程:考虑跨域限制,提供降级方案
  • 资源管理:iframe 必须及时清理,防止内存泄漏
  • 权限一致性:使用自定义插槽时,需注意 Avue 内置权限机制不再生效

修改汇总

1
2
3
4
src/views/iot/engine/device.vue  +35 行
- 模板:新增 #menu 插槽和 iframe 弹窗
- 脚本:新增 data 字段和两个方法
- 样式:iframe 尺寸样式

涉及文件

文件 改动 说明
src/views/iot/engine/device.vue 修改 唯一修改文件
src/config/website.js 无修改 复用已有配置
src/utils/auth.js 无修改 复用已有方法