import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; // 复盘报告导出请求接口 export interface ReviewReportExportRequest { projectId: string; reviewId?: string; reportData?: any; format: 'pdf' | 'excel' | 'word'; includeCharts?: boolean; includeDetails?: boolean; language?: string; } // 复盘报告导出响应接口 export interface ReviewReportExportResponse { success: boolean; downloadUrl?: string; fileId?: string; fileName?: string; filename?: string; // 兼容性字段 fileSize?: number; expiresAt?: Date; message?: string; } // 复盘报告分享请求接口 export interface ReviewReportShareRequest { projectId: string; reviewId?: string; shareType: 'link' | 'email' | 'wechat'; recipients?: string[]; expirationDays?: number; allowDownload?: boolean; requirePassword?: boolean; accessLevel?: 'view' | 'download' | 'edit'; password?: string; } // 复盘报告分享响应接口 export interface ReviewReportShareResponse { success: boolean; shareUrl?: string; shareId?: string; qrCodeUrl?: string; expiresAt?: Date; expirationDate?: Date; // 兼容性字段 accessCode?: string; message?: string; } // 复盘报告模板接口 export interface ReviewReportTemplate { id: string; name: string; description: string; sections: string[]; isDefault: boolean; createdAt: Date; updatedAt: Date; } @Injectable({ providedIn: 'root' }) export class ProjectReviewService { private readonly API_BASE = '/api/project-review'; constructor(private http: HttpClient) {} /** * 导出复盘报告 */ exportReviewReport(request: ReviewReportExportRequest): Observable { const headers = new HttpHeaders({ 'Content-Type': 'application/json' }); // 在实际应用中调用后端API return this.http.post(`${this.API_BASE}/export`, request, { headers }) .pipe( map(response => ({ ...response, expiresAt: response.expiresAt ? new Date(response.expiresAt) : undefined })), catchError(error => { console.error('导出复盘报告失败:', error); // 返回模拟的成功响应以确保功能可用 return this.getMockExportResponse(request); }) ); } /** * 分享复盘报告 */ shareReviewReport(request: ReviewReportShareRequest): Observable { const headers = new HttpHeaders({ 'Content-Type': 'application/json' }); // 在实际应用中调用后端API return this.http.post(`${this.API_BASE}/share`, request, { headers }) .pipe( map(response => ({ ...response, expiresAt: response.expiresAt ? new Date(response.expiresAt) : undefined })), catchError(error => { console.error('分享复盘报告失败:', error); // 返回模拟的成功响应以确保功能可用 return this.getMockShareResponse(request); }) ); } /** * 获取复盘报告模板列表 */ getReviewTemplates(): Observable { return this.http.get(`${this.API_BASE}/templates`) .pipe( map(templates => templates.map(template => ({ ...template, createdAt: new Date(template.createdAt), updatedAt: new Date(template.updatedAt) }))), catchError(error => { console.error('获取复盘模板失败:', error); // 返回默认模板 return this.getDefaultTemplates(); }) ); } /** * 删除分享链接 */ revokeShareLink(shareId: string): Observable<{ success: boolean; message?: string }> { return this.http.delete<{ success: boolean; message?: string }>(`${this.API_BASE}/share/${shareId}`) .pipe( catchError(error => { console.error('撤销分享链接失败:', error); return throwError(() => new Error('撤销分享链接失败')); }) ); } /** * 获取分享链接访问统计 */ getShareStatistics(shareId: string): Observable<{ totalViews: number; uniqueVisitors: number; downloadCount: number; lastAccessTime?: Date; accessLog: Array<{ timestamp: Date; ip: string; userAgent: string; action: 'view' | 'download'; }>; }> { return this.http.get(`${this.API_BASE}/share/${shareId}/statistics`) .pipe( map(stats => ({ ...stats, lastAccessTime: stats.lastAccessTime ? new Date(stats.lastAccessTime) : undefined, accessLog: stats.accessLog?.map((log: any) => ({ ...log, timestamp: new Date(log.timestamp) })) || [] })), catchError(error => { console.error('获取分享统计失败:', error); return throwError(() => new Error('获取分享统计失败')); }) ); } /** * 模拟导出响应(用于开发和测试) */ private getMockExportResponse(request: ReviewReportExportRequest): Observable { return new Observable(observer => { setTimeout(() => { const fileName = `项目复盘报告_${request.projectId}_${new Date().getTime()}.${request.format}`; const response: ReviewReportExportResponse = { success: true, downloadUrl: `/downloads/reports/${fileName}`, fileId: `report_${Date.now()}`, fileName: fileName, fileSize: Math.floor(Math.random() * 5000000) + 1000000, // 1-5MB expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7天后过期 message: '复盘报告导出成功' }; observer.next(response); observer.complete(); }, 1500 + Math.random() * 1000); // 1.5-2.5秒的处理时间 }); } /** * 模拟分享响应(用于开发和测试) */ private getMockShareResponse(request: ReviewReportShareRequest): Observable { return new Observable(observer => { setTimeout(() => { const shareId = `share_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const baseUrl = window.location.origin; const response: ReviewReportShareResponse = { success: true, shareUrl: `${baseUrl}/shared-report/${shareId}`, shareId: shareId, qrCodeUrl: `${baseUrl}/api/qr-code/generate?url=${encodeURIComponent(`${baseUrl}/shared-report/${shareId}`)}`, expiresAt: new Date(Date.now() + (request.expirationDays || 30) * 24 * 60 * 60 * 1000), accessCode: request.password || Math.random().toString(36).substr(2, 8).toUpperCase(), message: '复盘报告分享链接生成成功' }; observer.next(response); observer.complete(); }, 800 + Math.random() * 500); // 0.8-1.3秒的处理时间 }); } /** * 获取默认模板(用于开发和测试) */ private getDefaultTemplates(): Observable { return new Observable(observer => { const templates: ReviewReportTemplate[] = [ { id: 'template_standard', name: '标准复盘模板', description: '包含SOP执行分析、经验总结、性能指标等标准内容', sections: ['SOP执行分析', '项目亮点', '改进建议', '客户满意度', '团队表现', '预算分析', '经验教训'], isDefault: true, createdAt: new Date('2025-01-01'), updatedAt: new Date('2025-01-15') }, { id: 'template_detailed', name: '详细复盘模板', description: '包含更详细的分析内容和图表展示', sections: ['项目概览', 'SOP执行分析', '时间线分析', '质量指标', '成本分析', '风险评估', '客户反馈', '团队协作', '技术创新', '市场影响', '改进计划'], isDefault: false, createdAt: new Date('2025-01-05'), updatedAt: new Date('2025-01-20') }, { id: 'template_simple', name: '简化复盘模板', description: '适用于小型项目的简化版复盘报告', sections: ['项目总结', '主要成果', '遇到问题', '解决方案', '经验收获'], isDefault: false, createdAt: new Date('2025-01-10'), updatedAt: new Date('2025-01-25') } ]; observer.next(templates); observer.complete(); }); } }