前言

PE版本有CSV/XLS数据导出功能,具体视频演示查看官方文档地址

对此功能的描述如下:
ThingsBoard允许您将数据从小部件导出到CSV或XLS。几乎任何小部件都支持此功能
导出数据集中的列列表与您在数据集配置中配置的参数列表相对应

CE版本实现演示

点击查看【bilibili】


注意:
调试前端代码 在ui-ngx目录下 打开命令行 执行yarn start 进行调试,更改后自动重新编译前端,不需要重复启动项目。
thingsboard版本 3.2.0

组件设置页面修改

添加「启用数据导出选项」

可通过此选项启用或关闭数据导出功能
image.png

源码实现

主要修改下列文件(添加注释部分代码。官方源码部分有省略,减少篇幅)
ui-ngx/src/app/modules/home/components/widget/
widget-config.component.html
377行

  1. <div fxLayout="column" fxLayoutAlign="center" fxLayoutGap="8px" fxFlex.sm="40%" fxFlex.gt-sm="30%">
  2. <mat-checkbox formControlName="enableFullscreen">
  3. {{ 'widget-config.enable-fullscreen' | translate }}
  4. </mat-checkbox>
  5. <!--添加数据导出按钮↓↓↓-->
  6. <mat-checkbox formControlName="enableDataExport">
  7. {{ 'widget-config.enable-data-export' | translate }}
  8. </mat-checkbox>
  9. </div>

widget-config.component.ts
208行

  1. this.widgetSettings = this.fb.group({
  2. dropShadow: [null, []],
  3. enableFullscreen: [null, []],
  4. //添加是否允许数据导出变量
  5. enableDataExport: [null, []],
  6. backgroundColor: [null, []],
  7. ...
  8. });

379行

  1. this.widgetSettings.patchValue({
  2. dropShadow: isDefined(config.dropShadow) ? config.dropShadow : true,
  3. enableFullscreen: isDefined(config.enableFullscreen) ? config.enableFullscreen : true,
  4. //是否允许数据导出 设置默认值
  5. enableDataExport: isDefined(config.enableDataExport) ? config.enableDataExport : true,
  6. backgroundColor: config.backgroundColor,
  7. ...
  8. },

ui-ngx/src/app/shared/models/widget.models.ts
369行

  1. export interface WidgetConfig {
  2. dropShadow?: boolean;
  3. enableFullscreen?: boolean;
  4. //添加是否允许数据导出变量
  5. enableDataExport?: boolean;
  6. useDashboardTimewindow?: boolean;
  7. ...
  8. }

组件右上角导出数据按钮实现

image.png

源码实现

ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.html
123行 添加俩个注释中间部分

注意:<mat-icon>{{'archive'}}</mat-icon> 中的archive代表图标样式,其他mat-icon标签同理可替换图标 可以在https://www.materialpalette.com/icons中找到喜欢的进行替换。

  1. <button mat-button mat-icon-button *ngFor="let action of widget.widgetActions"
  2. [fxShow]="!isEdit && action.show"
  3. (click)="action.onAction($event)"
  4. matTooltip="{{ action.name | translate }}"
  5. matTooltipPosition="above">
  6. <mat-icon>{{ action.icon }}</mat-icon>
  7. </button>
  8. <!--数据导出按钮实现 开始↓-->
  9. <button mat-button mat-icon-button
  10. [matMenuTriggerFor]="menu"
  11. #menuTrigger="matMenuTrigger"
  12. [fxShow]="!isEdit && widget.enableDataExport"
  13. matTooltip="{{ 'widget.data-export' | translate }}"
  14. matTooltipPosition="above">
  15. <mat-icon>{{'archive'}}</mat-icon>
  16. </button>
  17. <mat-menu #menu="matMenu">
  18. <button mat-menu-item (click)="exportData($event, widgetComponent.widgetContext,'csv');menuTrigger.toggleMenu();">
  19. <mat-icon>insert_drive_file</mat-icon>
  20. <span>{{ 'widget.data-export-csv' | translate }}</span>
  21. </button>
  22. <button mat-menu-item (click)="exportData($event, widgetComponent.widgetContext,'xls');menuTrigger.toggleMenu();">
  23. <mat-icon>insert_drive_file</mat-icon>
  24. <span>{{ 'widget.data-export-xls' | translate }}</span>
  25. </button>
  26. <button mat-menu-item (click)="exportData($event, widgetComponent.widgetContext,'xlsx');menuTrigger.toggleMenu();">
  27. <mat-icon>insert_drive_file</mat-icon>
  28. <span>{{ 'widget.data-export-xlsx' | translate }}</span>
  29. </button>
  30. </mat-menu>
  31. <!--数据导出按钮实现 结束↑-->
  32. <button mat-button mat-icon-button
  33. [fxShow]="!isEdit && widget.enableFullscreen"
  34. (click)="$event.stopPropagation(); widget.isFullscreen = !widget.isFullscreen"
  35. matTooltip="{{(widget.isFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
  36. matTooltipPosition="above">
  37. <mat-icon>{{ widget.isFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
  38. </button>

ui-ngx/src/app/modules/home/models/dashboard-component.models.ts
添加注释部分代码

  1. export class DashboardWidget implements GridsterItem, IDashboardWidget {
  2. dropShadow: boolean;
  3. enableFullscreen: boolean;
  4. //308行后 添加变量
  5. enableDataExport: boolean;
  6. hasTimewindow: boolean;
  7. }
  8. //379行后 添加默认值
  9. this.enableDataExport = isDefined(this.widget.config.enableDataExport) ? this.widget.config.enableDataExport : true;

ui-ngx/src/app/shared/models/ace/widget-completion.models.ts
217行

  1. enableDataExport: {
  2. description: 'Whether to enable data export button on widget.',
  3. meta: 'property',
  4. type: 'boolean'
  5. },

ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts
添加方法

  1. //文件开头导入依赖
  2. import { WidgetContext } from '@home/models/widget-component.models';
  3. exportData($event: Event, ctx: WidgetContext, fileType) {
  4. if ($event) {
  5. $event.stopPropagation();
  6. }
  7. const export_data = this.data_format(ctx.datasources, ctx.data);
  8. this.export(export_data, fileType, ctx.widgetConfig.title);
  9. }

console.log(fileType);可以看出点击的哪个文件类型的导出按钮
console.log(ctx.datasources);可以看出实体enityName,实体类型enityType及数据点dataKeys
image.png
console.log(ctx.data);可以看到具体数据,格式是二维数据[[时间戳,值],[时间戳,值],[时间戳,值]],还有每条数据对应的数据键
image.png
this.data_format(datasource, data);是对数据做格式转换
转化后执行console.log(export_data);结果如下
image.png
最后执行this.export(export_data, fileType, ctx.widgetConfig.title);导出数据到浏览器下载。
文件名格式小部件标题-时间戳.文件后缀

translate相关

ui-ngx/src/assets/locale/locale.constant-zh_CN.json
添加widget中的内容

  1. "widget": {
  2. "data-export": "导出数据",
  3. "data-export-csv": "数据导出为CSV格式",
  4. "data-export-xls": "数据导出为XLS格式",
  5. "data-export-xlsx": "数据导出为XLSX格式",
  6. }

添加widget-config中的内容

  1. "widget-config": {
  2. "enable-data-export": "启用数据导出",
  3. }

时间段选择

如果勾选了「使用仪表板的时间窗口」
image.png
则导出数据的时间段就是仪表板上的时间段内的数据
image.png
可以根据自己需求得时间段进行修改


如果没有勾选「使用仪表板的时间窗口」
那么组件上会有时间选择器
image.png
可以根据自己需求得时间段进行修改

优化

按照前面步骤做完,所有部件类型都加上了数据导出功能。实际上rpc,alarm,static是不需要的。
image.png
image.png
小部件有五种类型:timeseries,latest-values,rpc,alarm,static
但并不是每一种部件类型都需要数据导出功能。下面演示如何让rpc,static,alarm三类部件去掉数据导出功能。

rpc,static,alarm去掉图例中的启用数据导出选项

ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts

  1. 添加变量控制是否渲染启用数据导出选项
  2. writeValue方法给isEnableDataExport赋值 ```typescript //添加变量控制是否渲染启用数据导出选项 isEnableDataExport: boolean;

writeValue(value: WidgetConfigComponentData): void { this.modelValue = value; this.removeChangeSubscriptions(); if (this.modelValue) { if (this.widgetType !== this.modelValue.widgetType) { this.widgetType = this.modelValue.widgetType; this.buildForms(); //给isEnableDataExport赋值 this.isEnableDataExport = (!(this.widgetType === widgetType.static || this.widgetType === widgetType.rpc || this.widgetType === widgetType.alarm)); } …. } }

//384行 this.widgetSettings.patchValue中之前定义的默认值改为false //是否允许数据导出 设置默认值 enableDataExport: isDefined(config.enableDataExport) ? config.enableDataExport : false,

  1. ui-ngx/src/app/modules/home/components/widget/widget-config.component.html
  2. 1. 前面图例页面中添加的`启用数据导出`按钮上添加`*ngIf='isEnableDataExport'`
  3. ```html
  4. <!--添加数据导出按钮↓↓↓-->
  5. <mat-checkbox *ngIf='isEnableDataExport' formControlName="enableDataExport">
  6. {{ 'widget-config.enable-data-export' | translate }}
  7. </mat-checkbox>

效果

导出功能手动打开,添加后默认 启用数据导出 选项是不勾选状态。rpc,alram,static类型部件不显示启用数据导出选项
alarm类型部件左上角没有了
image.png
rpc类型部件左上角没有了吧
image.png
而且部件设置中也没有了选项启用数据导出
image.png

测试

新建俩种实体
image.png
实体Timer A Timer B 有数据点 bili ali
实体Bus A Bus B 有数据点 long lat
规则链生成测试数据,红框内的节点复制后共8份。
每一个节点:1条数据/s,四个节点8份 = 32条数据/s。
测试导出10分钟数据:10分钟
60秒32条 = 1.92w条
image.pngimage.pngimage.png
注意:测试节点生成数据无数量限制message-count = 0,但是根规则链的保存时序节点TTL设置600s(10分钟)有效期,防止测试数据无限多。
image.png
1.92w条近10分钟的数据瞬间导出,数据结构视频演示,包含不同实体的不同字段。 [![数据演示.mp4 (1.79MB)](https://gw.alipayobjects.com/mdn/prod_resou/afts/img/A
NNs6TKOR3isAAAAAAAAAAABkARQnAQ)](https://www.yuque.com/thingsboard/book/yoe8ys?_lake_card=%7B%22status%22%3A%22done%22%2C%22name%22%3A%22%E6%95%B0%E6%8D%AE%E6%BC%94%E7%A4%BA.mp4%22%2C%22size%22%3A1881041%2C%22taskId%22%3A%22Bzrdghg9ZnWb%22%2C%22taskType%22%3A%22%22%2C%22url%22%3Anull%2C%22cover%22%3Anull%2C%22videoId%22%3A%22inputs%2Fprod%2Fyuque%2F2021%2F1453676%2Fmp4%2F1619587751391-ff983a97-57b9-45a1-9c98-5ffc5c9a43e5.mp4%22%2C%22download%22%3Afalse%2C%22percent%22%3A100%2C%22__spacing%22%3A%22both%22%2C%22id%22%3A%228BmAu%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22card%22%3A%22video%22%7D#8BmAu)到这里,毫无保留的数据及功能已经全部拿到,基本可以自己实现了,就差数据格式转换和导出浏览器下载,有动手能力的自己实现一下也是不错的。
看你妹点下面.gif
不想掉头发的可以继续看下面的内容:

  1. 下面俩个方法的具体实现

const export_data = this.data_format(ctx.datasources, ctx.data);
this.export(export_data, fileType, ctx.widgetConfig.title);

  1. 导出excel的单元格样式及首行冻结等实现思路(是思路,思路,思路)

    数据格式整理及导出具体实现