跳转至

小部件操作

介绍

操作功能可以视为仪表板状态之间或不同仪表板之间的导航。操作允许快速轻松地配置到创建状态的转换、转移到其他仪表板,甚至更新您所在的仪表板。根据小部件的不同,操作源也有所不同。但是,您可以选择的操作类型对于所有小部件都是相同的。

在所需小部件的编辑模式中调整操作。

动作类型

操作类型定义了将采取的具体操作。对于所有小部件来说,有六种相同的操作类型。通过实体卡小组件示例中的示例了解如何配置操作类型。

动作类型配置

由于所有小部件的操作类型都相同,因此在本教程中将使用操作单元格按钮操作源来解释所有操作类型,并将使用实体卡小部件示例来解释它们。

导航到新的仪表板状态

状态是所谓的级别,允许您在不同的设备、资产和小部件对象之间导航,以更详细地查看您需要的信息。选择 “导航到新的仪表板状态” 操作类型时,您将转移到您选择的先前创建的状态。如何向仪表板添加状态。

添加状态后,我们可以配置“ 导航到新的仪表板状态” 操作类型:

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 作为本手册的示例,在顶部下拉菜单中,选择“小部件标题按钮”操作源。
  4. 在下一行中输入操作的名称并选择代表按钮的图标。使用此按钮,将执行操作。
  5. 在下拉菜单“类型”中,选择导航到新的仪表板状态操作类型。
  6. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  7. 选择所需状态后,单击“添加操作”窗口底部的“添加”按钮。
  8. 现在您可以看到配置的操作,因此您可以仔细检查操作源、图标和操作类型。
  9. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  10. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

保存更改后,您可以在小部件的右上方看到一个图标按钮。单击此图标将带您进入之前选择的状态。

更新当前仪表板状态

此操作类型允许更新您当前所在的仪表板。使用仪表板时,您可以实时查看有关特定设备/资产的详细信息。此操作类型最常见的用途是通过图表小部件,您可以在其中更准确地查看详细信息。首先,我们将图表小部件添加到仪表板以配置更新当前仪表板状态操作类型:

  1. 进入仪表板的编辑模式,然后在下拉“选择小部件”菜单中选择图表:时间序列折线图。
  2. 在“添加小部件”窗口中输入您的数据源,在本手册中例如使用压力数据。单击小部件右下角的“添加”。
  3. 我们可以看到图表小部件已经出现在仪表板上,但还没有数据可显示。
  4. 单击小部件右上角的铅笔图标进入表格小部件的编辑模式。
  5. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  6. 单击窗口右侧的“+”图标添加新操作。
  7. 作为本手册的示例,在顶部下拉菜单中,选择“操作单元按钮”操作源。
  8. 在下一行中输入操作的名称并选择代表按钮的图标。使用此按钮,将执行操作。
  9. 在下拉菜单“类型”中,选择更新当前仪表板状态操作类型。
  10. 选择操作类型后,单击“添加操作”窗口右下角的“添加”。
  11. 现在您可以看到配置的操作,因此您可以仔细检查操作源、图标和操作类型。
  12. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  13. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

保存更改后,您将看到实体名称对面的按钮图标。单击任何这些图标都将更新实体详细信息,它们将显示在当前仪表板上的图表小部件上。

导航到其他仪表板

此类操作会将您转移到您选择的先前创建的仪表板。要快速转换到另一个选定的仪表板,您应该:

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 作为本手册的示例,在顶部下拉菜单中,选择“操作单元按钮”操作源。
  4. 在下一行中输入操作的名称并选择代表按钮的图标。使用此按钮,将执行操作。
  5. 在下拉菜单“类型”中,选择导航到其他仪表板操作类型。
  6. 选择操作类型后,将出现下拉菜单“目标仪表板”。选择您想要转换到的之前创建的仪表板。请注意,也可以转换到所选仪表板中的现有状态。
  7. 配置好动作类型后,点击“添加动作”窗口右下角的“添加”。
  8. 现在您可以看到配置的操作,因此您可以仔细检查操作源、图标和操作类型。
  9. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  10. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

保存更改后,您可以看到实体名称对面的图标按钮。单击这些图标中的任何一个都会将您转移到之前选择的仪表板(或该仪表板中的选定状态)。

自定义动作

自定义操作允许手动配置可用于向小部件添加单个操作的功能(例如删除列出的设备/资产)。要使用函数配置自定义操作(以设备删除为例):

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 作为本手册的示例,在顶部下拉菜单中,选择“操作单元按钮”操作源。
  4. 在下一行中输入操作的名称并选择代表按钮的图标。使用此按钮,将执行操作。
  5. 在下拉菜单“类型”中,选择自定义操作操作类型。
  6. 选择自定义操作类型后,将出现用于输入函数的字段。
  7. 在那里输入您的自定义函数。本教程中的一个示例是设备删除操作,它添加了直接从表中删除设备的功能(您可以在屏幕截图部分下找到该功能的示例)。
  8. 单击“添加操作”窗口右下角的“保存”按钮应用更改。
  9. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  10. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

通过单击实体名称对面的“垃圾箱”图标来执行操作。

设备删除功能的示例。
let $injector = widgetContext.$scope.$injector;
let dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));
let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));

openDeleteDeviceDialog();

function openDeleteDeviceDialog() {
    let title = "Are you sure you want to delete the device " + entityName + "?";
    let content = "Be careful, after the confirmation, the device and all related data will become unrecoverable!";
    dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(
        function(result) {
            if (result) {
                deleteDevice();
            }
        }
    );
}

function deleteDevice() {
    deviceService.deleteDevice(entityId.id).subscribe(
        function() {
            widgetContext.updateAliases();
        }
    );
}
自定义操作(使用 HTML 模板)

使用 HTML 模板的自定义操作允许在现有 HTML 模板中手动输入功能(例如创建对话框窗口,并提供创建或编辑列出的设备/资产的机会)。

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 作为本手册的示例,在顶部下拉菜单中,选择“操作单元按钮”操作源。
  4. 在下一行中输入操作的名称并选择代表按钮的图标。使用此按钮,将执行操作。
  5. 在下拉菜单“类型”中,选择 自定义操作(使用 HTML 模板) 操作类型。选择自定义操作类型后,会出现四个选项卡: Resources选项卡用于指定widget使用的外部JavaScript/CSS资源; CSS选项卡包含自定义操作特定的 CSS 样式定义; HTML选项卡包含自定义操作 HTML 代码; JavaScript部分包含您的自定义操作的 JS 代码。
  6. 在 JavaScript 选项卡中,输入自定义操作的 JavaScript 函数(您可以在屏幕截图部分下找到 JavaScript 函数的示例)。
  7. 在 HTML 选项卡中,输入自定义操作的 HTML 代码(您可以在屏幕截图部分下找到 HTML 代码的示例)。
  8. 单击“添加操作”窗口右下角的“保存”按钮应用更改。
  9. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  10. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

通过单击适当的图标来执行操作。

添加了创建设备或资产的可能性的 JavaScript 函数和 HTML 代码示例:

JavaScript 函数。
let $injector = widgetContext.$scope.$injector;
let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
let assetService = $injector.get(widgetContext.servicesMap.get('assetService'));
let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
let entityRelationService = $injector.get(widgetContext.servicesMap.get('entityRelationService'));

openAddEntityDialog();

function openAddEntityDialog() {
customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe();
}

function AddEntityDialogController(instance) {
let vm = instance;

    vm.allowedEntityTypes = ['ASSET', 'DEVICE'];
    vm.entitySearchDirection = {
        from: "FROM",
        to: "TO"
    }

    vm.addEntityFormGroup = vm.fb.group({
     entityName: ['', [vm.validators.required]],
     entityType: ['DEVICE'],
     entityLabel: [null],
     type: ['', [vm.validators.required]],
     attributes: vm.fb.group({
         latitude: [null],
         longitude: [null],
         address: [null],
         owner: [null],
         number: [null, [vm.validators.pattern(/^-?[0-9]+$/)]],
         booleanValue: [null]
     }),
     relations: vm.fb.array([])
    });

    vm.cancel = function() {
        vm.dialogRef.close(null);
    };

    vm.relations = function() {
        return vm.addEntityFormGroup.get('relations');
    };

    vm.addRelation = function() {
        vm.relations().push(vm.fb.group({
         relatedEntity: [null, [vm.validators.required]],
         relationType: [null, [vm.validators.required]],
         direction: [null, [vm.validators.required]]
        }));
    };

    vm.removeRelation = function(index) {
        vm.relations().removeAt(index);
        vm.relations().markAsDirty();
    };

    vm.save = function() {
        vm.addEntityFormGroup.markAsPristine();
        saveEntityObservable().subscribe(
            function (entity) {
                widgetContext.rxjs.forkJoin([
                    saveAttributes(entity.id),
                    saveRelations(entity.id)
                ]).subscribe(
                    function () {
                        widgetContext.updateAliases();
                        vm.dialogRef.close(null);
                    }
                );
            }
        );
    };

    function saveEntityObservable() {
        const formValues = vm.addEntityFormGroup.value;
        let entity = {
            name: formValues.entityName,
            type: formValues.type,
            label: formValues.entityLabel
        };
        if (formValues.entityType == 'ASSET') {
            return assetService.saveAsset(entity);
        } else if (formValues.entityType == 'DEVICE') {
            return deviceService.saveDevice(entity);
        }
    }

    function saveAttributes(entityId) {
        let attributes = vm.addEntityFormGroup.get('attributes').value;
        let attributesArray = [];
        for (let key in attributes) {
            if(attributes[key] !== null) {
                attributesArray.push({key: key, value: attributes[key]});
            }
        }
        if (attributesArray.length > 0) {
            return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray);
        }
        return widgetContext.rxjs.of([]);
    }

    function saveRelations(entityId) {
        let relations = vm.addEntityFormGroup.get('relations').value;
        let tasks = [];
        for(let i=0; i < relations.length; i++) {
            let relation = {
                type: relations[i].relationType,
                typeGroup: 'COMMON'
            };
            if (relations[i].direction == 'FROM') {
                relation.to = relations[i].relatedEntity;
                relation.from = entityId;
            } else {
                relation.to = entityId;
                relation.from = relations[i].relatedEntity;
            }
            tasks.push(entityRelationService.saveRelation(relation));
        }
        if (tasks.length > 0) {
            return widgetContext.rxjs.forkJoin(tasks);
        }
        return widgetContext.rxjs.of([]);
    }
}
HTML 代码。
<form #addEntityForm="ngForm" [formGroup]="addEntityFormGroup"
      (ngSubmit)="save()" class="add-entity-form">
    <mat-toolbar fxLayout="row" color="primary">
        <h2>Add entity</h2>
        <span fxFlex></span>
        <button mat-icon-button (click)="cancel()" type="button">
            <mat-icon class="material-icons">close</mat-icon>
        </button>
    </mat-toolbar>
    <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
    </mat-progress-bar>
    <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
    <div mat-dialog-content fxLayout="column">
        <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
            <mat-form-field fxFlex class="mat-block">
                <mat-label>Entity Name</mat-label>
                <input matInput formControlName="entityName" required>
                <mat-error *ngIf="addEntityFormGroup.get('entityName').hasError('required')">
                    Entity name is required.
                </mat-error>
            </mat-form-field>
            <mat-form-field fxFlex class="mat-block">
                <mat-label>Entity Label</mat-label>
                <input matInput formControlName="entityLabel" >
            </mat-form-field>
        </div>
        <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
            <tb-entity-type-select
                    class="mat-block"
                    formControlName="entityType"
                    [showLabel]="true"
                    [allowedEntityTypes]="allowedEntityTypes"
            ></tb-entity-type-select>
            <tb-entity-subtype-autocomplete
                    fxFlex *ngIf="addEntityFormGroup.get('entityType').value == 'ASSET'"
                    class="mat-block"
                    formControlName="type"
                    [required]="true"
                    [entityType]="'ASSET'"
            ></tb-entity-subtype-autocomplete>
            <tb-entity-subtype-autocomplete
                    fxFlex *ngIf="addEntityFormGroup.get('entityType').value != 'ASSET'"
                    class="mat-block"
                    formControlName="type"
                    [required]="true"
                    [entityType]="'DEVICE'"
            ></tb-entity-subtype-autocomplete>
        </div>
        <div formGroupName="attributes" fxLayout="column">
            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Latitude</mat-label>
                    <input type="number" step="any" matInput formControlName="latitude">
                </mat-form-field>
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Longitude</mat-label>
                    <input type="number" step="any" matInput formControlName="longitude">
                </mat-form-field>
            </div>
            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Address</mat-label>
                    <input matInput formControlName="address">
                </mat-form-field>
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Owner</mat-label>
                    <input matInput formControlName="owner">
                </mat-form-field>
            </div>
            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Integer Value</mat-label>
                    <input type="number" step="1" matInput formControlName="number">
                    <mat-error *ngIf="addEntityFormGroup.get('attributes.number').hasError('pattern')">
                        Invalid integer value.
                    </mat-error>
                </mat-form-field>
                <div class="boolean-value-input" fxLayout="column" fxLayoutAlign="center start" fxFlex>
                    <label class="checkbox-label">Boolean Value</label>
                    <mat-checkbox formControlName="booleanValue" style="margin-bottom: 40px;">

                    </mat-checkbox>
                </div>
            </div>
        </div>
        <div class="relations-list">
            <div class="mat-body-1" style="padding-bottom: 10px; color: rgba(0,0,0,0.57);">Relations</div>
            <div class="body" [fxShow]="relations().length">
                <div class="row" fxLayout="row" fxLayoutAlign="start center" formArrayName="relations" *ngFor="let relation of relations().controls; let i = index;">
                    <div [formGroupName]="i" class="mat-elevation-z2" fxFlex fxLayout="row" style="padding: 5px 0 5px 5px;">
                        <div fxFlex fxLayout="column">
                            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                                <mat-form-field class="mat-block" style="min-width: 100px;">
                                    <mat-label>Direction</mat-label>
                                    <mat-select formControlName="direction" name="direction">
                                        <mat-option *ngFor="let direction of entitySearchDirection | keyvalue" [value]="direction.value">

                                        </mat-option>
                                    </mat-select>
                                    <mat-error *ngIf="relation.get('direction').hasError('required')">
                                        Relation direction is required.
                                    </mat-error>
                                </mat-form-field>
                                <tb-relation-type-autocomplete
                                        fxFlex class="mat-block"
                                        formControlName="relationType"
                                        [required]="true">
                                </tb-relation-type-autocomplete>
                            </div>
                            <div fxLayout="row" fxLayout.xs="column">
                                <tb-entity-select
                                        fxFlex class="mat-block"
                                        [required]="true"
                                        formControlName="relatedEntity">
                                </tb-entity-select>
                            </div>
                        </div>
                        <div fxLayout="column" fxLayoutAlign="center center">
                            <button mat-icon-button color="primary"
                                    aria-label="Remove"
                                    type="button"
                                    (click)="removeRelation(i)"
                                    matTooltip="Remove relation"
                                    matTooltipPosition="above">
                                <mat-icon>close</mat-icon>
                            </button>
                        </div>
                    </div>
                </div>
            </div>
            <div>
                <button mat-raised-button color="primary"
                        type="button"
                        (click)="addRelation()"
                        matTooltip="Add Relation"
                        matTooltipPosition="above">
                    Add
                </button>
            </div>
        </div>
    </div>
    <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
        <button mat-button color="primary"
                type="button"
                [disabled]="(isLoading$ | async)"
                (click)="cancel()" cdkFocusInitial>
            Cancel
        </button>
        <button mat-button mat-raised-button color="primary"
                type="submit"
                [disabled]="(isLoading$ | async) || addEntityForm.invalid || !addEntityForm.dirty">
            Create
        </button>
    </div>
</form>

添加编辑设备或资产的可能性的 JavaScript 函数和 HTML 代码示例:

JavaScript 函数。
let $injector = widgetContext.$scope.$injector;
let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
let entityService = $injector.get(widgetContext.servicesMap.get('entityService'));
let assetService = $injector.get(widgetContext.servicesMap.get('assetService'));
let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
let entityRelationService = $injector.get(widgetContext.servicesMap.get('entityRelationService'));

openEditEntityDialog();

function openEditEntityDialog() {
customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();
}

function EditEntityDialogController(instance) {
let vm = instance;

    vm.entityName = entityName;
    vm.entityType = entityId.entityType;
    vm.entitySearchDirection = {
        from: "FROM",
        to: "TO"
    };
    vm.attributes = {};
    vm.oldRelationsData = [];
    vm.relationsToDelete = [];
    vm.entity = {};

    vm.editEntityFormGroup = vm.fb.group({
        entityName: ['', [vm.validators.required]],
        entityType: [null],
        entityLabel: [null],
        type: ['', [vm.validators.required]],
        attributes: vm.fb.group({
            latitude: [null],
            longitude: [null],
            address: [null],
            owner: [null],
            number: [null, [vm.validators.pattern(/^-?[0-9]+$/)]],
            booleanValue: [false]
        }),
        oldRelations: vm.fb.array([]),
        relations: vm.fb.array([])
    });

    getEntityInfo();

    vm.cancel = function() {
        vm.dialogRef.close(null);
    };

    vm.relations = function() {
        return vm.editEntityFormGroup.get('relations');
    };

    vm.oldRelations = function() {
        return vm.editEntityFormGroup.get('oldRelations');
    };

    vm.addRelation = function() {
        vm.relations().push(vm.fb.group({
            relatedEntity: [null, [vm.validators.required]],
            relationType: [null, [vm.validators.required]],
            direction: [null, [vm.validators.required]]
        }));
    };

    function addOldRelation() {
        vm.oldRelations().push(vm.fb.group({
            relatedEntity: [{value: null, disabled: true}, [vm.validators.required]],
            relationType: [{value: null, disabled: true}, [vm.validators.required]],
            direction: [{value: null, disabled: true}, [vm.validators.required]]
        }));
    }

    vm.removeRelation = function(index) {
        vm.relations().removeAt(index);
        vm.relations().markAsDirty();
    };

    vm.removeOldRelation = function(index) {
        vm.oldRelations().removeAt(index);
        vm.relationsToDelete.push(vm.oldRelationsData[index]);
        vm.oldRelations().markAsDirty();
    };

    vm.save = function() {
        vm.editEntityFormGroup.markAsPristine();
        widgetContext.rxjs.forkJoin([
            saveAttributes(entityId),
            saveRelations(entityId),
            saveEntity()
        ]).subscribe(
            function () {
                widgetContext.updateAliases();
                vm.dialogRef.close(null);
            }
        );
    };

    function getEntityAttributes(attributes) {
        for (var i = 0; i < attributes.length; i++) {
            vm.attributes[attributes[i].key] = attributes[i].value;
        }
    }

    function getEntityRelations(relations) {
        let relationsFrom = relations[0];
        let relationsTo = relations[1];
        for (let i=0; i < relationsFrom.length; i++) {
            let relation = {
                direction: 'FROM',
                relationType: relationsFrom[i].type,
                relatedEntity: relationsFrom[i].to
            };
            vm.oldRelationsData.push(relation);
            addOldRelation();
        }
        for (let i=0; i < relationsTo.length; i++) {
            let relation = {
                direction: 'TO',
                relationType: relationsTo[i].type,
                relatedEntity: relationsTo[i].from
            };
            vm.oldRelationsData.push(relation);
            addOldRelation();
        }
    }

    function getEntityInfo() {
        widgetContext.rxjs.forkJoin([
            entityRelationService.findInfoByFrom(entityId),
            entityRelationService.findInfoByTo(entityId),
            attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE'),
            entityService.getEntity(entityId.entityType, entityId.id)
        ]).subscribe(
            function (data) {
                getEntityRelations(data.slice(0,2));
                getEntityAttributes(data[2]);
                vm.entity = data[3];
                vm.editEntityFormGroup.patchValue({
                    entityName: vm.entity.name,
                    entityType: vm.entityType,
                    entityLabel: vm.entity.label,
                    type: vm.entity.type,
                    attributes: vm.attributes,
                    oldRelations: vm.oldRelationsData
                }, {emitEvent: false});
            }
        );
    }

    function saveEntity() {
        const formValues = vm.editEntityFormGroup.value;
        if (vm.entity.label !== formValues.entityLabel){
            vm.entity.label = formValues.entityLabel;
            if (formValues.entityType == 'ASSET') {
                return assetService.saveAsset(vm.entity);
            } else if (formValues.entityType == 'DEVICE') {
                return deviceService.saveDevice(vm.entity);
            }
        }
        return widgetContext.rxjs.of([]);
    }

    function saveAttributes(entityId) {
        let attributes = vm.editEntityFormGroup.get('attributes').value;
        let attributesArray = [];
        for (let key in attributes) {
            if (attributes[key] !== vm.attributes[key]) {
                attributesArray.push({key: key, value: attributes[key]});
            }
        }
        if (attributesArray.length > 0) {
            return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray);
        }
        return widgetContext.rxjs.of([]);
    }

    function saveRelations(entityId) {
        let relations = vm.editEntityFormGroup.get('relations').value;
        let tasks = [];
        for(let i=0; i < relations.length; i++) {
            let relation = {
                type: relations[i].relationType,
                typeGroup: 'COMMON'
            };
            if (relations[i].direction == 'FROM') {
                relation.to = relations[i].relatedEntity;
                relation.from = entityId;
            } else {
                relation.to = entityId;
                relation.from = relations[i].relatedEntity;
            }
            tasks.push(entityRelationService.saveRelation(relation));
        }
        for (let i=0; i < vm.relationsToDelete.length; i++) {
            let relation = {
                type: vm.relationsToDelete[i].relationType
            };
            if (vm.relationsToDelete[i].direction == 'FROM') {
                relation.to = vm.relationsToDelete[i].relatedEntity;
                relation.from = entityId;
            } else {
                relation.to = entityId;
                relation.from = vm.relationsToDelete[i].relatedEntity;
            }
            tasks.push(entityRelationService.deleteRelation(relation.from, relation.type, relation.to));
        }
        if (tasks.length > 0) {
            return widgetContext.rxjs.forkJoin(tasks);
        }
        return widgetContext.rxjs.of([]);
    }
}
HTML 代码。
<form #editEntityForm="ngForm" [formGroup]="editEntityFormGroup"
      (ngSubmit)="save()"  class="edit-entity-form">
    <mat-toolbar fxLayout="row" color="primary">
        <h2>Edit  </h2>
        <span fxFlex></span>
        <button mat-icon-button (click)="cancel()" type="button">
            <mat-icon class="material-icons">close</mat-icon>
        </button>
    </mat-toolbar>
    <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
    </mat-progress-bar>
    <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
    <div mat-dialog-content fxLayout="column">
        <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
            <mat-form-field fxFlex class="mat-block">
                <mat-label>Entity Name</mat-label>
                <input matInput formControlName="entityName" required readonly="">
            </mat-form-field>
            <mat-form-field fxFlex class="mat-block">
                <mat-label>Entity Label</mat-label>
                <input matInput formControlName="entityLabel">
            </mat-form-field>
        </div>
        <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
            <mat-form-field fxFlex class="mat-block">
                <mat-label>Entity Type</mat-label>
                <input matInput formControlName="entityType" readonly>
            </mat-form-field>
            <mat-form-field fxFlex class="mat-block">
                <mat-label>Type</mat-label>
                <input matInput formControlName="type" readonly>
            </mat-form-field>
        </div>
        <div formGroupName="attributes" fxLayout="column">
            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Latitude</mat-label>
                    <input type="number" step="any" matInput formControlName="latitude">
                </mat-form-field>
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Longitude</mat-label>
                    <input type="number" step="any" matInput formControlName="longitude">
                </mat-form-field>
            </div>
            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Address</mat-label>
                    <input matInput formControlName="address">
                </mat-form-field>
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Owner</mat-label>
                    <input matInput formControlName="owner">
                </mat-form-field>
            </div>
            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                <mat-form-field fxFlex class="mat-block">
                    <mat-label>Integer Value</mat-label>
                    <input type="number" step="1" matInput formControlName="number">
                    <mat-error *ngIf="editEntityFormGroup.get('attributes.number').hasError('pattern')">
                        Invalid integer value.
                    </mat-error>
                </mat-form-field>
                <div class="boolean-value-input" fxLayout="column" fxLayoutAlign="center start" fxFlex>
                    <label class="checkbox-label">Boolean Value</label>
                    <mat-checkbox formControlName="booleanValue" style="margin-bottom: 40px;">

                    </mat-checkbox>
                </div>
            </div>
        </div>
        <div class="relations-list old-relations">
            <div class="mat-body-1" style="padding-bottom: 10px; color: rgba(0,0,0,0.57);">Relations</div>
            <div class="body" [fxShow]="oldRelations().length">
                <div class="row" fxLayout="row" fxLayoutAlign="start center" formArrayName="oldRelations" 
                     *ngFor="let relation of oldRelations().controls; let i = index;">
                    <div [formGroupName]="i" class="mat-elevation-z2" fxFlex fxLayout="row" style="padding: 5px 0 5px 5px;">
                        <div fxFlex fxLayout="column">
                            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                                <mat-form-field class="mat-block" style="min-width: 100px;">
                                    <mat-label>Direction</mat-label>
                                    <mat-select formControlName="direction" name="direction">
                                        <mat-option *ngFor="let direction of entitySearchDirection | keyvalue" [value]="direction.value">

                                        </mat-option>
                                    </mat-select>
                                    <mat-error *ngIf="relation.get('direction').hasError('required')">
                                        Relation direction is required.
                                    </mat-error>
                                </mat-form-field>
                                <tb-relation-type-autocomplete
                                        fxFlex class="mat-block"
                                        formControlName="relationType"
                                        required="true">
                                </tb-relation-type-autocomplete>
                            </div>
                            <div fxLayout="row" fxLayout.xs="column">
                                <tb-entity-select
                                        fxFlex class="mat-block"
                                        required="true"
                                        formControlName="relatedEntity">
                                </tb-entity-select>
                            </div>
                        </div>
                        <div fxLayout="column" fxLayoutAlign="center center">
                            <button mat-icon-button color="primary"
                                    aria-label="Remove"
                                    type="button"
                                    (click)="removeOldRelation(i)"
                                    matTooltip="Remove relation"
                                    matTooltipPosition="above">
                                <mat-icon>close</mat-icon>
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="relations-list">
            <div class="mat-body-1" style="padding-bottom: 10px; color: rgba(0,0,0,0.57);">New Relations</div>
            <div class="body" [fxShow]="relations().length">
                <div class="row" fxLayout="row" fxLayoutAlign="start center" formArrayName="relations" *ngFor="let relation of relations().controls; let i = index;">
                    <div [formGroupName]="i" class="mat-elevation-z2" fxFlex fxLayout="row" style="padding: 5px 0 5px 5px;">
                        <div fxFlex fxLayout="column">
                            <div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column"  fxLayoutGap.xs="0">
                                <mat-form-field class="mat-block" style="min-width: 100px;">
                                    <mat-label>Direction</mat-label>
                                    <mat-select formControlName="direction" name="direction">
                                        <mat-option *ngFor="let direction of entitySearchDirection | keyvalue" [value]="direction.value">

                                        </mat-option>
                                    </mat-select>
                                    <mat-error *ngIf="relation.get('direction').hasError('required')">
                                        Relation direction is required.
                                    </mat-error>
                                </mat-form-field>
                                <tb-relation-type-autocomplete
                                        fxFlex class="mat-block"
                                        formControlName="relationType"
                                        [required]="true">
                                </tb-relation-type-autocomplete>
                            </div>
                            <div fxLayout="row" fxLayout.xs="column">
                                <tb-entity-select
                                        fxFlex class="mat-block"
                                        [required]="true"
                                        formControlName="relatedEntity">
                                </tb-entity-select>
                            </div>
                        </div>
                        <div fxLayout="column" fxLayoutAlign="center center">
                            <button mat-icon-button color="primary"
                                    aria-label="Remove"
                                    type="button"
                                    (click)="removeRelation(i)"
                                    matTooltip="Remove relation"
                                    matTooltipPosition="above">
                                <mat-icon>close</mat-icon>
                            </button>
                        </div>
                    </div>
                </div>
            </div>
            <div>
                <button mat-raised-button color="primary"
                        type="button"
                        (click)="addRelation()"
                        matTooltip="Add Relation"
                        matTooltipPosition="above">
                    Add
                </button>
            </div>
        </div>
    </div>
    <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
        <button mat-button color="primary"
                type="button"
                [disabled]="(isLoading$ | async)"
                (click)="cancel()" cdkFocusInitial>
            Cancel
        </button>
        <button mat-button mat-raised-button color="primary"
                type="submit"
                [disabled]="(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty">
            Save
        </button>
    </div>
</form>
移动动作

移动操作在移动应用程序配置中进行了解释。

行动来源

操作源是实现目标所需执行的特定操作(例如单击小部件标题按钮、双击行或地图标记)。所有小部件的操作源都不同。将使用最常用的操作类型“导航到新的仪表板状态”的示例分别解释每种小部件类型的操作源。

动作源配置

为了适用性,我们考虑最常用的小部件上的操作源。

要将操作添加到实体表小部件:

  • 进入仪表板的编辑模式;
  • 单击小部件右上角的“铅笔”图标;
  • 选择最后一个单元格“操作”,然后单击窗口右侧的“加号”符号。
1. 操作单元按钮

单击已选为按钮的图标即可执行操作。要配置操作单元格按钮操作源,您应该:

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 在顶部下拉菜单中,选择“操作”单元格按钮操作源。
  4. 在下一行中输入操作的名称并选择代表按钮的图标。使用此按钮,将执行操作。
  5. 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  6. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  7. 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  8. 现在您可以看到配置的操作,因此您可以仔细检查操作源、图标和操作类型。
  9. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  10. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

如您所见,每个实体名称对面是一个操作单元按钮。单击此按钮将执行操作,即转换到所选状态。

2. 小部件标题按钮

小部件的标题中会出现一个按钮。单击此按钮将执行一个操作。该按钮负责整个小部件,而不是独立的实体。小部件标题按钮是最常用的操作源,在所有小部件中都可以找到它。要配置Widget 标题按钮操作源,您应该:

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 在顶部下拉菜单中,选择小部件标题按钮操作源。
  4. 在下一行中输入操作的名称并选择代表按钮的图标。使用此按钮,将执行操作。
  5. 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  6. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  7. 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  8. 现在您可以看到配置的操作,因此您可以仔细检查操作源、图标和操作类型。
  9. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  10. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

正如您现在所看到的,小部件的标题中出现了一个按钮图标。单击后,将执行操作,即转换到所选状态。

3. 在行上单击

单击表格小部件的行将执行一个操作。要配置行上单击操作源,您应该:

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 在顶部下拉菜单中,选择行上单击操作源。
  4. 在相应的行中输入操作的名称。
  5. 使用此操作源,小部件上不会有任何按钮,因此我们不应该选择图标。
  6. 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  7. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  8. 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  9. 现在,您会看到配置的操作,因此您可以仔细检查操作源和操作类型。
  10. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  11. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

要执行操作,即转换到所选状态,只需单击表格小部件的任意行即可。

4. 在行上双击

双击实体表小部件的任意行即可执行操作。要配置行上双击操作源,您应该:

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 在顶部下拉菜单中,选择“在行上双击操作源”。
  4. 在相应的行中输入操作的名称。
  5. 使用此操作源,小部件上不会有任何按钮,因此我们不应该选择图标。
  6. 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  7. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  8. 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  9. 现在,您会看到配置的操作,因此您可以仔细检查操作源和操作类型。
  10. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  11. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

要执行操作,即转换到所选状态,只需双击表格小部件的任何行即可。

5. 在选定的节点上(仅在实体层次结构小部件中)

添加实体层次结构小部件后,您应该配置层次结构本身。添加关系后,转到实体层次结构小部件的编辑模式。要配置在节点上选择的操作源:

  1. 在小部件的编辑模式下,移至名为“操作”的最后一个单元格。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 在顶部下拉菜单中,选择“在节点上选择的操作源”。
  4. 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  5. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  6. 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  7. 现在您可以看到配置的操作,因此您可以仔细检查操作源和操作类型。
  8. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  9. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

要执行操作,您应该单击实体层次结构中的任何节点。

6. 在 HTML 元素上单击(仅在 HTML 卡和值标题小部件中)

YiCONNECT 有两个小部件,您可以通过在其设置中自定义 HTML 代码来完全自行配置。当编写代码时,可以在其中输入动作源。 如何将操作源添加到 HTML 卡和值标题小部件:

  • HTML 卡小部件
  • 在小部件的编辑模式下,移至名为“操作”的最后一个单元格。
  • 单击窗口右侧的“+”图标添加新操作。
  • 在顶部下拉菜单中,选择“在 HTML 元素上单击操作源”。
  • 输入动作名称,一定要记住,因为配置HTML代码时会用到动作名称。
  • 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  • 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  • 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  • 现在您可以看到配置的操作,因此您可以仔细检查操作源和操作类型。
  • 现在移至小部件的高级单元格。在那里您应该看到两个字段:CSS 和 HTML。
  • 在 HTML 字段中输入操作的 ID,即其名称。由于示例中的名称是 test1 ,因此 HTML 代码将如下所示:
<div id='button' class='card'>HTML code here</div>
  • 其中,按钮是操作的名称,HTML 代码是要在 HTML 卡小部件上显示的文本

然后通过单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。 在仪表板的编辑模式中,通过单击屏幕右下角的橙色勾号图标“应用更改”来保存应用的更改。

要执行操作,请单击小部件中的任意位置。

  • 值标题小部件
  • 在小部件的编辑模式下,移至名为“操作”的最后一个单元格。
  • 单击窗口右侧的“+”图标添加新操作。
  • 在顶部下拉菜单中,选择“在 HTML 元素上单击操作源”。
  • 输入动作名称,一定要记住,因为配置HTML代码时会用到动作名称。
  • 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  • 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  • 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  • 现在您可以看到配置的操作,因此您可以仔细检查操作源和操作类型。
  • 现在移至小部件的高级单元格。在那里您应该看到两个已编写代码的字段:CSS 和 HTML。
  • 例如,让我们配置一个通过单击小部件的标题来执行的操作。在 HTML 字段中找到标头标签并在其中输入您的操作 ID。由于示例中的名称是 test2 ,因此 HTML 代码将如下所示:
<h1 id='button2'>Value title</h1>
  • 其中,button2是操作的名称,Value title是将显示在小部件标题中的文本。

然后通过单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。 在仪表板的编辑模式中,通过单击屏幕右下角的橙色勾号图标“应用更改”来保存应用的更改。

要执行操作,请单击小部件的标题。

地图小部件操作源

地图小部件具有独特的操作源,需要单独考虑。

让我们从添加地图小部件开始。转到将放置地图的仪表板,然后单击右下角的“铅笔”图标:

  • 如果您有一个空的新仪表板 ,则只需单击中间的“添加新小部件”消息,然后在列表末尾的下拉菜单中选择“地图”。然后,添加小部件的数据源并单击“添加”。
  • 如果之前已将一些小部件添加到此仪表板 ,请单击“Paper”图标(“创建新小部件”)。在列表末尾的下拉菜单中选择“地图”。最后,添加小部件的数据源并单击“添加”。

  • 向地图小部件添加操作

现在是时候添加一个动作了。为此,您应该单击地图小部件右上角的“铅笔”图标以进入“编辑小部件”模式。导航到“操作”单元格,然后单击屏幕右侧的“+”图标。将打开“添加操作”窗口。

请注意 :所有操作说明均假设您已将状态添加到小部件中。

1. 在标记上单击

单击红色地图的标记即可执行操作。

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 在顶部下拉菜单中,选择标记单击操作源。
  4. 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  5. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  6. 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  7. 现在您可以看到配置的操作,因此您可以仔细检查操作源、图标和操作类型。
  8. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  9. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。
2. 在多边形上单击

多边形是由有限数量的点描述的平面图形。我们使用基于我们使用的设备中指定的坐标的多边形,但您可以使用任何其他实体。您可以使用多边形选项标记您的资产和任何其他实体。对于多边形,我们可以指定接下来的设置。多边形坐标以以下格式接收:

[[1CoordinateLatitude,1CoordinateLatitude],[2CoordinateLatitude,2CoordinateLatitude]...[nCoordinateLatitude,nCoordinateLatitude]]

其中 n - 描述多边形的坐标数。

要在地图小部件上配置“多边形单击操作源”,您应该:

  1. 在小部件的编辑模式下,移至单元格“高级”。
  2. 滚动到多边形设置,勾选“显示多边形”复选框。
  3. 输入Polygon键名并记住,稍后会用到。
  4. 单击窗口右上角的橙色勾号以应用更改。
  5. 单击右下角的勾号图标以保存更改。
  6. 通过左侧的 YiCONNECT 主菜单,转到“资产”。
  7. 从资源列表中选择您想要添加多边形的资源并将其打开。
  8. 在资产详细信息窗口中,转到属性单元格。
  9. 单击“+”图标向资产添加新属性。
  10. 在“添加属性”窗口中输入一个键 - 它必须与多边形键名称相同。
  11. 选择值类型“字符串”并输入多边形的块坐标。在示例中,我们使用随机坐标
    [[37.758436,  -122.509429],[37.759834, -122.476874],[37.734690, -122.475170],[37.733531, -122.506271]]
    
  12. 在“添加属性”窗口中单击右下按钮“添加”。
  13. 返回带有地图小部件的仪表板。
  14. 单击右下角的“铅笔”图标进入仪表板的编辑模式。
  15. 单击地图小部件右上角的“铅笔”图标进入其编辑模式。
  16. 在数据源中添加刚刚配置的数据密钥。只需开始输入其名称,它将显示在列表中。
  17. 添加新数据密钥后,应用更改。
  18. 移至最后一个单元格“操作”。
  19. 单击窗口右侧的“+”图标添加新操作。
  20. 在顶部下拉菜单中,选择“ 在多边形上单击” 操作源。
  21. 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  22. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  23. 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  24. 现在您可以看到配置的操作,因此您可以仔细检查操作源和操作类型。
  25. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  26. 单击屏幕右下角的橙色勾号图标“应用更改”保存应用的更改。

要执行操作,请单击多边形内的任意位置。

3. 工具提示标签动作

单击地图标记时,会出现工具提示。工具提示包含执行操作的链接。 请注意,本手册解释了使用工具提示标签操作源的基本方法。可以为返回不同值的各种设备/资产配置多个链接。使用地图小部件高级模式中的工具提示功能来完成此操作。

要配置地图小部件的工具提示标签操作,您应该:

  1. 在小部件的编辑模式下,移至最后一个单元格“操作”。
  2. 单击窗口右侧的“+”图标添加新操作。
  3. 在顶部下拉菜单中,选择标记单击操作源。
  4. 输入操作的名称并确保记住它,稍后会用到它。
  5. 由于所有操作源的示例都是“导航到新仪表板状态”操作类型,因此请在下拉类型菜单中选择它。
  6. 选择操作类型后,将出现下拉菜单“目标仪表板状态”。选择您想要转换到的先前创建的状态。
  7. 配置完所有需要的设置后,单击“添加操作”窗口右下角的“添加”。
  8. 现在您可以看到配置的操作,因此您可以仔细检查操作源、图标和操作类型。
  9. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  10. 移至高级设置单元格。
  11. 向下滚动到工具提示配置并勾选“显示工具提示”复选框。
  12. 在工具提示行中找到链接操作名称并以以下格式输入操作名称:
<link-act name='TooltipTag'>Navigate to the Building A</link-act>

其中TooltipTag是操作名称,Navigate to the Building A是将在工具提示上显示为链接的文本。

  1. 单击窗口右上角的橙色勾号图标应用更改,然后关闭详细信息窗口。
  2. 通过单击屏幕右下角的橙色来保存应用的更改。

单击地图的标记即可显示工具提示。要执行操作,请单击工具提示底部的链接文本。

特殊动作设置

打开右侧仪表板布局(移动视图)

用户通常需要在一个小部件附近的另一个小部件上查看其更新的详细信息。例如,我们在实体表小部件中有一个资产列表,我们希望在附近的图表小部件上更新它们的详细信息。在桌面上,可以通过将两个小部件彼此靠近并选择“更新当前仪表板”操作类型来轻松配置,但是自适应移动屏幕会自动将小部件放在彼此下方,因此您需要向下滚动才能在第二个小部件上查看所需的信息一。

布局功能解决了这个问题。要配置布局并移动已创建的小部件,您应该:

  1. 单击页面右下角的“铅笔”图标进入仪表板的编辑模式。
  2. 在窗口的左上角单击“管理布局”。
  3. 在打开的“管理布局”窗口中,勾选“右侧”复选框,然后单击“保存”。现在我们有两种布局。
  4. 然后,我们需要将图表小部件转移到正确的布局。右键单击小部件,然后从出现的菜单中选择“复制”。
  5. 右键单击空白布局上的任意位置,然后从出现的菜单中选择“粘贴”。
  6. 当我们在两个布局上都有相同小部件的两个副本时,让我们通过右键单击主布局上的那个小部件并在出现的菜单中选择“删除”来删除它。在打开的对话框确认窗口中单击“是”,该小部件将被删除。
  7. 通过拖动小部件的边缘来调整小部件的大小。

现在,要激活一项操作,只需单击一下按钮即可在另一个小部件上查看一个小部件的详细信息,而无需进行更多操作,您需要:

  1. 单击小部件右上角的“铅笔”图标,进入主布局上小部件的编辑模式。
  2. 转到“操作”单元格并单击“+”图标添加新操作。
  3. 选择所需的操作源,在示例中,它将是操作单元格按钮。为操作命名,它将在移动模式下可见。通过单击图标图像并从各种图标中进行选择,选择代表按钮的图标(如果需要)。
  4. 选择操作类型“更新当前仪表板状态”。选择目标仪表板状态 - 它应该是创建布局的仪表板状态。
  5. 最后,勾选“打开右侧仪表板布局(移动视图)”复选框。
  6. 单击对话框窗口右下角的“保存”以应用更改。
  7. 在仪表板编辑模式下,单击页面右下角的橙色勾号。

现在在移动模式下,通过单击操作按钮,我们将直接转换到所需的小部件,在其中我们可以看到主小部件的实体的详细信息。

在单独的对话框中打开

有时,移动到独立的仪表板状态来查看小部件的详细信息是不切实际的,但您只想在同一仪表板页面上打开它。对于这些情况,有一个“ 在单独的对话框中打开” 功能,允许使用配置的操作在同一页面上打开另一个状态。要在您所在仪表板上的单独对话窗口中打开状态,您应该:

  1. 单击页面右下角的“铅笔”图标进入仪表板的编辑模式。
  2. 首先,我们需要添加一个新状态,因此单击仪表板左上角的“管理仪表板状态”按钮。
  3. 在打开的窗口中,单击“+”图标添加新状态。
  4. 添加状态后,单击“管理仪表板状态”窗口右下角的“保存”按钮。
  5. 现在,通过单击小部件右上角的“铅笔”图标进入小部件编辑模式。
  6. 转到“操作”单元格并单击“+”图标添加新操作。
  7. 选择所需的操作源,在示例中,它将是操作单元格按钮。为该操作指定一个名称。通过单击图标图像并从各种图标中进行选择来选择代表按钮的图标。
  8. 从下拉菜单中选择“导航到新仪表板”操作类型和目标状态(在步骤 3 中创建的状态)。
  9. 勾选“在单独的对话框中打开”复选框并为对话框指定标题。
  10. 默认情况下,“在对话框中隐藏仪表板工具栏”复选框处于选中状态。如果您需要在对话框窗口中看到工具栏,则应取消选中它。工具栏显示实体、时间窗口、仪表板导出按钮,并展开为全屏按钮。
  11. 可以选择以百分比形式调整对话框的宽度和高度。宽度是相对于视口高度的,高度也是相对于宽度的。
  12. 配置操作后,单击“添加操作”窗口右下角的“添加”按钮。
  13. 添加操作后,请仔细检查操作来源、图标和操作类型。如果一切正确,请单击页面右上角的橙色勾号。

现在是时候将小部件添加到另一个状态并执行操作了。为此,您应该:

  1. 转到新创建的空状态,然后单击屏幕中间的“添加新小部件”。
  2. 从下拉菜单“当前包”中,选择所需的小部件,在我们的示例中,它将是地图小部件“OpenStreetMap”。
  3. 添加数据源并单击“添加”。
  4. 仪表板状态上已添加一个小部件,拖动其边缘可调整大小。
  5. 调整后,单击屏幕左下角的橙色勾号以保存应用的更改。

要执行操作并打开包含状态的对话窗口,请单击实体名称对面的单元格按钮。

从小部件设置实体

从小部件设置实体复选框负责将特定实体从小部件添加到状态。这允许您通过创建“来自仪表板状态的实体”或其他别名来使用目标仪表板状态中的实体。例如,如果您在表格小部件中有一个设备列表,并且希望在单击表格行时显示特定设备的详细信息。

有时您需要在状态中存储多个实体。例如,您希望导航到客户列表,然后导航到客户的设备,最后导航到特定设备的详细信息。在这种情况下,您可能有三种状态:“主要”、“客户设备”和“设备详细信息”。您可以使用两个不同的状态实体参数来引用“设备详细信息”状态上的当前客户(例如“currentCustomer”)和当前设备(例如“currentDevice”)。