| 
					
				 | 
			
			
				@@ -1,12 +1,15 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { Component, OnInit, OnDestroy } from '@angular/core'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { CommonModule } from '@angular/common'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { RouterModule } from '@angular/router'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { RouterModule, ActivatedRoute, Router } from '@angular/router'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { ProjectService } from '../../../services/project.service'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { Task } from '../../../models/project.model'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { SkillRadarComponent } from './skill-radar/skill-radar.component'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { PersonalBoard } from '../personal-board/personal-board'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { FmodeQuery, FmodeObject, FmodeUser } from 'fmode-ng/core'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { WxworkAuth } from 'fmode-ng/core'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { DesignerTaskService } from '../../../services/designer-task.service'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { LeaveService, LeaveApplication } from '../../../services/leave.service'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { FormsModule } from '@angular/forms'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 interface ShiftTask { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   id: string; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -28,7 +31,7 @@ interface ProjectTimelineItem { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 @Component({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   selector: 'app-dashboard', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   standalone: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  imports: [CommonModule, RouterModule, SkillRadarComponent, PersonalBoard], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  imports: [CommonModule, RouterModule, FormsModule, SkillRadarComponent, PersonalBoard], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   templateUrl: './dashboard.html', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   styleUrl: './dashboard.scss' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -54,52 +57,122 @@ export class Dashboard implements OnInit { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   projectTimeline: ProjectTimelineItem[] = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private wxAuth: WxworkAuth | null = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private currentUser: FmodeUser | null = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private currentProfile: FmodeObject | null = null; // 当前Profile 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private cid: string = ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 请假相关 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  showLeaveModal: boolean = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  leaveApplications: LeaveApplication[] = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  today: string = new Date().toISOString().split('T')[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 请假表单 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  leaveForm = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    startDate: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    endDate: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type: 'personal' as 'annual' | 'sick' | 'personal' | 'other', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    reason: '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  constructor(private projectService: ProjectService) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    this.initAuth(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  constructor( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private projectService: ProjectService, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private route: ActivatedRoute, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private router: Router, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private taskService: DesignerTaskService, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private leaveService: LeaveService 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ) {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  async ngOnInit(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 1. 从URL获取cid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.route.paramMap.subscribe(async params => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.cid = params.get('cid') || localStorage.getItem('company') || ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!this.cid) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.warn('⚠️ 未找到公司ID,尝试使用默认值'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.cid = 'cDL6R1hgSi'; // 默认公司ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 2. 初始化企微认证 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.initAuth(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 3. 执行认证并加载数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await this.authenticateAndLoadData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  // 初始化企业微信认证 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 初始化企业微信认证(优化版) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private initAuth(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.wxAuth = new WxworkAuth({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        cid: 'cDL6R1hgSi'  // 公司帐套ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cid: this.cid,  // 使用动态获取的cid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        appId: 'crm' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      console.log('✅ 设计师仪表板企业微信认证初始化成功'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('✅ 设计师端企微认证初始化成功,CID:', this.cid); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      console.error('❌ 设计师仪表板企业微信认证初始化失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('❌ 设计师端企微认证初始化失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  async ngOnInit(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    await this.authenticateAndLoadData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  // 认证并加载数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 认证并加载数据(优化版) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private async authenticateAndLoadData(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       // 执行企业微信认证和登录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      const { user } = await this.wxAuth!.authenticateAndLogin(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const { user, profile } = await this.wxAuth!.authenticateAndLogin(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.currentUser = user; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.currentProfile = profile; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (user) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        console.log('✅ 设计师登录成功:', user.get('username')); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        await this.loadDashboardData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!user || !profile) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         console.error('❌ 设计师登录失败'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.loadMockData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('✅ 设计师登录成功:', user.get('username')); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log('✅ Profile ID:', profile.id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 验证角色是否为"组员" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!await this.validateDesignerRole()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        alert('您不是设计师(组员),无权访问此页面'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.router.navigate(['/']); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 缓存Profile ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      localStorage.setItem('Parse/ProfileId', profile.id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 加载真实数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await this.loadDashboardData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       console.error('❌ 设计师认证过程出错:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       // 降级到模拟数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.loadMockData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 验证设计师(组员)角色 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private async validateDesignerRole(): Promise<boolean> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!this.currentProfile) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const roleName = this.currentProfile.get('roleName'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (roleName !== '组员') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.warn(`⚠️ 用户角色为"${roleName}",不是"组员"`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.log('✅ 角色验证通过:组员(设计师)'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // 加载仪表板数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private async loadDashboardData(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       await Promise.all([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this.loadTasks(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.loadRealTasks(),      // 使用真实数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         this.loadShiftTasks(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         this.calculateWorkloadPercentage(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         this.loadProjectTimeline() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -111,6 +184,127 @@ export class Dashboard implements OnInit { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 加载真实任务数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private async loadRealTasks(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!this.currentProfile) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        throw new Error('未找到当前Profile'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const designerTasks = await this.taskService.getMyTasks(this.currentProfile.id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 转换为组件所需格式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.tasks = designerTasks.map(task => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        id: task.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        projectId: task.projectId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        projectName: task.projectName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: task.projectName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        stage: task.stage, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        deadline: task.deadline, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        isOverdue: task.isOverdue, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        priority: task.priority, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        isCompleted: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assignee: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        description: `${task.stage} - ${task.customerName}` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })) as Task[]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 筛选超期任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.overdueTasks = this.tasks.filter(task => task.isOverdue); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 筛选紧急任务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.urgentTasks = this.tasks.filter(task => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const now = new Date(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const diffHours = (task.deadline.getTime() - now.getTime()) / (1000 * 60 * 60); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return diffHours <= 3 && diffHours > 0 && task.stage === '渲染'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 设置反馈项目ID 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (this.overdueTasks.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.feedbackProjectId = this.overdueTasks[0].projectId; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 加载待处理反馈 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await this.loadRealPendingFeedbacks(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 启动倒计时 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.startCountdowns(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log(`✅ 成功加载 ${this.tasks.length} 个真实任务`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('❌ 加载真实任务失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      throw error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 加载真实待处理反馈 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private async loadRealPendingFeedbacks(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const Parse = await import('fmode-ng/parse').then(m => m.FmodeParse.with('nova')); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 查询该设计师相关项目的待处理反馈 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const projectIds = this.tasks.map(t => t.projectId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (projectIds.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.pendingFeedbacks = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const query = new Parse.Query('ProjectFeedback'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const ProjectClass = Parse.Object.extend('Project'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      query.containedIn('project', projectIds.map(id => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const obj = new ProjectClass(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        obj.id = id; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return obj; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      query.equalTo('status', '待处理'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      query.notEqualTo('isDeleted', true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      query.include('project'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      query.include('contact'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      query.descending('createdAt'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      query.limit(100); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const feedbacks = await query.find(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.pendingFeedbacks = feedbacks.map((feedback: any) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const project = feedback.get('project'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const task = this.tasks.find(t => t.projectId === project?.id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const fallbackTask: Task = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          id: project?.id || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          projectId: project?.id || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          projectName: project?.get('title') || '未知项目', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          title: project?.get('title') || '未知项目', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          stage: '投诉处理', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          deadline: new Date(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          isOverdue: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          isCompleted: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          priority: 'high', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          assignee: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          description: '待处理反馈' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          task: task || fallbackTask, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          feedback: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            id: feedback.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            content: feedback.get('content') || '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            rating: feedback.get('rating'), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            createdAt: feedback.get('createdAt') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log(`✅ 成功加载 ${this.pendingFeedbacks.length} 个待处理反馈`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('❌ 加载待处理反馈失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.pendingFeedbacks = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // 降级到模拟数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private loadMockData(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     console.warn('⚠️ 使用模拟数据'); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -511,5 +705,135 @@ export class Dashboard implements OnInit { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ].sort((a, b) => new Date(a.deadline).getTime() - new Date(b.deadline).getTime()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 打开请假申请弹窗 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  openLeaveModal(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.showLeaveModal = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 关闭请假申请弹窗 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  closeLeaveModal(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.showLeaveModal = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.resetLeaveForm(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 提交请假申请 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  async submitLeaveApplication(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!this.currentProfile) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      alert('未找到当前用户信息'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 验证表单 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!this.leaveForm.startDate || !this.leaveForm.endDate) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      alert('请选择请假日期'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!this.leaveForm.reason.trim()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      alert('请输入请假原因'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const startDate = new Date(this.leaveForm.startDate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const endDate = new Date(this.leaveForm.endDate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (startDate > endDate) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      alert('结束日期不能早于开始日期'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 计算请假天数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const days = this.leaveService.calculateLeaveDays(startDate, endDate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (days === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      alert('请假天数必须大于0(周末不计入)'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const success = await this.leaveService.submitLeaveApplication( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.currentProfile.id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          startDate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          endDate, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type: this.leaveForm.type, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          reason: this.leaveForm.reason, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          days 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        alert(`请假申请已提交!共${days}天(已排除周末)`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.closeLeaveModal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        await this.loadMyLeaveRecords(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        alert('请假申请提交失败,请重试'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('提交请假申请失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      alert('请假申请提交失败,请重试'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 加载我的请假记录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private async loadMyLeaveRecords(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!this.currentProfile) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.leaveApplications = await this.leaveService.getMyLeaveRecords( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.currentProfile.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log(`✅ 成功加载 ${this.leaveApplications.length} 条请假记录`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.error('❌ 加载请假记录失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 重置请假表单 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private resetLeaveForm(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.leaveForm = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      startDate: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      endDate: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: 'personal', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      reason: '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 获取请假类型文本 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  getLeaveTypeText(type: string): string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const typeMap: Record<string, string> = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      'annual': '年假', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      'sick': '病假', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      'personal': '事假', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      'other': '其他' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return typeMap[type] || type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 获取请假状态文本 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  getLeaveStatusText(status: string): string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const statusMap: Record<string, string> = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      'pending': '待审批', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      'approved': '已批准', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      'rejected': '已拒绝' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return statusMap[status] || status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |