fengxiang
2018-07-11 12b04f145bae740e1971036b1e2dfc1bc224d17b
Revert "框架调整"

This reverts commit 6e95e54195235f650d748ae3e0f5718ad6a23556.

撤销框架调整修改
1 files copied
1 files renamed
16 files deleted
134 files added
6 files modified
8296 ■■■■■ changed files
.angulardoc.json 4 ●●●● patch | view | raw | blame | history
src/app/layout/default/header/header.component.html 30 ●●●● patch | view | raw | blame | history
src/app/routes/callback/callback.component.ts 35 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/analysis/analysis.component.html 226 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/analysis/analysis.component.less 135 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/analysis/analysis.component.ts 88 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/monitor/monitor.component.html 78 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/monitor/monitor.component.less 58 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/monitor/monitor.component.ts 99 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/v1/v1.component.html 150 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/v1/v1.component.spec.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/v1/v1.component.ts 62 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/workplace/workplace.component.html 111 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/workplace/workplace.component.less 240 ●●●●● patch | view | raw | blame | history
src/app/routes/dashboard/workplace/workplace.component.ts 114 ●●●●● patch | view | raw | blame | history
src/app/routes/data-v/data-v-routing.module.ts 11 ●●●●● patch | view | raw | blame | history
src/app/routes/data-v/data-v.module.ts 11 ●●●●● patch | view | raw | blame | history
src/app/routes/data-v/relation/relation.component.html patch | view | raw | blame | history
src/app/routes/data-v/relation/relation.component.less patch | view | raw | blame | history
src/app/routes/data-v/relation/relation.component.ts 169 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/acl/acl.component.html 43 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/acl/acl.component.spec.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/acl/acl.component.ts 41 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/cache/cache.component.html 10 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/cache/cache.component.ts 24 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/delon-routing.module.ts 61 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/delon.module.ts 48 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/downfile/downfile.component.html 6 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/downfile/downfile.component.spec.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/downfile/downfile.component.ts 14 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/form/form.component.html 5 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/form/form.component.ts 32 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/guard/admin.component.ts 9 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/guard/auth.component.ts 9 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/guard/can-leave.provide.ts 38 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/guard/guard.component.html 33 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/guard/guard.component.spec.ts 17 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/guard/guard.component.ts 23 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/guard/leave.component.ts 12 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/print/print.component.html 61 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/print/print.component.ts 79 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/qr/qr.component.html 76 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/qr/qr.component.ts 17 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/simple-table/simple-table.component.html 52 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/simple-table/simple-table.component.ts 74 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/util/util.component.html 54 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/util/util.component.ts 47 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/xlsx/xlsx.component.html 14 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/xlsx/xlsx.component.ts 50 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/zip/zip.component.html 38 ●●●●● patch | view | raw | blame | history
src/app/routes/delon/zip/zip.component.ts 71 ●●●●● patch | view | raw | blame | history
src/app/routes/exception/403.component.ts 12 ●●●●● patch | view | raw | blame | history
src/app/routes/exception/404.component.ts 12 ●●●●● patch | view | raw | blame | history
src/app/routes/exception/500.component.ts 12 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/extras-routing.module.ts 18 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/extras.module.ts 24 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/helpcenter/helpcenter.component.html 94 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/helpcenter/helpcenter.component.spec.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/helpcenter/helpcenter.component.ts 22 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/poi/edit/edit.component.html 87 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/poi/edit/edit.component.ts 39 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/poi/poi.component.html 37 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/poi/poi.component.ts 51 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/settings/settings.component.html 204 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/settings/settings.component.spec.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/extras/settings/settings.component.ts 64 ●●●●● patch | view | raw | blame | history
src/app/routes/home-page/home-page-routing.module.ts 11 ●●●●● patch | view | raw | blame | history
src/app/routes/home-page/home-page.module.ts 13 ●●●●● patch | view | raw | blame | history
src/app/routes/home-page/home-page/home-page.component.html 25 ●●●●● patch | view | raw | blame | history
src/app/routes/home-page/home-page/home-page.component.ts 15 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/lock/lock.component.html 29 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/lock/lock.component.spec.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/lock/lock.component.ts 35 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/login/login.component.html 70 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/login/login.component.less 42 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/login/login.component.ts 181 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/register-result/register-result.component.html 7 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/register-result/register-result.component.ts 10 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/register/register.component.html 85 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/register/register.component.less 42 ●●●●● patch | view | raw | blame | history
src/app/routes/passport/register/register.component.ts 133 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/advanced-form/advanced-form.component.html 218 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/advanced-form/advanced-form.component.ts 156 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/basic-form/basic-form.component.html 78 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/basic-form/basic-form.component.ts 41 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step-form.component.html 13 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step-form.component.less 26 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step-form.component.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step1.component.html 59 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step1.component.ts 61 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step2.component.html 51 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step2.component.ts 42 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step3.component.html 34 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/step3.component.ts 10 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/form/step-form/transfer.service.ts 53 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/applications/applications.component.html 92 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/applications/applications.component.less 51 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/applications/applications.component.ts 76 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/articles/articles.component.html 91 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/articles/articles.component.ts 86 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/basic-list/basic-list.component.html 91 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/basic-list/basic-list.component.less 21 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/basic-list/basic-list.component.ts 30 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/card-list/card-list.component.html 48 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/card-list/card-list.component.ts 31 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/list/list.component.html 16 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/list/list.component.ts 43 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/projects/projects.component.html 61 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/projects/projects.component.less 16 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/projects/projects.component.ts 61 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/table-list/table-list.component.html 108 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/list/table-list/table-list.component.ts 154 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/pro-routing.module.ts 65 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/pro.module.ts 48 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/profile/advanced/advanced.component.html 144 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/profile/advanced/advanced.component.less 19 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/profile/advanced/advanced.component.ts 40 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/profile/basic/basic.component.html 42 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/profile/basic/basic.component.ts 45 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/result/fail/fail.component.html 21 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/result/fail/fail.component.ts 7 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/result/success/success.component.html 53 ●●●●● patch | view | raw | blame | history
src/app/routes/pro/result/success/success.component.ts 10 ●●●●● patch | view | raw | blame | history
src/app/routes/routes-routing.module.ts 80 ●●●●● patch | view | raw | blame | history
src/app/routes/routes.module.ts 30 ●●●●● patch | view | raw | blame | history
src/app/routes/style/color.service.ts 31 ●●●●● patch | view | raw | blame | history
src/app/routes/style/colors/colors.component.html 105 ●●●●● patch | view | raw | blame | history
src/app/routes/style/colors/colors.component.less 13 ●●●●● patch | view | raw | blame | history
src/app/routes/style/colors/colors.component.spec.ts 18 ●●●●● patch | view | raw | blame | history
src/app/routes/style/colors/colors.component.ts 20 ●●●●● patch | view | raw | blame | history
src/app/routes/style/gridmasonry/gridmasonry.component.html 247 ●●●●● patch | view | raw | blame | history
src/app/routes/style/gridmasonry/gridmasonry.component.spec.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/style/gridmasonry/gridmasonry.component.ts 7 ●●●●● patch | view | raw | blame | history
src/app/routes/style/style-routing.module.ts 18 ●●●●● patch | view | raw | blame | history
src/app/routes/style/style.module.ts 20 ●●●●● patch | view | raw | blame | history
src/app/routes/style/typography/typography.component.html 130 ●●●●● patch | view | raw | blame | history
src/app/routes/style/typography/typography.component.spec.ts 18 ●●●●● patch | view | raw | blame | history
src/app/routes/style/typography/typography.component.ts 10 ●●●●● patch | view | raw | blame | history
src/app/routes/widgets/widgets-routing.module.ts 12 ●●●●● patch | view | raw | blame | history
src/app/routes/widgets/widgets.module.ts 13 ●●●●● patch | view | raw | blame | history
src/app/routes/widgets/widgets/widgets.component.html 797 ●●●●● patch | view | raw | blame | history
src/app/routes/widgets/widgets/widgets.component.less 11 ●●●●● patch | view | raw | blame | history
src/app/routes/widgets/widgets/widgets.component.spec.ts 16 ●●●●● patch | view | raw | blame | history
src/app/routes/widgets/widgets/widgets.component.ts 63 ●●●●● patch | view | raw | blame | history
src/assets/tmp/app-data.json 4 ●●●● patch | view | raw | blame | history
src/assets/tmp/i18n/zh-CN.json 4 ●●● patch | view | raw | blame | history
src/assets/tmp/img/No1.png patch | view | raw | blame | history
src/assets/tmp/img/No2.png patch | view | raw | blame | history
src/assets/tmp/img/No3.png patch | view | raw | blame | history
src/assets/tmp/img/No4.png patch | view | raw | blame | history
src/assets/tmp/img/No5.png patch | view | raw | blame | history
src/assets/tmp/img/logo.png patch | view | raw | blame | history
src/assets/tmp/img/logo_100x40.png patch | view | raw | blame | history
src/assets/tmp/img/logo_30x30.png patch | view | raw | blame | history
src/assets/tmp/img/logo_44x44.png patch | view | raw | blame | history
src/assets/tmp/img/map_coordinates.png patch | view | raw | blame | history
src/assets/tmp/img/zorro.svg 34 ●●●●● patch | view | raw | blame | history
src/index.html 2 ●●● patch | view | raw | blame | history
.angulardoc.json
File was deleted
src/app/layout/default/header/header.component.html
@@ -1,7 +1,7 @@
<div class="logo">
  <a [routerLink]="['/']">
    <img class="expanded" src="./assets/tmp/img/logo_100x40.png" alt="{{settings.app.name}}" style="max-height:40px;" />
    <img class="collapsed" src="./assets/tmp/img/logo_30x30.png" alt="{{settings.app.name}}" style="max-height:30px;" />
    <img class="expanded" src="./assets/logo-full.svg" alt="{{settings.app.name}}" style="max-height:40px;" />
    <img class="collapsed" src="./assets/logo.svg" alt="{{settings.app.name}}" style="max-height:30px;" />
  </a>
</div>
<div class="top-nav-wrap">
@@ -13,38 +13,38 @@
      </div>
    </li>
    <!-- Github Page -->
    <!-- <li>
    <li>
      <a class="item" href="//github.com/cipchk/ng-alain" target="_blank">
        <i class="anticon anticon-github"></i>
      </a>
    </li> -->
    </li>
    <!-- Lock Page -->
    <!-- <li class="hidden-xs">
    <li class="hidden-xs">
      <div class="item" [routerLink]="['/lock']">
        <i class="anticon anticon-lock"></i>
      </div>
    </li> -->
    </li>
    <!-- Search Button -->
    <!-- <li class="header-search__btn" (click)="searchToggleChange()">
    <li class="header-search__btn" (click)="searchToggleChange()">
      <div class="item">
        <i class="anticon anticon-search"></i>
      </div>
    </li> -->
    </li>
  </ul>
  <!-- <header-search class="header-search" [toggleChange]="searchToggleStatus"></header-search> -->
  <header-search class="header-search" [toggleChange]="searchToggleStatus"></header-search>
  <ul class="top-nav">
    <!-- Notify -->
    <!-- <li>
    <li>
      <header-notify></header-notify>
    </li> -->
    </li>
    <!-- Task -->
    <!-- <li class="hidden-xs">
    <li class="hidden-xs">
      <header-task></header-task>
    </li> -->
    </li>
    <!-- App Icons -->
    <!-- <li class="hidden-xs">
    <li class="hidden-xs">
      <header-icon></header-icon>
    </li> -->
    </li>
    <!-- Settings -->
    <li class="hidden-xs">
      <nz-dropdown nzTrigger="click" nzPlacement="bottomRight">
src/app/routes/callback/callback.component.ts
New file
@@ -0,0 +1,35 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { SocialService } from '@delon/auth';
@Component({
  selector: 'app-callback',
  template: ``,
  providers: [SocialService],
})
export class CallbackComponent implements OnInit {
  type: string;
  constructor(
    private socialService: SocialService,
    private route: ActivatedRoute,
    private router: Router,
  ) {}
  ngOnInit(): void {
    this.route.params.subscribe(params => {
      this.type = params['type'];
      this.mockModel();
    });
  }
  private mockModel() {
    this.socialService.callback({
      token: '123456789',
      name: 'cipchk',
      email: `${this.type}@${this.type}.com`,
      id: 10000,
      time: +new Date(),
    });
  }
}
src/app/routes/dashboard/analysis/analysis.component.html
New file
@@ -0,0 +1,226 @@
<page-header></page-header>
<div nz-row [nzGutter]="24" class="pt-lg">
  <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="6">
    <g2-card [title]="'总销售额'" total="¥ 126,560" contentHeight="44px" [action]="action1" [footer]="footer1">
      <ng-template #action1>
        <nz-tooltip [nzTitle]="'指标说明'">
          <i nz-tooltip class="anticon anticon-info-circle-o"></i>
        </nz-tooltip>
      </ng-template>
      <trend flag="up" style="display:block; margin-top:2px;">周同比
        <span class="pl-sm">12%</span>
      </trend>
      <trend flag="down">日环比
        <span class="pl-sm">11%</span>
      </trend>
      <ng-template #footer1>
        <p class="text-truncate mb0">日均销售额
          <span class="ml-sm">¥12,423</span>
        </p>
      </ng-template>
    </g2-card>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="6">
    <g2-card [title]="'访问量'" total="8,848" contentHeight="46px" [action]="action2" [footer]="footer2">
      <ng-template #action2>
        <nz-tooltip [nzTitle]="'指标说明'">
          <i nz-tooltip class="anticon anticon-info-circle-o"></i>
        </nz-tooltip>
      </ng-template>
      <g2-mini-area color="#975FE4" height="46" [data]="data.visitData"></g2-mini-area>
      <ng-template #footer2>
        <p class="text-truncate mb0">日访问量
          <span class="ml-sm">1,234</span>
        </p>
      </ng-template>
    </g2-card>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="6">
    <g2-card [title]="'支付笔数'" total="6,560" contentHeight="46px" [action]="action3" [footer]="footer3">
      <ng-template #action3>
        <nz-tooltip [nzTitle]="'指标说明'">
          <i nz-tooltip class="anticon anticon-info-circle-o"></i>
        </nz-tooltip>
      </ng-template>
      <g2-mini-bar height="46" [data]="data.visitData"></g2-mini-bar>
      <ng-template #footer3>
        <p class="text-truncate mb0">转化率
          <span class="ml-sm">60%</span>
        </p>
      </ng-template>
    </g2-card>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="12" nzLg="6">
    <g2-card [title]="'运营活动效果'" total="78%" contentHeight="46px" [action]="action4" [footer]="footer4">
      <ng-template #action4>
        <nz-tooltip [nzTitle]="'指标说明'">
          <i nz-tooltip class="anticon anticon-info-circle-o"></i>
        </nz-tooltip>
      </ng-template>
      <g2-mini-progress height="46" percent="78" strokeWidth="8" target="80" color="#13C2C2"></g2-mini-progress>
      <ng-template #footer4>
        <div class="d-flex justify-content-between">
          <trend flag="up">周同比
            <span class="pl-sm">12%</span>
          </trend>
          <trend flag="down">日环比
            <span class="pl-sm">11%</span>
          </trend>
        </div>
      </ng-template>
    </g2-card>
  </div>
</div>
<nz-card [nzLoading]="loading" [nzBordered]="false" class="ant-card__body-nopadding sales-card">
  <nz-tabset [nzTabBarExtraContent]="extraTemplate">
    <nz-tab nzTitle="销售额">
      <div nz-row>
        <div nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="16">
          <div class="bar">
            <g2-bar height="295" [title]="'销售额趋势'" [data]="data.salesData"></g2-bar>
          </div>
        </div>
        <div nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="8">
          <div class="rank-list">
            <h4 class="rank-title">门店销售额排名</h4>
            <ul>
              <li *ngFor="let i of rankingListData; let idx = index">
                <div>
                  <span class="icon" [ngClass]="{'active': idx < 3}">{{idx+1}}</span>
                  {{i.title}}
                </div>
                <span>{{i.total | number: '3.0'}}</span>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </nz-tab>
    <nz-tab nzTitle="访问量">
      <div nz-row>
        <div nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="16">
          <div class="bar">
            <g2-bar height="295" [title]="'访问量趋势'" [data]="data.salesData"></g2-bar>
          </div>
        </div>
        <div nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="8">
          <div class="rank-list">
            <h4 class="rank-title">门店访问量排名</h4>
            <ul>
              <li *ngFor="let i of rankingListData; let idx = index">
                <div>
                  <span class="icon" [ngClass]="{'active': idx < 3}">{{idx+1}}</span>
                  {{i.title}}
                </div>
                <span>{{i.total | number: '3.0'}}</span>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </nz-tab>
    <ng-template #extraTemplate>
      <div class="sales-extra-wrap">
        <div class="sales-extra">
          <a (click)="setDate('today')">今日</a>
          <a (click)="setDate('week')">本周</a>
          <a (click)="setDate('month')">本月</a>
          <a (click)="setDate('year')">全年</a>
        </div>
        <nz-range-picker [(ngModel)]="date_range" style="display:inline-block; width: 256px;"></nz-range-picker>
      </div>
    </ng-template>
  </nz-tabset>
</nz-card>
<div nz-row [nzGutter]="24">
  <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="12">
    <nz-card [nzLoading]="loading" [nzBordered]="false" nzTitle="线上热门搜索" [nzExtra]="extraOp">
      <ng-template #extraOp>
        <nz-dropdown>
          <i class="anticon anticon-ellipsis" nz-dropdown></i>
          <ul nz-menu>
            <li nz-menu-item>操作一</li>
            <li nz-menu-item>操作二</li>
          </ul>
        </nz-dropdown>
      </ng-template>
      <div nz-row [nzGutter]="64">
        <div nz-col nzXs="24" nzSm="12" class="mb-md">
          <number-info total="12,321" subTotal="17.1" status="up" [subTitle]="subTitle">
            <ng-template #subTitle>
              搜索用户数
              <nz-tooltip [nzTitle]="'指标文案'">
                <i nz-tooltip class="anticon anticon-info-circle-o ml-sm"></i>
              </nz-tooltip>
            </ng-template>
          </number-info>
          <g2-mini-area [line]="true" height="45" [data]="data.visitData2"></g2-mini-area>
        </div>
        <div nz-col nzXs="24" nzSm="12" class="mb-md">
          <number-info subTitle="人均搜索次数" total="2.7" subTotal="26.2" status="down"></number-info>
          <g2-mini-area [line]="true" height="45" [data]="data.visitData2"></g2-mini-area>
        </div>
      </div>
      <simple-table [data]="data.searchData" [columns]="searchColumn" size="small" ps="5" [toTopInChange]="false">
        <ng-template st-row="range" let-i>
          <trend [flag]="i.status === 1 ? 'down' : 'up'">
            <span>{{i.range}}%</span>
          </trend>
        </ng-template>
      </simple-table>
    </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}" [nzExtra]="extra"
      class="sales-card" style="min-height: 482px;">
      <ng-template #extra>
        <div class="sales-card-extra">
          <nz-dropdown>
            <i class="anticon anticon-icon-group" nz-dropdown nzType="ellipsis"></i>
            <ul nz-menu>
              <li nz-menu-item>操作一</li>
              <li nz-menu-item>操作二</li>
            </ul>
          </nz-dropdown>
          <div class="sales-type-radio">
            <nz-radio-group [(ngModel)]="salesType" (ngModelChange)="changeSaleType()">
              <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>
            </nz-radio-group>
          </div>
        </div>
      </ng-template>
      <h4 class="margin:8px 0 32px 0;">销售额</h4>
      <g2-pie [hasLegend]="true" subTitle="销售额" [height]="248" [lineWidth]="4" [total]="salesTotal" [data]="salesPieData" [valueFormat]="handlePieValueFormat">
      </g2-pie>
    </nz-card>
  </div>
</div>
<nz-card [nzLoading]="loading" [nzBordered]="false" [nzBodyStyle]="{'padding': '0 0 32px'}" class="offline-card mt-lg">
  <nz-tabset [(nzSelectedIndex)]="_activeTab" (nzSelectChange)="_tabChange($event)">
    <nz-tab *ngFor="let tab of data.offlineData; let i = index;" [nzTitle]="nzTabHeading">
      <ng-template #nzTabHeading>
        <div nz-row [nzGutter]="8" style="width: 138px; margin: 8px 0;">
          <div nz-col [nzSpan]="12">
            <number-info [title]="tab.name" subTitle="转化率" gap="2" [total]="(tab.cvr * 100) + '%'" [theme]="i !== _activeTab && 'light'"></number-info>
          </div>
          <div nz-col [nzSpan]="12" style="padding-top: 36px;">
            <g2-pie [animate]="false" [color]="i !== _activeTab && '#BDE4FF'" [inner]="0.55" [tooltip]="false" [padding]="[0, 0, 0, 0]"
              [percent]="tab.cvr * 100" [height]="64">
            </g2-pie>
          </div>
        </div>
      </ng-template>
      <div class="px-lg">
        <g2-timeline [data]="tab.chart" [titleMap]="{ y1: '客流量', y2: '支付笔数' }"></g2-timeline>
      </div>
    </nz-tab>
  </nz-tabset>
</nz-card>
src/app/routes/dashboard/analysis/analysis.component.less
New file
@@ -0,0 +1,135 @@
@import 'node_modules/@delon/theme/styles/default';
:host ::ng-deep {
  .icon-group {
    transition: color 0.32s;
    color: @text-color-secondary;
    cursor: pointer;
    margin-left: 16px;
    &:hover {
      color: @text-color;
    }
  }
  .rank-list {
    padding: 0 32px 32px 72px;
    ul {
      margin-top: 25px;
    }
    li {
      zoom: 1;
      margin-top: 16px;
      display: flex;
      justify-content: space-between;
      .icon {
        background-color: #f5f5f5;
        border-radius: 20px;
        display: inline-block;
        font-size: 12px;
        font-weight: 600;
        margin-right: 24px;
        height: 20px;
        line-height: 20px;
        width: 20px;
        text-align: center;
      }
      .active {
        background-color: #314659;
        color: #fff;
      }
    }
  }
  .sales-extra {
    display: inline-block;
    margin-right: 24px;
    a {
      margin-left: 24px;
    }
  }
  .sales-card {
    .bar {
      padding: 0 0 32px 32px;
    }
    .rank {
      padding: 0 32px 32px 72px;
    }
    .ant-tabs-tab {
      padding-top: 16px;
      padding-bottom: 14px;
      line-height: 24px;
    }
    .ant-tabs-extra-content {
      padding-right: 24px;
      line-height: 55px;
    }
    .ant-card-head {
      position: relative;
    }
  }
  .sales-card-extra {
    height: 68px;
  }
  .sales-type-radio {
    position: absolute;
    left: 24px;
    bottom: 15px;
  }
  .offline-card {
    .ant-tabs-ink-bar {
      bottom: auto;
    }
    .ant-tabs-bar {
      border-bottom: none;
    }
    .ant-tabs-nav-container-scrolling {
      padding-left: 40px;
      padding-right: 40px;
    }
    .ant-tabs-tab-prev-icon:before {
      position: relative;
      left: 6px;
    }
    .ant-tabs-tab-next-icon:before {
      position: relative;
      right: 6px;
    }
  }
  .trend-text {
    margin-left: 8px;
    color: @heading-color;
  }
  @media screen and (max-width: @screen-lg) {
    .sales-extra {
      display: none;
    }
    .rank-list {
      li {
        span:first-child {
          margin-right: 8px;
        }
      }
    }
  }
  @media screen and (max-width: @screen-md) {
    .rank-title {
      margin-top: 16px;
    }
    .sales-card .bar {
      padding: 16px;
    }
  }
  @media screen and (max-width: @screen-sm) {
    .sales-extra-wrap {
      display: none;
    }
    .sales-card {
      .ant-tabs-content {
        padding-top: 30px;
      }
    }
  }
  .ant-table-pagination {
    margin-bottom: 0;
  }
}
src/app/routes/dashboard/analysis/analysis.component.ts
New file
@@ -0,0 +1,88 @@
import { Component, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { SimpleTableColumn } from '@delon/abc';
import { getTimeDistance, yuan } from '@delon/util';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'app-dashboard-analysis',
  templateUrl: './analysis.component.html',
  styleUrls: ['./analysis.component.less'],
})
export class DashboardAnalysisComponent implements OnInit {
  data: any = {
    salesData: [],
    offlineData: [],
  };
  loading = true;
  date_range: Date[] = [];
  rankingListData: any[] = Array(7)
    .fill({})
    .map((item, i) => {
      return {
        title: `工专路 ${i} 号店`,
        total: 323234,
      };
    });
  searchColumn: SimpleTableColumn[] = [
    { title: '排名', index: 'index' },
    {
      title: '搜索关键词',
      index: 'keyword',
      click: (item: any) => this.msg.success(item.keyword),
    },
    {
      type: 'number',
      title: '用户数',
      index: 'count',
      sorter: (a, b) => a.count - b.count,
    },
    {
      type: 'number',
      title: '周涨幅',
      index: 'range',
      render: 'range',
      sorter: (a, b) => a.range - b.range,
    },
  ];
  constructor(private http: _HttpClient, public msg: NzMessageService) {}
  ngOnInit() {
    this.http.get('/chart').subscribe((res: any) => {
      res.offlineData.forEach((item: any) => {
        item.chart = Object.assign([], res.offlineChartData);
      });
      this.data = res;
      this.loading = false;
      this.changeSaleType();
    });
  }
  setDate(type: any) {
    this.date_range = getTimeDistance(type);
  }
  salesType = 'all';
  salesPieData: any;
  salesTotal = 0;
  changeSaleType() {
    this.salesPieData =
      this.salesType === 'all'
        ? this.data.salesTypeData
        : this.salesType === 'online'
          ? this.data.salesTypeDataOnline
          : this.data.salesTypeDataOffline;
    if (this.salesPieData)
      this.salesTotal = this.salesPieData.reduce((pre, now) => now.y + pre, 0);
  }
  handlePieValueFormat(value: any) {
    return yuan(value);
  }
  _activeTab = 0;
  _tabChange(value: any) {
    console.log('tab', this._activeTab, value);
  }
}
src/app/routes/dashboard/monitor/monitor.component.html
New file
@@ -0,0 +1,78 @@
<div nz-row [nzGutter]="24" class="pt-lg">
  <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="18">
    <nz-card nzTitle="活动实时交易情况" [nzBordered]="false" class="mb-lg">
      <div nz-row>
        <div nz-col nzXs="24" nzSm="12" nzMd="6">
          <number-info subTitle="今日交易总额" [total]="'124,543,233'" suffix="元"></number-info>
        </div>
        <div nz-col nzXs="24" nzSm="12" nzMd="6">
          <number-info subTitle="销售目标完成率" [total]="'92%'"></number-info>
        </div>
        <div nz-col nzXs="24" nzSm="12" nzMd="6">
          <number-info subTitle="活动剩余时间" [total]="lastTotalTime">
            <ng-template #lastTotalTime>
              <count-down [target]="30"></count-down>
            </ng-template>
          </number-info>
        </div>
        <div nz-col nzXs="24" nzSm="12" nzMd="6">
          <number-info subTitle="每秒交易总额" [total]="234" suffix="元"></number-info>
        </div>
      </div>
      <div class="map-chart">
        <nz-tooltip [nzTitle]="'等待后期实现'">
          <img nz-tooltip src="https://gw.alipayobjects.com/zos/rmsportal/HBWnDEUXCnGnGrRfrpKa.png" alt="map" />
        </nz-tooltip>
      </div>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="6">
    <nz-card nzTitle="活动情况预测" [nzBordered]="false" class="mb-lg">
      <div class="active-chart">
        <number-info subTitle="目标评估" total="有望达到预期"></number-info>
        <g2-mini-area [animate]="false" [line]="true" [borderWidth]="2" [height]="84" [yAxis]="activeYAxis" [data]="activeData"></g2-mini-area>
        <ng-container *ngIf="activeData?.length > 0">
          <div class="active-grid">
            <p>{{activeStat.max}} 亿元</p>
            <p>{{activeStat.min}} 亿元</p>
          </div>
          <div class="active-legend">
            <span>00:00</span>
            <span>{{activeStat.t1}}</span>
            <span>{{activeStat.t2}}</span>
          </div>
        </ng-container>
      </div>
    </nz-card>
    <nz-card nzTitle="券核效率" [nzBordered]="false" [nzBodyStyle]="{'text-align': 'center'}" class="mb-lg">
      <g2-gauge [title]="'跳出率'" [height]="180" [percent]="87" [format]="couponFormat"></g2-gauge>
    </nz-card>
  </div>
</div>
<div nz-row [nzGutter]="24">
  <div nz-col nzXs="24" nzSm="24" nzLg="12" class="mb-lg">
    <nz-card nzTitle="各品类占比" [nzBordered]="false" class="pie-card">
      <div nz-row [nzGutter]="4" style="padding:16px 0">
        <div nz-col [nzSpan]="8">
          <g2-pie [animate]="false" [percent]="28" subTitle="中式快餐" total="28%" [height]="128" [lineWidth]="2"></g2-pie>
        </div>
        <div nz-col [nzSpan]="8">
          <g2-pie [animate]="false" color="#5DDECF" [percent]="22" subTitle="西餐" total="22%" [height]="128" [lineWidth]="2"></g2-pie>
        </div>
        <div nz-col [nzSpan]="8">
          <g2-pie [animate]="false" color="#2FC25B" [percent]="32" subTitle="火锅" total="32%" [height]="128" [lineWidth]="2"></g2-pie>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzSm="24" nzLg="6" class="mb-lg">
    <nz-card nzTitle="热门搜索" [nzBordered]="false" [nzBodyStyle]="{'overflow': 'hidden'}">
      <g2-tag-cloud [data]="tags" [height]="165"></g2-tag-cloud>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzSm="24" nzLg="6" class="mb-lg">
    <nz-card nzTitle="资源剩余" [nzBordered]="false" [nzBodyStyle]="{'overflow': 'hidden'}">
      <g2-water-wave [title]="'补贴资金剩余'" [percent]="34" [height]="165"></g2-water-wave>
    </nz-card>
  </div>
</div>
src/app/routes/dashboard/monitor/monitor.component.less
New file
@@ -0,0 +1,58 @@
@import 'node_modules/@delon/theme/styles/default';
:host ::ng-deep {
  .map-chart {
    padding-top: 24px;
    height: 457px;
    text-align: center;
    img {
      display: inline-block;
      max-width: 100%;
      max-height: 437px;
    }
  }
  .pie-card {
    .pie-stat {
      font-size: 24px !important;
    }
  }
  .active-chart {
    position: relative;
    g2-mini-area {
      margin-top: 32px;
    }
    .active-grid {
      p {
        position: absolute;
        top: 80px;
      }
      p:last-child {
        top: 115px;
      }
    }
    .active-legend {
      position: relative;
      font-size: 0;
      margin-top: 8px;
      height: 20px;
      line-height: 20px;
      span {
        display: inline-block;
        font-size: 12px;
        text-align: center;
        width: 33.33%;
      }
      span:first-child {
        text-align: left;
      }
      span:last-child {
        text-align: right;
      }
    }
  }
  @media screen and (max-width: @screen-lg) {
    .map-chart {
      height: auto;
    }
  }
}
src/app/routes/dashboard/monitor/monitor.component.ts
New file
@@ -0,0 +1,99 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { zip } from 'rxjs';
import { getTimeDistance, yuan } from '@delon/util';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'app-dashboard-monitor',
  templateUrl: './monitor.component.html',
  styleUrls: ['./monitor.component.less'],
})
export class DashboardMonitorComponent implements OnInit, OnDestroy {
  data: any = {};
  tags = [];
  loading = true;
  q: any = {
    start: null,
    end: null,
  };
  constructor(private http: _HttpClient, public msg: NzMessageService) {}
  ngOnInit() {
    zip(this.http.get('/chart'), this.http.get('/chart/tags')).subscribe(
      ([res, tags]: [any, any]) => {
        this.data = res;
        tags.list[
          Math.floor(Math.random() * tags.list.length) + 1
        ].value = 1000;
        this.tags = tags.list;
        this.loading = false;
      },
    );
    // active chart
    this.genActiveData();
    this.activeTime$ = setInterval(() => this.genActiveData(), 1000);
  }
  // region: active chart
  activeTime$: any;
  activeYAxis = {
    tickCount: 3,
    tickLine: false,
    labels: false,
    title: false,
    line: false,
  };
  activeData: any[] = [];
  activeStat = {
    max: 0,
    min: 0,
    t1: '',
    t2: '',
  };
  genActiveData() {
    const activeData = [];
    for (let i = 0; i < 24; i += 1) {
      activeData.push({
        x: `${i.toString().padStart(2, '0')}:00`,
        y: i * 50 + Math.floor(Math.random() * 200),
      });
    }
    this.activeData = activeData;
    // stat
    this.activeStat.max = [...activeData].sort()[activeData.length - 1].y + 200;
    this.activeStat.min = [...activeData].sort()[
      Math.floor(activeData.length / 2)
    ].y;
    this.activeStat.t1 = activeData[Math.floor(activeData.length / 2)].x;
    this.activeStat.t2 = activeData[activeData.length - 1].x;
  }
  // endregion
  couponFormat(val: any) {
    switch (parseInt(val, 10)) {
      case 20:
        return '差';
      case 40:
        return '中';
      case 60:
        return '良';
      case 80:
        return '优';
      default:
        return '';
    }
  }
  ngOnDestroy(): void {
    if (this.activeTime$) clearInterval(this.activeTime$);
  }
}
src/app/routes/dashboard/v1/v1.component.html
New file
@@ -0,0 +1,150 @@
<div class="content__title">
  <h1>
    Dashboard
    <small>Welcome !</small>
  </h1>
</div>
<quick-menu>
  <nz-list [nzBordered]="false" [nzSplit]="false">
    <nz-list-item>
      <a routerLink="/">Home</a>
    </nz-list-item>
    <nz-list-item>
      <a routerLink="/widgets">Widgets</a>
    </nz-list-item>
    <nz-list-item>
      <a routerLink="/style/typography">typography</a>
    </nz-list-item>
    <nz-list-item>
      <a routerLink="/style/gridmasonry">gridmasonry</a>
    </nz-list-item>
    <nz-list-item>
      <a routerLink="/pro/result/success">success result</a>
    </nz-list-item>
  </nz-list>
</quick-menu>
<div nz-row nzGutter="16">
  <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="12" class="p-md text-white">
        <div class="h2 mt0">123,456</div>
        <p class="text-nowrap mb0">Website Traffics</p>
      </div>
      <div nz-col nzSpan="12">
        <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="webSite"></g2-mini-bar>
      </div>
    </div>
  </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="12" class="p-md text-white">
        <div class="h2 mt0">234,567K</div>
        <p class="text-nowrap mb0">Website Impressions</p>
      </div>
      <div nz-col nzSpan="12">
        <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="webSite"></g2-mini-bar>
      </div>
    </div>
  </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="12" class="p-md text-white">
        <div class="h2 mt0">$458,778</div>
        <p class="text-nowrap mb0">Total Sales</p>
      </div>
      <div nz-col nzSpan="12">
        <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="webSite"></g2-mini-bar>
      </div>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-magenta rounded-md">
      <div nz-col nzSpan="12" class="p-md text-white">
        <div class="h2 mt0">456</div>
        <p class="text-nowrap mb0">Support Tickets</p>
      </div>
      <div nz-col nzSpan="12">
        <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="webSite"></g2-mini-bar>
      </div>
    </div>
  </div>
</div>
<div nz-row nzGutter="16">
  <div nz-col nzXs="24" nzMd="12">
    <nz-card [nzBordered]="false" [nzTitle]="title">
      <ng-template #title>
        Sales Statistics
        <small class="text-sm font-weight-normal">Business Expectations & Retail Sales Statistics</small>
      </ng-template>
      <g2-bar height="275" [data]="salesData"></g2-bar>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzMd="12">
    <nz-card [nzTitle]="title" [nzBordered]="false">
      <ng-template #title>
        Growth Rate
        <small class="text-sm font-weight-normal">Business Expectations & Retail Sales Statistics</small>
      </ng-template>
      <g2-timeline [data]="offlineChartData" [height]="239" [padding]="[0, 0, 0, 0]" [titleMap]="{ y1: '客流量', y2: '支付笔数' }"></g2-timeline>
    </nz-card>
  </div>
</div>
<div nz-row nzGutter="16">
  <div nz-col nzXs="24" nzMd="12">
    <nz-card [nzBordered]="false" class="ant-card__img">
      <img class="img" src="//os.alipayobjects.com/rmsportal/GhjqstwSgxBXrZS.png">
      <div class="p-md">
        <h3>ANT DESIGN</h3>
        <p class="text-grey">A UI Design Language</p>
        <ol class="list-styled text-lg pt-md">
          <li>Designed by experienced team, and showcase dozens of inspiring projects.</li>
          <li>Provide solutions for usual problems that may be encountered while developing enterprise-like complex UIs.</li>
          <li>Dozens of flexible and practical reusable components that increase your productivity.</li>
        </ol>
        <p class="pt-md">
          <a class="text-grey" href="//ng.ant.design" target="_blank">View Site...</a>
        </p>
      </div>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzMd="12">
    <nz-card [nzTitle]="title" [nzBordered]="false" class="ant-card__body-nopadding">
      <ng-template #title>
        Recent Posts
        <small class="text-sm font-weight-normal">Venenatis portauam Inceptos ameteiam</small>
      </ng-template>
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point" *ngFor="let item of todoData">
        <div nz-col [nzSpan]="4" class="text-center">
          <nz-avatar [nzSrc]="'./assets/tmp/img/' + item.avatar + '.png'"></nz-avatar>
        </div>
        <div nz-col [nzSpan]="20">
          <strong>{{item.name}}</strong>
          <p class="mb0">{{item.content}}</p>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzMd="12">
    <nz-card nzTitle="Todo lists" [nzBordered]="false" class="ant-card__body-nopadding">
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point" *ngFor="let item of todoData">
        <div nz-col [nzSpan]="4" class="text-center">
          <nz-avatar [nzSrc]="'./assets/tmp/img/' + item.avatar + '.png'"></nz-avatar>
        </div>
        <div nz-col [nzSpan]="18">
          <strong>{{item.name}}</strong>
          <p [class.text-deleted]="item.completed" class="mb0">{{item.content}}</p>
        </div>
        <div nz-col [nzSpan]="2" class="text-right pr-md">
          <nz-dropdown [nzPlacement]="'topRight'">
            <i nz-dropdown class="icon-options-vertical"></i>
            <ul nz-menu>
              <li nz-menu-item *ngIf="item.completed" (click)="item.completed=false">Active</li>
              <li nz-menu-item *ngIf="!item.completed" (click)="item.completed=true">Completed</li>
              <li nz-menu-item (click)="todoData.splice(todoData.indexOf(item), 1)">Delted</li>
            </ul>
          </nz-dropdown>
        </div>
      </div>
    </nz-card>
  </div>
</div>
src/app/routes/dashboard/v1/v1.component.spec.ts
New file
@@ -0,0 +1,16 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { DashboardV1Component } from './v1.component';
describe('Comoponent: DashboardV1', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [DashboardV1Component],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(DashboardV1Component);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/dashboard/v1/v1.component.ts
New file
@@ -0,0 +1,62 @@
import { NzMessageService } from 'ng-zorro-antd';
import { Component, OnInit } from '@angular/core';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'app-dashboard-v1',
  templateUrl: './v1.component.html',
})
export class DashboardV1Component implements OnInit {
  constructor(private http: _HttpClient, public msg: NzMessageService) {}
  todoData: any[] = [
    {
      completed: true,
      avatar: '1',
      name: '苏先生',
      content: `请告诉我,我应该说点什么好?`,
    },
    {
      completed: false,
      avatar: '2',
      name: 'はなさき',
      content: `ハルカソラトキヘダツヒカリ`,
    },
    {
      completed: false,
      avatar: '3',
      name: 'cipchk',
      content: `this world was never meant for one as beautiful as you.`,
    },
    {
      completed: false,
      avatar: '4',
      name: 'Kent',
      content: `my heart is beating with hers`,
    },
    {
      completed: false,
      avatar: '5',
      name: 'Are you',
      content: `They always said that I love beautiful girl than my friends`,
    },
    {
      completed: false,
      avatar: '6',
      name: 'Forever',
      content: `Walking through green fields ,sunshine in my eyes.`,
    },
  ];
  webSite: any[] = [];
  salesData: any[] = [];
  offlineChartData: any[] = [];
  ngOnInit() {
    this.http.get('/chart').subscribe((res: any) => {
      this.webSite = res.visitData.slice(0, 10);
      this.salesData = res.salesData;
      this.offlineChartData = res.offlineChartData;
    });
  }
}
src/app/routes/dashboard/workplace/workplace.component.html
New file
@@ -0,0 +1,111 @@
<page-header>
  <ng-template #breadcrumb>
    <nz-breadcrumb>
      <nz-breadcrumb-item>
        <a [routerLink]="['/']">首页</a>
      </nz-breadcrumb-item>
      <nz-breadcrumb-item>
        <a [routerLink]="['/']">Dashboard</a>
      </nz-breadcrumb-item>
      <nz-breadcrumb-item>工作台</nz-breadcrumb-item>
    </nz-breadcrumb>
  </ng-template>
  <ng-template #content>
    <div class="page-header">
      <div class="avatar">
        <nz-avatar nzSrc="https://gw.alipayobjects.com/zos/rmsportal/lctvVCLfRpYCkYxAsiVQ.png"></nz-avatar>
      </div>
      <div class="desc">
        <div class="desc-title">早安,山治,我要吃肉!</div>
        <div>假砖家 | 地球-伟大航道-黄金梅丽号-厨房-小强部门</div>
      </div>
    </div>
  </ng-template>
  <ng-template #extra>
    <div class="page-extra">
      <div>
        <p>项目数</p>
        <p>56</p>
      </div>
      <div>
        <p>团队内排名</p>
        <p>8
          <span> / 24</span>
        </p>
      </div>
      <div>
        <p>项目访问</p>
        <p>2,223</p>
      </div>
    </div>
  </ng-template>
</page-header>
<div nz-row [nzGutter]="24">
  <div nz-col nzXs="24" nzSm="24" nzMd="16">
    <nz-card nzTitle="进行中的项目" [nzBordered]="false" [nzLoading]="loading" class="ant-card__body-nopadding mb-lg project-list">
      <ng-template #extra>
        <a (click)="msg.success('to')">全部项目</a>
      </ng-template>
      <div *ngFor="let item of notice" nz-card-grid class="project-grid">
        <nz-card [nzBordered]="false" class="ant-card__body-nopadding mb0">
          <nz-card-meta [nzTitle]="noticeTitle" [nzDescription]="item.description">
            <ng-template #noticeTitle>
              <div class="card-title">
                <nz-avatar [nzSrc]="item.logo" [nzSize]="'small'"></nz-avatar>
                <a (click)="msg.info('to' + item.href)">{{item.title}}</a>
              </div>
            </ng-template>
          </nz-card-meta>
          <div class="project-item">
            <a (click)="msg.info('show user: ' + item.member)">{{item.member}}</a>
            <span *ngIf="item.updatedAt" class="datetime" title="{{item.updatedAt}}">
              {{item.updatedAt | _date: 'fn' }}
            </span>
          </div>
        </nz-card>
      </div>
    </nz-card>
    <nz-card nzTitle="动态" [nzBordered]="false" [nzLoading]="loading" class="ant-card__body-nopadding mb-lg active-card">
      <nz-list nzSize="large" class="activities">
        <nz-list-item *ngFor="let item of activities">
          <nz-list-item-meta [nzAvatar]="item.user.avatar" [nzTitle]="activeTitle" [nzDescription]="activeDescription">
            <ng-template #activeTitle>
              <a (click)="msg.success(item.user.name)" class="username">{{item.user.name}}</a>
              &nbsp;
              <span class="event" [innerHTML]="item.template"></span>
            </ng-template>
            <ng-template #activeDescription>
              <span class="datetime" title="{{item.updatedAt}}">{{item.updatedAt | _date: 'fn'}}</span>
            </ng-template>
          </nz-list-item-meta>
        </nz-list-item>
      </nz-list>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzSm="24" nzMd="8">
    <nz-card nzTitle="快速开始 / 便捷导航" [nzBordered]="false" class="ant-card__body-nopadding mb-lg">
      <div class="links">
        <a *ngFor="let item of links" (click)="msg.success(item.title)">{{item.title}}</a>
        <button nz-button (click)="links.push({title: 'new titel', href: 'href'})" [nzType]="'dashed'" [nzSize]="'small'">
          <i class="anticon anticon-plus"></i>
          <span>添加</span>
        </button>
      </div>
    </nz-card>
    <nz-card nzTitle="XX 指数" [nzBordered]="false" [nzLoading]="loading" class="mb-lg">
      <g2-radar [data]="radarData" [height]="343" [hasLegend]="true"></g2-radar>
    </nz-card>
    <nz-card nzTitle="团队" [nzBordered]="false" [nzBodyStyle]="{'padding-top.px': 12, 'padding-bottom.px': 12 }" class="mb-lg">
      <div class="members">
        <div nz-row [nzGutter]="48">
          <div nz-col [nzSpan]="12" *ngFor="let i of members">
            <a (click)="msg.success(i.title)">
              <nz-avatar [nzSrc]="i.logo" [nzSize]="'small'"></nz-avatar>
              <span class="member">{{i.title}}</span>
            </a>
          </div>
        </div>
      </div>
    </nz-card>
  </div>
</div>
src/app/routes/dashboard/workplace/workplace.component.less
New file
@@ -0,0 +1,240 @@
@import 'node_modules/@delon/theme/styles/default';
:host ::ng-deep {
  .page-header {
    display: flex;
    .avatar {
      flex: 0 1 72px;
      margin-bottom: 8px;
      .ant-avatar {
        border-radius: 72px;
        display: block;
        width: 72px;
        height: 72px;
      }
    }
    .desc {
      position: relative;
      top: 4px;
      margin-left: 24px;
      flex: 1 1 auto;
      color: @text-color-secondary;
      line-height: 22px;
      .desc-title {
        font-size: 20px;
        line-height: 28px;
        font-weight: 500;
        color: @heading-color;
        margin-bottom: 12px;
      }
    }
  }
  .page-extra {
    .clearfix();
    float: right;
    white-space: nowrap;
    & > div {
      padding: 0 32px;
      position: relative;
      display: inline-block;
      & > p:first-child {
        color: @text-color-secondary;
        font-size: @font-size-base;
        line-height: 22px;
        margin-bottom: 4px;
      }
      & > p {
        color: @heading-color;
        font-size: 30px;
        line-height: 38px;
        margin: 0;
        & > span {
          color: @text-color-secondary;
          font-size: 20px;
        }
      }
      &:after {
        background-color: @border-color-split;
        position: absolute;
        top: 8px;
        right: 0;
        width: 1px;
        height: 40px;
        content: '';
      }
    }
    & > div:last-child {
      padding-right: 0;
      &:after {
        display: none;
      }
    }
  }
  .project-list {
    .ant-card-meta-description {
      color: @text-color-secondary;
      height: 44px;
      line-height: 22px;
      overflow: hidden;
    }
    .card-title {
      font-size: 0;
      a {
        color: @heading-color;
        margin-left: 12px;
        line-height: 24px;
        height: 24px;
        display: inline-block;
        vertical-align: top;
        font-size: @font-size-base;
        &:hover {
          color: @primary-color;
        }
      }
    }
    .project-grid {
      width: 33.33%;
    }
    .project-item {
      display: flex;
      margin-top: 8px;
      overflow: hidden;
      font-size: 12px;
      height: 20px;
      line-height: 20px;
      .textOverflow();
      a {
        color: @text-color-secondary;
        display: inline-block;
        flex: 1 1 0;
        .textOverflow();
        &:hover {
          color: @primary-color;
        }
      }
      .datetime {
        color: @disabled-color;
        flex: 0 0 auto;
        float: right;
      }
    }
  }
  .activities {
    padding: 0 24px 8px;
    .username {
      color: @text-color;
    }
    .event {
      font-weight: normal;
    }
  }
  .members {
    a {
      display: block;
      margin: 12px 0;
      line-height: 24px;
      height: 24px;
      .textOverflow();
      .member {
        font-size: @font-size-base;
        color: @text-color;
        line-height: 24px;
        max-width: 100px;
        vertical-align: top;
        margin-left: 12px;
        transition: all 0.3s;
        display: inline-block;
        .textOverflow();
      }
      &:hover {
        span {
          color: @primary-color;
        }
      }
    }
  }
  .datetime {
    color: @disabled-color;
  }
  .links {
    padding: 20px 0 8px 24px;
    font-size: 0;
    > a {
      color: @text-color;
      display: inline-block;
      font-size: @font-size-base;
      margin-bottom: 13px;
      width: 25%;
      &:hover {
        color: @primary-color;
      }
    }
  }
  @media screen and (max-width: @screen-xl) and (min-width: @screen-lg) {
    .active-card {
      margin-bottom: 24px;
    }
    .members {
      margin-bottom: 0;
    }
    .page-extra {
      margin-left: -44px;
      & > div {
        padding: 0 16px;
      }
    }
  }
  @media screen and (max-width: @screen-lg) {
    .active-card {
      margin-bottom: 24px;
    }
    .members {
      margin-bottom: 0;
    }
    .page-extra {
      float: none;
      margin-right: 0;
      & > div {
        padding: 0 16px;
        text-align: left;
        &:after {
          display: none;
        }
      }
    }
  }
  @media screen and (max-width: @screen-md) {
    .page-extra {
      margin-left: -16px;
    }
    .project-list {
      .project-grid {
        width: 50%;
      }
    }
  }
  @media screen and (max-width: @screen-sm) {
    .page-header {
      display: block;
      .desc {
        margin-left: 0;
      }
    }
    .page-extra {
      & > div {
        float: none;
      }
    }
  }
  @media screen and (max-width: @screen-xs) {
    .project-list {
      .project-grid {
        width: 100%;
      }
    }
  }
}
src/app/routes/dashboard/workplace/workplace.component.ts
New file
@@ -0,0 +1,114 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { zip } from 'rxjs';
import { NzMessageService } from 'ng-zorro-antd';
import { getTimeDistance, yuan } from '@delon/util';
import { _HttpClient } from '@delon/theme';
import { JWTTokenModel } from '@delon/auth';
@Component({
  selector: 'app-dashboard-workplace',
  templateUrl: './workplace.component.html',
  styleUrls: ['./workplace.component.less'],
})
export class DashboardWorkplaceComponent implements OnInit, OnDestroy {
  notice: any[] = [];
  activities: any[] = [];
  radarData: any[] = [];
  loading = true;
  // region: mock data
  links = [
    {
      title: '操作一',
      href: '',
    },
    {
      title: '操作二',
      href: '',
    },
    {
      title: '操作三',
      href: '',
    },
    {
      title: '操作四',
      href: '',
    },
    {
      title: '操作五',
      href: '',
    },
    {
      title: '操作六',
      href: '',
    },
  ];
  members = [
    {
      id: 'members-1',
      title: '科学搬砖组',
      logo:
        'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
      link: '',
    },
    {
      id: 'members-2',
      title: '程序员日常',
      logo:
        'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
      link: '',
    },
    {
      id: 'members-3',
      title: '设计天团',
      logo:
        'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png',
      link: '',
    },
    {
      id: 'members-4',
      title: '中二少女团',
      logo:
        'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png',
      link: '',
    },
    {
      id: 'members-5',
      title: '骗你学计算机',
      logo:
        'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
      link: '',
    },
  ];
  // endregion
  constructor(private http: _HttpClient, public msg: NzMessageService) {}
  ngOnInit() {
    this.http.get('user-context').subscribe(
      res => {
          console.log(res);
      }
    );
    zip(
      this.http.get('/chart'),
      this.http.get('/api/notice'),
      this.http.get('/api/activities'),
    ).subscribe(([chart, notice, activities]: [any, any, any]) => {
      this.radarData = chart.radarData;
      this.notice = notice;
      this.activities = activities.map((item: any) => {
        item.template = item.template
          .split(/@\{([^{}]*)\}/gi)
          .map((key: string) => {
            if (item[key]) return `<a>${item[key].name}</a>`;
            return key;
          });
        return item;
      });
      this.loading = false;
    });
  }
  ngOnDestroy(): void {}
}
src/app/routes/data-v/data-v-routing.module.ts
New file
@@ -0,0 +1,11 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RelationComponent } from './relation/relation.component';
const routes: Routes = [{ path: 'relation', component: RelationComponent }];
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class DataVRoutingModule {}
src/app/routes/data-v/data-v.module.ts
New file
@@ -0,0 +1,11 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '@shared/shared.module';
import { DataVRoutingModule } from './data-v-routing.module';
import { RelationComponent } from './relation/relation.component';
@NgModule({
  imports: [SharedModule, DataVRoutingModule],
  declarations: [RelationComponent],
})
export class DataVModule {}
src/app/routes/data-v/relation/relation.component.html
copy from src/app/routes/home-page/home-page/home-page.component.less copy to src/app/routes/data-v/relation/relation.component.html
src/app/routes/data-v/relation/relation.component.less
src/app/routes/data-v/relation/relation.component.ts
New file
@@ -0,0 +1,169 @@
import { Component, OnDestroy, ViewEncapsulation, OnInit } from '@angular/core';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'app-data-v-relation',
  templateUrl: './relation.component.html',
  styleUrls: ['./relation.component.less'],
})
export class RelationComponent implements OnInit, OnDestroy {
  ecIntance: any;
  options: any = {
    title: {
      text: 'User Releaction',
    },
    tooltip: {},
    animationDurationUpdate: 1500,
    animationEasingUpdate: 'quinticInOut',
    series: [
      {
        type: 'graph',
        layout: 'force',
        symbolSize: 60,
        focusNodeAdjacency: true,
        roam: true,
        categories: [
          {
            name: 'User',
          },
        ],
        label: {
          normal: {
            show: true,
            textStyle: {
              fontSize: 12,
            },
          },
        },
        force: {
          repulsion: 2000,
          gravity: 0.3,
        },
        edgeSymbol: ['circle', 'arrow'],
        edgeSymbolSize: [4, 10],
        draggable: true,
        tooltip: {
          triggerOn: 'click',
          formatter: item => {
            if (item.dataType === 'node')
              return `${item.data.name}:${item.data.arg}`;
            return item.name;
          },
        },
        data: Array(20)
          .fill({})
          .map((v, i) => {
            return {
              name: 'User' + i,
              arg: i + 10,
              category: 0,
            };
          }),
        links: [
          {
            source: 'User0',
            target: 'User1',
          },
          {
            source: 'User0',
            target: 'User2',
          },
          {
            source: 'User0',
            target: 'User3',
          },
          {
            source: 'User1',
            target: 'User4',
          },
          {
            source: 'User2',
            target: 'User5',
          },
          {
            source: 'User3',
            target: 'User6',
          },
          {
            source: 'User4',
            target: 'User7',
          },
          {
            source: 'User5',
            target: 'User8',
          },
          {
            source: 'User6',
            target: 'User9',
          },
          {
            source: 'User1',
            target: 'User10',
          },
          {
            source: 'User1',
            target: 'User11',
          },
          {
            source: 'User11',
            target: 'User12',
          },
          {
            source: 'User11',
            target: 'User13',
          },
          {
            source: 'User11',
            target: 'User14',
          },
          {
            source: 'User11',
            target: 'User15',
          },
          {
            source: 'User11',
            target: 'User16',
          },
          {
            source: 'User11',
            target: 'User17',
          },
          {
            source: 'User11',
            target: 'User18',
          },
          {
            source: 'User11',
            target: 'User19',
          },
        ],
        lineStyle: {
          normal: {
            opacity: 0.7,
            width: 1,
            curveness: 0.1,
          },
        },
      },
    ],
  };
  constructor(private http: _HttpClient) {}
  chartInit(ec) {
    this.ecIntance = ec;
  }
  ngOnInit() {
    window.addEventListener('resize', () => this.resize);
  }
  private resize() {
    if (this.ecIntance) this.ecIntance.resize();
  }
  ngOnDestroy(): void {
    window.removeEventListener('resize', () => this.resize);
  }
}
src/app/routes/delon/acl/acl.component.html
New file
@@ -0,0 +1,43 @@
<div class="content__title">
  <h1>
    ACL 访问控制
    <small>注意观察左边的菜单;ACLService提供一个完整的基于角色的访问控制的服务,若需要支持路由守卫,请配合ACLService与Route Guard配合简便实现。</small>
  </h1>
</div>
<page-header [title]="'asdfasdf'"></page-header>
<nz-card nzTitle="标题">
  klsjdf
</nz-card>
<div nz-row [nzGutter]="8">
  <div nz-col [nzSpan]="24">
    <nz-card nzTitle="按钮粒度">
      ACL原始数据:{{ aclSrv.data | json }}
      <button nz-button [acl]="'role-a'">role-a</button>
      <button nz-button [acl]="'role-b'" class="ml-sm">role-b</button>
    </nz-card>
  </div>
</div>
<div nz-row [nzGutter]="8">
  <div nz-col [nzSpan]="8">
    <nz-card nzTitle="全量">
      <button nz-button (click)="toggleFull()">
        <span>{{ full ? '离开' : '设置'}}权限</span>
      </button>
      <p class="pt-md">全量类指系统管理员角色,无任何受限。</p>
    </nz-card>
  </div>
  <div nz-col [nzSpan]="8">
    <nz-card nzTitle="角色[role-a]">
      <button nz-button (click)="toggleRoleA()">
        <span>{{ roleA.length > 0 ? '离开' : '设置'}}权限</span>
      </button>
    </nz-card>
  </div>
  <div nz-col [nzSpan]="8">
    <nz-card nzTitle="角色[role-b]">
      <button nz-button (click)="toggleRoleB()">
        <span>{{ roleB.length > 0 ? '离开' : '设置'}}权限</span>
      </button>
    </nz-card>
  </div>
</div>
src/app/routes/delon/acl/acl.component.spec.ts
New file
@@ -0,0 +1,16 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { ACLComponent } from './acl.component';
describe('Comoponent: ACL', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [ACLComponent],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(ACLComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/delon/acl/acl.component.ts
New file
@@ -0,0 +1,41 @@
import { Component } from '@angular/core';
import { ACLService } from '@delon/acl';
import { MenuService } from '@delon/theme';
@Component({
  selector: 'app-acl',
  templateUrl: './acl.component.html',
})
export class ACLComponent {
  full = true;
  roleA = '';
  roleB = '';
  constructor(public aclSrv: ACLService, private menuSrv: MenuService) {}
  private reMenu() {
    this.menuSrv.resume();
  }
  toggleFull() {
    this.full = !this.full;
    this.aclSrv.setFull(this.full);
    this.reMenu();
  }
  toggleRoleA() {
    this.full = false;
    this.roleA = this.roleA === 'role-a' ? '' : 'role-a';
    this.aclSrv.setFull(this.full);
    this.aclSrv.setRole([this.roleA]);
    this.reMenu();
  }
  toggleRoleB() {
    this.full = false;
    this.roleB = this.roleB === 'role-b' ? '' : 'role-b';
    this.aclSrv.setFull(this.full);
    this.aclSrv.setRole([this.roleB]);
    this.reMenu();
  }
}
src/app/routes/delon/cache/cache.component.html
New file
@@ -0,0 +1,10 @@
<div class="content__title">
  <h1>
    Cache 缓存,
    <a href="http://ng-alain.com/components/cache" target="_blank">Document</a>
  </h1>
</div>
<nz-card nzTitle="Service">
  <button nz-button (click)="set()">设置</button>
  <button nz-button (click)="get()" class="ml-sm">获取</button>
</nz-card>
src/app/routes/delon/cache/cache.component.ts
New file
@@ -0,0 +1,24 @@
import { Component, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { CacheService } from '@delon/cache';
@Component({
  selector: 'app-cache',
  templateUrl: './cache.component.html',
  styles: [],
})
export class CacheComponent implements OnInit {
  KEY = 'user';
  constructor(public cache: CacheService, public msg: NzMessageService) {}
  ngOnInit() {}
  set() {
    this.cache.set(this.KEY, +new Date());
  }
  get() {
    this.msg.success(this.cache.getNone(this.KEY));
  }
}
src/app/routes/delon/delon-routing.module.ts
New file
@@ -0,0 +1,61 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ACLGuard } from '@delon/acl';
import { SimpleTableComponent } from './simple-table/simple-table.component';
import { UtilComponent } from './util/util.component';
import { PrintComponent } from './print/print.component';
import { ACLComponent } from './acl/acl.component';
import { GuardComponent } from './guard/guard.component';
import { GuardLeaveComponent } from './guard/leave.component';
import { GuardAuthComponent } from './guard/auth.component';
import { GuardAdminComponent } from './guard/admin.component';
import { CanLeaveProvide } from './guard/can-leave.provide';
import { CacheComponent } from './cache/cache.component';
import { DownFileComponent } from './downfile/downfile.component';
import { XlsxComponent } from './xlsx/xlsx.component';
import { ZipComponent } from './zip/zip.component';
import { DelonFormComponent } from './form/form.component';
import { QRComponent } from './qr/qr.component';
const routes: Routes = [
  { path: 'simple-table', component: SimpleTableComponent },
  { path: 'util', component: UtilComponent },
  { path: 'print', component: PrintComponent },
  { path: 'acl', component: ACLComponent },
  {
    path: 'guard',
    component: GuardComponent,
    children: [
      {
        path: 'leave',
        component: GuardLeaveComponent,
        canDeactivate: [CanLeaveProvide],
      },
      {
        path: 'auth',
        component: GuardAuthComponent,
        canActivate: [ACLGuard],
        data: { guard: 'user1' },
      },
      {
        path: 'admin',
        component: GuardAdminComponent,
        canActivate: [ACLGuard],
        data: { guard: 'admin' },
      },
    ],
  },
  { path: 'cache', component: CacheComponent },
  { path: 'qr', component: QRComponent },
  { path: 'downfile', component: DownFileComponent },
  { path: 'xlsx', component: XlsxComponent },
  { path: 'zip', component: ZipComponent },
  { path: 'form', component: DelonFormComponent },
];
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class DelonRoutingModule {}
src/app/routes/delon/delon.module.ts
New file
@@ -0,0 +1,48 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
import { DelonRoutingModule } from './delon-routing.module';
import { SimpleTableComponent } from './simple-table/simple-table.component';
import { UtilComponent } from './util/util.component';
import { PrintComponent } from './print/print.component';
import { ACLComponent } from './acl/acl.component';
import { CanLeaveProvide } from './guard/can-leave.provide';
import { GuardComponent } from './guard/guard.component';
import { GuardLeaveComponent } from './guard/leave.component';
import { GuardAdminComponent } from './guard/admin.component';
import { GuardAuthComponent } from './guard/auth.component';
import { CacheComponent } from './cache/cache.component';
import { DownFileComponent } from './downfile/downfile.component';
import { XlsxComponent } from './xlsx/xlsx.component';
import { ZipComponent } from './zip/zip.component';
import { DelonFormComponent } from './form/form.component';
import { QRComponent } from './qr/qr.component';
const COMPONENT = [
  SimpleTableComponent,
  UtilComponent,
  PrintComponent,
  ACLComponent,
  GuardComponent,
  GuardLeaveComponent,
  GuardAdminComponent,
  GuardAuthComponent,
  CacheComponent,
  DownFileComponent,
  XlsxComponent,
  ZipComponent,
  DelonFormComponent,
  QRComponent,
];
const COMPONENT_NOROUNT = [];
@NgModule({
  imports: [CommonModule, SharedModule, DelonRoutingModule],
  providers: [CanLeaveProvide],
  declarations: [...COMPONENT, ...COMPONENT_NOROUNT],
  entryComponents: COMPONENT_NOROUNT,
})
export class DelonModule {}
src/app/routes/delon/downfile/downfile.component.html
New file
@@ -0,0 +1,6 @@
<div class="content__title">
  <h1>Download a file</h1>
</div>
<nz-card nzTitle="DEMO">
  <button nz-button *ngFor="let i of fileTypes" class="mr-sm" down-file [http-data]="data" http-url="assets/tmp/demo{{i}}" file-name="demo中文">{{i}}</button>
</nz-card>
src/app/routes/delon/downfile/downfile.component.spec.ts
New file
@@ -0,0 +1,16 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { DownFileComponent } from './downfile.component';
describe('Comoponent: DownFile', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [DownFileComponent],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(DownFileComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/delon/downfile/downfile.component.ts
New file
@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
@Component({
  selector: 'app-down-file',
  templateUrl: './downfile.component.html',
})
export class DownFileComponent {
  fileTypes = ['.xlsx', '.docx', '.pptx', '.pdf'];
  data = {
    otherdata: 1,
    time: new Date(),
  };
}
src/app/routes/delon/form/form.component.html
New file
@@ -0,0 +1,5 @@
<page-header [title]="'Page Name'"></page-header>
<nz-card>
  <sf mode="search" [schema]="searchSchema" [formData]="params" (formSubmit)="st.reset($event)" (formReset)="st.reset(params)"></sf>
  <simple-table #st [data]="url" [columns]="columns" [extraParams]="params"></simple-table>
</nz-card>
src/app/routes/delon/form/form.component.ts
New file
@@ -0,0 +1,32 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { _HttpClient } from '@delon/theme';
import { SimpleTableColumn, SimpleTableComponent } from '@delon/abc';
import { SFSchema } from '@delon/form';
@Component({
  selector: 'app-delon-form',
  templateUrl: './form.component.html',
})
export class DelonFormComponent implements OnInit {
  params: any = {};
  url = `/user`;
  @ViewChild('st') st: SimpleTableComponent;
  searchSchema: SFSchema = {
    properties: {
      no: {
        type: 'string',
        title: '编号',
      },
    },
  };
  columns: SimpleTableColumn[] = [
    { title: '编号', index: 'no' },
    { title: '调用次数', type: 'number', index: 'callNo' },
    { title: '头像', type: 'img', width: '50px', index: 'avatar' },
    { title: '时间', type: 'date', index: 'updatedAt' },
  ];
  constructor(private http: _HttpClient) {}
  ngOnInit() {}
}
src/app/routes/delon/guard/admin.component.ts
New file
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
  selector: 'app-guard-admin',
  template: `
    <p>这是一个admin页面</p>
  `,
})
export class GuardAdminComponent {}
src/app/routes/delon/guard/auth.component.ts
New file
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
  selector: 'app-guard-auth',
  template: `
    <p>这是一个user1页面</p>
  `,
})
export class GuardAuthComponent {}
src/app/routes/delon/guard/can-leave.provide.ts
New file
@@ -0,0 +1,38 @@
import { Injectable } from '@angular/core';
import {
  CanDeactivate,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
} from '@angular/router';
import { GuardComponent } from './guard.component';
import { Observable } from 'rxjs';
import { NzModalService } from 'ng-zorro-antd';
@Injectable()
export class CanLeaveProvide implements CanDeactivate<GuardComponent> {
  constructor(private confirmSrv: NzModalService) {}
  canDeactivate(
    component: GuardComponent,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState?: RouterStateSnapshot,
  ): boolean | Observable<boolean> | Promise<boolean> {
    return new Observable(observer => {
      this.confirmSrv.confirm({
        nzTitle: '确认要离开吗?',
        nzContent: '你已经填写了部分表单离开会放弃已经填写的内容。',
        nzOkText: '离开',
        nzCancelText: '取消',
        nzOnOk: () => {
          observer.next(true);
          observer.complete();
        },
        nzOnCancel: () => {
          observer.next(false);
          observer.complete();
        },
      });
    });
  }
}
src/app/routes/delon/guard/guard.component.html
New file
@@ -0,0 +1,33 @@
<div class="content__title">
  <h1>
    路由守卫
  </h1>
</div>
<nz-button-group>
  <button nz-button [routerLink]="['/delon/guard/leave']">
    <span>离开确认页</span>
  </button>
</nz-button-group>
<nz-button-group class="ml-sm">
  <button nz-button (click)="setRole(true)">
    <span>设置管理员</span>
  </button>
  <button nz-button (click)="setRole('user1')">
    <span>设置员工1</span>
  </button>
  <button nz-button (click)="setRole('user2')">
    <span>设置员工2</span>
  </button>
</nz-button-group>
<nz-button-group class="ml-sm">
  <button nz-button [routerLink]="['/delon/guard/auth']">
    <span>需要user1</span>
  </button>
  <button nz-button [routerLink]="['/delon/guard/admin']">
    <span>需要管理员</span>
  </button>
</nz-button-group>
<p class="mb-lg">
  当前ACL信息:{{ aclSrv.data | json }}
</p>
<router-outlet></router-outlet>
src/app/routes/delon/guard/guard.component.spec.ts
New file
@@ -0,0 +1,17 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { GuardComponent } from './guard.component';
describe('Comoponent: Guard', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [GuardComponent],
    providers: [],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(GuardComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/delon/guard/guard.component.ts
New file
@@ -0,0 +1,23 @@
import { MenuService } from '@delon/theme';
import { Router } from '@angular/router';
import { Component } from '@angular/core';
import { ACLService } from '@delon/acl';
@Component({
  selector: 'app-guard',
  templateUrl: './guard.component.html',
})
export class GuardComponent {
  constructor(
    public aclSrv: ACLService,
    private menuSrv: MenuService,
    private router: Router,
  ) {}
  setRole(value: string | boolean) {
    this.aclSrv.setFull(typeof value === 'boolean' ? value : false);
    this.aclSrv.set({ role: [value as string] });
    this.menuSrv.resume();
    this.router.navigate(['/delon/guard']);
  }
}
src/app/routes/delon/guard/leave.component.ts
New file
@@ -0,0 +1,12 @@
import { Component } from '@angular/core';
@Component({
  selector: 'app-guard-leave',
  template: `
    <p>离开时需要确认</p>
    <button nz-button [nzType]="'primary'" [routerLink]="['/logics/guard']">
      <span>我要离开</span>
    </button>
    `,
})
export class GuardLeaveComponent {}
src/app/routes/delon/print/print.component.html
New file
@@ -0,0 +1,61 @@
<div class="content__title">
  <h1>Lodop打印
    <small>更多体验请至
      <a href="http://ng-alain.com/components/lodop" target="_blank">ng-alain.com</a>
    </small>
  </h1>
</div>
<nz-card>
  <nz-alert *ngIf="error" [nzType]="'warning'" [nzMessage]="message">
    <ng-template #message>
      请先下载
      <a href="http://c-lodop.com/download.html" target="_blank">Lodop插件</a>。
    </ng-template>
  </nz-alert>
  <form *ngIf="!error" nz-form>
    <nz-form-item nz-row>
      <nz-form-label nz-col [nzSm]="6">打印服务器</nz-form-label>
      <nz-form-control nz-col [nzSm]="18">
        <nz-input-group>
          <div nz-col [nzSpan]="16">
            <input nz-input nzPlaceHolder="https://localhost:8443/CLodopfuncs.js" [(ngModel)]="cog.url" name="url">
          </div>
          <div nz-col [nzSpan]="8">
            <button nz-button (click)="reload(null)">重新加载打印机</button>
          </div>
        </nz-input-group>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item nz-row>
      <nz-form-label nz-col [nzSm]="6">打印机</nz-form-label>
      <nz-form-control nz-col [nzSm]="18">
        <nz-select style="width:90%;" nzPlaceHolder="请选择打印机" nzShowSearch nzAllowClear [(ngModel)]="cog.printer" name="printer" (ngModelChange)="changePinter($event)">
          <nz-option *ngFor="let name of pinters" [nzLabel]="name" [nzValue]="name">
          </nz-option>
        </nz-select>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item nz-row>
      <nz-form-label nz-col [nzSm]="6">纸张类型</nz-form-label>
      <nz-form-control nz-col [nzSm]="18">
        <nz-select style="width:90%;" nzPlaceHolder="请选择纸张类型" nzShowSearch nzAllowClear [(ngModel)]="cog.paper" name="paper">
          <nz-option *ngFor="let name of papers" [nzLabel]="name" [nzValue]="name">
          </nz-option>
        </nz-select>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item nz-row>
      <nz-form-label nz-col [nzSm]="6">打印内容</nz-form-label>
      <nz-form-control nz-col [nzSm]="18">
        <textarea nz-input [(ngModel)]="cog.html" name="html" nzAutosize></textarea>
        <div nz-form-extra>仅限HTML,更多类型支持请参考官网</div>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item nz-row>
      <nz-form-control nz-col [nzSm]="18" [nzOffset]="6">
        <button nz-button (click)="print(true)" [nzLoading]="printing">打印预览</button>
        <button nz-button (click)="print()" [nzLoading]="printing">直接打印</button>
      </nz-form-control>
    </nz-form-item>
  </form>
</nz-card>
src/app/routes/delon/print/print.component.ts
New file
@@ -0,0 +1,79 @@
import { Component } from '@angular/core';
import { NzMessageService, NzNotificationService } from 'ng-zorro-antd';
import { Lodop, LodopService } from '@delon/abc';
@Component({
  selector: 'app-print',
  templateUrl: './print.component.html',
})
export class PrintComponent {
  cog: any = {
    url: 'https://localhost:8443/CLodopfuncs.js',
    printer: '',
    paper: '',
    html: `
      <h1>Title</h1>
      <p>这~!@#¥%……&*()——sdilfjnvn</p>
      <p>这~!@#¥%……&*()——sdilfjnvn</p>
      <p>这~!@#¥%……&*()——sdilfjnvn</p>
      <p>这~!@#¥%……&*()——sdilfjnvn</p>
      <p>这~!@#¥%……&*()——sdilfjnvn</p>
    `,
  };
  error = false;
  lodop: Lodop = null;
  pinters: any[] = [];
  papers: string[] = [];
  constructor(
    public lodopSrv: LodopService,
    private msg: NzMessageService,
    private notify: NzNotificationService,
  ) {
    this.lodopSrv.lodop.subscribe(({ lodop, ok }) => {
      if (!ok) {
        this.error = true;
        return;
      }
      this.error = false;
      this.msg.success(`打印机加载成功`);
      this.lodop = lodop;
      this.pinters = this.lodopSrv.printer;
    });
  }
  reload(options: any = { url: 'https://localhost:8443/CLodopfuncs.js' }) {
    this.pinters = [];
    this.papers = [];
    this.cog.printer = '';
    this.cog.paper = '';
    this.lodopSrv.cog = Object.assign({}, this.cog, options);
    this.error = false;
    if (options === null) this.lodopSrv.reset();
  }
  changePinter(name: string) {
    this.papers = this.lodop.GET_PAGESIZES_LIST(name, '\n').split('\n');
  }
  printing = false;
  print(isPrivew = false) {
    const LODOP = this.lodop;
    LODOP.PRINT_INITA(10, 20, 810, 610, '测试C-Lodop远程打印四步骤');
    LODOP.SET_PRINTER_INDEXA(this.cog.printer);
    LODOP.SET_PRINT_PAGESIZE(0, 0, 0, this.cog.paper);
    LODOP.ADD_PRINT_TEXT(
      1,
      1,
      300,
      200,
      '下面输出的是本页源代码及其展现效果:',
    );
    LODOP.ADD_PRINT_TEXT(20, 10, '90%', '95%', this.cog.html);
    LODOP.SET_PRINT_STYLEA(0, 'ItemType', 4);
    LODOP.NewPageA();
    LODOP.ADD_PRINT_HTM(20, 10, '90%', '95%', this.cog.html);
    if (isPrivew) LODOP.PREVIEW();
    else LODOP.PRINT();
  }
}
src/app/routes/delon/qr/qr.component.html
New file
@@ -0,0 +1,76 @@
<div class="content__title">
  <h1>二维码
    <a href="//ng-alain.com/components/qr" target="_blank">Document</a>
  </h1>
</div>
<nz-card>
  <nz-row [nzGutter]="24">
    <nz-col [nzSpan]="8" class="text-center">
      <qr [value]="value" [background]="background" [backgroundAlpha]="backgroundAlpha" [foreground]="foreground" [foregroundAlpha]="foregroundAlpha"
        [level]="level" [mime]="mime" [padding]="padding" [size]="size" style="border:1px solid #999"></qr>
    </nz-col>
    <nz-col [nzSpan]="16">
      <form nz-form>
        <nz-form-item>
          <nz-form-label [nzSpan]="8">背景</nz-form-label>
          <nz-form-control [nzSpan]="16">
            <nz-input-group>
              <div nz-col nzSpan="12">
                <input nz-input type="color" [(ngModel)]="background" [ngModelOptions]="{standalone: true}">
              </div>
              <div nz-col nzSpan="12">
                <nz-input-number [(ngModel)]="backgroundAlpha" [nzMin]="0" [nzMax]="1" [nzStep]="0.1" [ngModelOptions]="{standalone: true}"></nz-input-number>
              </div>
            </nz-input-group>
          </nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label [nzSpan]="8">前景</nz-form-label>
          <nz-form-control [nzSpan]="16">
            <nz-input-group>
              <div nz-col nzSpan="12">
                <input nz-input type="color" [(ngModel)]="foreground" [ngModelOptions]="{standalone: true}">
              </div>
              <div nz-col nzSpan="12">
                <nz-input-number [(ngModel)]="foregroundAlpha" [nzMin]="0" [nzMax]="1" [nzStep]="0.1" [ngModelOptions]="{standalone: true}"></nz-input-number>
              </div>
            </nz-input-group>
          </nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label [nzSpan]="8">误差</nz-form-label>
          <nz-form-control [nzSpan]="16">
            <nz-select [(ngModel)]="level" [ngModelOptions]="{standalone: true}">
              <nz-option nzValue="L" nzLabel="L"></nz-option>
              <nz-option nzValue="M" nzLabel="M"></nz-option>
              <nz-option nzValue="Q" nzLabel="Q"></nz-option>
              <nz-option nzValue="H" nzLabel="H"></nz-option>
            </nz-select>
          </nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label [nzSpan]="8">Mime</nz-form-label>
          <nz-form-control [nzSpan]="16">
            <nz-select [(ngModel)]="mime" [ngModelOptions]="{standalone: true}">
              <nz-option nzValue="image/png" nzLabel="image/png"></nz-option>
              <nz-option nzValue="image/jpeg" nzLabel="image/jpeg"></nz-option>
              <nz-option nzValue="image/gif" nzLabel="image/gif"></nz-option>
            </nz-select>
          </nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label [nzSpan]="8">内边距</nz-form-label>
          <nz-form-control [nzSpan]="16">
            <nz-input-number [(ngModel)]="padding" [ngModelOptions]="{standalone: true}" [nzMin]="0" [nzMax]="100"></nz-input-number>px
          </nz-form-control>
        </nz-form-item>
        <nz-form-item>
          <nz-form-label [nzSpan]="8">大小</nz-form-label>
          <nz-form-control [nzSpan]="16">
            <nz-input-number [(ngModel)]="size" [ngModelOptions]="{standalone: true}" [nzMin]="100" [nzMax]="1000" [nzStep]="padding"></nz-input-number>px
          </nz-form-control>
        </nz-form-item>
      </form>
    </nz-col>
  </nz-row>
</nz-card>
src/app/routes/delon/qr/qr.component.ts
New file
@@ -0,0 +1,17 @@
import { Component } from '@angular/core';
@Component({
  selector: 'app-qr',
  templateUrl: './qr.component.html',
})
export class QRComponent {
  value = 'https://ng-alain.com/';
  background = 'white';
  backgroundAlpha = 1.0;
  foreground = 'black';
  foregroundAlpha = 1.0;
  level = 'L';
  mime = 'image/png';
  padding = 10;
  size = 220;
}
src/app/routes/delon/simple-table/simple-table.component.html
New file
@@ -0,0 +1,52 @@
<div class="content__title">
  <h1>
    Fullscreen Table
    <small>使用
      <a href="//ng-alain.com/components/simple-table" target="_blank">simple-table</a>、
      <a href="//ng-alain.com/components/full-content" target="_blank">full-content</a> 组合,由于 nz-table 固定表头暂不支持自适应,因此表格的展示的效果在响应式里面效果并不是特别好。</small>
  </h1>
</div>
<full-content (fullscreenChange)="fullChange($event)">
  <nz-card>
    <div nz-row class="mb-md">
      <div nz-col nzSpan="12">
        <form nz-form [nzLayout]="'inline'">
          <nz-form-item>
            <nz-form-label nzFor="userid">User ID</nz-form-label>
            <nz-form-control>
              <input nz-input [(ngModel)]="args.userid" name="userid" id="userid">
            </nz-form-control>
          </nz-form-item>
          <nz-form-item>
            <nz-form-control>
              <button nz-button [nzType]="'primary'" (click)="st.load()" [nzLoading]="http.loading">Search</button>
              <button nz-button (click)="st.load({_allow_anonymous: true})" [disabled]="http.loading">Clear</button>
            </nz-form-control>
          </nz-form-item>
        </form>
      </div>
      <div nz-col nzSpan="12">
        <div class="text-right">
          <nz-dropdown>
            <button nz-button nz-dropdown>
              <span>Export</span>
              <i class="anticon anticon-down"></i>
            </button>
            <ul nz-menu>
              <li nz-menu-item>Excel</li>
              <li nz-menu-item>JSON</li>
              <li nz-menu-item>PNG</li>
            </ul>
          </nz-dropdown>
          <button nz-button [nzType]="'default'" full-toggle class="ml-sm">Full</button>
        </div>
      </div>
    </div>
    <simple-table #st [data]="url" [extraParams]="args" [resReName]="{list: 'results' }" [total]="total" [ps]="ps" [columns]="columns"
      [scroll]="scroll">
      <ng-template st-row="events" let-item let-index="index">
        <g2-mini-bar height="15" theme="mini" color="#999" borderWidth="3" [padding]="[0, 0, 0, 0]" [data]="events"></g2-mini-bar>
      </ng-template>
    </simple-table>
  </nz-card>
</full-content>
src/app/routes/delon/simple-table/simple-table.component.ts
New file
@@ -0,0 +1,74 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { map } from 'rxjs/operators';
import {
  SimpleTableChange,
  SimpleTableColumn,
  SimpleTableButton,
} from '@delon/abc';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'app-simple-table',
  templateUrl: './simple-table.component.html',
})
export class SimpleTableComponent implements OnInit {
  ps = 20;
  total = 200; // mock total
  args: any = { _allow_anonymous: true };
  url = `https://api.randomuser.me/?results=20`;
  events: any[] = [];
  scroll = { y: '230px' };
  columns: SimpleTableColumn[] = [
    { title: 'id', index: 'id.value', type: 'checkbox' },
    { title: 'Avatar', index: 'picture.thumbnail', type: 'img', width: '80px' },
    {
      title: 'Name',
      index: 'name.first',
      width: '150px',
      format: (item: any) => `${item.name.first} ${item.name.last}`,
      type: 'link',
      click: (item: any) => this.message.info(`${item.name.first}`),
    },
    { title: 'Email', index: 'email' },
    {
      title: 'Gender',
      index: 'gender',
      type: 'yn',
      ynTruth: 'female',
      ynYes: '男',
      ynNo: '女',
      width: '120px',
    },
    { title: 'Events', render: 'events', width: '90px' },
    { title: 'Registered', index: 'registered', type: 'date', width: '150px' },
    {
      title: 'Actions',
      width: '120px',
      buttons: <SimpleTableButton[]>[
        {
          text: 'Edit',
          click: (item: any) => this.message.info(`edit [${item.id.value}]`),
          if: (item: any) => item.gender === 'female',
        },
        {
          text: 'Delete',
          type: 'del',
          click: (item: any) => this.message.info(`deleted [${item.id.value}]`),
        },
      ],
    },
  ];
  constructor(public http: _HttpClient, private message: NzMessageService) {}
  ngOnInit(): void {
    this.http
      .get('/chart/visit')
      .subscribe((res: any[]) => (this.events = res.slice(0, 8)));
  }
  fullChange(val: boolean) {
    this.scroll = val ? { y: '350px' } : { y: '230px' };
  }
}
src/app/routes/delon/util/util.component.html
New file
@@ -0,0 +1,54 @@
<div class="content__title">
  <h1>
    工具集
    <small>@delon/util 日常用法。</small>
  </h1>
</div>
<nz-row [nzGutter]="16">
  <nz-col [nzSpan]="12">
    <nz-card nzTitle="字符串类">
      <nz-card nzType="inner" nzTitle="format">
        <form nz-form>
          <nz-form-item>
            <nz-form-label [nzSm]="8">String</nz-form-label>
            <nz-form-control [nzSm]="16">
              <input nz-input [(ngModel)]="format_str" [ngModelOptions]="{standalone: true}">
            </nz-form-control>
          </nz-form-item>
          <nz-form-item>
            <nz-form-label [nzSm]="8">Object</nz-form-label>
            <nz-form-control [nzSm]="16">
              <input nz-input [(ngModel)]="format_obj" [ngModelOptions]="{standalone: true}">
            </nz-form-control>
          </nz-form-item>
          <nz-form-item>
            <nz-form-control [nzSpan]="16" [nzOffset]="8">
              <button (click)="onFormat()" nz-button>Run</button>
            </nz-form-control>
          </nz-form-item>
          <nz-form-item>
            <nz-form-label [nzSm]="8">Result</nz-form-label>
            <nz-form-control [nzSm]="16">
              {{format_res}}
            </nz-form-control>
          </nz-form-item>
        </form>
      </nz-card>
      <nz-card nzType="inner" nzTitle="yuan">
        <nz-row [nzGutter]="16">
          <nz-col [nzSpan]="12">
            <input type="number" nz-input [(ngModel)]="yuan_str" (ngModelChange)="onYuan($event)">
          </nz-col>
          <nz-col [nzSpan]="12">
            <div [innerHTML]="yuan_res"></div>
          </nz-col>
        </nz-row>
      </nz-card>
    </nz-card>
  </nz-col>
  <nz-col [nzSpan]="12">
    <nz-card nzTitle="其它类">
      <button nz-button (click)="onCopy()">Copy</button>
    </nz-card>
  </nz-col>
</nz-row>
src/app/routes/delon/util/util.component.ts
New file
@@ -0,0 +1,47 @@
import { Component } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { copy, format, yuan } from '@delon/util';
@Component({
  selector: 'app-util',
  templateUrl: './util.component.html',
})
export class UtilComponent {
  constructor(public messageSrv: NzMessageService) {}
  // region: string
  format_str = 'this is ${name}';
  format_res = '';
  format_obj = JSON.stringify({ name: 'asdf' });
  onFormat() {
    let obj = null;
    try {
      obj = JSON.parse(this.format_obj);
    } catch {
      this.messageSrv.error(`无法使用 JSON.parse 转换`);
      return;
    }
    this.format_res = format(this.format_str, obj, true);
  }
  // yuan
  yuan_str: any;
  yuan_res: string;
  onYuan(value: string) {
    this.yuan_res = yuan(value);
  }
  // endregion
  // region: other
  content = `time ${+new Date()}
    中文!@#¥%……&*`;
  onCopy() {
    copy(`time ${+new Date()}`).then(() => this.messageSrv.success(`success`));
  }
  // endregion
}
src/app/routes/delon/xlsx/xlsx.component.html
New file
@@ -0,0 +1,14 @@
<div class="content__title">
  <h1>Import & Export excel file,
    <a href="//ng-alain.com/components/xlsx" target="_blank">Document</a>
  </h1>
</div>
<nz-card nzTitle="Import">
  <button nz-button (click)="url()">Via Url</button>
  <input type="file" (change)="change($event)" multiple="false" class="ml-sm" />
  <p class="mt-sm">result: {{data | json}}</p>
</nz-card>
<nz-card nzTitle="Export">
  <button nz-button (click)="download()">Export</button>
  <simple-table [data]="users" [ps]="3" [columns]="columns" class="mt-sm"></simple-table>
</nz-card>
src/app/routes/delon/xlsx/xlsx.component.ts
New file
@@ -0,0 +1,50 @@
import { Component, OnInit } from '@angular/core';
import { XlsxService, SimpleTableColumn } from '@delon/abc';
@Component({
  selector: 'app-xlsx',
  templateUrl: './xlsx.component.html',
})
export class XlsxComponent {
  constructor(private xlsx: XlsxService) {}
  data: any;
  url() {
    this.xlsx.import(`./assets/tmp/demo.xlsx`).then(res => (this.data = res));
  }
  change(e: Event) {
    const file = (e.target as HTMLInputElement).files[0];
    this.xlsx.import(file).then(res => (this.data = res));
  }
  users: any[] = Array(100)
    .fill({})
    .map((item: any, idx: number) => {
      return {
        id: idx + 1,
        name: `name ${idx + 1}`,
        age: Math.ceil(Math.random() * 10) + 20,
      };
    });
  columns: SimpleTableColumn[] = [
    { title: '编号', index: 'id', type: 'checkbox' },
    { title: '姓名', index: 'name' },
    { title: '年龄', index: 'age' },
  ];
  download() {
    const data = [this.columns.map(i => i.title)];
    this.users.forEach(i =>
      data.push(this.columns.map(c => i[c.index as string])),
    );
    this.xlsx.export({
      sheets: [
        {
          data: data,
          name: 'sheet name',
        },
      ],
    });
  }
}
src/app/routes/delon/zip/zip.component.html
New file
@@ -0,0 +1,38 @@
<div class="content__title">
  <h1>Read & Write zip file,
    <a href="//ng-alain.com/components/zip" target="_blank">Document</a>
  </h1>
</div>
<nz-card nzTitle="解压">
  <button nz-button (click)="url()">Via Url</button>
  <input type="file" (change)="change($event)" multiple="false" class="ml-sm" />
  <ol>
    <li *ngFor="let i of list">{{i | json}}</li>
  </ol>
</nz-card>
<nz-card nzTitle="压缩" *ngIf="instance">
  <button nz-button (click)="data.push({})" [nzType]="'primary'">new</button>
  <button nz-button (click)="download()" class="ml-sm">download</button>
  <nz-table [nzData]="data" [nzFrontPagination]="false" [nzShowPagination]="false" class="mt-sm">
    <thead>
      <tr>
        <th>
          <span>path</span>
        </th>
        <th>
          <span>url</span>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let i of data; let index = index">
        <td>
          <input nz-input [(ngModel)]="i.path" name="path{{index}}">
        </td>
        <td>
          <input nz-input [(ngModel)]="i.url" name="url{{index}}">
        </td>
      </tr>
    </tbody>
  </nz-table>
</nz-card>
src/app/routes/delon/zip/zip.component.ts
New file
@@ -0,0 +1,71 @@
import { Component, OnInit } from '@angular/core';
import { ZipService } from '@delon/abc';
import * as JSZip from 'jszip';
import { NzMessageService } from 'ng-zorro-antd';
@Component({
  selector: 'app-zip',
  templateUrl: './zip.component.html',
})
export class ZipComponent {
  constructor(private zip: ZipService, private msg: NzMessageService) {
    this.zip.create().then(ret => (this.instance = ret));
  }
  // region: read
  list: any;
  private format(data: any) {
    const files = data.files;
    this.list = Object.keys(files).map(key => {
      return {
        name: key,
        dir: files[key].dir,
        date: files[key].date,
      };
    });
  }
  url() {
    this.zip.read(`./assets/tmp/demo.zip`).then(res => this.format(res));
  }
  change(e: Event) {
    const file = (e.target as HTMLInputElement).files[0];
    this.zip.read(file).then(res => this.format(res));
  }
  // endregion
  // region: write
  instance: JSZip = null;
  data: { path: string; url: string }[] = [
    { path: 'demo.docx', url: 'http://ng-alain.com/assets/demo.docx' },
    {
      path: '小程序标志.zip',
      url: 'https://wximg.gtimg.com/shake_tv/mina/standard_logo.zip',
    },
  ];
  download() {
    const promises: Promise<any>[] = [];
    this.data.forEach(item => {
      promises.push(this.zip.pushUrl(this.instance, item.path, item.url));
    });
    Promise.all(promises).then(
      () => {
        this.zip.save(this.instance).then(() => {
          this.msg.success('download success');
          this.data = [];
        });
      },
      (error: any) => {
        console.warn(error);
        this.msg.error(JSON.stringify(error));
      },
    );
  }
  // endregion
}
src/app/routes/exception/403.component.ts
New file
@@ -0,0 +1,12 @@
import { Component } from '@angular/core';
import { NzModalService } from 'ng-zorro-antd';
@Component({
  selector: 'exception-403',
  template: `<exception type="403" style="min-height: 500px; height: 80%;"></exception>`,
})
export class Exception403Component {
  constructor(modalSrv: NzModalService) {
    modalSrv.closeAll();
  }
}
src/app/routes/exception/404.component.ts
New file
@@ -0,0 +1,12 @@
import { Component } from '@angular/core';
import { NzModalService } from 'ng-zorro-antd';
@Component({
  selector: 'exception-404',
  template: `<exception type="404" style="min-height: 500px; height: 80%;"></exception>`,
})
export class Exception404Component {
  constructor(modalSrv: NzModalService) {
    modalSrv.closeAll();
  }
}
src/app/routes/exception/500.component.ts
New file
@@ -0,0 +1,12 @@
import { Component } from '@angular/core';
import { NzModalService } from 'ng-zorro-antd';
@Component({
  selector: 'exception-500',
  template: `<exception type="500" style="min-height: 500px; height: 80%;"></exception>`,
})
export class Exception500Component {
  constructor(modalSrv: NzModalService) {
    modalSrv.closeAll();
  }
}
src/app/routes/extras/extras-routing.module.ts
New file
@@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HelpCenterComponent } from './helpcenter/helpcenter.component';
import { ExtrasSettingsComponent } from './settings/settings.component';
import { ExtrasPoiComponent } from './poi/poi.component';
const routes: Routes = [
  { path: 'helpcenter', component: HelpCenterComponent },
  { path: 'settings', component: ExtrasSettingsComponent },
  { path: 'poi', component: ExtrasPoiComponent },
];
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class ExtrasRoutingModule {}
src/app/routes/extras/extras.module.ts
New file
@@ -0,0 +1,24 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SharedModule } from '@shared/shared.module';
import { ExtrasRoutingModule } from './extras-routing.module';
import { HelpCenterComponent } from './helpcenter/helpcenter.component';
import { ExtrasSettingsComponent } from './settings/settings.component';
import { ExtrasPoiComponent } from './poi/poi.component';
import { ExtrasPoiEditComponent } from './poi/edit/edit.component';
const COMPONENTS_NOROUNT = [ExtrasPoiEditComponent];
@NgModule({
  imports: [SharedModule, ExtrasRoutingModule],
  declarations: [
    HelpCenterComponent,
    ExtrasSettingsComponent,
    ExtrasPoiComponent,
    ...COMPONENTS_NOROUNT,
  ],
  entryComponents: COMPONENTS_NOROUNT,
})
export class ExtrasModule {}
src/app/routes/extras/helpcenter/helpcenter.component.html
New file
@@ -0,0 +1,94 @@
<div class="text-center pb-lg">
  <h1 class="py-md mt-sm">帮助中心</h1>
  <div>帮助用户快速找到问题答案</div>
</div>
<div class="text-center">
  <nz-input-group nzCompact nzSize="large">
    <input [(ngModel)]="q" placeholder="请用关键词进行搜索,例如“服务器密码重置”" style="width: 50%;" nz-input>
    <nz-select [(ngModel)]="type" nzSize="large" style="width:20%;">
      <nz-option [nzLabel]="'不限'" [nzValue]="''"></nz-option>
      <nz-option [nzLabel]="'弹性计算'" [nzValue]="'弹性计算'"></nz-option>
      <nz-option [nzLabel]="'存储与CDN'" [nzValue]="'存储与CDN'"></nz-option>
      <nz-option [nzLabel]="'会员服务'" [nzValue]="'会员服务'"></nz-option>
      <nz-option [nzLabel]="'数据库'" [nzValue]="'数据库'"></nz-option>
    </nz-select>
    <button nz-button [nzType]="'primary'" (click)="search()" nzSize="large">
      <span>搜索</span>
    </button>
  </nz-input-group>
  <div class="py-sm text-grey-dark">
    搜索热词:
    <a class="ml-sm" (click)="quick('远程连接服务器')">远程连接服务器</a>
    <a class="ml-sm" (click)="quick('挂载数据盘')">挂载数据盘</a>
    <a class="ml-sm" (click)="quick('域名解析')">域名解析</a>
    <a class="ml-sm" (click)="quick('域名实名认证')">域名实名认证</a>
    <a class="ml-sm" (click)="quick('账号实名认证')">账号实名认证</a>
    <a class="ml-sm" (click)="quick('忘记密码')">忘记密码</a>
  </div>
</div>
<nz-row [nzGutter]="16" class="py-lg">
  <nz-col [nzXs]="12" [nzMd]="8">
    <nz-card>
      <a (click)="msg.info('弹性计算')" class="d-block text-center text-primary">
        <i class="anticon anticon-rocket display-1 mb-md"></i>
        <h2 class="mb0">弹性计算</h2>
      </a>
    </nz-card>
  </nz-col>
  <nz-col [nzXs]="12" [nzMd]="8">
    <nz-card>
      <a (click)="msg.info('存储与CDN')" class="d-block text-center text-red">
        <i class="anticon anticon-hdd display-1 mb-md"></i>
        <h2 class="mb0">存储与CDN</h2>
      </a>
    </nz-card>
  </nz-col>
  <nz-col [nzXs]="12" [nzMd]="8">
    <nz-card>
      <a (click)="msg.info('会员服务')" class="d-block text-center text-orange">
        <i class="anticon anticon-user display-1 mb-md"></i>
        <h2 class="mb0">会员服务</h2>
      </a>
    </nz-card>
  </nz-col>
  <nz-col [nzXs]="12" [nzMd]="8">
    <nz-card>
      <a (click)="msg.info('数据库')" class="d-block text-center text-purple">
        <i class="anticon anticon-database display-1 mb-md"></i>
        <h2 class="mb0">数据库</h2>
      </a>
    </nz-card>
  </nz-col>
  <nz-col [nzXs]="12" [nzMd]="8">
    <nz-card>
      <a (click)="msg.info('域名与网站')" class="d-block text-center text-cyan">
        <i class="anticon anticon-api display-1 mb-md"></i>
        <h2 class="mb0">域名与网站</h2>
      </a>
    </nz-card>
  </nz-col>
  <nz-col [nzXs]="12" [nzMd]="8">
    <nz-card>
      <a (click)="msg.info('网络')" class="d-block text-center text-teal">
        <i class="anticon anticon-global display-1 mb-md"></i>
        <h2 class="mb0">网络</h2>
      </a>
    </nz-card>
  </nz-col>
  <nz-col [nzXs]="12" [nzMd]="8">
    <nz-card>
      <a (click)="msg.info('应用服务')" class="d-block text-center text-pink">
        <i class="anticon anticon-appstore-o display-1 mb-md"></i>
        <h2 class="mb0">应用服务</h2>
      </a>
    </nz-card>
  </nz-col>
  <nz-col [nzXs]="12" [nzMd]="8">
    <nz-card>
      <a (click)="msg.info('开发者工具')" class="d-block text-center text-success">
        <i class="anticon anticon-tool display-1 mb-md"></i>
        <h2 class="mb0">开发者工具</h2>
      </a>
    </nz-card>
  </nz-col>
</nz-row>
src/app/routes/extras/helpcenter/helpcenter.component.spec.ts
New file
@@ -0,0 +1,16 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { HelpCenterComponent } from './helpcenter.component';
describe('Comoponent: HelpCenter', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [HelpCenterComponent],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(HelpCenterComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/extras/helpcenter/helpcenter.component.ts
New file
@@ -0,0 +1,22 @@
import { NzMessageService } from 'ng-zorro-antd';
import { Component } from '@angular/core';
@Component({
  selector: 'app-helpcenter',
  templateUrl: './helpcenter.component.html',
})
export class HelpCenterComponent {
  type = '';
  q = '';
  quick(key: string) {
    this.q = key;
    this.search();
  }
  search() {
    this.msg.success(`搜索:${this.q}`);
  }
  constructor(public msg: NzMessageService) {}
}
src/app/routes/extras/poi/edit/edit.component.html
New file
@@ -0,0 +1,87 @@
<div class="modal-header">
  <div class="modal-title">{{i.id > 0 ? '编辑' : '添加'}}-门店(基于HTML模板表单写法)</div>
</div>
<form #f="ngForm" (ngSubmit)="save()" nz-form>
  <nz-form-item class="mb-sm">
    <nz-form-label nzSpan="4">所属分销商</nz-form-label>
    <nz-form-control nzSpan="8">
      {{i.user_id}}
      <a (click)="msgSrv.info('find')">查找用户</a>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item class="mb-sm">
    <nz-form-label nzSpan="4">门店名称</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.name" name="name" maxlength="30" required />
      <p nz-form-explain>如:国美、麦当劳,不应包含地区、地址、分店名等信息,错误示例:北京国美</p>
    </nz-form-control>
    <nz-form-label nzSpan="4">分店名称</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.branch_name" name="branch_name" maxlength="20" required />
      <p nz-form-explain>不应包含地区信息,不应与门店名有重复,错误示例:北京王府井店</p>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item class="mb-sm">
    <nz-form-label nzSpan="4">所在地</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.geo" name="geo" maxlength="50" required />
    </nz-form-control>
    <nz-form-label nzSpan="4">街道地址</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.address" name="address" maxlength="50" required />
    </nz-form-control>
  </nz-form-item>
  <nz-form-item class="mb-sm">
    <nz-form-label nzSpan="4">纬度</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.lat" name="lat" required />
    </nz-form-control>
    <nz-form-label nzSpan="4">经度</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.lng" name="lng" required />
    </nz-form-control>
  </nz-form-item>
  <nz-form-item class="mb-sm">
    <nz-form-label nzSpan="4">电话</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.tel" name="tel" maxlength="30" required />
    </nz-form-control>
    <nz-form-label nzSpan="4">门店类型</nz-form-label>
    <nz-form-control nzSpan="8">
      <nz-select [(ngModel)]="i.categories" name="categories" required [nzAllowClear]="false">
        <nz-option *ngFor="let i of cat" [nzLabel]="i" [nzValue]="i">
        </nz-option>
      </nz-select>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item class="mb-sm">
    <nz-form-label nzSpan="4">推荐品</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.recommend" name="recommend" maxlength="200" placeholder="200字以内" />
    </nz-form-control>
    <nz-form-label nzSpan="4">特色服务</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.special" name="special" maxlength="50" placeholder="50字以内" />
    </nz-form-control>
  </nz-form-item>
  <nz-form-item class="mb-sm">
    <nz-form-label nzSpan="4">商户简介</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.introduction" name="introduction" maxlength="300" placeholder="300字以内" />
    </nz-form-control>
    <nz-form-label nzSpan="4">营业时间</nz-form-label>
    <nz-form-control nzSpan="8">
      <input nz-input [(ngModel)]="i.open_time" name="open_time" maxlength="30" placeholder="30字以内" />
    </nz-form-control>
  </nz-form-item>
  <nz-form-item class="mb-sm">
    <nz-form-label nzSpan="4">人均价格</nz-form-label>
    <nz-form-control nzSpan="8">
      <nz-input-number [(ngModel)]="i.avg_price" name="avg_price" [nzMin]="0" [nzStep]="10"></nz-input-number>
    </nz-form-control>
  </nz-form-item>
  <div class="modal-footer">
    <button nz-button type="button" (click)="close()">关闭</button>
    <button nz-button [disabled]="!f.form.valid || !f.form.dirty" [nzLoading]="http.loading" [nzType]="'primary'">保存</button>
  </div>
</form>
src/app/routes/extras/poi/edit/edit.component.ts
New file
@@ -0,0 +1,39 @@
import { NzMessageService, NzModalRef } from 'ng-zorro-antd';
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'app-extras-poi-edit',
  templateUrl: './edit.component.html',
})
export class ExtrasPoiEditComponent implements OnInit {
  i: any;
  cat: string[] = ['美食', '美食,粤菜', '美食,粤菜,湛江菜'];
  constructor(
    private modal: NzModalRef,
    public msgSrv: NzMessageService,
    public http: _HttpClient,
  ) {}
  ngOnInit() {
    if (this.i.id > 0) {
      this.http
        .get('./assets/tmp/pois.json')
        .subscribe((res: any) => (this.i = res.data[0]));
    }
  }
  save() {
    this.http.get('./assets/tmp/pois.json').subscribe(() => {
      this.msgSrv.success('保存成功,只是模拟,实际未变更');
      this.modal.close(true);
      this.close();
    });
  }
  close() {
    this.modal.destroy();
  }
}
src/app/routes/extras/poi/poi.component.html
New file
@@ -0,0 +1,37 @@
<div class="content__title">
  <h1>门店
    <small>使用
      <code>.simple-table</code> 样式风格的一个实际项目示例。</small>
  </h1>
  <button nz-button (click)="add()" [nzType]="'primary'">添加</button>
</div>
<form nz-form [nzLayout]="'inline'" class="search-form">
  <nz-form-item>
    <nz-form-control>
      <nz-select [(ngModel)]="s.s" name="s" [nzAllowClear]="false">
        <nz-option nzValue="" nzLabel="状态不限"></nz-option>
        <nz-option nzValue="1" nzLabel="正常"></nz-option>
        <nz-option nzValue="2" nzLabel="已取消"></nz-option>
        <nz-option nzValue="3" nzLabel="已删除"></nz-option>
        <nz-option nzValue="10" nzLabel="待提交"></nz-option>
        <nz-option nzValue="11" nzLabel="待审核"></nz-option>
      </nz-select>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control>
      <input nz-input [(ngModel)]="s.user_id" name="user_id" nzPlaceHolder="用户编号">
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control>
      <input nz-input [(ngModel)]="s.q" name="q" nzPlaceHolder="门店、分店名称">
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control>
      <button nz-button (click)="st.reset(s)">搜索</button>
    </nz-form-control>
  </nz-form-item>
</form>
<simple-table #st class="simple-table" [columns]="columns" [data]="url" [extraParams]="s"></simple-table>
src/app/routes/extras/poi/poi.component.ts
New file
@@ -0,0 +1,51 @@
import { Component, ViewChild } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { ModalHelper } from '@delon/theme';
import { SimpleTableComponent, SimpleTableColumn } from '@delon/abc';
import { ExtrasPoiEditComponent } from './edit/edit.component';
@Component({
  selector: 'app-extras-poi',
  templateUrl: './poi.component.html',
})
export class ExtrasPoiComponent {
  @ViewChild('st') st: SimpleTableComponent;
  s: any = {
    pi: 1,
    ps: 10,
    s: '',
  };
  url = '/pois';
  columns: SimpleTableColumn[] = [
    { title: '编号', index: 'id', width: '100px' },
    { title: '门店名称', index: 'name' },
    { title: '分店名', index: 'branch_name' },
    { title: '状态', index: 'status_str', width: '100px' },
    {
      title: '操作',
      width: '180px',
      buttons: [
        {
          text: '编辑',
          type: 'modal',
          component: ExtrasPoiEditComponent,
          paramName: 'i',
          click: () => this.msg.info('回调,重新发起列表刷新'),
        },
        { text: '图片', click: () => this.msg.info('click photo') },
        { text: '经营SKU', click: () => this.msg.info('click sku') },
      ],
    },
  ];
  constructor(public msg: NzMessageService, private modal: ModalHelper) {}
  add() {
    this.modal
      .static(ExtrasPoiEditComponent, { i: { id: 0 } })
      .subscribe(() => {
        this.st.load();
        this.msg.info('回调,重新发起列表刷新');
      });
  }
}
src/app/routes/extras/settings/settings.component.html
New file
@@ -0,0 +1,204 @@
<nz-row [nzGutter]="24" class="py-lg">
  <nz-col [nzSpan]="6">
    <nz-card nzTitle="Personal settings" class="ant-card__body-nopadding">
      <a (click)="active=1" class="d-block py-sm px-md" [ngClass]="{'bg-primary-light text-white':active===1}">Profile</a>
      <a (click)="active=2" class="d-block py-sm px-md" [ngClass]="{'bg-primary-light text-white':active===2}">Account</a>
      <a (click)="active=3" class="d-block py-sm px-md" [ngClass]="{'bg-primary-light text-white':active===3}">Emails</a>
      <a (click)="active=4" class="d-block py-sm px-md" [ngClass]="{'bg-primary-light text-white':active===4}">Notifications</a>
    </nz-card>
    <nz-card nzTitle="Developer settings" class="ant-card__body-nopadding">
      <a (click)="active=5" class="d-block py-sm px-md" [ngClass]="{'bg-primary-light text-white':active===5}">OAuth applications</a>
      <a (click)="active=6" class="d-block py-sm px-md" [ngClass]="{'bg-primary-light text-white':active===6}">Personal access tokens</a>
    </nz-card>
  </nz-col>
  <nz-col [nzSpan]="18">
    <nz-card nzTitle="Public profile" *ngIf="active===1">
      <nz-row [nzGutter]="64">
        <nz-col [nzSpan]="16">
          <form nz-form [formGroup]="profileForm" (ngSubmit)="profileSave($event, profileForm.value)" [nzLayout]="'vertical'">
            <nz-form-item>
              <nz-form-label nzFor="name" nzRequired>name</nz-form-label>
              <nz-form-control>
                <input nz-input formControlName="name" id="name">
                <div *ngIf="name.invalid && (name.dirty || name.touched)">
                  <nz-form-explain *ngIf="name.errors.required">required</nz-form-explain>
                  <nz-form-explain *ngIf="name.errors.pattern">must match pattern [-_a-zA-Z0-9]</nz-form-explain>
                </div>
              </nz-form-control>
            </nz-form-item>
            <nz-form-item>
              <nz-form-label nzFor="email">email</nz-form-label>
              <nz-form-control>
                <nz-select formControlName="email">
                  <nz-option [nzLabel]="'Select a verified email to display'" [nzValue]="''"></nz-option>
                  <nz-option [nzLabel]="'cipchk@qq.com'" [nzValue]="'cipchk@qq.com'"></nz-option>
                </nz-select>
                <nz-form-explain>You can manage verified email addresses in your
                  <a (click)="active=3">email settings</a>.</nz-form-explain>
              </nz-form-control>
            </nz-form-item>
            <nz-form-item>
              <nz-form-label nzFor="bio">Bio</nz-form-label>
              <nz-form-control>
                <textarea nz-input formControlName="bio" id="bio" placeholder="Tell us a little bit about yourself"></textarea>
                <nz-form-explain>You can
                  <strong>@mention</strong> other users and organizations to link to them.</nz-form-explain>
              </nz-form-control>
            </nz-form-item>
            <nz-form-item>
              <nz-form-label nzFor="url">URL</nz-form-label>
              <nz-form-control>
                <input nz-input formControlName="url" id="url">
              </nz-form-control>
            </nz-form-item>
            <nz-form-item>
              <nz-form-label nzFor="company">Company</nz-form-label>
              <nz-form-control>
                <input nz-input formControlName="company" id="company">
                <nz-form-explain>You can
                  <strong>@mention</strong> your company's GitHub organization to link it.</nz-form-explain>
              </nz-form-control>
            </nz-form-item>
            <nz-form-item class="border-top-1 mt-md pt-md">
              <nz-form-label nzFor="location">Location</nz-form-label>
              <nz-form-control>
                <input nz-input formControlName="location" id="location">
              </nz-form-control>
            </nz-form-item>
            <nz-form-item>
              <nz-form-control>
                <button nz-button [nzType]="'primary'" [disabled]="profileForm.invalid">Update profile</button>
              </nz-form-control>
            </nz-form-item>
          </form>
        </nz-col>
        <nz-col [nzSpan]="8">
          <h4>Profile picture</h4>
          <img src="./assets/tmp/img/avatar.jpg" style="width: 100%;">
          <nz-upload nzAction="https://jsonplaceholder.typicode.com/posts/" class="d-block mt-md text-center">
            <button nz-button>Upload new picture</button>
          </nz-upload>
        </nz-col>
      </nz-row>
    </nz-card>
    <nz-card nzTitle="Change password" *ngIf="active===2">
      <nz-row [nzGutter]="64">
        <nz-col [nzSpan]="16">
          <form nz-form [nzLayout]="'vertical'">
            <nz-form-item>
              <nz-form-label nzFor="old_password" nzRequired>Old password</nz-form-label>
              <nz-form-control>
                <input nz-input [(ngModel)]="pwd.old_password" name="old_password" id="old_password" type="password" required>
              </nz-form-control>
            </nz-form-item>
            <nz-form-item>
              <nz-form-label nzFor="new_password" nzRequired>New password</nz-form-label>
              <nz-form-control>
                <input nz-input [(ngModel)]="pwd.new_password" name="new_password" id="new_password" type="password" required>
              </nz-form-control>
            </nz-form-item>
            <nz-form-item>
              <nz-form-label nzRequired nzFor="confirm_new_password">Confirm new password</nz-form-label>
              <nz-form-control>
                <input nz-input [(ngModel)]="pwd.confirm_new_password" name="confirm_new_password" id="confirm_new_password" type="password"
                  required>
              </nz-form-control>
            </nz-form-item>
            <nz-form-item>
              <nz-form-control>
                <button nz-button (click)="pwdSave()" [nzType]="'primary'">Update profile</button>
                <a class="pl-sm" [routerLink]="['/forget']">I forgot my password</a>
              </nz-form-control>
            </nz-form-item>
          </form>
        </nz-col>
      </nz-row>
      <h2 class="py-md mt-lg border-bottom-1">Change username</h2>
      <p class="py-sm">Changing your username can have unintended side effects.</p>
      <button nz-button (click)="msg.info('to change username page')">
        <span>Change username</span>
      </button>
    </nz-card>
    <nz-card nzTitle="Email" *ngIf="active===3">
      <nz-row class="border-1 p-md rounded-sm" [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
        <nz-col [nzSpan]="12">
          cipchk@qq.com
          <nz-tooltip [nzTitle]="'This email will be used for account-related notifications (e.g. account changes, password resets, billing receipts) as well as any web-based GitHub operations (e.g. edits and merges).'">
            <span nz-tooltip>
              <nz-tag [nzColor]="'#28a745'">Primary</nz-tag>
            </span>
          </nz-tooltip>
          <nz-tooltip [nzTitle]="'This email will be used as the \'from\' address for web-based GitHub operations.'">
            <span nz-tooltip>
              <nz-tag [nzColor]="'#959da5'">Public</nz-tag>
            </span>
          </nz-tooltip>
        </nz-col>
        <nz-col [nzSpan]="12" class="text-right">
          <i class="anticon anticon-delete text-lg"></i>
        </nz-col>
      </nz-row>
      <h4 class="pt-md mb-sm">Add email address</h4>
      <input nz-input style="width: 200px;" class="mr-sm">
      <button nz-button (click)="msg.info('add')">Add</button>
      <h4 class="border-top-1 py-md mt-md">Primary email address</h4>
      <p class="mb-md">cipchk@qq.com will be used for account-related notifications and for web-based GitHub operations (e.g. edits and merges).</p>
      <nz-select [(ngModel)]="primary_email" class="mr-sm">
        <nz-option [nzLabel]="'cipchk@qq.com'" [nzValue]="'cipchk@qq.com'"></nz-option>
      </nz-select>
      <button nz-button (click)="msg.info('save')">Save</button>
    </nz-card>
    <nz-card nzTitle="Notifications" *ngIf="active===4">
      <p class="pb-md">Choose how you receive notifications. These notification settings apply to the repositories you’re watching.</p>
      <nz-list nzBordered>
        <nz-list-item class="d-block">
          <h4>Automatically watch repositories</h4>
          <p class="py-sm">When you’re given push access to a repository, automatically receive notifications for it.</p>
          <label nz-checkbox [ngModel]="true">Automatically watch</label>
        </nz-list-item>
        <nz-list-item class="d-block">
          <h4>Participating</h4>
          <p class="py-sm">Notifications for the conversations you are participating in, or if someone cites you with an @mention.</p>
          <label nz-checkbox [ngModel]="true">Email</label>
          <label nz-checkbox [ngModel]="true">Web</label>
        </nz-list-item>
        <nz-list-item class="d-block">
          <h4>Watching</h4>
          <p class="py-sm">Notifications for all repositories or conversations you’re watching.</p>
          <label nz-checkbox [ngModel]="true">Email</label>
          <label nz-checkbox [ngModel]="true">Web</label>
        </nz-list-item>
      </nz-list>
    </nz-card>
    <nz-card class="ant-card__body-nopadding" *ngIf="active===5" [nzBordered]="false">
      <div class="border rounded-md text-center p-lg bg-grey-lighter">
        <h3>No OAuth applications</h3>
        <p class="py-md">OAuth applications are used to access the GitHub API. Read the docs to find out more.</p>
        <button nz-button (click)="msg.info('Register a new application')" [nzType]="'primary'">
          Register a new application
        </button>
      </div>
    </nz-card>
    <nz-card nzTitle="Personal access tokens" [nzExtra]="extra" *ngIf="active===6">
      <ng-template #extra>
        <button nz-button (click)="msg.info('Generate new token')" [nzSize]="'small'">Generate new token</button>
        <button nz-button (click)="msg.info('Revoke all')" [nzSize]="'small'" [nzType]="'danger'" class="ml-sm">Revoke all</button>
      </ng-template>
      <p>Tokens you have generated that can be used to access the GitHub API.</p>
      <nz-list nzBordered class="mt-sm">
        <nz-list-item>
          <nz-col [nzSpan]="12">
            <strong>octotree</strong> — repo
          </nz-col>
          <nz-col [nzSpan]="12" class="text-right">
            Last used within the last day
            <nz-button-group>
              <button nz-button>Edit</button>
              <button nz-button [nzType]="'danger'">Delete</button>
            </nz-button-group>
          </nz-col>
        </nz-list-item>
      </nz-list>
    </nz-card>
  </nz-col>
</nz-row>
src/app/routes/extras/settings/settings.component.spec.ts
New file
@@ -0,0 +1,16 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { ExtrasSettingsComponent } from './settings.component';
describe('Comoponent: ExtrasSetting', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [ExtrasSettingsComponent],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(ExtrasSettingsComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/extras/settings/settings.component.ts
New file
@@ -0,0 +1,64 @@
import { NzMessageService } from 'ng-zorro-antd';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
  selector: 'app-extras-settings',
  templateUrl: './settings.component.html',
})
export class ExtrasSettingsComponent implements OnInit {
  active = 1;
  profileForm: FormGroup;
  pwd = {
    old_password: '',
    new_password: '',
    confirm_new_password: '',
  };
  // Email
  primary_email = 'cipchk@qq.com';
  constructor(fb: FormBuilder, public msg: NzMessageService) {
    this.profileForm = fb.group({
      name: [
        null,
        Validators.compose([
          Validators.required,
          Validators.pattern(`^[-_a-zA-Z0-9]{4,20}$`),
        ]),
      ],
      email: '',
      bio: [null, Validators.maxLength(160)],
      url: '',
      company: '',
      location: '',
    });
  }
  get name() {
    return this.profileForm.get('name');
  }
  profileSave(event, value) {
    console.log('profile value', value);
  }
  pwdSave() {
    if (!this.pwd.old_password) {
      return this.msg.error('invalid old password');
    }
    if (!this.pwd.new_password) {
      return this.msg.error('invalid new password');
    }
    if (!this.pwd.confirm_new_password) {
      return this.msg.error('invalid confirm new password');
    }
    console.log('pwd value', this.pwd);
  }
  ngOnInit() {
    this.profileForm.patchValue({
      name: 'cipchk',
      email: 'cipchk@qq.com',
    });
  }
}
src/app/routes/home-page/home-page-routing.module.ts
File was deleted
src/app/routes/home-page/home-page.module.ts
File was deleted
src/app/routes/home-page/home-page/home-page.component.html
File was deleted
src/app/routes/home-page/home-page/home-page.component.ts
File was deleted
src/app/routes/passport/lock/lock.component.html
New file
@@ -0,0 +1,29 @@
<div class="wrapper">
  <div class="abs-center width-lg">
    <div class="py-lg text-center">
      <nz-avatar [nzSrc]="settings.user.avatar" nzIcon="anticon anticon-user" nzSize="large"></nz-avatar>
    </div>
    <nz-card [nzBordered]="false">
      <p class="mb-sm">输入密码后解锁屏幕。</p>
      <form nz-form [formGroup]="f" (ngSubmit)="submit()" role="form">
        <nz-form-item>
          <nz-form-control>
            <nz-input-group nzSize="large" nzSuffixIcon="anticon anticon-lock">
              <input type="password" nz-input formControlName="password">
            </nz-input-group>
            <nz-form-explain *ngIf="f.get('password').dirty && f.get('password').errors">This field is required</nz-form-explain>
          </nz-form-control>
        </nz-form-item>
        <nz-row nzType="flex" nzAlign="middle">
          <nz-col [nzOffset]="12" [nzSpan]="12" style="text-align:right;">
            <button nz-button nzSize="large" [disabled]="!f.valid" nzType="primary">解锁</button>
          </nz-col>
        </nz-row>
      </form>
    </nz-card>
    <div class="p-lg text-center text-sm">
      &copy; {{ settings.app.year }} - {{ settings.app.name }}
      <br> {{ settings.app.description }}
    </div>
  </div>
</div>
src/app/routes/passport/lock/lock.component.spec.ts
New file
@@ -0,0 +1,16 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { UserLockComponent } from './lock.component';
describe('Pages: lock', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [UserLockComponent],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(UserLockComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/passport/lock/lock.component.ts
New file
@@ -0,0 +1,35 @@
import { Router } from '@angular/router';
import { Component } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { SettingsService } from '@delon/theme';
@Component({
  selector: 'passport-lock',
  templateUrl: './lock.component.html',
})
export class UserLockComponent {
  f: FormGroup;
  constructor(
    public settings: SettingsService,
    fb: FormBuilder,
    private router: Router,
  ) {
    this.f = fb.group({
      password: [null, Validators.required],
    });
  }
  submit() {
    // tslint:disable-next-line:forin
    for (const i in this.f.controls) {
      this.f.controls[i].markAsDirty();
      this.f.controls[i].updateValueAndValidity();
    }
    if (this.f.valid) {
      console.log('Valid!');
      console.log(this.f.value);
      this.router.navigate(['dashboard']);
    }
  }
}
src/app/routes/passport/login/login.component.html
New file
@@ -0,0 +1,70 @@
<form nz-form [formGroup]="form" (ngSubmit)="submit()" role="form">
  <nz-tabset [nzAnimated]="false" class="tabs" (nzSelectChange)="switch($event)">
    <nz-tab nzTitle="账户密码登录">
      <nz-alert *ngIf="error" [nzType]="'error'" [nzMessage]="error" [nzShowIcon]="true" class="mb-lg"></nz-alert>
      <nz-form-item>
        <nz-form-control>
          <nz-input-group nzSize="large" nzPrefixIcon="anticon anticon-user">
            <input nz-input formControlName="userName" placeholder="admin">
          </nz-input-group>
          <nz-form-explain *ngIf="userName.dirty && userName.errors">请输入账户名且至少五个字符!</nz-form-explain>
        </nz-form-control>
      </nz-form-item>
      <nz-form-item>
        <nz-form-control>
          <nz-input-group nzSize="large" nzPrefixIcon="anticon anticon-lock">
            <input nz-input type="password" formControlName="password" placeholder="888888">
          </nz-input-group>
          <nz-form-explain *ngIf="password.dirty && password.errors">
            请输入密码!
          </nz-form-explain>
        </nz-form-control>
      </nz-form-item>
    </nz-tab>
    <nz-tab nzTitle="手机号登录">
      <nz-form-item>
        <nz-form-control>
          <nz-input-group nzSize="large" nzPrefixIcon="anticon anticon-user">
            <input nz-input formControlName="mobile" placeholder="手机号">
          </nz-input-group>
          <nz-form-explain *ngIf="mobile.dirty && mobile.errors">请输入手机号且至少五个字符!</nz-form-explain>
        </nz-form-control>
      </nz-form-item>
      <nz-form-item>
        <nz-form-control>
          <nz-row [nzGutter]="8">
            <nz-col [nzSpan]="16">
              <nz-input-group nzSize="large" nzPrefixIcon="anticon anticon-mail">
                <input nz-input formControlName="captcha" placeholder="验证码">
              </nz-input-group>
              <nz-form-explain *ngIf="mobile.dirty && mobile.errors">
                请输入验证码!
              </nz-form-explain>
            </nz-col>
            <nz-col [nzSpan]="8">
              <button nz-button nzSize="large" (click)="getCaptcha()" [disabled]="count" class="ant-btn__block">{{ count ? count + 's' : '获取验证码' }}</button>
            </nz-col>
          </nz-row>
        </nz-form-control>
      </nz-form-item>
    </nz-tab>
  </nz-tabset>
  <nz-form-item>
    <nz-col [nzSpan]="12">
      <label nz-checkbox formControlName="remember">自动登录</label>
    </nz-col>
    <nz-col [nzSpan]="12" class="text-right">
      <a class="forgot" (click)="msg.error('请找欧阳锋')">忘记密码?</a>
    </nz-col>
  </nz-form-item>
  <nz-form-item>
    <button nz-button type="submit" nzType="primary" nzSize="large" [nzLoading]="loading" class="ant-btn__block">登录</button>
  </nz-form-item>
</form>
<div class="other">
  其他登录方式
  <i title="in fact Auth0 via window" (click)="open('auth0', 'window')" class="anticon anticon-alipay-circle icon"></i>
  <i title="in fact Github via redirect" (click)="open('taobao')" class="anticon anticon-taobao-circle icon"></i>
  <i title="真的是微博" (click)="open('weibo', 'window')" class="anticon anticon-weibo-circle icon"></i>
  <a class="register" routerLink="/passport/register">注册账户</a>
</div>
src/app/routes/passport/login/login.component.less
New file
@@ -0,0 +1,42 @@
@import 'node_modules/@delon/theme/styles/default';
:host {
  display: block;
  width: 368px;
  margin: 0 auto;
  ::ng-deep {
    .ant-tabs .ant-tabs-bar {
      border-bottom: 0;
      margin-bottom: 24px;
      text-align: center;
    }
    .ant-tabs-tab {
      font-size: 16px;
      line-height: 24px;
    }
    .ant-input-affix-wrapper .ant-input:not(:first-child) {
      padding-left: 34px;
    }
    .icon {
      font-size: 24px;
      color: rgba(0, 0, 0, 0.2);
      margin-left: 16px;
      vertical-align: middle;
      cursor: pointer;
      transition: color 0.3s;
      &:hover {
        color: @primary-color;
      }
    }
    .other {
      text-align: left;
      margin-top: 24px;
      line-height: 22px;
      nz-tooltip {
        vertical-align: middle;
      }
      .register {
        float: right;
      }
    }
  }
}
src/app/routes/passport/login/login.component.ts
New file
@@ -0,0 +1,181 @@
import { SettingsService } from '@delon/theme';
import { Component, OnDestroy, Inject, Optional } from '@angular/core';
import { Router } from '@angular/router';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NzMessageService, NzModalService } from 'ng-zorro-antd';
import {
  SocialService,
  SocialOpenType,
  TokenService,
  DA_SERVICE_TOKEN,
} from '@delon/auth';
import { ReuseTabService } from '@delon/abc';
import { environment } from '@env/environment';
import { StartupService } from '@core/startup/startup.service';
@Component({
  selector: 'passport-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.less'],
  providers: [SocialService],
})
export class UserLoginComponent implements OnDestroy {
  form: FormGroup;
  error = '';
  type = 0;
  loading = false;
  constructor(
    fb: FormBuilder,
    private router: Router,
    public msg: NzMessageService,
    private modalSrv: NzModalService,
    private settingsService: SettingsService,
    private socialService: SocialService,
    @Optional()
    @Inject(ReuseTabService)
    private reuseTabService: ReuseTabService,
    @Inject(DA_SERVICE_TOKEN) private tokenService: TokenService,
    private startupSrv: StartupService,
  ) {
    this.form = fb.group({
      userName: [null, [Validators.required, Validators.minLength(5)]],
      password: [null, Validators.required],
      mobile: [null, [Validators.required, Validators.pattern(/^1\d{10}$/)]],
      captcha: [null, [Validators.required]],
      remember: [true],
    });
    modalSrv.closeAll();
  }
  // region: fields
  get userName() {
    return this.form.controls.userName;
  }
  get password() {
    return this.form.controls.password;
  }
  get mobile() {
    return this.form.controls.mobile;
  }
  get captcha() {
    return this.form.controls.captcha;
  }
  // endregion
  switch(ret: any) {
    this.type = ret.index;
  }
  // region: get captcha
  count = 0;
  interval$: any;
  getCaptcha() {
    this.count = 59;
    this.interval$ = setInterval(() => {
      this.count -= 1;
      if (this.count <= 0) clearInterval(this.interval$);
    }, 1000);
  }
  // endregion
  submit() {
    this.error = '';
    if (this.type === 0) {
      this.userName.markAsDirty();
      this.userName.updateValueAndValidity();
      this.password.markAsDirty();
      this.password.updateValueAndValidity();
      if (this.userName.invalid || this.password.invalid) return;
    } else {
      this.mobile.markAsDirty();
      this.mobile.updateValueAndValidity();
      this.captcha.markAsDirty();
      this.captcha.updateValueAndValidity();
      if (this.mobile.invalid || this.captcha.invalid) return;
    }
    // mock http
    this.loading = true;
    setTimeout(() => {
      this.loading = false;
      if (this.type === 0) {
        if (
          this.userName.value !== 'admin' ||
          this.password.value !== '888888'
        ) {
          this.error = `账户或密码错误`;
          return;
        }
      }
      // 清空路由复用信息
      this.reuseTabService.clear();
      // 设置Token信息
      this.tokenService.set({
        token: '123456789',
        name: this.userName.value,
        email: `cipchk@qq.com`,
        id: 10000,
        time: +new Date(),
      });
      // 重新获取 StartupService 内容,若其包括 User 有关的信息的话
      // this.startupSrv.load().then(() => this.router.navigate(['/']));
      // 否则直接跳转
      this.router.navigate(['/']);
    }, 1000);
  }
  // region: social
  open(type: string, openType: SocialOpenType = 'href') {
    let url = ``;
    let callback = ``;
    if (environment.production)
      callback = 'https://cipchk.github.io/ng-alain/callback/' + type;
    else callback = 'http://localhost:4200/callback/' + type;
    switch (type) {
      case 'auth0':
        url = `//cipchk.auth0.com/login?client=8gcNydIDzGBYxzqV0Vm1CX_RXH-wsWo5&redirect_uri=${decodeURIComponent(
          callback,
        )}`;
        break;
      case 'github':
        url = `//github.com/login/oauth/authorize?client_id=9d6baae4b04a23fcafa2&response_type=code&redirect_uri=${decodeURIComponent(
          callback,
        )}`;
        break;
      case 'weibo':
        url = `https://api.weibo.com/oauth2/authorize?client_id=1239507802&response_type=code&redirect_uri=${decodeURIComponent(
          callback,
        )}`;
        break;
    }
    if (openType === 'window') {
      this.socialService
        .login(url, '/', {
          type: 'window',
        })
        .subscribe(res => {
          if (res) {
            this.settingsService.setUser(res);
            this.router.navigateByUrl('/');
          }
        });
    } else {
      this.socialService.login(url, '/', {
        type: 'href',
      });
    }
  }
  // endregion
  ngOnDestroy(): void {
    if (this.interval$) clearInterval(this.interval$);
  }
}
src/app/routes/passport/register-result/register-result.component.html
New file
@@ -0,0 +1,7 @@
<result type="success" [title]="title" description="激活邮件已发送到你的邮箱中,邮件有效期为24小时。请及时登录邮箱,点击邮件中的链接激活帐户。">
  <ng-template #title>
    <div class="title">你的账户:ng-alain@example.com 注册成功</div>
  </ng-template>
  <button (click)="msg.success('email')" nz-button nzSize="large" [nzType]="'primary'">查看邮箱</button>
  <button routerLink="/" nz-button nzSize="large">返回首页</button>
</result>
src/app/routes/passport/register-result/register-result.component.ts
New file
@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
@Component({
  selector: 'passport-register-result',
  templateUrl: './register-result.component.html'
})
export class UserRegisterResultComponent {
  constructor(public msg: NzMessageService) {}
}
src/app/routes/passport/register/register.component.html
New file
@@ -0,0 +1,85 @@
<h3>注册</h3>
<form nz-form [formGroup]="form" (ngSubmit)="submit()" role="form">
  <nz-alert *ngIf="error" [nzType]="'error'" [nzMessage]="error" [nzShowIcon]="true" class="mb-lg"></nz-alert>
  <nz-form-item>
    <nz-form-control>
      <nz-input-group nzSize="large" nzAddonBeforeIcon="anticon anticon-user">
        <input nz-input formControlName="mail" placeholder="邮箱">
      </nz-input-group>
      <ng-container *ngIf="mail.dirty && mail.errors">
        <nz-form-explain *ngIf="mail.errors?.required">请输入邮箱地址!</nz-form-explain>
        <nz-form-explain *ngIf="mail.errors?.email">邮箱地址格式错误!</nz-form-explain>
      </ng-container>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control>
      <nz-popover [nzPlacement]="'right'" [nzTrigger]="'focus'" [(nzVisible)]="visible" nzOverlayClassName="register-password-cdk"
        [nzOverlayStyle]="{'width.px': 240}">
        <nz-input-group nzSize="large" nz-popover nzAddonBeforeIcon="anticon anticon-lock">
          <input nz-input type="password" formControlName="password" placeholder="至少6位密码,区分大小写">
        </nz-input-group>
        <nz-form-explain *ngIf="password.dirty && password.errors">请输入密码!</nz-form-explain>
        <ng-template #nzTemplate>
          <div style="padding: 4px 0;">
            <ng-container [ngSwitch]="status">
              <div *ngSwitchCase="'ok'" class="success">强度:强</div>
              <div *ngSwitchCase="'pass'" class="warning">强度:中</div>
              <div *ngSwitchDefault class="error">强度:太短</div>
            </ng-container>
            <div class="progress-{{status}}">
              <nz-progress [nzPercent]="progress" [nzStatus]="passwordProgressMap[status]" [nzStrokeWidth]="6" [nzShowInfo]="false"></nz-progress>
            </div>
            <p class="mt-sm">请至少输入 6 个字符。请不要使用容易被猜到的密码。</p>
          </div>
        </ng-template>
      </nz-popover>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control>
      <nz-input-group nzSize="large" nzAddonBeforeIcon="anticon anticon-lock">
        <input nz-input type="password" formControlName="confirm" placeholder="确认密码">
      </nz-input-group>
      <ng-container *ngIf="confirm.dirty && confirm.errors">
        <nz-form-explain *ngIf="confirm.errors?.required">请确认密码!</nz-form-explain>
        <nz-form-explain *ngIf="confirm.errors?.equar">两次输入的密码不匹配!</nz-form-explain>
      </ng-container>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control>
      <nz-input-group nzSize="large" [nzAddOnBefore]="addOnBeforeTemplate">
        <ng-template #addOnBeforeTemplate>
          <nz-select formControlName="mobilePrefix" style="width: 100px;">
            <nz-option [nzLabel]="'+86'" [nzValue]="'+86'"></nz-option>
            <nz-option [nzLabel]="'+87'" [nzValue]="'+87'"></nz-option>
          </nz-select>
        </ng-template>
        <input formControlName="mobile" nz-input>
      </nz-input-group>
      <nz-form-explain *ngIf="mobile.dirty && mobile.errors">请输入手机号!</nz-form-explain>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control>
      <nz-row [nzGutter]="8">
        <nz-col [nzSpan]="16">
          <nz-input-group nzSize="large" nzAddonBeforeIcon="anticon anticon-mail">
            <input nz-input formControlName="captcha" placeholder="验证码">
          </nz-input-group>
          <nz-form-explain *ngIf="captcha.dirty && captcha.errors">请输入验证码!</nz-form-explain>
        </nz-col>
        <nz-col [nzSpan]="8">
          <button nz-button nzSize="large" (click)="getCaptcha()" [disabled]="count" class="ant-btn__block">{{ count ? count + 's' : '获取验证码' }}</button>
        </nz-col>
      </nz-row>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <button nz-button nzType="primary" nzSize="large" type="submit" [nzLoading]="loading" class="submit">
      <span>注册</span>
    </button>
    <a class="login" routerLink="/passport/login">使用已有账户登录</a>
  </nz-form-item>
</form>
src/app/routes/passport/register/register.component.less
New file
@@ -0,0 +1,42 @@
@import 'node_modules/@delon/theme/styles/default';
:host {
  display: block;
  width: 368px;
  margin: 0 auto;
  ::ng-deep {
    h3 {
      font-size: 16px;
      margin-bottom: 20px;
    }
    .submit {
      width: 50%;
    }
    .login {
      float: right;
      line-height: @btn-height-lg;
    }
  }
}
::ng-deep {
  .register-password-cdk {
    .success,
    .warning,
    .error {
      transition: color 0.3s;
    }
    .success {
      color: @success-color;
    }
    .warning {
      color: @warning-color;
    }
    .error {
      color: @error-color;
    }
    .progress-pass > .progress {
      .ant-progress-bg {
        background-color: @warning-color;
      }
    }
  }
}
src/app/routes/passport/register/register.component.ts
New file
@@ -0,0 +1,133 @@
import { Component, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import {
  FormGroup,
  FormBuilder,
  Validators,
  FormControl,
} from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd';
@Component({
  selector: 'passport-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.less'],
})
export class UserRegisterComponent implements OnDestroy {
  form: FormGroup;
  error = '';
  type = 0;
  loading = false;
  visible = false;
  status = 'pool';
  progress = 0;
  passwordProgressMap = {
    ok: 'success',
    pass: 'normal',
    pool: 'exception',
  };
  constructor(
    fb: FormBuilder,
    private router: Router,
    public msg: NzMessageService,
  ) {
    this.form = fb.group({
      mail: [null, [Validators.email]],
      password: [
        null,
        [
          Validators.required,
          Validators.minLength(6),
          UserRegisterComponent.checkPassword.bind(this),
        ],
      ],
      confirm: [
        null,
        [
          Validators.required,
          Validators.minLength(6),
          UserRegisterComponent.passwordEquar,
        ],
      ],
      mobilePrefix: ['+86'],
      mobile: [null, [Validators.required, Validators.pattern(/^1\d{10}$/)]],
      captcha: [null, [Validators.required]],
    });
  }
  static checkPassword(control: FormControl) {
    if (!control) return null;
    const self: any = this;
    self.visible = !!control.value;
    if (control.value && control.value.length > 9) self.status = 'ok';
    else if (control.value && control.value.length > 5) self.status = 'pass';
    else self.status = 'pool';
    if (self.visible)
      self.progress =
        control.value.length * 10 > 100 ? 100 : control.value.length * 10;
  }
  static passwordEquar(control: FormControl) {
    if (!control || !control.parent) return null;
    if (control.value !== control.parent.get('password').value) {
      return { equar: true };
    }
    return null;
  }
  // region: fields
  get mail() {
    return this.form.controls.mail;
  }
  get password() {
    return this.form.controls.password;
  }
  get confirm() {
    return this.form.controls.confirm;
  }
  get mobile() {
    return this.form.controls.mobile;
  }
  get captcha() {
    return this.form.controls.captcha;
  }
  // endregion
  // region: get captcha
  count = 0;
  interval$: any;
  getCaptcha() {
    this.count = 59;
    this.interval$ = setInterval(() => {
      this.count -= 1;
      if (this.count <= 0) clearInterval(this.interval$);
    }, 1000);
  }
  // endregion
  submit() {
    this.error = '';
    for (const i in this.form.controls) {
      this.form.controls[i].markAsDirty();
      this.form.controls[i].updateValueAndValidity();
    }
    if (this.form.invalid) return;
    // mock http
    this.loading = true;
    setTimeout(() => {
      this.loading = false;
      this.router.navigate(['/passport/register-result']);
    }, 1000);
  }
  ngOnDestroy(): void {
    if (this.interval$) clearInterval(this.interval$);
  }
}
src/app/routes/pro/form/advanced-form/advanced-form.component.html
New file
@@ -0,0 +1,218 @@
<page-header [title]="'高级表单'">
  高级表单常见于一次性输入和提交大批量数据的场景。(示例采用响应式表单,也可使用模板驱动方式)
</page-header>
<form nz-form [formGroup]="form" (ngSubmit)="_submitForm()" [nzLayout]="'vertical'">
  <nz-card [nzBordered]="false" nzTitle="仓库管理">
    <nz-row nzGutter="16">
      <nz-col nzLg="6" nzMd="12" nzSm="24">
        <nz-form-item>
          <nz-form-label nzFor="name">仓库名</nz-form-label>
          <nz-form-control>
            <input nz-input formControlName="name" id="name" placeholder="请输入仓库名称">
            <nz-form-explain *ngIf="(name.dirty || name.touched) && name.errors?.required">
              请输入仓库名称
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzXl]="{span:6, offset:2}" [nzLg]="{span:8}" [nzMd]="{span:12}" nzSm="24">
        <nz-form-item>
          <nz-form-label>仓库域名</nz-form-label>
          <nz-form-control>
            <nz-input-group nzAddOnBefore="http://" nzAddOnAfter=".com">
              <input nz-input formControlName="url" placeholder="请输入">
            </nz-input-group>
            <nz-form-explain *ngIf="(url.dirty || url.touched) && url.errors?.required">
              请输入仓库域名
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzXl]="{span:8, offset:2}" [nzLg]="{span:10}" [nzMd]="{span:24}" nzSm="24">
        <nz-form-item>
          <nz-form-label>仓库管理员</nz-form-label>
          <nz-form-control>
            <nz-select formControlName="owner" [nzPlaceHolder]="'请选择管理员'" [nzShowSearch]="true">
              <nz-option *ngFor="let i of users" [nzLabel]="i.label" [nzValue]="i.value"></nz-option>
            </nz-select>
            <nz-form-explain *ngIf="(owner.dirty || owner.touched) && owner.errors?.required">
              请选择管理员
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
    </nz-row>
    <nz-row nzGutter="16">
      <nz-col nzLg="6" nzMd="12" nzSm="24">
        <nz-form-item>
          <nz-form-label>审批员</nz-form-label>
          <nz-form-control>
            <nz-select formControlName="approver" [nzPlaceHolder]="'请选择管理员'" [nzShowSearch]="true">
              <nz-option *ngFor="let i of users" [nzLabel]="i.label" [nzValue]="i.value">
              </nz-option>
            </nz-select>
            <nz-form-explain *ngIf="(approver.dirty || approver.touched) && approver.errors?.required">
              请选择审批员
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzXl]="{span:6, offset:2}" [nzLg]="{span:8}" [nzMd]="{span:12}" nzSm="24">
        <nz-form-item>
          <nz-form-label>生效日期</nz-form-label>
          <nz-form-control>
            <nz-range-picker formControlName="date_range" [nzStyle]="{width: '100%'}"></nz-range-picker>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzXl]="{span:8, offset:2}" [nzLg]="{span:10}" [nzMd]="{span:24}" nzSm="24">
        <nz-form-item>
          <nz-form-label>仓库类型</nz-form-label>
          <nz-form-control>
            <nz-select formControlName="type" [nzShowSearch]="true" [nzPlaceHolder]="'请选择仓库类型'">
              <nz-option [nzLabel]="'私密'" [nzValue]="'private'"></nz-option>
              <nz-option [nzLabel]="'公开'" [nzValue]="'public'"></nz-option>
            </nz-select>
            <nz-form-explain *ngIf="(type.dirty || type.touched) && type.errors?.required">
              请选择仓库类型
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
    </nz-row>
  </nz-card>
  <nz-card [nzBordered]="false" nzTitle="任务管理">
    <nz-row nzGutter="16">
      <nz-col nzLg="6" nzMd="12" nzSm="24">
        <nz-form-item>
          <nz-form-label>任务名</nz-form-label>
          <nz-form-control>
            <input nz-input formControlName="name2" placeholder="请输入任务名">
            <nz-form-explain *ngIf="(name2.dirty || name2.touched) && name2.errors?.required">
              请输入任务名
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzXl]="{span:6, offset:2}" [nzLg]="{span:8}" [nzMd]="{span:12}" nzSm="24">
        <nz-form-item>
          <nz-form-label>任务描述</nz-form-label>
          <nz-form-control>
            <textarea nz-input formControlName="summary" [nzAutosize]="true" placeholder="请输入任务描述"></textarea>
            <nz-form-explain *ngIf="(summary.dirty || summary.touched) && summary.errors?.required">
              请输入任务描述
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzXl]="{span:8, offset:2}" [nzLg]="{span:10}" [nzMd]="{span:24}" nzSm="24">
        <nz-form-item>
          <nz-form-label>执行人</nz-form-label>
          <nz-form-control>
            <nz-select formControlName="owner2" [nzPlaceHolder]="'请选择执行人'" [nzShowSearch]="true">
              <nz-option *ngFor="let i of users" [nzLabel]="i.label" [nzValue]="i.value">
              </nz-option>
            </nz-select>
            <nz-form-explain *ngIf="(owner2.dirty || owner2.touched) && owner2.errors?.required">
              请选择执行人
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
    </nz-row>
    <nz-row nzGutter="16">
      <nz-col nzLg="6" nzMd="12" nzSm="24">
        <nz-form-item>
          <nz-form-label>责任人</nz-form-label>
          <nz-form-control>
            <nz-select formControlName="approver2" [nzPlaceHolder]="'请选择责任人'" [nzShowSearch]="true">
              <nz-option *ngFor="let i of users" [nzLabel]="i.label" [nzValue]="i.value"></nz-option>
            </nz-select>
            <nz-form-explain *ngIf="(approver2.dirty || approver2.touched) && approver2.errors?.required">
              请选择责任人
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzXl]="{span:6, offset:2}" [nzLg]="{span:8}" [nzMd]="{span:12}" nzSm="24">
        <nz-form-item>
          <nz-form-label>生效时间</nz-form-label>
          <nz-form-control>
            <nz-time-picker formControlName="time"></nz-time-picker>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzXl]="{span:8, offset:2}" [nzLg]="{span:10}" [nzMd]="{span:24}" nzSm="24">
        <nz-form-item>
          <nz-form-label>任务类型</nz-form-label>
          <nz-form-control>
            <nz-select formControlName="type2" [nzShowSearch]="true" [nzPlaceHolder]="'请选择任务类型'">
              <nz-option [nzLabel]="'私密'" [nzValue]="'private'"></nz-option>
              <nz-option [nzLabel]="'公开'" [nzValue]="'public'"></nz-option>
            </nz-select>
            <nz-form-explain *ngIf="(type2.dirty || type2.touched) && type2.errors?.required">
              请选择任务类型
            </nz-form-explain>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
    </nz-row>
  </nz-card>
  <nz-card [nzBordered]="false" nzTitle="成员管理">
    <nz-table formArrayName="items" [nzData]="items.value" [nzShowPagination]="false">
      <thead>
        <tr>
          <th>成员姓名</th>
          <th>工号</th>
          <th>所属部门</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let item of items.controls; let i = index" [formGroupName]="i">
          <td>
            <span *ngIf="editIndex!==i">{{items.value[i].name}}</span>
            <span *ngIf="editIndex===i" nz-form-control>
              <input nz-input formControlName="name" placeholder="请输入成员姓名">
            </span>
          </td>
          <td>
            <span *ngIf="editIndex!==i">{{items.value[i].workId}}</span>
            <span *ngIf="editIndex===i" nz-form-control>
              <input nz-input formControlName="workId" placeholder="请输入工号">
            </span>
          </td>
          <td>
            <span *ngIf="editIndex!==i">{{items.value[i].department}}</span>
            <span *ngIf="editIndex===i" nz-form-control>
              <input nz-input formControlName="department" placeholder="请输入所属部门">
            </span>
          </td>
          <td>
            <span *ngIf="editIndex!==i">
              <a (click)="edit(i)">编辑</a>
              <nz-divider nzType="vertical"></nz-divider>
              <nz-popconfirm (nzOnConfirm)="del(i)" [nzTitle]="'是否要删除此行?'">
                <a nz-popconfirm>删除</a>
              </nz-popconfirm>
            </span>
            <span *ngIf="editIndex===i">
              <a (click)="save(i)">保存</a>
              <nz-divider nzType="vertical"></nz-divider>
              <nz-popconfirm (nzOnConfirm)="cancel(i)" [nzTitle]="'是否要取消操作?'">
                <a nz-popconfirm>取消</a>
              </nz-popconfirm>
            </span>
          </td>
        </tr>
      </tbody>
    </nz-table>
    <button *ngIf="editIndex===-1" nz-button [nzType]="'dashed'" (click)="add()" class="ant-btn__block mt-md">
      <i class="anticon anticon-plus"></i>
      <span>新增成员</span>
    </button>
  </nz-card>
  <footer-toolbar errorCollect>
    <button nz-button type="primary" nzType="primary">提交</button>
  </footer-toolbar>
</form>
src/app/routes/pro/form/advanced-form/advanced-form.component.ts
New file
@@ -0,0 +1,156 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
@Component({
  selector: 'app-advanced-form',
  templateUrl: './advanced-form.component.html',
})
export class AdvancedFormComponent implements OnInit {
  editIndex = -1;
  editObj = {};
  form: FormGroup;
  users: any[] = [
    { value: 'xiao', label: '付晓晓' },
    { value: 'mao', label: '周毛毛' },
  ];
  constructor(private fb: FormBuilder) {}
  ngOnInit() {
    this.form = this.fb.group({
      name: [null, [Validators.required]],
      url: [null, [Validators.required]],
      owner: [undefined, [Validators.required]],
      approver: [null, [Validators.required]],
      date_range: [null, [Validators.required]],
      type: [null, [Validators.required]],
      name2: [null, [Validators.required]],
      summary: [null, [Validators.required]],
      owner2: [null, [Validators.required]],
      approver2: [null, [Validators.required]],
      time: [null, [Validators.required]],
      type2: [null, [Validators.required]],
      items: this.fb.array([]),
    });
    const userList = [
      {
        key: '1',
        workId: '00001',
        name: 'John Brown',
        department: 'New York No. 1 Lake Park',
      },
      {
        key: '2',
        workId: '00002',
        name: 'Jim Green',
        department: 'London No. 1 Lake Park',
      },
      {
        key: '3',
        workId: '00003',
        name: 'Joe Black',
        department: 'Sidney No. 1 Lake Park',
      },
    ];
    userList.forEach(i => {
      const field = this.createUser();
      field.patchValue(i);
      this.items.push(field);
    });
  }
  createUser(): FormGroup {
    return this.fb.group({
      key: [null],
      workId: [null, [Validators.required]],
      name: [null, [Validators.required]],
      department: [null, [Validators.required]],
    });
  }
  //#region get form fields
  get name() {
    return this.form.controls.name;
  }
  get url() {
    return this.form.controls.url;
  }
  get owner() {
    return this.form.controls.owner;
  }
  get approver() {
    return this.form.controls.approver;
  }
  get time_start() {
    return this.form.controls.time_start;
  }
  get time_end() {
    return this.form.controls.time_end;
  }
  get type() {
    return this.form.controls.type;
  }
  get name2() {
    return this.form.controls.name2;
  }
  get summary() {
    return this.form.controls.summary;
  }
  get owner2() {
    return this.form.controls.owner2;
  }
  get approver2() {
    return this.form.controls.approver2;
  }
  get time() {
    return this.form.controls.time;
  }
  get type2() {
    return this.form.controls.type2;
  }
  get items() {
    return this.form.controls.items as FormArray;
  }
  //#endregion
  add() {
    this.items.push(this.createUser());
    this.edit(this.items.length - 1);
  }
  del(index: number) {
    this.items.removeAt(index);
  }
  edit(index: number) {
    if (this.editIndex !== -1 && this.editObj) {
      this.items.at(this.editIndex).patchValue(this.editObj);
    }
    this.editObj = { ...this.items.at(index).value };
    this.editIndex = index;
  }
  save(index: number) {
    this.items.at(index).markAsDirty();
    if (this.items.at(index).invalid) return;
    this.editIndex = -1;
  }
  cancel(index: number) {
    if (!this.items.at(index).value.key) {
      this.del(index);
    } else {
      this.items.at(index).patchValue(this.editObj);
    }
    this.editIndex = -1;
  }
  _submitForm() {
    for (const i in this.form.controls) {
      this.form.controls[i].markAsDirty();
      this.form.controls[i].updateValueAndValidity();
    }
    if (this.form.invalid) return;
  }
}
src/app/routes/pro/form/basic-form/basic-form.component.html
New file
@@ -0,0 +1,78 @@
<page-header [title]="'基础表单'">
  将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。
</page-header>
<nz-card [nzBordered]="false">
  <form nz-form [formGroup]="form" (ngSubmit)="submit()">
    <nz-form-item>
      <nz-form-label nzXs="24" nzSm="7" nzRequired nzFor="title">标题</nz-form-label>
      <nz-form-control nzXs="24" nzSm="12" nzMd="10">
        <input nz-input formControlName="title" id="title" placeholder="给目标起个名字">
        <nz-form-explain *ngIf="form.get('title').dirty && form.get('title').errors">请输入标题</nz-form-explain>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-label nzXs="24" nzSm="7" nzRequired nzFor="date">起止日期</nz-form-label>
      <nz-form-control nzXs="24" nzSm="12" nzMd="10">
        <nz-range-picker formControlName="date" [nzStyle]="{width: '100%'}"></nz-range-picker>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-label nzXs="24" nzSm="7" nzRequired nzFor="goal">目标描述</nz-form-label>
      <nz-form-control nzXs="24" nzSm="12" nzMd="10">
        <textarea nz-input formControlName="goal" id="goal" [nzAutosize]="{minRows: 4}" placeholder="请输入你的阶段性工作目标"></textarea>
        <nz-form-explain *ngIf="form.get('goal').dirty && form.get('goal').errors">请输入目标描述</nz-form-explain>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-label nzXs="24" nzSm="7" nzRequired nzFor="standard">衡量标准</nz-form-label>
      <nz-form-control nzXs="24" nzSm="12" nzMd="10">
        <textarea nz-input formControlName="standard" id="standard" [nzAutosize]="{minRows: 4}" placeholder="请输入衡量标准"></textarea>
        <nz-form-explain *ngIf="form.get('standard').dirty && form.get('standard').errors">请输入衡量标准</nz-form-explain>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-label nzXs="24" nzSm="7" nzFor="client">
        客户
        <em>
          <nz-tooltip nzTitle="目标的服务对象">
            <i nz-tooltip class="anticon anticon-info-circle-o"></i>
          </nz-tooltip>
        </em>
      </nz-form-label>
      <nz-form-control nzXs="24" nzSm="12" nzMd="10">
        <input nz-input formControlName="client" id="client" placeholder="请描述你服务的客户,内部客户直接 @姓名/工号">
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-label nzXs="24" nzSm="7" nzFor="invites">邀评人</nz-form-label>
      <nz-form-control nzXs="24" nzSm="12" nzMd="10">
        <input nz-input formControlName="invites" id="invites" placeholder="请直接 @姓名/工号,最多可邀请 5 人">
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-label nzXs="24" nzSm="7" nzFor="weight">权重</nz-form-label>
      <nz-form-control nzXs="24" nzSm="12" nzMd="10">
        <nz-input-number formControlName="weight" id="weight" placeholder="请输入"></nz-input-number>
        <em>%</em>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-label nzXs="24" nzSm="7" nzFor="public">目标公开</nz-form-label>
      <nz-form-control nzXs="24" nzSm="12" nzMd="10">
        <nz-radio-group formControlName="public">
          <label nz-radio [nzValue]="1">公开</label>
          <label nz-radio [nzValue]="2">部分公开</label>
          <label nz-radio [nzValue]="3">不公开</label>
        </nz-radio-group>
        <input *ngIf="form.value.public === 2" nz-input formControlName="publicUsers" placeholder="公开给">
        <nz-form-explain>客户、邀评人默认被分享</nz-form-explain>
      </nz-form-control>
    </nz-form-item>
    <nz-form-item>
      <nz-form-control [nzXs]="{ span: 24, offset: 0 }" [nzSm]="{ span: 10, offset: 7 }">
        <button nz-button nzType="primary" type="submit" [nzLoading]="submitting">提交</button>
        <button nz-button class="ml-sm">保存</button>
      </nz-form-control>
    </nz-form-item>
  </form>
</nz-card>
src/app/routes/pro/form/basic-form/basic-form.component.ts
New file
@@ -0,0 +1,41 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd';
@Component({
  selector: 'app-basic-form',
  templateUrl: './basic-form.component.html',
})
export class BasicFormComponent implements OnInit {
  form: FormGroup;
  submitting = false;
  constructor(private fb: FormBuilder, private msg: NzMessageService) {}
  ngOnInit(): void {
    this.form = this.fb.group({
      title: [null, [Validators.required]],
      date: [null, [Validators.required]],
      goal: [null, [Validators.required]],
      standard: [null, [Validators.required]],
      client: [null, []],
      invites: [null, []],
      weight: [null, []],
      public: [1, [Validators.min(1), Validators.max(3)]],
      publicUsers: [null, []],
    });
  }
  submit() {
    for (const i in this.form.controls) {
      this.form.controls[i].markAsDirty();
      this.form.controls[i].updateValueAndValidity();
    }
    if (this.form.invalid) return;
    this.submitting = true;
    setTimeout(() => {
      this.submitting = false;
      this.msg.success(`提交成功`);
    }, 1000);
  }
}
src/app/routes/pro/form/step-form/step-form.component.html
New file
@@ -0,0 +1,13 @@
<page-header [title]="'分步表单'">
  将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。
</page-header>
<nz-card [nzBordered]="false">
  <nz-steps [(nzCurrent)]="item.step">
    <nz-step nzTitle="填写转账信息"></nz-step>
    <nz-step nzTitle="确认转账信息"></nz-step>
    <nz-step nzTitle="完成"></nz-step>
  </nz-steps>
  <app-step1 *ngIf="item.step==0"></app-step1>
  <app-step2 *ngIf="item.step==1"></app-step2>
  <app-step3 *ngIf="item.step==2"></app-step3>
</nz-card>
src/app/routes/pro/form/step-form/step-form.component.less
New file
@@ -0,0 +1,26 @@
:host {
  display: block;
  ::ng-deep {
    .ant-steps {
      max-width: 750px;
      margin: 16px auto;
    }
    [nz-form] {
      margin: 40px auto 0;
      max-width: 500px;
    }
    app-step3 {
      display: block;
      text-align: center;
      width: 72%;
      max-width: 560px;
      margin: 0 auto;
    }
    .extra {
      background: #fafafa;
      padding: 24px 40px;
      border-radius: 2px;
      text-align: left;
    }
  }
}
src/app/routes/pro/form/step-form/step-form.component.ts
New file
@@ -0,0 +1,16 @@
import { Component, AfterViewInit, ViewEncapsulation } from '@angular/core';
import { TransferService } from './transfer.service';
@Component({
  selector: 'app-step-form',
  templateUrl: './step-form.component.html',
  styleUrls: ['./step-form.component.less'],
  providers: [TransferService],
})
export class StepFormComponent implements AfterViewInit {
  constructor(public item: TransferService) {}
  ngAfterViewInit() {
    console.log('item', this.item);
  }
}
src/app/routes/pro/form/step-form/step1.component.html
New file
@@ -0,0 +1,59 @@
<form nz-form [formGroup]="form" (ngSubmit)="_submitForm()">
  <nz-form-item>
    <nz-form-label nzSpan="5" nzRequired>付款账户</nz-form-label>
    <nz-form-control [nzSpan]="19">
      <nz-select formControlName="pay_account">
        <nz-option [nzLabel]="item.pay_account" [nzValue]="item.pay_account"></nz-option>
      </nz-select>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-label nzSpan="5" nzRequired nzFor="receiver_account">收款账户</nz-form-label>
    <nz-form-control nzSpan="19">
      <nz-input-group nzCompact>
        <nz-select formControlName="receiver_type" style="width: 100px;">
          <nz-option [nzLabel]="'支付宝'" [nzValue]="'alipay'"></nz-option>
          <nz-option [nzLabel]="'银行账号'" [nzValue]="'bank'"></nz-option>
        </nz-select>
        <input formControlName="receiver_account" id="receiver_account" nz-input style="width: calc(100% - 100px);">
      </nz-input-group>
      <nz-form-explain *ngIf="(receiver_account.dirty || receiver_account.touched) && receiver_account.errors?.required">
        请输入收款账户
      </nz-form-explain>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-label nzSpan="5" nzRequired nzFor="receiver_name">收款姓名</nz-form-label>
    <nz-form-control nzSpan="19">
      <input nz-input formControlName="receiver_name" id="receiver_name">
      <ng-container *ngIf="receiver_name.dirty || receiver_name.touched">
        <nz-form-explain *ngIf="receiver_name.errors?.required">请输入收款姓名</nz-form-explain>
        <nz-form-explain *ngIf="receiver_name.errors?.minlength">至少2个字符以上</nz-form-explain>
      </ng-container>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-label nzSpan="5" nzRequired nzFor="amount">转账金额</nz-form-label>
    <nz-form-control nzSpan="19">
      <input nz-input formControlName="amount" id="amount" nzAddonAfter="¥">
      <ng-container *ngIf="amount.dirty || amount.touched">
        <nz-form-explain *ngIf="amount.errors?.required">请输入转账金额</nz-form-explain>
        <nz-form-explain *ngIf="amount.errors?.pattern">金额只能是正整数</nz-form-explain>
        <nz-form-explain *ngIf="amount.errors?.min">金额最少1元以上</nz-form-explain>
        <nz-form-explain *ngIf="amount.errors?.max">金额最多100万以内</nz-form-explain>
      </ng-container>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control nzSpan="19" nzOffset="5">
      <button nz-button nzType="primary" [disabled]="form.invalid">下一步</button>
    </nz-form-control>
  </nz-form-item>
</form>
<div class="border-top-1 mt-lg px-lg text-grey-dark">
  <h3 class="h3 my-md">说明</h3>
  <h4 class="h4 mb-sm">转账到支付宝账户</h4>
  <p class="mb-sm">如果需要,这里可以放一些关于产品的常见问题说明。如果需要,这里可以放一些关于产品的常见问题说明。如果需要,这里可以放一些关于产品的常见问题说明。</p>
  <h4 class="h4 mb-sm">转账到银行卡</h4>
  <p>如果需要,这里可以放一些关于产品的常见问题说明。如果需要,这里可以放一些关于产品的常见问题说明。如果需要,这里可以放一些关于产品的常见问题说明。</p>
</div>
src/app/routes/pro/form/step-form/step1.component.ts
New file
@@ -0,0 +1,61 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { TransferService } from './transfer.service';
@Component({
  selector: 'app-step1',
  templateUrl: './step1.component.html',
})
export class Step1Component implements OnInit {
  form: FormGroup;
  constructor(private fb: FormBuilder, public item: TransferService) {}
  ngOnInit() {
    this.form = this.fb.group({
      pay_account: [
        null,
        Validators.compose([Validators.required, Validators.email]),
      ],
      receiver_type: [null, [Validators.required]],
      receiver_account: [null, [Validators.required]],
      receiver_name: [
        null,
        Validators.compose([Validators.required, Validators.minLength(2)]),
      ],
      amount: [
        null,
        Validators.compose([
          Validators.required,
          Validators.pattern(`[0-9]+`),
          Validators.min(1),
          Validators.max(10000 * 100),
        ]),
      ],
    });
    this.form.patchValue(this.item);
  }
  //#region get form fields
  get pay_account() {
    return this.form.controls['pay_account'];
  }
  get receiver_type() {
    return this.form.controls['receiver_type'];
  }
  get receiver_account() {
    return this.form.controls['receiver_account'];
  }
  get receiver_name() {
    return this.form.controls['receiver_name'];
  }
  get amount() {
    return this.form.controls['amount'];
  }
  //#endregion
  _submitForm() {
    this.item = Object.assign(this.item, this.form.value);
    ++this.item.step;
  }
}
src/app/routes/pro/form/step-form/step2.component.html
New file
@@ -0,0 +1,51 @@
<form nz-form [formGroup]="form" (ngSubmit)="_submitForm()">
  <nz-alert class="pb-lg" [nzMessage]="'确认转账后,资金将直接打入对方账户,无法退回。'" [nzShowIcon]="true" [nzCloseable]="true"></nz-alert>
  <nz-form-item>
    <nz-form-label nzSpan="5">付款账户</nz-form-label>
    <nz-form-control nzSpan="19">
      <nz-form-text>{{item.pay_account}}</nz-form-text>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-label nzSpan="5">账户类型</nz-form-label>
    <nz-form-control nzSpan="19">
      <nz-form-text>{{item.receiver_type==='alipay' ? '支付宝' : '银行'}}</nz-form-text>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-label nzSpan="5">收款账户</nz-form-label>
    <nz-form-control nzSpan="19">
      <nz-form-text>{{item.receiver_account}}</nz-form-text>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-label nzSpan="5">收款人姓名</nz-form-label>
    <nz-form-control nzSpan="19">
      <nz-form-text>{{item.receiver_name}}</nz-form-text>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-label nzSpan="5">转账金额</nz-form-label>
    <nz-form-control nzSpan="19">
      <nz-form-text>
        <strong class="text-lg">{{item.amount}}</strong>
      </nz-form-text>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item class="border-top-1 mt-lg pt-lg">
    <nz-form-label nzSpan="5" nzRequired nzFor="password">支付密码</nz-form-label>
    <nz-form-control nzSpan="19">
      <input nz-input formControlName="password" type="password" id="password">
      <ng-container *ngIf="password.dirty || password.touched">
        <nz-form-explain *ngIf="password.errors?.required">请输入密码</nz-form-explain>
        <nz-form-explain *ngIf="password.errors?.minlength">至少6位数以上</nz-form-explain>
      </ng-container>
    </nz-form-control>
  </nz-form-item>
  <nz-form-item>
    <nz-form-control [nzSpan]="19" [nzOffset]="5">
      <button nz-button [nzType]="'primary'" [nzLoading]="loading" [disabled]="form.invalid">提交</button>
      <button nz-button (click)="prev()">上一步</button>
    </nz-form-control>
  </nz-form-item>
</form>
src/app/routes/pro/form/step-form/step2.component.ts
New file
@@ -0,0 +1,42 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { TransferService } from './transfer.service';
@Component({
  selector: 'app-step2',
  templateUrl: './step2.component.html',
})
export class Step2Component implements OnInit {
  form: FormGroup;
  loading = false;
  constructor(private fb: FormBuilder, public item: TransferService) {}
  ngOnInit() {
    this.form = this.fb.group({
      password: [
        null,
        Validators.compose([Validators.required, Validators.minLength(6)]),
      ],
    });
    this.form.patchValue(this.item);
  }
  //#region get form fields
  get password() {
    return this.form.controls.password;
  }
  //#endregion
  _submitForm() {
    this.loading = true;
    setTimeout(() => {
      this.loading = false;
      ++this.item.step;
    }, 1000 * 2);
  }
  prev() {
    --this.item.step;
  }
}
src/app/routes/pro/form/step-form/step3.component.html
New file
@@ -0,0 +1,34 @@
<div class="icon pt-md">
  <i class="anticon anticon-check-circle text-success icon-lg"></i>
</div>
<h1 class="h2 pt-md">操作成功</h1>
<p class="pt-md text-grey">预计两小时内到账</p>
<div class="extra mt-md">
  <div nz-row class="mb-md">
    <div nz-col [nzSm]="8" class="text-right">付款账户:</div>
    <div nz-col [nzSm]="16">{{item.pay_account}}</div>
  </div>
  <div nz-row class="mb-md">
    <div nz-col [nzSm]="8" class="text-right">账户类型:</div>
    <div nz-col [nzSm]="16">{{item.receiver_type_str}}</div>
  </div>
  <div nz-row class="mb-md">
    <div nz-col [nzSm]="8" class="text-right">收款账户:</div>
    <div nz-col [nzSm]="16">{{item.receiver_account}}</div>
  </div>
  <div nz-row class="mb-md">
    <div nz-col [nzSm]="8" class="text-right">收款人姓名:</div>
    <div nz-col [nzSm]="16">{{item.receiver_name}}</div>
  </div>
  <div nz-row>
    <div nz-col [nzSm]="8" class="text-right">转账金额:</div>
    <div nz-col [nzSm]="16">
      <strong class="text-lg pr-sm">{{item.amount}}</strong>元</div>
  </div>
</div>
<div nz-row class="my-md py-md">
  <div nz-col>
    <button nz-button (click)="item.again()" [nzType]="'primary'">再转一笔</button>
    <button nz-button class="ml-sm">查看账单</button>
  </div>
</div>
src/app/routes/pro/form/step-form/step3.component.ts
New file
@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { TransferService } from './transfer.service';
@Component({
  selector: 'app-step3',
  templateUrl: './step3.component.html',
})
export class Step3Component {
  constructor(public item: TransferService) {}
}
src/app/routes/pro/form/step-form/transfer.service.ts
New file
@@ -0,0 +1,53 @@
import { Injectable } from '@angular/core';
@Injectable()
export class TransferService {
  step: 0 | 1 | 2 = 1;
  /**
   * 付款账户
   */
  pay_account: string;
  /**
   * 收款账户类型
   */
  receiver_type: 'alipay' | 'bank';
  get receiver_type_str() {
    return this.receiver_type === 'alipay' ? '支付宝' : '银行';
  }
  /**
   * 收款账户
   */
  receiver_account: string;
  /**
   * 收款姓名
   */
  receiver_name: string;
  /**
   * 金额
   */
  amount: number;
  /**
   * 支付密码
   */
  password = '123456';
  again() {
    this.step = 0;
    this.pay_account = 'ant-design@alipay.com';
    this.receiver_type = 'alipay';
    this.receiver_account = 'test@example.com';
    this.receiver_name = 'asdf';
    this.amount = 500;
  }
  constructor() {
    this.again();
  }
}
src/app/routes/pro/list/applications/applications.component.html
New file
@@ -0,0 +1,92 @@
<nz-card [nzBordered]="false">
  <form nz-form [nzLayout]="'inline'">
    <standard-form-row [title]="'所属类目'" block style="padding-bottom: 11px;">
      <nz-form-item>
        <nz-form-control>
          <tag-select>
            <nz-tag *ngFor="let i of categories; let idx = index" nzMode="checkable" [nzChecked]="i.value" (nzCheckedChange)="changeCategory($event, idx)">
              {{i.text}}
            </nz-tag>
          </tag-select>
        </nz-form-control>
      </nz-form-item>
    </standard-form-row>
    <standard-form-row [title]="'其它选项'" grid last>
      <nz-row [nzGutter]="16">
        <nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="10" nzXl="8">
          <nz-form-item>
            <nz-form-label nzFor="rate">作者</nz-form-label>
            <nz-form-control nzXs="24" nzSm="24" nzMd="12">
              <nz-select [(ngModel)]="q.user" name="user" [nzPlaceHolder]="'不限'" [nzShowSearch]="true" style="width: 200px;">
                <nz-option [nzLabel]="'王昭君'" [nzValue]="'lisa'"></nz-option>
                <nz-option [nzLabel]="'李白'" [nzValue]="'libai'"></nz-option>
                <nz-option [nzLabel]="'妲己'" [nzValue]="'daji'"></nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </nz-col>
        <nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="10" nzXl="8">
          <nz-form-item>
            <nz-form-label nzFor="rate">好评度</nz-form-label>
            <nz-form-control nzXs="24" nzSm="24" nzMd="12">
              <nz-select [(ngModel)]="q.rate" name="rate" [nzPlaceHolder]="'不限'" [nzShowSearch]="true" style="width: 200px;">
                <nz-option [nzLabel]="'优秀'" [nzValue]="'good'"></nz-option>
                <nz-option [nzLabel]="'普通'" [nzValue]="'normal'"></nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </nz-col>
      </nz-row>
    </standard-form-row>
  </form>
</nz-card>
<nz-list [nzLoading]="loading" [nzDataSource]="list" [nzRenderItem]="item" [nzGrid]="{ gutter: 24, xl: 6, lg: 8, md: 8, sm: 12, xs: 24 }">
  <ng-template #item let-item>
    <nz-list-item>
      <nz-card nzHoverable [nzActions]="[op1,op2,op3,op4]">
        <ng-template #op1>
          <nz-tooltip [nzTitle]="'下载'">
            <i nz-tooltip class="anticon anticon-download"></i>
          </nz-tooltip>
        </ng-template>
        <ng-template #op2>
          <nz-tooltip [nzTitle]="'编辑'">
            <i nz-tooltip class="anticon anticon-edit"></i>
          </nz-tooltip>
        </ng-template>
        <ng-template #op3>
          <nz-tooltip [nzTitle]="'分享'">
            <i nz-tooltip class="anticon anticon-share-alt"></i>
          </nz-tooltip>
        </ng-template>
        <ng-template #op4>
          <nz-dropdown [nzPlacement]="'bottomLeft'">
            <i nz-dropdown class="anticon anticon-ellipsis"></i>
            <ul nz-menu>
              <li nz-menu-item>1st menu item</li>
              <li nz-menu-item>2st menu item</li>
              <li nz-menu-item>3st menu item</li>
            </ul>
          </nz-dropdown>
        </ng-template>
        <nz-card-meta [nzTitle]="item.title" [nzAvatar]="nzAvatar">
          <ng-template #nzAvatar>
            <nz-avatar nzSize="small" [nzSrc]="item.avatar"></nz-avatar>
          </ng-template>
        </nz-card-meta>
        <div class="card-info d-flex">
          <div>
            <p>活跃用户</p>
            <p>{{item.activeUser}}
              <em class="wan">万</em>
            </p>
          </div>
          <div>
            <p>新增用户</p>
            <p>{{item.newUser | number: '3.'}}</p>
          </div>
        </div>
      </nz-card>
    </nz-list-item>
  </ng-template>
</nz-list>
src/app/routes/pro/list/applications/applications.component.less
New file
@@ -0,0 +1,51 @@
@import 'node_modules/@delon/theme/styles/default';
:host {
  margin-bottom: -24px;
  ::ng-deep {
    .ant-card {
      width: 100%;
    }
    .ant-card-meta-content {
      margin-top: 0;
    } // disabled white space
    .ant-card-meta-avatar {
      font-size: 0;
    }
    .ant-card-actions {
      background: #f7f9fa;
    }
    .ant-list .ant-list-item-content-single {
      max-width: 100%;
    }
    .card-info {
      .clearfix();
      margin-top: 16px;
      margin-left: 40px;
      & > div {
        position: relative;
        text-align: left;
        float: left;
        width: 50%;
        p {
          line-height: 32px;
          font-size: 24px;
          margin: 0;
        }
        p:first-child {
          color: @text-color-secondary;
          font-size: 12px;
          line-height: 20px;
          margin-bottom: 4px;
        }
      }
    }
    .wan {
      position: relative;
      top: -2px;
      font-size: @font-size-base;
      font-style: normal;
      line-height: 20px;
      margin-left: 2px;
    }
  }
}
src/app/routes/pro/list/applications/applications.component.ts
New file
@@ -0,0 +1,76 @@
import { Component, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'pro-list-applications',
  templateUrl: './applications.component.html',
  styleUrls: ['./applications.component.less'],
})
export class ProListApplicationsComponent implements OnInit {
  q: any = {
    ps: 8,
    categories: [],
    owners: ['zxx'],
  };
  list: any[] = [];
  loading = true;
  // region: cateogry
  categories = [
    { id: 0, text: '全部', value: false },
    { id: 1, text: '类目一', value: false },
    { id: 2, text: '类目二', value: false },
    { id: 3, text: '类目三', value: false },
    { id: 4, text: '类目四', value: false },
    { id: 5, text: '类目五', value: false },
    { id: 6, text: '类目六', value: false },
    { id: 7, text: '类目七', value: false },
    { id: 8, text: '类目八', value: false },
    { id: 9, text: '类目九', value: false },
    { id: 10, text: '类目十', value: false },
    { id: 11, text: '类目十一', value: false },
    { id: 12, text: '类目十二', value: false },
  ];
  changeCategory(status: boolean, idx: number) {
    if (idx === 0) {
      this.categories.map(i => (i.value = status));
    } else {
      this.categories[idx].value = status;
    }
    this.getData();
  }
  // endregion
  constructor(private http: _HttpClient, public msg: NzMessageService) {}
  ngOnInit() {
    this.getData();
  }
  getData() {
    this.loading = true;
    this.http.get('/api/list', { count: this.q.ps }).subscribe((res: any) => {
      this.list = res.map(item => {
        item.activeUser = this.formatWan(item.activeUser);
        return item;
      });
      this.loading = false;
    });
  }
  private formatWan(val) {
    const v = val * 1;
    if (!v || isNaN(v)) return '';
    let result = val;
    if (val > 10000) {
      result = Math.floor(val / 10000);
      result = `${result}`;
    }
    return result;
  }
}
src/app/routes/pro/list/articles/articles.component.html
New file
@@ -0,0 +1,91 @@
<nz-card [nzBordered]="false">
  <form nz-form [nzLayout]="'inline'">
    <standard-form-row [title]="'所属类目'" block style="padding-bottom: 11px;">
      <nz-form-item>
        <nz-form-control>
          <tag-select>
            <nz-tag *ngFor="let i of categories; let idx = index" nzMode="checkable" [nzChecked]="i.value" (nzCheckedChange)="changeCategory($event, idx)">
              {{i.text}}
            </nz-tag>
          </tag-select>
        </nz-form-control>
      </nz-form-item>
    </standard-form-row>
    <standard-form-row [title]="'owner'" grid>
      <nz-form-item>
        <nz-form-control>
          <nz-select [(ngModel)]="q.owners" name="owners" [nzMode]="'tags'" style="width: 286px;">
            <nz-option *ngFor="let i of owners" [nzLabel]="i.name" [nzValue]="i.id"></nz-option>
          </nz-select>
          <a class="ml-sm" (click)="setOwner()">只看自己的</a>
        </nz-form-control>
      </nz-form-item>
    </standard-form-row>
    <standard-form-row [title]="'其它选项'" grid last>
      <nz-row [nzGutter]="16">
        <nz-col nzXl="8" nzLg="10" nzMd="12" nzSm="24" nzXs="24">
          <nz-form-item>
            <nz-form-label nzFor="rate">活跃用户</nz-form-label>
            <nz-form-control>
              <nz-select [(ngModel)]="q.user" name="user" [nzPlaceHolder]="'不限'" [nzShowSearch]="true" style="width: 200px;">
                <nz-option [nzLabel]="'李三'" [nzValue]="'lisa'"></nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </nz-col>
        <nz-col nzXl="8" nzLg="10" nzMd="12" nzSm="24" nzXs="24">
          <nz-form-item>
            <nz-form-label nzFor="rate">好评度</nz-form-label>
            <nz-form-control>
              <nz-select [(ngModel)]="q.rate" name="rate" [nzPlaceHolder]="'不限'" [nzShowSearch]="true" style="width: 200px;">
                <nz-option [nzLabel]="'优秀'" [nzValue]="'good'"></nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </nz-col>
      </nz-row>
    </standard-form-row>
  </form>
</nz-card>
<nz-card [nzBordered]="false">
  <nz-list nzItemLayout="vertical" [nzLoading]="loading" [nzDataSource]="list" [nzRenderItem]="item" [nzLoadMore]="loadMore">
    <ng-template #item let-item>
      <nz-list-item [nzContent]="nzContent" [nzExtra]="nzExtra" [nzActions]="[op1,op2,op3]">
        <ng-template #op1>
          <i class="anticon anticon-star-o mr-sm"></i>{{item.star}}</ng-template>
        <ng-template #op2>
          <i class="anticon anticon-like-o mr-sm"></i>{{item.like}}</ng-template>
        <ng-template #op3>
          <i class="anticon anticon-message mr-sm"></i>{{item.message}}</ng-template>
        <ng-template #nzExtra>
          <div style="width: 272px; height: 1px;"></div>
        </ng-template>
        <nz-list-item-meta [nzTitle]="nzTitle" [nzDescription]="nzDescription">
          <ng-template #nzTitle>
            <a href="{{item.href}}" target="_blank">{{item.title}}</a>
          </ng-template>
          <ng-template #nzDescription>
            <nz-tag>Alain</nz-tag>
            <nz-tag>ng-zorro-antd</nz-tag>
            <nz-tag>Ant Design</nz-tag>
          </ng-template>
        </nz-list-item-meta>
        <ng-template #nzContent>
          <p>{{item.content}}</p>
          <div class="mt-md d-flex">
            <nz-avatar [nzSrc]="item.avatar" [nzSize]="'small'" class="mr-sm"></nz-avatar>
            <a href="{{item.href}}" target="_blank">{{item.owner}}</a>
            <span class="px-sm">发布在</span>
            <a href="{{item.href}}" target="_blank">{{item.href}}</a>
            <time class="pl-md text-grey" title="{{item.updatedAt}}">{{item.updatedAt | _date}}</time>
          </div>
        </ng-template>
      </nz-list-item>
    </ng-template>
    <ng-template #loadMore>
      <div class="text-center mt-md">
        <button nz-button (click)="getData(true)" [nzLoading]="loading" [nzType]="'dashed'" style="min-width:200px;">加载更多</button>
      </div>
    </ng-template>
  </nz-list>
</nz-card>
src/app/routes/pro/list/articles/articles.component.ts
New file
@@ -0,0 +1,86 @@
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'pro-list-articles',
  templateUrl: './articles.component.html',
})
export class ProListArticlesComponent implements OnInit {
  q: any = {
    ps: 5,
    categories: [],
    owners: ['zxx'],
  };
  list: any[] = [];
  loading = false;
  // region: cateogry
  categories = [
    { id: 0, text: '全部', value: false },
    { id: 1, text: '类目一', value: false },
    { id: 2, text: '类目二', value: false },
    { id: 3, text: '类目三', value: false },
    { id: 4, text: '类目四', value: false },
    { id: 5, text: '类目五', value: false },
    { id: 6, text: '类目六', value: false },
    { id: 7, text: '类目七', value: false },
    { id: 8, text: '类目八', value: false },
    { id: 9, text: '类目九', value: false },
    { id: 10, text: '类目十', value: false },
    { id: 11, text: '类目十一', value: false },
    { id: 12, text: '类目十二', value: false },
  ];
  changeCategory(status: boolean, idx: number) {
    if (idx === 0) {
      this.categories.map(i => (i.value = status));
    } else {
      this.categories[idx].value = status;
    }
  }
  // endregion
  // region: owners
  owners = [
    {
      id: 'wzj',
      name: '我自己',
    },
    {
      id: 'wjh',
      name: '吴家豪',
    },
    {
      id: 'zxx',
      name: '周星星',
    },
    {
      id: 'zly',
      name: '赵丽颖',
    },
    {
      id: 'ym',
      name: '姚明',
    },
  ];
  setOwner() {
    this.q.owners = [`wzj`];
  }
  // endregion
  constructor(private http: _HttpClient) {}
  ngOnInit() {
    this.getData();
  }
  getData(more = false) {
    this.loading = true;
    this.http.get('/api/list', { count: this.q.ps }).subscribe((res: any) => {
      this.list = more ? this.list.concat(res) : res;
      this.loading = false;
    });
  }
}
src/app/routes/pro/list/basic-list/basic-list.component.html
New file
@@ -0,0 +1,91 @@
<page-header></page-header>
<nz-card [nzBordered]="false">
  <div nz-row>
    <div nz-col [nzXs]="24" [nzSm]="8" class="header-info">
      <span class="text-grey-dark">我的待办</span>
      <span class="d-block display-2">8个任务</span>
      <em></em>
    </div>
    <div nz-col [nzXs]="24" [nzSm]="8" class="header-info">
      <span class="text-grey-dark">本周任务平均处理时间</span>
      <span class="d-block display-2">32分钟</span>
      <em></em>
    </div>
    <div nz-col [nzXs]="24" [nzSm]="8" class="header-info">
      <span class="text-grey-dark">本周完成任务数</span>
      <span class="d-block display-2">24个任务</span>
    </div>
  </div>
</nz-card>
<nz-card [nzBordered]="false">
  <div class="d-flex align-items-center mb-lg">
    <h3 class="flex-1 text-lg">标准列表</h3>
    <div>
      <nz-radio-group [(ngModel)]="q.status" class="mr-md">
        <label nz-radio-button [nzValue]="'all'">
          <span>全部</span>
        </label>
        <label nz-radio-button [nzValue]="'progress'">
          <span>进行中</span>
        </label>
        <label nz-radio-button [nzValue]="'waiting'">
          <span>等待中</span>
        </label>
      </nz-radio-group>
      <nz-input-group nzSuffixIcon="anticon anticon-search" style="width: 270px;">
        <input type="text" nz-input placeholder="请输入" [(ngModel)]="q.q" name="q">
      </nz-input-group>
    </div>
  </div>
  <button nz-button (click)="msg.success('add')" [nzType]="'dashed'" class="ant-btn__block mb-sm">
    <i class="anticon anticon-plus"></i>
    <span>添加</span>
  </button>
  <nz-list [nzDataSource]="data" [nzLoading]="loading" [nzRenderItem]="item" [nzPagination]="pagination">
    <ng-template #item let-item>
      <nz-list-item [nzContent]="nzContent" [nzActions]="[edit, op]">
        <ng-template #edit>
          <a (click)="msg.success('编辑:' + item.title)">编辑</a>
        </ng-template>
        <ng-template #op>
          <nz-dropdown>
            <a class="ant-dropdown-link" nz-dropdown>
              编辑
              <i class="anticon anticon-down"></i>
            </a>
            <ul nz-menu>
              <li nz-menu-item (click)="msg.success('编辑:' + item.title)">编辑</li>
              <li nz-menu-item (click)="msg.success('删除:' + item.title)">删除</li>
            </ul>
          </nz-dropdown>
        </ng-template>
        <nz-list-item-meta [nzTitle]="nzTitle" [nzDescription]="item.subDescription" [nzAvatar]="nzAvatar">
          <ng-template #nzTitle>
            <a href="{{item.href}}" target="_blank">{{item.title}}</a>
          </ng-template>
          <ng-template #nzAvatar>
            <nz-avatar [nzSrc]="item.logo" nzSize="large" [nzShape]="'square'"></nz-avatar>
          </ng-template>
        </nz-list-item-meta>
        <ng-template #nzContent>
          <div class="width-md">
            <div class="d-flex text-grey-dark">
              <div class="flex-1">
                Owner
                <p>{{item.owner}}</p>
              </div>
              <div class="text-right">
                开始时间
                <p>{{item.createdAt | _date}}</p>
              </div>
            </div>
            <nz-progress [nzPercent]="item.percent" [nzStatus]="item.status" [nzStrokeWidth]="6"></nz-progress>
          </div>
        </ng-template>
      </nz-list-item>
    </ng-template>
    <ng-template #pagination>
      <nz-pagination [nzTotal]="50" [nzPageSize]="5" (nzPageIndexChange)="getData()"></nz-pagination>
    </ng-template>
  </nz-list>
</nz-card>
src/app/routes/pro/list/basic-list/basic-list.component.less
New file
@@ -0,0 +1,21 @@
.header-info {
  position: relative;
  text-align: center;
  > em {
    background-color: #e8e8e8;
    position: absolute;
    height: 56px;
    width: 1px;
    top: 0;
    right: 0;
  }
}
@media screen and (max-width: 576px) {
  .header-info {
    margin-bottom: 16px;
    > em {
      display: none;
    }
  }
}
src/app/routes/pro/list/basic-list/basic-list.component.ts
New file
@@ -0,0 +1,30 @@
import { Component, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'pro-basic-list',
  templateUrl: './basic-list.component.html',
  styleUrls: ['./basic-list.component.less'],
})
export class ProBasicListComponent implements OnInit {
  q: any = {
    status: 'all',
  };
  loading = false;
  data: any[] = [];
  constructor(private http: _HttpClient, public msg: NzMessageService) {}
  ngOnInit() {
    this.getData();
  }
  getData() {
    this.loading = true;
    this.http.get('/api/list', { count: 5 }).subscribe((res: any) => {
      this.data = res;
      this.loading = false;
    });
  }
}
src/app/routes/pro/list/card-list/card-list.component.html
New file
@@ -0,0 +1,48 @@
<page-header [title]="'卡片列表'">
  <ng-template #extra>
    <div style="margin-top: -60px; text-align: center; width: 195px;">
      <img class="img-fluid" src="https://gw.alipayobjects.com/zos/rmsportal/RzwpdLnhmvDJToTdfDPe.png">
    </div>
  </ng-template>
  段落示意:蚂蚁金服务设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。
  <div class="d-flex pt-md">
    <a class="d-flex pr-lg">
      <img class="pr-sm" src="https://gw.alipayobjects.com/zos/rmsportal/MjEImQtenlyueSmVEfUD.svg" />快速开始
    </a>
    <a class="d-flex pr-lg">
      <img class="pr-sm" src="https://gw.alipayobjects.com/zos/rmsportal/NbuDUAuBlIApFuDvWiND.svg" />产品简介
    </a>
    <a class="d-flex">
      <img class="pr-sm" src="https://gw.alipayobjects.com/zos/rmsportal/ohOEPSYdDTNnyMbGuyLb.svg" />产品文档
    </a>
  </div>
</page-header>
<nz-list [nzLoading]="loading" [nzDataSource]="list" [nzRenderItem]="item" [nzGrid]="{gutter: 24, lg: 8, md: 12, sm: 24, xs: 24 }">
  <ng-template #item let-item>
    <nz-list-item>
      <button *ngIf="item === null" nz-button (click)="msg.success('add')" [nzType]="'dashed'" style="width: 100%; height: 183px;">
        <i class="anticon anticon-plus"></i>
        <span>新增产品</span>
      </button>
      <nz-card nzHoverable *ngIf="item !== null" [nzActions]="[op1, op2]">
        <ng-template #op1>
          <a (click)="msg.success('操作一:' + item.id);">操作一</a>
        </ng-template>
        <ng-template #op2>
          <a (click)="msg.success('操作二:' + item.id);">操作二</a>
        </ng-template>
        <nz-card-meta [nzAvatar]="nzAvatar" [nzTitle]="nzTitle" [nzDescription]="nzDescription">
          <ng-template #nzAvatar>
            <nz-avatar nzSize="large" [nzSrc]="item.avatar"></nz-avatar>
          </ng-template>
          <ng-template #nzTitle>
            <a (click)="msg.success('标题:' + item.id);">{{item.title}}</a>
          </ng-template>
          <ng-template #nzDescription>
            <ellipsis>{{item.description}}</ellipsis>
          </ng-template>
        </nz-card-meta>
      </nz-card>
    </nz-list-item>
  </ng-template>
</nz-list>
src/app/routes/pro/list/card-list/card-list.component.ts
New file
@@ -0,0 +1,31 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'pro-list-card-list',
  templateUrl: './card-list.component.html',
  styles: [
    `
    :host ::ng-deep .ant-card-meta-title {
      margin-bottom: 12px;
    }
    `,
  ],
  encapsulation: ViewEncapsulation.Emulated,
})
export class ProCardListComponent implements OnInit {
  list: any[] = [null];
  loading = true;
  constructor(private http: _HttpClient, public msg: NzMessageService) {}
  ngOnInit() {
    this.loading = true;
    this.http.get('/api/list', { count: 8 }).subscribe((res: any) => {
      this.list = this.list.concat(res);
      this.loading = false;
    });
  }
}
src/app/routes/pro/list/list/list.component.html
New file
@@ -0,0 +1,16 @@
<page-header #ph [title]="'搜索列表'">
  <div class="text-center">
    <nz-input-group nzSearch nzSize="large" [nzSuffix]="suffixButton" style="width: 520px;">
      <input type="text" nz-input placeholder="请输入">
      <ng-template #suffixButton>
        <button nz-button nzType="primary" nzSize="large" nzSearch>Search</button>
      </ng-template>
    </nz-input-group>
  </div>
  <ng-template #tab>
    <nz-tabset [nzSelectedIndex]="pos">
      <nz-tab *ngFor="let i of tabs" [nzTitle]="i.tab" (click)="to(i)"></nz-tab>
    </nz-tabset>
  </ng-template>
</page-header>
<router-outlet></router-outlet>
src/app/routes/pro/list/list/list.component.ts
New file
@@ -0,0 +1,43 @@
import { Component, ViewChild, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { PageHeaderComponent } from '@delon/abc';
@Component({
  // tslint:disable-next-line:component-selector
  selector: 'pro-list-layout',
  templateUrl: './list.component.html',
})
export class ProListLayoutComponent implements OnInit {
  tabs: any[] = [
    {
      key: 'articles',
      tab: '文章',
    },
    {
      key: 'applications',
      tab: '应用',
    },
    {
      key: 'projects',
      tab: '项目',
    },
  ];
  @ViewChild('ph') ph: PageHeaderComponent;
  pos = 0;
  constructor(private router: Router) {}
  ngOnInit(): void {
    const key = this.router.url.substr(this.router.url.lastIndexOf('/') + 1);
    const idx = this.tabs.findIndex(w => w.key === key);
    if (idx !== -1) this.pos = idx;
  }
  to(item: any) {
    this.router
      .navigateByUrl(`/pro/list/${item.key}`)
      .then(() => this.ph.refresh());
  }
}
src/app/routes/pro/list/projects/projects.component.html
New file
@@ -0,0 +1,61 @@
<nz-card [nzBordered]="false">
  <form nz-form [nzLayout]="'inline'">
    <standard-form-row [title]="'所属类目'" block style="padding-bottom: 11px;">
      <nz-form-item>
        <nz-form-control>
          <tag-select>
            <nz-tag *ngFor="let i of categories; let idx = index" nzMode="checkable" [nzChecked]="i.value" (nzCheckedChange)="changeCategory($event, idx)">
              {{i.text}}
            </nz-tag>
          </tag-select>
        </nz-form-control>
      </nz-form-item>
    </standard-form-row>
    <standard-form-row [title]="'其它选项'" grid last>
      <nz-row [nzGutter]="16">
        <nz-col nzXl="8" nzLg="10" nzMd="12" nzSm="24" nzXs="24">
          <nz-form-item>
            <nz-form-label nzFor="rate">活跃用户</nz-form-label>
            <nz-form-control>
              <nz-select [(ngModel)]="q.user" name="user" [nzPlaceHolder]="'不限'" [nzShowSearch]="true" style="width: 200px;">
                <nz-option [nzLabel]="'李三'" [nzValue]="'lisa'"></nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </nz-col>
        <nz-col nzXl="8" nzLg="10" nzMd="12" nzSm="24" nzXs="24">
          <nz-form-item>
            <nz-form-label nzFor="rate">好评度</nz-form-label>
            <nz-form-control>
              <nz-select [(ngModel)]="q.rate" name="rate" [nzPlaceHolder]="'不限'" [nzShowSearch]="true" style="width: 200px;">
                <nz-option [nzLabel]="'优秀'" [nzValue]="'good'"></nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </nz-col>
      </nz-row>
    </standard-form-row>
  </form>
</nz-card>
<nz-list [nzLoading]="loading" [nzRenderItem]="item" [nzDataSource]="list" [nzGrid]="{gutter: 24, lg: 6, md: 8, sm: 12, xs: 24 }">
  <ng-template #item let-item>
    <nz-list-item>
      <nz-card nzHoverable [nzCover]="cover">
        <ng-template #cover>
          <img alt="{{item.title}}" src="{{item.cover}}">
        </ng-template>
        <nz-card-meta [nzTitle]="nzTitle" [nzDescription]="item.subDescription">
          <ng-template #nzTitle>
            <a (click)="msg.success('标题:' + item.id);">{{item.title}}</a>
          </ng-template>
        </nz-card-meta>
        <div class="card-item-content">
          <span class="text-grey">{{item.updatedAt | _date:'fn'}}</span>
          <avatar-list size="mini">
            <avatar-list-item *ngFor="let m of item.members" [src]="m.avatar" [tips]="m.name"></avatar-list-item>
          </avatar-list>
        </div>
      </nz-card>
    </nz-list-item>
  </ng-template>
</nz-list>
src/app/routes/pro/list/projects/projects.component.less
New file
@@ -0,0 +1,16 @@
:host ::ng-deep {
  .ant-card-meta-title {
    margin-bottom: 4px;
  }
  nz-list nz-card {
    margin-bottom: 0 !important;
  }
  .card-item-content {
    display: flex;
    margin-top: 16px;
    margin-bottom: -4px;
    line-height: 20px;
    height: 20px;
    justify-content: space-between;
  }
}
src/app/routes/pro/list/projects/projects.component.ts
New file
@@ -0,0 +1,61 @@
import { Component, OnInit } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'pro-list-projects',
  templateUrl: './projects.component.html',
  styleUrls: ['./projects.component.less'],
})
export class ProListProjectsComponent implements OnInit {
  q: any = {
    ps: 8,
    categories: [],
    owners: ['zxx'],
  };
  list: any[] = [];
  loading = true;
  // region: cateogry
  categories = [
    { id: 0, text: '全部', value: false },
    { id: 1, text: '类目一', value: false },
    { id: 2, text: '类目二', value: false },
    { id: 3, text: '类目三', value: false },
    { id: 4, text: '类目四', value: false },
    { id: 5, text: '类目五', value: false },
    { id: 6, text: '类目六', value: false },
    { id: 7, text: '类目七', value: false },
    { id: 8, text: '类目八', value: false },
    { id: 9, text: '类目九', value: false },
    { id: 10, text: '类目十', value: false },
    { id: 11, text: '类目十一', value: false },
    { id: 12, text: '类目十二', value: false },
  ];
  changeCategory(status: boolean, idx: number) {
    if (idx === 0) {
      this.categories.map(i => (i.value = status));
    } else {
      this.categories[idx].value = status;
    }
    this.getData();
  }
  // endregion
  constructor(private http: _HttpClient, public msg: NzMessageService) {}
  ngOnInit() {
    this.getData();
  }
  getData() {
    this.loading = true;
    this.http.get('/api/list', { count: this.q.ps }).subscribe((res: any) => {
      this.list = this.list.concat(res);
      this.loading = false;
    });
  }
}
src/app/routes/pro/list/table-list/table-list.component.html
New file
@@ -0,0 +1,108 @@
<page-header [title]="'查询表格'"></page-header>
<nz-card [nzBordered]="false">
  <form nz-form [nzLayout]="'inline'" (ngSubmit)="getData()" class="search__form">
    <nz-row [nzGutter]="{ md: 8, lg: 24, xl: 48 }">
      <nz-col nzMd="8" nzSm="24">
        <nz-form-item>
          <nz-form-label nzFor="no">规则编号</nz-form-label>
          <nz-form-control>
            <input nz-input [(ngModel)]="q.no" name="no" placeholder="请输入" id="no">
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col nzMd="8" nzSm="24">
        <nz-form-item>
          <nz-form-label nzFor="status">使用状态</nz-form-label>
          <nz-form-control>
            <nz-select [(ngModel)]="q.status" name="status" id="status" [nzPlaceHolder]="'请选择'" [nzShowSearch]="true">
              <nz-option *ngFor="let i of status; let idx = index" [nzLabel]="i.text" [nzValue]="idx"></nz-option>
            </nz-select>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col nzMd="8" nzSm="24" *ngIf="expandForm">
        <nz-form-item>
          <nz-form-label nzFor="callNo">调用次数</nz-form-label>
          <nz-form-control>
            <input nz-input id="callNo">
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col nzMd="8" nzSm="24" *ngIf="expandForm">
        <nz-form-item>
          <nz-form-label nzFor="updatedAt">更新日期</nz-form-label>
          <nz-form-control>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col nzMd="8" nzSm="24" *ngIf="expandForm">
        <nz-form-item>
          <nz-form-label nzFor="status2">使用状态</nz-form-label>
          <nz-form-control>
            <nz-select [nzPlaceHolder]="'请选择'" nzId="status2" [nzShowSearch]="true">
              <nz-option *ngFor="let i of status; let idx = index" [nzLabel]="i.text" [nzValue]="idx"></nz-option>
            </nz-select>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col nzMd="8" nzSm="24" *ngIf="expandForm">
        <nz-form-item>
          <nz-form-label nzFor="status3">使用状态</nz-form-label>
          <nz-form-control>
            <nz-select [nzPlaceHolder]="'请选择'" nzId="status3" [nzShowSearch]="true">
              <nz-option *ngFor="let i of status; let idx = index" [nzLabel]="i.text" [nzValue]="idx"></nz-option>
            </nz-select>
          </nz-form-control>
        </nz-form-item>
      </nz-col>
      <nz-col [nzSpan]="expandForm ? 24 : 8" [class.text-right]="expandForm">
        <button nz-button type="submit" [nzType]="'primary'" [nzLoading]="loading">查询</button>
        <button nz-button type="reset" (click)="getData()" class="mx-sm">重置</button>
        <a (click)="expandForm=!expandForm">
          {{expandForm ? '收起' : '展开'}}
          <i class="anticon" [class.anticon-down]="!expandForm" [class.anticon-up]="expandForm"></i>
        </a>
      </nz-col>
    </nz-row>
  </form>
  <button nz-button (click)="add(modalContent)" [nzType]="'primary'">
    <i class="anticon anticon-plus"></i>
    <span>新建</span>
  </button>
  <ng-container *ngIf="selectedRows.length > 0">
    <button nz-button class="ml-sm">批量操作</button>
    <nz-dropdown [nzPlacement]="'bottomLeft'">
      <button nz-button nz-dropdown class="ml-sm">
        更多操作
        <i class="anticon anticon-down"></i>
      </button>
      <ul nz-menu>
        <li nz-menu-item (click)="remove()">删除</li>
        <li nz-menu-item (click)="approval()">批量审批</li>
      </ul>
    </nz-dropdown>
  </ng-container>
  <div class="my-md">
    <nz-alert [nzType]="'info'" [nzShowIcon]="true" [nzMessage]="message">
      <ng-template #message>
        已选择
        <strong class="text-primary">{{selectedRows.length}}</strong> 项&nbsp;&nbsp; 服务调用总计
        <strong>{{totalCallNo}}</strong> 万
        <a *ngIf="totalCallNo > 0" (click)="st.clearCheck()" class="ml-lg">清空</a>
      </ng-template>
    </nz-alert>
  </div>
  <simple-table #st [columns]="columns" [data]="data" [loading]="loading" (checkboxChange)="checkboxChange($event)" (filterChange)="getData()">
    <ng-template st-row="status" let-i>
      <nz-badge [nzStatus]="i.statusType" [nzText]="i.statusText"></nz-badge>
    </ng-template>
  </simple-table>
</nz-card>
<ng-template #modalContent>
  <nz-form-item>
    <nz-form-label nzFor="no">描述</nz-form-label>
    <nz-form-control>
      <input nz-input [(ngModel)]="description" name="description" placeholder="请输入" id="no">
    </nz-form-control>
  </nz-form-item>
</ng-template>
src/app/routes/pro/list/table-list/table-list.component.ts
New file
@@ -0,0 +1,154 @@
import { Component, OnInit, ViewChild, TemplateRef } from '@angular/core';
import { NzMessageService, NzModalService } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
import { tap, map } from 'rxjs/operators';
import {
  SimpleTableComponent,
  SimpleTableColumn,
  SimpleTableData,
} from '@delon/abc';
@Component({
  selector: 'pro-table-list',
  templateUrl: './table-list.component.html',
})
export class ProTableListComponent implements OnInit {
  q: any = {
    pi: 1,
    ps: 10,
    sorter: '',
    status: null,
    statusList: [],
  };
  data: any[] = [];
  loading = false;
  status = [
    { index: 0, text: '关闭', value: false, type: 'default', checked: false },
    {
      index: 1,
      text: '运行中',
      value: false,
      type: 'processing',
      checked: false,
    },
    { index: 2, text: '已上线', value: false, type: 'success', checked: false },
    { index: 3, text: '异常', value: false, type: 'error', checked: false },
  ];
  @ViewChild('st') st: SimpleTableComponent;
  columns: SimpleTableColumn[] = [
    { title: '', index: 'key', type: 'checkbox' },
    { title: '规则编号', index: 'no' },
    { title: '描述', index: 'description' },
    {
      title: '服务调用次数',
      index: 'callNo',
      type: 'number',
      format: (item: any) => `${item.callNo} 万`,
      sorter: (a: any, b: any) => a.callNo - b.callNo,
    },
    {
      title: '状态',
      index: 'status',
      render: 'status',
      filters: this.status,
      filter: () => true,
    },
    {
      title: '更新时间',
      index: 'updatedAt',
      type: 'date',
      sorter: (a: any, b: any) => a.updatedAt - b.updatedAt,
    },
    {
      title: '操作',
      buttons: [
        {
          text: '配置',
          click: (item: any) => this.msg.success(`配置${item.no}`),
        },
        {
          text: '订阅警报',
          click: (item: any) => this.msg.success(`订阅警报${item.no}`),
        },
      ],
    },
  ];
  selectedRows: SimpleTableData[] = [];
  description = '';
  totalCallNo = 0;
  expandForm = false;
  constructor(
    private http: _HttpClient,
    public msg: NzMessageService,
    private modalSrv: NzModalService,
  ) {}
  ngOnInit() {
    this.getData();
  }
  getData() {
    this.loading = true;
    this.q.statusList = this.status
      .filter(w => w.checked)
      .map(item => item.index);
    if (this.q.status !== null && this.q.status > -1)
      this.q.statusList.push(this.q.status);
    this.http
      .get('/rule', this.q)
      .pipe(
        map((list: any[]) =>
          list.map(i => {
            const statusItem = this.status[i.status];
            i.statusText = statusItem.text;
            i.statusType = statusItem.type;
            return i;
          }),
        ),
        tap(() => (this.loading = false)),
      )
      .subscribe(res => (this.data = res));
  }
  checkboxChange(list: SimpleTableData[]) {
    this.selectedRows = list;
    this.totalCallNo = this.selectedRows.reduce(
      (total, cv) => total + cv.callNo,
      0,
    );
  }
  remove() {
    this.http
      .delete('/rule', { nos: this.selectedRows.map(i => i.no).join(',') })
      .subscribe(() => {
        this.getData();
        this.st.clearCheck();
      });
  }
  approval() {
    this.msg.success(`审批了 ${this.selectedRows.length} 笔`);
  }
  add(tpl: TemplateRef<{}>) {
    this.modalSrv.create({
      nzTitle: '新建规则',
      nzContent: tpl,
      nzOnOk: () => {
        this.loading = true;
        this.http
          .post('/rule', { description: this.description })
          .subscribe(() => {
            this.getData();
          });
      },
    });
  }
  reset(ls: any[]) {
    for (const item of ls) item.value = false;
    this.getData();
  }
}
src/app/routes/pro/pro-routing.module.ts
New file
@@ -0,0 +1,65 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { StepFormComponent } from './form/step-form/step-form.component';
import { AdvancedFormComponent } from './form/advanced-form/advanced-form.component';
import { BasicFormComponent } from './form/basic-form/basic-form.component';
import { ProTableListComponent } from './list/table-list/table-list.component';
import { ProBasicListComponent } from './list/basic-list/basic-list.component';
import { ProCardListComponent } from './list/card-list/card-list.component';
import { ProListArticlesComponent } from './list/articles/articles.component';
import { ProListProjectsComponent } from './list/projects/projects.component';
import { ProListApplicationsComponent } from './list/applications/applications.component';
import { ProProfileBaseComponent } from './profile/basic/basic.component';
import { ProProfileAdvancedComponent } from './profile/advanced/advanced.component';
import { ProResultSuccessComponent } from './result/success/success.component';
import { ProResultFailComponent } from './result/fail/fail.component';
import { ProListLayoutComponent } from './list/list/list.component';
const routes: Routes = [
  {
    path: 'form',
    children: [
      { path: 'basic-form', component: BasicFormComponent },
      { path: 'step-form', component: StepFormComponent },
      { path: 'advanced-form', component: AdvancedFormComponent },
    ],
  },
  {
    path: 'list',
    children: [
      { path: 'table-list', component: ProTableListComponent },
      { path: 'basic-list', component: ProBasicListComponent },
      { path: 'card-list', component: ProCardListComponent },
      {
        path: '',
        component: ProListLayoutComponent,
        children: [
          { path: 'articles', component: ProListArticlesComponent },
          { path: 'projects', component: ProListProjectsComponent },
          { path: 'applications', component: ProListApplicationsComponent },
        ],
      },
    ],
  },
  {
    path: 'profile',
    children: [
      { path: 'basic', component: ProProfileBaseComponent },
      { path: 'advanced', component: ProProfileAdvancedComponent },
    ],
  },
  {
    path: 'result',
    children: [
      { path: 'success', component: ProResultSuccessComponent },
      { path: 'fail', component: ProResultFailComponent },
    ],
  },
];
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class ProRoutingModule {}
src/app/routes/pro/pro.module.ts
New file
@@ -0,0 +1,48 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SharedModule } from '@shared/shared.module';
import { ProRoutingModule } from './pro-routing.module';
import { BasicFormComponent } from './form/basic-form/basic-form.component';
import { StepFormComponent } from './form/step-form/step-form.component';
import { Step1Component } from './form/step-form/step1.component';
import { Step2Component } from './form/step-form/step2.component';
import { Step3Component } from './form/step-form/step3.component';
import { AdvancedFormComponent } from './form/advanced-form/advanced-form.component';
import { ProTableListComponent } from './list/table-list/table-list.component';
import { ProBasicListComponent } from './list/basic-list/basic-list.component';
import { ProCardListComponent } from './list/card-list/card-list.component';
import { ProListLayoutComponent } from './list/list/list.component';
import { ProListArticlesComponent } from './list/articles/articles.component';
import { ProListProjectsComponent } from './list/projects/projects.component';
import { ProListApplicationsComponent } from './list/applications/applications.component';
import { ProProfileBaseComponent } from './profile/basic/basic.component';
import { ProProfileAdvancedComponent } from './profile/advanced/advanced.component';
import { ProResultSuccessComponent } from './result/success/success.component';
import { ProResultFailComponent } from './result/fail/fail.component';
const COMPONENTS_NOROUNT = [Step1Component, Step2Component, Step3Component];
@NgModule({
  imports: [SharedModule, ProRoutingModule],
  declarations: [
    BasicFormComponent,
    StepFormComponent,
    AdvancedFormComponent,
    ProTableListComponent,
    ProBasicListComponent,
    ProCardListComponent,
    ProListLayoutComponent,
    ProListArticlesComponent,
    ProListProjectsComponent,
    ProListApplicationsComponent,
    ProProfileBaseComponent,
    ProProfileAdvancedComponent,
    ProResultSuccessComponent,
    ProResultFailComponent,
    ...COMPONENTS_NOROUNT,
  ],
  entryComponents: COMPONENTS_NOROUNT,
})
export class ProModule {}
src/app/routes/pro/profile/advanced/advanced.component.html
New file
@@ -0,0 +1,144 @@
<page-header [title]="'单号:234231029431'">
  <ng-template #logo>
    <img src="https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png">
  </ng-template>
  <ng-template #action>
    <nz-button-group>
      <button nz-button>操作</button>
      <button nz-button>操作</button>
    </nz-button-group>
    <nz-dropdown class="mx-sm">
      <button nz-button nz-dropdown>
        <i class="anticon anticon-ellipsis"></i>
      </button>
      <ul nz-menu>
        <li nz-menu-item>选项一</li>
        <li nz-menu-item>选项二</li>
        <li nz-menu-item>选项三</li>
      </ul>
    </nz-dropdown>
    <button nz-button [nzType]="'primary'">主操作</button>
  </ng-template>
  <ng-template #extra>
    <div nz-row>
      <div nz-col nzXs="24" nzSm="12">
        <p class="text-grey">状态</p>
        <p class="text-lg">待审批</p>
      </div>
      <div nz-col nzXs="24" nzSm="12">
        <p class="text-grey">订单金额</p>
        <p class="text-lg">¥ 568.08</p>
      </div>
    </div>
  </ng-template>
  <ng-template #tab>
    <nz-tabset>
      <nz-tab nzTitle="详情"></nz-tab>
      <nz-tab nzTitle="规则"></nz-tab>
    </nz-tabset>
  </ng-template>
  <desc-list size="small" col="2">
    <desc-list-item term="创建人">曲丽丽</desc-list-item>
    <desc-list-item term="订购产品">XX 服务</desc-list-item>
    <desc-list-item term="创建时间">2017-07-07</desc-list-item>
    <desc-list-item term="关联单据">
      <a (click)="msg.success('yes')">12421</a>
    </desc-list-item>
    <desc-list-item term="生效日期">2017-07-07 ~ 2017-08-08</desc-list-item>
    <desc-list-item term="备注">请于两个工作日内确认</desc-list-item>
  </desc-list>
</page-header>
<nz-card [nzBordered]="false" class="mb-lg" nzTitle="流程进度">
  <nz-steps [nzCurrent]="1" nzProgressDot>
    <nz-step [nzTitle]="'创建项目'" [nzDescription]="createDesc">
      <ng-template #createDesc>
        <div class="desc">
          <div class="my-sm">曲丽丽
            <i class="anticon anticon-dingding-o ml-sm"></i>
          </div>
          <div>2016-12-12 12:32</div>
        </div>
      </ng-template>
    </nz-step>
    <nz-step [nzTitle]="'部门初审'" [nzDescription]="checkedDesc">
      <ng-template #checkedDesc>
        <div class="desc">
          <div class="my-sm">周毛毛
            <i class="anticon anticon-dingding-o ml-sm" style="color: #00a0e9;"></i>
          </div>
          <a (click)="msg.success('click')">催一下</a>
        </div>
      </ng-template>
    </nz-step>
    <nz-step [nzTitle]="'财务复核'"></nz-step>
    <nz-step [nzTitle]="'完成'"></nz-step>
  </nz-steps>
  <div class="steps-content"></div>
</nz-card>
<nz-card [nzBordered]="false" nzTitle="用户信息" class="mb-lg">
  <desc-list class="mb-lg">
    <desc-list-item term="用户姓名">付小小</desc-list-item>
    <desc-list-item term="会员卡号">32943898021309809423</desc-list-item>
    <desc-list-item term="身份证">3321944288191034921</desc-list-item>
    <desc-list-item term="联系方式">18112345678</desc-list-item>
    <desc-list-item term="联系地址">曲丽丽 18100000000 浙江省杭州市西湖区黄姑山路工专路交叉路口</desc-list-item>
  </desc-list>
  <desc-list class="mb-lg" title="信息组">
    <desc-list-item term="某某数据">725</desc-list-item>
    <desc-list-item term="该数据更新时间">2017-08-08</desc-list-item>
    <desc-list-item>&nbsp;</desc-list-item>
    <desc-list-item [term]="term">
      <ng-template #term>
        某某数据
        <nz-tooltip [nzTitle]="'数据说明'">
          <span nz-tooltip>
            <i class="anticon anticon-info-circle-o"></i>
          </span>
        </nz-tooltip>
      </ng-template>
      725
    </desc-list-item>
    <desc-list-item term="该数据更新时间">2017-08-08</desc-list-item>
  </desc-list>
  <h4 class="mb-md">信息组</h4>
  <nz-card nzType="inner" nzTitle="多层级信息组">
    <desc-list size="small" title="组名称" class="mb-md">
      <desc-list-item term="负责人">林东东</desc-list-item>
      <desc-list-item term="角色码">1234567</desc-list-item>
      <desc-list-item term="所属部门">XX公司 - YY部</desc-list-item>
      <desc-list-item term="过期时间">2017-08-08</desc-list-item>
      <desc-list-item term="描述">这段描述很长很长很长很长很长很长很长很长很长很长很长很长很长很长...</desc-list-item>
    </desc-list>
    <nz-divider class="mb-md"></nz-divider>
    <desc-list size="small" title="组名称" col="1" class="mb-md">
      <desc-list-item term="学名">
        Citrullus lanatus (Thunb.) Matsum. et Nakai一年生蔓生藤本;茎、枝粗壮,具明显的棱。卷须较粗..
      </desc-list-item>
    </desc-list>
    <nz-divider class="mb-md"></nz-divider>
    <desc-list size="small" title="组名称">
      <desc-list-item term="负责人">付小小</desc-list-item>
      <desc-list-item term="角色码">1234568</desc-list-item>
    </desc-list>
  </nz-card>
</nz-card>
<nz-card [nzBordered]="false" nzTitle="用户近半年来电记录" class="mb-lg">
  <div class="no-data">
    <i class="anticon anticon-frown-o"></i>暂无数据
  </div>
</nz-card>
<nz-card [nzBordered]="false">
  <nz-card-tab>
    <nz-tabset nzSize="large" (nzSelectChange)="change($event)">
      <nz-tab nzTitle="操作日志一"></nz-tab>
      <nz-tab nzTitle="操作日志二"></nz-tab>
      <nz-tab nzTitle="操作日志三"></nz-tab>
    </nz-tabset>
  </nz-card-tab>
  <simple-table [columns]="opColumns" [data]="list">
    <ng-template st-row="status" let-i>
      <nz-badge *ngIf="i.status === 'success'" [nzStatus]="'success'" [nzText]="'成功'"></nz-badge>
      <nz-badge *ngIf="i.status !== 'success'" [nzStatus]="'processing'" [nzText]="'进行中'"></nz-badge>
    </ng-template>
  </simple-table>
</nz-card>
src/app/routes/pro/profile/advanced/advanced.component.less
New file
@@ -0,0 +1,19 @@
@import 'node_modules/@delon/theme/styles/default';
:host {
  ::ng-deep {
    @media screen and (max-width: @screen-sm) {
      .desc {
        left: 8px;
      }
    }
    .desc {
      font-size: @font-size-base;
      position: relative;
      left: 38px;
      & > div {
        margin-top: 8px;
        margin-bottom: 4px;
      }
    }
  }
}
src/app/routes/pro/profile/advanced/advanced.component.ts
New file
@@ -0,0 +1,40 @@
import { Component, OnInit } from '@angular/core';
import { NzMessageService, NzTabChangeEvent } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
import { SimpleTableColumn } from '@delon/abc';
@Component({
  selector: 'pro-profile-advanced',
  templateUrl: './advanced.component.html',
  styleUrls: ['./advanced.component.less'],
})
export class ProProfileAdvancedComponent implements OnInit {
  list: any[] = [];
  data = {
    advancedOperation1: [],
    advancedOperation2: [],
    advancedOperation3: [],
  };
  opColumns: SimpleTableColumn[] = [
    { title: '操作类型', index: 'type' },
    { title: '操作人', index: 'name' },
    { title: '执行结果', index: 'status', render: 'status' },
    { title: '操作时间', index: 'updatedAt', type: 'date' },
    { title: '备注', index: 'memo', default: '-' },
  ];
  constructor(public msg: NzMessageService, private http: _HttpClient) {}
  ngOnInit() {
    this.http.get('/profile/advanced').subscribe((res: any) => {
      this.data = res;
      this.change({ index: 0, tab: null });
    });
  }
  change(args: NzTabChangeEvent) {
    this.list = this.data[`advancedOperation${args.index + 1}`];
  }
}
src/app/routes/pro/profile/basic/basic.component.html
New file
@@ -0,0 +1,42 @@
<page-header [title]="'基础详情页'"></page-header>
<nz-card [nzHoverable]="true" [nzBordered]="false">
  <desc-list size="large" title="退款申请" class="mb-lg">
    <desc-list-item term="取货单号">1000000000</desc-list-item>
    <desc-list-item term="状态">已取货</desc-list-item>
    <desc-list-item term="销售单号">1234123421</desc-list-item>
    <desc-list-item term="子订单">3214321432</desc-list-item>
  </desc-list>
  <nz-divider class="mb-lg"></nz-divider>
  <desc-list size="large" title="用户信息" class="mb-lg">
    <desc-list-item term="用户姓名">付小小</desc-list-item>
    <desc-list-item term="联系电话">18100000000</desc-list-item>
    <desc-list-item term="常用快递">菜鸟仓储</desc-list-item>
    <desc-list-item term="取货地址">浙江省杭州市西湖区万塘路18号</desc-list-item>
    <desc-list-item term="备注">无</desc-list-item>
  </desc-list>
  <nz-divider class="mb-lg"></nz-divider>
  <div class="text-lg mb-md">退货商品</div>
  <simple-table [data]="goods" [columns]="goodsColumns">
    <ng-template #body>
      <tr nz-tbody-tr>
        <td nz-td>合计</td>
        <td nz-td></td>
        <td nz-td></td>
        <td nz-td class="text-right"></td>
        <td nz-td class="text-right">
          <strong>{{basicNum}}</strong>
        </td>
        <td nz-td class="text-right">
          <strong>{{amountNum}}</strong>
        </td>
      </tr>
    </ng-template>
  </simple-table>
  <div class="text-lg my-md">退货进度</div>
  <simple-table [data]="progress" [columns]="progressColumns">
    <ng-template st-row="status" let-i>
      <nz-badge *ngIf="i.status === 'success'" [nzStatus]="'success'" [nzText]="'成功'"></nz-badge>
      <nz-badge *ngIf="i.status !== 'success'" [nzStatus]="'processing'" [nzText]="'进行中'"></nz-badge>
    </ng-template>
  </simple-table>
</nz-card>
src/app/routes/pro/profile/basic/basic.component.ts
New file
@@ -0,0 +1,45 @@
import { Component } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
import { _HttpClient } from '@delon/theme';
import { SimpleTableColumn } from '@delon/abc';
import { tap } from 'rxjs/operators';
@Component({
  selector: 'pro-profile-basic',
  templateUrl: './basic.component.html',
})
export class ProProfileBaseComponent {
  basicNum = 0;
  amountNum = 0;
  goods = this.http.get('/profile/goods').pipe(
    tap((list: any[]) => {
      list.forEach(item => {
        this.basicNum += Number(item.num);
        this.amountNum += Number(item.amount);
      });
    }),
  );
  goodsColumns: SimpleTableColumn[] = [
    {
      title: '商品编号',
      index: 'id',
      type: 'link',
      click: (item: any) => this.msg.success(`show ${item.id}`),
    },
    { title: '商品名称', index: 'name' },
    { title: '商品条码', index: 'barcode' },
    { title: '单价', index: 'price', type: 'currency' },
    { title: '数量(件)', index: 'num', className: 'text-right' },
    { title: '金额', index: 'amount', type: 'currency' },
  ];
  progress = this.http.get('/profile/progress');
  progressColumns: SimpleTableColumn[] = [
    { title: '时间', index: 'time' },
    { title: '当前进度', index: 'rate' },
    { title: '状态', render: 'status' },
    { title: '操作员ID', index: 'operator' },
    { title: '耗时', index: 'cost' },
  ];
  constructor(private http: _HttpClient, private msg: NzMessageService) {}
}
src/app/routes/pro/result/fail/fail.component.html
New file
@@ -0,0 +1,21 @@
<page-header></page-header>
<nz-card [nzBordered]="false">
  <result type="error" [title]="'提交失败'" description="请核对并修改以下信息后,再重新提交。" [extra]="resultExtra">
    <ng-template #resultExtra>
      <div class="mb-md text-lg">您提交的内容有如下错误:</div>
      <div class="mb-md">
        <i class="anticon anticon-close-circle-o text-error pr-sm"></i>您的账户已被冻结
        <a class="ml-md">立即解冻
          <i class="anticon anticon-right pl-sm"></i>
        </a>
      </div>
      <div>
        <i class="anticon anticon-close-circle-o text-error pr-sm"></i>您的账户还不具备申请资格
        <a class="ml-md">立即升级
          <i class="anticon anticon-right pl-sm"></i>
        </a>
      </div>
    </ng-template>
    <button nz-button [nzType]="'primary'">返回修改</button>
  </result>
</nz-card>
src/app/routes/pro/result/fail/fail.component.ts
New file
@@ -0,0 +1,7 @@
import { Component } from '@angular/core';
@Component({
  selector: 'pro-result-fail',
  templateUrl: './fail.component.html',
})
export class ProResultFailComponent {}
src/app/routes/pro/result/success/success.component.html
New file
@@ -0,0 +1,53 @@
<page-header></page-header>
<nz-card>
  <result type="success" [title]="'提交成功'" description="提交结果页用于反馈一系列操作任务的处理结果,如果仅是简单操作,使用 Message 全局提示反馈即可。本文字区域可以展示简单的补充说明,如果有类似展示x“单据”的需求,下面这个灰色区域可以呈现比较复杂的内容。"
    [extra]="resultExtra">
    <ng-template #resultExtra>
      <div nz-row [nzGutter]="16" class="mb-md">
        <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="12" [nzLg]="12" [nzXl]="6">
          <span class="text-grey-darker">项目 ID:</span>
          23421
        </div>
        <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="12" [nzLg]="12" [nzXl]="6">
          <span class="text-grey-darker">负责人:</span>
          曲丽丽
        </div>
        <div nz-col [nzXs]="24" [nzSm]="24" [nzMd]="24" [nzLg]="24" [nzXl]="12">
          <span class="text-grey-darker">生效时间:</span>
          2016-12-12 ~ 2017-12-12
        </div>
      </div>
      <nz-steps [nzCurrent]="1" nzProgressDot>
        <nz-step [nzTitle]="'创建项目'" [nzDescription]="createDesc">
          <ng-template #createDesc>
            <div style="font-size: 14px; position: relative; left: 38px;">
              <div style="margin-top: 8px; margin-bottom: 4px;">
                曲丽丽
                <i class="anticon anticon-dingding-o ml-sm"></i>
              </div>
              <div style="margin-top: 8px; margin-bottom: 4px;">2016-12-12 12:32</div>
            </div>
          </ng-template>
        </nz-step>
        <nz-step [nzTitle]="'部门初审'" [nzDescription]="checkedDesc">
          <ng-template #checkedDesc>
            <div style="font-size: 14px; position: relative; left: 38px;">
              <div style="margin-top: 8px; margin-bottom: 4px;">
                周毛毛
                <i class="anticon anticon-dingding-o ml-sm" style="color: #00a0e9;"></i>
              </div>
              <div style="margin-top: 8px; margin-bottom: 4px;">
                <a (click)="msg.success('click')">催一下</a>
              </div>
            </div>
          </ng-template>
        </nz-step>
        <nz-step [nzTitle]="'财务复核'"></nz-step>
        <nz-step [nzTitle]="'完成'"></nz-step>
      </nz-steps>
    </ng-template>
    <button nz-button [nzType]="'primary'">返回列表</button>
    <button nz-button>查看项目</button>
    <button nz-button>打 印</button>
  </result>
</nz-card>
src/app/routes/pro/result/success/success.component.ts
New file
@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { NzMessageService } from 'ng-zorro-antd';
@Component({
  selector: 'pro-result-success',
  templateUrl: './success.component.html',
})
export class ProResultSuccessComponent {
  constructor(public msg: NzMessageService) {}
}
src/app/routes/routes-routing.module.ts
@@ -3,20 +3,86 @@
import { environment } from '@env/environment';
// layout
import { LayoutDefaultComponent } from '../layout/default/default.component';
import { LayoutFullScreenComponent } from '../layout/fullscreen/fullscreen.component';
import { LayoutPassportComponent } from '../layout/passport/passport.component';
// dashboard pages
import { DashboardV1Component } from './dashboard/v1/v1.component';
import { DashboardAnalysisComponent } from './dashboard/analysis/analysis.component';
import { DashboardMonitorComponent } from './dashboard/monitor/monitor.component';
import { DashboardWorkplaceComponent } from './dashboard/workplace/workplace.component';
// passport pages
import { UserLoginComponent } from './passport/login/login.component';
import { UserRegisterComponent } from './passport/register/register.component';
import { UserRegisterResultComponent } from './passport/register-result/register-result.component';
// single pages
import { CallbackComponent } from './callback/callback.component';
import { UserLockComponent } from './passport/lock/lock.component';
import { Exception403Component } from './exception/403.component';
import { Exception404Component } from './exception/404.component';
import { Exception500Component } from './exception/500.component';
const routes: Routes = [
  {
    path: '',
    component: LayoutDefaultComponent,
    children: [
      { path: '', redirectTo: 'home-page', pathMatch: 'full' },
      { path: '', redirectTo: 'dashboard/v1', pathMatch: 'full' },
      { path: 'dashboard', redirectTo: 'dashboard/v1', pathMatch: 'full' },
      { path: 'dashboard/v1', component: DashboardV1Component },
      { path: 'dashboard/analysis', component: DashboardAnalysisComponent },
      { path: 'dashboard/monitor', component: DashboardMonitorComponent },
      { path: 'dashboard/workplace', component: DashboardWorkplaceComponent },
      {
        path: 'home-page',
        loadChildren: './home-page/home-page.module#HomePageModule',
      }
    ]
  }
        path: 'widgets',
        loadChildren: './widgets/widgets.module#WidgetsModule',
      },
      { path: 'style', loadChildren: './style/style.module#StyleModule' },
      { path: 'delon', loadChildren: './delon/delon.module#DelonModule' },
      { path: 'extras', loadChildren: './extras/extras.module#ExtrasModule' },
      { path: 'pro', loadChildren: './pro/pro.module#ProModule' },
    ],
  },
  // 全屏布局
  {
    path: 'data-v',
    component: LayoutFullScreenComponent,
    children: [
      { path: '', loadChildren: './data-v/data-v.module#DataVModule' },
    ],
  },
  // passport
  {
    path: 'passport',
    component: LayoutPassportComponent,
    children: [
      {
        path: 'login',
        component: UserLoginComponent,
        data: { title: '登录', titleI18n: 'pro-login' },
      },
      {
        path: 'register',
        component: UserRegisterComponent,
        data: { title: '注册', titleI18n: 'pro-register' },
      },
      {
        path: 'register-result',
        component: UserRegisterResultComponent,
        data: { title: '注册结果', titleI18n: 'pro-register-result' },
      },
    ],
  },
  // 单页不包裹Layout
  { path: 'callback/:type', component: CallbackComponent },
  {
    path: 'lock',
    component: UserLockComponent,
    data: { title: '锁屏', titleI18n: 'lock' },
  },
  { path: '403', component: Exception403Component },
  { path: '404', component: Exception404Component },
  { path: '500', component: Exception500Component },
  { path: '**', redirectTo: 'dashboard' },
];
@NgModule({
src/app/routes/routes.module.ts
@@ -2,9 +2,37 @@
import { SharedModule } from '@shared/shared.module';
import { RouteRoutingModule } from './routes-routing.module';
// dashboard pages
import { DashboardV1Component } from './dashboard/v1/v1.component';
import { DashboardAnalysisComponent } from './dashboard/analysis/analysis.component';
import { DashboardMonitorComponent } from './dashboard/monitor/monitor.component';
import { DashboardWorkplaceComponent } from './dashboard/workplace/workplace.component';
// passport pages
import { UserLoginComponent } from './passport/login/login.component';
import { UserRegisterComponent } from './passport/register/register.component';
import { UserRegisterResultComponent } from './passport/register-result/register-result.component';
// single pages
import { UserLockComponent } from './passport/lock/lock.component';
import { CallbackComponent } from './callback/callback.component';
import { Exception403Component } from './exception/403.component';
import { Exception404Component } from './exception/404.component';
import { Exception500Component } from './exception/500.component';
const COMPONENTS = [
  DashboardV1Component,
  DashboardAnalysisComponent,
  DashboardMonitorComponent,
  DashboardWorkplaceComponent,
  // passport pages
  UserLoginComponent,
  UserRegisterComponent,
  UserRegisterResultComponent,
  // single pages
  UserLockComponent,
  CallbackComponent,
  Exception403Component,
  Exception404Component,
  Exception500Component
];
const COMPONENTS_NOROUNT = [];
src/app/routes/style/color.service.ts
New file
@@ -0,0 +1,31 @@
import { Injectable } from '@angular/core';
@Injectable()
export class ColorService {
  APP_COLORS = {
    primary: '#1890ff',
    success: '#52c41a',
    error: '#f5222d',
    warning: '#fadb14',
    red: '#f5222d',
    volcano: '#fa541c',
    orange: '#fa8c16',
    gold: '#faad14',
    yellow: '#fadb14',
    lime: '#a0d911',
    green: '#52c41a',
    cyan: '#13c2c2',
    blue: '#1890ff',
    geekblue: '#2f54eb',
    purple: '#722ed1',
    magenta: '#eb2f96',
  };
  get names() {
    return Object.keys(this.APP_COLORS).filter((name, index) => index > 3);
  }
  get brands() {
    return ['primary', 'success', 'error', 'warning'];
  }
}
src/app/routes/style/colors/colors.component.html
New file
@@ -0,0 +1,105 @@
<div class="content__title">
  <h1>
    Colors
    <small>Color Palettes</small>
  </h1>
</div>
<div nz-row [nzGutter]="16" class="list">
  <div nz-col [nzMd]="24">
    <nz-card nzTitle="Classic colors">
      <div nz-row *ngFor="let c of c.brands">
        <div nz-col [nzSpan]="8">
          <div class="bg-{{c}}-light p-lg">
            <p (click)="onCopy('bg-' + c + '-light')">.bg-{{c}}-light</p>
            <p (click)="onCopy('text-' + c + '-light')">.text-{{c}}-light</p>
          </div>
        </div>
        <div nz-col [nzSpan]="8">
          <div class="bg-{{c}} p-lg">
            <p (click)="onCopy('bg-' + c)">.bg-{{c}}</p>
            <p (click)="onCopy('text-' + c)">.text-{{c}}</p>
          </div>
        </div>
        <div nz-col [nzSpan]="8">
          <div class="bg-{{c}}-dark p-lg">
            <p (click)="onCopy('bg-' + c + '-dark')">.bg-{{c}}-dark</p>
            <p (click)="onCopy('text-' + c + '-dark')">.text-{{c}}-dark</p>
          </div>
        </div>
      </div>
    </nz-card>
  </div>
</div>
<div nz-row [nzGutter]="16" class="list">
  <div nz-col [nzMd]="24">
    <nz-card nzTitle="Name colors">
      <div nz-row *ngFor="let c of c.names">
        <div nz-col [nzSpan]="8">
          <div class="bg-{{c}}-light p-lg">
            <p (click)="onCopy('bg-' + c + '-light')">.bg-{{c}}-light</p>
            <p (click)="onCopy('text-' + c + '-light')">.text-{{c}}-light</p>
          </div>
        </div>
        <div nz-col [nzSpan]="8">
          <div class="bg-{{c}} p-lg">
            <p (click)="onCopy('bg-' + c)">.bg-{{c}}</p>
            <p (click)="onCopy('text-' + c)">.text-{{c}}</p>
          </div>
        </div>
        <div nz-col [nzSpan]="8">
          <div class="bg-{{c}}-dark p-lg">
            <p (click)="onCopy('bg-' + c + '-dark')">.bg-{{c}}-dark</p>
            <p (click)="onCopy('text-' + c + '-dark')">.text-{{c}}-dark</p>
          </div>
        </div>
      </div>
      <div nz-row>
        <div nz-col [nzSpan]="5">
          <div class="bg-grey-darker p-lg">
            <p (click)="onCopy('bg-grey-darker')">.bg-grey-darker</p>
            <p (click)="onCopy('text-grey-darker')">.text-grey-darker</p>
          </div>
        </div>
        <div nz-col [nzSpan]="5">
          <div class="bg-grey-dark p-lg">
            <p (click)="onCopy('bg-grey-dark')">.bg-grey-dark</p>
            <p (click)="onCopy('text-grey-dark')">.text-grey-dark</p>
          </div>
        </div>
        <div nz-col [nzSpan]="4">
          <div class="bg-grey p-lg">
            <p (click)="onCopy('bg-grey')">.bg-grey</p>
            <p (click)="onCopy('text-grey')">.text-grey</p>
          </div>
        </div>
        <div nz-col [nzSpan]="5">
          <div class="bg-grey-light p-lg">
            <p (click)="onCopy('bg-grey-light')">.bg-grey-light</p>
            <p (click)="onCopy('text-grey-light')">.text-grey-light</p>
          </div>
        </div>
        <div nz-col [nzSpan]="5">
          <div class="bg-grey-lighter p-lg">
            <p (click)="onCopy('bg-grey-lighter')">.bg-grey-lighter</p>
            <p (click)="onCopy('text-grey-lighter')">.text-grey-lighter</p>
          </div>
        </div>
      </div>
    </nz-card>
  </div>
</div>
<div nz-row [nzGutter]="16" class="list">
  <div nz-col [nzMd]="24">
    <nz-card nzTitle="Full Colors">
      <div nz-row>
        <div nz-col [nzSpan]="4" *ngFor="let c of c.names">
          <div *ngFor="let i of nums" class="bg-{{c}}-{{i}} p-lg">
            <p (click)="onCopy('bg-' + c + '-' + i)">.bg-{{c}}-{{i}}</p>
            <p (click)="onCopy('bg-' + c + '-' + i + '-h')">.bg-{{c}}-{{i}}-h</p>
            <p (click)="onCopy('text-' + c + '-' + i)">.text-{{c}}-{{i}}</p>
          </div>
        </div>
      </div>
    </nz-card>
  </div>
</div>
src/app/routes/style/colors/colors.component.less
New file
@@ -0,0 +1,13 @@
:host {
  ::ng-deep {
    .list {
      p {
        margin-bottom: 0;
        cursor: pointer;
        &:first-child {
          margin-bottom: 4px;
        }
      }
    }
  }
}
src/app/routes/style/colors/colors.component.spec.ts
New file
@@ -0,0 +1,18 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { ColorsComponent } from './colors.component';
import { ColorService } from '../color.service';
describe('Component: Colors', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [ColorsComponent],
    providers: [ColorService],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(ColorsComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/style/colors/colors.component.ts
New file
@@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { ColorService } from '../color.service';
import { copy } from '@delon/util';
import { NzMessageService } from 'ng-zorro-antd';
@Component({
  selector: 'app-colors',
  templateUrl: './colors.component.html',
  styleUrls: ['./colors.component.less'],
})
export class ColorsComponent {
  nums = Array(10)
    .fill(1)
    .map((v, i) => v + i);
  constructor(public c: ColorService, private msg: NzMessageService) {}
  onCopy(str: string) {
    copy(str).then(() => this.msg.success(`Copied Success!`));
  }
}
src/app/routes/style/gridmasonry/gridmasonry.component.html
New file
@@ -0,0 +1,247 @@
<div class="content__title">
  <h1>
    Grid Masonry
    <small>Pure CSS and mobile first with a fallback to inline grid, Supported from IE10,
      <a href="//caniuse.com/#feat=multicolumn"
        target="_blank">browser compatibility</a>
    </small>
  </h1>
</div>
<div class="row-masonry row-masonry-xl-8 row-masonry-lg-5 row-masonry-md-4 row-masonry-sm-3 row-masonry-xs-2">
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Ipsum do ullamco laboris excepteur. Do incididunt commodo adipisicing officia sunt tempor. Deserunt exercitation proident
        enim veniam laboris fugiat ipsum veniam dolore duis sit duis. In deserunt ut nulla ad eu.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Veniam non sunt quis ex consequat ea esse duis esse. Ut incididunt eiusmod occaecat esse aute adipisicing culpa. Voluptate
        ullamco labore laboris et do in.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Esse elit et aute do aliqua ipsum cillum consectetur deserunt deserunt cupidatat aute aliqua aute. Aliquip ad incididunt
        dolor cupidatat quis officia cillum sit ex. Irure ut sit Lorem sunt nulla excepteur ipsum ipsum dolore cillum cupidatat
        ipsum. Do amet aliquip sunt consectetur nulla. Cupidatat ad consectetur veniam aliqua non ullamco laboris eiusmod.
        In voluptate officia aliquip dolore sit qui consectetur fugiat aliqua duis occaecat. Non mollit elit nisi ea mollit
        anim excepteur ut qui exercitation.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Ullamco incididunt do deserunt cillum veniam cillum amet ad. Deserunt laborum cupidatat mollit proident adipisicing
        in culpa consequat adipisicing et non. Aliqua ea elit voluptate esse aliqua dolor ipsum. Ut officia officia fugiat
        sint esse qui incididunt Lorem occaecat.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Ea non irure qui fugiat aliquip esse adipisicing. Cillum aliquip dolor non fugiat ad aliqua. In voluptate et non irure
        elit. Tempor qui sunt incididunt amet tempor sint et voluptate sunt qui sit culpa proident ipsum. Sunt duis pariatur
        officia ut magna pariatur fugiat dolor cillum laboris eu. Qui incididunt minim nostrud exercitation aliquip.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Fugiat commodo ad consectetur reprehenderit. Officia fugiat ea proident exercitation occaecat mollit laboris fugiat
        consequat deserunt anim ipsum magna ex. Esse do amet cillum aute ut ea.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Magna id fugiat laborum elit ullamco deserunt do laboris non qui. Duis et exercitation nulla labore cupidatat nostrud
        pariatur reprehenderit in nostrud. Consequat consequat consectetur mollit adipisicing. Laborum amet sit sint aliquip
        fugiat adipisicing enim reprehenderit. Voluptate nisi reprehenderit voluptate sit enim aute deserunt cupidatat et
        dolore labore voluptate id dolore.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Reprehenderit non ullamco quis non excepteur irure excepteur anim ullamco labore. Sit occaecat consectetur laborum
        consequat elit sint sit sunt. Duis aliquip magna ipsum consequat eiusmod officia.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Magna nostrud ex cupidatat id in non labore ad voluptate est irure tempor. Nostrud aliqua magna laborum incididunt
        deserunt veniam nulla nulla labore cillum. Id laboris Lorem dolore minim reprehenderit eu proident aliqua magna id
        aute aute. Aliqua est et nulla eu duis id laborum magna.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Sint pariatur eiusmod id sit est exercitation laboris mollit pariatur minim. Ex aliquip commodo nulla reprehenderit
        et laboris consequat pariatur culpa culpa proident ullamco laboris. Ex aliquip deserunt labore aliquip ea est sit
        quis amet tempor sunt amet. Id reprehenderit do elit sit consectetur. Aute amet sint tempor ipsum sint laboris est
        do culpa tempor. Pariatur fugiat aute officia et laboris voluptate sit nisi in anim excepteur amet eu.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Incididunt ut eu fugiat do deserunt voluptate id et est aliqua eu sint. Ad dolore excepteur ipsum nulla proident dolore
        aute sunt. Aute enim do dolor laborum id eiusmod sit.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Amet elit et ad amet nulla minim deserunt mollit adipisicing. Laboris non ipsum ad laborum non magna velit tempor cillum
        cillum. Proident dolore eiusmod ex elit cillum. Cupidatat duis pariatur ut id deserunt laboris. Culpa excepteur est
        deserunt eiusmod do do ut est labore eiusmod. Eu eu veniam excepteur mollit anim est velit nisi. Velit quis tempor
        laboris culpa.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Nostrud nulla nisi laboris officia anim nostrud nulla cupidatat veniam ea duis. Pariatur ea ullamco irure laborum.
        Consectetur labore in occaecat ullamco est fugiat nisi sunt deserunt. Non sunt dolor elit culpa dolore adipisicing.
        Fugiat mollit ex voluptate nulla deserunt dolore ea sunt commodo et qui laborum.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Quis pariatur ea nisi excepteur mollit nulla reprehenderit labore. Exercitation pariatur eu pariatur tempor deserunt
        ad occaecat ad in pariatur id et dolore. Enim veniam aute magna fugiat eiusmod velit quis. Laborum sit consequat
        dolore qui minim culpa aliqua pariatur cillum velit. Nostrud enim aliqua ut nisi consectetur pariatur fugiat do esse
        fugiat enim et tempor ad. Eiusmod ut incididunt proident labore sint sit culpa excepteur id. Fugiat mollit qui eu
        eu fugiat proident.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Tempor do officia magna do sunt. Nulla cillum anim excepteur adipisicing commodo culpa. Adipisicing pariatur qui voluptate
        consectetur mollit quis sunt enim veniam ullamco. Duis nostrud anim aliqua adipisicing fugiat aute excepteur deserunt
        enim occaecat pariatur ad. Qui aliquip aute labore minim ipsum in aute et. Aliqua laboris magna aute incididunt esse
        ex. Eu ipsum occaecat aliquip enim aute.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Labore cillum id non anim eiusmod officia. Nostrud laboris sint aliquip cillum magna. Minim sit labore proident culpa
        non nisi cillum non officia est. Proident elit sit adipisicing est cupidatat ex cupidatat labore aliqua ad.
      </p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Officia tempor ea adipisicing ad sit qui dolore consequat irure veniam. Est sit magna deserunt sint aute commodo fugiat
        fugiat irure sint dolore commodo amet. Duis cillum dolor quis consectetur dolor et et culpa id elit. Amet ut nulla
        sunt non in non duis sit fugiat consequat. Velit incididunt ullamco sunt deserunt nulla ad adipisicing. In fugiat
        ullamco deserunt amet. Ex voluptate amet magna minim ut incididunt veniam.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Occaecat anim do cillum est dolore sint. Do ut proident exercitation est incididunt irure duis ea laborum minim cillum
        est. Mollit irure non qui veniam labore eu elit veniam ea amet nisi esse labore. Elit ut nulla exercitation fugiat
        cupidatat non cupidatat sint id minim.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Voluptate incididunt tempor nulla voluptate esse dolor Lorem veniam voluptate adipisicing laborum in aliqua. Proident
        voluptate exercitation mollit consectetur qui commodo minim. Ea esse veniam velit minim reprehenderit incididunt
        reprehenderit do laborum aliqua. In quis et excepteur cupidatat qui duis. Pariatur Lorem laborum ut consectetur deserunt
        consectetur officia tempor commodo aliqua aliqua ipsum.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Ullamco officia esse ex reprehenderit reprehenderit cupidatat. Sunt excepteur sint consectetur ex aliqua excepteur.
        Laborum id cupidatat ea reprehenderit sit eiusmod ad exercitation ullamco nostrud. Nulla tempor voluptate magna amet
        culpa exercitation ad laborum in. Aliqua voluptate deserunt pariatur excepteur. Ullamco voluptate est dolore velit
        aliquip tempor nostrud deserunt. Minim excepteur dolor nulla commodo incididunt ex ullamco excepteur cillum veniam
        quis reprehenderit.</p>
    </div>
  </div>
</div>
<h3 class="my-md">Masonry with any kind of element</h3>
<div class="row-masonry row-masonry-xl-8 row-masonry-lg-5 row-masonry-md-4 row-masonry-sm-3 row-masonry-xs-2">
  <div class="col-masonry">
    <img src="assets/tmp/img/bg1.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Proident est cillum magna qui pariatur. Deserunt ut voluptate sint aliquip anim nisi consequat. Elit laboris anim anim
        dolor incididunt. Nostrud qui labore qui cillum excepteur mollit excepteur consequat esse anim enim ad enim. Esse
        qui mollit et minim mollit laboris reprehenderit laborum fugiat do id. Mollit labore proident cupidatat aliqua dolore
        exercitation consectetur commodo sint mollit nostrud esse sunt. Nostrud fugiat duis sit excepteur excepteur mollit.</p>
    </div>
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg2.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg3.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg4.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg5.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg6.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Dolore consequat elit est qui dolore dolore tempor amet magna adipisicing non in commodo. Veniam sint et proident duis
        eu nulla commodo sunt duis aliquip eiusmod. Occaecat incididunt deserunt consectetur non aliquip velit ullamco eu
        sit labore proident exercitation. Cillum deserunt voluptate eu eiusmod sint in esse. Velit anim non Lorem proident
        eu sit nisi Lorem aute do sit ea. Esse nostrud amet excepteur occaecat incididunt amet laborum aliqua qui mollit
        ullamco. Labore incididunt ullamco non ipsum Lorem duis commodo adipisicing in.</p>
    </div>
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Amet est dolor id esse veniam duis eu ex velit. Id qui deserunt voluptate veniam. Voluptate ea ipsum in eiusmod enim
        do velit commodo nulla sint. Fugiat ipsum esse pariatur voluptate exercitation magna ut proident consectetur et.
        Sint qui elit exercitation anim duis nulla commodo aliqua excepteur pariatur.</p>
    </div>
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg7.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg8.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <div class="box-placeholder">
      <h2 class="text-grey text-md mb-sm">Masonry Item</h2>
      <p>Culpa amet adipisicing consequat nisi dolore sunt amet labore officia aliquip elit tempor officia aliqua. Deserunt
        laborum enim ut laboris duis. Cillum non proident dolor ullamco cillum nostrud in sint aliqua cillum. Proident magna
        incididunt occaecat eiusmod cillum dolor tempor Lorem adipisicing nisi adipisicing mollit ex exercitation. Magna
        nostrud est sunt incididunt culpa. Duis nulla elit ut ea adipisicing duis esse ullamco.</p>
    </div>
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg9.jpg" alt="" />
  </div>
  <div class="col-masonry">
    <img src="assets/tmp/img/bg10.jpg" alt="" />
  </div>
</div>
src/app/routes/style/gridmasonry/gridmasonry.component.spec.ts
New file
@@ -0,0 +1,16 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { GridMasonryComponent } from './gridmasonry.component';
describe('Component: GridMasonry', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [GridMasonryComponent],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(GridMasonryComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/style/gridmasonry/gridmasonry.component.ts
New file
@@ -0,0 +1,7 @@
import { Component } from '@angular/core';
@Component({
  selector: 'app-gridmasonry',
  templateUrl: './gridmasonry.component.html',
})
export class GridMasonryComponent {}
src/app/routes/style/style-routing.module.ts
New file
@@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GridMasonryComponent } from './gridmasonry/gridmasonry.component';
import { TypographyComponent } from './typography/typography.component';
import { ColorsComponent } from './colors/colors.component';
const routes: Routes = [
  { path: 'gridmasonry', component: GridMasonryComponent },
  { path: 'typography', component: TypographyComponent },
  { path: 'colors', component: ColorsComponent },
];
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class StyleRoutingModule {}
src/app/routes/style/style.module.ts
New file
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { SharedModule } from '@shared/shared.module';
import { StyleRoutingModule } from './style-routing.module';
import { ColorService } from './color.service';
import { GridMasonryComponent } from './gridmasonry/gridmasonry.component';
import { TypographyComponent } from './typography/typography.component';
import { ColorsComponent } from './colors/colors.component';
@NgModule({
  imports: [SharedModule, StyleRoutingModule],
  declarations: [
    GridMasonryComponent,
    TypographyComponent,
    ColorsComponent,
  ],
  providers: [ColorService],
})
export class StyleModule {}
src/app/routes/style/typography/typography.component.html
New file
@@ -0,0 +1,130 @@
<div class="content__title">
  <h1>
    Typography
  </h1>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Headings">
      <h1 class="h1">
        class="h1"
        <small>Sub-heading</small>
      </h1>
      <h2 class="h2">
        class="h2"
        <small>Sub-heading</small>
      </h2>
      <h3 class="h3">
        class="h3"
        <small>Sub-heading</small>
      </h3>
      <h4 class="h4">
        class="h4"
        <small>Sub-heading</small>
      </h4>
      <h5 class="h5">
        class="h5"
        <small>Sub-heading</small>
      </h5>
      <h6 class="h6">
        class="h6"
        <small>Sub-heading</small>
      </h6>
    </nz-card>
  </div>
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Paragraphs">
      <p>
        <small>This is an example of small, fine print text.</small>
      </p>
      <p class="mt-sm">
        <strong>This is an example of strong, bold text.</strong>
      </p>
      <p class="mt-sm">
        <em>This is an example of emphasized, italic text.</em>
      </p>
      <h4 class="mt-sm">Alignment & Sizing Helpers</h4>
      <p class="mt-sm text-left text-sm">class="text-left text-sm"</p>
      <p class="mt-sm text-center text-md">class="text-center text-md"</p>
      <p class="text-right text-lg">class="text-right text-lg"</p>
    </nz-card>
  </div>
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Text Colors">
      <p *ngFor="let color of c.names" class="pb-0 text-{{color}}">class="text-{{color}} bg-{{color}}"</p>
    </nz-card>
  </div>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Formatting">
      <h4>text-nowrap</h4>
      <p class="pt-sm text-nowrap">[class="text-nowrap"].Ad eiusmod eu velit veniam laborum voluptate duis aliqua esse eiusmod.</p>
      <h4 class="pt-sm">text-truncate</h4>
      <p class="pt-sm text-truncate">[class="text-truncate"].Officia nulla velit minim mollit laborum et irure ullamco nisi dolore qui. Sint aute aliqua
        tempor commodo officia sunt non do id laborum mollit ex ea cupidatat. Amet ad non fugiat magna. Ut cupidatat labore
        pariatur esse reprehenderit esse sint in proident elit minim sunt enim sit. Enim sint deserunt exercitation duis.
        Aliquip cillum irure do incididunt do eu eiusmod excepteur culpa ex consectetur nulla duis sit. Ex officia excepteur
        officia ea ea cupidatat veniam officia officia est.</p>
      <h4 class="pt-sm">Transformation</h4>
      <p class="pt-sm text-lowercase">class="text-lowercase"</p>
      <p class="pt-sm text-uppercase">class="text-uppercase"</p>
      <p class="pt-sm text-capitalize">class="text-capitalize"</p>
      <p class="pt-sm text-deleted">class="text-deleted"</p>
    </nz-card>
  </div>
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Border">
      <div class="p-sm m-sm text-center width-sm d-inline-block border border-primary">class="border border-primary"</div>
      <div class="p-sm m-sm text-center width-sm d-inline-block border-top-1 border-success rounded-circle">class="border-top-1 border-success rounded-circle"</div>
      <div class="p-sm m-sm text-center width-sm d-inline-block border-bottom-1 border-error">class="border-bottom-1 border-error"</div>
      <div class="p-sm m-sm text-center width-md d-inline-block border-right-1 border-warning">class="border-right-1 border-warning"</div>
    </nz-card>
  </div>
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Padding & Margin">
      <strong>清除间距</strong>
      <p>
        <code>[<类型>p|m][<方向>t|r|b|l|x|y]?0</code>
      </p>
      <p>eg: p0, pt0, mb0, mt0</p>
      <strong>间距</strong>
      <p>
        <code>[<类型>p|m][<方向>t|r|b|l|x|y]?-[<尺寸>sm|md|lg]</code>
      </p>
      <p>eg: p-sm, pb-sm, mt-md, mr-md</p>
    </nz-card>
  </div>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Display">
      <p class="display-1">class="display-1"</p>
      <p class="display-2">class="display-2"</p>
      <p class="display-3">class="display-3"</p>
    </nz-card>
  </div>
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Code">
      <p>This is an example of an inline code element within body copy. Wrap inline code within a
        <code>...</code>tag.</p>
      <pre class="mt-sm"><code>This is an example of preformatted text.</code></pre>
    </nz-card>
  </div>
  <div nz-col [nzMd]="8">
    <nz-card nzTitle="Lists">
      <h4>list styled</h4>
      <ol class="mt-sm list-styled">
        <li>List Item</li>
        <li>List Item</li>
        <li>List Item</li>
      </ol>
      <h4 class="mt-sm">Unstyled List</h4>
      <ul class="mt-sm list-unstyled">
        <li>List Item</li>
        <li>List Item</li>
        <li>List Item</li>
      </ul>
    </nz-card>
  </div>
</div>
src/app/routes/style/typography/typography.component.spec.ts
New file
@@ -0,0 +1,18 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { TypographyComponent } from './typography.component';
import { ColorService } from '../color.service';
describe('Component: Typography', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [TypographyComponent],
    providers: [ColorService],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(TypographyComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/style/typography/typography.component.ts
New file
@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { ColorService } from '../color.service';
@Component({
  selector: 'app-typography',
  templateUrl: './typography.component.html',
})
export class TypographyComponent {
  constructor(public c: ColorService) {}
}
src/app/routes/widgets/widgets-routing.module.ts
New file
@@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { WidgetsComponent } from './widgets/widgets.component';
const routes: Routes = [{ path: '', component: WidgetsComponent }];
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class WidgetsRoutingModule {}
src/app/routes/widgets/widgets.module.ts
New file
@@ -0,0 +1,13 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SharedModule } from '@shared/shared.module';
import { WidgetsRoutingModule } from './widgets-routing.module';
import { WidgetsComponent } from './widgets/widgets.component';
@NgModule({
  imports: [SharedModule, WidgetsRoutingModule],
  declarations: [WidgetsComponent],
})
export class WidgetsModule {}
src/app/routes/widgets/widgets/widgets.component.html
New file
@@ -0,0 +1,797 @@
<div class="content__title">
  <h1>Widgets</h1>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col [nzXs]="24" [nzSm]="8">
    <nz-card>
      <div class="text-right text-grey">
        <i class="anticon anticon-pay-circle display-2"></i>
      </div>
      <h3 class="h3">99.999</h3>
      <div class="text-grey">Games played last month</div>
      <nz-progress [nzStatus]="'active'" [nzPercent]="60" [nzShowInfo]="false" [nzStrokeWidth]="5"></nz-progress>
    </nz-card>
  </div>
  <div nz-col [nzXs]="24" [nzSm]="8">
    <nz-card>
      <div class="text-right text-grey">
        <i class="anticon anticon-pie-chart display-2"></i>
      </div>
      <h3 class="h3">300</h3>
      <div class="text-grey">Coffee cups per day</div>
      <nz-progress [nzStatus]="'success'" [nzPercent]="30" [nzShowInfo]="false" [nzStrokeWidth]="5"></nz-progress>
    </nz-card>
  </div>
  <div nz-col [nzXs]="24" [nzSm]="8">
    <nz-card>
      <div class="text-right text-grey">
        <i class="anticon anticon-cloud display-2"></i>
      </div>
      <h3 class="h3">1000 Gb</h3>
      <div class="text-grey">Average Monthly Uploads</div>
      <nz-progress [nzStatus]="'exception'" [nzPercent]="10" [nzShowInfo]="false" [nzStrokeWidth]="5"></nz-progress>
    </nz-card>
  </div>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col [nzXs]="24" [nzSm]="8">
    <nz-card class="ant-card__body-nopadding">
      <div nz-row>
        <div nz-col [nzSpan]="12" class="border-right-1 border-bottom-1">
          <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
            <div nz-col [nzSpan]="12" class="text-center text-red">
              <i class="anticon anticon-user display-2"></i>
            </div>
            <div nz-col [nzSpan]="12" class="py-md">
              <h4 class="h4">10k</h4>
              <div class="text-grey">VISITORS</div>
            </div>
          </div>
        </div>
        <div nz-col [nzSpan]="12" class="border-bottom-1">
          <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
            <div nz-col [nzSpan]="12" class="text-center text-pink">
              <i class="anticon anticon-sound display-2"></i>
            </div>
            <div nz-col [nzSpan]="12" class="py-md">
              <h4 class="h4">100%</h4>
              <div class="text-grey">VOLUME</div>
            </div>
          </div>
        </div>
      </div>
      <div nz-row>
        <div nz-col [nzSpan]="12" class="border-right-1">
          <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
            <div nz-col [nzSpan]="12" class="text-center text-grey">
              <i class="anticon anticon-fork display-2"></i>
            </div>
            <div nz-col [nzSpan]="12" class="py-md">
              <h4 class="h4">150</h4>
              <div class="text-grey">FORKS</div>
            </div>
          </div>
        </div>
        <div nz-col [nzSpan]="12">
          <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
            <div nz-col [nzSpan]="12" class="text-center text-green">
              <i class="anticon anticon-message display-2"></i>
            </div>
            <div nz-col [nzSpan]="12" class="py-md">
              <h4 class="h4">10</h4>
              <div class="text-grey">MESSAGES</div>
            </div>
          </div>
        </div>
      </div>
    </nz-card>
    <nz-card class="ant-card__body-nopadding">
      <div nz-row>
        <div nz-col [nzSpan]="12" class="border-right-1 border-bottom-1">
          <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
            <div nz-col [nzSpan]="12" class="text-center">
              <g2-mini-bar height="35" color="#999" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="smallData"></g2-mini-bar>
            </div>
            <div nz-col [nzSpan]="12" class="py-md">
              <h4 class="h4">10k</h4>
              <div class="text-grey">VISITORS</div>
            </div>
          </div>
        </div>
        <div nz-col [nzSpan]="12" class="border-bottom-1">
          <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
            <div nz-col [nzSpan]="12" class="text-center">
              <g2-mini-bar height="35" color="#999" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="smallData"></g2-mini-bar>
            </div>
            <div nz-col [nzSpan]="12" class="py-md">
              <h4 class="h4">100%</h4>
              <div class="text-grey">VOLUME</div>
            </div>
          </div>
        </div>
      </div>
      <div nz-row>
        <div nz-col [nzSpan]="12" class="border-right-1">
          <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
            <div nz-col [nzSpan]="12" class="text-center">
              <g2-mini-bar height="35" color="#999" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="smallData"></g2-mini-bar>
            </div>
            <div nz-col [nzSpan]="12" class="py-md">
              <h4 class="h4">150</h4>
              <div class="text-grey">FORKS</div>
            </div>
          </div>
        </div>
        <div nz-col [nzSpan]="12">
          <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
            <div nz-col [nzSpan]="12" class="text-center">
              <g2-mini-bar height="35" color="#999" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="smallData"></g2-mini-bar>
            </div>
            <div nz-col [nzSpan]="12" class="py-md">
              <h4 class="h4">10</h4>
              <div class="text-grey">MESSAGES</div>
            </div>
          </div>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col [nzXs]="24" [nzSm]="8">
    <nz-card class="ant-card__body-nopadding">
      <div class="half-float half-float-md">
        <img src="./assets/tmp/img/half-float-bg-1.jpg">
        <div class="half-float-bottom rounded-circle bg-grey-lighter">
          <img class="p-sm" src="./assets/tmp/img/1.png">
        </div>
      </div>
      <div class="text-center">
        <h3 class="h3">cipchk</h3>
        <div class="text-grey">Lead director</div>
        <div class="p-sm">Voluptate velit id mollit ex. Anim labore non dolore ad cupidatat aute reprehenderit ullamco culpa esse. Esse exercitation
          laboris culpa ipsum pariatur mollit minim culpa magna.</div>
      </div>
      <div class="text-center bg-grey-darker text-white">
        <div nz-row>
          <div nz-col [nzSpan]="8" class="py-sm">
            <h3 class="text-white mb0">400</h3>
            <div>Photos</div>
          </div>
          <div nz-col [nzSpan]="8" class="py-sm">
            <h3 class="text-white mb0">2000</h3>
            <div>Likes</div>
          </div>
          <div nz-col [nzSpan]="8" class="py-sm">
            <h3 class="text-white mb0">500</h3>
            <div>Following</div>
          </div>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col [nzXs]="24" [nzSm]="8">
    <nz-card class="ant-card__body-nopadding">
      <div class="text-center bg-center py-lg text-white" style="background-image: url('./assets/tmp/img/bg9.jpg');">
        <nz-avatar [nzSrc]="'./assets/tmp/img/1.png'"></nz-avatar>
        <h3 class="text-white">cipchk</h3>
        <div>
          <i class="fa fa-github fa-fw"></i>
          @cipchk
        </div>
      </div>
      <div class="text-center bg-grey-darker text-white">
        <div nz-row>
          <div nz-col [nzSpan]="8" class="py-md">
            <a (click)="msg.success('to twitter')">
              <i class="fa fa-twitter fa-2x"></i>
            </a>
          </div>
          <div nz-col [nzSpan]="8" class="py-md">
            <a (click)="msg.success('to facebook')">
              <i class="fa fa-facebook fa-2x"></i>
            </a>
          </div>
          <div nz-col [nzSpan]="8" class="py-md">
            <a (click)="msg.success('comment')">
              <i class="fa fa-comments fa-2x"></i>
            </a>
          </div>
        </div>
      </div>
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point">
        <div nz-col [nzSpan]="4" class="text-center">
          <i class="fa fa-fw fa-clock-o text-grey"></i>
        </div>
        <div nz-col [nzSpan]="17">Recent Activity</div>
        <div nz-col [nzSpan]="3">
          <nz-tag [nzColor]="'blue'">350</nz-tag>
        </div>
      </div>
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point">
        <div nz-col [nzSpan]="4" class="text-center">
          <i class="fa fa-fw fa-user text-grey"></i>
        </div>
        <div nz-col [nzSpan]="17">Following</div>
        <div nz-col [nzSpan]="3">
          <nz-tag [nzColor]="'pink'">150</nz-tag>
        </div>
      </div>
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point">
        <div nz-col [nzSpan]="4" class="text-center">
          <i class="fa fa-fw fa-folder-open-o text-grey"></i>
        </div>
        <div nz-col [nzSpan]="17">Photos</div>
        <div nz-col [nzSpan]="3">
          <nz-tag [nzColor]="'green'">100</nz-tag>
        </div>
      </div>
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point">
        <div nz-col [nzSpan]="4" class="text-center">
          <i class="fa fa-fw fa-folder-open-o text-grey"></i>
        </div>
        <div nz-col [nzSpan]="17">Article</div>
        <div nz-col [nzSpan]="3">
          <nz-tag [nzColor]="'purple'">100</nz-tag>
        </div>
      </div>
    </nz-card>
  </div>
</div>
<div nz-row nzGutter="16">
  <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="12" class="p-md text-white">
        <div class="h2 mt0">123,456</div>
        <div class="text-nowrap">Website Traffics</div>
      </div>
      <div nz-col nzSpan="12">
        <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="data"></g2-mini-bar>
      </div>
    </div>
  </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="12" class="p-md text-white">
        <div class="h2 mt0">234,567K</div>
        <div class="text-nowrap">Website Impressions</div>
      </div>
      <div nz-col nzSpan="12">
        <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="data"></g2-mini-bar>
      </div>
    </div>
  </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="12" class="p-md text-white">
        <div class="h2 mt0">$458,778</div>
        <div class="text-nowrap">Total Sales</div>
      </div>
      <div nz-col nzSpan="12">
        <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="data"></g2-mini-bar>
      </div>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-magenta rounded-md">
      <div nz-col nzSpan="12" class="p-md text-white">
        <div class="h2 mt0">456</div>
        <div class="text-nowrap">Support Tickets</div>
      </div>
      <div nz-col nzSpan="12">
        <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="data"></g2-mini-bar>
      </div>
    </div>
  </div>
</div>
<div nz-row nzGutter="16">
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-primary text-center rounded-md">
      <div nz-col nzSpan="8" class="p-md text-white">
        <i class="anticon anticon-user display-2"></i>
      </div>
      <div nz-col nzSpan="16" class="bg-white py-md">
        <h3 class="h3 mb0">10k</h3>
        <div class="text-grey-dark">VISITORS</div>
      </div>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-magenta text-center rounded-md">
      <div nz-col nzSpan="8" class="p-md text-white">
        <i class="anticon anticon-sound display-2"></i>
      </div>
      <div nz-col nzSpan="16" class="bg-white py-md">
        <h3 class="h3 mb0">100%</h3>
        <div class="text-grey-dark">VOLUME</div>
      </div>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-grey-darker text-center rounded-md">
      <div nz-col nzSpan="8" class="p-md text-white">
        <i class="anticon anticon-fork display-2"></i>
      </div>
      <div nz-col nzSpan="16" class="bg-white py-md">
        <h3 class="h3 mb0">150</h3>
        <div class="text-grey-dark">FORKS</div>
      </div>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-green text-center rounded-md">
      <div nz-col nzSpan="8" class="p-md text-white">
        <i class="anticon anticon-message display-2"></i>
      </div>
      <div nz-col nzSpan="16" class="bg-white py-md">
        <h3 class="h3 mb0">10</h3>
        <div class="text-grey-dark">NEW MESSAGES</div>
      </div>
    </div>
  </div>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col nzXs="24" nzSm="12" nzMd="8" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-green-dark text-white rounded-md">
      <div nz-col nzSpan="8" class="p-md text-center">
        <i class="icon-share display-1"></i>
      </div>
      <div nz-col nzSpan="16" class="bg-green-light p-md">
        <h2 class="h2 text-white mb0">150</h2>
        <div class="text-lg text-uppercase">New connections</div>
      </div>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="8" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-red-dark text-white rounded-md">
      <div nz-col nzSpan="8" class="p-md text-center">
        <i class="icon-star display-1"></i>
      </div>
      <div nz-col nzSpan="16" class="bg-red-light p-md">
        <h2 class="h2 text-white mb0">7000</h2>
        <div class="text-lg text-uppercase">RATINGS RECEIVED</div>
      </div>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="8" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-warning-dark text-white rounded-md">
      <div nz-col nzSpan="8" class="p-md text-center">
        <i class="icon-trophy display-1"></i>
      </div>
      <div nz-col nzSpan="16" class="bg-warning-light p-md">
        <h2 class="h2 text-white mb0">15</h2>
        <div class="text-lg text-uppercase">ACHIEVEMENTS</div>
      </div>
    </div>
  </div>
</div>
<div nz-row nzGutter="16">
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-green text-white text-center rounded-md">
      <div nz-col nzSpan="10" class="p-md">
        <i class="anticon anticon-book display-1"></i>
      </div>
      <div nz-col nzSpan="14" class="py-md">
        <h1 class="text-white mb0">120</h1>
        <div>New Tasks!</div>
      </div>
      <a nz-col nzSpan="24" (click)="msg.info('view')" class="d-block p-sm bg-grey-darker text-white">
        <div class="float-left">View Details</div>
        <div class="float-right">
          <i class="fa fa-chevron-circle-right"></i>
        </div>
      </a>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-primary text-white text-center rounded-md">
      <div nz-col nzSpan="10" class="p-md">
        <i class="anticon anticon-message display-1"></i>
      </div>
      <div nz-col nzSpan="14" class="py-md">
        <h1 class="text-white mb0">36</h1>
        <div>New Comments!</div>
      </div>
      <a nz-col nzSpan="24" (click)="msg.info('view')" class="d-block p-sm bg-grey-darker text-white">
        <div class="float-left">View Details</div>
        <div class="float-right">
          <i class="fa fa-chevron-circle-right"></i>
        </div>
      </a>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-warning text-white text-center rounded-md">
      <div nz-col nzSpan="10" class="p-md">
        <i class="anticon anticon-shopping-cart display-1"></i>
      </div>
      <div nz-col nzSpan="14" class="py-md">
        <h1 class="text-white mb0">110</h1>
        <div>New Orders!</div>
      </div>
      <a nz-col nzSpan="24" (click)="msg.info('view')" class="d-block p-sm bg-grey-darker text-white">
        <div class="float-left">View Details</div>
        <div class="float-right">
          <i class="fa fa-chevron-circle-right"></i>
        </div>
      </a>
    </div>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="6" class="mb-md">
    <div nz-row nzType="flex" nzAlign="middle" class="bg-red text-white text-center rounded-md">
      <div nz-col nzSpan="10" class="p-md">
        <i class="anticon anticon-customer-service display-1"></i>
      </div>
      <div nz-col nzSpan="14" class="py-md">
        <h1 class="text-white mb0">19</h1>
        <div>Support Tickets!</div>
      </div>
      <a nz-col nzSpan="24" (click)="msg.info('view')" class="d-block p-sm bg-grey-darker text-white">
        <div class="float-left">View Details</div>
        <div class="float-right">
          <i class="fa fa-chevron-circle-right"></i>
        </div>
      </a>
    </div>
  </div>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8">
    <nz-card nzTitle="服务" [nzExtra]="extra">
      <ng-template #extra>
        <a (click)="msg.info('更多服务')">更多服务</a>
      </ng-template>
      <div class="pb-md">
        <i class="anticon anticon-check-circle-o text-green"></i> 已开通 16 个
        <i class="anticon anticon-check-circle-o pl-md"></i> 未开通 4 个
      </div>
      <nz-carousel class="nz-carousel__dot-blue">
        <div nz-carousel-content>
          <div nz-row [nzGutter]="24" class="mb-md">
            <div nz-col [nzSpan]="12">
              <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
                <div nz-col [nzSpan]="8">
                  <i class="anticon anticon-laptop display-2 text-blue"></i>
                </div>
                <div nz-col [nzSpan]="16">
                  <h4 class="fs-md text-blue mb0">服务注册中心</h4>
                  <div class="text-grey">Register Server</div>
                </div>
              </div>
            </div>
            <div nz-col [nzSpan]="12">
              <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
                <div nz-col [nzSpan]="8">
                  <i class="anticon anticon-rocket display-2 text-red"></i>
                </div>
                <div nz-col [nzSpan]="16">
                  <h4 class="fs-md text-blue mb0">可靠消息</h4>
                  <div class="text-grey">Msg Broker</div>
                </div>
              </div>
            </div>
          </div>
          <div nz-row [nzGutter]="24">
            <div nz-col [nzSpan]="12">
              <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
                <div nz-col [nzSpan]="8">
                  <i class="anticon anticon-usb display-2 text-purple"></i>
                </div>
                <div nz-col [nzSpan]="16">
                  <h4 class="fs-md text-blue mb0">分布式资源管理</h4>
                  <div class="text-grey">DRM</div>
                </div>
              </div>
            </div>
            <div nz-col [nzSpan]="12">
              <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
                <div nz-col [nzSpan]="8">
                  <i class="anticon anticon-fork display-2 text-pink"></i>
                </div>
                <div nz-col [nzSpan]="16">
                  <h4 class="fs-md text-blue mb0">分布式数据管理</h4>
                  <div class="text-grey">ZDC</div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div nz-carousel-content>
          <div nz-row [nzGutter]="24" class="mb-md">
            <div nz-col [nzSpan]="12">
              <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
                <div nz-col [nzSpan]="8">
                  <i class="anticon anticon-laptop display-2 text-blue"></i>
                </div>
                <div nz-col [nzSpan]="16">
                  <h4 class="fs-md text-blue mb0">服务注册中心</h4>
                  <div class="text-grey">Register Server</div>
                </div>
              </div>
            </div>
            <div nz-col [nzSpan]="12">
              <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
                <div nz-col [nzSpan]="8">
                  <i class="anticon anticon-rocket display-2 text-red"></i>
                </div>
                <div nz-col [nzSpan]="16">
                  <h4 class="fs-md text-blue mb0">可靠消息</h4>
                  <div class="text-grey">Msg Broker</div>
                </div>
              </div>
            </div>
          </div>
          <div nz-row [nzGutter]="24">
            <div nz-col [nzSpan]="12">
              <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
                <div nz-col [nzSpan]="8">
                  <i class="anticon anticon-usb display-2 text-purple"></i>
                </div>
                <div nz-col [nzSpan]="16">
                  <h4 class="fs-md text-blue">分布式资源管理</h4>
                  <div class="text-grey">DRM</div>
                </div>
              </div>
            </div>
            <div nz-col [nzSpan]="12">
              <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
                <div nz-col [nzSpan]="8">
                  <i class="anticon anticon-fork display-2 text-pink"></i>
                </div>
                <div nz-col [nzSpan]="16">
                  <h4 class="fs-md text-blue">分布式数据管理</h4>
                  <div class="text-grey">ZDC</div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </nz-carousel>
    </nz-card>
  </div>
  <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8">
    <nz-card nzTitle="开发服务器">
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'">
        <div nz-col [nzSpan]="4">
          <i class="anticon anticon-database display-1"></i>
        </div>
        <div nz-col [nzSpan]="15">
          <h3 class="font-weight-bold mb0">暂无服务器</h3>
          <div class="pt-sm text-grey-dark">
            <nz-badge [nzStatus]="'error'"></nz-badge>
            服务器申请失败
          </div>
        </div>
        <div nz-col [nzSpan]="5" class="text-right">
          <button nz-button (click)="msg.info('Apply')" [nzType]="'default'">
            <span>申请</span>
          </button>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8">
    <nz-card nzTitle="华东 1" class="ant-card__body-nopadding" [nzExtra]="extra">
      <ng-template #extra>
        <nz-tooltip [nzTitle]="'购买实例'">
          <span nz-tooltip>
            <i class="anticon anticon-shopping-cart display-3"></i>
          </span>
        </nz-tooltip>
      </ng-template>
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" [nzGutter]="8">
        <div nz-col [nzSpan]="12" class="text-center">
          云服务器
          <strong class="display-1 text-blur">12</strong>
        </div>
        <div nz-col [nzSpan]="12" class="my-md pl-md border-left-1">
          <div class="pb-sm">
            <nz-badge [nzStatus]="'success'"></nz-badge>
            运行中
            <strong class="text-green">2</strong>
          </div>
          <div class="pb-sm">
            <nz-badge [nzStatus]="'default'"></nz-badge>
            近期创建
            <strong class="text-grey">0</strong>
          </div>
          <div class="pb-sm">
            <nz-badge [nzStatus]="'error'"></nz-badge>
            即将过期
            <strong class="text-red">0</strong>
          </div>
          <div class="pb-sm">
            <nz-badge [nzStatus]="'error'"></nz-badge>
            已过期
            <strong class="text-red">1</strong>
          </div>
        </div>
      </div>
      <div nz-row class="text-center border-top-1">
        <div nz-col [nzSpan]="8" class="bg-grey-lighter-h py-sm point">
          磁盘
          <strong class="text-blue">18</strong>
        </div>
        <div nz-col [nzSpan]="8" class="bg-grey-lighter-h py-sm point">
          快照
          <strong>0</strong>
        </div>
        <div nz-col [nzSpan]="8" class="bg-grey-lighter-h py-sm point">
          镜像
          <strong class="text-blue">2</strong>
        </div>
      </div>
    </nz-card>
  </div>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col [nzXs]="24" [nzMd]="12" class="mb-md">
    <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="bg-white py-md rounded-md">
      <div nz-col [nzSpan]="3" class="text-center">
        <span class="ant-avatar ant-avatar-lg ant-avatar-circle ant-avatar-icon bg-primary">
          <i class="icon-speedometer"></i>
        </span>
      </div>
      <div nz-col [nzSpan]="6">
        <strong class="display-2">10</strong> 个
        <div class="text-grey">运行测压任务</div>
      </div>
      <div nz-col [nzSpan]="5">
        <nz-badge [nzStatus]="'success'"></nz-badge>
        已完成
        <span class="display-3 text-grey-dark">3</span>
      </div>
      <div nz-col [nzSpan]="5">
        <nz-badge [nzStatus]="'processing'"></nz-badge>
        正在进行
        <span class="display-3 text-grey-dark">5</span>
      </div>
      <div nz-col [nzSpan]="5">
        <nz-badge [nzStatus]="'error'"></nz-badge>
        已失败
        <span class="display-3 text-grey-dark">2</span>
      </div>
    </div>
  </div>
  <div nz-col [nzXs]="24" [nzMd]="12" class="mb-md">
    <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="bg-white rounded-md border p-md">
      <div nz-col [nzSpan]="16">
        你觉得这篇文章如何:
      </div>
      <div nz-col [nzSpan]="8" class="text-right">
        <nz-popconfirm [(nzVisible)]="like" [nzPlacement]="'top'" [nzTitle]="'喜欢就开启此内容提醒吧!'" [nzOkText]="'立即开启'" [nzCancelText]="'下次再说'"
          (nzOnConfirm)="msg.success('开启提醒')" (nzOnCancel)="msg.error('取消提醒')" style="display:inline-block; padding-top:15px;">
          <span nz-popconfirm></span>
        </nz-popconfirm>
        <span class="pr-lg">
          <i class="anticon anticon-like display-3 point" [class.text-primary]="like" (click)="like=!like"></i> 赞
        </span>
        <i class="anticon anticon-dislike display-3 point" [class.text-primary]="dislike" (click)="dislike=!dislike"></i> 踩
      </div>
    </div>
  </div>
</div>
<div nz-row [nzGutter]="16">
  <div nz-col nzXs="24" nzSm="12" nzMd="8" class="mb-md">
    <nz-card class="ant-card__body-nopadding bg-green rounded-md">
      <div class="p-md">
        <div class="h5 pb-sm text-white">Received all time</div>
        <g2-mini-area color="#fff" height="46" [data]="data"></g2-mini-area>
      </div>
      <div class="text-center bg-grey-darker text-white">
        <div nz-row>
          <div nz-col [nzSpan]="8" class="py-sm">
            <h3 class="text-white mb0">400</h3>
            <div>Photos</div>
          </div>
          <div nz-col [nzSpan]="8" class="py-sm">
            <h3 class="text-white mb0">2000</h3>
            <div>Likes</div>
          </div>
          <div nz-col [nzSpan]="8" class="py-sm">
            <h3 class="text-white mb0">500</h3>
            <div>Following</div>
          </div>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="8" class="mb-md">
    <nz-card class="ant-card__body-nopadding bg-green rounded-md">
      <div class="p-md">
        <div class="h5 pb-sm text-white">Monthly incomes</div>
        <g2-mini-area color="#fff" height="46" [data]="data"></g2-mini-area>
      </div>
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="bg-grey-darker py-sm text-center">
        <div nz-col [nzSpan]="16">
          <g2-mini-bar height="35" color="#fff" borderWidth="3" [padding]="[36, 30, 30, 30]" [data]="data"></g2-mini-bar>
        </div>
        <div nz-col [nzSpan]="8">
          <div class="text-white">+150</div>
          <div class="text-grey">From last month</div>
        </div>
      </div>
      <div class="py-sm text-center bg-white text-grey">
        <div nz-row>
          <div nz-col [nzSpan]="12">
            <div class="text-grey-dark">Gross income</div>
            <h4 class="h4 mb0">12000</h4>
          </div>
          <div nz-col [nzSpan]="12">
            <div class="text-grey-dark">Net income</div>
            <h4 class="h4 mb0">5100</h4>
          </div>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzSm="12" nzMd="8" class="mb-md">
    <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="rounded-md bg-blue">
      <div nz-col nzSpan="16">
        <img class="img-fluid align-middle" src="./assets/tmp/img/bg1.jpg" alt="" />
      </div>
      <div nz-col nzSpan="8" class="text-white text-center">
        <h2 class="h1 text-white mb0">11°</h2>
        <div class="py-sm">Cold</div>
        <i class="fa fa-sun-o fa-2x"></i>
      </div>
    </div>
  </div>
</div>
<div nz-row nzGutter="16">
  <div nz-col nzXs="24" nzMd="12">
    <nz-card class="ant-card__img">
      <img class="img" src="//os.alipayobjects.com/rmsportal/GhjqstwSgxBXrZS.png">
      <div class="p-md">
        <h3 class="h3 mb0">ANT DESIGN</h3>
        <div class="text-grey">A UI Design Language</div>
        <ol class="list-styled text-lg pt-md">
          <li>Designed by experienced team, and showcase dozens of inspiring projects.</li>
          <li>Provide solutions for usual problems that may be encountered while developing enterprise-like complex UIs.</li>
          <li>Dozens of flexible and practical reusable components that increase your productivity.</li>
        </ol>
        <div class="pt-md">
          <a class="text-grey" href="//ng.ant.design" target="_blank">View Site...</a>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzMd="12">
    <nz-card [nzTitle]="nzTitle" class="ant-card__body-nopadding" [nzTitle]="nzTitle">
      <ng-template #nzTitle>
        Recent Posts
        <small class="text-sm font-weight-normal">Venenatis portauam Inceptos ameteiam</small>
      </ng-template>
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point" *ngFor="let item of todoData">
        <div nz-col [nzSpan]="4" class="text-center">
          <nz-avatar [nzSrc]="'./assets/tmp/img/' + item.avatar + '.png'"></nz-avatar>
        </div>
        <div nz-col [nzSpan]="20">
          <strong>{{item.name}}</strong>
          <div>{{item.content}}</div>
        </div>
      </div>
    </nz-card>
  </div>
  <div nz-col nzXs="24" nzMd="12">
    <nz-card nzTitle="Todo lists" class="ant-card__body-nopadding">
      <div nz-row [nzType]="'flex'" [nzJustify]="'center'" [nzAlign]="'middle'" class="py-sm bg-grey-lighter-h point" *ngFor="let item of todoData">
        <div nz-col [nzSpan]="4" class="text-center">
          <nz-avatar [nzSrc]="'./assets/tmp/img/' + item.avatar + '.png'"></nz-avatar>
        </div>
        <div nz-col [nzSpan]="18">
          <strong>{{item.name}}</strong>
          <div [class.text-deleted]="item.completed">{{item.content}}</div>
        </div>
        <div nz-col [nzSpan]="2" class="text-right pr-md">
          <nz-dropdown [nzPlacement]="'topRight'">
            <i nz-dropdown class="icon-options-vertical"></i>
            <ul nz-menu>
              <li nz-menu-item *ngIf="item.completed" (click)="item.completed=false">Active</li>
              <li nz-menu-item *ngIf="!item.completed" (click)="item.completed=true">Completed</li>
              <li nz-menu-item (click)="todoData.splice(todoData.indexOf(item), 1)">Delted</li>
            </ul>
          </nz-dropdown>
        </div>
      </div>
    </nz-card>
  </div>
</div>
src/app/routes/widgets/widgets/widgets.component.less
New file
@@ -0,0 +1,11 @@
@import 'node_modules/@delon/theme/styles/default';
:host ::ng-deep {
  .ant-carousel {
    .slick-dots {
      bottom: -10px;
      li.slick-active button {
        background: @primary-color;
      }
    }
  }
}
src/app/routes/widgets/widgets/widgets.component.spec.ts
New file
@@ -0,0 +1,16 @@
import { TestBed, TestModuleMetadata } from '@angular/core/testing';
import { setUpTestBed } from '@testing/common.spec';
import { WidgetsComponent } from './widgets.component';
describe('Comoponent: Widgets', () => {
  setUpTestBed(<TestModuleMetadata>{
    declarations: [WidgetsComponent],
  });
  it('should create an instance', () => {
    const fixture = TestBed.createComponent(WidgetsComponent);
    const comp = fixture.debugElement.componentInstance;
    expect(comp).toBeTruthy();
  });
});
src/app/routes/widgets/widgets/widgets.component.ts
New file
@@ -0,0 +1,63 @@
import { NzMessageService } from 'ng-zorro-antd';
import { Component } from '@angular/core';
import { _HttpClient } from '@delon/theme';
@Component({
  selector: 'app-widgets',
  templateUrl: './widgets.component.html',
  styleUrls: ['./widgets.component.less'],
})
export class WidgetsComponent {
  data = [];
  smallData = [];
  todoData: any[] = [
    {
      completed: true,
      avatar: '1',
      name: '苏先生',
      content: `请告诉我,我应该说点什么好?`,
    },
    {
      completed: false,
      avatar: '2',
      name: 'はなさき',
      content: `ハルカソラトキヘダツヒカリ`,
    },
    {
      completed: false,
      avatar: '3',
      name: 'cipchk',
      content: `this world was never meant for one as beautiful as you.`,
    },
    {
      completed: false,
      avatar: '4',
      name: 'Kent',
      content: `my heart is beating with hers`,
    },
    {
      completed: false,
      avatar: '5',
      name: 'Are you',
      content: `They always said that I love beautiful girl than my friends`,
    },
    {
      completed: false,
      avatar: '6',
      name: 'Forever',
      content: `Walking through green fields ,sunshine in my eyes.`,
    },
  ];
  like = false;
  dislike = false;
  constructor(public msg: NzMessageService, private http: _HttpClient) {
    this.http.get('/chart/visit').subscribe((res: any[]) => {
      this.data = res;
      this.smallData = res.slice(0, 6);
    });
  }
}
src/assets/tmp/app-data.json
@@ -1,12 +1,12 @@
{
  "app": {
    "name": "七星瓢虫环境监测",
    "name": "Alain",
    "description": "Ng-zorro admin panel front-end framework"
  },
  "user": {
    "name": "Admin",
    "avatar": "./assets/tmp/img/avatar.jpg",
    "email": "admin@qq.com"
    "email": "cipchk@qq.com"
  },
  "menu": [
    {
src/assets/tmp/i18n/zh-CN.json
@@ -64,7 +64,5 @@
  "pro-user": "账户",
  "pro-login": "登录",
  "pro-register": "注册",
  "pro-register-result": "注册结果",
  "home-page":"首页概览",
  "system_navigation":"系统导航"
  "pro-register-result": "注册结果"
}
src/assets/tmp/img/No1.png
Binary files differ
src/assets/tmp/img/No2.png
Binary files differ
src/assets/tmp/img/No3.png
Binary files differ
src/assets/tmp/img/No4.png
Binary files differ
src/assets/tmp/img/No5.png
Binary files differ
src/assets/tmp/img/logo.png
Binary files differ
src/assets/tmp/img/logo_100x40.png
Binary files differ
src/assets/tmp/img/logo_30x30.png
Binary files differ
src/assets/tmp/img/logo_44x44.png
Binary files differ
src/assets/tmp/img/map_coordinates.png
Binary files differ
src/assets/tmp/img/zorro.svg
File was deleted
src/index.html
@@ -3,7 +3,7 @@
<head>
  <meta charset="utf-8">
  <title>七星瓢虫环境监测</title>
  <title>ngAlain</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta http-equiv="x-ua-compatible" content="ie=edge">