| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 | 
							- import { Component, OnInit, OnDestroy } from '@angular/core';
 
- import { CommonModule } from '@angular/common';
 
- import { RouterModule } 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';
 
- interface ShiftTask {
 
-   id: string;
 
-   projectId: string;
 
-   projectName: string;
 
-   taskDescription: string;
 
-   priority: '高' | '中' | '低';
 
-   shiftDate: string;
 
-   status: '待处理' | '处理中' | '已完成';
 
- }
 
- interface ProjectTimelineItem {
 
-   id: string;
 
-   name: string;
 
-   deadline: string;
 
-   status: string;
 
- }
 
- @Component({
 
-   selector: 'app-dashboard',
 
-   standalone: true,
 
-   imports: [CommonModule, RouterModule, SkillRadarComponent, PersonalBoard],
 
-   templateUrl: './dashboard.html',
 
-   styleUrl: './dashboard.scss'
 
- })
 
- export class Dashboard implements OnInit {
 
-   // 视图管理
 
-   activeDashboard: 'main' | 'skills' | 'personal' = 'main';
 
-   // 新增:工作台视图模式(卡片/列表)
 
-   viewMode: 'card' | 'list' = 'list';
 
-   
 
-   tasks: Task[] = [];
 
-   overdueTasks: Task[] = [];
 
-   urgentTasks: Task[] = [];
 
-   pendingFeedbacks: {task: Task, feedback: any}[] = [];
 
-   reminderMessage: string = '';
 
-   feedbackProjectId: string = '';
 
-   countdowns: Map<string, string> = new Map();
 
-   
 
-   // 代班信息相关属性
 
-   shiftTasks: ShiftTask[] = [];
 
-   
 
-   // 个人项目饱和度相关属性
 
-   workloadPercentage: number = 0;
 
-   projectTimeline: ProjectTimelineItem[] = [];
 
-   private wxAuth: WxworkAuth | null = null;
 
-   private currentUser: FmodeUser | null = null;
 
-   constructor(private projectService: ProjectService) {
 
-     this.initAuth();
 
-   }
 
-   // 初始化企业微信认证
 
-   private initAuth(): void {
 
-     try {
 
-       this.wxAuth = new WxworkAuth({
 
-         cid: 'cDL6R1hgSi'  // 公司帐套ID
 
-       });
 
-       console.log('✅ 设计师仪表板企业微信认证初始化成功');
 
-     } catch (error) {
 
-       console.error('❌ 设计师仪表板企业微信认证初始化失败:', error);
 
-     }
 
-   }
 
-   async ngOnInit(): Promise<void> {
 
-     await this.authenticateAndLoadData();
 
-   }
 
-   // 认证并加载数据
 
-   private async authenticateAndLoadData(): Promise<void> {
 
-     try {
 
-       // 执行企业微信认证和登录
 
-       const { user } = await this.wxAuth!.authenticateAndLogin();
 
-       this.currentUser = user;
 
-       if (user) {
 
-         console.log('✅ 设计师登录成功:', user.get('username'));
 
-         await this.loadDashboardData();
 
-       } else {
 
-         console.error('❌ 设计师登录失败');
 
-       }
 
-     } catch (error) {
 
-       console.error('❌ 设计师认证过程出错:', error);
 
-       // 降级到模拟数据
 
-       this.loadMockData();
 
-     }
 
-   }
 
-   // 加载仪表板数据
 
-   private async loadDashboardData(): Promise<void> {
 
-     try {
 
-       await Promise.all([
 
-         this.loadTasks(),
 
-         this.loadShiftTasks(),
 
-         this.calculateWorkloadPercentage(),
 
-         this.loadProjectTimeline()
 
-       ]);
 
-       console.log('✅ 设计师仪表板数据加载完成');
 
-     } catch (error) {
 
-       console.error('❌ 设计师仪表板数据加载失败:', error);
 
-       throw error;
 
-     }
 
-   }
 
-   // 降级到模拟数据
 
-   private loadMockData(): void {
 
-     console.warn('⚠️ 使用模拟数据');
 
-     this.loadTasks();
 
-     this.loadShiftTasks();
 
-     this.calculateWorkloadPercentage();
 
-     this.loadProjectTimeline();
 
-   }
 
-   
 
-   // 切换视图方法
 
-   switchDashboard(view: 'main' | 'skills' | 'personal'): void {
 
-     this.activeDashboard = view;
 
-   }
 
-   
 
-   // 新增:切换卡片/列表视图
 
-   toggleView(): void {
 
-     this.viewMode = this.viewMode === 'card' ? 'list' : 'card';
 
-   }
 
-   
 
-   // 获取前N个任务的方法
 
-   getTopTasks(count: number): Task[] {
 
-     // 过滤掉紧急任务和超期任务
 
-     const regularTasks = this.tasks.filter(task => 
 
-       !this.urgentTasks.some(urgent => urgent.id === task.id) &&
 
-       !this.overdueTasks.some(overdue => overdue.id === task.id)
 
-     );
 
-     
 
-     // 返回指定数量的任务
 
-     return regularTasks.slice(0, count);
 
-   }
 
-   
 
-   // 获取工作量颜色的方法
 
-   getWorkloadColor(): string {
 
-     if (this.workloadPercentage >= 80) {
 
-       return '#ff4560'; // 红色
 
-     } else if (this.workloadPercentage >= 50) {
 
-       return '#ffa726'; // 橙色
 
-     } else {
 
-       return '#66bb6a'; // 绿色
 
-     }
 
-   }
 
-   
 
-   // 获取工作量状态的方法
 
-   getWorkloadStatus(): string {
 
-     if (this.workloadPercentage >= 80) {
 
-       return '工作量饱和';
 
-     } else if (this.workloadPercentage >= 50) {
 
-       return '工作量适中';
 
-     } else if (this.workloadPercentage > 0) {
 
-       return '工作量轻松';
 
-     } else {
 
-       return '暂无工作任务';
 
-     }
 
-   }
 
-   loadTasks(): void {
 
-     this.projectService.getTasks().subscribe(tasks => {
 
-       // 按阶段优先级排序:建模 > 渲染 > 对图 > 反馈处理 > 后期 > 其他
 
-       this.tasks = tasks.sort((a, b) => {
 
-         const stagePriority: Record<string, number> = {
 
-           '建模': 5,
 
-           '渲染': 4,
 
-           '对图': 3,
 
-           '反馈处理': 2,
 
-           '后期': 1,
 
-           '投诉处理': 0
 
-         };
 
-         
 
-         const priorityA = stagePriority[a.stage] || 0;
 
-         const priorityB = stagePriority[b.stage] || 0;
 
-         
 
-         if (priorityA !== priorityB) {
 
-           return priorityB - priorityA;
 
-         }
 
-         
 
-         // 优先级相同时,按截止日期排序
 
-         return a.deadline.getTime() - b.deadline.getTime();
 
-       });
 
-       
 
-       // 筛选超期任务
 
-       this.overdueTasks = this.tasks.filter(task => task.isOverdue);
 
-       
 
-       // 筛选紧急任务(渲染超时预警,交付前3小时/1小时)
 
-       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;
 
-       }
 
-       
 
-       // 加载待处理反馈
 
-       this.loadPendingFeedbacks();
 
-       
 
-       // 启动倒计时
 
-       this.startCountdowns();
 
-     });
 
-   }
 
-   
 
-   loadPendingFeedbacks(): void {
 
-     this.pendingFeedbacks = [];
 
-     
 
-     // 模拟加载待处理反馈数据
 
-     this.tasks.forEach(task => {
 
-       // 使用模拟数据代替API调用
 
-       const mockFeedbacks = [
 
-         {
 
-           id: 'fb-' + task.id,
 
-           projectId: task.projectId,
 
-           content: '客户对色彩不满意,需要调整',
 
-           isSatisfied: false,
 
-           problemLocation: '色彩',
 
-           expectedEffect: '更明亮的色调',
 
-           referenceCase: '无',
 
-           status: '待处理' as const,
 
-           createdAt: new Date(Date.now() - 30 * 60 * 1000) // 30分钟前
 
-         },
 
-         {
 
-           id: 'fb-' + task.id + '-2',
 
-           projectId: task.projectId,
 
-           content: '家具款式需要调整',
 
-           isSatisfied: false,
 
-           problemLocation: '家具',
 
-           expectedEffect: '更现代的款式',
 
-           referenceCase: '无',
 
-           status: '待处理' as const,
 
-           createdAt: new Date(Date.now() - 45 * 60 * 1000) // 45分钟前
 
-         }
 
-       ];
 
-       
 
-       const pending = mockFeedbacks.filter(feedback => 
 
-         feedback.status === '待处理' && 
 
-         !feedback.isSatisfied
 
-       );
 
-       
 
-       if (pending.length > 0) {
 
-         this.pendingFeedbacks.push({task, feedback: pending[0]});
 
-       }
 
-     });
 
-   }
 
-   
 
-   startCountdowns(): void {
 
-     // 清除之前的定时器
 
-     this.countdowns.clear();
 
-     
 
-     // 为所有任务启动倒计时,确保列表视图也有剩余时间显示
 
-     this.tasks.forEach(task => {
 
-       this.updateCountdown(task.id, task.deadline);
 
-     });
 
-     
 
-     // 定期更新倒计时
 
-     setInterval(() => {
 
-       this.tasks.forEach(task => {
 
-         this.updateCountdown(task.id, task.deadline);
 
-       });
 
-     }, 60000); // 每分钟更新一次
 
-   }
 
-   
 
-   updateCountdown(taskId: string, deadline: Date): void {
 
-     const now = new Date();
 
-     const diffMs = deadline.getTime() - now.getTime();
 
-     
 
-     if (diffMs <= 0) {
 
-       this.countdowns.set(taskId, '已超期');
 
-       return;
 
-     }
 
-     
 
-     const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
 
-     const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
 
-     
 
-     if (diffHours > 0) {
 
-       this.countdowns.set(taskId, `${diffHours}小时${diffMinutes}分钟`);
 
-     } else {
 
-       this.countdowns.set(taskId, `${diffMinutes}分钟`);
 
-     }
 
-   }
 
-   
 
-   getTaskCountdown(taskId: string): string {
 
-     return this.countdowns.get(taskId) || '';
 
-   }
 
-   
 
-   // 新增:列表视图专用剩余时间格式化(若未在countdowns中,直接计算)
 
-   getListTimeLeft(task: Task): string {
 
-     const cached = this.getTaskCountdown(task.id);
 
-     if (cached) return cached;
 
-     const now = new Date();
 
-     const diffMs = task.deadline.getTime() - now.getTime();
 
-     if (diffMs <= 0) return '已超期';
 
-     const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
 
-     const diffHours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
 
-     if (diffDays > 0) return `${diffDays}天${diffHours}小时`;
 
-     const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
 
-     if (diffHours > 0) return `${diffHours}小时${diffMinutes}分钟`;
 
-     return `${diffMinutes}分钟`;
 
-   }
 
-   // 新增:按紧急度排序
 
-   getTasksSortedByUrgency(): Task[] {
 
-     return this.tasks
 
-       .filter(t => !t.isCompleted)
 
-       .slice()
 
-       .sort((a, b) => this.getUrgencyScore(b) - this.getUrgencyScore(a));
 
-   }
 
-   // 新增:紧急度评分,数值越大越紧急
 
-   private getUrgencyScore(task: Task): number {
 
-     if (task.isOverdue) return 10000;
 
-     const now = new Date().getTime();
 
-     const hoursLeft = (task.deadline.getTime() - now) / (1000 * 60 * 60);
 
-     let base = 0;
 
-     if (hoursLeft <= 3) base = 9000;
 
-     else if (hoursLeft <= 24) base = 7000;
 
-     else if (hoursLeft <= 72) base = 4000;
 
-     else base = 1000;
 
-     // 渲染阶段适度提高权重
 
-     const stageBoost = task.stage === '渲染' ? 300 : 0;
 
-     return base + stageBoost;
 
-   }
 
-   // 新增:紧急度标签
 
-   getUrgencyLevel(task: Task): '超期' | '高' | '中' | '低' {
 
-     if (task.isOverdue) return '超期';
 
-     const now = new Date().getTime();
 
-     const hoursLeft = (task.deadline.getTime() - now) / (1000 * 60 * 60);
 
-     if (hoursLeft <= 24) return '高';
 
-     if (hoursLeft <= 72) return '中';
 
-     return '低';
 
-   }
 
-   // 新增:紧急度样式类
 
-   getUrgencyClass(task: Task): string {
 
-     const level = this.getUrgencyLevel(task);
 
-     switch (level) {
 
-       case '超期':
 
-         return 'urgency-overdue';
 
-       case '高':
 
-         return 'urgency-high';
 
-       case '中':
 
-         return 'urgency-medium';
 
-       default:
 
-         return 'urgency-low';
 
-     }
 
-   }
 
-   
 
-   getTaskStageProgress(taskId: string): number {
 
-     const task = this.tasks.find(t => t.id === taskId);
 
-     if (!task) return 0;
 
-     // 为不同阶段设置固定的模拟进度值
 
-     const stageProgressMap: Record<string, number> = {
 
-       '建模': 22,
 
-       '渲染': 23,
 
-       '对图': 50,
 
-       '反馈处理': 80,
 
-       '后期': 75,
 
-       '投诉处理': 100
 
-     };
 
-     // 对于渲染任务,如果有实际的渲染进度数据,使用它
 
-     if (task.stage === '渲染') {
 
-       // 在实际应用中,这里会从服务中获取真实的进度
 
-       // this.projectService.getRenderProgress(task.projectId).subscribe(progress => {
 
-       //   if (progress) {
 
-       //     return progress.completionRate;
 
-       //   }
 
-       // });
 
-     }
 
-     return stageProgressMap[task.stage] || 0;
 
-   }
 
-   markTaskAsCompleted(taskId: string): void {
 
-     this.projectService.markTaskAsCompleted(taskId).subscribe(() => {
 
-       this.loadTasks(); // 重新加载任务列表
 
-     });
 
-   }
 
-   
 
-   handleFeedback(taskId: string): void {
 
-     const task = this.tasks.find(t => t.id === taskId);
 
-     if (task) {
 
-       // 跳转到项目详情的反馈处理页面
 
-       window.location.href = `/designer/project-detail/${task.projectId}#feedback`;
 
-     }
 
-   }
 
-   generateReminderMessage(): void {
 
-     this.projectService.generateReminderMessage('overdue').subscribe(message => {
 
-       this.reminderMessage = message;
 
-     });
 
-   }
 
-   clearReminder(): void {
 
-     this.reminderMessage = '';
 
-   }
 
-   // 代班任务相关方法
 
-   loadShiftTasks(): void {
 
-     // 在实际应用中,这里应该从服务中获取代班任务
 
-     // 这里使用模拟数据
 
-     this.shiftTasks = [
 
-       {
 
-         id: 'shift1',
 
-         projectId: 'project1',
 
-         projectName: '现代风格客厅设计',
 
-         taskDescription: '小图修改反馈和渲染进度跟踪',
 
-         priority: '高',
 
-         shiftDate: '2025-09-15',
 
-         status: '待处理'
 
-       },
 
-       {
 
-         id: 'shift2',
 
-         projectId: 'project2',
 
-         projectName: '北欧风卧室装修',
 
-         taskDescription: '查看客户反馈并提供初步修改建议',
 
-         priority: '中',
 
-         shiftDate: '2025-09-16',
 
-         status: '待处理'
 
-       },
 
-       {
 
-         id: 'shift3',
 
-         projectId: 'project3',
 
-         projectName: '新中式书房改造',
 
-         taskDescription: '完成剩余渲染任务',
 
-         priority: '低',
 
-         shiftDate: '2025-09-17',
 
-         status: '处理中'
 
-       }
 
-     ];
 
-   }
 
-   // 打开添加代班任务的模态框
 
-   openShiftModal(): void {
 
-     // 在实际应用中,这里应该打开一个模态框让用户添加代班任务
 
-     // 这里使用alert模拟
 
-     window.fmode?.alert?.({
 
-       header: '添加代班任务',
 
-       message: '将打开添加代班任务的表单',
 
-       buttons: [{ text: '确定', role: 'confirm' }]
 
-     });
 
-     // 实际实现可能是:this.modalService.openShiftModal();
 
-   }
 
-   // 查看代班任务详情
 
-   viewShiftDetail(shiftId: string): void {
 
-     const shift = this.shiftTasks.find(s => s.id === shiftId);
 
-     if (shift) {
 
-       // 实际应用中,这里应该打开详情页面或模态框
 
-       console.log('查看代班任务详情:', shift);
 
-      window?.fmode?.alert(`代班任务详情:\n项目:${shift.projectName}\n任务:${shift.taskDescription}\n优先级:${shift.priority}\n代班日期:${shift.shiftDate}`);
 
-     }
 
-   }
 
-   // 标记代班任务完成
 
-   markShiftComplete(shiftId: string): void {
 
-     const shiftIndex = this.shiftTasks.findIndex(s => s.id === shiftId);
 
-     if (shiftIndex !== -1) {
 
-       // 在实际应用中,这里应该调用API更新状态
 
-       this.shiftTasks[shiftIndex].status = '已完成';
 
-      window?.fmode?.alert('代班任务已标记为完成');
 
-     }
 
-   }
 
-   // 计算项目饱和度
 
-   calculateWorkloadPercentage(): void {
 
-     // 在实际应用中,这里应该从服务中获取真实的项目饱和度数据
 
-     // 这里使用模拟数据,根据当前任务数量计算饱和度
 
-     const totalCapacity = 5; // 假设设计师最大同时处理5个项目
 
-     const currentProjects = this.tasks.length;
 
-     
 
-     // 计算饱和度百分比
 
-     this.workloadPercentage = Math.round((currentProjects / totalCapacity) * 100);
 
-     
 
-     // 确保百分比在0-100之间
 
-     this.workloadPercentage = Math.min(Math.max(this.workloadPercentage, 0), 100);
 
-   }
 
-   // 加载项目排期表
 
-   loadProjectTimeline(): void {
 
-     // 在实际应用中,这里应该从服务中获取项目排期数据
 
-     // 这里使用模拟数据
 
-     this.projectTimeline = [
 
-       {
 
-         id: 'timeline1',
 
-         name: '现代风格客厅设计',
 
-         deadline: '2025-09-20',
 
-         status: '进行中'
 
-       },
 
-       {
 
-         id: 'timeline2',
 
-         name: '北欧风卧室装修',
 
-         deadline: '2025-09-25',
 
-         status: '进行中'
 
-       },
 
-       {
 
-         id: 'timeline3',
 
-         name: '新中式书房改造',
 
-         deadline: '2025-09-30',
 
-         status: '进行中'
 
-       }
 
-     ].sort((a, b) => new Date(a.deadline).getTime() - new Date(b.deadline).getTime());
 
-   }
 
- }
 
 
  |