沈斌
2018-07-13 aefa2dc89b44f21453e9e3bf19c90d41b1c83e8e
updates
3 files added
4 files modified
1045 ■■■■■ changed files
src/app/routes/home-page/home-page/home-page.component.ts 8 ●●●● patch | view | raw | blame | history
src/app/routes/pollution/management/management.component.html 2 ●●● patch | view | raw | blame | history
src/app/routes/reports/query2/query.component.html 188 ●●●●● patch | view | raw | blame | history
src/app/routes/reports/query2/query.component.less 24 ●●●●● patch | view | raw | blame | history
src/app/routes/reports/query2/query.component.ts 819 ●●●●● patch | view | raw | blame | history
src/app/routes/reports/query2/query2.component.html 2 ●●● patch | view | raw | blame | history
src/app/routes/statistics/monitorpoint/monitorpoint.component.html 2 ●●● patch | view | raw | blame | history
src/app/routes/home-page/home-page/home-page.component.ts
@@ -56,7 +56,7 @@
        }
    );
  }
  public aqiChartOption = {};
  public aqiEchartsIntance;
  public aqiChartLoading = false;
@@ -66,11 +66,11 @@
  public meteChartOption = {};
  public meteEchartsIntance;
  public meteChartLoading = false;
  private onMeteChartInit(e): void {
  public onMeteChartInit(e): void {
      this.meteEchartsIntance = e;
  }
  private reloadAqiChart(): void {
    // const  timeList = this.grid.columns.map(item => item.text);
    // const  timeList = this.grid.columns.map(item => item.text);
     if (!!this.aqiEchartsIntance) {
         this.aqiChartOption = null;
         this.aqiEchartsIntance.clear();
@@ -79,7 +79,7 @@
    //  if ( this.chartSelectedIndex < this.grid.data.length ) {
    //     series = [{type: 'line', data: this.grid.data[this.chartSelectedIndex]}];
    //  }
    //  this.initOpton(chartOption ,{ xAxis : [{data : []}]});
    //  this.aqiChartOption = true;
    this.initOpton(this.aqiChartOption ,{ xAxis : [{data : this.newArray(0, 24, null, '时')}]});
src/app/routes/pollution/management/management.component.html
@@ -1,7 +1,7 @@
<div nz-row [nzGutter]="24">
    <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="24">
        <nz-card [nzLoading]="loading" [nzBordered]="false" nzTitle="警报类别占比" [nzBodyStyle]="{'padding.px': 24}" class="sales-card" style="min-height: 482px;">
        <nz-card [nzBordered]="false" nzTitle="警报类别占比" [nzBodyStyle]="{'padding.px': 24}" class="sales-card" style="min-height: 482px;">
            <ng-template #extra>
                <div class="sales-card-extra">
                    <div class="sales-type-radio">
src/app/routes/reports/query2/query.component.html
New file
@@ -0,0 +1,188 @@
<div class="content__title">
    <h1>数据查询</h1>
</div>
<nz-card [nzBordered]="false">
    <form nz-form  [nzLayout]="'inline'">
        <div nz-row [nzGutter]="24">
            <div nz-col [nzSpan]="6" class="mb-md">
                <div nz-form-item class="d-flex">
                    <div  [ngStyle]="{'width': '100px'}" nz-form-label>
                        <label>污染因子</label>
                    </div>
                    <div nz-form-control class="flex-1">
                        <nz-popover   [nzPlacement]="'bottomLeft'" [(nzVisible)]="sensorSelectVisible" [nzTrigger]="'click'">
                            <nz-input [nzType]="'input'" nz-popover [ngModel]="sensorNames" style="cursor:pointer;"
                            name="sensorNames" [nzReadonly]="true"
                            [nzPlaceHolder]="'请选择监控类型'">
                                <ng-template #suffix>
                                        <i class="anticon anticon-down ng-star-inserted ant-cascader-picker-arrow" style="right: 1px;"></i>
                                </ng-template>
                            </nz-input>
                            <ng-template #nzTemplate>
                                <div style="position: relative; width: 240px; height: 240px;" (mouseover) = "onTreeMouseOver($event)"  (mouseout) = "onTreeMouseOut($event)">
                                    <div style="position: absolute; left: -16px; width: 272px; height: 256px; overflow-y :auto; top: -8px;">
                                            <nz-tree [nzNodes]="sensorOptions"  (nzActivate)="onTreeClickSelect($event)"
                                            (nzDeactivate)="onTreeClickSelect($event)" [nzCheckable]="true" (nzCheck)="onSensorSelect($event)"></nz-tree>
                                    </div>
                                </div>
                            </ng-template>
                        </nz-popover>
                    </div>
                </div>
            </div>
            <div nz-col [nzSpan]="4" class="mb-md">
                <div nz-form-item class="d-flex">
                    <div [ngStyle]="{'width': '128px'}" nz-form-label>
                        <label>类型</label>
                    </div>
                    <div nz-form-control class="flex-1">
                        <nz-select name="timeUnit" [(ngModel)]="timeUnit" [nzPlaceHolder]="'选择 数据类型'" (ngModelChange)="setTimeUnit($event)" [nzNotFoundContent]="'无法找到'">
                            <nz-option *ngFor="let option of timeUnitOptions" [nzLabel]="option.label" [nzValue]="option">
                            </nz-option>
                        </nz-select>
                    </div>
                </div>
            </div>
            <div nz-col [nzSpan]="7" class="mb-md">
                <div nz-form-item class="d-flex">
                    <div [ngStyle]="{'width': '128px'}" nz-form-label>
                        <label>监测站点</label>
                    </div>
                    <div nz-form-control class="flex-1">
                        <nz-select name="deviceDimension" style="width: 100%;" [(ngModel)]="deviceDimension" nzAllowClear [nzPlaceHolder]="'选择 '+ dimensionItem.label +'(输入名称搜索)'"
                                   nzShowSearch (nzSearchChange)="dimensionsChange($event)" [nzNotFoundContent]="'无法找到'">
                            <nz-option *ngFor="let option of dimensionOptions" [nzLabel]="option.name" [nzValue]="option">
                            </nz-option>
                        </nz-select>
                    </div>
                </div>
            </div>
            <div nz-col [nzSpan]="5" class="mb-md">
                <div nz-form-item class="d-flex">
                    <div  nz-form-label>
                        <label>时间:</label>
                    </div>
                    <div *ngIf="timeUnit.value!='MONTH'; else elseBlock" nz-form-control class="flex-1">
                        <nz-datepicker [ngStyle]="{'width': '100%'}" name="actualTime" [(ngModel)]="actualTime" [nzAllowClear]="false" [nzShowTime]="_timeType.showTime"
                            [nzMode]="_timeType.mode" [nzFormat]="_timeType.dateFormat" [nzPlaceHolder]="'具体日期'">
                        </nz-datepicker>
                    </div>
                    <ng-template #elseBlock>
                        <div nz-form-control class="flex-1">
                            <nz-select name="actualYear" [(ngModel)]="actualYear" [nzPlaceHolder]="'选择 数据类型'" (ngModelChange)="setTimeUnit($event)" [nzNotFoundContent]="'无法找到'">
                                <nz-option *ngFor="let option of actualYearOptions" [nzLabel]="option + ' 年'" [nzValue]="option">
                                </nz-option>
                            </nz-select>
                        </div>
                    </ng-template>
                </div>
            </div>
            <div nz-col [nzSpan]="2" class="mb-md">
                <button nz-button [nzType]="'primary'" (click)="loadGrid()">
                    <i class="anticon anticon-search"></i>
                    <span>查询</span>
                </button>
            </div>
        </div>
    </form>
</nz-card>
<nz-card>
    <div nz-row [nzGutter]="16">
        <div nz-col [ngStyle]="{'display':isChartCollapse ? 'none' : 'block' }" [nzMd]="24">
            <div echarts style="margin-top: 12px;" [options]="chartOption" [loading]="chartLoading" class="line-chart" (chartInit)="onChartInit($event)"></div>
        </div>
        <div *ngIf="isChartCollapse" style="width:100%; text-align:center;">
            <span style="font-size:18px; font-weight: bold;">{{ _chartTitleTemp }}</span>
        </div>
        <div *ngIf="!!echartsIntance&&!isChartCollapse" class="chart-switch-select">
            <nz-dropdown>
                <a class="ant-dropdown-link" nz-dropdown>
                    <p class="display-3 text-primary">切换项目
                        <i class="anticon anticon-down"></i>
                    </p>
                </a>
                <ul style="cursor:pointer; max-height: 260px; overflow:auto;" nz-menu>
                    <li [ngClass]="{'ant-dropdown-menu-item-selected':chartSelectedIndex==m}" *ngFor="let item of grid.data,index as m" (click)="switchSensor(m)"
                        nz-menu-item>
                        {{item.sensor.name}}&nbsp;
                        <i *ngIf="chartSelectedIndex==m" class="anticon anticon-check-circle-o"></i>
                    </li>
                </ul>
            </nz-dropdown>
        </div>
        <a *ngIf="!!echartsIntance" style="position: absolute; right: 0; top: -10px;" class="pl-sm" (click)="toggleChartCollapse()">
            折叠
            <i class="anticon" [class.anticon-down]="isChartCollapse" [class.anticon-up]="!isChartCollapse"></i>
        </a>
    </div>
</nz-card>
<!--<nz-card>-->
    <!--<div nz-row [nzGutter]="16">-->
        <!--<div nz-col [nzMd]="24">-->
            <!--<div style="width:100%; text-align:center;">-->
                <!--<span style="font-size:18px; font-weight: bold;">{{ _tableTitleTemp }}</span>-->
            <!--</div>-->
        <!--</div>-->
    <!--</div>-->
    <!--<div nz-row [nzGutter]="16">-->
        <!--<div nz-col [nzMd]="24">-->
            <!--<nz-table #nzTable [nzScroll]="{ x:tableWidth,y:350 }" [nzDataSource]="grid.data" [nzIsPagination]="false" [nzLoading]="grid.loading">-->
                <!--<ng-template #nzFixedHeader>-->
                    <!--<thead nz-thead>-->
                        <!--<tr>-->
                            <!--<th nz-th [nzWidth]="'160px'" [ngStyle]="{'position': 'relative', 'text-align':'center', 'left':sensorNameScrollLeft+'px'}">-->
                                <!--<span>监测项目</span>-->
                            <!--</th>-->
                            <!--<th nz-th [nzWidth]="'80px'" *ngFor="let col of grid.columns" [ngStyle]="{'width':col.width,'text-align':col['align'] === undefined?'left':col.align}">-->
                                <!--<span>{{ col.text }}</span>-->
                            <!--</th>-->
                        <!--</tr>-->
                    <!--</thead>-->
                <!--</ng-template>-->
                <!--<tbody nz-tbody>-->
                    <!--<tr nz-tbody-tr style="cursor:pointer;" *ngFor="let row of nzTable.data,index as i" (click)="switchSensor(i)" (mouseover)="sensorTableFocus(i)"-->
                        <!--(mouseout)="sensorTableBlur(i)" [ngClass]="{'table-tr-bgcolor-focus': i === sensorTableFocusIndex,'table-tr-bgcolor-blur': i !== sensorTableFocusIndex}">-->
                        <!--<td nz-td class='sensor-name' [ngStyle]="{'background-color': '#FFF'}">-->
                            <!--<span>-->
                                <!--<span>{{ row.sensor.name+'('+row.sensor.unit+')' }}</span>&nbsp;-->
                                <!--<i *ngIf="chartSelectedIndex==i" class="anticon anticon-line-chart"></i>-->
                            <!--</span>-->
                        <!--</td>-->
                        <!--<td nz-td *ngFor="let col of grid.columns,index as n" [ngStyle]="{'width':col.width,'text-align':col['align'] === undefined?'left':col.align}">-->
                            <!--<span [ngSwitch]="col.type">-->
                                <!--&lt;!&ndash; 要使用管道,无法自动生成 &ndash;&gt;-->
                                <!--<span title="{{ row.data[n]|tyepHandle:col:row }}" style="width:100%; display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;"-->
                                    <!--*ngSwitchDefault> {{ row.data[n]|tyepHandle:col:row }} </span>-->
                                <!--&lt;!&ndash; 要使用管道,无法自动生成 &ndash;&gt;-->
                            <!--</span>-->
                        <!--</td>-->
                    <!--</tr>-->
                <!--</tbody>-->
            <!--</nz-table>-->
            <!---->
            <!--<div *ngIf="grid.data.length>0" [ngClass]="{'table-scroll':true,'table-scroll-box-shadow': sensorNameScrollLeft>2 }" style="position: absolute; top:0;">-->
                <!--<nz-table #nzTable [nzDataSource]="grid.data" [nzIsPagination]="false">-->
                    <!--<thead nz-thead>-->
                        <!--<tr>-->
                            <!--<th nz-th [nzWidth]="'160px'" style="text-align:center; position:relative; display:block; z-index:9;">-->
                                <!--<span>监测项目</span>-->
                            <!--</th>-->
                        <!--</tr>-->
                    <!--</thead>-->
                    <!--<tbody nz-tbody [ngStyle]="{'top':sensorNameScrollTop+'px'}" style="position: relative; z-index:7; display:block;">-->
                        <!--<tr nz-tbody-tr style="cursor:pointer;" *ngFor="let row of nzTable.data,index as i" (mouseover)="sensorTableFocus(i)" (mouseout)="sensorTableBlur(i)"-->
                            <!--[ngClass]="{'table-tr-bgcolor-focus': i === sensorTableFocusIndex,'table-tr-bgcolor-blur': i !== sensorTableFocusIndex}"-->
                            <!--(click)="switchSensor(i)">-->
                            <!--<td nz-td class='sensor-name' [ngStyle]="{'width':'160px','text-align': 'center'}">-->
                                <!--<span>-->
                                    <!--<span>{{ row.sensor.name+'('+row.sensor.unit+')' }}</span>&nbsp;-->
                                    <!--<i *ngIf="chartSelectedIndex==i" class="anticon anticon-line-chart"></i>-->
                                <!--</span>-->
                            <!--</td>-->
                        <!--</tr>-->
                    <!--</tbody>-->
                <!--</nz-table>-->
            <!--</div>-->
        <!--</div>-->
    <!--</div>-->
<!--</nz-card>-->
src/app/routes/reports/query2/query.component.less
New file
@@ -0,0 +1,24 @@
.line-chart {
    height: 100%;
}
.table-tr-bgcolor-focus {
    background-color: #ecf6fd;
}
.table-tr-bgcolor-blur {
    background-color: #fff;
}
.table-scroll {
    z-index: 9;
    height: auto;
    max-height: 388px;
    overflow: hidden;
}
.table-scroll-box-shadow {
    -moz-box-shadow: 4px 0 2px rgba(0, 0, 0, 0.1); /* 老的 Firefox */
    box-shadow: 4px 0 2px rgba(0, 0, 0, 0.1);
}
.chart-switch-select {
     position: absolute;
     right: 8%;
     top: 2%;
}
src/app/routes/reports/query2/query.component.ts
New file
@@ -0,0 +1,819 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { Sensor, Device, DataCondition, MonitorPoint, Organization, LineChartCriteria } from '@business/entity/data';
import { TimeUnits, AreaRange, ResultCode, DeviceDimension } from '@business/enum/types.enum';
import { SensorsService } from '@business/services/http/sensors.service';
import { PageBean, ResultBean, Grid } from '@business/entity/grid';
import { NzTreeComponent } from 'ng-tree-antd';
import * as moment from 'moment';
import { ExampleService } from '@business/services/util/example.service';
import { DeviceService } from '@business/services/http/device.service';
import { CascaderOption } from 'ng-zorro-antd/src/cascader/nz-cascader.component';
import { AreacodeService } from '@business/services/http/areacode.service';
import { MonitorPointService } from '@business/services/http/monitor-point.service';
import { NzMessageService } from 'ng-zorro-antd';
import * as $ from 'jquery';
import { DateService } from '@business/services/util/date.service';
import { zip } from 'rxjs/observable/zip';
import { Subject } from 'rxjs/Subject';
@Component({
  selector: 'app-query',
  templateUrl: './query.component.html',
  styleUrls: ['./query.component.less']
})
export class QueryComponent implements OnInit {
    // aqi六项排序
    private aqiSort = {
        e1: 1,
        e2: 2,
        e10: 3,
        e11: 4,
        e15: 5,
        e16: 6
    };
    public tableWidth = 2800;
    // private tableWidthOption = {
    //     'MONTH': 1400,
    //     'DAY': 2800,
    //     'HOUR': 2100,
    //     'MINUTE': 5000
    // };
    public expandForm: boolean; // 搜索区 展开控制
    // public sensors: any[] = [];
    public sensorOptions: any[] = [];
    /**
     * 数据类型,下拉列表数据
     * 注意,年度类型,对应查询数据单位为月,以此类推
     * @memberof QueryComponent
     */
    public timeUnitOptions = [
        {label: '年', value: TimeUnits.MONTH},
        {label: '月', value: TimeUnits.DAY},
        {label: '日', value: TimeUnits.HOUR},
        {label: '时', value: TimeUnits.MINUTE},
    ];
    public timeUnit: {label: string, value: TimeUnits} = this.timeUnitOptions[2];
    // 默认时间为昨天,今天无数据
    public actualTime: Date = moment().subtract(1, 'days').toDate();
    public actualYearOptions: number [];
    public isCollapse = false;
    public isChartCollapse = false;
    // 显示使用
    public _areas: { label: string, value: string }[] = new Array();
    public  grid: Grid<{sensor: Sensor, data: string [], weight?: number}> = new Grid();
    // public grid.data: {sensor: Sensor, data: string [], weight?: number} [] = [];
    //  样式控制,设备名称列冻结偏移
    public sensorNameScrollLeft = 0;
    public sensorNameScrollTop = 0;
     @ViewChild(NzTreeComponent)  private tree: NzTreeComponent;
     private _timeType: {showTime: boolean|{[key: string]: Function|boolean}, mode:  'month' | 'day', dateFormat: string  } = {showTime: false, mode: 'day', dateFormat: 'YYYY年MM月DD日'};
     // 用key-value方式,暂存监测项目
     private _sensors: {[key: string]: string} = {};
     private _sensorNames: string;
     get sensorNames(): string {
         return this._sensorNames;
     }
     public toggleCollapse() {
         this.isCollapse = !this.isCollapse;
     }
     public toggleChartCollapse() {
          // 打开的时候
         if (this.isChartCollapse && !!this.echartsIntance) {
            this.reloadChart();
            this.switchSensor(this.chartSelectedIndex);
            // this.chartLoading = false;
         }
         this.isChartCollapse = !this.isChartCollapse;
     }
     public deviceOptions: Device[] = [];
     public dataCondition: DataCondition = {areaRangeId: 320583, areaRange: AreaRange.AREA, deviceDimension: DeviceDimension.NONE};
     public dimensionOptions: MonitorPoint[] = [];
     get actualYear(): number {
         return this.actualTime.getFullYear();
     }
     set actualYear(year) {
         this.actualTime.setFullYear(Number(year));
     }
     dimensionsChange(text?: string) {
        switch (this.dimensionItem.value) {
            case DeviceDimension.MONITORPOINT:
            this.monitorPointsChange(text); break;
            case DeviceDimension.PROFESSION:
            this.professionsChange(text); break;
        }
     }
     professionsChange(text?: string) {
        this.http.get<ResultBean<any[]>>('profession/getall').subscribe(
            result => {
                if (!!result.code) {
                    this.dimensionOptions = result.data;
                }
            }
        );
      }
     monitorPointsChange(text?: string) {
        const pageBean: PageBean = { pageIndex: 0, pageSize: 20 };
        const example = new ExampleService();
        let areaName = '';
        switch (this._areas.length) {
            case 1:
                areaName = 'provinceCode'; break;
            case 2:
                areaName = 'cityCode'; break;
            case 3:
                areaName = 'areaCode'; break;
        }
        if (!!text) {
            example.or().andLike({ name: 'name', value: '%' + text + '%' })
                .andEqualTo({ name: areaName, value:  Number(this._areas.slice(-1).pop().value) });
        } else {
            example.or()
                .andEqualTo({ name: areaName, value:  Number(this._areas.slice(-1).pop().value) });
        }
        this.monitorPointService.getPageByExample(pageBean, example).subscribe(
            (res: PageBean) => {
                if (!!res && !!res.data) {
                    this.dimensionOptions = res.data;
                }
            }
        );
    }
     devicesChange(text?: string) {
        if (!!this.deviceDimension) {
            const example = new ExampleService();
            const deviceDimensionProperty =
            this.dimensionItem.value === DeviceDimension.MONITORPOINT ? 'monitorPointId' : 'professionId';
            if (!!text) {
            example.or().andEqualTo({ name: deviceDimensionProperty, value: this.deviceDimension.id })
                .andLike({name: 'text', value: text});
            } else {
                example.or().andEqualTo({ name: deviceDimensionProperty, value: this.deviceDimension.id });
            }
            this.deviceService.getPageByExample(null, example).subscribe(
                (res: PageBean) => {
                    if (!!res && !!res.data) {
                        this.deviceOptions = res.data;
                    }
                }
            );
        } else {
            this.deviceOptions = [];
        }
    }
    /**
     * 报表属性
     */
    public chartLoading: boolean;
    public chartOption;
    public echartsIntance;
    public chartSelectedIndex = 0;
    public onChartInit(e): void {
        this.echartsIntance = e;
    }
    /**
     * 放在 sensor 选项加载完后调用
     * @param sensorKeys
     */
    private mockSelectSensors(sensorKeys: string[]) {
        // 模拟选择 aqi 6个参数
        // Object.keys(this.aqiSort)
        sensorKeys.forEach( key => {
            const sensor =  this.sensorOptions[0].children.find(
                 sen => sen.sensorKey === key
            )
            if (!!sensor) {
             sensor['halfChecked'] = false;
             sensor['checked'] = true;
             const event = {node: {data: sensor}};
             this.onSensorSelect(event);
            }
         });
    }
    constructor(
    private http: _HttpClient,
    private sensorsService: SensorsService,
    private deviceService: DeviceService,
    private areacodeService: AreacodeService,
    private monitorPointService: MonitorPointService,
    private msg: NzMessageService,
    private dateService: DateService,
    ) { }
    ngOnInit() {
        this.initPage();
        // 监测项目 tree click 事件
        this.treeClickStream.debounceTime(1).subscribe( event => {
            const data = event.node.data;
            // console.log(data);
            if (data.id === -1) {
                const children = data.children;
                // 全选状态
                if (!data.halfChecked && data.checked) {
                    // 全取消操作
                    data['checked'] = false;
                    data['halfChecked'] = false;
                    children.forEach(element => {
                        element['checked'] = false;
                    });
                    this._sensors = {};
                    // 未选 或者 半选状态
                } else {
                    // 全选操作
                    children.forEach(element => {
                        element['checked'] = true;
                        this._sensors [element.id] = element.sensorKey;
                    });
                    data['checked'] = true;
                    data['halfChecked'] = false;
                }
            } else {
                const parentData = event.node.parent.data;
                data['checked'] = !data['checked'];
                if (data['checked']) {
                    this._sensors [data.id] = data.sensorKey;
                } else {
                    delete this._sensors [data.id];
                }
                const length = Object.keys(this._sensors).length;
                parentData['halfChecked'] = length > 0
                && this.sensorOptions[0].children.length > length;
                parentData['checked'] = !parentData['halfChecked'] && length !== 0;
            }
            this.reloadSensorNames();
        });
    }
    private initPage() {
        this.sensorsService.getPagingList(null, null).subscribe(
            (res: PageBean) => {
                this.sensorOptions.push({id: -1, name: '全部', isExpanded: true, children: res.data});
                this.mockSelectSensors(Object.keys(this.aqiSort));
            }
        );
        this.actualYearOptions = this.newArray(this.actualYear - 9, 10).map(item => Number(item)).reverse();
                // 省市区 初始值
                this.http.get('organization/get-my-org').subscribe(
                    (res: ResultBean<Organization>) => {
                        if (res.code === ResultCode.SUCCESS) {
                            const org = res.data;
                            const areas = new Array(3);
                            if (!!org.areaNames) {
                                const areaNames = org.areaNames;
                                Object.keys(areaNames).forEach(
                                    key => {
                                        const value = areaNames[key];
                                        if ( value != null) {
                                            switch (key) {
                                                case 'provinceName' :
                                                areas[0] = {label : value, value: org.provinceCode }; break;
                                                case 'cityName' :
                                                areas[1] = {label : value, value: org.cityCode }; break;
                                                case 'areaName' :
                                                areas[2] = {label : value, value: org.areaCode }; break;
                                            }
                                        }
                                    }
                                );
                            } else {
                                for (let i = 0; i < areas.length; i++) {
                                    switch (i) {
                                        case  0:
                                        areas[0] = {label : '江苏省', value: 320000 }; break;
                                        case  1:
                                        areas[1] = {label : '苏州市', value: 320500 }; break;
                                        case  2:
                                        areas[2] = {label : '昆山市', value: 320583 }; break;
                                    }
                                }
                            }
                            this.setAreasData(areas);
                        }
                    }
                );
                this.dimensionItem = this.dimensions[0];
                // this.dimensionsChange();
    }
    public get sensorsLength(): number {
        return this.sensorOptions.length > 0 ? this.sensorOptions[0].children.length : 0;
    }
    public  get  sensorsSelect(): number {
        return Object.keys(this._sensors).length;
    }
    public areaLazyLoad(event: { option: CascaderOption, index: number, resolve: (children: CascaderOption[]) => void, reject: () => void }) {
        const index = event['index'];
        const option = event.option;
        switch (index) {
            case -1:
                this.areacodeService.getProvinces().subscribe(
                    (res: { label: string, value: string }[]) => {
                        event.resolve(res);
                    }
                ); break;
            case 0:
                this.areacodeService.getCities(option.value).subscribe(
                    (res: { label: string, value: string }[]) => {
                        event.resolve(res);
                    }
                ); break;
            case 1:
                this.areacodeService.getAreas(option.value).subscribe(
                    (res: { label: string, value: string }[]) => {
                        event.resolve(res);
                    }
                ); break;
        }
    }
    // 第一步,省市区 赋值变 并 改变监控站点选项
    public  setAreasData(areas: {label: string, value: string}[] ) {
        let isChanged = false;
        isChanged = areas.some( (item , index: number) => {
            // this._areas[index] 为null 改变 监控站点选项
            return this._areas.length < areas.length
            || !this._areas[index]
            || this._areas[index].value !== item.value;
        });
        if ( isChanged ) {
            this._areas = areas;
            this.deviceDimension = null;
            if (this.dimensionItem.value === DeviceDimension.MONITORPOINT) {
                this.dimensionsChange();
            }
        }
    }
     // 第二步 设置 监控站点, 值变 改变设备选项,值为null 置空设备选项和设备值
     public dimensionItem: {label: string, value: DeviceDimension};
     public dimensions: {label: string, value: DeviceDimension}[] = [
         {label: '监控站点', value: DeviceDimension.MONITORPOINT},
         {label: '监控行业', value: DeviceDimension.PROFESSION}
     ];
     public get otherDimensions(): {label: string, value: DeviceDimension}[] {
         return  this.dimensions.filter(
             item => {
                 return item.value !== this.dimensionItem.value;
             }
         );
     }
     public selectDimension(option: {label: string, value: DeviceDimension}) {
         this.dimensionItem = option;
         this.dimensionsChange();
         this._deviceDimension = null;
         // 清空设备选项
         this.device = null;
         this.deviceOptions = null;
     }
     public _deviceDimension: {id: number, name: string};
     get deviceDimension(): {id: number, name: string} {
         return this._deviceDimension;
     }
     set deviceDimension(value) {
        if (!!value) {
              // 值变 改变设备选项
             if (this._deviceDimension !== value) {
                this._deviceDimension = value; // 此处不能提前也不能放后,设备改变要调用
                this._device = null; // 设备值清空
                this.devicesChange();
             }
             // 值为null 置空设备选项和设备值
        } else {
             this._deviceDimension = null;
             this.device = null;
             this.deviceOptions = null;
        }
     }
    // 第三步 设置 监控站点
    public _device: Device;
    set device(val: Device) {
        this._device = val;
    }
    get device(): Device {
        return this._device;
    }
    /**
     * 获取 传感器名称
     *
     * @readonly
     * @type {string}
     * @memberof QueryComponent
     */
    private treeClickStream: Subject<any> = new Subject<any>();
    public onTreeClickSelect(event): void {
          this.treeClickStream.next(event);
    }
    public onSensorSelect(event): void {
        debugger;
        const data = event.node.data;
        if (data.id === -1 && data.halfChecked === false) {
            if (!!data.checked) {
                this.sensorOptions[0].children.forEach(
                    sensor => {
                        this._sensors [sensor.id] = sensor.sensorKey;
                    }
                );
            } else {
                this._sensors = {};
            }
        } else {
             if (!!data.checked) {
                this._sensors [data.id] = data.sensorKey;
             } else {
                delete this._sensors[data.id];
             }
        }
        this.reloadSensorNames();
    }
    private reloadSensorNames(): void {
        // 异步提升展现速度
        setTimeout(() => {
            this._sensorNames = '';
            const sensorNameList = Object.keys(this._sensors).map(
                id => {
                  const sensor =  this.sensorOptions[0].children.find(item => {
                        return Number(id) === Number(item.id)   ;
                    });
                    return sensor.name;
                }
            );
            this._sensorNames = sensorNameList.join(', ');
        }, 1);
    }
    public setTimeUnit(val: {label: string, value: TimeUnits} ) {
        switch (val.value) {
            // YYYY-MM-DD HH:mm:ss
            case TimeUnits.MONTH:
            this._timeType.dateFormat = 'YYYY年';
                // this._timeType.dateFormat = 'YYYY-MM';
                // this._timeType.mode = 'month';
                // this._timeType.endShowTime = null;
                break;
            case TimeUnits.DAY:
                this._timeType.dateFormat = 'YYYY年MM月';
                this._timeType.mode = 'month';
                this._timeType.showTime = false;
                break;
            case TimeUnits.HOUR:
                this._timeType.dateFormat = 'YYYY年MM月DD日';
                this._timeType.mode = 'day';
                this._timeType.showTime = false;
                break;
            case TimeUnits.MINUTE:
                this._timeType.dateFormat = 'YYYY年MM月DD日 HH时';
                this._timeType.mode = 'day';
                this._timeType.showTime = {
                    nzHideDisabledOptions: true,
                    nzDisabledHours: () => {
                        return [];
                    },
                    nzDisabledMinutes: (h) => {
                        return this.newArray(60).slice(1).map(
                            item => Number(item)
                        );
                    },
                    nzDisabledSeconds: () => {
                        return this.newArray(60).slice(1).map(
                            item => Number(item)
                        );
                    }
                };
                break;
        }
    }
   private newArray = (startOrLen: number, len?: number, prefix?: string, suffix?: string) => {
        const result = [];
        const s = !!len ? startOrLen : 0;
        len = !!len ? len : startOrLen;
        suffix = !!suffix ? suffix : '';
        prefix = !!prefix ? prefix :  '';
        for (let i = s; result.length < len; i++) {
            result.push(prefix + i + suffix);
        }
        return result;
    }
    public loadGrid(): void {
        // 数据检查
        const sensors = Object.values(this._sensors);
        debugger;
        if ( sensors.length === 0 ) {
            this.msg.error(' 监测项目 不能为空');
            return ;
        }
       this.grid.loading = true;
       this.sensorNameScrollLeft = 0;
       this.grid.data = [];
       const start: Date = this.getPeriodDate(this.actualTime , 'start');
       const end: Date = this.getPeriodDate(this.actualTime , 'end');
       this.dataCondition['actualTime'] = null;
       this.dataCondition['timeUnits'] = this.timeUnit.value;
       // 设置区域值
       const dimValue: number = !!this._deviceDimension ? this._deviceDimension.id : null;
       const devValue: number = !!this._device ? this._device.id : null;
       const areasData = [ devValue, dimValue, Number(this._areas.slice(-1).pop().value)];
       if (!!this.deviceDimension) {
        this.dataCondition.dimensionValue = this._deviceDimension.id;
        this.dataCondition.deviceDimension = this.dimensionItem.value;
       }
       for (let index = 0 ; index < areasData.length ; index++) {
            const item = areasData[index];
            if ( item !== null ) {
                this.dataCondition.areaRangeId = item;
                switch (index) {
                    case 0: this.dataCondition.areaRange = AreaRange.DEVICE; break;
                    case 1:
                    // 维度为监控点
                    if (this.dimensionItem.value === DeviceDimension.MONITORPOINT) {
                         this.dataCondition.areaRange = AreaRange.MONITORPOINT;
                    // 维度为行业
                    } else {
                         // 重新标定区域范围
                         this.switchAreas();
                         // 重新设置区域值
                         this.dataCondition.areaRangeId = areasData.slice(-1).pop();
                    } break;
                    case 2:
                        this.switchAreas();
                    break;
                }
                break;
            }
       }
       const dataConditions = [this.dataCondition];
       const lineChartCriteria: LineChartCriteria = {
        sensorKeys: sensors,
        timePeriod: {startTime: start , endTime: end, timeUnits: this.timeUnit.value },
        dataConditions: dataConditions
      };
      const timePeriod = lineChartCriteria.timePeriod;
      switch (timePeriod.timeUnits) {
          case TimeUnits.MONTH:
          this.grid.columns = this.newArray(1, 12, null, '月').map(
               item => {
                   return {text: item};
               }
          ); break;
          case TimeUnits.DAY:
          const mo = moment(lineChartCriteria.timePeriod.startTime);
          const days = mo.endOf('month').date();
          this.grid.columns = this.newArray(1, days, null, '日').map(
               item => {
                   return {text: item};
               }
          ); break;
          case TimeUnits.HOUR:
          this.grid.columns = this.newArray(0, 24, null, '时').map(
            item => {
                return {text: item};
            }
          ); break;
          case TimeUnits.MINUTE:
          this.grid.columns = this.newArray(0, 60, null, '分').map(
            item => {
                return {text: item};
            }
          ); break;
      }
        // 设置表格宽度,要在此处
        this.tableWidth =  this.grid.columns.length * 80 + 160;
      this.reloadChart();
      // 重设报表标题
      this.reloadChartTitle();
      // 清空数据
      this.grid.data = [];
      console.log(lineChartCriteria);
      this.http.post('/report/line-chart', lineChartCriteria).subscribe(
        (res: ResultBean<{[key: string]: Array<Array<number>>}>) => {
           if (res.code === 1) {
              const data =  res.data;
              if (!!data) {
                const sensorKeys = Object.keys(data);
                // aqi六项置前,其他是有数据项 向前。
                sensorKeys.forEach(
                    key => {
                       const sensor = (<Array<Sensor>>this.sensorOptions[0].children).
                       find(item => {
                           return item.sensorKey === key;
                       });
                       let weight = this.aqiSort[key];
                       weight = !!weight ? weight : 101;
                    //    this.gridSensors.push(sensor);
                       const sensorData = data[key][0].map(
                           value => {
                                if (weight > 100) {
                                    // pair.value 为null,权重后移
                                    weight = !!value ? weight : weight + 1;
                                }
                                // 四舍五入,保留2位
                                return value != null ? String(Math.round(value * 100) / 100) : '-';
                           }
                       );
                       this.grid.data.push({sensor: sensor, data: sensorData, weight: weight});
                    }
               );
              }
              this.grid.data.sort( (a, b) =>  a.weight - b.weight );
              this.grid.loading = false;
              this.switchSensor(0);
           }
        }
      );
        $('.ant-table-body').scroll(
            () => {
                this.sensorNameScrollLeft =  $('.ant-table-body').scrollLeft();
                this.sensorNameScrollTop =   -$('.ant-table-body').scrollTop();
            }
        );
    }
    private switchAreas(): void {
          switch (this._areas.length ) {
            case 1: this.dataCondition.areaRange = AreaRange.PROVINCE; break;
            case 2: this.dataCondition.areaRange = AreaRange.CITY; break;
            case 3: this.dataCondition.areaRange = AreaRange.AREA; break;
          }
    }
    private reloadChart(): void {
        const  timeList = this.grid.columns.map(item => item.text);
         if (!!this.echartsIntance) {
             this.chartOption = null;
             this.echartsIntance.clear();
         }
        //  let series = null;
        //  if ( this.chartSelectedIndex < this.grid.data.length ) {
        //     series = [{type: 'line', data: this.grid.data[this.chartSelectedIndex]}];
        //  }
         this.initOpton({ xAxis : [{data : timeList}]});
         this.chartLoading = true;
      }
      private initOpton(opt: {[key: string]: object}) {
         const defaultOption = {
            title: {
                left: 'center'
            },
            tooltip : {
                trigger: 'axis',
                axisPointer: {
                    type: 'cross',
                    label: {
                        backgroundColor: '#6a7985'
                    }
                }
            },
            legend: {
                data: []
            },
            toolbox: {
                feature: {
                    saveAsImage: {}
                }
            },
            grid: {
                left: '3%',
                right: '4%',
                bottom: '3%',
                containLabel: true
            },
            xAxis : [
                {
                    type : 'category',
                    boundaryGap : false
                }
            ],
            yAxis : [
                {
                    type : 'value'
                }
            ],
            series : [
            ]
        };
        $.extend(true, defaultOption, opt);
        this.chartOption = defaultOption;
      }
    public get sensorUnit() {
        return this.grid.data[this.chartSelectedIndex].sensor.unit;
    }
    // 报表标题暂存 防止联动
    public _chartTitleTemp = '';
    public _tableTitleTemp = '';
    public reloadChartTitle(): void {
        const names = ['辖区', '地区', '维度', '时间', '项目'];
        switch ( this.dataCondition.areaRange ) {
            case AreaRange.MONITORPOINT :
            names[0] = '监控站点';
            names[1] = this._deviceDimension.name; break;
            case AreaRange.DEVICE :
            names[0] = '设备';
            names[1] = this._device.name; break;
            default :
            names[0] = '';
            names[1] = this._areas.map( item => item.label).join('/');
            break;
        }
        // 维度命名
        if (!!this._deviceDimension) {
            switch (this.dataCondition.deviceDimension) {
                case DeviceDimension.PROFESSION :
                names[2] = '[' + this._deviceDimension.name + ']';
                break;
                default :
                names[2] = '';
                break;
            }
        } else {
            names[2] = '';
        }
        names[3] = moment(this.actualTime).format(this._timeType.dateFormat);
        if ( this.grid.data.length > this.chartSelectedIndex) {
            names[4] = this.grid.data[this.chartSelectedIndex].sensor.name;
        }
        const title = names.join('  ') + ' 报表';
        if (title.trim() !== this._chartTitleTemp.trim()) {
             this._chartTitleTemp = title;
        }
        const tableTile = names.slice(0, -1).join('  ') + ' 各项数据';
        if (tableTile.trim() !== this._tableTitleTemp.trim()) {
            this._tableTitleTemp = tableTile;
       }
    }
    public switchSensor(index: number): void {
        this.chartSelectedIndex = index;
        this.chartLoading = true;
          this.reloadChartTitle();
        setTimeout(() => {
            const series = [{type: 'line', data: this.grid.data[index].data}];
            this.echartsIntance.setOption({
                title: {
                        text: this._chartTitleTemp
                },
                yAxis : [
                    {
                        name : '单位:' + this.sensorUnit
                    }
                ],
                series: series
            });
           this.chartLoading = false;
        }, 600);
    }
    private getPeriodDate(value: Date , type?: 'start'|'end' ): Date {
        let month = 0;
        let day = 1;
        let hour = 0;
        let minute = 0;
        let second = 0;
        let millisecond = 0;
        if ('end' === type) {
            month = 11;
            day = 31;
            hour = 23;
            minute = 59;
            second = 59;
            millisecond = 999;
        }
        const mo = moment(value);
        switch ( this.timeUnit.value ) {
            case TimeUnits.MONTH:
            mo.month(month).date(day).hour(hour).minute(minute).second(second).millisecond(millisecond); break;
            case TimeUnits.DAY:
            mo.date(day).hour(hour).minute(minute).second(second).millisecond(millisecond); break;
            case TimeUnits.HOUR:
            mo.hour(hour).minute(minute).second(second).millisecond(millisecond); break;
            case TimeUnits.MINUTE:
            mo.minute(minute).second(second).millisecond(millisecond); break;
            // case TimeUnits.MINUTE:
            // mo.second(second).millisecond(millisecond); break;
        }
        return mo.toDate();
    }
    public sensorTableFocusIndex = -1;
    public sensorTableFocus(index) {
        this.sensorTableFocusIndex = index;
    }
    public sensorTableBlur(index) {
        this.sensorTableFocusIndex = -1;
    }
    public sensorSelectVisible = false;
    public treeMouseOverOccur = false;
    public onTreeMouseOver(event) {
        this.treeMouseOverOccur = true;
    }
    public onTreeMouseOut(event) {
        this.treeMouseOverOccur = false;
        setTimeout(() => {
            if (!this.treeMouseOverOccur) {
                this.sensorSelectVisible =  false;
            }
        }, 900);
    }
}
src/app/routes/reports/query2/query2.component.html
@@ -1,7 +1,7 @@
<div nz-row [nzGutter]="24" style="padding-top: 25px">
    <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="24">
        <nz-card [nzLoading]="loading" [nzBordered]="false" nzTitle="监控站点排名" [nzBodyStyle]="{'padding.px': 24}" class="sales-card" style="min-height: 482px;">
        <nz-card [nzBordered]="false" nzTitle="监控站点排名" [nzBodyStyle]="{'padding.px': 24}" class="sales-card" style="min-height: 482px;">
            <ng-template #extra>
                <div class="sales-card-extra">
                    <div class="sales-type-radio">
src/app/routes/statistics/monitorpoint/monitorpoint.component.html
@@ -1,7 +1,7 @@
<div nz-row [nzGutter]="24">
    <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="24">
        <nz-card [nzLoading]="loading" [nzBordered]="false" nzTitle="警报类别占比" [nzBodyStyle]="{'padding.px': 24}" class="sales-card" style="min-height: 482px;">
        <nz-card [nzBordered]="false" nzTitle="警报类别占比" [nzBodyStyle]="{'padding.px': 24}" class="sales-card" style="min-height: 482px;">
            <ng-template #extra>
                <div class="sales-card-extra">
                    <div class="sales-type-radio">