import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { DesignerTeamAssignmentModalComponent } from '../designer-team-assignment-modal/designer-team-assignment-modal.component'; export interface Designer { id: string; name: string; avatar?: string; teamId: string; teamName: string; isTeamLeader: boolean; status: 'idle' | 'busy' | 'reviewing'; idleDays: number; recentOrders: number; lastOrderDate?: string; reviewDates: string[]; // 对图日期,这些日期不能安排其他工作 workload: number; // 当前工作量 (0-100) skills: string[]; // 技能标签 isOnStagnantProject?: boolean; // 是否在停滞期项目中 isInStagnantProject: boolean; // 是否处于停滞期项目 availableDates: string[]; // 空闲日期 // 为了兼容团队分配弹窗与客户服务的日历组件,补充以下字段 groupId: string; // 对应 teamId groupName: string; // 对应 teamName isLeader: boolean; // 对应 isTeamLeader currentProjects: number; // 当前项目数量 } export interface ProjectTeam { id: string; name: string; leaderId: string; leaderName: string; members: Designer[]; } export interface QuotationAssignment { quotationItemId: string; quotationItemName: string; assignedDesigners: string[]; estimatedHours?: number; } export interface DesignerAssignmentData { primaryTeamId: string; quotationAssignments: QuotationAssignment[]; crossTeamCollaborators: string[]; // 跨组合作的设计师ID notes?: string; } @Component({ selector: 'app-designer-assignment', standalone: true, imports: [CommonModule, FormsModule, DesignerTeamAssignmentModalComponent], templateUrl: './designer-assignment.component.html', styleUrls: ['./designer-assignment.component.scss'] }) export class DesignerAssignmentComponent implements OnInit { @Input() quotationItems: any[] = []; @Input() initialAssignment?: DesignerAssignmentData; @Output() assignmentChange = new EventEmitter(); @Output() designerClick = new EventEmitter(); showTeamAssignmentModal = false; // 控制弹窗显示 showDesignerCalendar = false; // 控制设计师日历显示 selectedDesignerForCalendar: Designer | null = null; // 当前查看日历的设计师 // 模拟数据 - 实际项目中应该从服务获取 projectTeams: ProjectTeam[] = [ { id: 'team-1', name: '家装设计组', leaderId: 'designer-1', leaderName: '张组长', members: [ { id: 'designer-1', name: '张组长', teamId: 'team-1', teamName: '家装设计组', isTeamLeader: true, // 为了兼容弹窗与日历组件,补充映射字段 groupId: 'team-1', groupName: '家装设计组', isLeader: true, currentProjects: 3, status: 'busy', idleDays: 0, recentOrders: 3, lastOrderDate: '2024-01-15', reviewDates: ['2024-01-20', '2024-01-25'], workload: 85, skills: ['家装设计', '软装搭配', '项目管理'], isOnStagnantProject: false, isInStagnantProject: false, availableDates: ['2024-01-22', '2024-01-23', '2024-01-24'] }, { id: 'designer-2', name: '李设计师', teamId: 'team-1', teamName: '家装设计组', isTeamLeader: false, // 为了兼容弹窗与日历组件,补充映射字段 groupId: 'team-1', groupName: '家装设计组', isLeader: false, currentProjects: 2, status: 'busy', idleDays: 0, recentOrders: 1, lastOrderDate: '2024-01-10', reviewDates: [], workload: 30, skills: ['家装设计', '3D建模'], isOnStagnantProject: false, isInStagnantProject: false, availableDates: ['2024-01-21', '2024-01-22', '2024-01-23', '2024-01-24', '2024-01-25'] }, { id: 'designer-5', name: '赵停滞', teamId: 'team-1', teamName: '家装设计组', isTeamLeader: false, // 为了兼容弹窗与日历组件,补充映射字段 groupId: 'team-1', groupName: '家装设计组', isLeader: false, currentProjects: 4, status: 'busy', idleDays: 0, recentOrders: 1, lastOrderDate: '2023-12-20', reviewDates: [], workload: 90, skills: ['家装设计'], isOnStagnantProject: true, isInStagnantProject: true, availableDates: [] } ] }, { id: 'team-2', name: '工装设计组', leaderId: 'designer-3', leaderName: '王组长', members: [ { id: 'designer-3', name: '王组长', teamId: 'team-2', teamName: '工装设计组', isTeamLeader: true, // 为了兼容弹窗与日历组件,补充映射字段 groupId: 'team-2', groupName: '工装设计组', isLeader: true, currentProjects: 2, status: 'reviewing', idleDays: 0, recentOrders: 2, lastOrderDate: '2024-01-14', reviewDates: ['2024-01-18', '2024-01-22'], workload: 70, skills: ['工装设计', '商业空间', '项目管理'], isOnStagnantProject: false, isInStagnantProject: false, availableDates: ['2024-01-19', '2024-01-20', '2024-01-21'] }, { id: 'designer-4', name: '赵设计师', teamId: 'team-2', teamName: '工装设计组', isTeamLeader: false, // 为了兼容弹窗与日历组件,补充映射字段 groupId: 'team-2', groupName: '工装设计组', isLeader: true, currentProjects: 2, status: 'reviewing', idleDays: 0, recentOrders: 0, lastOrderDate: '2024-01-03', reviewDates: [], workload: 10, skills: ['工装设计', '效果图制作'], isOnStagnantProject: false, isInStagnantProject: false, availableDates: ['2024-01-21', '2024-01-22', '2024-01-23', '2024-01-24', '2024-01-25', '2024-01-26'] } ] } ]; assignmentData: DesignerAssignmentData = { primaryTeamId: '', quotationAssignments: [], crossTeamCollaborators: [], notes: '' }; selectedTeamId = ''; showCrossTeamSelection = false; availableCrossTeamDesigners: Designer[] = []; constructor() {} ngOnInit() { if (this.initialAssignment) { this.assignmentData = { ...this.initialAssignment }; this.selectedTeamId = this.assignmentData.primaryTeamId; } // 初始化报价分配 this.initializeQuotationAssignments(); } // 初始化报价分配 initializeQuotationAssignments() { if (this.quotationItems.length > 0 && this.assignmentData.quotationAssignments.length === 0) { this.assignmentData.quotationAssignments = this.quotationItems.map(item => ({ quotationItemId: item.id, quotationItemName: item.name, assignedDesigners: [], estimatedHours: 0 })); } } // 选择主要项目组 selectPrimaryTeam(teamId: string) { this.selectedTeamId = teamId; this.assignmentData.primaryTeamId = teamId; // 清空之前的分配 this.assignmentData.quotationAssignments.forEach(assignment => { assignment.assignedDesigners = []; }); this.updateAvailableCrossTeamDesigners(); this.emitAssignmentChange(); } // 获取选中的项目组 getSelectedTeam(): ProjectTeam | undefined { return this.projectTeams.find(team => team.id === this.selectedTeamId); } // 分配设计师到报价项目 assignDesignerToQuotation(quotationId: string, designerId: string) { const assignment = this.assignmentData.quotationAssignments.find(a => a.quotationItemId === quotationId); if (assignment) { if (!assignment.assignedDesigners.includes(designerId)) { assignment.assignedDesigners.push(designerId); this.emitAssignmentChange(); } } } // 移除设计师分配 removeDesignerFromQuotation(quotationId: string, designerId: string) { const assignment = this.assignmentData.quotationAssignments.find(a => a.quotationItemId === quotationId); if (assignment) { assignment.assignedDesigners = assignment.assignedDesigners.filter(id => id !== designerId); this.emitAssignmentChange(); } } // 更新可用的跨组合作设计师 updateAvailableCrossTeamDesigners() { this.availableCrossTeamDesigners = []; this.projectTeams.forEach(team => { if (team.id !== this.selectedTeamId) { this.availableCrossTeamDesigners.push(...team.members); } }); } // 添加跨组合作设计师 addCrossTeamCollaborator(designerId: string) { if (!this.assignmentData.crossTeamCollaborators.includes(designerId)) { this.assignmentData.crossTeamCollaborators.push(designerId); this.emitAssignmentChange(); } } // 移除跨组合作设计师 removeCrossTeamCollaborator(designerId: string) { this.assignmentData.crossTeamCollaborators = this.assignmentData.crossTeamCollaborators.filter(id => id !== designerId); this.emitAssignmentChange(); } // 获取设计师信息 getDesignerById(designerId: string): Designer | undefined { for (const team of this.projectTeams) { const designer = team.members.find(d => d.id === designerId); if (designer) return designer; } return undefined; } // 获取设计师状态颜色 getDesignerStatusColor(status: string): string { switch (status) { case 'idle': return '#52c41a'; case 'busy': return '#faad14'; case 'reviewing': return '#1890ff'; default: return '#d9d9d9'; } } // 获取设计师状态文本 getDesignerStatusText(status: string): string { switch (status) { case 'idle': return '空闲'; case 'busy': return '忙碌'; case 'reviewing': return '对图中'; default: return '未知'; } } // 获取工作量状态 getWorkloadStatus(workload: number): 'low' | 'medium' | 'high' { if (workload < 30) return 'low'; if (workload < 70) return 'medium'; return 'high'; } // 点击设计师 onDesignerClick(designer: Designer) { this.designerClick.emit(designer); } // 发送分配变化事件 emitAssignmentChange() { this.assignmentChange.emit({ ...this.assignmentData }); } // 自动分配建议 getAutoAssignmentSuggestion(): string { const selectedTeam = this.getSelectedTeam(); if (!selectedTeam) return ''; const idleDesigners = selectedTeam.members.filter(d => d.status === 'idle' && d.workload < 50); const busyDesigners = selectedTeam.members.filter(d => d.workload >= 70); let suggestion = ''; if (idleDesigners.length > 0) { suggestion += `建议优先分配给空闲设计师:${idleDesigners.map(d => d.name).join('、')}。`; } if (busyDesigners.length > 0) { suggestion += `注意:${busyDesigners.map(d => d.name).join('、')} 工作量较重。`; } return suggestion; } // 检查是否有冲突的对图日期 hasReviewDateConflict(designerId: string, projectStartDate?: string): boolean { const designer = this.getDesignerById(designerId); if (!designer || !projectStartDate) return false; // 简单的日期冲突检查逻辑 const startDate = new Date(projectStartDate); const endDate = new Date(startDate.getTime() + 30 * 24 * 60 * 60 * 1000); // 假设项目周期30天 return designer.reviewDates.some(reviewDate => { const review = new Date(reviewDate); return review >= startDate && review <= endDate; }); } // 获取团队空闲人数的安全方法 getIdleCount(team: ProjectTeam): number { if (!team || !team.members) return 0; return team.members.filter(m => m && m.status === 'idle').length; } // 获取团队平均工作量 getAverageWorkload(team: ProjectTeam): number { if (team.members.length === 0) return 0; const totalWorkload = team.members.reduce((sum, member) => sum + member.workload, 0); return Math.round(totalWorkload / team.members.length); } // 获取工作量样式类 getWorkloadClass(workload: number): string { if (workload < 50) return 'low'; if (workload < 80) return 'medium'; return 'high'; } // 打开设计师组分配弹窗 openTeamAssignmentModal(): void { this.showTeamAssignmentModal = true; } // 关闭设计师组分配弹窗 closeTeamAssignmentModal(): void { this.showTeamAssignmentModal = false; } // 显示设计师详细日历 showDesignerDetailCalendar(designer: Designer): void { this.selectedDesignerForCalendar = designer; this.showDesignerCalendar = true; } // 关闭设计师详细日历 closeDesignerCalendar(): void { this.showDesignerCalendar = false; this.selectedDesignerForCalendar = null; } // 过滤停滞期项目的设计师 filterStagnantDesigners(designers: Designer[]): Designer[] { return designers.filter(designer => !designer.isOnStagnantProject); } // 获取可用的设计师(过滤停滞期项目) getAvailableDesigners(team: ProjectTeam): Designer[] { return this.filterStagnantDesigners(team.members); } // 处理弹窗中的设计师分配确认 onModalAssignmentConfirm(assignmentResult: any): void { // 更新分配数据 this.selectedTeamId = assignmentResult.primaryTeamId; this.assignmentData.primaryTeamId = assignmentResult.primaryTeamId; this.assignmentData.crossTeamCollaborators = assignmentResult.crossTeamCollaborators; // 更新报价项目分配 if (assignmentResult.quotationAssignments) { this.assignmentData.quotationAssignments = assignmentResult.quotationAssignments; } // 关闭弹窗 this.closeTeamAssignmentModal(); // 触发变更事件 this.emitAssignmentChange(); } // 获取总分配设计师数量 getTotalAssignedDesigners(): number { return this.assignmentData.quotationAssignments.reduce((total, assignment) => total + assignment.assignedDesigners.length, 0); } }