project-progress-modal.component.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { FormsModule } from '@angular/forms';
  4. import { RouterModule } from '@angular/router';
  5. import { ProjectSpaceDeliverableSummary, PhaseProgressInfo } from '../../services/project-space-deliverable.service';
  6. import { PHASE_INFO, PhaseName } from '../../../../app/models/project-phase.model';
  7. /**
  8. * 项目进度详情弹窗组件(独立组件)
  9. *
  10. * 功能:
  11. * - 显示项目的整体进度统计
  12. * - 按阶段展示完成情况(建模、软装、渲染、后期)
  13. * - 显示未完成的空间列表和负责人
  14. * - 提供问题提交入口
  15. *
  16. * 使用场景:
  17. * - 项目时间轴页面
  18. * - 项目详情页面
  19. * - 其他需要查看项目进度的地方
  20. */
  21. @Component({
  22. selector: 'app-project-progress-modal',
  23. standalone: true,
  24. imports: [CommonModule, FormsModule, RouterModule],
  25. templateUrl: './project-progress-modal.component.html',
  26. styleUrl: './project-progress-modal.component.scss'
  27. })
  28. export class ProjectProgressModalComponent implements OnInit {
  29. @Input() summary: ProjectSpaceDeliverableSummary | null = null;
  30. @Input() visible: boolean = false;
  31. @Input() companyId: string = ''; // 🆕 公司ID,用于项目详情页导航
  32. @Output() close = new EventEmitter<void>();
  33. @Output() reportIssue = new EventEmitter<string>(); // 提交问题,传递项目ID
  34. // 当前选中的阶段(用于展开/收起详情)
  35. selectedPhase: PhaseName | null = null;
  36. // 阶段常量
  37. readonly PHASE_INFO = PHASE_INFO;
  38. ngOnInit(): void {
  39. console.log('📊 项目进度弹窗初始化', this.summary);
  40. }
  41. /**
  42. * 关闭弹窗
  43. */
  44. onClose(): void {
  45. this.close.emit();
  46. }
  47. /**
  48. * 阻止点击弹窗内容时关闭
  49. */
  50. onContentClick(event: MouseEvent): void {
  51. event.stopPropagation();
  52. }
  53. /**
  54. * 切换阶段展开/收起
  55. */
  56. togglePhase(phaseName: PhaseName): void {
  57. this.selectedPhase = this.selectedPhase === phaseName ? null : phaseName;
  58. }
  59. /**
  60. * 判断阶段是否展开
  61. */
  62. isPhaseExpanded(phaseName: PhaseName): boolean {
  63. return this.selectedPhase === phaseName;
  64. }
  65. /**
  66. * 获取阶段列表
  67. */
  68. getPhases(): Array<{ name: PhaseName; info: PhaseProgressInfo }> {
  69. if (!this.summary?.phaseProgress) return [];
  70. return [
  71. { name: 'modeling', info: this.summary.phaseProgress.modeling },
  72. { name: 'softDecor', info: this.summary.phaseProgress.softDecor },
  73. { name: 'rendering', info: this.summary.phaseProgress.rendering },
  74. { name: 'postProcessing', info: this.summary.phaseProgress.postProcessing }
  75. ];
  76. }
  77. /**
  78. * 获取阶段进度颜色
  79. */
  80. getPhaseProgressColor(completionRate: number): string {
  81. if (completionRate === 100) return '#4CAF50'; // 绿色
  82. if (completionRate >= 75) return '#8BC34A'; // 浅绿
  83. if (completionRate >= 50) return '#FFC107'; // 黄色
  84. if (completionRate >= 25) return '#FF9800'; // 橙色
  85. if (completionRate > 0) return '#FF5722'; // 深橙
  86. return '#9E9E9E'; // 灰色(未开始)
  87. }
  88. /**
  89. * 获取阶段状态标签
  90. */
  91. getPhaseStatusLabel(completionRate: number): string {
  92. if (completionRate === 100) return '已完成';
  93. if (completionRate >= 75) return '接近完成';
  94. if (completionRate >= 50) return '进行中';
  95. if (completionRate >= 25) return '刚开始';
  96. if (completionRate > 0) return '已启动';
  97. return '未开始';
  98. }
  99. /**
  100. * 提交问题
  101. */
  102. onReportIssue(): void {
  103. if (this.summary) {
  104. this.reportIssue.emit(this.summary.projectId);
  105. }
  106. }
  107. /**
  108. * 获取整体完成率的颜色
  109. */
  110. getOverallProgressColor(): string {
  111. if (!this.summary) return '#9E9E9E';
  112. return this.getPhaseProgressColor(this.summary.overallCompletionRate);
  113. }
  114. /**
  115. * 获取整体完成率的状态文字
  116. */
  117. getOverallStatusLabel(): string {
  118. if (!this.summary) return '加载中';
  119. return this.getPhaseStatusLabel(this.summary.overallCompletionRate);
  120. }
  121. /**
  122. * 🆕 获取项目详情页路由
  123. */
  124. getProjectDetailRoute(): string[] {
  125. if (!this.summary || !this.companyId) {
  126. return [];
  127. }
  128. return ['/wxwork', this.companyId, 'project', this.summary.projectId];
  129. }
  130. /**
  131. * 🆕 检查是否可以导航到项目详情页
  132. */
  133. canNavigateToProject(): boolean {
  134. return !!(this.summary?.projectId && this.companyId);
  135. }
  136. /**
  137. * 🆕 获取阶段显示名称
  138. */
  139. getPhaseLabel(phaseKey: string): string {
  140. const map: Record<string, string> = {
  141. 'modeling': '白模',
  142. 'softDecor': '软装',
  143. 'rendering': '渲染',
  144. 'postProcessing': '后期',
  145. 'whiteModel': '白模' // 兼容性
  146. };
  147. return map[phaseKey] || phaseKey;
  148. }
  149. /**
  150. * 获取指定阶段的已完成空间列表
  151. */
  152. getCompletedSpaces(phaseName: string): any[] {
  153. if (!this.summary || !this.summary.spaces) return [];
  154. const phaseKeyMap: Record<string, string> = {
  155. 'modeling': 'whiteModel',
  156. 'softDecor': 'softDecor',
  157. 'rendering': 'rendering',
  158. 'postProcessing': 'postProcess'
  159. };
  160. const key = phaseKeyMap[phaseName];
  161. if (!key) return [];
  162. return this.summary.spaces.filter(space => {
  163. // @ts-ignore - 动态访问属性
  164. return space.deliverableTypes[key] > 0;
  165. });
  166. }
  167. }