|
@@ -1,17 +1,15 @@
|
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { Component, OnInit } from '@angular/core';
|
|
|
import { CommonModule, NgFor, NgIf, DatePipe } from '@angular/common';
|
|
import { CommonModule, NgFor, NgIf, DatePipe } from '@angular/common';
|
|
|
import { DashboardService, NewArtworkTab } from '../services/dashboard.service';
|
|
import { DashboardService, NewArtworkTab } from '../services/dashboard.service';
|
|
|
|
|
+import { ArtDoneRateComponent } from './art-done-rate.component';
|
|
|
|
|
|
|
|
import { NzCardModule } from 'ng-zorro-antd/card';
|
|
import { NzCardModule } from 'ng-zorro-antd/card';
|
|
|
import { NzIconModule } from 'ng-zorro-antd/icon';
|
|
import { NzIconModule } from 'ng-zorro-antd/icon';
|
|
|
-import { NzGridModule } from 'ng-zorro-antd/grid';
|
|
|
|
|
import { NzStatisticModule } from 'ng-zorro-antd/statistic';
|
|
import { NzStatisticModule } from 'ng-zorro-antd/statistic';
|
|
|
import { NzSpinModule } from 'ng-zorro-antd/spin';
|
|
import { NzSpinModule } from 'ng-zorro-antd/spin';
|
|
|
import { NzTableModule } from 'ng-zorro-antd/table';
|
|
import { NzTableModule } from 'ng-zorro-antd/table';
|
|
|
-import { NzProgressModule } from 'ng-zorro-antd/progress';
|
|
|
|
|
import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
|
|
import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
|
|
|
import { NzTabsModule } from 'ng-zorro-antd/tabs';
|
|
import { NzTabsModule } from 'ng-zorro-antd/tabs';
|
|
|
-import { NzModalService } from 'ng-zorro-antd/modal';
|
|
|
|
|
import { NzMessageService } from 'ng-zorro-antd/message';
|
|
import { NzMessageService } from 'ng-zorro-antd/message';
|
|
|
|
|
|
|
|
@Component({
|
|
@Component({
|
|
@@ -22,173 +20,122 @@ import { NzMessageService } from 'ng-zorro-antd/message';
|
|
|
NgFor,
|
|
NgFor,
|
|
|
NgIf,
|
|
NgIf,
|
|
|
DatePipe,
|
|
DatePipe,
|
|
|
|
|
+ ArtDoneRateComponent,
|
|
|
NzCardModule,
|
|
NzCardModule,
|
|
|
NzIconModule,
|
|
NzIconModule,
|
|
|
- NzGridModule,
|
|
|
|
|
NzStatisticModule,
|
|
NzStatisticModule,
|
|
|
NzSpinModule,
|
|
NzSpinModule,
|
|
|
NzTableModule,
|
|
NzTableModule,
|
|
|
- NzProgressModule,
|
|
|
|
|
NzPageHeaderModule,
|
|
NzPageHeaderModule,
|
|
|
NzTabsModule,
|
|
NzTabsModule,
|
|
|
],
|
|
],
|
|
|
- providers: [NzModalService, NzMessageService],
|
|
|
|
|
|
|
+ providers: [NzMessageService],
|
|
|
template: `
|
|
template: `
|
|
|
<div class="dashboard-container">
|
|
<div class="dashboard-container">
|
|
|
<nz-page-header [nzGhost]="false">
|
|
<nz-page-header [nzGhost]="false">
|
|
|
<nz-page-header-title>数据看板</nz-page-header-title>
|
|
<nz-page-header-title>数据看板</nz-page-header-title>
|
|
|
<nz-page-header-extra>
|
|
<nz-page-header-extra>
|
|
|
- <span
|
|
|
|
|
- nz-icon
|
|
|
|
|
- nzType="sync"
|
|
|
|
|
- nzTheme="outline"
|
|
|
|
|
- (click)="refreshData()"
|
|
|
|
|
- ></span>
|
|
|
|
|
|
|
+ <span nz-icon nzType="sync" nzTheme="outline" (click)="refreshData()"></span>
|
|
|
</nz-page-header-extra>
|
|
</nz-page-header-extra>
|
|
|
<nz-page-header-content>
|
|
<nz-page-header-content>
|
|
|
- <p>
|
|
|
|
|
- 最后更新时间:{{ lastUpdateTime | date: 'yyyy-MM-dd HH:mm:ss' }}
|
|
|
|
|
- </p>
|
|
|
|
|
|
|
+ <p>最后更新时间:{{ lastUpdateTime | date: 'yyyy-MM-dd HH:mm:ss' }}</p>
|
|
|
</nz-page-header-content>
|
|
</nz-page-header-content>
|
|
|
</nz-page-header>
|
|
</nz-page-header>
|
|
|
|
|
|
|
|
<nz-spin [nzSpinning]="isLoading" nzTip="数据加载中...">
|
|
<nz-spin [nzSpinning]="isLoading" nzTip="数据加载中...">
|
|
|
- <nz-row [nzGutter]="16">
|
|
|
|
|
- <nz-col [nzXs]="24" [nzLg]="10">
|
|
|
|
|
- <nz-card nzTitle="用户活跃" nzHoverable>
|
|
|
|
|
- <nz-statistic
|
|
|
|
|
- [nzTitle]="'当日日活(DAU)'"
|
|
|
|
|
- [nzValue]="activeUsersToday"
|
|
|
|
|
- [nzPrefix]="userIcon"
|
|
|
|
|
- [nzSuffix]="'人'"
|
|
|
|
|
- [nzValueStyle]="{ color: '#1677ff' }"
|
|
|
|
|
- ></nz-statistic>
|
|
|
|
|
- <ng-template #userIcon>
|
|
|
|
|
- <span nz-icon nzType="user" nzTheme="outline"></span>
|
|
|
|
|
- </ng-template>
|
|
|
|
|
-
|
|
|
|
|
- <div class="range-buttons">
|
|
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- class="range-btn"
|
|
|
|
|
- [class.active]="selectedDauRange === 7"
|
|
|
|
|
- (click)="changeDauRange(7)"
|
|
|
|
|
- >
|
|
|
|
|
- 7天
|
|
|
|
|
- </button>
|
|
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- class="range-btn"
|
|
|
|
|
- [class.active]="selectedDauRange === 14"
|
|
|
|
|
- (click)="changeDauRange(14)"
|
|
|
|
|
- >
|
|
|
|
|
- 14天
|
|
|
|
|
- </button>
|
|
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- class="range-btn"
|
|
|
|
|
- [class.active]="selectedDauRange === 30"
|
|
|
|
|
- (click)="changeDauRange(30)"
|
|
|
|
|
- >
|
|
|
|
|
- 30天
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="chart-wrapper">
|
|
|
|
|
- <svg
|
|
|
|
|
- viewBox="0 0 600 180"
|
|
|
|
|
- class="line-chart"
|
|
|
|
|
- preserveAspectRatio="none"
|
|
|
|
|
- >
|
|
|
|
|
- <polyline
|
|
|
|
|
- *ngIf="dauChartPoints"
|
|
|
|
|
- [attr.points]="dauChartPoints"
|
|
|
|
|
- fill="none"
|
|
|
|
|
- stroke="#1677ff"
|
|
|
|
|
- stroke-width="3"
|
|
|
|
|
- stroke-linecap="round"
|
|
|
|
|
- stroke-linejoin="round"
|
|
|
|
|
- ></polyline>
|
|
|
|
|
- </svg>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="chart-meta">
|
|
|
|
|
- <span>{{ dauTrendStartDate }}</span>
|
|
|
|
|
- <span>Max: {{ dauMax }}</span>
|
|
|
|
|
- <span>Min: {{ dauMin }}</span>
|
|
|
|
|
- <span>{{ dauTrendEndDate }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </nz-card>
|
|
|
|
|
- </nz-col>
|
|
|
|
|
-
|
|
|
|
|
- <nz-col [nzXs]="24" [nzLg]="14">
|
|
|
|
|
- <nz-card nzTitle="最近7天上新作品表现" nzHoverable>
|
|
|
|
|
- <nz-tabset
|
|
|
|
|
- [nzSelectedIndex]="activeArtworkTabIndex"
|
|
|
|
|
- (nzSelectedIndexChange)="activeArtworkTabIndex = $event"
|
|
|
|
|
|
|
+ <nz-card nzTitle="用户卡片:当日日活 + 日活曲线" nzHoverable class="stack-card">
|
|
|
|
|
+ <nz-statistic
|
|
|
|
|
+ [nzTitle]="'当日日活(DAU)'"
|
|
|
|
|
+ [nzValue]="activeUsersToday"
|
|
|
|
|
+ [nzPrefix]="userIcon"
|
|
|
|
|
+ [nzSuffix]="'人'"
|
|
|
|
|
+ [nzValueStyle]="{ color: '#1677ff' }"
|
|
|
|
|
+ ></nz-statistic>
|
|
|
|
|
+ <ng-template #userIcon>
|
|
|
|
|
+ <span nz-icon nzType="user" nzTheme="outline"></span>
|
|
|
|
|
+ </ng-template>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="range-buttons">
|
|
|
|
|
+ <button type="button" class="range-btn" [class.active]="selectedDauRange === 7" (click)="changeDauRange(7)">7天</button>
|
|
|
|
|
+ <button type="button" class="range-btn" [class.active]="selectedDauRange === 14" (click)="changeDauRange(14)">14天</button>
|
|
|
|
|
+ <button type="button" class="range-btn" [class.active]="selectedDauRange === 30" (click)="changeDauRange(30)">30天</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="chart-wrapper">
|
|
|
|
|
+ <svg viewBox="0 0 600 180" class="line-chart" preserveAspectRatio="none">
|
|
|
|
|
+ <polyline
|
|
|
|
|
+ *ngIf="dauChartPoints"
|
|
|
|
|
+ [attr.points]="dauChartPoints"
|
|
|
|
|
+ fill="none"
|
|
|
|
|
+ stroke="#1677ff"
|
|
|
|
|
+ stroke-width="3"
|
|
|
|
|
+ stroke-linecap="round"
|
|
|
|
|
+ stroke-linejoin="round"
|
|
|
|
|
+ ></polyline>
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="chart-meta">
|
|
|
|
|
+ <span>{{ dauTrendStartDate }}</span>
|
|
|
|
|
+ <span>Max: {{ dauMax }}</span>
|
|
|
|
|
+ <span>Min: {{ dauMin }}</span>
|
|
|
|
|
+ <span>{{ dauTrendEndDate }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </nz-card>
|
|
|
|
|
+
|
|
|
|
|
+ <nz-card nzTitle="作品卡片:最近7天上新作品表现" nzHoverable class="stack-card">
|
|
|
|
|
+ <nz-tabset [nzSelectedIndex]="activeArtworkTabIndex" (nzSelectedIndexChange)="activeArtworkTabIndex = $event">
|
|
|
|
|
+ <nz-tab *ngFor="let tab of artworkTabs" [nzTitle]="tab.label">
|
|
|
|
|
+ <div class="tab-subtitle">{{ tab.date }} · 当日DAU {{ tab.dau }}</div>
|
|
|
|
|
+
|
|
|
|
|
+ <nz-table
|
|
|
|
|
+ #worksTable
|
|
|
|
|
+ [nzData]="tab.artworks"
|
|
|
|
|
+ [nzFrontPagination]="false"
|
|
|
|
|
+ [nzBordered]="true"
|
|
|
|
|
+ [nzSize]="'small'"
|
|
|
>
|
|
>
|
|
|
- <nz-tab *ngFor="let tab of artworkTabs" [nzTitle]="tab.label">
|
|
|
|
|
- <div class="tab-subtitle">
|
|
|
|
|
- {{ tab.date }} · 当日DAU {{ tab.dau }}
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <nz-table
|
|
|
|
|
- #worksTable
|
|
|
|
|
- [nzData]="tab.artworks"
|
|
|
|
|
- [nzFrontPagination]="false"
|
|
|
|
|
- [nzBordered]="true"
|
|
|
|
|
- [nzSize]="'small'"
|
|
|
|
|
- >
|
|
|
|
|
- <thead>
|
|
|
|
|
- <tr>
|
|
|
|
|
- <th>作品</th>
|
|
|
|
|
- <th>名称</th>
|
|
|
|
|
- <th>点击率</th>
|
|
|
|
|
- <th>完成率</th>
|
|
|
|
|
- <th>点击数</th>
|
|
|
|
|
- <th>完成数</th>
|
|
|
|
|
- </tr>
|
|
|
|
|
- </thead>
|
|
|
|
|
- <tbody>
|
|
|
|
|
- <tr *ngFor="let work of worksTable.data">
|
|
|
|
|
- <td>
|
|
|
|
|
- <div
|
|
|
|
|
- class="work-thumbnail"
|
|
|
|
|
- [style.backgroundImage]="
|
|
|
|
|
- 'url(' + work.thumbnail + ')'
|
|
|
|
|
- "
|
|
|
|
|
- ></div>
|
|
|
|
|
- </td>
|
|
|
|
|
- <td>{{ work.name }}</td>
|
|
|
|
|
- <td>{{ work.clickRate * 100 | number: '1.1-2' }}%</td>
|
|
|
|
|
- <td>
|
|
|
|
|
- <nz-progress
|
|
|
|
|
- [nzPercent]="work.completionRate * 100"
|
|
|
|
|
- [nzShowInfo]="true"
|
|
|
|
|
- [nzStrokeWidth]="6"
|
|
|
|
|
- [nzStrokeColor]="
|
|
|
|
|
- work.completionRate >= 0.6
|
|
|
|
|
- ? '#52c41a'
|
|
|
|
|
- : work.completionRate >= 0.35
|
|
|
|
|
- ? '#faad14'
|
|
|
|
|
- : '#ff4d4f'
|
|
|
|
|
- "
|
|
|
|
|
- ></nz-progress>
|
|
|
|
|
- </td>
|
|
|
|
|
- <td>{{ work.clickCount }}</td>
|
|
|
|
|
- <td>{{ work.completionCount }}</td>
|
|
|
|
|
- </tr>
|
|
|
|
|
- </tbody>
|
|
|
|
|
- </nz-table>
|
|
|
|
|
-
|
|
|
|
|
- <div class="empty-tip" *ngIf="tab.artworks.length === 0">
|
|
|
|
|
- 当日无上新作品
|
|
|
|
|
- </div>
|
|
|
|
|
- </nz-tab>
|
|
|
|
|
- </nz-tabset>
|
|
|
|
|
- </nz-card>
|
|
|
|
|
- </nz-col>
|
|
|
|
|
- </nz-row>
|
|
|
|
|
|
|
+ <thead>
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ <th>作品</th>
|
|
|
|
|
+ <th>名称</th>
|
|
|
|
|
+ <th>区块数</th>
|
|
|
|
|
+ <th>点击率</th>
|
|
|
|
|
+ <th>完成率</th>
|
|
|
|
|
+ <th>点击数</th>
|
|
|
|
|
+ <th>完成数</th>
|
|
|
|
|
+ <th>道具使用数</th>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </thead>
|
|
|
|
|
+ <tbody>
|
|
|
|
|
+ <tr *ngFor="let work of worksTable.data">
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <div class="work-thumbnail" [style.backgroundImage]="'url(' + work.thumbnail + ')'" ></div>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td>{{ work.name }}</td>
|
|
|
|
|
+ <td>{{ work.areaCount || 0 }}</td>
|
|
|
|
|
+ <td>{{ work.clickRate * 100 | number: '1.1-2' }}%</td>
|
|
|
|
|
+ <td>
|
|
|
|
|
+ <art-done-rate
|
|
|
|
|
+ [data]="{
|
|
|
|
|
+ completionRate: work.completionRate,
|
|
|
|
|
+ areaCountFloor: work.areaCountFloor,
|
|
|
|
|
+ totalStartCount: work.clickCount,
|
|
|
|
|
+ totalDoneCount: work.completionCount
|
|
|
|
|
+ }"
|
|
|
|
|
+ ></art-done-rate>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td>{{ work.clickCount }}</td>
|
|
|
|
|
+ <td>{{ work.completionCount }}</td>
|
|
|
|
|
+ <td>{{ work.tipCount || 0 }}</td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </tbody>
|
|
|
|
|
+ </nz-table>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="empty-tip" *ngIf="tab.artworks.length === 0">当日无上新作品</div>
|
|
|
|
|
+ </nz-tab>
|
|
|
|
|
+ </nz-tabset>
|
|
|
|
|
+ </nz-card>
|
|
|
</nz-spin>
|
|
</nz-spin>
|
|
|
</div>
|
|
</div>
|
|
|
`,
|
|
`,
|
|
@@ -200,6 +147,10 @@ import { NzMessageService } from 'ng-zorro-antd/message';
|
|
|
min-height: 100%;
|
|
min-height: 100%;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ .stack-card {
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
.range-buttons {
|
|
.range-buttons {
|
|
|
margin: 12px 0 8px;
|
|
margin: 12px 0 8px;
|
|
|
display: flex;
|
|
display: flex;
|
|
@@ -282,7 +233,6 @@ export class DashboardComponent implements OnInit {
|
|
|
activeArtworkTabIndex = 0;
|
|
activeArtworkTabIndex = 0;
|
|
|
|
|
|
|
|
constructor(
|
|
constructor(
|
|
|
- private modalService: NzModalService,
|
|
|
|
|
private message: NzMessageService,
|
|
private message: NzMessageService,
|
|
|
private dashboardService: DashboardService,
|
|
private dashboardService: DashboardService,
|
|
|
) {}
|
|
) {}
|
|
@@ -323,6 +273,22 @@ export class DashboardComponent implements OnInit {
|
|
|
.join(' ');
|
|
.join(' ');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private applyDauData(dau: { today: number; trend: Array<{ date: string; dau: number }> }): void {
|
|
|
|
|
+ this.activeUsersToday = dau.today;
|
|
|
|
|
+ this.dauTrendLabels = dau.trend.map((item) => item.date);
|
|
|
|
|
+ this.dauTrendData = dau.trend.map((item) => item.dau);
|
|
|
|
|
+ this.dauMin = this.dauTrendData.length
|
|
|
|
|
+ ? Math.min(...this.dauTrendData)
|
|
|
|
|
+ : 0;
|
|
|
|
|
+ this.dauMax = this.dauTrendData.length
|
|
|
|
|
+ ? Math.max(...this.dauTrendData)
|
|
|
|
|
+ : 0;
|
|
|
|
|
+ this.dauTrendStartDate = this.dauTrendLabels[0] || '';
|
|
|
|
|
+ this.dauTrendEndDate =
|
|
|
|
|
+ this.dauTrendLabels[this.dauTrendLabels.length - 1] || '';
|
|
|
|
|
+ this.dauChartPoints = this.buildDauChartPoints(this.dauTrendData);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private loadUserCardData(): void {
|
|
private loadUserCardData(): void {
|
|
|
this.isLoading = true;
|
|
this.isLoading = true;
|
|
|
this.dashboardService.getKpi(this.selectedDauRange).subscribe({
|
|
this.dashboardService.getKpi(this.selectedDauRange).subscribe({
|
|
@@ -333,21 +299,7 @@ export class DashboardComponent implements OnInit {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const { dau } = response.data;
|
|
|
|
|
- this.activeUsersToday = dau.today;
|
|
|
|
|
- this.dauTrendLabels = dau.trend.map((item) => item.date);
|
|
|
|
|
- this.dauTrendData = dau.trend.map((item) => item.dau);
|
|
|
|
|
- this.dauMin = this.dauTrendData.length
|
|
|
|
|
- ? Math.min(...this.dauTrendData)
|
|
|
|
|
- : 0;
|
|
|
|
|
- this.dauMax = this.dauTrendData.length
|
|
|
|
|
- ? Math.max(...this.dauTrendData)
|
|
|
|
|
- : 0;
|
|
|
|
|
- this.dauTrendStartDate = this.dauTrendLabels[0] || '';
|
|
|
|
|
- this.dauTrendEndDate =
|
|
|
|
|
- this.dauTrendLabels[this.dauTrendLabels.length - 1] || '';
|
|
|
|
|
- this.dauChartPoints = this.buildDauChartPoints(this.dauTrendData);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ this.applyDauData(response.data.dau);
|
|
|
this.lastUpdateTime = new Date();
|
|
this.lastUpdateTime = new Date();
|
|
|
this.isLoading = false;
|
|
this.isLoading = false;
|
|
|
},
|
|
},
|
|
@@ -390,21 +342,7 @@ export class DashboardComponent implements OnInit {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const { dau } = kpiResponse.data;
|
|
|
|
|
- this.activeUsersToday = dau.today;
|
|
|
|
|
- this.dauTrendLabels = dau.trend.map((item) => item.date);
|
|
|
|
|
- this.dauTrendData = dau.trend.map((item) => item.dau);
|
|
|
|
|
- this.dauMin = this.dauTrendData.length
|
|
|
|
|
- ? Math.min(...this.dauTrendData)
|
|
|
|
|
- : 0;
|
|
|
|
|
- this.dauMax = this.dauTrendData.length
|
|
|
|
|
- ? Math.max(...this.dauTrendData)
|
|
|
|
|
- : 0;
|
|
|
|
|
- this.dauTrendStartDate = this.dauTrendLabels[0] || '';
|
|
|
|
|
- this.dauTrendEndDate =
|
|
|
|
|
- this.dauTrendLabels[this.dauTrendLabels.length - 1] || '';
|
|
|
|
|
- this.dauChartPoints = this.buildDauChartPoints(this.dauTrendData);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ this.applyDauData(kpiResponse.data.dau);
|
|
|
await this.loadArtworkTabsData();
|
|
await this.loadArtworkTabsData();
|
|
|
|
|
|
|
|
this.lastUpdateTime = new Date();
|
|
this.lastUpdateTime = new Date();
|