# 项目空间与交付物统计服务 - 快速开始 ## 🚀 5分钟快速上手 ### 第一步:导入服务 ```typescript import { ProjectSpaceDeliverableService } from '@modules/project/services/project-space-deliverable.service'; @Component({ // ... }) export class YourComponent { constructor( private projectSpaceDeliverableService: ProjectSpaceDeliverableService ) {} } ``` ### 第二步:获取项目统计 ```typescript async loadProjectStats(projectId: string) { const summary = await this.projectSpaceDeliverableService .getProjectSpaceDeliverableSummary(projectId); console.log('项目统计:', summary); } ``` ### 第三步:在模板中使用 ```html

{{ projectName }}

空间: {{ summary.spacesWithDeliverables }}/{{ summary.totalSpaces }} 文件: {{ summary.totalDeliverableFiles }} 完成率: {{ summary.overallCompletionRate }}%
``` ## 📊 常用场景 ### 场景1:显示项目完成徽章 ```typescript // TypeScript getCompletionBadge(projectId: string) { const summary = this.cache.get(projectId); if (!summary) return null; return { text: `${summary.spacesWithDeliverables}/${summary.totalSpaces}`, color: this.projectSpaceDeliverableService.getDeliveryStatusColor( summary.overallCompletionRate ), tooltip: `已完成 ${summary.spacesWithDeliverables} 个空间,共 ${summary.totalSpaces} 个` }; } ``` ```html @if (getCompletionBadge(project.id); as badge) { 📦 {{ badge.text }} } ``` ### 场景2:检查项目是否可以交付 ```typescript async canDeliver(projectId: string): Promise { const isCompleted = await this.projectSpaceDeliverableService .isAllSpacesDelivered(projectId); if (!isCompleted) { const incompleteSpaces = await this.projectSpaceDeliverableService .getIncompleteSpaces(projectId); alert(`以下空间还未完成:${incompleteSpaces.join(', ')}`); return false; } return true; } ``` ### 场景3:显示进度条 ```typescript // TypeScript async loadProgress(projectId: string) { this.progress = await this.projectSpaceDeliverableService .getProjectDeliveryProgress(projectId); this.progressColor = this.projectSpaceDeliverableService .getDeliveryStatusColor(this.progress); } ``` ```html
{{ progress }}%
``` ```scss // SCSS .progress-bar { width: 100%; height: 24px; background: #e5e7eb; border-radius: 12px; overflow: hidden; .progress-fill { height: 100%; display: flex; align-items: center; justify-content: center; color: white; font-size: 12px; font-weight: 600; transition: width 0.3s, background-color 0.3s; } } ``` ## 💡 最佳实践 ### 1. 使用缓存避免重复查询 ```typescript export class YourComponent implements OnInit { private statsCache = new Map(); async getStats(projectId: string) { if (!this.statsCache.has(projectId)) { const summary = await this.projectSpaceDeliverableService .getProjectSpaceDeliverableSummary(projectId); this.statsCache.set(projectId, summary); } return this.statsCache.get(projectId)!; } } ``` ### 2. 批量加载提高性能 ```typescript async loadAllStats(projectIds: string[]) { const promises = projectIds.map(id => this.projectSpaceDeliverableService.getProjectSpaceDeliverableSummary(id) ); const results = await Promise.allSettled(promises); results.forEach((result, index) => { if (result.status === 'fulfilled') { this.statsCache.set(projectIds[index], result.value); } }); } ``` ### 3. 添加错误处理 ```typescript async loadStats(projectId: string) { try { const summary = await this.projectSpaceDeliverableService .getProjectSpaceDeliverableSummary(projectId); this.statsCache.set(projectId, summary); } catch (error) { console.error('加载统计失败:', error); // 使用默认值 this.statsCache.set(projectId, { projectId, projectName: '未知项目', totalSpaces: 0, spacesWithDeliverables: 0, spaces: [], totalDeliverableFiles: 0, totalByType: { whiteModel: 0, softDecor: 0, rendering: 0, postProcess: 0 }, overallCompletionRate: 0 }); } } ``` ## 🎨 实际应用示例 ### 组长端看板卡片 ```html

{{ project.name }}

@if (getStats(project.id); as stats) { {{ stats.overallCompletionRate }}% }
@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(); loading = false; constructor( private projectSpaceDeliverableService: ProjectSpaceDeliverableService ) {} async ngOnInit() { await this.loadProjects(); await this.loadAllStats(); } async loadProjects() { // 加载项目列表... this.projects = []; // 从API获取 } async loadAllStats() { this.loading = true; try { const projectIds = this.projects.map(p => p.id); const promises = projectIds.map(id => this.projectSpaceDeliverableService.getProjectSpaceDeliverableSummary(id) ); const results = await Promise.allSettled(promises); results.forEach((result, index) => { if (result.status === 'fulfilled') { this.statsCache.set(projectIds[index], result.value); } else { console.warn(`加载项目 ${projectIds[index]} 统计失败:`, result.reason); } }); } catch (error) { console.error('加载统计失败:', error); } finally { this.loading = false; } } getStats(projectId: string): ProjectSpaceDeliverableSummary | null { return this.statsCache.get(projectId) || null; } getStatusColor(completionRate: number): string { return this.projectSpaceDeliverableService.getDeliveryStatusColor(completionRate); } getStatusLabel(completionRate: number): string { return this.projectSpaceDeliverableService.getDeliveryStatusLabel(completionRate); } formatTooltip(projectId: string): string { const stats = this.getStats(projectId); if (!stats) return '加载中...'; return `空间: ${stats.spacesWithDeliverables}/${stats.totalSpaces}\n` + `文件: ${stats.totalDeliverableFiles}\n` + `完成率: ${stats.overallCompletionRate}%`; } } ``` ## 🔗 相关链接 - [完整使用指南](./PROJECT-SPACE-DELIVERABLE-SERVICE-GUIDE.md) - [API文档](./API.md) - [组长端时间轴示例](../src/app/pages/team-leader/project-timeline/) ## ❓ 常见问题 ### Q: 如何刷新统计数据? ```typescript // 清除缓存并重新加载 this.statsCache.delete(projectId); await this.loadStats(projectId); ``` ### Q: 如何处理加载失败? ```typescript async getStats(projectId: string) { try { if (!this.statsCache.has(projectId)) { const summary = await this.projectSpaceDeliverableService .getProjectSpaceDeliverableSummary(projectId); this.statsCache.set(projectId, summary); } return this.statsCache.get(projectId)!; } catch (error) { console.error('加载失败:', error); return null; // 返回null,让模板使用@if处理 } } ``` ### Q: 如何优化大量项目的加载性能? ```typescript // 使用分页加载 async loadStatsInPages(projectIds: string[], pageSize = 10) { for (let i = 0; i < projectIds.length; i += pageSize) { const page = projectIds.slice(i, i + pageSize); await this.loadBatch(page); // 触发UI更新 this.cdr.markForCheck(); } } private async loadBatch(projectIds: string[]) { const promises = projectIds.map(id => this.projectSpaceDeliverableService.getProjectSpaceDeliverableSummary(id) ); const results = await Promise.allSettled(promises); results.forEach((result, index) => { if (result.status === 'fulfilled') { this.statsCache.set(projectIds[index], result.value); } }); } ``` --- **提示**:更多高级用法和详细说明,请查看[完整使用指南](./PROJECT-SPACE-DELIVERABLE-SERVICE-GUIDE.md)。