@if (getStats(project.id); as stats) {
@for (space of stats.spaces; track space.spaceId) {
{{ space.spaceName }}
📁 {{ space.totalFiles }}
@if (space.hasDeliverables) {
✅
} @else {
⏳
}
}
}
@if (getStats(project.id); as stats) {
🏗️
{{ stats.totalByType.whiteModel }}
🎨
{{ stats.totalByType.softDecor }}
🖼️
{{ stats.totalByType.rendering }}
✨
{{ stats.totalByType.postProcess }}
}
```
```scss
.project-card {
background: white;
border-radius: 12px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
}
.completion-badge {
padding: 4px 12px;
border-radius: 12px;
color: white;
font-size: 12px;
font-weight: 600;
}
}
.spaces-list {
margin-bottom: 16px;
.space-item {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 0;
border-bottom: 1px solid #f3f4f6;
&:last-child {
border-bottom: none;
}
.space-name {
flex: 1;
font-size: 14px;
}
.space-files {
font-size: 12px;
color: #6b7280;
}
.check-icon {
font-size: 16px;
}
.pending-icon {
font-size: 16px;
opacity: 0.5;
}
}
}
.file-stats {
display: flex;
gap: 12px;
padding-top: 12px;
border-top: 1px solid #f3f4f6;
.stat-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
.icon {
font-size: 20px;
}
.count {
font-size: 14px;
font-weight: 600;
color: #374151;
}
}
}
}
```
## 📝 TypeScript完整示例
```typescript
import { Component, OnInit } from '@angular/core';
import { ProjectSpaceDeliverableService, ProjectSpaceDeliverableSummary }
from '@modules/project/services/project-space-deliverable.service';
@Component({
selector: 'app-project-dashboard',
templateUrl: './project-dashboard.component.html',
styleUrls: ['./project-dashboard.component.scss']
})
export class ProjectDashboardComponent implements OnInit {
projects: any[] = [];
statsCache = new Map