fengxiang
2018-07-30 af9fa5a094ca652293a890f06634b59c955e1067
token刷新
7 files modified
1172 ■■■■■ changed files
src/app/app.component.ts 2 ●●● patch | view | raw | blame | history
src/app/delon.module.ts 3 ●●●● patch | view | raw | blame | history
src/app/routes/home-page/home-page/home-page.component.html 346 ●●●● patch | view | raw | blame | history
src/app/routes/home-page/home-page/home-page.component.ts 768 ●●●● patch | view | raw | blame | history
src/app/routes/statistics/calendar/calendar.component.html 19 ●●●●● patch | view | raw | blame | history
src/app/routes/statistics/calendar/calendar.component.ts 32 ●●●● patch | view | raw | blame | history
src/app/routes/statistics/statistics.module.ts 2 ●●● patch | view | raw | blame | history
src/app/app.component.ts
@@ -29,7 +29,7 @@
  ngOnInit() {
    // 设置Token信息
    this.tokenService.set({
      token: 'eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsIm9pZCI6NSwibW9kZSI6IldlYiIsInNjb3BlcyI6WyJ0ZW1wIl0sImlzcyI6Imh0dHA6Ly9tb25pdG9yLjdkcmxiLmNvbSIsImlhdCI6MTUzMTQ0ODcwMCwiZXhwIjoxNTMyNzQ0NzAwfQ.a2o1-bruQKjgvYDkA4fdhDmqpwJSbqdlKmK5spz5bk_15VvP0TN1rl1j8nQD7bJxgFQerVT3iouYVBXf3zN67A',
      token: 'eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsIm9pZCI6NSwibW9kZSI6IldlYiIsInNjb3BlcyI6WyJ0ZW1wIl0sImlzcyI6Imh0dHA6Ly9tb25pdG9yLjdkcmxiLmNvbSIsImlhdCI6MTUzMjkxMjY2OSwiZXhwIjoxNTQwNjg4NjY5fQ.nhD_CI4Dd6mU0xWoXlp4qU6yW_P9mjBEWXcidKOujtNelbQF4imVWbleo0tKgYOUWjrYNFjq7neufGYPQW1zrQ',
      name: 'admin',
      email: `admin@qq.com`,
      id: 10000,
src/app/delon.module.ts
@@ -181,7 +181,8 @@
// const MOCKMODULE = !environment.production || environment.chore === true ?
//                     [ DelonMockModule.forRoot({ data: MOCKDATA }) ] : [];
// 生产 测试 开发 都打mock
const MOCKMODULE = [ DelonMockModule.forRoot({ data: MOCKDATA }) ];
const MOCKMODULE = [ DelonMockModule.forRoot({ data: MOCKDATA,
force: false}) ];
// region: global config functions
src/app/routes/home-page/home-page/home-page.component.html
@@ -3,36 +3,45 @@
</div>
<div nz-row [nzGutter]="24" class="pt-lg">
    <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
        <div nz-row nzType="flex" nzAlign="middle" class="bg-primary rounded-md">
            <div nz-col nzSpan="24" class="p-md text-white" style="height: 90px;text-align: center;">
                <div style="height: 40px;" class="h2 mt0">{{ cardData.api }}</div>
                <p class="text-nowrap mb0">AQI</p>
        <nz-spin [nzSpinning]="firstRowLoading">
            <div nz-row nzType="flex" nzAlign="middle" class="bg-primary rounded-md">
                <div nz-col nzSpan="24" class="p-md text-white" style="height: 90px;text-align: center;">
                    <div style="height: 40px;" class="h2 mt0">{{ cardData.aqi }}</div>
                    <p class="text-nowrap mb0">AQI</p>
                </div>
            </div>
        </div>
        </nz-spin>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
        <div nz-row nzType="flex" nzAlign="middle" class="bg-success rounded-md">
            <div nz-col nzSpan="24" class="p-md text-white" style="height: 90px;text-align: center;">
                <div style="height: 40px;" class="h2 mt0">{{ cardData.temperature }} ℃</div>
                <p class="text-nowrap mb0">温度</p>
        <nz-spin [nzSpinning]="firstRowLoading">
            <div nz-row nzType="flex" nzAlign="middle" class="bg-success rounded-md">
                <div nz-col nzSpan="24" class="p-md text-white" style="height: 90px;text-align: center;">
                    <div style="height: 40px;" class="h2 mt0">{{ cardData.temperature }} ℃</div>
                    <p class="text-nowrap mb0">温度</p>
                </div>
            </div>
        </div>
        </nz-spin>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
        <div nz-row nzType="flex" nzAlign="middle" class="bg-orange rounded-md">
            <div nz-col nzSpan="24" class="p-md text-white" style="height: 90px;text-align: center;">
                <div style="height: 40px;" class="h2 mt0">{{ cardData.windDirection }}</div>
                <p class="text-nowrap mb0">风向</p>
        <nz-spin [nzSpinning]="firstRowLoading">
            <div nz-row nzType="flex" nzAlign="middle" class="bg-orange rounded-md">
                <div nz-col nzSpan="24" class="p-md text-white" style="height: 90px;text-align: center;">
                    <div style="height: 40px;" class="h2 mt0">{{ cardData.windDirection }}</div>
                    <p class="text-nowrap mb0">风向</p>
                </div>
            </div>
        </div>
        </nz-spin>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
        <div nz-row nzType="flex" nzAlign="middle" class="bg-pink rounded-md">
            <div nz-col nzSpan="24" class="p-md text-white" style="height: 90px;text-align: center;">
                <div style="height: 40px;" class="h2 mt0">{{ cardData.pm25 }} mg/m³</div>
                <p class="text-nowrap">PM2.5</p>
        <nz-spin [nzSpinning]="firstRowLoading">
            <div nz-row nzType="flex" nzAlign="middle" class="bg-pink rounded-md">
                <div nz-col nzSpan="24" class="p-md text-white" style="height: 90px;text-align: center;">
                    <div style="height: 40px;" class="h2 mt0">{{ cardData.pm25 }} mg/m³</div>
                    <p class="text-nowrap">PM2.5</p>
                </div>
            </div>
        </div>
        </nz-spin>
    </div>
</div>
<div nz-row [nzGutter]="24" class="pt-lg">
@@ -56,31 +65,24 @@
    <div nz-col nzXs="24" nzMd="24">
        <nz-card [nzBordered]="false">
            <ng-template #title>
                AQI因子柱形图 &nbsp;
                AQI因子柱形图(过去24小时) &nbsp;
                <nz-dropdown>
                    <a class="ant-dropdown-link" nz-dropdown>
                     PM2.5 <i class="anticon anticon-down"></i>
                        {{ selectedApiItem.name }}
                        <i class="anticon anticon-down"></i>
                    </a>
                    <ul nz-menu>
                      <li nz-menu-item>
                        PM10
                      </li>
                      <li nz-menu-item>
                        一氧化碳
                      </li>
                      <li nz-menu-item>
                        二氧化氮
                      </li>
                      <li nz-menu-item>
                        二氧化硫
                      </li>
                      <li nz-menu-item>
                        臭氧
                      </li>
                        <li *ngFor="let item of aqiItems" [ngClass]="{'ant-dropdown-menu-item-selected':item.selected}"
                            (click) ="setSelectedApiItem(item)" nz-menu-item>
                            {{ item.name }}
                        </li>
                    </ul>
                  </nz-dropdown>
                </nz-dropdown>
            </ng-template>
            <bar height="275" [data]="salesData"></bar>
            <nz-spin [nzTip]="'加载中...'" [nzSpinning]="aqiDataLoading">
                <p class="text-left text-md">单位:{{ selectedApiItem.unit }}</p>
                <bar height="275" [data]="aqiData"></bar>
            </nz-spin>
        </nz-card>
    </div>
</div>
@@ -88,152 +90,132 @@
    <div nz-col nzXs="24" nzMd="24">
        <nz-card [nzBordered]="false">
            <ng-template #title>
               监控站点GIS分布
               <small class="text-sm font-weight-normal">总共: 128</small>
                监控站点GIS分布
                <small class="text-sm font-weight-normal">总共: 128</small>
            </ng-template>
            <iframe style="width: 100%; height: 500px;" target="_top" src="http://monitor-api2.7drlb.com/screen/map-page?areaCode=320583&accountId=1" frameborder="0"></iframe>
            <iframe style="width: 100%; height: 500px;" target="_top" src="http://monitor-api2.7drlb.com/screen/map-page?areaCode=320583&accountId=1"
                frameborder="0"></iframe>
        </nz-card>
    </div>
  </div>
  <div nz-row [nzGutter]="24" class="pt-lg">
</div>
<div nz-row [nzGutter]="24" class="pt-lg">
    <div nz-col style="display: block;" nzXs="24" nzMd="24">
       <nz-card [nzBordered]="false">
        <nz-card [nzBordered]="false">
            <ng-template #title>
                    空气质量预报 &nbsp;
                    <nz-dropdown>
                        <a class="ant-dropdown-link" nz-dropdown>
                         PM2.5 <i class="anticon anticon-down"></i>
                        </a>
                        <ul nz-menu>
                          <li nz-menu-item>
                            PM10
                          </li>
                          <li nz-menu-item>
                            一氧化碳
                          </li>
                          <li nz-menu-item>
                            二氧化氮
                          </li>
                          <li nz-menu-item>
                            二氧化硫
                          </li>
                          <li nz-menu-item>
                            臭氧
                          </li>
                        </ul>
                      </nz-dropdown>
                </ng-template>
            <div echarts style="margin-top: 12px;" class="line-chart" [options]="aqiChartOption" [loading]="aqiChartLoading" (chartInit)="onApiChartInit($event)"></div>
       </nz-card>
                空气质量预报(24小时)
                <nz-dropdown>
                    <a class="ant-dropdown-link" nz-dropdown>
                        {{ selectedApiForecastItem.name }}
                        <i class="anticon anticon-down"></i>
                    </a>
                    <ul nz-menu>
                        <li *ngFor="let item of aqiForecastItems" [ngClass]="{'ant-dropdown-menu-item-selected':item.selected}"
                            (click) ="setSelectedApiForecastItem(item)" nz-menu-item>
                            {{ item.name }}
                        </li>
                    </ul>
                </nz-dropdown>
            </ng-template>
            <p class="text-left text-md">单位:{{ selectedApiForecastItem.unit }}</p>
            <div echarts style="margin: 0;height: 300px;" class="line-chart" [options]="aqiChartOption" [loading]="aqiForecastDataLoading" (chartInit)="onApiChartInit($event)"></div>
        </nz-card>
    </div>
  </div>
  <div nz-row [nzGutter]="24" class="pt-lg">
        <div nz-col style="display: block;" nzXs="24" nzMd="24">
           <nz-card [nzBordered]="false">
                <ng-template #title>
                        气象预报 &nbsp;
                        <nz-dropdown>
                            <a class="ant-dropdown-link" nz-dropdown>
                             温度<i class="anticon anticon-down"></i>
                            </a>
                            <ul nz-menu>
                              <li nz-menu-item>
                                气压
                              </li>
                              <li nz-menu-item>
                                湿度
                              </li>
                              <li nz-menu-item>
                                风向
                              </li>
                              <li nz-menu-item>
                                风速
                              </li>
                            </ul>
                          </nz-dropdown>
                    </ng-template>
                <div echarts style="margin-top: 12px;" class="line-chart" [options]="meteChartOption" [loading]="meteChartLoading" (chartInit)="onMeteChartInit($event)"></div>
           </nz-card>
        </div>
      </div>
      <div nz-row [nzGutter]="24">
            <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="12">
                <nz-card [nzLoading]="loading" [nzBordered]="false" nzTitle="本月站点排序">
                    <ng-template #extra>
                        <nz-dropdown>
                                <nz-dropdown>
                                        <a class="ant-dropdown-link" nz-dropdown>
                                         PM2.5 <i class="anticon anticon-down"></i>
                                        </a>
                                        <ul nz-menu>
                                          <li nz-menu-item>
                                            PM10
                                          </li>
                                          <li nz-menu-item>
                                            一氧化碳
                                          </li>
                                          <li nz-menu-item>
                                            二氧化氮
                                          </li>
                                          <li nz-menu-item>
                                            二氧化硫
                                          </li>
                                          <li nz-menu-item>
                                            臭氧
                                          </li>
                                        </ul>
                                      </nz-dropdown>
                        </nz-dropdown>
                    </ng-template>
                    <ng-template #body>
                        <nz-table #keyTable [nzDataSource]="data.searchData" [nzPageSize]="5" nzSize="small">
                            <thead nz-thead>
                                <tr>
                                    <th nz-th><span>排名</span></th>
                                    <th nz-th><span>监控站点名称</span></th>
                                    <th nz-th class="text-right">
                                        <span>监控因子数值</span>
                                        <nz-table-sort (nzValueChange)="sort('count',$event)"></nz-table-sort>
                                    </th>
                                </tr>
                            </thead>
                            <tbody nz-tbody>
                                <tr nz-tbody-tr *ngFor="let i of keyTable.data">
                                    <td nz-td>{{i.index}}</td>
                                    <td nz-td><a (click)="msg.success(i.keyword)">{{i.keyword}}</a></td>
                                    <td nz-td class="text-right">{{i.count}}</td>
                                </tr>
                            </tbody>
                        </nz-table>
                    </ng-template>
                </nz-card>
            </div>
            <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="12">
                <nz-card [nzLoading]="loading" [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">
                                <nz-radio-group [(ngModel)]="salesType" (ngModelChange)="changeSaleType()" [nzSize]="'large'">
                                    <label nz-radio-button [nzValue]="'all'"><span>全部</span></label>
                                    <label nz-radio-button [nzValue]="'online'"><span>一级</span></label>
                                    <label nz-radio-button [nzValue]="'offline'"><span>二级</span></label>
                                    <label nz-radio-button [nzValue]="'online2'"><span>三级</span></label>
                                </nz-radio-group>
                            </div>
                        </div>
                    </ng-template>
                    <ng-template #body>
                        <h4 class="margin:8px 0 32px 0;">警报饼图</h4>
                        <pie
                            [hasLegend]="true"
                            subTitle="警报总数"
                            [height]="248"
                            [lineWidth]="4"
                            [total]="salesTotal"
                            [data]="salesPieData"
                            [valueFormat]="handlePieValueFormat">
                        </pie>
                    </ng-template>
                </nz-card>
            </div>
        </div>
</div>
<div nz-row [nzGutter]="24" class="pt-lg">
    <div nz-col style="display: block;" nzXs="24" nzMd="24">
        <nz-card [nzBordered]="false">
            <ng-template #title>
                气象预报(24小时) &nbsp;
                <nz-dropdown>
                    <a class="ant-dropdown-link" nz-dropdown>
                        {{ selectedMeteItem.name }}
                        <i class="anticon anticon-down"></i>
                    </a>
                    <ul nz-menu>
                        <li *ngFor="let item of meteItems" [ngClass]="{'ant-dropdown-menu-item-selected':item.selected}"
                            (click) ="setSelectedMeteItem(item)" nz-menu-item>
                            {{ item.name }}
                        </li>
                    </ul>
                </nz-dropdown>
            </ng-template>
            <p class="text-left text-md">单位:{{ selectedMeteItem.unit }}</p>
            <div echarts style="margin: 0;height: 300px;" class="line-chart" [options]="meteChartOption" [loading]="meteChartLoading" (chartInit)="onMeteChartInit($event)"></div>
        </nz-card>
    </div>
</div>
<div nz-row [nzGutter]="24">
    <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="12">
        <nz-card [nzLoading]="loading" [nzBordered]="false" nzTitle="本月站点排序">
            <ng-template #extra>
                <nz-dropdown>
                    <a class="ant-dropdown-link" nz-dropdown>
                        {{ selectedApiSortedItem.name }}
                        <i class="anticon anticon-down"></i>
                    </a>
                    <ul nz-menu>
                        <li *ngFor="let item of apiSortedItems" [ngClass]="{'ant-dropdown-menu-item-selected':item.selected}"
                            (click) ="setSelectedApiSortedItem(item)" nz-menu-item>
                            {{ item.name }}
                        </li>
                    </ul>
                </nz-dropdown>
            </ng-template>
            <ng-template #body>
                <nz-table #keyTable [nzDataSource]="apiSortedTableList" [nzLoading]="apiSortedTableLoading" [nzPageSize]="8" nzSize="small">
                    <thead nz-thead>
                        <tr>
                            <th nz-th>
                                <span>排名</span>
                            </th>
                            <th nz-th>
                                <span>监控站点名称</span>
                            </th>
                            <th nz-th class="text-right">
                                <span>数值({{selectedApiSortedItem.unit}})</span>
                                <nz-table-sort (nzValueChange)="aqiSortedTableSort('sum',$event)"></nz-table-sort>
                            </th>
                        </tr>
                    </thead>
                    <tbody nz-tbody>
                        <tr nz-tbody-tr *ngFor="let i of keyTable.data;let j = index">
                            <td nz-td>{{j + 1}}</td>
                            <td nz-td><a>{{i.name}}</a></td>
                            <td nz-td class="text-right">{{i.avg}}</td>
                        </tr>
                        </tbody>
                </nz-table>
            </ng-template>
        </nz-card>
    </div>
    <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="12">
        <nz-card [nzLoading]="loading" [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">
                        <nz-radio-group [(ngModel)]="salesType" (ngModelChange)="changeSaleType()" [nzSize]="'large'">
                            <label nz-radio-button [nzValue]="'all'">
                                <span>全部</span>
                            </label>
                            <label nz-radio-button [nzValue]="'online'">
                                <span>一级</span>
                            </label>
                            <label nz-radio-button [nzValue]="'offline'">
                                <span>二级</span>
                            </label>
                            <label nz-radio-button [nzValue]="'online2'">
                                <span>三级</span>
                            </label>
                        </nz-radio-group>
                    </div>
                </div>
            </ng-template>
            <ng-template #body>
                <h4 class="margin:8px 0 32px 0;">警报饼图</h4>
                <pie [hasLegend]="true" subTitle="警报总数" [height]="248" [lineWidth]="4" [total]="salesTotal" [data]="salesPieData" [valueFormat]="handlePieValueFormat">
                </pie>
            </ng-template>
        </nz-card>
    </div>
</div>
src/app/routes/home-page/home-page/home-page.component.ts
@@ -1,185 +1,631 @@
import { Component, OnInit } from "@angular/core";
import { _HttpClient } from "@delon/theme";
import { zip } from 'rxjs/observable/zip';
import { zip } from "rxjs/observable/zip";
import * as moment from "moment";
import { ResultBean } from "@business/entity/grid";
@Component({
  selector: "app-home-page",
  templateUrl: "./home-page.component.html",
  styleUrls: ["./home-page.component.less"]
    selector: "app-home-page",
    templateUrl: "./home-page.component.html",
    styleUrls: ["./home-page.component.less"]
})
export class HomePageComponent implements OnInit {
  public cardData: {'api'?:number,'temperature'?:number,'windDirection'?: string,'pm25'?: number} = {};
    // 页面 构造函数和初始化
    constructor(private http: _HttpClient) {
        this.reloadAqiChart();
        this.reloadMeteChart();
    }
    salesData: any[] = [];
    aqiData: any[] = [];
    ngOnInit() {
        zip(
            this.http.get<any>(
                "http://sapi.7drlb.com/api/mj?cityID=1102&apiKey=condition"
            ),
            this.http.get<any>(
                "http://sapi.7drlb.com/api/mj?cityID=1102&apiKey=aqi"
            )
        ).subscribe(([conRes, aqiRes]) => {
            if (conRes.code == 0 && aqiRes.code == 0) {
                this.cardData.windDirection = conRes.data.condition.windDir;
                this.cardData.temperature = conRes.data.condition.temp;
                this.cardData.aqi = aqiRes.data.aqi.value;
                this.cardData.pm25 = aqiRes.data.aqi.pm25;
                setTimeout(() => {
                    this.firstRowLoading = false;
                }, 500);
            }
        });
  constructor(
    private http:_HttpClient,
  ) {
     this.reloadAqiChart();
     this.reloadMeteChart()
  }
  salesData: any[] =  [ ];
  ngOnInit() {
    zip(
       this.http.get<any>('http://sapi.7drlb.com/api/mj?cityID=1102&apiKey=condition'),
       this.http.get<any>('http://sapi.7drlb.com/api/mj?cityID=1102&apiKey=aqi')
        this.http.get("/chart").subscribe((res: any) => {
            res.offlineData.forEach((item: any) => {
                item.chart = Object.assign([], res.offlineChartData);
            });
            this.data = res;
            this.salesData = res.salesData;
            this.loading = false;
            this.changeSaleType();
        });
        this.setSelectedApiItem();
        this.setSelectedApiForecastItem();
        this.setSelectedMeteItem();
        this.setSelectedApiSortedItem();
    }
     ).subscribe(
        ([conRes,aqiRes]) => {
          if( conRes.code == 0 && aqiRes.code == 0 ) {
            this.cardData.windDirection = conRes.data.condition.windDir;
            this.cardData.temperature = conRes.data.condition.temp;
            this.cardData.api = aqiRes.data.aqi.value;
            this.cardData.pm25 = aqiRes.data.aqi.pm25;
            this.http.get('/aqi/forecast24hours',{base: this.cardData.pm25,range: 10}).subscribe(
                (res: any) => {
                    this.aqiEchartsIntance.setOption(
                        {
                           series: [{type: 'line', data: res}]
    // ---------------- 实时气象参数 -----------------------------------
    public cardData: {
        aqi?: number;
        temperature?: number;
        windDirection?: string;
        pm25?: number;
    } = {};
    public firstRowLoading = true;
    // ---------------- AQI因子柱形图(过去24小时) --------------------------
    public aqiDataLoading = true;
    public aqiItems = [
        {
            name: "PM2.5",
            key: "e1",
            unit: "ug/m³",
            selected: true
        },
        {
            name: "PM10",
            key: "e2",
            unit: "ug/m³",
            selected: false
        },
        {
            name: "一氧化碳",
            key: "e10",
            unit: "mg/m³",
            selected: false
        },
        {
            name: "二氧化硫",
            key: "e11",
            unit: "ug/m³",
            selected: false
        },
        {
            name: "臭氧",
            key: "e15",
            unit: "ug/m³",
            selected: false
        },
        {
            name: "二氧化氮",
            key: "e16",
            unit: "ug/m³",
            selected: false
        }
    ];
    public get selectedApiItem() {
        return this.aqiItems.find(item => {
            return !!item.selected;
        });
    }
    public setSelectedApiItem(item?: any) {
        if (!!item) {
            this.aqiItems.forEach(it => {
                if (item.key === it.key) {
                    it.selected = true;
                } else {
                    it.selected = false;
                }
            });
        }
        let dValue = 24;
        const startTime: Date = moment()
            .subtract(1, "days")
            .subtract(dValue, "hours")
            .toDate();
        const endTime: Date = moment()
            .subtract(1, "days")
            .toDate();
        const key = this.selectedApiItem.key;
        const lineChartCriteria = {
            dataConditions: [
                {
                    areaRangeId: 320583,
                    areaRange: 2,
                    deviceDimension: "NONE",
                    actualTime: null,
                    timeUnits: "HOUR"
                }
            ],
            sensorKeys: [key],
            timePeriod: {
                startTime: startTime,
                endTime: endTime,
                timeUnits: "HOUR"
            }
        };
        this.aqiDataLoading = true;
        this.http
            .post("/report/line-chart", lineChartCriteria)
            .subscribe(
                (res: ResultBean<{ [key: string]: Array<Array<number>> }>) => {
                    const data = res.data[key][0];
                    if (!!data && data.length > 0) {
                        const mo = moment(startTime);
                        const aqiData = [];
                        for (
                            let index = 0, num = 0;
                            index < dValue;
                            index++, num = 1
                        ) {
                            aqiData.push({
                                x: mo.add(num, "hours").hours() + "时",
                                y: data[index]
                            });
                        }
                    )
                        this.aqiData = aqiData;
                        this.aqiDataLoading = false;
                    }
                    console.log(this.aqiData);
                }
            );
            this.http.get('/aqi/forecast24hours',{base: this.cardData.temperature,range: 5}).subscribe(
               (res: any) => {
                   this.meteEchartsIntance.setOption(
                       {
                          series: [{type: 'line', data: res}]
                       }
                   )
               }
           );
          }
        }
     );
     this.http.get('/chart').subscribe((res: any) => {
        res.offlineData.forEach((item: any) => {
            item.chart = Object.assign([], res.offlineChartData);
        });
        this.data = res;
        this.salesData = res.salesData;
        this.loading = false;
        this.changeSaleType();
    });
  }
  public aqiChartOption = {};
  public aqiEchartsIntance;
  public aqiChartLoading = false;
  public onApiChartInit(e): void {
        this.aqiEchartsIntance = e;
  }
  public meteChartOption = {};
  public meteEchartsIntance;
  public meteChartLoading = false;
  public onMeteChartInit(e): void {
      this.meteEchartsIntance = e;
  }
  private reloadAqiChart(): void {
    // const  timeList = this.grid.columns.map(item => item.text);
     if (!!this.aqiEchartsIntance) {
         this.aqiChartOption = null;
         this.aqiEchartsIntance.clear();
     }
    //  let series = null;
    //  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, '时')}]});
  }
  private reloadMeteChart(): void {
     if (!!this.aqiEchartsIntance) {
         this.aqiChartOption = null;
         this.aqiEchartsIntance.clear();
     }
    this.initOpton(this.meteChartOption ,{ xAxis : [{data : this.newArray(0, 24, null, '时')}]});
  }
  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;
}
  private initOpton(chartOption,opt: {[key: string]: object}) {
     const defaultOption = {
        title: {
            left: 'center'
    // ----------- 空气质量预报(24小时) ----------------------------
    public aqiChartOption = {};
    public aqiEchartsIntance;
    public aqiForecastDataLoading = true;
    public aqiForecastItems = [
        {
            name: "PM2.5",
            key: "e1",
            unit: "ug/m³",
            selected: true
        },
        tooltip : {
            trigger: 'axis',
            axisPointer: {
                type: 'cross',
                label: {
                    backgroundColor: '#6a7985'
                }
            }
        {
            name: "PM10",
            key: "e2",
            unit: "ug/m³",
            selected: false
        },
        legend: {
            data: []
        {
            name: "一氧化碳",
            key: "e10",
            unit: "mg/m³",
            selected: false
        },
        toolbox: {
            feature: {
                saveAsImage: {}
            }
        {
            name: "二氧化硫",
            key: "e11",
            unit: "ug/m³",
            selected: false
        },
        grid: {
            left: '3%',
            right: '4%',
            bottom: '3%',
            containLabel: true
        {
            name: "臭氧",
            key: "e15",
            unit: "ug/m³",
            selected: false
        },
        xAxis : [
            {
                type : 'category',
                boundaryGap : false
            }
        ],
        yAxis : [
            {
                type : 'value'
            }
        ],
        series : [
        ]
    };
    Object.assign( defaultOption, opt);
    Object.assign(chartOption, defaultOption);
  }
  //---------mock-------------------
  data: any = {
    salesData: [],
    offlineData: []
  };
  sort(sortName, sortValue) {
    this.data.searchData = [
        ...(<any[]>this.data.searchData).sort((a, b) => {
            if (a[ sortName ] > b[ sortName ]) {
                return (sortValue === 'ascend') ? 1 : -1;
            } else if (a[ sortName ] < b[ sortName ]) {
                return (sortValue === 'ascend') ? -1 : 1;
            } else {
                return 0;
            }
        })
        {
            name: "二氧化氮",
            key: "e16",
            unit: "ug/m³",
            selected: false
        }
    ];
  }
    public onApiChartInit(e): void {
        this.aqiEchartsIntance = e;
    }
    public get selectedApiForecastItem() {
        return this.aqiForecastItems.find(item => {
            return !!item.selected;
        });
    }
    public setSelectedApiForecastItem(item?: any) {
        if (!!item) {
            this.aqiForecastItems.forEach(it => {
                if (item.key === it.key) {
                    it.selected = true;
                } else {
                    it.selected = false;
                }
            });
        }
        let dValue = 24;
        const startTime: Date = moment()
            .subtract(2, "days")
            .subtract(dValue, "hours")
            .toDate();
        const endTime: Date = moment()
            .subtract(2, "days")
            .toDate();
        const key = this.selectedApiForecastItem.key;
        const lineChartCriteria = {
            dataConditions: [
                {
                    areaRangeId: 320583,
                    areaRange: 2,
                    deviceDimension: "NONE",
                    actualTime: null,
                    timeUnits: "HOUR"
                }
            ],
            sensorKeys: [key],
            timePeriod: {
                startTime: startTime,
                endTime: endTime,
                timeUnits: "HOUR"
            }
        };
        this.aqiForecastDataLoading = true;
        this.reloadAqiChart();
        this.http
            .post("/report/line-chart", lineChartCriteria)
            .subscribe(
                (res: ResultBean<{ [key: string]: Array<Array<number>> }>) => {
                    this.aqiForecastDataLoading = false;
                    const data = res.data[key][0];
                    if (!!data && data.length > 0) {
                        this.aqiEchartsIntance.setOption({
                            series: [{ type: "line", data: data }]
                        });
                    }
                }
            );
    }
    private reloadAqiChart(): void {
        // const  timeList = this.grid.columns.map(item => item.text);
        //  if (!!this.aqiEchartsIntance) {
        //      this.aqiChartOption = null;
        //      this.aqiEchartsIntance.clear();
        //  }
        //  let series = null;
        //  if ( this.chartSelectedIndex < this.grid.data.length ) {
        //     series = [{type: 'line', data: this.grid.data[this.chartSelectedIndex]}];
        //  }
        //  this.initOpton(chartOption ,{ xAxis : [{data : []}]});
        //  this.aqiChartOption = true;
        const hour = moment().hours() + 1;
        const xList = [
            ...this.newArray(hour, 24 - hour, null, "时"),
            ...this.newArray(0, hour, null, "时")
        ];
        this.initOpton(this.aqiChartOption, { xAxis: [{ data: xList }] });
    }
    private reloadMeteChart(): void {
        //  if (!!this.aqiEchartsIntance) {
        //      this.aqiChartOption = null;
        //      this.aqiEchartsIntance.clear();
        //  }
        const hour = moment().hours() + 1;
        const xList = [
            ...this.newArray(hour, 24 - hour, null, "时"),
            ...this.newArray(0, hour, null, "时")
        ];
        this.initOpton(this.meteChartOption, { xAxis: [{ data: xList }] });
    }
    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;
    };
    // ----------- 气象预报(24小时) -------------
    public meteChartOption = {};
    public meteEchartsIntance;
    public meteChartLoading = false;
    public onMeteChartInit(e): void {
        this.meteEchartsIntance = e;
    }
    public meteItems = [
        {
            name: "风速",
            key: "windSpeed",
            unit: "m/s",
            selected: true
        },
        {
            name: "温度",
            key: "temp",
            unit: "℃",
            selected: false
        },
        {
            name: "降水",
            key: "qpf",
            unit: "mm",
            selected: false
        },
        {
            name: "湿度",
            key: "humidity",
            unit: "%RH",
            selected: false
        },
        {
            name: "紫外线",
            key: "uvi",
            unit: "毫瓦/平方米",
            selected: false
        },
        {
            name: "气压",
            key: "pressure",
            unit: "Pa",
            selected: false
        }
    ];
    public get selectedMeteItem() {
        return this.meteItems.find(item => {
            return !!item.selected;
        });
    }
    public setSelectedMeteItem(item?: any) {
        if (!!item) {
            this.meteItems.forEach(it => {
                if (item.key === it.key) {
                    it.selected = true;
                } else {
                    it.selected = false;
                }
            });
        }
        this.reloadMeteChart();
        this.meteChartLoading = true;
        const key = this.selectedMeteItem.key;
        this.http
            .get(
                "http://sapi.7drlb.com/api/mj?cityID=1102&apiKey=forecast24hours"
            )
            .subscribe((res: any) => {
                const hourlyData = <any[]>res.data.hourly;
                if (!!hourlyData && hourlyData.length > 0) {
                    const selectedData = [];
                    let windDirsData = [];
                    hourlyData.forEach((item, index) => {
                        const itemData = item[key];
                        selectedData.push(itemData);
                        let windDirData = item['windDir'];
                        // windDirData = windDirData.length >  2 ? windDirData.substr(1) : windDirData;
                        if(index == 0 ) {
                            const windDirName = this.winToChName(windDirData);
                            console.log(windDirName);
                            windDirsData.push(
                                {
                                    value: windDirName,
                                    xAxis: index,
                                    yAxis: itemData
                                }
                            );
                        } else {
                            let preWindDirData = hourlyData[index-1]['windDir'];
                            // preWindDirData = preWindDirData.length >  2 ? preWindDirData.substr(1) : preWindDirData;
                            if(preWindDirData !== windDirData) {
                                const windDirName = this.winToChName(windDirData);
                                windDirsData.push(
                                    {
                                        value: windDirName,
                                        xAxis: index,
                                        yAxis: itemData
                                    }
                                );
                            }
                        }
                    });
                    if (!!selectedData && selectedData.length > 0) {
                        this.meteEchartsIntance.setOption({
                            legend: {
                                data:['风向']
                            },
                            series: [
                                {
                                    type: 'line',
                                    data: selectedData
                                },
                                {
                                    name: '风向',
                                    type: 'line',
                                    itemStyle: {
                                        color: '#c23531'
                                    },
                                    markPoint: {
                                        data: windDirsData
                                    }
                                }
                        ]
                        });
                        this.meteChartLoading = false;
                    }
                }
            });
    }
    public winToChName(windDir: string) {
         let name = '';
         if(!!windDir) {
             if(windDir.length >1) {
                windDir = windDir.split('').reverse().join('');
             }
            //  let index = 0;
             for (let ch of windDir) {
                switch(ch) {
                    case 'E':name += '东';break;
                    case 'S':name += '南';break;
                    case 'W':name += '西';break;
                    case 'N':name += '北';break;
                }
                // if(windDir.length >2 && index == 1){
                //     name += '偏';
                // }
                // index++;
             }
             name += '风';
         }
         return name;
    }
    // ---------------- echart 初始化函数 ---------------------------
    private initOpton(chartOption, 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: []
        };
        Object.assign(defaultOption, opt);
        Object.assign(chartOption, defaultOption);
    }
    //---------- 本月站点排序 apiSortedItem ------------------------
    public apiSortedTableLoading = false;
    public apiSortedTableList = [];
    public apiSortedItems = [
        {
            name: "PM2.5",
            key: "e1",
            unit: "ug/m³",
            selected: true
        },
        {
            name: "PM10",
            key: "e2",
            unit: "ug/m³",
            selected: false
        },
        {
            name: "一氧化碳",
            key: "e10",
            unit: "mg/m³",
            selected: false
        },
        {
            name: "二氧化硫",
            key: "e11",
            unit: "ug/m³",
            selected: false
        },
        {
            name: "臭氧",
            key: "e15",
            unit: "ug/m³",
            selected: false
        },
        {
            name: "二氧化氮",
            key: "e16",
            unit: "ug/m³",
            selected: false
        }
    ];
    public get selectedApiSortedItem() {
        return this.apiSortedItems.find(item => {
            return !!item.selected;
        });
    }
    public setSelectedApiSortedItem(item ?: any) {
        if (!!item) {
            this.apiSortedItems.forEach(it => {
                if (item.key === it.key) {
                    it.selected = true;
                } else {
                    it.selected = false;
                }
            });
        }
        this.apiSortedTableLoading = true;
        const params = {sensorKey: this.selectedApiSortedItem.key, dimension: 'monitorPoint', regionCode: '320583', accountId: '1', timeType: 'day'};
        this.http.get('screen/region_ranking_data',params).subscribe((res: any) => {
            this.apiSortedTableLoading = false;
            // console.log(res);
          this.apiSortedTableList = res.data;
        });
    }
    public aqiSortedTableSort(sortName, sortValue) {
        this.apiSortedTableList = [
          ...(<any[]>this.apiSortedTableList).sort((a, b) => {
            if (a[sortName] > b[sortName]) {
              return (sortValue === 'ascend') ? 1 : -1;
            } else if (a[sortName] < b[sortName]) {
              return (sortValue === 'ascend') ? -1 : 1;
            } else {
              return 0;
            }
          })
        ];
      }
    //---------mock-------------------
    data: any = {
        salesData: [],
        offlineData: []
    };
    sort(sortName, sortValue) {
        this.data.searchData = [
            ...(<any[]>this.data.searchData).sort((a, b) => {
                if (a[sortName] > b[sortName]) {
                    return sortValue === "ascend" ? 1 : -1;
                } else if (a[sortName] < b[sortName]) {
                    return sortValue === "ascend" ? -1 : 1;
                } else {
                    return 0;
                }
            })
        ];
    }
    loading = true;
    salesType = 'all';
    salesType = "all";
    salesPieData: any;
    salesTotal = 0;
    changeSaleType() {
        this.salesPieData = this.salesType === 'all' ? this.data.salesTypeData : (
            this.salesType === 'online' ? this.data.salesTypeDataOnline : (
                this.salesType === 'online2' ?  this.data.salesTypeDataOnline2 : this.data.salesTypeDataOffline
            )
        );
        if (this.salesPieData) this.salesTotal = this.salesPieData.reduce((pre, now) => now.y + pre, 0);
        this.salesPieData =
            this.salesType === "all"
                ? this.data.salesTypeData
                : this.salesType === "online"
                    ? this.data.salesTypeDataOnline
                    : this.salesType === "online2"
                        ? this.data.salesTypeDataOnline2
                        : this.data.salesTypeDataOffline;
        if (this.salesPieData)
            this.salesTotal = this.salesPieData.reduce(
                (pre, now) => now.y + pre,
                0
            );
    }
}
src/app/routes/statistics/calendar/calendar.component.html
@@ -2,12 +2,19 @@
<div nz-row [nzGutter]="24" style="padding: 20px">
    <div nz-col nzXs="24"   nzMd="24">
        <div nz-form-control nz-col [nzSm]="20">
            <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>
            <nz-card [nzBordered]="false">
                <nz-calendar [nzLocale]="'zh-cn'" >
                    <ng-template #dateCell let-day>
                        <div *ngIf="!isExpire(day.date)" style="width: 80px;height: 80px;display: block;position: absolute;" (click)="calendarClick(day.date)">
                                <nz-badge [nzStatus]="calendarDayCells[day.date|date:'dd']['status']" [nzText]="calendarDayCells[day.date|date:'dd']['statusName']" ></nz-badge>
                                <!-- <nz-badge [nzStatus]="'success'" [nzText]="'Sunday'" *ngIf="(day.date|date:'EEE')==='Sun'"></nz-badge>
                                {{day.date|date:'EEE'}}
                                {{day.date|date:'dd'}}
                                {{calendarDayCells[day.date|date:'dd']['status']}} -->
                        </div>
                    </ng-template>
                </nz-calendar>
            </nz-card>
        </div>
    </div>
    <div nz-col nzXs="24" nzSm="12" nzMd="24" nzLg="15">
src/app/routes/statistics/calendar/calendar.component.ts
@@ -14,7 +14,13 @@
export class CalendarComponent implements OnInit, OnDestroy {
    data: any = {};
    public calendarDayCells:{
       [key : string] : {
         'status': string,
         'statusName': string,
         'data': {}
       }
    } = {};
    constructor(
        private deviceService: DeviceService,
        private http: _HttpClient,
@@ -23,12 +29,30 @@
    }
    ngOnInit() {
        const day = Number(moment().format('DD'));
        for(let index = 1;index <= day; index++) {
            this.calendarDayCells[('0'+index).slice(-2)] = {
                status: 'processing',
                statusName: '加载中',
                data: {}
            }
        }
        // console.log(this.calendarDayCells);
    }
    ngOnDestroy(): void {
    }
    calendarClick(event,day) {
        console.log(day);
    // 日历单元格 被点击
    calendarClick(mo: moment.Moment) {
        console.log(mo.format('DD'));
    }
    public isExpire(mo: moment.Moment):boolean {
        //  console.log(moment().valueOf());
        //  console.log(mo.valueOf());
        //  console.log(moment().valueOf() < mo.valueOf());
         return moment().valueOf() < mo.valueOf();
    }
    loadCalendar(event) {
        console.log(event);
    }
}
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, DatePipe } from '@angular/common';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { AnalysisComponent } from './analysis/analysis.component';
import { CalendarComponent } from './calendar/calendar.component';