fengxiang
2018-06-25 27cd36be226ca2434f06b1ae9e4d43f1fea639ab
组织配置单位和页面显示
5 files added
15 files modified
866 ■■■■■ changed files
package.json 1 ●●●● patch | view | raw | blame | history
src/app/business/entity/data.ts 20 ●●●●● patch | view | raw | blame | history
src/app/business/enum/types.enum.ts 6 ●●●●● patch | view | raw | blame | history
src/app/business/services/http/organization.service.ts 16 ●●●● patch | view | raw | blame | history
src/app/business/services/http/sensor-unit.service.ts 18 ●●●●● patch | view | raw | blame | history
src/app/business/services/util/tools.service.ts 7 ●●●●● patch | view | raw | blame | history
src/app/routes/devices/basic-info/device-edit/device-edit.component.ts 1 ●●●● patch | view | raw | blame | history
src/app/routes/sensors/basic-info/basic-info.component.html 2 ●●● patch | view | raw | blame | history
src/app/routes/sensors/basic-info/sensor-unit/sensor-unit.component.html 81 ●●●●● patch | view | raw | blame | history
src/app/routes/sensors/basic-info/sensor-unit/sensor-unit.component.ts 135 ●●●●● patch | view | raw | blame | history
src/app/routes/sensors/sensors.module.ts 4 ●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-config-screen/organization-config-screen.component.html 150 ●●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-config-screen/organization-config-screen.component.ts 222 ●●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-config-unit/organization-config-unit.component.html 42 ●●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-config-unit/organization-config-unit.component.ts 83 ●●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-config/organization-config.component.ts 4 ●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-list/organization-list.component.html 19 ●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-list/organization-list.component.ts 49 ●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization.component.html 2 ●●●●● patch | view | raw | blame | history
src/app/routes/systems/systems.module.ts 4 ●●●● patch | view | raw | blame | history
package.json
@@ -13,7 +13,6 @@
  },
  "license": "MIT",
  "scripts": {
    "precommit": "npm run lint-staged",
    "ng": "ng",
    "start": "ng serve --host=0.0.0.0",
    "serve:hmr": "ng serve -o --hmr -e=hmr",
src/app/business/entity/data.ts
@@ -1,5 +1,5 @@
import { Column } from '@business/entity/grid';
import { AlarmStyle, TimeUnits, AreaRange, DeviceDimension } from '@business/enum/types.enum';
import { AlarmStyle, TimeUnits, AreaRange, DeviceDimension, Operator } from '@business/enum/types.enum';
export interface AreaNames {
@@ -167,3 +167,21 @@
  category: string;
  value: number;
}
export interface OperatorRule {
  operator: Operator;
  value: number;
}
export interface SensorUnit {
  id?: number|any;
  originalUnitName?: string;
  name?: string|any;
  rules?: OperatorRule[]|any;
  sensorId?: number|any;
}
export interface OrganizationSensorUnit {
  id?: number|any;
  sensorUnitId?: number|any;
  sensorUnit?: SensorUnit|any;
  sensor?: Sensor|any;
  organizationId?: number|any;
}
src/app/business/enum/types.enum.ts
@@ -25,3 +25,9 @@
    PROFESSION= 'PROFESSION',
    NONE= 'NONE'
}
export enum Operator {
    PLUS = 'PLUS', // 加
    MINUS = 'MINUS', // 减
    MULTIPLY = 'MULTIPLY', // 乘
    DIVIDE = 'DIVIDE' // 除
 }
src/app/business/services/http/organization.service.ts
@@ -1,4 +1,4 @@
import { Organization, AlarmConfig } from '@business/entity/data';
import { Organization, AlarmConfig, OrganizationSensorUnit, SensorUnit } from '@business/entity/data';
import { ExampleService } from '@business/services/util/example.service';
import { _HttpClient } from '@delon/theme';
import { environment } from 'environments/environment';
@@ -11,10 +11,10 @@
@Injectable()
export class OrganizationService {
  handle: 'list'|'config' = 'list';
  config: {pageBean: PageBean, resultBean: ResultBean<AlarmConfig>};
  handle: 'list'|'config'|'unit'|'screen' = 'list';
  config: {pageBean?: PageBean, resultBean?: ResultBean<AlarmConfig|any>} = {};
  data: Organization;
  title: '组织列表'|'组织配置' = '组织列表';
  title: '组织列表'|'配置三级警报'|'配置显示单位'|'配置大屏布局' = '组织列表';
  private urls = {
      list: environment.SERVER_BASH_URL + '/organization/page-list',
      save: environment.SERVER_BASH_URL + '/organization/add-or-modify',
@@ -40,4 +40,12 @@
  public delete(...ids: number[]): Observable<any> {             
        return this.http.post(this.urls.delete, ids);
  }
  public getResultBeanData(key: string) {
        if (!!this.config.resultBean
          && !!this.config.resultBean.code
          && !!this.config.resultBean.data) {
          return this.config.resultBean.data[key];
       }
       return null;
  }
}
src/app/business/services/http/sensor-unit.service.ts
New file
@@ -0,0 +1,18 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { SensorUnit } from '@business/entity/data';
import { _HttpClient } from '@delon/theme';
import { ResultBean } from '@business/entity/grid';
@Injectable()
export class SensorUnitService {
  private urls = {
    list: 'sensor-unit/gets-bysid',
  };
  constructor(
    private http: _HttpClient
  ) { }
  public getListBySensorId(sensorId: number): Observable<ResultBean<SensorUnit[]>> {
    return this.http.get( this.urls.list, {  sensorId : sensorId });
  }
}
src/app/business/services/util/tools.service.ts
@@ -15,6 +15,13 @@
             }
         );
      }
      public static getValueFormControl(controlSet: FormGroup, name: string) {
        return controlSet.controls[name].value;
      }
      public static setValueToControl(controlSet: FormGroup, name: string, value: any) {
         controlSet.controls[name].setValue(value);
         controlSet.controls[name].updateValueAndValidity();
      }
      public static removePrivate(obj: object) {
            Object.keys(obj).forEach(
                 (key: string) => {
src/app/routes/devices/basic-info/device-edit/device-edit.component.ts
@@ -39,7 +39,6 @@
  originalData: Device = {};
  validateForm: FormGroup;
  ngOnInit() {
      debugger;
    if (!!this.data) {
        Object.assign(this.originalData, this.data);
    }    
src/app/routes/sensors/basic-info/basic-info.component.html
@@ -18,7 +18,7 @@
                </nz-alert>
    </div>
    <nz-table #nzTable
              [nzAjaxData]="grid.data"
              [nzAjaxData]="grid.data"
              [nzTotal]="grid.total"
              [(nzPageIndex)]="grid.pageIndex"
              [(nzPageSize)]="grid.pageSize"
src/app/routes/sensors/basic-info/sensor-unit/sensor-unit.component.html
@@ -1,3 +1,84 @@
<div class="modal-header">
    <div class="modal-title">配置-传感器单位</div>
</div>
<form [formGroup]="validateForm" (ngSubmit)="save($event,validateForm.value,validateForm.valid)" nz-form [nzType]="'horizontal'">
    <div nz-form-item nz-row class="mb-sm">
      <div nz-form-label nz-col [nzSm]="7" [nzXs]="24">
        <label nz-form-item-required>类别</label>
      </div>
      <div nz-form-control nz-col [nzSpan]="5" nzHasFeedback>
           <label>{{ data.name }}</label>
      </div>
      <div nz-form-label nz-col [nzSm]="2" [nzXs]="24">
          <label nz-form-item-required>原单位</label>
      </div>
      <div nz-form-control nz-col [nzSpan]="5" nzHasFeedback>
             <label>{{ data.unit }}</label>
      </div>
    </div>
    <div nz-form-item nz-row class="mb-sm">
      <div nz-form-label nz-col [nzSm]="7" [nzXs]="24">
        <label nz-form-item-required>单位名称</label>
      </div>
      <div nz-form-control nz-col [nzSpan]="10" nzHasFeedback>
        <nz-input formControlName="name" maxlength="20" [nzPlaceHolder]="'名称'">
        </nz-input>
      </div>
    </div>
    <div nz-form-item nz-row class="mb-sm">
      <div nz-form-label nz-col [nzSm]="7" [nzXs]="24">
        <label nz-form-item-required>计算规则</label>
      </div>
      <div nz-form-control nz-col [nzSpan]="10">
          <nz-select formControlName="_rule-operator"  style="width: 18%">
            <nz-option *ngFor="let option of operatorOptions" [nzLabel]="option.label" [nzValue]="option.value">
            </nz-option>
          </nz-select>
          <nz-input-number formControlName="_rule-value" style="width: 20%" [nzMin]="0.000001" maxlength="20" [nzStep]="0.000001"></nz-input-number>
          <button nz-button style="left: 1px;" [nzType]="'default'" (click) = "addRule($event)"><i class="anticon anticon-plus"></i></button>
      </div>
    </div>
    <div nz-form-item nz-row class="mb-sm">
      <div nz-col [nzSm]="7" [nzXs]="24">
      </div>
      <div nz-form-control nz-col [nzSpan]="9" nzHasFeedback>
        <nz-input  nzReadonly = "true" formControlName="_rules" maxlength="10000" [nzPlaceHolder]="'(通过上面选择框添加规则)'">
        </nz-input>
      </div>
      <div nz-col [nzSpan]="3" style="padding-left: 8px;padding-top: 2px;">
        <button nz-button [nzType]="'default'" (click) = "clearRules($event)"><i class="anticon anticon-close"></i></button>
      </div>
    </div>
    <div nz-row class="mb-sm">
        <div nz-col [nzSm]="7" [nzXs]="24">
        </div>
        <div nz-col [nzSpan]="10" style="text-align:right;">
          <button nz-button [nzType]="'default'" (click)="reset($event)">重置条件</button>
          <button nz-button [nzType]="'primary'" [nzLoading]="isSaving">
            <span *ngIf="getValueFormControl('id') !== null">保存编辑</span>
            <span *ngIf="getValueFormControl('id') === null">添加单位</span>
          </button>
        </div>
    </div>
  </form>
  <div nz-row class="mb-sm">
    <div nz-col [nzSm]="5" [nzXs]="24">
    </div>
    <div nz-col [nzSm]="13" [nzXs]="24">
      <div style="display: block;overflow-y:auto; width:100%;max-height:200px;border: 0;padding: 0;margin: 0">
      <div *ngFor="let item of dataList" nz-row class="mb-sm" style="padding:4px 0 0 0;border-top: 2px dotted #e9e9e9;">
        <div nz-col [nzSm]="8" [nzXs]="24">
           <label>{{item.name}}</label>
        </div>
        <div nz-col [nzSm]="8" [nzXs]="24">
            <label>{{item.rules.replace('{0}','初值')}}</label>
        </div>
        <div nz-col [nzSm]="8" [nzXs]="24">
            <a (click)="toEdit(item)">编辑</a>
            <span>&nbsp;|&nbsp;</span>
            <nz-popconfirm [nzTitle]="'确定要删除?'" [nzOkText]="'Yes'" [nzCancelText]="'No'" (nzOnConfirm)="delete(item.id)" >
              <a nz-popconfirm>删除</a>
          </nz-popconfirm>
        </div>
    </div>
  </div>
src/app/routes/sensors/basic-info/sensor-unit/sensor-unit.component.ts
@@ -1,7 +1,12 @@
import { Component, OnInit } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { NzModalSubject } from 'ng-zorro-antd';
import { FormGroup } from '@angular/forms';
import { FormGroup, Validators, FormBuilder, FormControl } from '@angular/forms';
import { Sensor, SensorUnit, OperatorRule } from '@business/entity/data';
import { ToolsService } from '@business/services/util/tools.service';
import { Operator, ResultCode } from '@business/enum/types.enum';
import { ResultBean } from '@business/entity/grid';
import { SensorUnitService } from '@business/services/http/sensor-unit.service';
@Component({
  selector: 'app-sensor-unit',
@@ -10,13 +15,44 @@
export class SensorUnitComponent implements OnInit {
    public isSaving = false;
    public validateForm: FormGroup;
    public data: any;
    public operatorOptions: {label: string, value: Operator} [] = [
      {label: '加', value: Operator.PLUS},
      {label: '减', value: Operator.MINUS},
      {label: '乘', value: Operator.MULTIPLY},
      {label: '除', value: Operator.DIVIDE}
    ];
    // public rule = '乘';
    public data: Sensor;
    public dataList: SensorUnit[] = [];
    constructor(
        private subject: NzModalSubject,
        private http: _HttpClient
        private formBuilder: FormBuilder,
        private http: _HttpClient,
        private sensorUnitService: SensorUnitService
    ) { }
    loadDataList() {
      this.sensorUnitService.getListBySensorId(this.data.id).subscribe(
        res => {
          if (res.code === 1 ) {
            this.dataList = res.data;
          }
        }
      );
    }
    ngOnInit() {
      this.loadDataList();
      const validates: SensorUnit  = {
           id: [null ],
           sensorId: [this.data.id, [Validators.required] ],
           name: [null, [Validators.required] ]
      };
      validates['_rule-operator'] = [Operator.MULTIPLY];
      validates['_rule-value'] = 1000;
      validates['_rules'] =  [null, [Validators.required]];
      this.validateForm = this.formBuilder.group(
          validates
      );
      // this.validateForm.controls['_rules'].disable();
    }
    save($event, value, valid) {
        $event.preventDefault();
@@ -25,19 +61,100 @@
            this.validateForm.controls[ i ].disable();
          } 
          this.isSaving = true;
          Object.keys(value).forEach( (key: string) => {
                // '_'为前缀的为自定义属性
                if (!key.startsWith('_') && value[key] != null) {
                     this.data[key] = value[key];
          ToolsService.removePrivate(value);
          const sensorUnit: SensorUnit = {};
          Object.assign(sensorUnit, value);
          sensorUnit['rules'] = this.rulesToString(this.rules);
          sensorUnit['originalUnitName'] = this.data.unit;
          console.log(JSON.stringify(sensorUnit));
          this.http.post('sensor-unit/add-or-modify', sensorUnit).subscribe(
            (res: ResultBean<any>) => {
                if (!!res.code) {
                  for (const i in this.validateForm.controls) {
                    this.validateForm.controls[ i ].enable();
                  }
                  this.isSaving = false;
                  this.loadDataList();
                  this.reset();
                }
          } );
            }
          );
        } else {
          this.validate(); 
        }
    }
    toEdit(item) {
        this.reset();
        this.setValueToControl('id', item.id);
        this.setValueToControl('name', item.name);
    }
    delete(id) {
      this.http.get('sensor-unit/delete', {id: id}).subscribe(
          (res: ResultBean<any>) => {
             if (!!res.code ) {
               this.loadDataList();
             }
          }
      );
    }
    validate() {
        for (const i in this.validateForm.controls) {
          this.validateForm.controls[ i ].markAsDirty();
        }
     }
     private rules: OperatorRule[] = [];
     addRule(event) {
      event.preventDefault();
      const rule: OperatorRule = {
        operator: this.getValueFormControl('_rule-operator'),
        value: this.getValueFormControl('_rule-value')
      };
      this.rules.push(rule);
      this.setValueToControl('_rules' , this.rulesToString(this.rules, '初值'));
     }
     rulesToString(rules , dataLabel?: string) {
        let rulesString = '' ;
        dataLabel = dataLabel === undefined ? '{0}' : dataLabel;
        if (!!this.rules && this.rules.length > 0) {
            // const dataLabel = '初值';
            rulesString += dataLabel ;
            this.rules.forEach(rule => {
              if (!rulesString.endsWith(dataLabel)) {
                rulesString = '(' + rulesString + ')';
              }
               switch (rule.operator) {
                  case Operator.PLUS: rulesString += '+' + rule.value + 'd'; break;
                  case Operator.MINUS: rulesString += '-' + rule.value + 'd'; break;
                  case Operator.MULTIPLY: rulesString += '*' + rule.value + 'd'; break;
                  case Operator.DIVIDE: rulesString += '/' + rule.value + 'd'; break;
               }
            });
        }
        return rulesString;
     }
     getValueFormControl(controlName: string) {
       return ToolsService.getValueFormControl(this.validateForm, controlName);
     }
     setValueToControl(controlName: string, value: any) {
      ToolsService.setValueToControl(this.validateForm, controlName, value);
     }
     clearRules(event) {
      event.preventDefault();
      this.rules = [];
      this.setValueToControl('_rules', this.rulesToString(this.rules, '初值'));
     }
    //  print() {
    //      debugger;
    //      console.log(this.validateForm.controls['_rule']);
    //  }
    reset(event?: any) {
      if (!!event) {
        event.preventDefault();
      }
      this.setValueToControl('id', null);
      this.setValueToControl('name', null);
      this.setValueToControl('_rules', null);
      this.setValueToControl('_rule-operator', Operator.MULTIPLY);
      this.setValueToControl('_rule-value', 1000);
    }
}
src/app/routes/sensors/sensors.module.ts
@@ -9,6 +9,8 @@
import { FormBuilder } from '@angular/forms';
import { SensorEditComponent } from './basic-info/sensor-edit/sensor-edit.component';
import { SensorUnitComponent } from './basic-info/sensor-unit/sensor-unit.component';
import { ToolsService } from '@business/services/util/tools.service';
import { SensorUnitService } from '@business/services/http/sensor-unit.service';
const routes: Routes = [
  {
@@ -32,7 +34,7 @@
    SensorUnitComponent,
    SensorEditComponent
  ],
  providers: [SensorsService, _HttpClient, FormBuilder],
  providers: [SensorsService, _HttpClient, FormBuilder, ToolsService, SensorUnitService],
  entryComponents: COMPONENTS_NOROUNT
})
export class SensorsModule { }
src/app/routes/systems/organization/organization-config-screen/organization-config-screen.component.html
New file
@@ -0,0 +1,150 @@
<nz-tabset [nzTabPosition]="'left'" [(nzSelectedIndex)]="selectedIndex" (nzSelectedIndexChange)="swapTab()">
    <nz-tab *ngFor="let tab of deviceVersions">
        <ng-template #nzTabHeading>
            {{tab.name}}
        </ng-template>
        <nz-spin [nzSpinning]="isSpinning">
            <form nz-form>
                <nz-card [nzBordered]="false" nzTitle="待选区({{surplusSensors.length}})">
                    <div nz-form-item nz-row>
                        <ng-container *ngFor="let sensor of surplusSensors,index as i">
                            <div nz-form-control nz-col [nzSm]="2">
                                <label>{{ sensor.name }}</label>
                            </div>
                            <div nz-form-control nz-col [nzSm]="4">
                                <nz-dropdown [nzTrigger]="'click'">
                                    <a class="ant-dropdown-link" nz-dropdown>
                                        移到
                                        <i class="anticon anticon-down"></i>
                                    </a>
                                    <ul nz-menu>
                                        <li nz-menu-item>
                                            <a (click)="moveTo(surplusSensors,i,defaultMonitorItems)">
                                                默认区
                                            </a>
                                        </li>
                                        <li nz-menu-divider></li>
                                        <li nz-menu-item (click)="moveTo(surplusSensors,i,coreMonitorItems)" [nzDisable]="isCoreItemsFull">
                                            核心区
                                            <span *ngIf="isCoreItemsFull">(已满)</span>
                                        </li>
                                    </ul>
                                </nz-dropdown>
                            </div>
                        </ng-container>
                    </div>
                    <nz-row nzType="flex" nzJustify="end" nzAlign="top">
                        <nz-col nzSpan="4" >
                            <button (click)="moveAllto(surplusSensors,defaultMonitorItems)" nz-button>全添加到默认区</button>
                        </nz-col>
                    </nz-row>
                </nz-card>
                <div nz-form-item nz-row>
                    <div nz-form-control nz-col [nzSm]="8"></div>
                    <div nz-form-control nz-col [nzSm]="8">
                        <label class="display-3">图表显示 :</label>
                        <span class="display-3">{{ chartSensorName }}</span>
                    </div>
                    <div nz-form-control nz-col [nzSm]="8"></div>
                </div>
                <nz-card [nzBordered]="false" nzTitle="默认区({{defaultMonitorItems.length}})">
                    <div *ngFor="let sensor of defaultMonitorItems,index as i" nz-form-item nz-row>
                        <div nz-form-control nz-col [nzSm]="6">
                            <label>{{ sensor.name }}</label>
                        </div>
                        <div nz-form-control nz-col [nzSm]="3">
                            <a (click)="itemUp(defaultMonitorItems,i)">上移</a>
                        </div>
                        <div nz-form-control nz-col [nzSm]="3">
                            <a (click)="itemDown(defaultMonitorItems,i)">下移</a>
                        </div>
                        <div nz-form-control nz-col [nzSm]="3">
                            <a (click)="setChartSensorKey(sensor.sensorKey)">设为图表</a>
                        </div>
                        <div nz-form-control nz-col [nzSm]="3">
                            <nz-dropdown [nzTrigger]="'click'">
                                <a class="ant-dropdown-link" nz-dropdown>
                                    移到
                                    <i class="anticon anticon-down"></i>
                                </a>
                                <ul nz-menu>
                                    <li nz-menu-item>
                                        <a (click)="moveTo(defaultMonitorItems,i,surplusSensors)">
                                            待选区
                                        </a>
                                    </li>
                                    <li nz-menu-divider></li>
                                    <li nz-menu-item (click)="moveTo(defaultMonitorItems,i,coreMonitorItems)" [nzDisable]="isCoreItemsFull">
                                        核心区
                                        <span *ngIf="isCoreItemsFull">(已满)</span>
                                    </li>
                                </ul>
                            </nz-dropdown>
                        </div>
                    </div>
                </nz-card>
                <nz-card [nzBordered]="false" nzTitle="核心区({{coreMonitorItems.length}}/6)">
                    <div *ngFor="let sensor of coreMonitorItems,index as i" nz-form-item nz-row>
                        <div nz-form-control nz-col [nzSm]="6">
                            <label>{{ sensor.name }}</label>
                        </div>
                        <div nz-form-control nz-col [nzSm]="3">
                            <a (click)="itemUp(coreMonitorItems,i)">上移</a>
                        </div>
                        <div nz-form-control nz-col [nzSm]="3">
                            <a (click)="itemDown(coreMonitorItems,i)">下移</a>
                        </div>
                        <div nz-form-control nz-col [nzSm]="3">
                            <a (click)="setChartSensorKey(sensor.sensorKey)">设为图表</a>
                        </div>
                        <div nz-form-control nz-col [nzSm]="3">
                            <nz-dropdown [nzTrigger]="'click'">
                                <a class="ant-dropdown-link" nz-dropdown>
                                    移到
                                    <i class="anticon anticon-down"></i>
                                </a>
                                <ul nz-menu>
                                    <li nz-menu-item>
                                        <a (click)="moveTo(coreMonitorItems,i,surplusSensors)">
                                            待选区
                                        </a>
                                    </li>
                                    <li nz-menu-divider></li>
                                    <li nz-menu-item (click)="moveTo(coreMonitorItems,i,defaultMonitorItems)">
                                        默认区
                                    </li>
                                </ul>
                            </nz-dropdown>
                        </div>
                    </div>
                </nz-card>
                <nz-card [nzBordered]="false" nzTitle="固定区({{optionalFixedItems.length}})">
                        <div nz-form-item nz-row>
                            <ng-container *ngFor="let sensor of optionalFixedItems,index as i">
                                <div nz-form-control nz-col [nzSm]="2">
                                </div>
                                <div nz-form-control nz-col [nzSm]="4">
                                    <label nz-checkbox [ngModel]="isFixedSensorSelected(sensor.sensorKey)"
                                    (ngModelChange) = "changeFixedItem( $event, sensor)"
                                    name="fixed_{{sensor.sensorKey}}_selected"></label>
                                    &nbsp;
                                    <label>{{ sensor.name }}</label>
                                </div>
                            </ng-container>
                        </div>
                    </nz-card>
            </form>
        </nz-spin>
    </nz-tab>
</nz-tabset>
<footer-toolbar>
    <label>组织名称:</label>
    <span [ngStyle]="{'font-size': '16px','font-weight': 'bold','margin-right':'30px'}">{{ organization.name }}</span>
    <button nz-button type="button" (click)="backToList()">返回</button>
    <button nz-button [nzType]="'primary'" (click)="save()" [nzLoading]="isSaving">
        <span>
            保存
            <span *ngIf="isSaving">中</span>
        </span>
    </button>
</footer-toolbar>
src/app/routes/systems/organization/organization-config-screen/organization-config-screen.component.ts
New file
@@ -0,0 +1,222 @@
import { Component, OnInit } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { NzMessageService } from 'ng-zorro-antd';
import { OrganizationService } from '@business/services/http/organization.service';
import { Sensor, Organization } from '@business/entity/data';
import { ResultBean } from '@business/entity/grid';
@Component({
  selector: 'app-organization-config-screen',
  templateUrl: './organization-config-screen.component.html',
})
export class OrganizationConfigScreenComponent implements OnInit {
    constructor(
        private http: _HttpClient,
        private organizationService: OrganizationService,
        public msgSrv: NzMessageService
    ) { }
    public selectedIndex = 0;
    public defaultSwapFlag: string;
    public coreSwapFlag: string;
    public organization: Organization;
    public deviceVersions: any[] = [];
    public addedSensors: any[] = [];
    // 待添加传感器
    public surplusSensors: any[] = [];
    public defaultMonitorItems: any[] = [];
    public coreMonitorItems: any[] = [];
    public optionalFixedItems: any[] = [];
    public fixedMonitorItems: any[] =  [];
    public chartSensorKey: string;
    ngOnInit() {
      this.organization = this.organizationService.data;
      this.deviceVersions =
                !!this.organizationService.getResultBeanData('deviceVersions') ?
                this.organizationService.getResultBeanData('deviceVersions') : [];
      const rtdLayout = this.organizationService.getResultBeanData('rtdLayout');
      const sensorCombs = <any[]>this.organizationService.getResultBeanData('sensorCombs');
      const optionalFixedItems = <any[]>this.organizationService.getResultBeanData('optionalFixedItems');
      this.loadPage(rtdLayout, sensorCombs, optionalFixedItems);
    }
    swapTab() {
        const version = this.deviceVersions[this.selectedIndex];
        this.isSaving = true;
        this.isSpinning = true;
        this.http.get('org-layout/rtd-act-config', {orgId: this.organization.id, versionNo: version.version }).subscribe(
            (res: ResultBean<any>) => {
                if ( res.code > 0 ) {
                    const data = res.data;
                    const rtdLayout = data.rtdLayout;
                    const sensorCombs = data.sensorCombs;
                    const optionalFixedItems = data.optionalFixedItems;
                    this.loadPage(rtdLayout, sensorCombs, optionalFixedItems);
                    this.isSaving = false;
                    this.isSpinning = false;
                }
            }
        );
    }
    loadPage(rtdLayout:
        {chartSensorKey: string,
         coreMonitorItems: any[],
         defaultMonitorItems: any [],
         optionalFixedItems: any[],
         fixedMonitorItems: any[]}
        , sensorCombs: any[], optionalFixedItems: any[]) {
        this.chartSensorKey = '';
        this.coreMonitorItems = [];
        this.defaultMonitorItems = [];
        this.addedSensors = [];
        this.surplusSensors = [];
        this.fixedMonitorItems = [];
        this.optionalFixedItems = !!optionalFixedItems ? optionalFixedItems : [];
        if (!!rtdLayout && !!sensorCombs.length) {
            this.chartSensorKey = rtdLayout.chartSensorKey;
            this.coreMonitorItems = rtdLayout.coreMonitorItems;
            this.defaultMonitorItems = rtdLayout.defaultMonitorItems;
            this.fixedMonitorItems = rtdLayout.fixedMonitorItems;
            this.addedSensors = [...rtdLayout.coreMonitorItems, ...rtdLayout.defaultMonitorItems];
            this.surplusSensors = sensorCombs.filter(
                ( item: any ) => {
                  return !this.addedSensors.some(
                      (sen: any) => {
                          return item.sensorKey === sen.sensorKey;
                      }
                  );
                }
            );
        } else {
          this.surplusSensors = sensorCombs;
        }
    }
    public get haveTaps(): Boolean {
        return !!this.deviceVersions && !!this.deviceVersions.length;
    }
    public get isCoreItemsFull(): Boolean {
        return this.coreMonitorItems.length >= 6;
    }
    public setChartSensorKey(sensorKey) {
        this.chartSensorKey = sensorKey;
    }
    public itemUp(items: any[], index) {
        if (index !== 0 ) {
           const tempIndex = index - 1;
           const temp = items[tempIndex];
           items[tempIndex] = items[index];
           items[index] = temp;
        }
   }
   public itemDown(items: any[], index) {
     if (index < (items.length - 1) ) {
        const tempIndex = index + 1;
        const temp = items[tempIndex];
        items[tempIndex] = items[index];
        items[index] = temp;
     }
    }
    moveTo(source: any[], sIndex: number, target: any[]) {
        const temp = source[sIndex];
        source.splice(sIndex, 1);
        target.push(temp);
        // 顺序不要颠倒
        this.refreshAddedList();
        this.refreshChartSensorKey();
    }
    moveAllto(source: any[],  target: any[]) {
        const length = source.length;
        target.push(...source);
        source.splice(0, length);
        this.refreshAddedList();
        this.refreshChartSensorKey();
    }
    public refreshChartSensorKey() {
        const isChartKeyRemoved = this.surplusSensors.some(
            item => {
                return item.sensorKey === this.chartSensorKey;
            }
        );
        if (isChartKeyRemoved || !this.chartSensorKey) {
            this.chartSensorKey = null;
            const length = this.addedSensors.length;
            if (length > 0) {
                this.chartSensorKey =  this.addedSensors[length - 1].sensorKey;
            }
        }
    }
    public get chartSensorName() {
        const sensor = this.addedSensors.find(
            item => {
                return item.sensorKey === this.chartSensorKey;
            }
        );
        return !!sensor ? sensor.name : '';
    }
    refreshAddedList() {
        this.addedSensors = [...this.defaultMonitorItems, ...this.coreMonitorItems];
    }
    public isSaving = false;
    public isSpinning = false;
    save() {
         this.isSaving = true;
         const version = this.deviceVersions[this.selectedIndex].version;
         const orgId = this.organization.id;
         if ( !!this.addedSensors.length ) {
            const rtdLayout = {
                chartSensorKey: this.chartSensorKey,
                defaultMonitorItems: this.defaultMonitorItems,
                coreMonitorItems: this.coreMonitorItems,
                fixedMonitorItems: this.fixedMonitorItems
            };
            const rtdLayoutUpload = {
                realTimeDeviceLayout : rtdLayout,
                organizationId: orgId,
                version: version
            };
            this.http.post('org-layout/rtd-save', rtdLayoutUpload).subscribe(
                (res: ResultBean<any>) => {
                    if (res.code > 0 ) {
                        this.isSaving = false;
                        this.msgSrv.success('保存成功');
                    }
                }
            );
         } else {
            this.http.get('org-layout/rtd-remove', {orgId: orgId, version: version}).subscribe(
                (res: ResultBean<any>) => {
                    if (res.code > 0 ) {
                        this.isSaving = false;
                        this.msgSrv.success('保存成功');
                    }
                }
            );
         }
    }
    isFixedSensorSelected(sensorKey: string) {
        const isSelected = this.fixedMonitorItems.some( item => {
            return item.sensorKey === sensorKey;
        });
        return isSelected;
    }
    changeFixedItem(event, sensor) {
         if (event) {
            this.fixedMonitorItems.push(sensor);
         } else {
            const delteIndex =  this.fixedMonitorItems.findIndex(
                item => {
                    return item.sensorKey === sensor.sensorKey;
                }
            );
            if (delteIndex > 0 ) {
                this.fixedMonitorItems.splice(delteIndex, 1);
            }
         }
    }
    backToList() {
        this.organizationService.handle = 'list';
        this.organizationService.title = '组织列表';
    }
}
src/app/routes/systems/organization/organization-config-unit/organization-config-unit.component.html
New file
@@ -0,0 +1,42 @@
<form nz-form>
    <ng-container *ngIf="!!osuTowDimList.length; else elseTemplate">
            <div  *ngFor= "let osuList of osuTowDimList" nz-form-item nz-row>
                    <ng-container *ngFor="let osu of osuList">
                        <div  nz-form-label nz-col [nzSm]="3">
                                <label>{{osu.sensor.description}}</label>
                        </div>
                        <div nz-form-control nz-col [nzSm]="4">
                            <nz-select [nzMode]="'default'" nzAllowClear
                            nzPlaceHolder="{{osu.sensor.unit}}(默认单位)" [(ngModel)]="osu.sensorUnitId" name="sensorUnitId">
                                <nz-option
                                    *ngFor="let option of sensorUnitMap[osu.sensor.id]"
                                    [nzLabel]="option.name"
                                    [nzValue]="option.id">
                                    </nz-option>
                            </nz-select>
                        </div>
                    </ng-container>
                </div>
    </ng-container>
    <ng-template #elseTemplate>
            <div nz-form-item nz-row>
                    <div  nz-form-label nz-col [nzSm]="24" style="text-align: center;">
                            <h2>该组织下没有传感器或者没有可选单位</h2>
                    </div>
                </div>
    </ng-template>
</form>
<footer-toolbar>
        <label>组织名称:</label>
        <span [ngStyle]="{'font-size': '16px','font-weight': 'bold','margin-right':'30px'}">{{ organization.name }}</span>
        <button nz-button type="button" (click)="backToList()">返回</button>
        <button nz-button [nzType]="'primary'" (click)="save()" [nzLoading]="isSaving">
            <span>
                保存
                <span *ngIf="isSaving">中</span>
            </span>
        </button>
</footer-toolbar>
src/app/routes/systems/organization/organization-config-unit/organization-config-unit.component.ts
New file
@@ -0,0 +1,83 @@
import { Component, OnInit } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { OrganizationService } from '@business/services/http/organization.service';
import { Organization, OrganizationSensorUnit } from '@business/entity/data';
import { ResultBean } from '@business/entity/grid';
import { NzMessageService } from 'ng-zorro-antd';
@Component({
  selector: 'app-organization-config-unit',
  templateUrl: './organization-config-unit.component.html',
})
export class OrganizationConfigUnitComponent implements OnInit {
    public organization: Organization;
    constructor(
        private http: _HttpClient,
        private organizationService: OrganizationService,
        public msgSrv: NzMessageService
    ) { }
    public osuTowDimList: OrganizationSensorUnit[][] = [];
    public originalOsuList: OrganizationSensorUnit[] = [];
    public osuList: OrganizationSensorUnit[];
    public sensorUnitMap;
    ngOnInit() {
        this.organization = this.organizationService.data;
        this.sensorUnitMap = <OrganizationSensorUnit []> this.organizationService.config.resultBean.data.sensorUnitMap;
        const osuList = <OrganizationSensorUnit []> this.organizationService.config.resultBean.data.osuList;
        this.osuList = osuList;
        // 保存原始数据
        osuList.forEach(item => {
            const osu = {};
            Object.assign(osu, item);
            this.originalOsuList.push(osu);
        });
        if ( !!osuList ) {
            for (let index = 0 ; index < osuList.length; index += 3 ) {
                const osuListTemp: OrganizationSensorUnit[] = [];
                for (let n = 0 ; n < 3; n++ ) {
                        const nTemp =  index + n;
                        if (nTemp < osuList.length ) {
                            osuListTemp.push(osuList[nTemp]);
                        }
                }
                this.osuTowDimList.push(osuListTemp);
            }
        }
        console.log(this.osuTowDimList);
    }
    public isSaving = false;
    save() {
        this.isSaving = true;
        const modifyList = [];
        // 寻找发生修改的
        this.osuList.forEach(
            item => {
                const osu = this.originalOsuList.find(
                    su => {
                        return su.sensor.id === item.sensor.id &&
                        su.sensorUnitId !== item.sensorUnitId;
                    }
                );
                if (!!osu) {
                    modifyList.push(item);
                }
            }
        );
        if (!!modifyList.length) {
            this.http.post('org-sunit/saves', modifyList).subscribe(
                (res: ResultBean<any>) => {
                    if (res.code > 0 ) {
                        this.isSaving = false;
                        this.msgSrv.success(this.organization.name + ' 配置成功!');
                        // this.backToList();
                    }
                }
            );
        }
    }
    backToList() {
        this.organizationService.handle = 'list';
        this.organizationService.title = '组织列表';
      }
}
src/app/routes/systems/organization/organization-config/organization-config.component.ts
@@ -57,7 +57,7 @@
        alarmConfig = this.alarmConfigService.generateAlarmConfig(pageBean.data);
      } else {
        // 防止 新增 传感器
        alarmConfig = this.alarmConfigService.generateAlarmConfig(pageBean.data, resultBean.data);
        alarmConfig = this.alarmConfigService.generateAlarmConfig(pageBean.data, <AlarmConfig>resultBean.data);
      }
      const alarmConfigValue = alarmConfig.value;
@@ -183,7 +183,7 @@
           result => {
              if (result != null && result.code === 1) {
                 this.msgSrv.success(this.organization.name + ' 配置成功!');
                 this.backToList();
                //  this.backToList();
              }
           }
       );
src/app/routes/systems/organization/organization-list/organization-list.component.html
@@ -51,8 +51,6 @@
                        </span>
                    </td>
                    <td nz-td>
                            <a (click)="config(row)">配置</a>
                            <span nz-table-divider></span>
                            <a (click)="addOrModify(row)">编辑</a>
                            <span nz-table-divider></span>
                              <nz-popconfirm [nzTitle]="'确定要删除该'+grid.title+'吗?'" [nzOkText]="'Yes'" [nzCancelText]="'No'" (nzOnConfirm)="delete(row.id)" >
@@ -60,6 +58,23 @@
                              </nz-popconfirm>
                            <span nz-table-divider></span>
                            <a [routerLink]="['/systems/registration']" (click)="registration(row)">注册码</a>
                            <span nz-table-divider></span>
                            <nz-dropdown>
                                <a class="ant-dropdown-link" nz-dropdown>
                                  更多 <i class="anticon anticon-down"></i>
                                </a>
                                <ul nz-menu>
                                  <li nz-menu-item>
                                        <a (click)="configAlarm(row)">配置三级警报</a>
                                  </li>
                                  <li nz-menu-item>
                                        <a (click)="configScreenLayout(row)">配置大屏布局</a>
                                  </li>
                                  <li nz-menu-item>
                                        <a (click)="configShowUnit(row)">配置显示单位</a>
                                  </li>
                                </ul>
                              </nz-dropdown>
                     </td>
                </tr>
              </tbody>
src/app/routes/systems/organization/organization-list/organization-list.component.ts
@@ -1,11 +1,11 @@
import { AlarmConfigService } from '@business/services/http/alarm-config.service';
import { SensorsService } from '@business/services/http/sensors.service';
import { Router } from '@angular/router';
import { ModalHelper } from '@delon/theme';
import { ModalHelper, _HttpClient } from '@delon/theme';
import { NzModalService, NzMessageService } from 'ng-zorro-antd';
import { OrganizationService } from '@business/services/http/organization.service';
import { Grid, Column, PageBean } from '@business/entity/grid';
import { Organization } from '@business/entity/data';
import { Grid, Column, PageBean, ResultBean } from '@business/entity/grid';
import { Organization, OrganizationSensorUnit } from '@business/entity/data';
import { Component, OnInit } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Types } from '@business/enum/types.enum';
@@ -95,6 +95,7 @@
    private router: Router,
    private sensorsService: SensorsService,
    private alarmConfigService: AlarmConfigService,
    private http: _HttpClient
  ) {}
  ngOnInit() {
@@ -210,7 +211,7 @@
     }
     this.load();
  }
  config(row) {
   configAlarm(row) {
        // 延时加载避免ExpressionChangedAfterItHasBeenCheckedError
        setTimeout(() => {
          this.grid.loading = true;
@@ -219,15 +220,49 @@
      this.sensorsService.getPagingList({pageIndex: 0, pageSize: 0}, null),
      this.alarmConfigService.getByOid( row.id )
    ).subscribe(([pageBean, resultBean]) => {
      console.log(pageBean);
      this.grid.loading = false;
      this.organizationService.handle = 'config' ;
      this.organizationService.data = row;
      this.organizationService.config = {pageBean, resultBean};
      this.organizationService.title = '组织配置';
      this.organizationService.title = '配置三级警报';
    });
  }
    configScreenLayout(row) {
              // 延时加载避免ExpressionChangedAfterItHasBeenCheckedError
              setTimeout(() => {
                this.grid.loading = true;
                }, 1);
              this.http.get('org-layout/rtd-config', {orgId: row.id}).subscribe(
                   (res: ResultBean<any>) => {
                      if ( res.code > 0 ) {
                        this.grid.loading = false;
                        this.organizationService.handle = 'screen' ;
                        this.organizationService.data = row;
                        this.organizationService.config['resultBean'] = res;
                        console.log(res);
                        this.organizationService.title = '配置大屏布局';
                      }
                   }
              );
    }
    configShowUnit(row) {
        // 延时加载避免ExpressionChangedAfterItHasBeenCheckedError
        setTimeout(() => {
          this.grid.loading = true;
          }, 1);
        this.http.get('org-sunit/gets-byoid', {orgId: row.id}).subscribe(
             (res: ResultBean<any>) => {
                if ( res.code > 0 ) {
                  this.grid.loading = false;
                  this.organizationService.handle = 'unit' ;
                  this.organizationService.data = row;
                  this.organizationService.config['resultBean'] = res;
                  console.log(res);
                  this.organizationService.title = '配置显示单位';
                }
             }
        );
    }
  registration(row) {
      sessionStorage.setItem('organization', JSON.stringify(row));
  }
src/app/routes/systems/organization/organization.component.html
@@ -5,6 +5,8 @@
        <ng-template #body>
            <app-organization-list *ngIf="organizationService.handle=='list'"></app-organization-list>
            <app-organization-config *ngIf="organizationService.handle=='config'"></app-organization-config>
            <app-organization-config-screen *ngIf="organizationService.handle=='screen'"></app-organization-config-screen>
            <app-organization-config-unit *ngIf="organizationService.handle=='unit'"></app-organization-config-unit>
        </ng-template>
</nz-card>
  
src/app/routes/systems/systems.module.ts
@@ -18,6 +18,8 @@
import { RegistrationComponent } from './registration/registration.component';
import { SensorsService } from '@business/services/http/sensors.service';
import { BusinessModule } from '@business/business.module';
import { OrganizationConfigScreenComponent } from './organization/organization-config-screen/organization-config-screen.component';
import { OrganizationConfigUnitComponent } from './organization/organization-config-unit/organization-config-unit.component';
const routes: Routes = [
  {
@@ -48,6 +50,8 @@
    OrganizationComponent,
    OrganizationConfigComponent,
    OrganizationListComponent,
    OrganizationConfigScreenComponent,
    OrganizationConfigUnitComponent,
    RegistrationComponent
  ],
  providers: [ToolsService, SensorsService, OrganizationService, _HttpClient, FormBuilder, AreacodeService],