fengxiang
2018-07-20 902e52b94d2518196f5c5c91f62013342590abc7
页面更新提交
1 files added
11 files modified
1049 ■■■■■ changed files
src/app/routes/enterprise-management/enterprise-data/enterprise-data.component.html 160 ●●●●● patch | view | raw | blame | history
src/app/routes/enterprise-management/enterprise-data/enterprise-data.component.less 24 ●●●●● patch | view | raw | blame | history
src/app/routes/enterprise-management/enterprise-data/enterprise-data.component.ts 817 ●●●●● patch | view | raw | blame | history
src/app/routes/enterprise-management/enterprise-management.module.ts 14 ●●●●● patch | view | raw | blame | history
src/app/routes/environment/management/management.component.html 6 ●●●● patch | view | raw | blame | history
src/app/routes/home-page/home-page/home-page.component.html 6 ●●●● patch | view | raw | blame | history
src/app/routes/reports/query2/query2.component.ts 1 ●●●● patch | view | raw | blame | history
src/app/routes/statistics/analysis/analysis.component.html 6 ●●●● patch | view | raw | blame | history
src/app/routes/statistics/calendar/calendar.component.html 8 ●●●● patch | view | raw | blame | history
src/app/routes/statistics/calendar/calendar.component.ts 3 ●●●●● patch | view | raw | blame | history
src/app/routes/statistics/statistics.module.ts 2 ●●● patch | view | raw | blame | history
src/app/routes/systems/organization/organization-edit/organization-edit.component.html 2 ●●● patch | view | raw | blame | history
src/app/routes/enterprise-management/enterprise-data/enterprise-data.component.html
@@ -1,4 +1,162 @@
<div class="content__title">
    <h1>企业数据</h1>
</div>
<pro-header [title]="'Page Name'"></pro-header>
<nz-card [nzBordered]="false">
    <form nz-form  [nzLayout]="'inline'">
        <div nz-row [nzGutter]="24">
                <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]="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="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  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]="3" 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/enterprise-management/enterprise-data/enterprise-data.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/enterprise-management/enterprise-data/enterprise-data.component.ts
@@ -1,17 +1,814 @@
import { Component, OnInit } from '@angular/core';
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 { Subject } from 'rxjs/Subject';
@Component({
  selector: 'app-enterprise-data',
  templateUrl: './enterprise-data.component.html',
  styleUrls: ['./enterprise-data.component.less'],
})
export class EnterpriseDataComponent implements OnInit {
    constructor(
        private http: _HttpClient
    ) { }
    ngOnInit() {
export class EnterpriseDataComponent 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 {
            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);
            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/enterprise-management/enterprise-management.module.ts
@@ -6,6 +6,14 @@
import { PipeModule } from '@business/pipe/pipe.module';
import { EnterpriseDataComponent } from './enterprise-data/enterprise-data.component';
import { StandardAlarmComponent } from './standard-alarm/standard-alarm.component';
import { NzTreeModule } from 'ng-tree-antd';
import { NgxEchartsModule } from 'ngx-echarts';
import { SensorsService } from '@business/services/http/sensors.service';
import { NzMessageService } from 'ng-zorro-antd';
import { AreacodeService } from '@business/services/http/areacode.service';
import { MonitorPointService } from '@business/services/http/monitor-point.service';
import { DeviceService } from '@business/services/http/device.service';
import { DateService } from '@business/services/util/date.service';
const routes: Routes = [
@@ -24,6 +32,8 @@
  imports: [
    // 管道模块必须当前模块导入
    PipeModule,
    NzTreeModule,
    NgxEchartsModule,
    CommonModule,
    SharedModule,
    RouterModule.forChild(routes)
@@ -34,6 +44,8 @@
      StandardAlarmComponent,
      GisShowComponent
  ],
  entryComponents: COMPONENT_NOROUNT
  entryComponents: COMPONENT_NOROUNT,
  providers: [SensorsService, NzMessageService, AreacodeService,
    MonitorPointService, DeviceService, DateService],
})
export class EnterpriseManagementModule { }
src/app/routes/environment/management/management.component.html
@@ -1,16 +1,16 @@
<div nz-row [nzGutter]="24" class="pt-lg">
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'API优良天数'" total="216天" contentHeight="46px">
        <chart-card [title]="'AQI优良天数'" total="112天" contentHeight="46px">
            <mini-progress height="46" percent="60" target="60" strokeWidth="8" color="#13C2C2"></mini-progress>
        </chart-card>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'PM2.5优良天数'" total="158天" contentHeight="46px">
        <chart-card [title]="'PM2.5优良天数'" total="148天" contentHeight="46px">
            <mini-progress height="46" percent="50" target="50" strokeWidth="8" color="#108ee9"></mini-progress>
        </chart-card>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'PM10优良天数'" total="112天" contentHeight="46px">
        <chart-card [title]="'PM10优良天数'" total="156天" contentHeight="46px">
            <mini-progress height="46" percent="40" target="40" strokeWidth="8" color="#00a854"></mini-progress>
        </chart-card>
    </div>
src/app/routes/home-page/home-page/home-page.component.html
@@ -37,17 +37,17 @@
</div>
<div nz-row [nzGutter]="24" class="pt-lg">
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'API优良天数'" total="216天" contentHeight="46px">
        <chart-card [title]="'AQI优良天数'" total="112天" contentHeight="46px">
            <mini-progress height="46" percent="60" target="60" strokeWidth="8" color="#13C2C2"></mini-progress>
        </chart-card>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'PM2.5优良天数'" total="158天" contentHeight="46px">
        <chart-card [title]="'PM2.5优良天数'" total="148天" contentHeight="46px">
            <mini-progress height="46" percent="50" target="50" strokeWidth="8" color="#108ee9"></mini-progress>
        </chart-card>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'PM10优良天数'" total="112天" contentHeight="46px">
        <chart-card [title]="'PM10优良天数'" total="156天" contentHeight="46px">
            <mini-progress height="46" percent="40" target="40" strokeWidth="8" color="#00a854"></mini-progress>
        </chart-card>
    </div>
src/app/routes/reports/query2/query2.component.ts
@@ -424,7 +424,6 @@
          this.treeClickStream.next(event);
    }
    public onSensorSelect(event): void {
        debugger;
        const data = event.node.data;
        if (data.id === -1 && data.halfChecked === false) {
            if (!!data.checked) {
src/app/routes/statistics/analysis/analysis.component.html
@@ -1,16 +1,16 @@
<div nz-row [nzGutter]="24" class="pt-lg">
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'API优良天数'" total="216天" contentHeight="46px">
        <chart-card [title]="'AQI优良天数'" total="112天" contentHeight="46px">
            <mini-progress height="46" percent="60" target="60" strokeWidth="8" color="#13C2C2"></mini-progress>
        </chart-card>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'PM2.5优良天数'" total="158天" contentHeight="46px">
        <chart-card [title]="'PM2.5优良天数'" total="148天" contentHeight="46px">
            <mini-progress height="46" percent="50" target="50" strokeWidth="8" color="#108ee9"></mini-progress>
        </chart-card>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="8">
        <chart-card [title]="'PM10优良天数'" total="112天" contentHeight="46px">
        <chart-card [title]="'PM10优良天数'" total="156天" contentHeight="46px">
            <mini-progress height="46" percent="40" target="40" strokeWidth="8" color="#00a854"></mini-progress>
        </chart-card>
    </div>
src/app/routes/statistics/calendar/calendar.component.html
@@ -1,8 +1,12 @@
<div nz-row [nzGutter]="24" style="padding: 20px">
    <div nz-col nzXs="24" nzSm="12" nzMd="24" nzLg="9">
    <div nz-col nzXs="24"   nzMd="24">
        <div nz-form-control nz-col [nzSm]="20">
            <nz-calendar [nzLocale]="'zh-cn'" [nzFullScreen]="false" style="width: 290px; border: 1px solid rgb(217, 217, 217); border-radius: 4px;">
            <nz-calendar [nzLocale]="'zh-cn'" style="width: 290px; border: 1px solid rgb(217, 217, 217); border-radius: 4px;">
                <!-- <ng-template #dateCell let-day>
                    <div style="width: 22px;height: 22px;display: block;position: absolute; background-color: red;">
                    </div>
                </ng-template> -->
            </nz-calendar>
        </div>
    </div>
src/app/routes/statistics/calendar/calendar.component.ts
@@ -28,4 +28,7 @@
    ngOnDestroy(): void {
    }
    calendarClick(event,day) {
        console.log(day);
    }
}
src/app/routes/statistics/statistics.module.ts
@@ -3,7 +3,7 @@
import { PipeModule } from '@business/pipe/pipe.module';
import { NzTreeModule } from 'ng-tree-antd';
import { NgxEchartsModule } from 'ngx-echarts';
import { CommonModule } from '@angular/common';
import { CommonModule, DatePipe } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { AnalysisComponent } from './analysis/analysis.component';
import { CalendarComponent } from './calendar/calendar.component';
src/app/routes/systems/organization/organization-edit/organization-edit.component.html
@@ -25,7 +25,7 @@
      <label nz-form-item-required>省/市/区</label>
    </div>
    <div nz-form-control nz-col [nzSpan]="7" nzHasFeedback>
      <nz-cascader [class.class123]="true" (nzChange)="setAreaCodes($event)" formControlName="_areas" (nzLoad)="areaLazyLoad($event)"
      <nz-cascader [class.class123]="true" (nzChange)="setAreaCodes($event)" formControlName="_areas" (nzLoad)="areaLazyLoad($event)" [nzChangeOnSelect]="true"
      [nzPlaceHolder]="'选择 省/市/区'" >
      </nz-cascader>
    </div>