| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- 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<ReviewReportExportResponse> {
- const headers = new HttpHeaders({
- 'Content-Type': 'application/json'
- });
- // 在实际应用中调用后端API
- return this.http.post<ReviewReportExportResponse>(`${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<ReviewReportShareResponse> {
- const headers = new HttpHeaders({
- 'Content-Type': 'application/json'
- });
- // 在实际应用中调用后端API
- return this.http.post<ReviewReportShareResponse>(`${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<ReviewReportTemplate[]> {
- return this.http.get<ReviewReportTemplate[]>(`${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<any>(`${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<ReviewReportExportResponse> {
- 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<ReviewReportShareResponse> {
- 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<ReviewReportTemplate[]> {
- 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();
- });
- }
- }
|