百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Thingsboard二次开发系列拷贝篇-10widget(03创建简单的小部件)

yuyutoo 2024-10-12 01:28 2 浏览 0 评论

素材和版本

tb-release:3.2.2

小部件(Widget类型)

最新值小部件

Widgets Bundle视图中,单击屏幕右下角的大“+”按钮,然后单击“创建新的小部件类型”按钮。单击选择小部件类型弹出窗口最新值按钮控件编辑器将打开,预先填充默认的内容最新值小部件模板。

  • 清除“资源”部分 CSS 选项卡的内容。

  • 将以下 HTML 代码放在“资源”部分的 HTML 选项卡中:

  <div fxFlex fxLayout="column" style="height: 100%;" fxLayoutAlign="center stretch">
    <div>My first latest values widget.</div>
    <div fxFlex fxLayout="row" *ngFor="let dataKeyData of data" fxLayoutAlign="space-around center">
        <div>{{dataKeyData.dataKey.label}}:</div>
        <div>{{(dataKeyData.data[0] && dataKeyData.data[0][0]) | date : 'yyyy-MM-dd HH:mm:ss' }}</div>
        <div>{{dataKeyData.data[0] && dataKeyData.data[0][1]}}</div>
    </div>
  </div>
  • 将以下 JavaScript 代码放入“JavaScript”部分:

    self.onInit = function() {
       self.ctx.$scope.data = self.ctx.defaultSubscription.data;
    }
        
    self.onDataUpdated = function() {
        self.ctx.detectChanges();
    }
  • 单击小部件编辑器工具栏运行按钮,以便在小部件预览部分查看结果

在这个例子中,订阅的数据属性被分配给$scope并且可以在 HTML 模板中访问。在 HTML 中,使用特殊的*ngFor结构角度指令来迭代可用的数据键和数据点,然后使用相应的时间戳呈现最新值。

时间序列小部件

Widgets Bundle视图中,单击屏幕右下角的大“+”按钮,然后单击“创建新的小部件类型”按钮。单击选择小部件类型弹出窗口时间序列按钮控件编辑器将打开,预先填充默认时间序列模板控件的内容。

  • 将“资源”部分中 CSS 选项卡的内容替换为以下内容:

.my-data-table th {
    text-align: left;}
  • 将以下 HTML 代码放在“资源”部分的 HTML 选项卡中:

  <mat-tab-group style="height: 100%;">
      <mat-tab *ngFor="let datasource of datasources; let $dsIndex = index" label="{{datasource.name}}">
          <table class="my-data-table" style="width: 100%;">
              <thead>
                  <tr>
                      <th>Timestamp</th>
                      <th *ngFor="let dataKeyData of datasourceData[$dsIndex]">{{dataKeyData.dataKey.label}}</th>
                  <tr>          
              </thead>
              <tbody>
                  <tr *ngFor="let data of datasourceData[$dsIndex][0].data; let $dataIndex = index">
                      <td>{{data[0] | date : 'yyyy-MM-dd HH:mm:ss'}}</td>
                      <td *ngFor="let dataKeyData of datasourceData[$dsIndex]">{{dataKeyData.data[$dataIndex] && dataKeyData.data[$dataIndex][1]}}</td>
                  </tr>      
              </tbody>          
          </table>          
      </mat-tab>       
  </mat-tab-group>
  • 将以下 JavaScript 代码放入“JavaScript”部分:

self.onInit = function() {
    self.ctx.widgetTitle = 'My first Time-Series widget';
    self.ctx.$scope.datasources = self.ctx.defaultSubscription.datasources;
    self.ctx.$scope.data = self.ctx.defaultSubscription.data;
    
    self.ctx.$scope.datasourceData = [];
    
    var currentDatasource = null;
    var currentDatasourceIndex = -1;
    
    for (var i=0;i<self.ctx.$scope.data.length;i++) {
        var dataKeyData = self.ctx.$scope.data[i];
        if (dataKeyData.datasource != currentDatasource) {
            currentDatasource = dataKeyData.datasource
            currentDatasourceIndex++;
            self.ctx.$scope.datasourceData[currentDatasourceIndex] = [];
            
        } 
        self.ctx.$scope.datasourceData[currentDatasourceIndex].push(dataKeyData);
    }
    self.ctx.updateWidgetParams();}self.onDataUpdated = function() {
    self.ctx.detectChanges();}
  • 单击小部件编辑器工具栏运行按钮,以便在小部件预览部分查看结果

在此示例中,订阅 数据源和数据属性被分配给$scope并在 HTML 模板中变得可访问。在$ scope.datasourceData属性介绍了数据源指数为HTML模板中灵活地访问数据源的具体dataKeys数据映射。在 HTML 中,使用特殊的*ngFor结构角度指令来迭代可用数据源并呈现相应的选项卡。在每个选项卡内,使用从数据源索引访问的 datasourceData 范围属性获取的dataKeys 呈现表。每个表通过遍历所有dataKeyData 来呈现列对象并通过迭代每个dataKeyData 的数据数组来呈现所有可用的数据点以呈现时间戳和值。请注意,在这段代码,onDataUpdated功能与一个呼叫实现detectChanges功能,必要时接收到新的数据来执行新的变更检测周期。

RPC(控制)小部件

Widgets Bundle视图中,单击屏幕右下角的大“+”按钮,然后单击“创建新的小部件类型”按钮。单击“选择小部件类型”弹出窗口上的控制小部件”按钮控件编辑器将打开,预先填充的默认控件模板控件的内容。

  • 清除“资源”部分 CSS 选项卡的内容。

  • 将以下 HTML 代码放在“资源”部分的 HTML 选项卡中:

<form #rpcForm="ngForm" (submit)="sendCommand()">
      <div class="mat-content mat-padding" fxLayout="column">
        <mat-form-field class="mat-block">
          <mat-label>RPC method</mat-label>
          <input matInput required name="rpcMethod" #rpcMethodField="ngModel" [(ngModel)]="rpcMethod"/>
          <mat-error *ngIf="rpcMethodField.hasError('required')">
            RPC method name is required.          </mat-error>
        </mat-form-field>
        <mat-form-field class="mat-block">
          <mat-label>RPC params</mat-label>
          <input matInput required name="rpcParams" #rpcParamsField="ngModel" [(ngModel)]="rpcParams"/>
          <mat-error *ngIf="rpcParamsField.hasError('required')">
            RPC params is required.          </mat-error>
        </mat-form-field>
        <button [disabled]="rpcForm.invalid || !rpcForm.dirty" mat-raised-button color="primary" type="submit" >
          Send RPC command        </button>
        <div>
          <label>RPC command response</label>
          <div style="width: 100%; height: 100px; border: solid 2px gray" [innerHTML]="rpcCommandResponse">
          </div>
        </div>
      </div>
    </form>
  • 将以下 JSON 内容放在设置架构部分的“设置架构”选项卡中

{
    "schema": {
        "type": "object",
        "title": "Settings",
        "properties": {
            "oneWayElseTwoWay": {
                "title": "Is One Way Command",
                "type": "boolean",
                "default": true
            },
            "requestTimeout": {
                "title": "RPC request timeout",
                "type": "number",
                "default": 500
            }
        },
        "required": []
    },
    "form": [
        "oneWayElseTwoWay",
        "requestTimeout"
    ]}
  • 将以下 JavaScript 代码放入“JavaScript”部分:

self.onInit = function() {
    
    self.ctx.$scope.sendCommand = function() {
        var rpcMethod = self.ctx.$scope.rpcMethod;
        var rpcParams = self.ctx.$scope.rpcParams;
        var timeout = self.ctx.settings.requestTimeout;
        var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ? true : false;

        var commandObservable;
        if (oneWayElseTwoWay) {
            commandObservable = self.ctx.controlApi.sendOneWayCommand(rpcMethod, rpcParams, timeout);
        } else {
            commandObservable = self.ctx.controlApi.sendTwoWayCommand(rpcMethod, rpcParams, timeout);
        }
        commandObservable.subscribe(
            function (response) {
                if (oneWayElseTwoWay) {
                    self.ctx.$scope.rpcCommandResponse = "Command was successfully received by device.<br> No response body because of one way command mode.";
                } else {
                    self.ctx.$scope.rpcCommandResponse = "Response from device:<br>";                    
                    self.ctx.$scope.rpcCommandResponse += JSON.stringify(response, undefined, 2);
                }
                self.ctx.detectChanges();
            },
            function (rejection) {
                self.ctx.$scope.rpcCommandResponse = "Failed to send command to the device:<br>"
                self.ctx.$scope.rpcCommandResponse += "Status: " + rejection.status + "<br>";
                self.ctx.$scope.rpcCommandResponse += "Status text: '" + rejection.statusText + "'";
                self.ctx.detectChanges();
            }
            
        );
    }
    }
  • 使用小部件类型名称填充小部件标题字段,例如。“我的第一个控件小部件”。

  • 单击小部件编辑器工具栏运行按钮,以便在小部件预览部分查看结果

  • 单击预览部分上的仪表板编辑按钮以更改生成的小部件的大小。然后单击仪表板应用按钮。最终的小部件应如下图所示。

  • 单击小部件编辑器工具栏保存按钮以保存小部件类型。

要测试此小部件如何执行 RPC 命令,我们需要将其放置在仪表板中,然后将其绑定到使用 RPC 命令的设备。为此,请执行以下步骤:

以租户管理员身份登录。

导航到设备并使用某个名称创建新设备,例如。“我的 RPC 设备”。

打开设备详细信息,然后单击“复制访问令牌”按钮将设备访问令牌复制到剪贴板。

下载mqtt-js-rpc-from-server.sh和mqtt-js-rpc-from-server.js。将这些文件放在一个文件夹中。编辑mqtt-js-rpc-from-server.sh - 用剪贴板中的设备访问令牌替换$ACCESS_TOKEN。并安装 mqtt 客户端库。

运行mqtt-js-rpc-from-server.sh脚本。您应该会在控制台中看到“已连接”消息。

导航到仪表板并创建一个具有某些名称的新仪表板,例如。“我的第一个控制仪表板”。打开此仪表板。

单击仪表板“编辑”按钮。在仪表板编辑模式下,单击仪表板工具栏上的“实体别名”按钮。

  • 实体别名弹出窗口中单击“添加别名”。

  • 填写“别名”字段,例如。“我的 RPC 设备别名”。

  • 在“过滤器类型”字段中选择“实体列表”。

  • 在“类型”字段中选择“设备”。

  • 在“实体列表”字段中选择您的设备。在此示例中为“我的 RPC 设备”。

  • 实体别名中单击“添加”,然后单击“保存”

  • 单击仪表板“+”按钮,然后单击“创建新小部件”按钮。

  • 然后选择保存 RPC 小部件的小部件包选择“控制小部件”选项卡。

  • 单击您的小部件。在这个例子中,“我的第一个控件小部件”。

  • 从“添加小部件”弹出窗口中,在“目标设备”部分中选择您的设备别名在此示例中为“我的 RPC 设备别名”。

  • 单击添加您的控制小部件将出现在仪表板中。单击仪表板应用更改按钮以保存仪表板并退出编辑模式。

  • 使用 RPC 方法名称填充RPC 方法字段。例如。“测试方法”。

  • 用 RPC params填充RPC params字段。例如。“{ param1: “value1” }”。

  • 单击发送 RPC 命令按钮。您应该会在小部件中看到以下响应。

应在设备控制台中打印以下输出:

1
2  request.topic: v1/devices/me/rpc/request/0
  request.body: {"method":"TestMethod","params":"{ param1: \"value1\" }"}

为了测试“双向”RPC 命令模式,我们需要更改相应的小部件设置属性。为此,请执行以下步骤:

  • 单击仪表板“编辑”按钮。在仪表板编辑模式下,单击位于控件小部件标题中的编辑小部件按钮。

  • 在小部件详细信息中,查看选择“高级”选项卡并取消选中“单向命令”复选框。

  • 单击小部件详细信息标题上的应用更改按钮。关闭详细信息并单击仪表板应用更改按钮。

  • 像前面的步骤一样,用 RPC 方法名称和参数填充小部件字段。单击发送 RPC 命令按钮。您应该会在小部件中看到以下响应。

  • 停止mqtt-js-rpc-from-server.sh脚本。单击发送 RPC 命令按钮。您应该会在小部件中看到以下响应。

在本例中,controlApi用于发送 RPC 命令。此外,还引入了自定义小部件设置以配置 RPC 命令模式和 RPC 请求超时。来自设备的响应由commandObservable处理它具有成功和失败的回调以及相应的响应,或包含有关请求执行结果信息的拒绝对象。

闹钟小工具

在Widgets Bundle视图中,单击屏幕右下角的大“+”按钮,然后单击“创建新的小部件类型”按钮。单击“选择小部件类型”弹出窗口上的“警报小部件”按钮。该控件编辑器将被打开,预填充了默认的内容报警模板窗口小部件。

将“资源”部分中 CSS 选项卡的内容替换为以下内容:

1
2
3.my-alarm-table th {
text-align: left;}

将以下 HTML 代码放在“资源”部分的 HTML 选项卡中:

<div fxFlex fxLayout="column" style="height: 100%;">
<div>My first Alarm widget.</div>
<table class="my-alarm-table" style="width: 100%;">
<thead>
<tr>
<th *ngFor="let dataKey of alarmSource?.dataKeys">{{dataKey.label}}</th>
<tr>
</thead>
<tbody>
<tr *ngFor="let alarm of alarms">
<td *ngFor="let dataKey of alarmSource?.dataKeys"
[ngStyle]="getAlarmCellStyle(alarm, dataKey)">
{{getAlarmValue(alarm, dataKey)}} </td>
</tr>
</tbody>
</table>
</div>

将以下 JSON 内容放在设置架构部分的“设置架构”选项卡中:

{
"schema": {
"type": "object",
"title": "AlarmTableSettings",
"properties": {
"alarmSeverityColorFunction": {
"title": "Alarm severity color function: f(severity)",
"type": "string",
"default": "if(severity == 'CRITICAL') {return 'red';} else if (severity == 'MAJOR') {return 'orange';} else return 'green'; "
}
},
"required": []
},
"form": [
{
"key": "alarmSeverityColorFunction",
"type": "javascript"
}
]}

将以下 JavaScript 代码放入“JavaScript”部分:

self.onInit = function() {
var pageLink = self.ctx.pageLink();

pageLink.typeList = self.ctx.widgetConfig.alarmTypeList;
pageLink.statusList = self.ctx.widgetConfig.alarmStatusList;
pageLink.severityList = self.ctx.widgetConfig.alarmSeverityList;
pageLink.searchPropagatedAlarms = self.ctx.widgetConfig.searchPropagatedAlarms;

self.ctx.defaultSubscription.subscribeForAlarms(pageLink, null);
self.ctx.$scope.alarmSource = self.ctx.defaultSubscription.alarmSource;

var alarmSeverityColorFunctionBody = self.ctx.settings.alarmSeverityColorFunction;
if (typeof alarmSeverityColorFunctionBody === 'undefined' || !alarmSeverityColorFunctionBody.length) {
alarmSeverityColorFunctionBody = "if(severity == 'CRITICAL') {return 'red';} else if (severity == 'MAJOR') {return 'orange';} else return 'green';";
}

var alarmSeverityColorFunction = null;
try {
alarmSeverityColorFunction = new Function('severity', alarmSeverityColorFunctionBody);
} catch (e) {
alarmSeverityColorFunction = null;
}

self.ctx.$scope.getAlarmValue = function(alarm, dataKey) {
var alarmKey = dataKey.name;
if (alarmKey === 'originator') {
alarmKey = 'originatorName';
}
var value = alarm[alarmKey];
if (alarmKey === 'createdTime') {
return self.ctx.date.transform(value, 'yyyy-MM-dd HH:mm:ss');
} else {
return value;
}
}

self.ctx.$scope.getAlarmCellStyle = function(alarm, dataKey) {
var alarmKey = dataKey.name;
if (alarmKey === 'severity' && alarmSeverityColorFunction) {
var severity = alarm[alarmKey];
var color = alarmSeverityColorFunction(severity);
return {
color: color
};
}
return {};
}}self.onDataUpdated = function() {
self.ctx.$scope.alarms = self.ctx.defaultSubscription.alarms.data;
self.ctx.detectChanges();}

单击小部件编辑器工具栏上的运行按钮,以便在小部件预览部分查看结果。

在这个例子中,订阅的alarmSource和alarms属性被分配给$scope并且可以在 HTML 模板中访问。在 HTML 中,使用了一个特殊的*ngFor结构角度指令,以便迭代alarmSource的可用警报dataKeys并呈现相应的列。表格行通过迭代警报数组呈现,相应的单元格通过迭代dataKeys呈现。该功能getAlarmValue被取报警值和格式化createdTime使用报警属性DatePipe可通过ctx 的date属性访问角管。函数getAlarmCellStyle用于为每个警报单元格分配自定义单元格样式。在此示例中,我们引入了名为alarmSeverityColorFunction 的新设置属性,其中包含根据警报严重性返回颜色的函数体。在getAlarmCellStyle函数中,有相应的调用带有严重性值的alarmSeverityColorFunction以获取警报严重性单元格的颜色。请注意,在此代码中实现了onDataUpdated函数,以便使用来自订阅的最新警报更新警报属性并使用调用更改检测检测更改()函数。


相关推荐

jQuery VS AngularJS 你更钟爱哪个?

在这一次的Web开发教程中,我会尽力解答有关于jQuery和AngularJS的两个非常常见的问题,即jQuery和AngularJS之间的区别是什么?也就是说jQueryVSAngularJS?...

Jquery实时校验,指定长度的「负小数」,小数位未满末尾补0

在可以输入【负小数】的输入框获取到焦点时,移除千位分隔符,在输入数据时,实时校验输入内容是否正确,失去焦点后,添加千位分隔符格式化数字。同时小数位未满时末尾补0。HTML代码...

如何在pbootCMS前台调用自定义表单?pbootCMS自定义调用代码示例

要在pbootCMS前台调用自定义表单,您需要在后台创建表单并为其添加字段,然后在前台模板文件中添加相关代码,如提交按钮和表单验证代码。您还可以自定义表单数据的存储位置、添加文件上传字段、日期选择器、...

编程技巧:Jquery实时验证,指定长度的「负小数」

为了保障【负小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【负小数】的方法。HTML代码<inputtype="text"class="forc...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

编程技巧:Jquery实时验证,指定长度的「正小数」

为了保障【正小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【正小数】的方法。HTML做成方法<inputtype="text"class="fo...

jquery.validate检查数组全部验证

问题:html中有多个name[],每个参数都要进行验证是否为空,这个时候直接用required:true话,不能全部验证,只要这个数组中有一个有值就可以通过的。解决方法使用addmethod...

Vue进阶(幺叁肆):npm查看包版本信息

第一种方式npmviewjqueryversions这种方式可以查看npm服务器上所有的...

layui中使用lay-verify进行条件校验

一、layui的校验很简单,主要有以下步骤:1.在form表单内加上class="layui-form"2.在提交按钮上加上lay-submit3.在想要校验的标签,加上lay-...

jQuery是什么?如何使用? jquery是什么功能组件

jQuery于2006年1月由JohnResig在BarCampNYC首次发布。它目前由TimmyWilson领导,并由一组开发人员维护。jQuery是一个JavaScript库,它简化了客户...

django框架的表单form的理解和用法-9

表单呈现...

jquery对上传文件的检测判断 jquery实现文件上传

总体思路:在前端使用jquery对上传文件做部分初步的判断,验证通过的文件利用ajaxFileUpload上传到服务器端,并将文件的存储路径保存到数据库。<asp:FileUploadI...

Nodejs之MEAN栈开发(四)-- form验证及图片上传

这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/R...

大数据开发基础之JAVA jquery 大数据java实战

上一篇我们讲解了JAVAscript的基础知识、特点及基本语法以及组成及基本用途,本期就给大家带来了JAVAweb的第二个知识点jquery,大数据开发基础之JAVAjquery,这是本篇文章的主要...

推荐四个开源的jQuery可视化表单设计器

jquery开源在线表单拖拉设计器formBuilder(推荐)jQueryformBuilder是一个开源的WEB在线html表单设计器,开发人员可以通过拖拉实现一个可视化的表单。支持表单常用控件...

取消回复欢迎 发表评论: