import { Component, OnInit } from '@angular/core';
import { CommonModule, NgFor, DatePipe } from '@angular/common';
import { debounceTime } from 'rxjs/operators';
import { DashboardService } from '../services/dashboard.service';
// NG-ZORRO 组件
import { NzCardModule } from 'ng-zorro-antd/card';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzGridModule } from 'ng-zorro-antd/grid';
import { NzStatisticModule } from 'ng-zorro-antd/statistic';
import { NzSpinModule } from 'ng-zorro-antd/spin';
import { NzTableModule } from 'ng-zorro-antd/table';
import { NzDividerModule } from 'ng-zorro-antd/divider';
import { NzProgressModule } from 'ng-zorro-antd/progress';
import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
import { NzTagModule } from 'ng-zorro-antd/tag';
import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzMessageService } from 'ng-zorro-antd/message';
@Component({
selector: 'app-dashboard',
standalone: true,
imports: [
CommonModule,
NgFor,
DatePipe,
// NG-ZORRO 模块
NzCardModule,
NzIconModule,
NzGridModule,
NzStatisticModule,
NzSpinModule,
NzTableModule,
NzDividerModule,
NzProgressModule,
NzPageHeaderModule,
NzTagModule,
NzToolTipModule,
],
providers: [NzModalService, NzMessageService],
template: `
数据看板
最后更新时间:{{ lastUpdateTime | date : 'yyyy-MM-dd HH:mm:ss' }}
实时数据自动更新
来自广告平台
近 7 天平均值
近 7 天累计
今日广告收益
展示量 {{ bannerImpressions }} 次
展示量 {{ interstitialImpressions }} 次
展示量 {{ rewardedImpressions }} 次
今日上新作品
| 作品 |
名称 |
填色开始数 |
填色完成数 |
完成率 |
操作 |
|
|
{{ work.name }} |
{{ work.startedCount }} |
{{ work.completedCount }} |
70
? '#52c41a'
: work.completionRate > 30
? '#faad14'
: '#f5222d'
"
[nzShowInfo]="true"
[nzStrokeWidth]="5"
>
|
详情
|
`,
styles: [
`
.dashboard-container {
padding: 24px;
background: #f0f2f5;
min-height: 100%;
}
.metrics-container {
margin-bottom: 24px;
}
.section {
background: #fff;
padding: 16px 24px;
border-radius: 8px;
margin-bottom: 24px;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
}
.section-title {
margin-bottom: 16px;
font-size: 18px;
color: rgba(0, 0, 0, 0.85);
}
nz-card {
margin-bottom: 16px;
transition: all 0.3s;
}
nz-card:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transform: translateY(-4px);
}
.compare {
margin-top: 8px;
font-size: 12px;
color: rgba(0, 0, 0, 0.45);
}
.work-thumbnail {
width: 60px;
height: 60px;
background-size: cover;
background-position: center;
border-radius: 4px;
}
.ant-statistic-content {
display: flex;
flex-direction: column;
align-items: center;
}
.ant-statistic-title {
font-size: 14px;
color: rgba(0, 0, 0, 0.65);
}
.ant-statistic-content-value {
font-size: 28px;
}
.ant-statistic-content-suffix {
font-size: 16px;
}
`,
],
})
export class DashboardComponent implements OnInit {
isLoading = true;
lastUpdateTime = new Date();
Math = Math; // 暴露 Math 对象给模板使antml
// 核心指标数据(来自 KPI 接口)
activeUsersToday = 0; // 日活用户数
dailyRevenue = 0; // 当日广告收益
// DAU 趋势数据
dauTrendLabels: string[] = [];
dauTrendData: number[] = [];
avgDau7d = 0;
// 收益趋势数据
revenueTrendLabels: string[] = [];
revenueTrendData: number[] = [];
totalRevenue7d = 0;
// 广告收益数据(暂时保留,后续可删除)
bannerRevenue = 0;
interstitialRevenue = 0;
rewardedRevenue = 0;
bannerImpressions = 0;
interstitialImpressions = 0;
rewardedImpressions = 0;
// 今日上新作品
newWorksToday: any[] = [];
constructor(
private modalService: NzModalService,
private message: NzMessageService,
private dashboardService: DashboardService
) {}
ngOnInit(): void {
this.loadDashboardData();
}
refreshData(): void {
this.isLoading = true;
this.loadDashboardData();
}
loadDashboardData(): void {
this.dashboardService.getKpi(7).subscribe({
next: (response) => {
if (response.success) {
const { dau, revenue } = response.data;
// 更新 KPI 数据
this.activeUsersToday = dau.today;
this.dailyRevenue = revenue.today;
// 更新 DAU 趋势
this.dauTrendLabels = dau.trend.map((item) => item.date);
this.dauTrendData = dau.trend.map((item) => item.dau);
const dauSum = this.dauTrendData.reduce((sum, value) => sum + value, 0);
this.avgDau7d = this.dauTrendData.length > 0 ? Math.round(dauSum / this.dauTrendData.length) : 0;
// 更新收益趋势
this.revenueTrendLabels = revenue.trend.map((item) => item.date);
this.revenueTrendData = revenue.trend.map((item) => item.revenue);
const revenueSum = this.revenueTrendData.reduce((sum, value) => sum + value, 0);
this.totalRevenue7d = Math.round(revenueSum);
// 模拟广告收益细分(后续可从其他接口获取)
this.bannerRevenue = revenue.today * 0.35;
this.interstitialRevenue = revenue.today * 0.40;
this.rewardedRevenue = revenue.today * 0.25;
this.bannerImpressions = Math.floor(Math.random() * 30000);
this.interstitialImpressions = Math.floor(Math.random() * 10000);
this.rewardedImpressions = Math.floor(Math.random() * 8000);
// 模拟上新作品数据(后续可从接口获取)
this.newWorksToday = [
{
id: 1,
name: '作品 #1',
thumbnail: 'https://via.placeholder.com/60',
startedCount: Math.floor(Math.random() * 2000),
completedCount: Math.floor(Math.random() * 1000),
},
{
id: 2,
name: '作品 #2',
thumbnail: 'https://via.placeholder.com/60',
startedCount: Math.floor(Math.random() * 2000),
completedCount: Math.floor(Math.random() * 1000),
},
{
id: 3,
name: '作品 #3',
thumbnail: 'https://via.placeholder.com/60',
startedCount: Math.floor(Math.random() * 2000),
completedCount: Math.floor(Math.random() * 1000),
},
];
this.newWorksToday = this.newWorksToday.map((work) => ({
...work,
completionRate: work.startedCount > 0
? Math.round((work.completedCount / work.startedCount) * 100)
: 0,
}));
this.lastUpdateTime = new Date();
this.isLoading = false;
} else {
this.message.error('获取 KPI 数据失败');
this.isLoading = false;
}
},
error: (error) => {
console.error('Failed to load KPI data:', error);
this.message.error('加载数据出错,请重试');
this.isLoading = false;
},
});
}
showWorkDetails(work: any): void {
this.modalService.create({
nzTitle: '作品详情',
nzContent: `
作品名称: ${work.name}
填色开始数: ${work.startedCount}
填色完成数: ${work.completedCount}
完成率: ${work.completionRate}%
`,
nzFooter: null,
});
}
}