Kaynağa Gözat

```
refactor: redesign employee detail panel with modern card-based layout

- Replaced traditional header with avatar placeholder and user role display
- Reorganized overview section into grid layout with workload and capability cards
- Enhanced workload card with larger metrics, mini project list, and status badges
- Added capability card with skill tags cloud and mini stats (weekly capacity, urgent orders)
- Simplified leave records to compact alert banner instead of full table
- Moved full survey

0235711 21 saat önce
ebeveyn
işleme
3a8cd9ca4f

+ 123 - 295
src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.html

@@ -4,13 +4,15 @@
     <div class="employee-detail-panel" (click)="stopPropagation($event)">
       <!-- 面板头部 -->
       <div class="panel-header">
-        <h3 class="panel-title">
-          <svg class="icon-user" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-            <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
-            <circle cx="12" cy="7" r="4"></circle>
-          </svg>
-          {{ currentEmployeeDetail.name }} 详情
-        </h3>
+        <div class="header-info">
+          <div class="avatar-placeholder">
+            {{ currentEmployeeDetail.name.charAt(0) }}
+          </div>
+          <div class="user-info">
+            <h3 class="user-name">{{ currentEmployeeDetail.name }}</h3>
+            <span class="user-role">设计师</span>
+          </div>
+        </div>
         <button class="btn-close" (click)="onClose()">
           <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
             <line x1="18" y1="6" x2="6" y2="18"></line>
@@ -21,56 +23,86 @@
 
       <!-- 面板内容 -->
       <div class="panel-content">
-        <!-- 负载概况栏 -->
-        <div class="section workload-section">
-          <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
-              <line x1="9" y1="9" x2="15" y2="9"></line>
-              <line x1="9" y1="15" x2="15" y2="15"></line>
-            </svg>
-            <h4>负载概况</h4>
-          </div>
-          <div class="workload-info">
-            <div class="workload-stat">
-              <span class="stat-label">当前负责项目数:</span>
-              <span class="stat-value" [class]="currentEmployeeDetail.currentProjects >= 3 ? 'high-workload' : 'normal-workload'">
-                {{ currentEmployeeDetail.currentProjects }} 个
+        <!-- 概览区域 (Grid Layout) -->
+        <div class="overview-grid">
+          
+          <!-- 左侧:负载概况 -->
+          <div class="card workload-card">
+            <div class="card-header">
+              <h4>近期负载</h4>
+              <span class="status-badge" [style.background-color]="workloadStatus.color + '20'" [style.color]="workloadStatus.color">
+                {{ workloadStatus.label }}
               </span>
             </div>
-            @if (currentEmployeeDetail.projectData.length > 0) {
-              <div class="project-list">
-                <span class="project-label">核心项目:</span>
-                <div class="project-tags">
-                  @for (project of currentEmployeeDetail.projectData; track project.id) {
-                    <span class="project-tag clickable" 
-                          (click)="onProjectClick(project.id)"
-                          title="点击查看项目详情">
-                      {{ project.name }}
-                      <svg class="icon-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                        <path d="M7 17L17 7M17 7H7M17 7V17"/>
-                      </svg>
-                    </span>
-                  }
-                  @if (currentEmployeeDetail.currentProjects > currentEmployeeDetail.projectData.length) {
-                    <span class="project-tag more">+{{ currentEmployeeDetail.currentProjects - currentEmployeeDetail.projectData.length }}</span>
-                  }
-                </div>
+            <div class="workload-metrics">
+              <div class="metric-big">
+                <span class="number">{{ currentEmployeeDetail.currentProjects }}</span>
+                <span class="label">当前项目</span>
+              </div>
+              <div class="project-preview">
+                <span class="sub-label">核心项目:</span>
+                @if (currentEmployeeDetail.projectData.length > 0) {
+                  <div class="mini-project-list">
+                    @for (project of currentEmployeeDetail.projectData; track project.id) {
+                      <div class="mini-project-item" (click)="onProjectClick(project.id)" title="{{ project.name }}">
+                        <span class="dot"></span>
+                        <span class="name">{{ project.name }}</span>
+                      </div>
+                    }
+                  </div>
+                } @else {
+                  <span class="empty-text">暂无活跃项目</span>
+                }
+              </div>
+            </div>
+          </div>
+
+          <!-- 右侧:能力画像 -->
+          <div class="card capability-card">
+            <div class="card-header">
+              <h4>能力标签</h4>
+              <button class="btn-text" (click)="toggleSurveyDisplay()">详情 &gt;</button>
+            </div>
+            
+            @if (currentEmployeeDetail.surveyCompleted) {
+              <div class="tags-cloud">
+                @for (tag of strengthTags; track tag) {
+                  <span class="skill-tag">{{ tag }}</span>
+                }
+                @if (strengthTags.length === 0) {
+                  <span class="empty-text">暂无标签数据</span>
+                }
+              </div>
+              @if (currentEmployeeDetail.surveyData?.answers; as answers) {
+                 @if (getCapabilitySummary(answers); as summary) {
+                    <div class="mini-stats">
+                      <div class="stat-item">
+                        <span class="label">周承接:</span>
+                        <span class="val">{{ summary.capacity }}</span>
+                      </div>
+                      <div class="stat-item">
+                        <span class="label">接急单:</span>
+                        <span class="val">{{ summary.urgent }}</span>
+                      </div>
+                    </div>
+                 }
+              }
+            } @else {
+              <div class="empty-state">
+                <span>尚未完成能力问卷</span>
+                <button class="btn-refresh" (click)="onRefreshSurvey()" [disabled]="refreshingSurvey">
+                  <svg viewBox="0 0 24 24" width="14" height="14" [class.rotating]="refreshingSurvey"><path d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" fill="currentColor"/></svg>
+                  刷新
+                </button>
               </div>
             }
           </div>
         </div>
 
-        <!-- 负载详细日历 -->
+        <!-- 日历区域 -->
         <div class="section calendar-section">
           <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
-              <line x1="16" y1="2" x2="16" y2="6"></line>
-              <line x1="8" y1="2" x2="8" y2="6"></line>
-              <line x1="3" y1="10" x2="21" y2="10"></line>
-            </svg>
-            <h4>负载详细日历</h4>
+            <h4>项目日历分布</h4>
             <button class="btn-view-designer-calendar" (click)="openDesignerCalendar()" title="查看详细日历">
               📅 详细日历
             </button>
@@ -80,42 +112,23 @@
             <div class="employee-calendar">
               <!-- 月份标题 -->
               <div class="calendar-month-header">
-                <button class="btn-prev-month" 
-                        (click)="onChangeMonth(-1)"
-                        title="上月">
-                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                    <polyline points="15 18 9 12 15 6"></polyline>
-                  </svg>
+                <button class="btn-prev-month" (click)="onChangeMonth(-1)" title="上月">
+                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"></polyline></svg>
                 </button>
-                <span class="month-title">
-                  {{ currentEmployeeDetail.calendarData.currentMonth | date:'yyyy年M月' }}
-                </span>
-                <button class="btn-next-month" 
-                        (click)="onChangeMonth(1)"
-                        title="下月">
-                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                    <polyline points="9 18 15 12 9 6"></polyline>
-                  </svg>
+                <span class="month-title">{{ currentEmployeeDetail.calendarData.currentMonth | date:'yyyy年M月' }}</span>
+                <button class="btn-next-month" (click)="onChangeMonth(1)" title="下月">
+                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"></polyline></svg>
                 </button>
               </div>
-              
-              <!-- 星期标题 -->
+
               <div class="calendar-weekdays">
-                <div class="weekday">日</div>
-                <div class="weekday">一</div>
-                <div class="weekday">二</div>
-                <div class="weekday">三</div>
-                <div class="weekday">四</div>
-                <div class="weekday">五</div>
-                <div class="weekday">六</div>
+                <div class="weekday">日</div><div class="weekday">一</div><div class="weekday">二</div><div class="weekday">三</div><div class="weekday">四</div><div class="weekday">五</div><div class="weekday">六</div>
               </div>
-              
-              <!-- 日历网格 -->
               <div class="calendar-grid">
                 @for (day of currentEmployeeDetail.calendarData.days; track day.date.getTime()) {
                   <div class="calendar-day"
-                       [class.today]="day.isToday"
                        [class.other-month]="!day.isCurrentMonth"
+                       [class.today]="day.isToday"
                        [class.has-projects]="day.projectCount > 0"
                        [class.high-load]="day.projectCount >= 2"
                        [class.clickable]="day.projectCount > 0 && day.isCurrentMonth"
@@ -148,215 +161,38 @@
             </div>
           }
         </div>
-
-        <!-- 请假明细栏 -->
-        <div class="section leave-section">
-          <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
-              <line x1="16" y1="2" x2="16" y2="6"></line>
-              <line x1="8" y1="2" x2="8" y2="6"></line>
-              <line x1="3" y1="10" x2="21" y2="10"></line>
-            </svg>
-            <h4>请假明细(未来7天)</h4>
-          </div>
-          <div class="leave-table">
-            @if (currentEmployeeDetail.leaveRecords.length > 0) {
-              <table>
-                <thead>
-                  <tr>
-                    <th>日期</th>
-                    <th>状态</th>
-                    <th>备注</th>
-                  </tr>
-                </thead>
-                <tbody>
-                  @for (record of currentEmployeeDetail.leaveRecords; track record.id) {
-                    <tr [class]="record.isLeave ? 'leave-day' : 'work-day'">
-                      <td>{{ record.date | date:'M月d日' }}</td>
-                      <td>
-                        <span class="status-badge" [class]="record.isLeave ? 'leave' : 'work'">
-                          {{ record.isLeave ? '请假' : '正常' }}
-                        </span>
-                      </td>
-                      <td>{{ record.isLeave ? getLeaveTypeText(record.leaveType) : '-' }}</td>
-                    </tr>
-                  }
-                </tbody>
-              </table>
-            } @else {
-              <div class="no-leave">
-                <svg class="no-data-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                  <circle cx="12" cy="12" r="10"></circle>
-                  <path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
-                  <line x1="9" y1="9" x2="9.01" y2="9"></line>
-                  <line x1="15" y1="9" x2="15.01" y2="9"></line>
-                </svg>
-                <p>未来7天无请假安排</p>
-              </div>
-            }
+        
+        <!-- 请假区域 (折叠/简化) -->
+        @if (currentEmployeeDetail.leaveRecords.length > 0) {
+          <div class="leave-simple-alert">
+            <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
+            <span>未来7天有 <strong>{{ currentEmployeeDetail.leaveRecords.length }}</strong> 条请假记录</span>
           </div>
-        </div>
+        }
 
-        <!-- 红色标记说明 -->
-        <div class="section explanation-section">
-          <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <circle cx="12" cy="12" r="10"></circle>
-              <line x1="12" y1="8" x2="12" y2="12"></line>
-              <line x1="12" y1="16" x2="12.01" y2="16"></line>
-            </svg>
-            <h4>红色标记说明</h4>
-          </div>
-          <div class="explanation-content">
-            <p class="explanation-text">{{ currentEmployeeDetail.redMarkExplanation }}</p>
-          </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- 问卷详情侧边栏/弹窗 -->
+  @if (showFullSurvey && currentEmployeeDetail.surveyData) {
+    <div class="survey-drawer-overlay" (click)="toggleSurveyDisplay()">
+      <div class="survey-drawer" (click)="stopPropagation($event)">
+        <div class="drawer-header">
+          <h3>能力问卷详情</h3>
+          <button class="btn-close-text" (click)="toggleSurveyDisplay()">关闭</button>
         </div>
-        
-        <!-- 能力问卷 -->
-        <div class="section survey-section">
-          <div class="section-header">
-            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <path d="M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3"/>
-            </svg>
-            <h4>能力问卷</h4>
-            <button 
-              class="btn-refresh-survey" 
-              (click)="onRefreshSurvey()"
-              [disabled]="refreshingSurvey"
-              title="刷新问卷状态">
-              <svg viewBox="0 0 24 24" width="16" height="16" [class.rotating]="refreshingSurvey">
-                <path fill="currentColor" d="M17.65 6.35A7.958 7.958 0 0 0 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0 1 12 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
-              </svg>
-            </button>
-          </div>
-          
-          @if (currentEmployeeDetail.surveyCompleted && currentEmployeeDetail.surveyData) {
-            <div class="survey-content">
-              <div class="survey-status completed">
-                <svg viewBox="0 0 24 24" width="20" height="20" fill="#34c759">
-                  <path d="M9,20.42L2.79,14.21L5.62,11.38L9,14.77L18.88,4.88L21.71,7.71L9,20.42Z"/>
-                </svg>
-                <span>已完成问卷</span>
-                <span class="survey-time">
-                  {{ currentEmployeeDetail.surveyData.createdAt | date:'yyyy-MM-dd HH:mm' }}
-                </span>
+        <div class="drawer-content">
+           @for (answer of currentEmployeeDetail.surveyData.answers; track $index) {
+              <div class="qa-item">
+                <div class="q-text">Q{{$index + 1}}: {{ answer.question }}</div>
+                <div class="a-text">{{ answer.answer || '未填写' }}</div>
               </div>
-              
-              <!-- 能力画像摘要 -->
-              @if (!showFullSurvey) {
-                <div class="capability-summary">
-                  <h5>您的能力画像</h5>
-                  @if (getCapabilitySummary(currentEmployeeDetail.surveyData.answers); as summary) {
-                    <div class="summary-grid">
-                      <div class="summary-item">
-                        <span class="label">擅长风格:</span>
-                        <span class="value">{{ summary.styles }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">擅长空间:</span>
-                        <span class="value">{{ summary.spaces }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">技术优势:</span>
-                        <span class="value">{{ summary.advantages }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">项目难度:</span>
-                        <span class="value">{{ summary.difficulty }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">周承接量:</span>
-                        <span class="value">{{ summary.capacity }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">紧急订单:</span>
-                        <span class="value">
-                          {{ summary.urgent }}
-                          @if (summary.urgentLimit) {
-                            <span class="limit-hint">(每月不超过{{summary.urgentLimit}}次)</span>
-                          }
-                        </span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">进度同步:</span>
-                        <span class="value">{{ summary.feedback }}</span>
-                      </div>
-                      <div class="summary-item">
-                        <span class="label">沟通方式:</span>
-                        <span class="value">{{ summary.communication }}</span>
-                      </div>
-                    </div>
-                  }
-                  
-                  <button class="btn-view-full" (click)="toggleSurveyDisplay()">
-                    <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
-                      <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
-                    </svg>
-                    查看完整问卷(共 {{ currentEmployeeDetail.surveyData.answers.length }} 道题)
-                  </button>
-                </div>
-              }
-              
-              <!-- 完整问卷答案 -->
-              @if (showFullSurvey) {
-                <div class="survey-answers">
-                  <h5>完整问卷答案(共 {{ currentEmployeeDetail.surveyData.answers.length }} 道题):</h5>
-                  @for (answer of currentEmployeeDetail.surveyData.answers; track $index) {
-                    <div class="answer-item">
-                      <div class="question-text">
-                        <strong>Q{{$index + 1}}:</strong> {{ answer.question }}
-                      </div>
-                      <div class="answer-text">
-                        @if (!answer.answer) {
-                          <span class="answer-tag empty">未填写(选填)</span>
-                        } @else if (answer.type === 'single' || answer.type === 'text' || answer.type === 'textarea' || answer.type === 'number') {
-                          <span class="answer-tag single">{{ answer.answer }}</span>
-                        } @else if (answer.type === 'multiple') {
-                          @if (Array.isArray(answer.answer)) {
-                            @for (opt of answer.answer; track opt) {
-                              <span class="answer-tag multiple">{{ opt }}</span>
-                            }
-                          } @else {
-                            <span class="answer-tag single">{{ answer.answer }}</span>
-                          }
-                        } @else if (answer.type === 'scale') {
-                          <div class="answer-scale">
-                            <div class="scale-bar">
-                              <div class="scale-fill" [style.width.%]="(answer.answer / 10) * 100">
-                                <span>{{ answer.answer }} / 10</span>
-                              </div>
-                            </div>
-                          </div>
-                        } @else {
-                          <span class="answer-tag single">{{ answer.answer }}</span>
-                        }
-                      </div>
-                    </div>
-                  }
-                  
-                  <button class="btn-collapse" (click)="toggleSurveyDisplay()">
-                    <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
-                      <path d="M19 13H5v-2h14v2z"/>
-                    </svg>
-                    收起详情
-                  </button>
-                </div>
-              }
-            </div>
-          } @else {
-            <div class="survey-empty">
-              <svg class="no-data-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                <circle cx="12" cy="12" r="10"></circle>
-                <path d="M8 12h8M12 8v8"/>
-              </svg>
-              <p>该员工尚未完成能力问卷</p>
-            </div>
-          }
+           }
         </div>
       </div>
     </div>
-  </div>
+  }
 }
 
 <!-- 日历项目列表弹窗 -->
@@ -369,7 +205,7 @@
             <path d="M9 11l3 3L22 4"></path>
             <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
           </svg>
-          {{ selectedDate | date:'M月d日' }} 项目
+          {{ selectedDate | date:'M月d日' }} 项目列表
         </h3>
         <button class="btn-close" (click)="closeCalendarProjectList()">
           <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -388,15 +224,11 @@
           @for (project of selectedDayProjects; track project.id) {
             <div class="project-item">
               <div class="project-info" (click)="onProjectClick(project.id); closeCalendarProjectList()">
-                <svg class="project-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                  <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
-                  <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
-                </svg>
                 <div class="project-details">
                   <h4 class="project-name">{{ project.name }}</h4>
                   @if (project.deadline) {
                     <p class="project-deadline">
-                      截止日期: {{ project.deadline | date:'yyyy-MM-dd' }}
+                      截止: {{ project.deadline | date:'yyyy-MM-dd' }}
                     </p>
                   }
                 </div>
@@ -408,9 +240,11 @@
                   </svg>
                   <span>进度</span>
                 </button>
-                <svg class="arrow-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" (click)="onProjectClick(project.id); closeCalendarProjectList()">
-                  <path d="M5 12h14M12 5l7 7-7 7"/>
-                </svg>
+                <button class="btn-arrow" (click)="onProjectClick(project.id); closeCalendarProjectList()">
+                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                    <path d="M9 18l6-6-6-6"/>
+                  </svg>
+                </button>
               </div>
             </div>
           }
@@ -420,18 +254,12 @@
   </div>
 }
 
-<!-- 设计师详细日历(复用订单分配页组件) -->
+<!-- 设计师详细日历 -->
 @if (showDesignerCalendar) {
   <div class="calendar-project-modal-overlay" (click)="closeDesignerCalendar()">
-    <div class="calendar-project-modal" (click)="stopPropagation($event)">
+    <div class="calendar-project-modal full-modal" (click)="stopPropagation($event)">
       <div class="modal-header">
-        <h3>
-          <svg class="header-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-            <path d="M9 11l3 3L22 4"></path>
-            <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
-          </svg>
-          设计师工作日历
-        </h3>
+        <h3>设计师工作日历</h3>
         <button class="btn-close" (click)="closeDesignerCalendar()">
           <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
             <line x1="18" y1="6" x2="6" y2="18"></line>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 508 - 696
src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.scss


+ 45 - 8
src/app/pages/team-leader/employee-detail-panel/employee-detail-panel.ts

@@ -81,6 +81,40 @@ export class EmployeeDetailPanelComponent implements OnInit, OnChanges {
   showFullSurvey: boolean = false;
   refreshingSurvey: boolean = false;
 
+  // 获取负载状态
+  get workloadStatus(): { label: string; class: string; color: string } {
+    const count = this.currentEmployeeDetail?.currentProjects || 0;
+    if (count >= 3) {
+      return { label: '高负载', class: 'high', color: '#ef4444' }; // red
+    } else if (count >= 1) {
+      return { label: '正常', class: 'normal', color: '#3b82f6' }; // blue
+    }
+    return { label: '空闲', class: 'low', color: '#10b981' }; // green
+  }
+
+  // 获取能力标签
+  get strengthTags(): string[] {
+    if (!this.currentEmployeeDetail?.surveyData?.answers) return [];
+    
+    const summary = this.getCapabilitySummary(this.currentEmployeeDetail.surveyData.answers);
+    const tags: string[] = [];
+    
+    // 解析风格
+    if (summary.styles && summary.styles !== '未填写') {
+      tags.push(...summary.styles.split('、').slice(0, 3));
+    }
+    // 解析空间
+    if (summary.spaces && summary.spaces !== '未填写') {
+      tags.push(...summary.spaces.split('、').slice(0, 2));
+    }
+    // 技术优势
+    if (summary.advantages && summary.advantages !== '未填写') {
+      tags.push(...summary.advantages.split('、').slice(0, 2));
+    }
+    
+    return tags.slice(0, 6); // 最多显示6个标签
+  }
+
   // 获取当前显示的 employeeDetail(优先使用 Input,否则使用内部生成的)
   get currentEmployeeDetail(): EmployeeDetail | null {
     return this.employeeDetail || this.internalEmployeeDetail;
@@ -137,10 +171,13 @@ export class EmployeeDetailPanelComponent implements OnInit, OnChanges {
     if (!this.employeeName) return;
 
     const employeeName = this.employeeName;
-    const currentProjects = this.projects.length;
     
-    // 保存完整的项目数据(最多显示3个)
-    const projectData = this.projects.slice(0, 3).map(p => ({
+    // 过滤出当前活跃的项目(非已完成/已交付)用于显示"当前项目数"
+    const activeProjects = this.projects.filter(p => p.status !== '已完成' && p.status !== '已交付');
+    const currentProjects = activeProjects.length;
+    
+    // 保存完整的项目数据(最多显示3个活跃项目)
+    const projectData = activeProjects.slice(0, 3).map(p => ({
       id: p.id,
       name: p.name
     }));
@@ -162,7 +199,7 @@ export class EmployeeDetailPanelComponent implements OnInit, OnChanges {
     // 生成红色标记说明
     const redMarkExplanation = this.generateRedMarkExplanation(employeeName, employeeLeaveRecords, currentProjects);
     
-    // 生成日历数据
+    // 生成日历数据 (传入所有项目以显示历史负载)
     const calendarData = this.generateEmployeeCalendar(employeeName, this.projects);
     
     // 构建基础对象
@@ -257,10 +294,10 @@ export class EmployeeDetailPanelComponent implements OnInit, OnChanges {
       
       // 找出该日期相关的项目(项目进行中且在当天范围内)
       const dayProjects = employeeProjects.filter(p => {
-        // 1. 过滤已完成/已交付的项目
-        if (p.status === '已完成' || p.status === '已交付') {
-          return false;
-        }
+        // 移除对已完成项目的过滤,以便在日历中显示历史负载
+        // if (p.status === '已完成' || p.status === '已交付') {
+        //   return false;
+        // }
 
         const projectData = p.data || {};
 

+ 9 - 0
src/app/pages/team-leader/services/urgent-event.service.ts

@@ -167,6 +167,13 @@ export class UrgentEventService {
             rendering: '渲染',
             postProcessing: '后期'
           };
+
+          const phaseTypeMap: Record<string, 'modeling' | 'soft_fitting' | 'rendering' | 'post_processing'> = {
+            modeling: 'modeling',
+            softDecor: 'soft_fitting',
+            rendering: 'rendering',
+            postProcessing: 'post_processing'
+          };
           
           Object.entries(project.phaseDeadlines).forEach(([key, phaseInfo]: [string, any]) => {
             if (phaseInfo && phaseInfo.deadline) {
@@ -178,6 +185,7 @@ export class UrgentEventService {
               // 如果阶段已经到期或即将到期(1天内),且状态不是已完成
               if (daysDiff <= 1 && phaseInfo.status !== 'completed') {
                 const phaseName = phaseMap[key as keyof typeof phaseMap] || key;
+                const phaseType = phaseTypeMap[key];
                 
                 // 获取该阶段的完成率
                 const summary = project.spaceDeliverableSummary;
@@ -196,6 +204,7 @@ export class UrgentEventService {
                   description: `项目「${project.projectName}」的${phaseName}阶段截止时间已${daysDiff < 0 ? '逾期' : '临近'}(完成率 ${completionRate}%)${descSuffix}`,
                   eventType: 'phase_deadline',
                   phaseName,
+                  phaseType,
                   deadline,
                   projectId: project.projectId,
                   projectName: project.projectName,

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor