// 修复 OnDestroy 导入和使用 import { Component, OnInit, OnDestroy, signal, computed } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { RouterModule, Router, ActivatedRoute } from '@angular/router'; import { ProjectService } from '../../../services/project.service'; import { Project, Task, CustomerFeedback } from '../../../models/project.model'; @Component({ selector: 'app-dashboard', standalone: true, imports: [CommonModule, FormsModule, RouterModule], templateUrl: './dashboard.html', styleUrls: ['./dashboard.scss', '../customer-service-styles.scss'], providers: [ProjectService] }) export class Dashboard implements OnInit, OnDestroy { // 数据看板统计 stats = { newConsultations: signal(12), pendingAssignments: signal(5), exceptionProjects: signal(2), todayRevenue: signal(28500) }; // 紧急待办列表 urgentTasks = signal([]); // 任务处理状态 taskProcessingState = signal<{[key: string]: {inProgress: boolean, progress: number}}>({}); // 项目动态流 projectUpdates = signal<(Project | CustomerFeedback)[]>([]); // 搜索关键词 searchTerm = signal(''); // 筛选后的项目更新 filteredUpdates = computed(() => { if (!this.searchTerm()) return this.projectUpdates(); return this.projectUpdates().filter(item => { if ('name' in item) { // 项目 return item.name.toLowerCase().includes(this.searchTerm().toLowerCase()) || item.customerName.toLowerCase().includes(this.searchTerm().toLowerCase()) || item.status.toLowerCase().includes(this.searchTerm().toLowerCase()); } else { // 反馈 return 'content' in item && item.content.toLowerCase().includes(this.searchTerm().toLowerCase()) || 'status' in item && item.status.toLowerCase().includes(this.searchTerm().toLowerCase()); } }); }); currentDate = new Date(); // 回到顶部按钮可见性信号 showBackToTopSignal = signal(false); // 任务表单可见性 isTaskFormVisible = signal(false); // 新任务数据 newTask: Task = { id: '', projectId: '', projectName: '', title: '', stage: '需求沟通', deadline: new Date(), isOverdue: false, isCompleted: false, priority: 'high', assignee: '当前用户', description: '' }; // 用于日期时间输入的属性 deadlineInput = ''; // 预设快捷时长选项 timePresets = [ { label: '1小时内', hours: 1 }, { label: '3小时内', hours: 3 }, { label: '6小时内', hours: 6 }, { label: '12小时内', hours: 12 }, { label: '24小时内', hours: 24 } ]; // 选中的预设时长 selectedPreset = ''; // 自定义时间弹窗可见性 isCustomTimeVisible = false; // 自定义选择的日期和时间 customDate = new Date(); customTime = ''; // 错误提示信息 deadlineError = ''; // 提交按钮是否禁用 isSubmitDisabled = false; // 下拉框可见性 deadlineDropdownVisible = false; // 日期范围限制 get todayDate(): string { return new Date().toISOString().split('T')[0]; } get sevenDaysLaterDate(): string { const date = new Date(); date.setDate(date.getDate() + 7); return date.toISOString().split('T')[0]; } constructor( private projectService: ProjectService, private router: Router, private activatedRoute: ActivatedRoute ) {} ngOnInit(): void { this.loadUrgentTasks(); this.loadProjectUpdates(); // 添加滚动事件监听 window.addEventListener('scroll', this.onScroll.bind(this)); } // 添加滚动事件处理方法 private onScroll(): void { this.showBackToTopSignal.set(window.scrollY > 300); } // 添加显示回到顶部按钮的计算属性 showBackToTop = computed(() => this.showBackToTopSignal()); // 清理事件监听器 ngOnDestroy(): void { window.removeEventListener('scroll', this.onScroll.bind(this)); } // 添加scrollToTop方法 scrollToTop(): void { window.scrollTo({ top: 0, behavior: 'smooth' }); } // 修改loadUrgentTasks方法,添加status属性 loadUrgentTasks(): void { // 从服务获取任务数据,筛选出紧急任务 this.projectService.getTasks().subscribe(tasks => { const filteredTasks = tasks.map(task => ({...task, status: task.isOverdue ? '已逾期' : task.isCompleted ? '已完成' : '进行中'})) .filter(task => task.isOverdue || task.deadline.toDateString() === new Date().toDateString()); this.urgentTasks.set(filteredTasks.sort((a, b) => { // 按紧急程度排序 if (a.isOverdue && !b.isOverdue) return -1; if (!a.isOverdue && b.isOverdue) return 1; return a.deadline.getTime() - b.deadline.getTime(); })); }); } loadProjectUpdates(): void { // 模拟项目更新数据 this.projectService.getProjects().subscribe(projects => { this.projectService.getCustomerFeedbacks().subscribe(feedbacks => { // 合并项目和反馈,按时间倒序排序 const updates: (Project | CustomerFeedback)[] = [ ...projects, ...feedbacks ].sort((a, b) => { const dateA = 'createdAt' in a ? a.createdAt : new Date(a['updatedAt'] || a['deadline']); const dateB = 'createdAt' in b ? b.createdAt : new Date(b['updatedAt'] || b['deadline']); return dateB.getTime() - dateA.getTime(); }).slice(0, 20); // 限制显示20条 this.projectUpdates.set(updates); }); }); } // 处理任务完成 markTaskAsCompleted(taskId: string): void { this.urgentTasks.set( this.urgentTasks().map(task => task.id === taskId ? { ...task, isCompleted: true, status: '已完成' } : task ) ); } // 处理派单操作 handleAssignment(taskId: string): void { // 标记任务为处理中 const task = this.urgentTasks().find(t => t.id === taskId); if (task) { // 初始化处理状态 this.taskProcessingState.update(state => ({ ...state, [task.id]: { inProgress: true, progress: 0 } })); // 模拟处理进度 let progress = 0; const interval = setInterval(() => { progress += 10; this.taskProcessingState.update(state => ({ ...state, [task.id]: { inProgress: progress < 100, progress } })); if (progress >= 100) { clearInterval(interval); // 处理完成后从列表中移除该任务 this.urgentTasks.set( this.urgentTasks().filter(t => t.id !== task.id) ); // 清除处理状态 this.taskProcessingState.update(state => { const newState = { ...state }; delete newState[task.id]; return newState; }); } }, 300); } // 更新统计数据 this.stats.pendingAssignments.set(this.stats.pendingAssignments() - 1); } // 显示任务表单 showTaskForm(): void { // 重置表单数据 this.newTask = { id: '', projectId: '', projectName: '', title: '', stage: '需求沟通', deadline: new Date(), isOverdue: false, isCompleted: false, priority: 'high', assignee: '当前用户', description: '' }; // 重置相关状态 this.deadlineError = ''; this.isSubmitDisabled = false; // 计算并设置默认预设时长 this.setDefaultPreset(); // 显示表单 this.isTaskFormVisible.set(true); // 添加iOS风格的面板显示动画 setTimeout(() => { document.querySelector('.ios-panel')?.classList.add('ios-panel-visible'); }, 10); } // 设置默认预设时长 private setDefaultPreset(): void { const now = new Date(); const todayEnd = new Date(now); todayEnd.setHours(23, 59, 59, 999); // 检查3小时后是否超过当天24:00 const threeHoursLater = new Date(now.getTime() + 3 * 60 * 60 * 1000); if (threeHoursLater <= todayEnd) { // 3小时后未超过当天24:00,默认选中3小时内 this.selectedPreset = '3'; this.updatePresetDeadline(3); } else { // 3小时后超过当天24:00,默认选中当天24:00前 this.selectedPreset = 'today'; this.deadlineInput = todayEnd.toISOString().slice(0, 16); this.newTask.deadline = todayEnd; } } // 处理预设时长选择 handlePresetSelection(preset: string): void { this.selectedPreset = preset; this.deadlineError = ''; if (preset === 'custom') { // 打开自定义时间选择器 this.openCustomTimePicker(); } else if (preset === 'today') { // 设置为当天24:00前 const now = new Date(); const todayEnd = new Date(now); todayEnd.setHours(23, 59, 59, 999); this.deadlineInput = todayEnd.toISOString().slice(0, 16); this.newTask.deadline = todayEnd; } else { // 计算预设时长的截止时间 const hours = parseInt(preset); this.updatePresetDeadline(hours); } } // 更新预设时长的截止时间 private updatePresetDeadline(hours: number): void { const now = new Date(); const deadline = new Date(now.getTime() + hours * 60 * 60 * 1000); this.deadlineInput = deadline.toISOString().slice(0, 16); this.newTask.deadline = deadline; } // 打开自定义时间选择器 openCustomTimePicker(): void { // 重置自定义时间 this.customDate = new Date(); const now = new Date(); this.customTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`; // 显示自定义时间弹窗 this.isCustomTimeVisible = true; // 添加iOS风格的弹窗动画 setTimeout(() => { document.querySelector('.custom-time-modal')?.classList.add('modal-visible'); }, 10); } // 关闭自定义时间选择器 closeCustomTimePicker(): void { // 添加iOS风格的弹窗关闭动画 const modal = document.querySelector('.custom-time-modal'); if (modal) { modal.classList.remove('modal-visible'); setTimeout(() => { this.isCustomTimeVisible = false; }, 300); } else { this.isCustomTimeVisible = false; } } // 处理自定义时间选择 handleCustomTimeSelection(): void { const [hours, minutes] = this.customTime.split(':').map(Number); const selectedDateTime = new Date(this.customDate); selectedDateTime.setHours(hours, minutes, 0, 0); // 验证选择的时间是否有效 if (this.validateDeadline(selectedDateTime)) { this.deadlineInput = selectedDateTime.toISOString().slice(0, 16); this.newTask.deadline = selectedDateTime; this.closeCustomTimePicker(); } } // 验证截止时间是否有效 validateDeadline(deadline: Date): boolean { const now = new Date(); if (deadline < now) { this.deadlineError = '截止时间不能早于当前时间,请重新选择'; this.isSubmitDisabled = true; return false; } this.deadlineError = ''; this.isSubmitDisabled = false; return true; } // 获取显示的截止时间文本 getDisplayDeadline(): string { if (!this.deadlineInput) return ''; try { const date = new Date(this.deadlineInput); return date.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } catch (error) { return ''; } } // 隐藏任务表单 hideTaskForm(): void { // 添加iOS风格的面板隐藏动画 const panel = document.querySelector('.ios-panel'); if (panel) { panel.classList.remove('ios-panel-visible'); setTimeout(() => { this.isTaskFormVisible.set(false); }, 300); } else { this.isTaskFormVisible.set(false); } } // 处理添加任务表单提交 handleAddTaskSubmit(): void { // 验证表单数据 if (!this.newTask.title.trim() || !this.newTask.projectName.trim() || !this.deadlineInput || this.isSubmitDisabled) { // 在实际应用中,这里应该显示错误提示 alert('请填写必填字段(任务标题、项目名称、截止时间)'); return; } // 创建新任务 const taskToAdd: Task = { ...this.newTask, id: `task-${Date.now()}`, projectId: `project-${Math.floor(Math.random() * 1000)}`, deadline: new Date(this.deadlineInput), isOverdue: new Date(this.deadlineInput) < new Date() }; // 添加到任务列表 this.urgentTasks.set([taskToAdd, ...this.urgentTasks()]); // 更新统计数据 this.stats.pendingAssignments.set(this.stats.pendingAssignments() + 1); // 隐藏表单 this.hideTaskForm(); } // 添加新的紧急事项 addUrgentTask(): void { // 调用显示表单方法 this.showTaskForm(); } // 新咨询数图标点击处理 handleNewConsultationsClick(): void { this.navigateToDetail('consultations'); } // 待派单数图标点击处理 handlePendingAssignmentsClick(): void { this.navigateToDetail('assignments'); } // 异常项目图标点击处理 handleExceptionProjectsClick(): void { this.navigateToDetail('exceptions'); } // 今日成交额图标点击处理 handleTodayRevenueClick(): void { this.navigateToDetail('revenue'); } // 导航到详情页 private navigateToDetail(type: 'consultations' | 'assignments' | 'exceptions' | 'revenue'): void { const routeMap = { consultations: '/customer-service/consultation-list', assignments: '/customer-service/assignment-list', exceptions: '/customer-service/exception-list', revenue: '/customer-service/revenue-detail' }; console.log('导航到:', routeMap[type]); console.log('当前路由:', this.router.url); // 添加iOS风格页面过渡动画 document.body.classList.add('ios-page-transition'); setTimeout(() => { this.router.navigateByUrl(routeMap[type]) .then(navResult => { console.log('导航结果:', navResult); if (!navResult) { console.error('导航失败,检查路由配置'); } }) .catch(err => { console.error('导航错误:', err); }); setTimeout(() => { document.body.classList.remove('ios-page-transition'); }, 300); }, 100); } // 格式化日期 formatDate(date: Date | string): string { if (!date) return ''; try { return new Date(date).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } catch (error) { console.error('日期格式化错误:', error); return ''; } } // 添加安全获取客户名称的方法 getCustomerName(update: Project | CustomerFeedback): string { if ('customerName' in update && update.customerName) { return update.customerName; } else if ('projectId' in update) { // 查找相关项目获取客户名称 return '客户反馈'; } return '未知客户'; } // 优化的日期格式化方法 getFormattedDate(update: Project | CustomerFeedback): string { if (!update) return ''; if ('createdAt' in update && update.createdAt) { return this.formatDate(update.createdAt); } else if ('updatedAt' in update && update.updatedAt) { return this.formatDate(update.updatedAt); } else if ('deadline' in update && update.deadline) { return this.formatDate(update.deadline); } return ''; } // 添加获取状态的安全方法 getUpdateStatus(update: Project | CustomerFeedback): string { if ('status' in update && update.status) { return update.status; } return '已更新'; } // 添加getTaskStatus方法的正确实现 getTaskStatus(task: Task): string { if (!task) return '未知状态'; if (task.isCompleted) return '已完成'; if (task.isOverdue) return '已逾期'; return '进行中'; } // 添加getUpdateStatusClass方法的正确实现 getUpdateStatusClass(update: Project | CustomerFeedback): string { if (!update || !('status' in update) || !update.status) return ''; switch (update.status) { case '进行中': return 'status-active'; case '已完成': return 'status-completed'; case '已延期': case '已暂停': return 'status-warning'; case '已解决': return 'status-success'; case '待处理': case '处理中': return 'status-info'; default: return ''; } } }