e4cadb22394599a2f508078ff5b1e8889944475e..09e95982e57f1a26be4249d11091a935544df684
2018-01-16 fengxiang
Merge branch 'develop' of http://blit.7drlb.com:8888/r/screen-frontend into...
09e959 diff | tree
2018-01-16 fengxiang
组织配置
928d55 diff | tree
2018-01-12 fengxiang
组织配置
f0b742 diff | tree
3 files added
14 files modified
588 ■■■■ changed files
src/app/business/business.module.ts 20 ●●●●● patch | view | raw | blame | history
src/app/business/entity/data.ts 31 ●●●●● patch | view | raw | blame | history
src/app/business/entity/grid.ts 5 ●●●●● patch | view | raw | blame | history
src/app/business/enum/patterns.enum.ts 3 ●●●●● patch | view | raw | blame | history
src/app/business/enum/types.enum.ts 4 ●●●● patch | view | raw | blame | history
src/app/business/services/http/alarm-config.service.ts 54 ●●●●● patch | view | raw | blame | history
src/app/business/services/http/areacode.service.ts 5 ●●●●● patch | view | raw | blame | history
src/app/business/services/http/organization.service.ts 6 ●●●● patch | view | raw | blame | history
src/app/business/services/http/sensors.service.ts 4 ●●●● patch | view | raw | blame | history
src/app/routes/devices/version/version-sensor-config/version-sensor-config.component.html 2 ●●● patch | view | raw | blame | history
src/app/routes/routes.module.ts 2 ●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-config/organization-config.component.html 163 ●●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-config/organization-config.component.ts 257 ●●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-list/organization-list.component.ts 20 ●●●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization.component.html 4 ●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization.component.ts 1 ●●●● patch | view | raw | blame | history
src/app/routes/systems/systems.module.ts 7 ●●●● patch | view | raw | blame | history
src/app/business/business.module.ts
New file
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
// Statics
import 'rxjs/add/observable/throw';
// Operators
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/filter';
@NgModule({
  imports: [
    CommonModule
  ]
})
export class BusinessModule { }
src/app/business/entity/data.ts
@@ -1,4 +1,5 @@
import { Column } from '@business/entity/grid';
import { AlarmStyle } from '@business/enum/types.enum';
export interface AreaNames {
@@ -61,3 +62,33 @@
    areaNames?: AreaNames|any ;
    organization?: Organization;
  }
 // 报警配置
 export interface AlarmConfig {
  id?: number;
  organizationId?: number;
  createTime?: number;
  updateTime?: number;
  value: AlarmConfigValue;
}
export interface AlarmConfigValue {
  alarmMode: AlarmMode;
  alarmLevels:{[key: string]:AlarmSensorLevel};
}
export interface AlarmSensorLevel {
  enable: boolean|any [];
  increment: number []|any[];
  degression: number []|any [];
}
export interface AlarmMode {
  enable: boolean|any[];
  level1: AlarmStyle[]|any[];
  level2: AlarmStyle[]|any[];
  level3: AlarmStyle[]|any[];
}
src/app/business/entity/grid.ts
@@ -111,3 +111,8 @@
        return arr;
    }
}
export interface ResultBean<T>{
  code?: number;
  data?: T;
  message?: string;
}
src/app/business/enum/patterns.enum.ts
New file
@@ -0,0 +1,3 @@
export enum patterns{
    num = '\\d+(\\.\\d+)?'
}
src/app/business/enum/types.enum.ts
@@ -1,3 +1,7 @@
export enum Types {
    Date, Json
}
export enum AlarmStyle {
    //微信,邮件,短信,语音
    weixin='weixin',email='email',sms='sms',voice='voice'
}
src/app/business/services/http/alarm-config.service.ts
New file
@@ -0,0 +1,54 @@
import { _HttpClient } from '@delon/theme';
import { Injectable } from '@angular/core';
import { environment } from '@env/environment';
import { Observable } from 'rxjs/Observable';
import { ResultBean } from '@business/entity/grid';
import { AlarmConfig, AlarmConfigValue,AlarmSensorLevel, AlarmMode } from '@business/entity/data';
@Injectable()
export class AlarmConfigService {
  private urls = {
    getByOid: environment.SERVER_BASH_URL + 'alarm-config/get-by-oid',
    save: environment.SERVER_BASH_URL + '/alarm-config/add-or-modify',
  };
  constructor( private http: _HttpClient) {
  }
  public generateAlarmConfig(sensors: {key:string} [],alarmConfig?: AlarmConfig): AlarmConfig{
        const _alarmConfig : AlarmConfig = alarmConfig==null || alarmConfig.value == null ? {value:{
            alarmLevels:null,
            alarmMode:null
        }}: alarmConfig;
        let alarmLevels = _alarmConfig.value.alarmLevels;
        alarmLevels = alarmLevels ==null ?{} :alarmLevels;
        sensors.forEach(
          sensor => {
                const key = sensor.key;
                alarmLevels[key]  =
                alarmLevels[key] == null ?
                {
                  enable: false,
                  increment: [0,0,0],
                  degression:  [0,0,0]
                } : alarmLevels[key];
             }
         );
         _alarmConfig.value.alarmLevels = alarmLevels;
         //报警方式
         let alarmMode = _alarmConfig.value.alarmMode;
         alarmMode = alarmMode == null ? {
          enable: false,
          level1: null,
          level2: null,
          level3: null
        } : alarmMode;
        _alarmConfig.value.alarmMode = alarmMode;
        return _alarmConfig;
  }
  public getByOid(oid:number):Observable<ResultBean<AlarmConfig>>{
     return this.http.get(this.urls.getByOid,{organizationId:oid});
  }
  public save(data: any): Observable<ResultBean<any>> {
    return this.http.post(this.urls.save, data);
  }
}
src/app/business/services/http/areacode.service.ts
@@ -1,10 +1,5 @@
import { Injectable } from '@angular/core';
import { _HttpClient } from '@delon/theme/services/http/http.client';
// Statics
import 'rxjs/add/observable/throw';
// Operators
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import { environment } from 'environments/environment';
src/app/business/services/http/organization.service.ts
@@ -1,4 +1,4 @@
import { Organization } from '@business/entity/data';
import { Organization, AlarmConfig } from '@business/entity/data';
import { ExampleService } from '@business/services/util/example.service';
import { _HttpClient } from '@delon/theme';
import { environment } from 'environments/environment';
@@ -6,13 +6,13 @@
import { Injectable } from '@angular/core';
import { equal } from 'assert';
import { Observable } from 'rxjs/Observable';
import {  PageBean } from '@business/entity/grid';
import {  PageBean, ResultBean } from '@business/entity/grid';
@Injectable()
export class OrganizationService {
  handle: 'list'|'config' = 'list';
  config: {pageBean: PageBean,resultBean: ResultBean<AlarmConfig>};
  data: Organization;
  title: '组织列表'|'组织配置' = '组织列表';
  private urls = {
src/app/business/services/http/sensors.service.ts
@@ -10,7 +10,7 @@
@Injectable()
export class SensorsService {
  private urls = {
    edit: environment.SERVER_BASH_URL + '/sensor/page-list',
    list: environment.SERVER_BASH_URL + '/sensor/page-list',
    save: environment.SERVER_BASH_URL + '/sensor/add-or-modify',
    delete: environment.SERVER_BASH_URL + '/sensor/delete-by-ids'
};
@@ -27,7 +27,7 @@
  }
  const param: PageBean = {pageSize: page.pageSize, pageIndex: page.pageIndex, 
      queryParams: example.getSqlParam(), orderByClause: orderByClause};
      return this.http.get(this.urls.edit, param);
      return this.http.get(this.urls.list, param);
}
public save(data: any): Observable<any> {
      return this.http.post(this.urls.save, data);
src/app/routes/devices/version/version-sensor-config/version-sensor-config.component.html
@@ -2,7 +2,7 @@
  <div class="modal-title">配置传感器</div>
</div>
<nz-table #nzTable [nzDataSource]="grid.data"  [nzPageSize]="8"
  [nzLoading]="grid.loading" [nzShowTotal]="true" >
  [nzLoading]="grid.loading" [nzShowTotal]="true">
  <thead nz-thead>
    <tr>
      <th nz-th [nzCheckbox]="true">
src/app/routes/routes.module.ts
@@ -29,7 +29,7 @@
        DashboardV1Component,
        DashboardAnalysisComponent,
        DashboardMonitorComponent,
        DashboardWorkplaceComponent,
        DashboardWorkplaceComponent
    ],
    providers: [
        _HttpClient,
src/app/routes/systems/organization/organization-config/organization-config.component.html
@@ -1,67 +1,104 @@
<form>
    <p>111111111111111111111111111<br/>
      222222222222222222222222222<br/>
      333333333333333333333333333<br/>
   </p>
   <p>111111111111111111111111111<br/>
       222222222222222222222222222<br/>
       333333333333333333333333333<br/>
    </p>
    <p>111111111111111111111111111<br/>
      222222222222222222222222222<br/>
      333333333333333333333333333<br/>
   </p>
   <p>111111111111111111111111111<br/>
       222222222222222222222222222<br/>
       333333333333333333333333333<br/>
    </p>
    <p>111111111111111111111111111<br/>
      222222222222222222222222222<br/>
      333333333333333333333333333<br/>
   </p>
   <p>111111111111111111111111111<br/>
       222222222222222222222222222<br/>
       333333333333333333333333333<br/>
    </p>
    <p>111111111111111111111111111<br/>
      222222222222222222222222222<br/>
      333333333333333333333333333<br/>
   </p>
   <p>111111111111111111111111111<br/>
       222222222222222222222222222<br/>
       333333333333333333333333333<br/>
    </p>
    <p>111111111111111111111111111<br/>
      222222222222222222222222222<br/>
      333333333333333333333333333<br/>
   </p>
   <p>111111111111111111111111111<br/>
       222222222222222222222222222<br/>
       333333333333333333333333333<br/>
    </p>
    <p>111111111111111111111111111<br/>
      222222222222222222222222222<br/>
      333333333333333333333333333<br/>
   </p>
   <p>111111111111111111111111111<br/>
       222222222222222222222222222<br/>
       333333333333333333333333333<br/>
    </p>
    <p>111111111111111111111111111<br/>
      222222222222222222222222222<br/>
      333333333333333333333333333<br/>
   </p>
   <p>111111111111111111111111111<br/>
       222222222222222222222222222<br/>
       333333333333333333333333333<br/>
    </p>
   <footer-toolbar errorCollect>
<form nz-form [formGroup]="validateForm" (ngSubmit)="save($event,validateForm.value,validateForm.valid)" [nzLayout]="'vertical'"
    #f="ngForm">
    <nz-card [nzBordered]="false" nzTitle="报警阀值(注意,只有部分选项有 反向三级 数值,没有可不填)">
        <nz-table #nzTable [nzDataSource]="grid.data" [nzPageSize]="10" [nzLoading]="grid.loading" [nzShowTotal]="true">
            <thead nz-thead>
                <tr>
                    <th nz-th [nzCheckbox]="true">
                        <label nz-checkbox formControlName="_allChecked" [nzIndeterminate]="indeterminate" (ngModelChange)="checkAll($event)"></label>
                    </th>
                    <th nz-th>
                        传感器名称(单位)
                    </th>
                    <th nz-th>
                        一级
                    </th>
                    <th nz-th>
                        二级
                    </th>
                    <th nz-th>
                        三级
                    </th>
                    <th nz-th>
                        反向一级
                    </th>
                    <th nz-th>
                        反向二级
                    </th>
                    <th nz-th>
                        反向三级
                    </th>
                </tr>
            </thead>
            <tbody formGroupName="alarmLevels" nz-tbody>
                <tr nz-tbody-tr *ngFor="let row of nzTable.data" formGroupName="{{row.key}}">
                    <td nz-td [nzCheckbox]="true">
                        <label nz-checkbox formControlName="enable"></label>
                    </td>
                    <td>
                        <span>
                            {{ row.name }}({{ row.unit }})
                        </span>
                    </td>
                    <td formArrayName="increment" *ngFor="let in of validateForm.get('alarmLevels.'+row.key+'.increment').controls; index as i">
                            <div nz-form-item>
                                <div nz-form-control nzHasFeedback>
                                    <nz-input [formControlName]="i" maxlength="20" nzDisabled="{{ !f.value['alarmLevels'][row.key]['enable'] }}"></nz-input>
                                </div>
                            </div>
                    </td>
                    <td formArrayName="degression" *ngFor="let in of validateForm.get('alarmLevels.'+row.key+'.degression').controls; index as i">
                        <div nz-form-item>
                            <div nz-form-control nzHasFeedback>
                                <nz-input [formControlName]="i" maxlength="20" nzDisabled="{{ !f.value['alarmLevels'][row.key]['enable'] }}"></nz-input>
                            </div>
                        </div>
                   </td>
                </tr>
            </tbody>
        </nz-table>
    </nz-card>
    <div [ngStyle]="{'background-color':'#f5f7fa','width':'110%','left':'-5%','height':'20px','position':'relative'}"></div>
    <nz-card [nzBordered]="false" nzTitle="报警方式"  formGroupName="alarmMode">
            <label nz-checkbox formControlName="enable">
                <span>启用报警</span>
            </label>
            <div [ngStyle]="{'margin-left': '20%'}">
                <br/>
                <br/>
                <br/>
                  <div *ngFor="let i of [1,2,3]" nz-form-item nz-row class="mb-sm">
                    <div nz-form-label nz-col [nzSm]="3" [nzXs]="24">
                        <span [ngSwitch]="i">
                            <label *ngSwitchCase="1">一级报警方式:</label>
                            <label *ngSwitchCase="2">二级报警方式:</label>
                            <label *ngSwitchCase="3">三级报警方式:</label>
                        </span>
                    </div>
                    <div nz-form-control nz-col [nzSpan]="12" nzHasFeedback>
                        <nz-select formControlName="{{ 'level'+i }}" [nzMode]="'multiple'" [nzPlaceHolder]="'选择 报警方式'" [nzNotFoundContent]="'无法找到'"
                            nzDisabled="{{ !f.value['alarmMode']['enable'] }}">
                            <nz-option *ngFor="let option of alarmModes" [nzLabel]="option.label" [nzValue]="option.value" [nzDisabled]="option.disabled">
                            </nz-option>
                        </nz-select>
                    </div>
                    <br/>
                    <br/>
                    <br/>
                </div>
            </div>
        </nz-card>
    <footer-toolbar errorCollect>
        <span [ngStyle]="{'color':'red','width':'300px','margin-right':'40px'}">{{ errorMessage }}</span>
        <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'" [nzLoading]="isSaving">
          <span>
            保存
            <span *ngIf="isSaving">中</span>
          </span>
            <span>
                保存
                <span *ngIf="isSaving">中</span>
            </span>
        </button>
    </footer-toolbar>
    </footer-toolbar>
</form>
src/app/routes/systems/organization/organization-config/organization-config.component.ts
@@ -1,24 +1,265 @@
import { Organization } from '@business/entity/data';
import { Component, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { filter } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';
import { FormGroup, FormBuilder, FormControl, Validators, FormArray } from '@angular/forms';
import { SensorsService } from '@business/services/http/sensors.service';
import { Grid, PageBean } from '@business/entity/grid';
import { Organization, AlarmConfig, AlarmSensorLevel, AlarmConfigValue } from '@business/entity/data';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { OrganizationService } from '@business/services/http/organization.service';
import { _HttpClient } from '@delon/theme';
import { AlarmConfigService } from '@business/services/http/alarm-config.service';
import { AlarmStyle } from '@business/enum/types.enum';
import { patterns } from '@business/enum/patterns.enum';
@Component({
  selector: 'app-organization-config',
  templateUrl: './organization-config.component.html',
  styles: []
  styles: [],
  providers: [AlarmConfigService]
})
export class OrganizationConfigComponent implements OnInit {
  organization: Organization;
export class OrganizationConfigComponent implements OnInit, OnDestroy {
  ngOnDestroy(): void {
    this.backToList();
  }
  private organization: Organization;
  grid: Grid<object> = new Grid<object>(null);
  validateForm: FormGroup;
  constructor(
    private organizationService: OrganizationService
  ) {
      console.log(this.organizationService.data);
    private organizationService: OrganizationService,
    private sensorsService: SensorsService,
    private alarmConfigService: AlarmConfigService,
    private formBuilder: FormBuilder,
    private http: _HttpClient,
    public msgSrv: NzMessageService
  ) {
    this.organization = this.organizationService.data;
  }
  ngOnInit() {
    this.load();
  }
  load(reload: boolean = false) {
    if (reload) {
      this.grid.pageIndex = 1;
    }
    // 延时加载避免ExpressionChangedAfterItHasBeenCheckedError
    setTimeout(() => {
      this.grid.loading = true;
     }, 1);
    let pageBean = this.organizationService.config.pageBean;
    let resultBean = this.organizationService.config.resultBean;
    resultBean = resultBean == null ? {} : resultBean;
    if (pageBean != null && pageBean.data != null) {
      this.grid.initData(pageBean);
      let alarmConfig: AlarmConfig = null;
      if (resultBean == null || resultBean.data == null) {
        alarmConfig = this.alarmConfigService.generateAlarmConfig(pageBean.data);
      } else {
        // 防止 新增 传感器
        alarmConfig = this.alarmConfigService.generateAlarmConfig(pageBean.data, resultBean.data);
      }
      const alarmConfigValue = alarmConfig.value;
      const alarmLevels = alarmConfigValue.alarmLevels;
      let alarmLevelsGroupsConfig = {};
      Object.keys(alarmLevels).forEach(key => {
        let increment = alarmLevels[key].increment;
        increment = increment == null || increment.length != 3 ? [0, 0, 0] : increment;
        const incrementArray = this.formBuilder.array([
          [increment[0], Validators.pattern(patterns.num)],
          [increment[1], Validators.pattern(patterns.num)],
          [increment[2], Validators.pattern(patterns.num)]
        ]);
        let degression = alarmLevels[key].degression;
        degression = degression == null || degression.length != 3 ? [0, 0, 0] : degression;
        const degressionArray =
          this.formBuilder.array([
            [degression[0], Validators.pattern(patterns.num)],
            [degression[1], Validators.pattern(patterns.num)],
            [degression[2], Validators.pattern(patterns.num)]
          ]);
        const alarmSensorGroup = this.formBuilder.group(
          {
            enable: [alarmLevels[key].enable],
            increment: incrementArray,
            degression: degressionArray,
          }, { validator: this.alarmLevelValidator }
        );
        alarmSensorGroup.get('enable').valueChanges.subscribe(
          (value: any) => {
            if (this._allCheckTriggers <= 0) {
              this.refreshIndeterminate();
            } else {
              this._allCheckTriggers--;
            }
          }
        );
        alarmLevelsGroupsConfig[key] = alarmSensorGroup;
      });
      this.alarmModes.push(
        { label: '邮件', value: AlarmStyle.email, disabled: false },
        { label: '短信', value: AlarmStyle.sms, disabled: false },
        { label: '语音', value: AlarmStyle.voice, disabled: false },
        { label: '微信', value: AlarmStyle.weixin, disabled: false }
      );
      const alarmMode = alarmConfigValue.alarmMode;
      this.validateForm = this.formBuilder.group({
        alarmLevels: this.formBuilder.group(alarmLevelsGroupsConfig),
        alarmMode: this.formBuilder.group(
          {
            enable: [alarmMode.enable],
            level1: [alarmMode.level1],
            level2: [alarmMode.level2],
            level3: [alarmMode.level3]
          }
        ),
        '_id':alarmConfig.id,
        '_allChecked': []
      });
      this.validateForm.statusChanges.subscribe(
         item => {
             this.setErrorMessage();
         }
      )
      this.refreshIndeterminate();
    }
        // 延时加载避免ExpressionChangedAfterItHasBeenCheckedError
        setTimeout(() => {
          this.grid.loading = false;
         }, 1);
  }
  alarmModes: { label: string, value: AlarmStyle, disabled: boolean }[] = [];
  backToList() {
    this.organizationService.handle = 'list';
    this.organizationService.title = '组织列表';
  }
  indeterminate: boolean;
  checkAll(param) {
    const keys = this.grid.data.map(
      item => {
        return item['key'];
      }
    );
    this._allCheckTriggers = 0;
    keys.forEach(
      (key: string) => {
        this._allCheckTriggers++;
        this.validateForm.get('alarmLevels.' + key + '.enable').setValue(param);
      }
    );
    this.refreshIndeterminate();
  }
  private _allCheckTriggers: number = 0;
  refreshIndeterminate() {
    const keys = this.grid.data.map(
      item => {
        return item['key'];
      }
    );
    const allChecked = keys.every(key => this.validateForm.get('alarmLevels.' + key + '.enable').value);
    const allUnChecked = keys.every(key => !this.validateForm.get('alarmLevels.' + key + '.enable').value);
    this.indeterminate = (!allChecked) && (!allUnChecked);
  }
  save($event, value, valid) {
    $event.preventDefault();
    if (valid) {
       const data:AlarmConfig = {
         id:value._id,
         organizationId:this.organization.id,
         value:value
       }
       this.alarmConfigService.save(data).subscribe(
           result => {
              if(result!=null&&result.code==1){
                 this.msgSrv.success(this.organization.name+' 配置成功!');
                 this.backToList();
              }
           }
       );
    }
  }
  setErrorMessage(){
    this.errorMessage = '';
    const errObj = this.getLastError(this.validateForm);
    if(errObj!=null&&Object.keys(errObj).length>0){
     if(errObj['increment']){
      this.errorMessage = '一级 二级 三级 依次递增';
     } else if(errObj['degression']){
      this.errorMessage = '反向一级 反向二级 反向三级 依次递减';
     } else if(errObj['pattern']!=null&&errObj['pattern']['requiredPattern'] == '^'+patterns.num.toString()+'$'){
      this.errorMessage = '阀值只能为数字';
     }
    }
}
  errorMessage:string = '';
  private alarmLevelValidator = (control: FormControl): { [s: string]: boolean } => {
    let result = {};
      const i0 = control.get("increment.0");
      const i1 = control.get("increment.1");
      const i2 = control.get("increment.2");
      if ((i0.value != 0 || i1.value != 0 || i2.value != 0)&&(i0.value >= i1.value||i1.value >= i2.value)) {
        i0.setErrors({ increment: true });
        i0.markAsDirty();
        i1.setErrors({ increment: true });
        i1.markAsDirty();
        i2.setErrors({ increment: true });
        i2.markAsDirty();
        result["increment"] = true;
      }else{
        if(i0.hasError('increment')&&Object.keys(i0.errors).length==1){
          i0.setErrors(null);
        }
        if(i1.hasError('increment')&&Object.keys(i1.errors).length==1){
          i1.setErrors(null);
        }
        if(i2.hasError('increment')&&Object.keys(i2.errors).length==1){
          i2.setErrors(null);
        }
      }
      const d0 = control.get("degression.0");
      const d1 = control.get("degression.1");
      const d2 = control.get("degression.2");
      if ((d0.value != 0 || d1.value != 0 || d2.value != 0)&&(d1.value >= d0.value||d2.value >= d1.value)) {
        d0.setErrors({ degression: true });
        d0.markAsDirty();
        d1.setErrors({ degression: true });
        d1.markAsDirty();
        d2.setErrors({ degression: true });
        d2.markAsDirty();
        result["degression"] = true;
      }else{
        if(d0.hasError('degression')&&Object.keys(d0.errors).length==1){
          d0.setErrors(null);
        }
        if(d1.hasError('degression')&&Object.keys(d1.errors).length==1){
          d1.setErrors(null);
        }
        if(d2.hasError('degression')&&Object.keys(d2.errors).length==1){
          d2.setErrors(null);
        }
      }
      return Object.keys(result).length == 0?null:result;
  };
   getLastError(control:FormGroup|FormArray){
         if(control.errors!=null){
             return control.errors;
         }else{
           const controls =   Object.values(control.controls);
           for(let i = controls.length-1;i>=0;i--){
                const c = controls[i];
                if(c.errors!=null){
                  return c.errors;
                }else if(c instanceof FormArray||c instanceof FormGroup){
                      const result = this.getLastError(c);
                      if(result != null) {
                         return result;
                      }
                }
           }
         }
   }
}
src/app/routes/systems/organization/organization-list/organization-list.component.ts
@@ -1,3 +1,5 @@
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 { NzModalService, NzMessageService } from 'ng-zorro-antd';
@@ -8,11 +10,13 @@
import { Subject } from 'rxjs/Subject';
import { Types } from '@business/enum/types.enum';
import { OrganizationEditComponent } from 'app/routes/systems/organization/organization-edit/organization-edit.component';
import { zip } from 'rxjs/observable/zip';
@Component({
  selector: 'app-organization-list',
  templateUrl: './organization-list.component.html',
  styles: []
  styles: [],
  providers: [AlarmConfigService]
})
export class OrganizationListComponent implements OnInit {
  private organization: Organization;
@@ -89,6 +93,8 @@
    public msgSrv: NzMessageService,
    private modalHelper: ModalHelper,
    private router: Router,
    private sensorsService:SensorsService,
    private alarmConfigService:AlarmConfigService,
  ) {}
  ngOnInit() {
@@ -205,8 +211,20 @@
     this.load();
  }
  config(row) {
        // 延时加载避免ExpressionChangedAfterItHasBeenCheckedError
        setTimeout(() => {
          this.grid.loading = true;
         }, 1);
    zip(
      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 = '组织配置';
    });
  }
}
src/app/routes/systems/organization/organization.component.html
@@ -1,4 +1,6 @@
<pro-header [title]="organizationService.title"></pro-header>
<pro-header [title]="organizationService.title">
</pro-header>
<nz-card [nzBordered]="false" [nzNoHovering]="true">
        <ng-template #body>
            <app-organization-list *ngIf="organizationService.handle=='list'"></app-organization-list>
src/app/routes/systems/organization/organization.component.ts
@@ -10,7 +10,6 @@
})
export class OrganizationComponent implements OnInit {
  ngOnInit(): void {
  }
  constructor(
    private organizationService: OrganizationService
src/app/routes/systems/systems.module.ts
@@ -15,6 +15,8 @@
import { AreacodeService } from '@business/services/http/areacode.service';
import { OrganizationConfigComponent } from './organization/organization-config/organization-config.component';
import { OrganizationListComponent } from './organization/organization-list/organization-list.component';
import { SensorsService } from '@business/services/http/sensors.service';
import { BusinessModule } from '@business/business.module';
const routes: Routes = [
  {
@@ -34,7 +36,8 @@
    PipeModule,
    CommonModule,
    SharedModule,
    RouterModule.forChild(routes)
    RouterModule.forChild(routes),
    BusinessModule
  ],
  declarations: [
    ...COMPONENTS_NOROUNT,
@@ -44,7 +47,7 @@
    OrganizationConfigComponent,
    OrganizationListComponent
  ],
  providers: [ToolsService, OrganizationService, _HttpClient, FormBuilder, AreacodeService],
  providers: [ToolsService, SensorsService,OrganizationService, _HttpClient, FormBuilder, AreacodeService],
  entryComponents: COMPONENTS_NOROUNT
})
export class SystemsModule { }