Sfoglia il codice sorgente

Merge branch 'master' of http://git.fmode.cn:3000/nkkj/yss-project

徐福静0235668 1 giorno fa
parent
commit
2054677700

+ 45 - 36
src/app/pages/team-leader/dashboard/dashboard.ts

@@ -378,6 +378,7 @@ export class Dashboard implements OnInit, OnDestroy {
         const deadlineValue = project.get('deadline');
         const deliveryDateValue = project.get('deliveryDate');
         const expectedDeliveryDateValue = project.get('expectedDeliveryDate');
+        const demodayValue = project.get('demoday'); // 🆕 小图对图日期
         
         // 🔧 如果 get() 方法都返回假值,尝试从 createdAt/updatedAt 属性直接获取
         // Parse 对象的 createdAt/updatedAt 是内置属性
@@ -395,6 +396,7 @@ export class Dashboard implements OnInit, OnDestroy {
           status: project.get('status') || '进行中',
           currentStage: project.get('currentStage') || '未知阶段',
           deadline: deadlineValue || deliveryDateValue || expectedDeliveryDateValue,
+          demoday: demodayValue, // 🆕 小图对图日期
           createdAt: finalCreatedAt,
           designerName: profileName
         };
@@ -461,6 +463,7 @@ export class Dashboard implements OnInit, OnDestroy {
         const deadlineValue = project.get('deadline');
         const deliveryDateValue = project.get('deliveryDate');
         const expectedDeliveryDateValue = project.get('expectedDeliveryDate');
+        const demodayValue = project.get('demoday'); // 🆕 小图对图日期
         
         // 🔧 如果 get() 方法都返回假值,尝试从 createdAt/updatedAt 属性直接获取
         let finalCreatedAt = createdAtValue || updatedAtValue;
@@ -477,6 +480,7 @@ export class Dashboard implements OnInit, OnDestroy {
           status: project.get('status') || '进行中',
           currentStage: project.get('currentStage') || '未知阶段',
           deadline: deadlineValue || deliveryDateValue || expectedDeliveryDateValue,
+          demoday: demodayValue, // 🆕 小图对图日期
           createdAt: finalCreatedAt,
           designerName: assigneeName
         };
@@ -535,48 +539,45 @@ export class Dashboard implements OnInit, OnDestroy {
     
     console.log('📊 重新计算项目时间轴数据...');
     
-    // 从 designerWorkloadMap 获取所有组员的项目数据(去重)
-    const projectMap = new Map<string, any>(); // 使用Map去重,key为projectId
+    // 🔧 不去重,保留所有项目-设计师关联关系(一个项目可能有多个设计师)
     const allDesignerProjects: any[] = [];
     
-    // 调试:打印所有的 designerKey
+    // 调试:打印所有的 designerKey 和项目数量
     const allKeys: string[] = [];
+    let totalProjectsInMap = 0;
     this.designerWorkloadMap.forEach((projects, designerKey) => {
-      allKeys.push(designerKey);
+      allKeys.push(`${designerKey}(${projects.length})`);
+      totalProjectsInMap += projects.length;
     });
     console.log('📊 designerWorkloadMap所有key:', allKeys);
+    console.log('📊 designerWorkloadMap 总项目数(含重复,因为一个项目可能有多个设计师):', totalProjectsInMap);
     
     this.designerWorkloadMap.forEach((projects, designerKey) => {
-      // 只处理真实的设计师名称(中文姓名),跳过ID形式的key
-      // 判断条件:
-      // 1. 是字符串
-      // 2. 长度在2-10之间(中文姓名通常2-4个字)
-      // 3. 包含中文字符(最可靠的判断)
-      const isChineseName = typeof designerKey === 'string' 
-        && designerKey.length >= 2 
-        && designerKey.length <= 10
-        && /[\u4e00-\u9fa5]/.test(designerKey); // 包含中文字符
-      
-      if (isChineseName) {
+      // 🔧 改进判断逻辑:跳过明显的 ID 格式(Parse objectId 是10位字母数字组合)
+      // 只要包含中文字符,就认为是设计师名称
+      const isParseId = typeof designerKey === 'string' 
+        && designerKey.length === 10 
+        && /^[a-zA-Z0-9]{10}$/.test(designerKey); // Parse ID 格式:10位字母数字
+      
+      const isDesignerName = !isParseId && typeof designerKey === 'string' && /[\u4e00-\u9fa5]/.test(designerKey);
+      
+      if (isDesignerName) {
         console.log('✅ 使用设计师名称:', designerKey, '项目数:', projects.length);
         projects.forEach(proj => {
-          const projectId = proj.id;
-          // 使用projectId去重
-          if (!projectMap.has(projectId)) {
-            const projectWithDesigner = {
-              ...proj,
-              designerName: designerKey
-            };
-            projectMap.set(projectId, projectWithDesigner);
-            allDesignerProjects.push(projectWithDesigner);
-          }
+          // ✅ 不去重,保留每个设计师-项目的关联
+          const projectWithDesigner = {
+            ...proj,
+            designerName: designerKey // 使用当前的设计师名称
+          };
+          allDesignerProjects.push(projectWithDesigner);
         });
       } else {
-        console.log('⏭️ 跳过key:', designerKey, '(不是中文姓名)');
+        console.log('⏭️ 跳过key:', designerKey, '(Parse ID 或无效格式)', '类型:', typeof designerKey, '长度:', designerKey.length);
       }
     });
     
-    console.log('📊 从designerWorkloadMap转换项目数据:', allDesignerProjects.length, '个项目(已去重)');
+    console.log('📊 从designerWorkloadMap转换项目数据:', allDesignerProjects.length, '个项目-设计师关联');
+    console.log('📊 对比 this.projects 数量:', this.projects?.length || 0, '(不重复的项目数)');
     
     this.projectTimelineData = allDesignerProjects.map((project, index) => {
       const now = new Date();
@@ -591,9 +592,17 @@ export class Dashboard implements OnInit, OnDestroy {
       const projectDuration = 3 + (index % 5); // 3-7天的项目周期
       const adjustedStartDate = new Date(adjustedEndDate.getTime() - projectDuration * 24 * 60 * 60 * 1000);
       
-      // 对图时间:交付前1-2天
-      const reviewDaysBefore = 1 + (index % 2); // 交付前1-2天
-      const adjustedReviewDate = new Date(adjustedEndDate.getTime() - reviewDaysBefore * 24 * 60 * 60 * 1000);
+      // 🆕 小图对图时间:优先使用真实的 demoday,否则默认为交付前1-2天
+      let adjustedReviewDate: Date;
+      if (project.demoday && project.demoday instanceof Date) {
+        // 使用真实的小图对图日期
+        adjustedReviewDate = project.demoday;
+        console.log(`📋 项目 ${project.name} 使用真实小图日期:`, adjustedReviewDate.toLocaleDateString());
+      } else {
+        // 默认计算:交付前1-2天
+        const reviewDaysBefore = 1 + (index % 2);
+        adjustedReviewDate = new Date(adjustedEndDate.getTime() - reviewDaysBefore * 24 * 60 * 60 * 1000);
+      }
       
       // 计算距离交付还有几天
       const daysUntilDeadline = Math.ceil((adjustedEndDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
@@ -733,12 +742,12 @@ export class Dashboard implements OnInit, OnDestroy {
     
     // 调试:打印前3个项目的时间信息
     if (this.projectTimelineData.length > 0) {
-      console.log('📅 示例项目时间:');
-      this.projectTimelineData.slice(0, 3).forEach(p => {
-        console.log(`  - ${p.projectName}:`, {
-          开始: p.startDate.toLocaleDateString(),
-          对图: p.reviewDate.toLocaleDateString(),
-          交付: p.deliveryDate.toLocaleDateString(),
+      console.log('📅 示例项目时间(前5个):');
+      this.projectTimelineData.slice(0, 5).forEach(p => {
+        console.log(`  🎨 ${p.projectName}:`, {
+          开始: p.startDate.toLocaleDateString() + ' ' + p.startDate.toLocaleTimeString(),
+          小图对图: p.reviewDate.toLocaleDateString() + ' ' + p.reviewDate.toLocaleTimeString(),
+          交付: p.deliveryDate.toLocaleDateString() + ' ' + p.deliveryDate.toLocaleTimeString(),
           状态: p.status,
           阶段: p.stageName
         });

+ 1 - 1
src/app/pages/team-leader/project-timeline/project-timeline.html

@@ -144,7 +144,7 @@
           </div>
           <div class="legend-item">
             <span class="legend-icon review-icon">📋</span>
-            <span class="legend-label">对图时间</span>
+            <span class="legend-label">小图对图(灰色=已完成)</span>
           </div>
           <div class="legend-item">
             <span class="legend-icon delivery-icon">📦</span>

+ 1 - 1
src/app/pages/team-leader/project-timeline/project-timeline.scss

@@ -426,7 +426,7 @@
   }
   
   &.review-icon {
-    background: #3b82f6;
+    background: #8b5cf6;
   }
   
   &.delivery-icon {

+ 21 - 5
src/app/pages/team-leader/project-timeline/project-timeline.ts

@@ -330,14 +330,15 @@ export class ProjectTimelineComponent implements OnInit, OnDestroy {
       });
     }
     
-    // 评审事件
-    if (project.reviewDate && this.isEventInFuture(project.reviewDate)) {
+    // 小图对图事件(显示所有小图事件,不受今日线限制)
+    if (project.reviewDate && this.isEventInRange(project.reviewDate)) {
+      const isPast = project.reviewDate.getTime() < this.currentTime.getTime();
       events.push({
         date: project.reviewDate,
-        label: '评审',
+        label: '小图对图',
         type: 'review',
         projectId: project.projectId,
-        color: '#3b82f6',
+        color: isPast ? '#94a3b8' : '#8b5cf6', // 过去的事件显示为灰色
         icon: '📋'
       });
     }
@@ -407,6 +408,7 @@ export class ProjectTimelineComponent implements OnInit, OnDestroy {
   private buildDesignerStats(): DesignerInfo[] {
     const designerMap = new Map<string, DesignerInfo>();
     
+    // 🔧 统计每个设计师负责的项目(不去重,因为项目列表已经包含了所有设计师-项目关联)
     this.projects.forEach(project => {
       const designerName = project.designerName || '未分配';
       
@@ -422,7 +424,7 @@ export class ProjectTimelineComponent implements OnInit, OnDestroy {
       }
       
       const designer = designerMap.get(designerName)!;
-      designer.projectCount++;
+      designer.projectCount++; // 每个项目-设计师关联都计数
       
       if (project.status === 'urgent' || project.status === 'overdue') {
         designer.urgentCount++;
@@ -442,6 +444,8 @@ export class ProjectTimelineComponent implements OnInit, OnDestroy {
       }
     });
     
+    console.log('📊 设计师统计:', Array.from(designerMap.entries()).map(([name, info]) => `${name}: ${info.projectCount}个项目`));
+    
     return Array.from(designerMap.values()).sort((a, b) => b.projectCount - a.projectCount);
   }
 
@@ -450,7 +454,18 @@ export class ProjectTimelineComponent implements OnInit, OnDestroy {
     
     // 设计师筛选
     if (this.selectedDesigner !== 'all') {
+      // 选择单个设计师:显示该设计师的所有项目
       result = result.filter(p => p.designerName === this.selectedDesigner);
+    } else {
+      // 🔧 全部设计师:对项目去重(一个项目可能有多个设计师)
+      const projectMap = new Map<string, ProjectTimeline>();
+      result.forEach(p => {
+        if (!projectMap.has(p.projectId)) {
+          projectMap.set(p.projectId, p);
+        }
+      });
+      result = Array.from(projectMap.values());
+      console.log('📊 全部设计师视图 - 去重后项目数:', result.length);
     }
     
     // 状态筛选
@@ -481,6 +496,7 @@ export class ProjectTimelineComponent implements OnInit, OnDestroy {
   selectDesigner(designerId: string): void {
     this.selectedDesigner = designerId;
     this.applyFilters();
+    this.cdr.markForCheck(); // 触发变更检测
   }
 
   toggleViewMode(mode: 'timeline' | 'list'): void {