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 }} 详情
`, 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, }); } }