徐福静0235668 22 小時之前
父節點
當前提交
c8f2b3748c

+ 19 - 6
src/app/pages/customer-service/dashboard/dashboard.html

@@ -1,7 +1,20 @@
 <!-- 欢迎区域 -->
 <section class="welcome-section">
-  <h2>您好,客服小李 👋</h2>
-  <p>今天是 {{ currentDate.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' }) }},祝您工作顺利!</p>
+  <div class="welcome-header">
+    <div>
+      <h2>您好,客服小李 👋</h2>
+      <p>今天是 {{ currentDate.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' }) }},祝您工作顺利!</p>
+    </div>
+    <button class="attendance-view-btn" (click)="viewAttendance()" title="查看人员考勤">
+      <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+        <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>
+      查看考勤
+    </button>
+  </div>
 </section>
 
 <!-- 数据看板 -->
@@ -121,7 +134,7 @@
       </div>
       <div class="crm-list">
         @for (c of newReachOutCustomers(); track c.name) {
-        <div class="crm-item" (click)="navigateToConsultation(c.name)">
+        <div class="crm-item">
           <div class="crm-item-main">
             <div class="avatar small">{{ c.name.charAt(0) }}</div>
             <div class="info">
@@ -139,7 +152,7 @@
               </div>
             </div>
           </div>
-          <button class="ios-btn mini">触达</button>
+          <button class="ios-btn mini" (click)="goToConsultationList()">触达</button>
         </div>
         }
         @if (newReachOutCustomers().length === 0) {
@@ -168,7 +181,7 @@
       </div>
       <div class="crm-list">
         @for (c of oldCustomerFollowUps(); track c.name) {
-        <div class="crm-item" (click)="navigateToConsultation(c.name)">
+        <div class="crm-item">
           <div class="crm-item-main">
             <div class="avatar small alt">{{ c.name.charAt(0) }}</div>
             <div class="info">
@@ -186,7 +199,7 @@
               </div>
             </div>
           </div>
-          <button class="ios-btn mini outline">回访</button>
+          <button class="ios-btn mini outline" (click)="goToConsultationList()">回访</button>
         </div>
         }
         @if (oldCustomerFollowUps().length === 0) {

+ 321 - 82
src/app/pages/customer-service/dashboard/dashboard.scss

@@ -483,18 +483,25 @@ $ios-radius-xl: 22px;
   }
 }
 
-/* 数据看板 */
+/* 数据看板 - iOS风格 */
 .stats-dashboard {
-  background-color: $card-background;
-  border-radius: $border-radius;
-  padding: 24px;
-  box-shadow: $shadow-md;
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 248, 248, 0.95));
+  border-radius: 24px;
+  padding: 28px;
+  box-shadow: 
+    0 8px 32px rgba(0, 0, 0, 0.08),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  backdrop-filter: blur(10px);
+  border: 1px solid rgba(255, 255, 255, 0.2);
   margin-bottom: 24px;
-  transition: $transition;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 }
 
 .stats-dashboard:hover {
-  box-shadow: $shadow-lg;
+  box-shadow: 
+    0 12px 40px rgba(0, 0, 0, 0.12),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  transform: translateY(-2px);
 }
 
 .stats-header {
@@ -518,62 +525,80 @@ $ios-radius-xl: 22px;
   margin-bottom: 20px;
 }
 
+/* 统计卡片 - iOS风格 */
 .stat-card {
-  background-color: $card-background;
-  border: 1px solid $border-color;
-  border-radius: $border-radius;
-  padding: 20px;
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(248, 248, 248, 0.9));
+  border: 1px solid rgba(255, 255, 255, 0.3);
+  border-radius: 20px;
+  padding: 24px;
   text-align: center;
-  transition: $transition;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
   cursor: pointer;
+  backdrop-filter: blur(10px);
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
 }
 
 .stat-card:hover {
-  border-color: $primary-color;
-  box-shadow: 0 4px 12px color-mix(in srgb, $primary-color 10%, transparent);
-  transform: translateY(-2px);
+  border-color: rgba($primary-color, 0.3);
+  box-shadow: 
+    0 8px 32px rgba($primary-color, 0.15),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  transform: translateY(-4px);
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(252, 252, 252, 0.95));
 }
 
 .stat-icon {
-  width: 48px;
-  height: 48px;
-  background-color: color-mix(in srgb, $primary-color 15%, transparent);
-  border-radius: 12px;
+  width: 56px;
+  height: 56px;
+  background: linear-gradient(135deg, rgba($primary-color, 0.1), rgba($primary-color, 0.15));
+  border-radius: 16px;
   display: flex;
   align-items: center;
   justify-content: center;
-  margin: 0 auto 12px;
+  margin: 0 auto 16px;
   color: $primary-color;
-  transition: $transition;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  backdrop-filter: blur(4px);
+  border: 1px solid rgba($primary-color, 0.1);
 }
 
 .stat-card:nth-child(2) .stat-icon {
-  background-color: color-mix(in srgb, $success-color 15%, transparent);
+  background: linear-gradient(135deg, rgba($success-color, 0.1), rgba($success-color, 0.15));
   color: $success-color;
+  border: 1px solid rgba($success-color, 0.1);
 }
 
 .stat-card:nth-child(3) .stat-icon {
-  background-color: color-mix(in srgb, $warning-color 15%, transparent);
+  background: linear-gradient(135deg, rgba($warning-color, 0.1), rgba($warning-color, 0.15));
   color: $warning-color;
+  border: 1px solid rgba($warning-color, 0.1);
 }
 
 .stat-card:nth-child(4) .stat-icon {
-  background-color: color-mix(in srgb, $danger-color 15%, transparent);
+  background: linear-gradient(135deg, rgba($danger-color, 0.1), rgba($danger-color, 0.15));
   color: $danger-color;
+  border: 1px solid rgba($danger-color, 0.1);
 }
 
 .stat-number {
-  font-size: 24px;
+  font-size: 28px;
   font-weight: 700;
   color: $text-primary-dark;
-  margin-bottom: 6px;
+  margin-bottom: 8px;
   line-height: 1.2;
+  letter-spacing: -0.5px;
+  background: linear-gradient(135deg, $text-primary-dark, #b8a99a);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  background-clip: text;
 }
 
 .stat-label {
-  font-size: 14px;
+  font-size: 15px;
   color: $text-secondary-dark;
   margin: 0;
+  font-weight: 500;
+  letter-spacing: -0.2px;
 }
 
 /* 内容网格 */
@@ -584,17 +609,24 @@ $ios-radius-xl: 22px;
   margin-top: 16px;
 }
 
-/* 任务列表区块 */
+/* 任务列表区块 - iOS风格 */
 .tasks-section {
-  background-color: $card-background;
-  border-radius: $border-radius;
-  padding: 24px;
-  box-shadow: $shadow-md;
-  transition: $transition;
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 248, 248, 0.95));
+  border-radius: 24px;
+  padding: 28px;
+  box-shadow: 
+    0 8px 32px rgba(0, 0, 0, 0.08),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  backdrop-filter: blur(10px);
+  border: 1px solid rgba(255, 255, 255, 0.2);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 }
 
 .tasks-section:hover {
-  box-shadow: $shadow-lg;
+  box-shadow: 
+    0 12px 40px rgba(0, 0, 0, 0.12),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  transform: translateY(-2px);
 }
 
 /* 通用区块头部 */
@@ -666,16 +698,19 @@ $ios-radius-xl: 22px;
   margin: 0;
 }
 
-/* 任务项目样式 */
+/* 任务项目样式 - iOS风格 */
 .task-item {
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 16px 20px;
-  border-radius: $border-radius;
-  transition: $transition;
+  padding: 20px 24px;
+  border-radius: 16px;
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
   margin-bottom: 12px;
   position: relative;
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(248, 248, 248, 0.9));
+  border: 1px solid rgba(0, 0, 0, 0.05);
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
 }
 
 .task-item.completed {
@@ -689,7 +724,10 @@ $ios-radius-xl: 22px;
 }
 
 .task-item:hover {
-  transform: translateY(-1px);
+  transform: translateY(-3px);
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(252, 252, 252, 0.95));
+  border-color: rgba(0, 0, 0, 0.1);
 }
 
 /* 任务复选框样式 */
@@ -913,17 +951,24 @@ $ios-radius-xl: 22px;
   box-shadow: 0 0 0 3px color-mix(in srgb, $primary-color 10%, transparent);
 }
 
-/* 项目动态流 */
+/* 项目动态流 - iOS风格 */
 .project-updates-section {
-  background-color: $card-background;
-  border-radius: $border-radius;
-  padding: 24px;
-  box-shadow: $shadow-md;
-  transition: $transition;
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 248, 248, 0.95));
+  border-radius: 24px;
+  padding: 28px;
+  box-shadow: 
+    0 8px 32px rgba(0, 0, 0, 0.08),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  backdrop-filter: blur(10px);
+  border: 1px solid rgba(255, 255, 255, 0.2);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 }
 
 .project-updates-section:hover {
-  box-shadow: $shadow-lg;
+  box-shadow: 
+    0 12px 40px rgba(0, 0, 0, 0.12),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  transform: translateY(-2px);
 }
 
 .project-updates-section.empty {
@@ -1039,26 +1084,34 @@ $ios-radius-xl: 22px;
     grid-template-columns: repeat(2, 1fr);
   }
 
-/* 欢迎区域 */
+/* 欢迎区域 - iOS风格 */
 .welcome-section {
-  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-  color: white;
-  padding: 24px 32px;
-  border-radius: $border-radius;
+  background: linear-gradient(135deg, #c7d3d9, #d4c5b9);
+  color: #4a5568;
+  padding: 28px 36px;
+  border-radius: 24px;
   margin-bottom: 24px;
-  box-shadow: $shadow-lg;
+  box-shadow: 
+    0 8px 32px rgba(0, 0, 0, 0.1),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  backdrop-filter: blur(10px);
+  border: 1px solid rgba(255, 255, 255, 0.2);
 }
 
 .welcome-section h2 {
-  font-size: 24px;
+  font-size: 26px;
   font-weight: 700;
-  margin: 0 0 6px 0;
+  margin: 0 0 8px 0;
+  letter-spacing: -0.5px;
+  color: #2d3748;
 }
 
 .welcome-section p {
-  font-size: 14px;
-  opacity: 0.9;
+  font-size: 15px;
+  opacity: 0.8;
   margin: 0;
+  font-weight: 500;
+  color: #4a5568;
 }
 
 @media (max-width: 768px) {
@@ -1174,6 +1227,105 @@ $ios-radius-xl: 22px;
   }
 }
 
+/* 莫兰迪色系变量 */
+$morandi-cream: #f5f1eb;
+$morandi-sage: #a8b5a0;
+$morandi-blush: #e8d5d2;
+$morandi-stone: #d4c5b9;
+$morandi-mist: #c7d3d9;
+$morandi-dust: #b8a99a;
+
+/* iOS风格卡片 - 莫兰迪色系 */
+.ios-card {
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(248, 248, 248, 0.9));
+  backdrop-filter: blur(10px);
+  border: 1px solid rgba(255, 255, 255, 0.2);
+  border-radius: 20px;
+  box-shadow: 
+    0 8px 32px rgba(0, 0, 0, 0.1),
+    inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  overflow: hidden;
+  
+  &:hover {
+    transform: translateY(-4px);
+    box-shadow: 
+      0 12px 40px rgba(0, 0, 0, 0.15),
+      inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  }
+  
+  &:active {
+    transform: translateY(-1px);
+    box-shadow: 
+      0 4px 20px rgba(0, 0, 0, 0.1),
+      inset 0 1px 0 rgba(255, 255, 255, 0.6);
+  }
+}
+
+/* iOS风格按钮 */
+.ios-btn {
+  background: linear-gradient(135deg, $primary-color, $primary-dark);
+  border: none;
+  border-radius: 16px;
+  color: white;
+  font-weight: 600;
+  font-size: 16px;
+  padding: 12px 24px;
+  cursor: pointer;
+  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+  box-shadow: 
+    0 4px 12px rgba($primary-color, 0.3),
+    inset 0 1px 0 rgba(255, 255, 255, 0.2);
+  position: relative;
+  overflow: hidden;
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 
+      0 6px 20px rgba($primary-color, 0.4),
+      inset 0 1px 0 rgba(255, 255, 255, 0.2);
+  }
+  
+  &:active {
+    transform: translateY(0);
+    box-shadow: 
+      0 2px 8px rgba($primary-color, 0.3),
+      inset 0 1px 0 rgba(255, 255, 255, 0.2);
+  }
+  
+  &.mini {
+    padding: 8px 16px;
+    font-size: 14px;
+    border-radius: 12px;
+  }
+  
+  &.outline {
+    background: transparent;
+    border: 2px solid $primary-color;
+    color: $primary-color;
+    box-shadow: none;
+    
+    &:hover {
+      background: $primary-color;
+      color: white;
+      box-shadow: 0 4px 12px rgba($primary-color, 0.3);
+    }
+  }
+  
+  &.secondary {
+    background: linear-gradient(135deg, $morandi-sage, $morandi-dust);
+    box-shadow: 
+      0 4px 12px rgba($morandi-sage, 0.3),
+      inset 0 1px 0 rgba(255, 255, 255, 0.2);
+    
+    &:hover {
+      box-shadow: 
+        0 6px 20px rgba($morandi-sage, 0.4),
+        inset 0 1px 0 rgba(255, 255, 255, 0.2);
+    }
+  }
+}
+
 /* iOS风格面板 - 紧急事项添加 */
 .ios-modal-overlay {
   position: fixed;
@@ -1512,7 +1664,7 @@ input[type="datetime-local"]::-webkit-calendar-picker-indicator {
   }
 }
 
-/* CRM队列 */
+/* CRM队列 - iOS风格 */
 .crm-queues {
   margin-bottom: 24px;
 }
@@ -1524,11 +1676,9 @@ input[type="datetime-local"]::-webkit-calendar-picker-indicator {
 }
 
 .crm-card {
-  background: $ios-card-background;
-  border: 1px solid $ios-border;
-  border-radius: $ios-radius-lg;
-  padding: 16px;
-  box-shadow: $shadow-sm;
+  @extend .ios-card;
+  padding: 20px;
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 248, 248, 0.95));
 }
 
 .crm-header {
@@ -1607,56 +1757,145 @@ input[type="datetime-local"]::-webkit-calendar-picker-indicator {
   gap: 10px;
 }
 
+/* CRM项目 - iOS风格卡片 */
 .crm-item {
   display: flex;
   align-items: flex-start;
   justify-content: space-between;
   gap: 12px;
-  padding: 10px 12px;
-  border-radius: 10px;
-  border: 1px solid $border-color;
-  background: $background-color;
-  transition: $transition;
+  padding: 12px 16px;
+  border-radius: 12px;
+  border: 1px solid rgba(0, 0, 0, 0.05);
+  background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(248, 248, 248, 0.9));
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  margin-bottom: 8px;
 
-  &:hover { background: #f7f7fb; }
+  &:hover { 
+    background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(252, 252, 252, 0.95));
+    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+    transform: translateY(-2px);
+    border-color: rgba(0, 0, 0, 0.1);
+  }
 
   .crm-item-main { display: flex; align-items: flex-start; gap: 12px; }
   .avatar.small {
-    width: 28px; height: 28px; border-radius: 50%;
-    background: $primary-color; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700;
+    width: 32px; height: 32px; border-radius: 50%;
+    background: linear-gradient(135deg, $primary-color, $primary-dark); 
+    color: #fff; 
+    display: flex; 
+    align-items: center; 
+    justify-content: center; 
+    font-weight: 600;
     flex-shrink: 0;
-    &.alt { background: $ios-secondary; }
+    box-shadow: 0 2px 8px rgba($primary-color, 0.3);
+    transition: all 0.2s ease;
+    
+    &.alt { 
+      background: linear-gradient(135deg, $morandi-sage, $morandi-dust);
+      box-shadow: 0 2px 8px rgba($morandi-sage, 0.3);
+    }
+    
+    &:hover {
+      transform: scale(1.05);
+      box-shadow: 0 4px 12px rgba($primary-color, 0.4);
+      
+      &.alt {
+        box-shadow: 0 4px 12px rgba($morandi-sage, 0.4);
+      }
+    }
   }
   .info {
-    .name { font-weight: 600; color: $text-primary-dark; }
-    .meta { color: $text-tertiary-dark; font-size: 12px; display: flex; gap: 8px; margin-bottom: 8px; }
+    .name { 
+      font-weight: 600; 
+      color: $text-primary-dark; 
+      font-size: 15px;
+      letter-spacing: -0.2px;
+    }
+    .meta { 
+      color: $text-tertiary-dark; 
+      font-size: 12px; 
+      display: flex; 
+      gap: 8px; 
+      margin-bottom: 8px;
+      font-weight: 500;
+    }
     .tag { 
-      background: rgba(0,0,0,0.05); padding: 2px 6px; border-radius: 6px;
+      background: linear-gradient(135deg, rgba(0,0,0,0.03), rgba(0,0,0,0.06)); 
+      padding: 3px 8px; 
+      border-radius: 8px;
+      font-size: 11px;
+      font-weight: 600;
+      backdrop-filter: blur(4px);
+      
       &.value-tag {
-        background: #e8f5e8;
-        color: #2e7d32;
+        background: linear-gradient(135deg, #f0fdf4, #dcfce7);
+        color: #166534;
+        border: 1px solid rgba(22, 101, 52, 0.1);
       }
       &.price-tag {
-        background: #fff3e0;
-        color: #f57c00;
+        background: linear-gradient(135deg, #fffbeb, #fef3c7);
+        color: #d97706;
+        border: 1px solid rgba(217, 119, 6, 0.1);
       }
     }
     .strategy-info {
       font-size: 12px;
-      line-height: 1.4;
+      line-height: 1.5;
+      margin-top: 6px;
+      
       .recommended-phrase {
-        color: #555;
+        color: $morandi-dust;
         margin-bottom: 4px;
         font-style: italic;
+        font-weight: 500;
+        letter-spacing: -0.1px;
       }
+      
       .case-strategy {
-        color: #666;
+        color: $morandi-sage;
         font-size: 11px;
+        font-weight: 500;
+        background: rgba($morandi-sage, 0.1);
+        padding: 2px 6px;
+        border-radius: 4px;
+        display: inline-block;
       }
     }
   }
 
-  .ios-btn.mini { padding: 6px 10px; font-size: 12px; border-radius: 8px; }
+  .ios-btn.mini { 
+    padding: 8px 14px; 
+    font-size: 13px; 
+    border-radius: 10px;
+    font-weight: 600;
+    letter-spacing: -0.2px;
+    background: linear-gradient(135deg, $primary-color, $primary-dark);
+    box-shadow: 0 2px 8px rgba($primary-color, 0.3);
+    
+    &:hover {
+      transform: translateY(-1px);
+      box-shadow: 0 4px 12px rgba($primary-color, 0.4);
+    }
+    
+    &:active {
+      transform: translateY(0);
+      box-shadow: 0 1px 4px rgba($primary-color, 0.3);
+    }
+  }
+  
+  .ios-btn.outline.mini {
+    background: transparent;
+    border: 2px solid $primary-color;
+    color: $primary-color;
+    box-shadow: none;
+    
+    &:hover {
+      background: $primary-color;
+      color: white;
+      box-shadow: 0 2px 8px rgba($primary-color, 0.3);
+    }
+  }
 }
 
 .empty-state.small { color: $text-tertiary-dark; font-size: 13px; text-align: center; padding: 8px 0; }

+ 5 - 69
src/app/pages/customer-service/dashboard/dashboard.ts

@@ -178,6 +178,11 @@ export class Dashboard implements OnInit, OnDestroy {
       behavior: 'smooth'
     });
   }
+
+  // 查看人员考勤
+  viewAttendance(): void {
+    this.router.navigate(['/hr/attendance']);
+  }
   
   // 修改loadUrgentTasks方法,添加status属性
   loadUrgentTasks(): void {
@@ -253,75 +258,6 @@ export class Dashboard implements OnInit, OnDestroy {
     ]);
   }
 
-  // 便捷跳转到企业微信聊天窗口或咨询列表
-  navigateToConsultation(keyword: string): void {
-    // 尝试打开企业微信聊天窗口
-    this.openWeChatWorkChat(keyword);
-    
-    // 同时导航到咨询列表作为备选方案
-    this.router.navigate(['/customer-service/consultation-list'], { queryParams: { q: keyword } });
-  }
-
-  // 打开企业微信聊天窗口
-  private openWeChatWorkChat(customerName: string): void {
-    try {
-      // 企业微信 Web 版聊天链接格式
-      const weChatWorkUrl = `https://work.weixin.qq.com/wework_admin/frame#/chat/${encodeURIComponent(customerName)}`;
-      
-      // 尝试在新窗口中打开企业微信聊天
-      const chatWindow = window.open(weChatWorkUrl, '_blank', 'width=800,height=600,scrollbars=yes,resizable=yes');
-      
-      if (!chatWindow) {
-        console.warn('无法打开企业微信聊天窗口,可能被浏览器阻止弹窗');
-        // 如果弹窗被阻止,显示提示信息
-        this.showWeChatWorkTip(customerName);
-      }
-    } catch (error) {
-      console.error('打开企业微信聊天窗口失败:', error);
-      this.showWeChatWorkTip(customerName);
-    }
-  }
-
-  // 显示企业微信提示信息
-  private showWeChatWorkTip(customerName: string): void {
-    // 创建临时提示元素
-    const tip = document.createElement('div');
-    tip.className = 'wechat-work-tip';
-    tip.innerHTML = `
-      <div class="tip-content">
-        <div class="tip-icon">💬</div>
-        <div class="tip-text">正在为您打开与 ${customerName} 的企业微信聊天</div>
-        <div class="tip-subtext">如未自动打开,请手动前往企业微信查找该客户</div>
-      </div>
-    `;
-    
-    // 添加样式
-    tip.style.cssText = `
-      position: fixed;
-      top: 20px;
-      right: 20px;
-      background: linear-gradient(135deg, #1890ff, #36cfc9);
-      color: white;
-      padding: 16px 20px;
-      border-radius: 12px;
-      box-shadow: 0 8px 32px rgba(24, 144, 255, 0.3);
-      z-index: 10000;
-      font-size: 14px;
-      max-width: 320px;
-      animation: slideInRight 0.3s ease-out;
-    `;
-    
-    document.body.appendChild(tip);
-    
-    // 3秒后自动移除提示
-    setTimeout(() => {
-      if (tip.parentNode) {
-        tip.style.animation = 'slideOutRight 0.3s ease-in';
-        setTimeout(() => tip.remove(), 300);
-      }
-    }, 3000);
-  }
-
   // 查看全部咨询列表
   goToConsultationList(): void {
     this.router.navigate(['/customer-service/consultation-list']);

+ 74 - 34
src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.html

@@ -1,42 +1,82 @@
-<div class="ios-container">
-  <header class="ios-header">
-    <button class="ios-back-btn" (click)="goBack()">
-      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-        <path d="M19 12H5M12 19l-7-7 7-7"/>
-      </svg>
-    </button>
-    <h1>客户咨询记录</h1>
-  </header>
+@if (consultations && consultations.length > 0) {
+  <div class="ios-container">
+    <header class="ios-header">
+      <button class="ios-back-btn" (click)="goBack()">
+        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <path d="M19 12H5M12 19l-7-7 7-7"/>
+        </svg>
+      </button>
+      <h1>客户咨询记录</h1>
+    </header>
 
-  <div class="ios-content">
-    <div class="search-bar">
-      <input type="text" placeholder="搜索咨询记录...">
-      <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-        <circle cx="11" cy="11" r="8"/>
-        <line x1="21" y1="21" x2="16.65" y2="16.65"/>
-      </svg>
-    </div>
+    <div class="ios-content">
+      <div class="search-bar">
+        <input type="text" placeholder="搜索咨询记录..." [(ngModel)]="searchKeyword" (input)="filterConsultations()">
+        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <circle cx="11" cy="11" r="8"/>
+          <line x1="21" y1="21" x2="16.65" y2="16.65"/>
+        </svg>
+      </div>
 
-    <div class="consultation-list">
-      <div class="consultation-card" *ngFor="let item of consultations">
-        <div class="card-header">
-          <div class="customer-info">
-            <div class="avatar">{{item.customer.charAt(0)}}</div>
-            <div>
-              <h3>{{item.customer}}</h3>
-              <p class="time">{{item.time}}</p>
+      <div class="consultation-list">
+        @for (item of filteredConsultations; track item.id) {
+          <div class="consultation-card" [class.urgent]="item.priority === 'high'">
+            <div class="card-header">
+              <div class="customer-info">
+                <div class="avatar" [style.background-color]="getAvatarColor(item.customer)">
+                  {{item.customer.charAt(0)}}
+                </div>
+                <div>
+                  <h3>{{item.customer}}</h3>
+                  <p class="time">{{item.time}}</p>
+                </div>
+              </div>
+              <span class="status-badge" [class.urgent]="item.priority === 'high'">
+                {{item.priority === 'high' ? '紧急' : '普通'}}
+              </span>
+            </div>
+            <p class="content">{{item.content}}</p>
+            <div class="card-footer">
+              <button class="ios-btn primary" (click)="viewDetails(item)">查看详情</button>
+              <button class="ios-btn secondary" (click)="assignHandler(item)">分配处理</button>
             </div>
           </div>
-          <span class="status-badge" [class.urgent]="item.priority === 'high'">
-            {{item.priority === 'high' ? '紧急' : '普通'}}
-          </span>
-        </div>
-        <p class="content">{{item.content}}</p>
-        <div class="card-footer">
-          <button class="ios-btn">查看详情</button>
-          <button class="ios-btn outline">分配处理</button>
+        }
+      </div>
+
+      @if (filteredConsultations.length === 0 && searchKeyword) {
+        <div class="empty-state">
+          <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
+            <circle cx="11" cy="11" r="8"></circle>
+            <path d="m21 21-4.35-4.35"></path>
+          </svg>
+          <h3>未找到匹配记录</h3>
+          <p>尝试其他关键词搜索</p>
         </div>
+      }
+    </div>
+  </div>
+}
+@else {
+  <div class="ios-container">
+    <header class="ios-header">
+      <button class="ios-back-btn" (click)="goBack()">
+        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <path d="M19 12H5M12 19l-7-7 7-7"/>
+        </svg>
+      </button>
+      <h1>客户咨询记录</h1>
+    </header>
+
+    <div class="ios-content">
+      <div class="empty-state">
+        <svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
+          <circle cx="11" cy="11" r="8"></circle>
+          <path d="m21 21-4.35-4.35"></path>
+        </svg>
+        <h3>暂无咨询记录</h3>
+        <p>还没有客户咨询记录</p>
       </div>
     </div>
   </div>
-</div>
+}

+ 403 - 141
src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.scss

@@ -1,15 +1,75 @@
 @import "../../../customer-service-styles.scss";
 
+// 全部客户咨询页面 - iOS风格
 .consultation-container {
   min-height: 100vh;
-  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+  background: linear-gradient(135deg, #f2f2f7 0%, #e5e5ea 100%);
   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
 }
 
-// 页面头部
+// iOS容器样式
+.ios-container {
+  min-height: 100vh;
+  background: linear-gradient(135deg, #f2f2f7 0%, #e5e5ea 100%);
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+}
+
+// iOS头部导航
+.ios-header {
+  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+  padding: 16px 20px;
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  position: sticky;
+  top: 0;
+  z-index: 100;
+  box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08);
+  backdrop-filter: blur(20px);
+  -webkit-backdrop-filter: blur(20px);
+
+  .ios-back-btn {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 40px;
+    height: 40px;
+    border: none;
+    background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+    border-radius: 12px;
+    color: #6c757d;
+    cursor: pointer;
+    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(255, 255, 255, 0.8);
+
+    &:hover {
+      background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
+      color: #495057;
+      transform: translateX(-2px);
+      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), inset 0 1px 2px rgba(255, 255, 255, 0.8);
+    }
+
+    &:active {
+      transform: translateX(-1px) scale(0.95);
+      box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(255, 255, 255, 0.8);
+    }
+  }
+
+  h1 {
+    font-size: 24px;
+    font-weight: 700;
+    color: #1d1d1f;
+    margin: 0;
+    line-height: 1.2;
+    letter-spacing: -0.3px;
+  }
+}
+
+// 页面头部 - iOS风格
 .page-header {
-  background: #ffffff;
-  border-bottom: 1px solid #e2e8f0;
+  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
   padding: 20px 24px;
   display: flex;
   align-items: center;
@@ -17,7 +77,9 @@
   position: sticky;
   top: 0;
   z-index: 100;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+  box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08);
+  backdrop-filter: blur(20px);
+  -webkit-backdrop-filter: blur(20px);
 
   .header-left {
     display: flex;
@@ -29,40 +91,45 @@
     display: flex;
     align-items: center;
     justify-content: center;
-    width: 40px;
-    height: 40px;
+    width: 44px;
+    height: 44px;
     border: none;
-    background: #f8fafc;
-    border-radius: 10px;
-    color: #64748b;
+    background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+    border-radius: 12px;
+    color: #6c757d;
     cursor: pointer;
-    transition: all 0.2s ease;
+    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(255, 255, 255, 0.8);
 
     &:hover {
-      background: #e2e8f0;
-      color: #475569;
+      background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
+      color: #495057;
       transform: translateX(-2px);
+      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15), inset 0 1px 2px rgba(255, 255, 255, 0.8);
     }
 
     &:active {
-      transform: translateX(-1px);
+      transform: translateX(-1px) scale(0.95);
+      box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(255, 255, 255, 0.8);
     }
   }
 
   .header-title {
     h1 {
-      font-size: 24px;
+      font-size: 28px;
       font-weight: 700;
-      color: #1e293b;
+      color: #1d1d1f;
       margin: 0;
       line-height: 1.2;
+      letter-spacing: -0.5px;
     }
 
     .subtitle {
-      font-size: 14px;
-      color: #64748b;
-      margin: 4px 0 0;
+      font-size: 15px;
+      color: #8e8e93;
+      margin: 6px 0 0;
       line-height: 1.4;
+      font-weight: 500;
     }
   }
 
@@ -71,19 +138,23 @@
       display: flex;
       align-items: center;
       gap: 8px;
-      padding: 10px 16px;
-      border: 1px solid #e2e8f0;
-      background: #ffffff;
-      border-radius: 8px;
-      color: #475569;
+      padding: 12px 18px;
+      border: 1px solid rgba(0, 0, 0, 0.08);
+      background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+      border-radius: 12px;
+      color: #007AFF;
       font-size: 14px;
-      font-weight: 500;
+      font-weight: 600;
       cursor: pointer;
-      transition: all 0.2s ease;
+      transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(255, 255, 255, 0.8);
 
       &:hover:not(:disabled) {
-        background: #f8fafc;
-        border-color: #cbd5e1;
+        background: linear-gradient(135deg, #007AFF 0%, #0062CC 100%);
+        border-color: rgba(0, 0, 0, 0.1);
+        color: #ffffff;
+        transform: translateY(-1px);
+        box-shadow: 0 4px 16px rgba(0, 122, 255, 0.3), inset 0 1px 2px rgba(255, 255, 255, 0.2);
       }
 
       &:disabled {
@@ -98,11 +169,49 @@
   }
 }
 
-// 搜索和筛选区域
-.search-filter-section {
-  padding: 24px;
-  background: #ffffff;
-  border-bottom: 1px solid #e2e8f0;
+// iOS内容区域
+.ios-content {
+  padding: 20px;
+  max-width: 800px;
+  margin: 0 auto;
+}
+
+// iOS搜索栏
+.search-bar {
+  position: relative;
+  margin-bottom: 24px;
+
+  input {
+    width: 100%;
+    padding: 16px 48px 16px 16px;
+    border: 1px solid rgba(0, 0, 0, 0.1);
+    border-radius: 16px;
+    font-size: 16px;
+    background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+    outline: none;
+    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(255, 255, 255, 0.8);
+
+    &::placeholder {
+      color: #8e8e93;
+    }
+
+    &:focus {
+      border-color: #007AFF;
+      background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+      box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.15), inset 0 2px 4px rgba(0, 0, 0, 0.05);
+    }
+  }
+
+  svg {
+    position: absolute;
+    right: 16px;
+    top: 50%;
+    transform: translateY(-50%);
+    color: #8e8e93;
+    pointer-events: none;
+  }
+}
 
   .search-container {
     margin-bottom: 20px;
@@ -122,22 +231,23 @@
 
       .search-input {
         width: 100%;
-        padding: 14px 16px 14px 48px;
-        border: 2px solid #e2e8f0;
-        border-radius: 12px;
+        padding: 16px 16px 16px 48px;
+        border: 1px solid rgba(0, 0, 0, 0.1);
+        border-radius: 16px;
         font-size: 16px;
-        background: #f8fafc;
-        transition: all 0.2s ease;
+        background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
         outline: none;
+        box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(255, 255, 255, 0.8);
 
         &::placeholder {
-          color: #94a3b8;
+          color: #8e8e93;
         }
 
         &:focus {
-          border-color: #3b82f6;
-          background: #ffffff;
-          box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
+          border-color: #007AFF;
+          background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+          box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.15), inset 0 2px 4px rgba(0, 0, 0, 0.05);
         }
       }
 
@@ -167,37 +277,41 @@
   }
 
   .filter-chips {
-    display: flex;
-    gap: 12px;
-    flex-wrap: wrap;
-
-    .filter-chip {
       display: flex;
-      align-items: center;
-      gap: 8px;
-      padding: 10px 16px;
-      border: 2px solid #e2e8f0;
-      background: #ffffff;
-      border-radius: 20px;
-      color: #64748b;
-      font-size: 14px;
-      font-weight: 500;
-      cursor: pointer;
-      transition: all 0.2s ease;
-      position: relative;
+      gap: 12px;
+      flex-wrap: wrap;
 
-      &:hover {
-        border-color: #cbd5e1;
-        background: #f8fafc;
-      }
+      .filter-chip {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        padding: 12px 18px;
+        border: 1px solid rgba(0, 0, 0, 0.08);
+        background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+        border-radius: 20px;
+        color: #6c757d;
+        font-size: 14px;
+        font-weight: 500;
+        cursor: pointer;
+        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+        position: relative;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05), inset 0 1px 2px rgba(255, 255, 255, 0.8);
 
-      &.active {
-        border-color: #3b82f6;
-        background: #3b82f6;
-        color: #ffffff;
+        &:hover {
+          border-color: rgba(0, 122, 255, 0.3);
+          background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+          transform: translateY(-1px);
+          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.8);
+        }
+
+        &.active {
+          border-color: #007AFF;
+          background: linear-gradient(135deg, #007AFF 0%, #0062CC 100%);
+          color: #ffffff;
+          box-shadow: 0 4px 16px rgba(0, 122, 255, 0.3), inset 0 1px 2px rgba(255, 255, 255, 0.2);
 
-        .chip-count {
-          background: rgba(255, 255, 255, 0.2);
+          .chip-count {
+            background: rgba(255, 255, 255, 0.2);
           color: #ffffff;
         }
       }
@@ -226,8 +340,8 @@
     flex-direction: column;
     align-items: center;
     justify-content: center;
-    padding: 60px 20px;
-    color: #64748b;
+    padding: 80px 20px;
+    color: #8e8e93;
 
     .loading-spinner {
       width: 40px;
@@ -240,8 +354,9 @@
     }
 
     p {
-      font-size: 16px;
+      font-size: 18px;
       margin: 0;
+      font-weight: 500;
     }
   }
 
@@ -250,26 +365,30 @@
     flex-direction: column;
     align-items: center;
     justify-content: center;
-    padding: 60px 20px;
+    padding: 80px 20px;
     text-align: center;
-    color: #64748b;
+    color: #8e8e93;
 
     svg {
-      margin-bottom: 20px;
-      opacity: 0.5;
+      margin-bottom: 24px;
+      opacity: 0.6;
+      width: 80px;
+      height: 80px;
     }
 
     h3 {
       font-size: 20px;
-      font-weight: 600;
-      color: #475569;
-      margin: 0 0 8px;
+      font-weight: 700;
+      color: #1d1d1f;
+      margin: 0 0 12px;
+      letter-spacing: -0.3px;
     }
 
     p {
       font-size: 16px;
+      color: #8e8e93;
       margin: 0;
-      line-height: 1.5;
+      font-weight: 500;
     }
   }
 
@@ -277,38 +396,170 @@
     display: flex;
     flex-direction: column;
     gap: 16px;
+    margin-bottom: 24px;
+  }
+
+  // iOS咨询卡片
+  .consultation-card {
+    background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+    border: 1px solid rgba(0, 0, 0, 0.05);
+    border-radius: 20px;
+    padding: 24px;
+    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.8);
+    backdrop-filter: blur(20px);
+    -webkit-backdrop-filter: blur(20px);
+
+    &:hover {
+      transform: translateY(-2px);
+      box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.8);
+    }
+
+    &.urgent {
+      border: 2px solid #FF3B30;
+      background: linear-gradient(135deg, #ffffff 0%, #fff5f5 100%);
+    }
+
+    .card-header {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 16px;
+
+      .customer-info {
+        display: flex;
+        align-items: center;
+        gap: 12px;
+
+        .avatar {
+          width: 48px;
+          height: 48px;
+          border-radius: 16px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-weight: 700;
+          font-size: 18px;
+          color: white;
+          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+        }
+
+        h3 {
+          font-size: 18px;
+          font-weight: 600;
+          color: #1d1d1f;
+          margin: 0 0 4px;
+        }
+
+        .time {
+          font-size: 14px;
+          color: #8e8e93;
+          margin: 0;
+          font-weight: 500;
+        }
+      }
+
+      .status-badge {
+        padding: 8px 12px;
+        border-radius: 12px;
+        font-size: 12px;
+        font-weight: 600;
+        background: linear-gradient(135deg, #e5f4ff 0%, #cce7ff 100%);
+        color: #007AFF;
+        border: 1px solid rgba(0, 122, 255, 0.2);
+
+        &.urgent {
+          background: linear-gradient(135deg, #ffe5e5 0%, #ffcccc 100%);
+          color: #FF3B30;
+          border: 1px solid rgba(255, 59, 48, 0.2);
+        }
+      }
+    }
+
+    .content {
+      font-size: 16px;
+      color: #3c3c43;
+      line-height: 1.6;
+      margin: 0 0 20px;
+      font-weight: 500;
+    }
+
+    .card-footer {
+      display: flex;
+      gap: 12px;
+
+      .ios-btn {
+        flex: 1;
+        padding: 12px 20px;
+        border: none;
+        border-radius: 12px;
+        font-size: 14px;
+        font-weight: 600;
+        cursor: pointer;
+        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        gap: 8px;
+
+        &.primary {
+          background: linear-gradient(135deg, #007AFF 0%, #0062CC 100%);
+          color: white;
+          box-shadow: 0 2px 8px rgba(0, 122, 255, 0.3);
+
+          &:hover {
+            transform: translateY(-1px);
+            box-shadow: 0 4px 16px rgba(0, 122, 255, 0.4);
+          }
+        }
+
+        &.secondary {
+          background: linear-gradient(135deg, #f2f2f7 0%, #e5e5ea 100%);
+          color: #8e8e93;
+          border: 1px solid rgba(0, 0, 0, 0.1);
+
+          &:hover {
+            background: linear-gradient(135deg, #e5e5ea 0%, #d1d1d6 100%);
+            transform: translateY(-1px);
+          }
+        }
+      }
+    }
   }
 }
 
 // 咨询条目
 .consultation-item {
-  background: #ffffff;
-  border: 1px solid #e2e8f0;
-  border-radius: 16px;
-  padding: 20px;
-  transition: all 0.2s ease;
+  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+  border: 1px solid rgba(0, 0, 0, 0.05);
+  border-radius: 20px;
+  padding: 24px;
+  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+  cursor: pointer;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.8);
+  backdrop-filter: blur(10px);
+  -webkit-backdrop-filter: blur(10px);
   position: relative;
   overflow: hidden;
 
   &:hover {
-    border-color: #cbd5e1;
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
-    transform: translateY(-1px);
+    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.8);
+    transform: translateY(-4px);
   }
 
   &.urgent {
-    border-left: 4px solid #ef4444;
-    background: linear-gradient(135deg, #fef2f2 0%, #ffffff 100%);
+    border-left: 4px solid #FF3B30;
+    background: linear-gradient(135deg, #ffebee 0%, #ffffff 100%);
   }
 
   &.sensitive {
-    border-left: 4px solid #f59e0b;
-    background: linear-gradient(135deg, #fffbeb 0%, #ffffff 100%);
+    border-left: 4px solid #FF9500;
+    background: linear-gradient(135deg, #fff3e0 0%, #ffffff 100%);
   }
 
   &.overdue {
-    border-left: 4px solid #dc2626;
-    background: linear-gradient(135deg, #fef2f2 0%, #ffffff 100%);
+    border-left: 4px solid #FF2D55;
+    background: linear-gradient(135deg, #ffebee 0%, #ffffff 100%);
   }
 
   .item-header {
@@ -324,27 +575,30 @@
       flex: 1;
 
       .customer-avatar {
-        width: 48px;
-        height: 48px;
-        border-radius: 12px;
+        width: 52px;
+        height: 52px;
+        border-radius: 16px;
         display: flex;
         align-items: center;
         justify-content: center;
         color: #ffffff;
-        font-size: 18px;
-        font-weight: 600;
+        font-size: 20px;
+        font-weight: 700;
         flex-shrink: 0;
+        background: linear-gradient(135deg, #007AFF 0%, #5856D6 100%);
+        box-shadow: 0 4px 12px rgba(0, 122, 255, 0.3);
       }
 
       .customer-details {
         flex: 1;
 
         .customer-name {
-          font-size: 18px;
-          font-weight: 600;
-          color: #1e293b;
-          margin: 0 0 4px;
+          font-size: 20px;
+          font-weight: 700;
+          color: #1d1d1f;
+          margin: 0 0 6px;
           line-height: 1.3;
+          letter-spacing: -0.3px;
         }
 
         .customer-meta {
@@ -352,16 +606,17 @@
           align-items: center;
           gap: 8px;
           font-size: 14px;
-          color: #64748b;
+          color: #8e8e93;
+          font-weight: 500;
 
           .separator {
-            color: #cbd5e1;
+            color: #c7c7cc;
           }
 
           .reply-status {
             &.overdue {
-              color: #dc2626;
-              font-weight: 500;
+              color: #FF3B30;
+              font-weight: 600;
             }
           }
         }
@@ -377,43 +632,46 @@
         display: flex;
         align-items: center;
         gap: 4px;
-        padding: 6px 10px;
-        border-radius: 12px;
+        padding: 8px 12px;
+        border-radius: 14px;
         font-size: 12px;
         font-weight: 600;
         text-transform: uppercase;
         letter-spacing: 0.5px;
+        backdrop-filter: blur(10px);
+        -webkit-backdrop-filter: blur(10px);
 
         &.urgent {
-          background: #fef2f2;
-          color: #dc2626;
-          border: 1px solid #fecaca;
+          background: rgba(255, 59, 48, 0.1);
+          color: #FF3B30;
+          border: 1px solid rgba(255, 59, 48, 0.2);
         }
 
         &.sensitive {
-          background: #fffbeb;
-          color: #d97706;
-          border: 1px solid #fed7aa;
+          background: rgba(255, 149, 0, 0.1);
+          color: #FF9500;
+          border: 1px solid rgba(255, 149, 0, 0.2);
         }
       }
     }
   }
 
   .consultation-content-text {
-    margin-bottom: 20px;
+    margin-bottom: 24px;
 
     p {
       font-size: 16px;
-      line-height: 1.6;
-      color: #374151;
+      line-height: 1.7;
+      color: #3c3c43;
       margin: 0;
+      font-weight: 500;
 
       :global(mark) {
-        background: #fef3c7;
-        color: #92400e;
-        padding: 2px 4px;
-        border-radius: 4px;
-        font-weight: 500;
+        background: rgba(255, 149, 0, 0.15);
+        color: #FF9500;
+        padding: 2px 6px;
+        border-radius: 6px;
+        font-weight: 600;
       }
     }
   }
@@ -427,14 +685,15 @@
       display: flex;
       align-items: center;
       gap: 8px;
-      padding: 10px 16px;
-      border-radius: 8px;
+      padding: 12px 18px;
+      border-radius: 12px;
       font-size: 14px;
-      font-weight: 500;
+      font-weight: 600;
       cursor: pointer;
-      transition: all 0.2s ease;
+      transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
       border: none;
       outline: none;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
 
       &:disabled {
         opacity: 0.6;
@@ -442,35 +701,38 @@
       }
 
       &.primary {
-        background: #3b82f6;
+        background: linear-gradient(135deg, #007AFF 0%, #5856D6 100%);
         color: #ffffff;
 
         &:hover:not(:disabled) {
-          background: #2563eb;
-          transform: translateY(-1px);
-          box-shadow: 0 4px 8px rgba(59, 130, 246, 0.3);
+          background: linear-gradient(135deg, #0062CC 0%, #4A4AB8 100%);
+          transform: translateY(-2px);
+          box-shadow: 0 6px 20px rgba(0, 122, 255, 0.4);
         }
       }
 
       &.secondary {
-        background: #f8fafc;
-        color: #475569;
-        border: 1px solid #e2e8f0;
+        background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+        color: #6c757d;
+        border: 1px solid rgba(0, 0, 0, 0.08);
 
         &:hover {
-          background: #f1f5f9;
-          border-color: #cbd5e1;
+          background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+          border-color: rgba(0, 0, 0, 0.15);
+          transform: translateY(-1px);
+          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
         }
       }
 
       &.tertiary {
-        background: #f0fdf4;
-        color: #16a34a;
-        border: 1px solid #bbf7d0;
+        background: linear-gradient(135deg, #34C759 0%, #30B855 100%);
+        color: #ffffff;
+        border: none;
 
         &:hover {
-          background: #dcfce7;
-          border-color: #86efac;
+          background: linear-gradient(135deg, #30B855 0%, #2DA54A 100%);
+          transform: translateY(-2px);
+          box-shadow: 0 6px 20px rgba(52, 199, 89, 0.4);
         }
       }
     }

+ 31 - 18
src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.ts

@@ -45,11 +45,11 @@ import { FormsModule } from '@angular/forms';
             <input 
               type="text" 
               placeholder="搜索客户姓名、咨询内容..." 
-              [(ngModel)]="keyword" 
+              [(ngModel)]="searchKeyword" 
               (input)="applyFilters()"
               class="search-input"
             >
-            <button *ngIf="keyword" class="clear-search" (click)="clearSearch()">
+            <button *ngIf="searchKeyword" class="clear-search" (click)="clearSearch()">
               <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                 <line x1="18" y1="6" x2="6" y2="18"></line>
                 <line x1="6" y1="6" x2="18" y2="18"></line>
@@ -109,7 +109,7 @@ import { FormsModule } from '@angular/forms';
             <path d="m21 21-4.35-4.35"></path>
           </svg>
           <h3>暂无咨询记录</h3>
-          <p>{{ keyword ? '没有找到匹配的咨询记录' : '还没有客户咨询记录' }}</p>
+          <p>{{ searchKeyword ? '没有找到匹配的咨询记录' : '还没有客户咨询记录' }}</p>
         </div>
 
         <div *ngIf="!isLoading && filteredConsultations.length > 0" class="consultation-list">
@@ -197,14 +197,6 @@ import { FormsModule } from '@angular/forms';
   `]
 })
 export class ConsultationListComponent implements OnInit {
-  keyword = '';
-  filterUnrepliedOver1h = false;
-  filterSensitive = false;
-  filterHighPriority = false;
-  isLoading = false;
-
-  private sensitivePatterns = /(发手机|发邮箱|找不到人|微信|QQ|电话|联系方式)/;
-
   consultations = [
     {
       id: '1',
@@ -264,6 +256,13 @@ export class ConsultationListComponent implements OnInit {
   ];
 
   filteredConsultations = [...this.consultations];
+  searchKeyword = '';
+  filterUnrepliedOver1h = false;
+  filterSensitive = false;
+  filterHighPriority = false;
+  isLoading = false;
+
+  private sensitivePatterns = /(发手机|发邮箱|找不到人|微信|QQ|电话|联系方式)/;
 
   constructor(private route: ActivatedRoute) {}
 
@@ -271,17 +270,31 @@ export class ConsultationListComponent implements OnInit {
     this.route.queryParams.subscribe(params => {
       const q = params['q'];
       if (q) {
-        this.keyword = q;
+        this.searchKeyword = q;
       }
       this.applyFilters();
     });
   }
 
+  // 搜索过滤功能
+  filterConsultations() {
+    if (!this.searchKeyword.trim()) {
+      this.filteredConsultations = [...this.consultations];
+      return;
+    }
+
+    const keyword = this.searchKeyword.toLowerCase();
+    this.filteredConsultations = this.consultations.filter(item => 
+      item.customer.toLowerCase().includes(keyword) ||
+      item.content.toLowerCase().includes(keyword)
+    );
+  }
+
   applyFilters(): void {
     this.filteredConsultations = this.consultations.filter(item => {
-      const matchesKeyword = !this.keyword || 
-        item.customer.toLowerCase().includes(this.keyword.toLowerCase()) || 
-        item.content.toLowerCase().includes(this.keyword.toLowerCase());
+      const matchesKeyword = !this.searchKeyword || 
+        item.customer.toLowerCase().includes(this.searchKeyword.toLowerCase()) || 
+        item.content.toLowerCase().includes(this.searchKeyword.toLowerCase());
       const matchesUnreplied = !this.filterUnrepliedOver1h || item.lastReplyMinutes > 60;
       const matchesSensitive = !this.filterSensitive || this.containsSensitiveWords(item.content);
       const matchesPriority = !this.filterHighPriority || item.priority === 'high';
@@ -305,7 +318,7 @@ export class ConsultationListComponent implements OnInit {
   }
 
   clearSearch(): void {
-    this.keyword = '';
+    this.searchKeyword = '';
     this.applyFilters();
   }
 
@@ -347,8 +360,8 @@ export class ConsultationListComponent implements OnInit {
   }
 
   highlightKeyword(content: string): string {
-    if (!this.keyword) return content;
-    const regex = new RegExp(`(${this.keyword})`, 'gi');
+    if (!this.searchKeyword) return content;
+    const regex = new RegExp(`(${this.searchKeyword})`, 'gi');
     return content.replace(regex, '<mark>$1</mark>');
   }
 

+ 93 - 5
src/app/pages/hr/attendance/attendance.html

@@ -47,17 +47,61 @@
     </div>
     
     <div class="action-buttons">
-      <button mat-raised-button color="primary" (click)="exportAttendanceData()" class="export-btn">
-        <mat-icon>file_download</mat-icon>
-        导出考勤数据
+      <button 
+        mat-raised-button 
+        [class.active]="!showGanttView()" 
+        (click)="toggleView()"
+        class="view-btn">
+        考勤视图
+      </button>
+      <button 
+        mat-raised-button 
+        [class.active]="showGanttView()" 
+        (click)="toggleView()"
+        class="view-btn">
+        任务视图
+      </button>
+      <button 
+        mat-raised-button 
+        (click)="exportAttendanceData()"
+        class="export-btn">
+        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
+          <polyline points="7 10 12 15 17 10"></polyline>
+          <line x1="12" y1="15" x2="12" y2="3"></line>
+        </svg>
+        导出数据
       </button>
     </div>
   </div>
 
   <!-- 主内容区 -->
   <div class="main-content">
-    <!-- 左侧:考勤日历 -->
-    <div class="calendar-section">
+    <!-- 甘特图视图切换按钮 -->
+    <div class="view-toggle-buttons">
+      <button 
+        mat-raised-button 
+        [class.active]="!showGanttView()" 
+        (click)="showGanttView.set(false)"
+        class="view-btn"
+      >
+        <mat-icon>calendar_today</mat-icon>
+        考勤日历
+      </button>
+      <button 
+        mat-raised-button 
+        [class.active]="showGanttView()" 
+        (click)="toggleView()"
+        class="view-btn"
+      >
+        <mat-icon>timeline</mat-icon>
+        任务甘特图
+      </button>
+    </div>
+
+    @if (!showGanttView()) {
+      <!-- 左侧:考勤日历 -->
+      <div class="calendar-section">
       <div class="section-header">
         <h2>考勤日历</h2>
       </div>
@@ -241,5 +285,49 @@
         </div>
       </div>
     </div>
+    } @else {
+      <!-- 甘特图视图 -->
+      <div class="gantt-section">
+        <div class="gantt-header">
+          <h2>订单任务甘特图</h2>
+          <div class="gantt-controls">
+            <button 
+              mat-raised-button 
+              [class.active]="ganttScale() === 'week'" 
+              (click)="setGanttScale('week')"
+              class="scale-btn"
+            >
+              周视图
+            </button>
+            <button 
+              mat-raised-button 
+              [class.active]="ganttScale() === 'month'" 
+              (click)="setGanttScale('month')"
+              class="scale-btn"
+            >
+              月视图
+            </button>
+          </div>
+        </div>
+        
+        <div #ganttChartRef class="gantt-chart"></div>
+        
+        <!-- 图例说明 -->
+        <div class="gantt-legend">
+          <div class="legend-item">
+            <div class="legend-color" style="background-color: #22c55e;"></div>
+            <span>已完成 (100%)</span>
+          </div>
+          <div class="legend-item">
+            <div class="legend-color" style="background-color: #f59e0b;"></div>
+            <span>进展良好 (≥75%)</span>
+          </div>
+          <div class="legend-item">
+            <div class="legend-color" style="background-color: #ef4444;"></div>
+            <span>需要关注 (<75%)</span>
+          </div>
+        </div>
+      </div>
+    }
   </div>
 </div>

+ 203 - 2
src/app/pages/hr/attendance/attendance.scss

@@ -164,9 +164,10 @@ $transition: all 0.2s ease;
 // 主内容区
 .main-content {
   display: grid;
-  grid-template-columns: 1fr;
+  grid-template-columns: 1fr 400px;
   gap: 24px;
   align-items: start;
+  min-height: 600px;
 }
 
 // 左侧:考勤日历
@@ -178,6 +179,207 @@ $transition: all 0.2s ease;
   height: fit-content;
   position: sticky;
   top: 24px;
+  grid-column: 1;
+}
+
+// 视图切换按钮
+.view-toggle-buttons {
+  display: flex;
+  gap: 12px;
+  margin-bottom: 24px;
+  background-color: $bg-tertiary;
+  border-radius: $border-radius;
+  padding: 4px;
+  
+  .view-btn {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    padding: 12px 24px;
+    border-radius: $border-radius;
+    font-size: 14px;
+    font-weight: 500;
+    transition: $transition;
+    border: none;
+    cursor: pointer;
+    
+    &.active {
+      background-color: $primary-color;
+      color: white;
+      box-shadow: $shadow-md;
+    }
+    
+    &:not(.active) {
+      background-color: transparent;
+      color: $text-secondary;
+      
+      &:hover {
+        background-color: $bg-secondary;
+        color: $text-primary;
+      }
+    }
+  }
+}
+
+// 右侧:统计图表和异常列表
+.stats-section {
+  background-color: $bg-primary;
+  border-radius: $border-radius;
+  box-shadow: $shadow-sm;
+  padding: 20px;
+  grid-column: 2;
+  height: fit-content;
+  position: sticky;
+  top: 24px;
+  max-height: 80vh;
+  overflow-y: auto;
+  
+  // 统计卡片
+  .stats-cards {
+    display: grid;
+    grid-template-columns: repeat(2, 1fr);
+    gap: 12px;
+    margin-bottom: 24px;
+  }
+  
+  .stat-card {
+    padding: 16px;
+    border-radius: $border-radius;
+    background-color: $bg-secondary;
+    text-align: center;
+    transition: $transition;
+    
+    &:hover {
+      transform: translateY(-2px);
+      box-shadow: $shadow-md;
+    }
+    
+    .stat-value {
+      font-size: 24px;
+      font-weight: 700;
+      color: $text-primary;
+      margin-bottom: 4px;
+    }
+    
+    .stat-label {
+      font-size: 14px;
+      color: $text-secondary;
+    }
+    
+    .stat-rate {
+      font-size: 12px;
+      color: $success-color;
+      margin-top: 4px;
+    }
+    
+    &.warning {
+      background-color: rgba($warning-color, 0.1);
+      .stat-value { color: $warning-color; }
+    }
+    
+    &.danger {
+      background-color: rgba($error-color, 0.1);
+      .stat-value { color: $error-color; }
+    }
+    
+    &.info {
+      background-color: rgba($info-color, 0.1);
+      .stat-value { color: $info-color; }
+    }
+    
+    &.primary {
+      background-color: rgba($primary-color, 0.1);
+      .stat-value { color: $primary-color; }
+    }
+  }
+}
+
+// 甘特图区域
+.gantt-section {
+  background-color: $bg-primary;
+  border-radius: $border-radius;
+  box-shadow: $shadow-sm;
+  padding: 24px;
+  margin-top: 24px;
+  
+  .gantt-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+    
+    h2 {
+      font-size: 20px;
+      font-weight: 600;
+      color: $text-primary;
+      margin: 0;
+    }
+    
+    .gantt-controls {
+      display: flex;
+      gap: 8px;
+      background-color: $bg-tertiary;
+      border-radius: $border-radius;
+      padding: 4px;
+      
+      .scale-btn {
+        padding: 8px 16px;
+        border-radius: $border-radius;
+        font-size: 14px;
+        font-weight: 500;
+        transition: $transition;
+        border: none;
+        cursor: pointer;
+        
+        &.active {
+          background-color: $primary-color;
+          color: white;
+        }
+        
+        &:not(.active) {
+          background-color: transparent;
+          color: $text-secondary;
+          
+          &:hover {
+            background-color: $bg-secondary;
+            color: $text-primary;
+          }
+        }
+      }
+    }
+  }
+  
+  .gantt-chart {
+    width: 100%;
+    height: 500px;
+    min-height: 400px;
+    border-radius: $border-radius;
+    background-color: $bg-secondary;
+    border: 1px solid $border-color;
+  }
+  
+  .gantt-legend {
+    display: flex;
+    gap: 24px;
+    margin-top: 20px;
+    padding-top: 20px;
+    border-top: 1px solid $border-color;
+    
+    .legend-item {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      font-size: 14px;
+      color: $text-secondary;
+      
+      .legend-color {
+        width: 16px;
+        height: 16px;
+        border-radius: 4px;
+      }
+    }
+  }
+}
 
   .section-header {
     margin-bottom: 20px;
@@ -338,7 +540,6 @@ $transition: all 0.2s ease;
       }
     }
   }
-}
 
 // 右侧:统计图表和异常列表
 .stats-section {

+ 295 - 4
src/app/pages/hr/attendance/attendance.ts

@@ -1,4 +1,4 @@
-import { Component, OnInit, signal, computed, Inject } from '@angular/core';
+import { Component, OnInit, signal, computed, Inject, ViewChild, ElementRef, OnDestroy } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
 import { MatButtonModule } from '@angular/material/button';
@@ -9,6 +9,7 @@ import { MatCardModule } from '@angular/material/card';
 import { MatTooltipModule } from '@angular/material/tooltip';
 import { MatDialogModule, MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { Attendance as AttendanceModel, Employee } from '../../../models/hr.model';
+import * as echarts from 'echarts';
 
 // 补卡申请对话框组件
 @Component({
@@ -251,7 +252,11 @@ const generateMockEmployees = (): Employee[] => {
   ],
   templateUrl: './attendance.html',
   styleUrl: './attendance.scss'
-}) export class Attendance implements OnInit {
+}) export class Attendance implements OnDestroy, OnInit {
+  @ViewChild('ganttChartRef') ganttChartRef!: ElementRef;
+  private ganttChart: any = null;
+  showGanttView = signal(false);
+  ganttScale = signal<'week' | 'month'>('week');
   // 数据
   attendanceData = signal<AttendanceModel[]>([]);
   employees = signal<Employee[]>([]);
@@ -416,10 +421,40 @@ const generateMockEmployees = (): Employee[] => {
     this.attendanceData.set(generateMockAttendanceData());
     this.employees.set(generateMockEmployees());
   }
+
+  ngOnDestroy() {
+    if (this.ganttChart) {
+      this.ganttChart.dispose();
+      this.ganttChart = null;
+    }
+  }
   
   // 切换视图(日/周/月)
   switchView(view: 'day' | 'week' | 'month') {
     this.selectedView.set(view);
+    // 重置到当前日期
+    this.selectedDate.set(new Date());
+  }
+
+  // 切换视图(考勤/任务)
+  toggleView() {
+    this.showGanttView.set(!this.showGanttView());
+    if (this.showGanttView()) {
+      setTimeout(() => this.initOrUpdateGantt(), 0);
+    } else {
+      if (this.ganttChart) {
+        this.ganttChart.dispose();
+        this.ganttChart = null;
+      }
+    }
+  }
+
+  // 设置甘特时间尺度
+  setGanttScale(scale: 'week' | 'month') {
+    if (this.ganttScale() !== scale) {
+      this.ganttScale.set(scale);
+      this.updateGantt();
+    }
   }
   
   // 获取员工姓名
@@ -497,8 +532,47 @@ const generateMockEmployees = (): Employee[] => {
   }
   
   // 导出考勤数据
-  exportAttendanceData() {
-    alert('考勤数据导出功能待实现');
+  exportAttendanceData(): void {
+    const data = this.filteredAttendance();
+    const csvContent = this.convertToCSV(data);
+    this.downloadCSV(csvContent, '考勤数据.csv');
+  }
+
+  // 将数据转换为CSV格式
+  private convertToCSV(data: any[]): string {
+    if (data.length === 0) return '';
+    
+    const headers = ['员工ID', '员工姓名', '日期', '上班时间', '下班时间', '状态', '工作时长', '所属项目'];
+    const rows = data.map(item => {
+      const employee = this.employees().find(emp => emp.id === item.employeeId);
+      return [
+        item.employeeId,
+        employee ? employee.name : '未知员工',
+        this.formatDate(item.date),
+        item.checkInTime ? this.formatTime(item.checkInTime) : '',
+        item.checkOutTime ? this.formatTime(item.checkOutTime) : '',
+        item.status,
+        item.workHours || '',
+        item.projectName
+      ];
+    });
+    
+    return [headers, ...rows].map(row => row.map(field => `"${field}"`).join(',')).join('\n');
+  }
+
+  // 下载CSV文件
+  private downloadCSV(csvContent: string, filename: string): void {
+    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
+    const link = document.createElement('a');
+    const url = URL.createObjectURL(blob);
+    
+    link.setAttribute('href', url);
+    link.setAttribute('download', filename);
+    link.style.visibility = 'hidden';
+    
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link);
   }
   
   // 获取日历数据
@@ -565,4 +639,221 @@ const generateMockEmployees = (): Employee[] => {
     const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
     return weekdays[index];
   }
+
+  private initOrUpdateGantt(): void {
+    if (!this.ganttChartRef) return;
+    const el = this.ganttChartRef.nativeElement;
+    if (!this.ganttChart) {
+      this.ganttChart = echarts.init(el);
+      window.addEventListener('resize', () => {
+        this.ganttChart && this.ganttChart.resize();
+      });
+    }
+    this.updateGantt();
+  }
+
+  private updateGantt(): void {
+    if (!this.ganttChart) return;
+
+    // 生成甘特图数据 - 模拟订单任务数据
+    const tasks = [
+      {
+        name: '需求补充',
+        startDate: new Date(2024, 4, 1), // 2024-05-01
+        endDate: new Date(2024, 4, 5),   // 2024-05-05
+        progress: 33,
+        employee: '张三',
+        unfinishedItems: ['图纸上传(2/3)', '设计文档(0/1)', '客户确认(0/1)']
+      },
+      {
+        name: '方案设计',
+        startDate: new Date(2024, 4, 3),
+        endDate: new Date(2024, 4, 8),
+        progress: 75,
+        employee: '李四',
+        unfinishedItems: ['效果图(3/4)', '材料清单(1/1)']
+      },
+      {
+        name: '施工图绘制',
+        startDate: new Date(2024, 4, 6),
+        endDate: new Date(2024, 4, 12),
+        progress: 50,
+        employee: '王五',
+        unfinishedItems: ['平面图(1/2)', '立面图(2/4)', '节点图(0/3)']
+      },
+      {
+        name: '预算编制',
+        startDate: new Date(2024, 4, 10),
+        endDate: new Date(2024, 4, 15),
+        progress: 100,
+        employee: '赵六',
+        unfinishedItems: []
+      }
+    ];
+
+    const categories = tasks.map(t => t.name);
+    const DAY = 24 * 60 * 60 * 1000;
+
+    const data = tasks.map((task, idx) => {
+      const start = task.startDate.getTime();
+      const end = task.endDate.getTime();
+      const progress = task.progress;
+      
+      return {
+        name: task.name,
+        value: [idx, start, end, task.employee, progress, task.unfinishedItems],
+        itemStyle: {
+        color: task?.progress === 100 ? '#22c55e' : (task?.progress && task.progress >= 75) ? '#f59e0b' : '#ef4444'
+      }
+      };
+    });
+
+    // 计算时间范围
+    const now = new Date();
+    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+    const todayTs = today.getTime();
+
+    let xMin: number;
+    let xMax: number;
+    let xSplitNumber: number;
+    let xLabelFormatter: (value: number) => string;
+
+    if (this.ganttScale() === 'week') {
+      const day = today.getDay();
+      const diffToMonday = (day === 0 ? 6 : day - 1);
+      const startOfWeek = new Date(today.getTime() - diffToMonday * DAY);
+      const endOfWeek = new Date(startOfWeek.getTime() + 7 * DAY - 1);
+      xMin = startOfWeek.getTime();
+      xMax = endOfWeek.getTime();
+      xSplitNumber = 7;
+      const WEEK_LABELS = ['周日','周一','周二','周三','周四','周五','周六'];
+      xLabelFormatter = (val) => WEEK_LABELS[new Date(val).getDay()];
+    } else {
+      const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
+      const endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0, 23, 59, 59, 999);
+      xMin = startOfMonth.getTime();
+      xMax = endOfMonth.getTime();
+      xSplitNumber = 4;
+      xLabelFormatter = (val) => `第${Math.ceil(new Date(val).getDate() / 7)}周`;
+    }
+
+    const option = {
+      backgroundColor: 'transparent',
+      tooltip: {
+        trigger: 'item',
+        formatter: (params: any) => {
+          const v = params.value;
+          const start = new Date(v[1]);
+          const end = new Date(v[2]);
+          const progress = v[4];
+          const unfinished = v[5];
+          let html = `任务:${params.name}<br/>负责人:${v[3]}<br/>进度:${progress}%<br/>起止:${start.toLocaleDateString()} ~ ${end.toLocaleDateString()}`;
+          
+          if (unfinished.length > 0) {
+            html += '<br/><br/>未完成项:<br/>' + unfinished.join('<br/>');
+          }
+          return html;
+        }
+      },
+      grid: { left: 100, right: 64, top: 30, bottom: 30 },
+      xAxis: {
+        type: 'time',
+        min: xMin,
+        max: xMax,
+        splitNumber: xSplitNumber,
+        axisLine: { lineStyle: { color: '#e5e7eb' } },
+        axisLabel: { color: '#6b7280', formatter: xLabelFormatter },
+        splitLine: { lineStyle: { color: '#f1f5f9' } }
+      },
+      yAxis: {
+        type: 'category',
+        data: categories,
+        inverse: true,
+        axisLabel: {
+          color: '#374151',
+          margin: 8,
+          formatter: (val: string) => {
+            const task = tasks.find(t => t.name === val);
+            const color = task?.progress === 100 ? '#22c55e' : (task?.progress && task.progress >= 75) ? '#f59e0b' : '#ef4444';
+            const text = val.length > 16 ? val.slice(0, 16) + '…' : val;
+            return `{dot|●} ${text}`;
+          },
+          rich: {
+            dot: { color: '#ef4444' }
+          }
+        },
+        axisTick: { show: false },
+        axisLine: { lineStyle: { color: '#e5e7eb' } }
+      },
+      dataZoom: [
+        { type: 'slider', yAxisIndex: 0, orient: 'vertical', right: 6, width: 14, start: 0, end: 100, zoomLock: false },
+        { type: 'inside', yAxisIndex: 0, zoomOnMouseWheel: true, moveOnMouseMove: true, moveOnMouseWheel: true }
+      ],
+      series: [
+        {
+          type: 'custom',
+          renderItem: (params: any, api: any) => {
+            const categoryIndex = api.value(0);
+            const start = api.coord([api.value(1), categoryIndex]);
+            const end = api.coord([api.value(2), categoryIndex]);
+            const height = Math.max(api.size([0, 1])[1] * 0.5, 8);
+            
+            // 主进度条
+            const rectShape = echarts.graphic.clipRectByRect({
+              x: start[0],
+              y: start[1] - height / 2,
+              width: Math.max(end[0] - start[0], 2),
+              height
+            }, {
+              x: params.coordSys.x,
+              y: params.coordSys.y,
+              width: params.coordSys.width,
+              height: params.coordSys.height
+            });
+
+            // 进度指示条
+            const progress = api.value(4);
+            const progressWidth = Math.max((end[0] - start[0]) * (progress / 100), 2);
+            const progressShape = echarts.graphic.clipRectByRect({
+              x: start[0],
+              y: start[1] - height / 2,
+              width: progressWidth,
+              height
+            }, {
+              x: params.coordSys.x,
+              y: params.coordSys.y,
+              width: params.coordSys.width,
+              height: params.coordSys.height
+            });
+
+            return {
+              type: 'group',
+              children: [
+                {
+                  type: 'rect',
+                  shape: rectShape,
+                  style: {
+                    fill: 'rgba(0,0,0,0.1)',
+                    stroke: 'transparent'
+                  }
+                },
+                {
+                  type: 'rect',
+                  shape: progressShape,
+                  style: api.style()
+                }
+              ]
+            };
+          },
+          encode: { x: [1, 2], y: 0 },
+          data,
+          itemStyle: { borderRadius: 4 },
+          emphasis: { focus: 'self' }
+        }
+      ]
+    };
+
+    this.ganttChart.setOption(option, true);
+    this.ganttChart.resize();
+  }
 }

+ 849 - 58
src/app/pages/hr/dashboard/dashboard.html

@@ -12,11 +12,19 @@
       </button>
       <button 
         mat-raised-button 
-        [class.active]="activeTab === 'promotion'"
-        (click)="switchTab('promotion')"
+        [class.active]="activeTab === 'recruitment'"
+        (click)="switchTab('recruitment')"
         class="nav-button">
-        <mat-icon>trending_up</mat-icon>
-        职级与晋升管理
+        <mat-icon>psychology</mat-icon>
+        招聘流程优化
+      </button>
+      <button 
+        mat-raised-button 
+        [class.active]="activeTab === 'performance'"
+        (click)="switchTab('performance')"
+        class="nav-button">
+        <mat-icon>assessment</mat-icon>
+        绩效统计与分析
       </button>
       <button 
         mat-raised-button 
@@ -26,6 +34,15 @@
         <mat-icon>person_add</mat-icon>
         新人跟进管理
       </button>
+      <!-- 晋升规则圆圈按钮 -->
+      <button 
+        mat-fab 
+        color="primary"
+        (click)="openPromotionRules()"
+        class="promotion-rules-btn"
+        matTooltip="晋升规则">
+        <mat-icon>rule</mat-icon>
+      </button>
     </div>
   </div>
 
@@ -192,79 +209,853 @@
             </mat-card-content>
           </mat-card>
         </div>
-      </div>
-    </div>
-  }
 
-  <!-- 职级与晋升管理页面 -->
-  @if (activeTab === 'promotion') {
-    <div class="promotion-page">
-      <div class="content-layout">
-        <!-- 晋升规则卡片 -->
-        <div class="promotion-rules-section">
-          <mat-card class="rules-card">
+        <!-- 离职原因分析区域 -->
+        <div class="resignation-analysis-section">
+          <mat-card class="analysis-card">
             <mat-card-header>
               <mat-card-title>
-                <mat-icon>rule</mat-icon>
-                晋升规则
+                <mat-icon>exit_to_app</mat-icon>
+                离职原因分析
               </mat-card-title>
+              <div class="analysis-actions">
+                <mat-form-field appearance="outline" class="time-range-selector">
+                  <mat-label>时间范围</mat-label>
+                  <mat-select [(value)]="resignationTimeRange" (selectionChange)="updateResignationData()">
+                    <mat-option value="month">近一个月</mat-option>
+                    <mat-option value="quarter">近一季度</mat-option>
+                    <mat-option value="year">近一年</mat-option>
+                    <mat-option value="all">全部时间</mat-option>
+                  </mat-select>
+                </mat-form-field>
+                
+                <button mat-stroked-button class="export-analysis-btn" (click)="exportResignationAnalysis()">
+                  <mat-icon>download</mat-icon>
+                  导出分析
+                </button>
+              </div>
             </mat-card-header>
+            
             <mat-card-content>
-              @for (rule of promotionRules; track rule.id) {
-                <div class="rule-item">
-                  <h4 class="rule-title">{{rule.title}}</h4>
-                  <p class="rule-description">{{rule.description}}</p>
-                  <div class="rule-conditions">
-                    @for (condition of rule.conditions; track condition) {
-                      <mat-chip class="condition-chip">{{condition}}</mat-chip>
+              <!-- 分类筛选器 -->
+              <div class="category-filters">
+                <div class="filter-group">
+                  <label>部门筛选:</label>
+                  <mat-chip-set>
+                    @for (dept of resignationDepartments; track dept.id) {
+                      <mat-chip 
+                        (click)="toggleDepartmentFilter(dept.id)"
+                        [class.selected]="dept.selected">
+                        {{ dept.name }}
+                        <span class="count">({{ dept.count }})</span>
+                      </mat-chip>
+                    }
+                  </mat-chip-set>
+                </div>
+                
+                <div class="filter-group">
+                  <label>职级筛选:</label>
+                  <mat-chip-set>
+                    @for (level of resignationLevels; track level.id) {
+                      <mat-chip 
+                        (click)="toggleLevelFilter(level.id)"
+                        [class.selected]="level.selected">
+                        {{ level.name }}
+                        <span class="count">({{ level.count }})</span>
+                      </mat-chip>
                     }
+                  </mat-chip-set>
+                </div>
+              </div>
+
+              <!-- 统计概览 -->
+              <div class="resignation-overview">
+                <div class="overview-cards">
+                  <div class="overview-card total">
+                    <div class="card-icon">
+                      <mat-icon>people</mat-icon>
+                    </div>
+                    <div class="card-content">
+                      <div class="card-value">{{ totalResignations }}</div>
+                      <div class="card-label">总离职人数</div>
+                    </div>
+                  </div>
+                  
+                  <div class="overview-card rate">
+                    <div class="card-icon">
+                      <mat-icon>trending_up</mat-icon>
+                    </div>
+                    <div class="card-content">
+                      <div class="card-value">{{ resignationRate }}%</div>
+                      <div class="card-label">离职率</div>
+                    </div>
+                  </div>
+                  
+                  <div class="overview-card avg-tenure">
+                    <div class="card-icon">
+                      <mat-icon>schedule</mat-icon>
+                    </div>
+                    <div class="card-content">
+                      <div class="card-value">{{ averageTenure }}个月</div>
+                      <div class="card-label">平均在职时长</div>
+                    </div>
+                  </div>
+                  
+                  <div class="overview-card cost">
+                    <div class="card-icon">
+                      <mat-icon>attach_money</mat-icon>
+                    </div>
+                    <div class="card-content">
+                      <div class="card-value">{{ resignationCost }}万</div>
+                      <div class="card-label">离职成本</div>
+                    </div>
                   </div>
                 </div>
-              }
+              </div>
+
+              <!-- 离职原因分析 -->
+              <div class="resignation-reasons-analysis">
+                <div class="reasons-chart-section">
+                  <div class="chart-header">
+                    <h3>离职原因占比分析</h3>
+                    <mat-button-toggle-group [(value)]="reasonsChartType">
+                      <mat-button-toggle value="pie">
+                        <mat-icon>pie_chart</mat-icon>
+                        饼图
+                      </mat-button-toggle>
+                      <mat-button-toggle value="doughnut">
+                        <mat-icon>donut_large</mat-icon>
+                        环形图
+                      </mat-button-toggle>
+                      <mat-button-toggle value="bar">
+                        <mat-icon>bar_chart</mat-icon>
+                        柱状图
+                      </mat-button-toggle>
+                    </mat-button-toggle-group>
+                  </div>
+                  
+                  <div class="chart-container">
+                    <canvas #resignationChart width="600" height="400"></canvas>
+                  </div>
+                </div>
+
+                <div class="reasons-list-section">
+                  <h3>详细原因分析</h3>
+                  <div class="reasons-list">
+                    @for (reason of resignationReasons; track reason.id) {
+                      <div class="reason-item" [class]="'reason-' + reason.category">
+                        <div class="reason-header">
+                          <div class="reason-info">
+                            <mat-icon [class]="'icon-' + reason.category">{{ reason.icon }}</mat-icon>
+                            <div class="reason-details">
+                              <h4>{{ reason.name }}</h4>
+                              <span class="reason-category">{{ reason.categoryName }}</span>
+                            </div>
+                          </div>
+                          <div class="reason-stats">
+                            <div class="percentage">{{ reason.percentage }}%</div>
+                            <div class="count">{{ reason.count }}人</div>
+                          </div>
+                        </div>
+                        
+                        <div class="reason-progress">
+                          <mat-progress-bar 
+                            mode="determinate" 
+                            [value]="reason.percentage"
+                            [class]="'progress-' + reason.category">
+                          </mat-progress-bar>
+                        </div>
+                        
+                        <div class="reason-description">
+                          <p>{{ reason.description }}</p>
+                          @if (reason.trend) {
+                            <div class="trend-indicator" [class]="'trend-' + reason.trend.direction">
+                              <mat-icon>{{ reason.trend.direction === 'up' ? 'trending_up' : 'trending_down' }}</mat-icon>
+                              <span>较上期{{ reason.trend.direction === 'up' ? '上升' : '下降' }}{{ reason.trend.value }}%</span>
+                            </div>
+                          }
+                        </div>
+                        
+                        <div class="reason-actions">
+                          <button mat-stroked-button (click)="viewReasonDetails(reason.id)">
+                            <mat-icon>visibility</mat-icon>
+                            查看详情
+                          </button>
+                          <button mat-stroked-button (click)="viewImprovementPlan(reason.id)">
+                            <mat-icon>lightbulb</mat-icon>
+                            改进建议
+                          </button>
+                        </div>
+                      </div>
+                    }
+                  </div>
+                </div>
+              </div>
+
+              <!-- 趋势分析 -->
+              <div class="resignation-trends">
+                <div class="trends-header">
+                  <h3>离职趋势分析</h3>
+                  <mat-button-toggle-group [(value)]="trendsTimeframe">
+                    <mat-button-toggle value="monthly">月度</mat-button-toggle>
+                    <mat-button-toggle value="quarterly">季度</mat-button-toggle>
+                    <mat-button-toggle value="yearly">年度</mat-button-toggle>
+                  </mat-button-toggle-group>
+                </div>
+                
+                <div class="trends-chart-container">
+                  <canvas #trendsChart width="800" height="300"></canvas>
+                </div>
+              </div>
             </mat-card-content>
           </mat-card>
         </div>
+      </div>
+    </div>
+  }
 
-        <!-- 部门绩效展示 -->
-        <div class="performance-section">
-          <mat-card class="performance-card">
-            <mat-card-header>
-              <mat-card-title>
-                <mat-icon>assessment</mat-icon>
-                部门绩效概览
-              </mat-card-title>
-            </mat-card-header>
-            <mat-card-content>
-              @for (dept of departmentPerformance; track dept.department) {
-                <div class="dept-performance-item">
-                  <div class="dept-header">
-                    <h4 class="dept-name">{{dept.department}}</h4>
-                    <div class="overall-score">{{dept.completionRate}}%</div>
+  <!-- 招聘流程优化页面 -->
+  @if (activeTab === 'recruitment') {
+    <div class="recruitment-page">
+      <div class="content-layout">
+        <!-- AI简历分析功能区 -->
+        <mat-card class="ai-analysis-section">
+          <mat-card-header>
+            <mat-card-title>
+              <mat-icon>smart_toy</mat-icon>
+              AI 简历分析
+            </mat-card-title>
+          </mat-card-header>
+          <mat-card-content>
+            <!-- 简历上传区域 -->
+            <div class="upload-area">
+              <div class="upload-zone" 
+                   (click)="uploadResume()"
+                   (dragover)="onDragOver($event)"
+                   (dragleave)="onDragLeave($event)"
+                   (drop)="onFileDrop($event)"
+                   [class.drag-over]="isDragOver">
+                <mat-icon class="upload-icon">cloud_upload</mat-icon>
+                <p class="upload-title">点击上传简历或拖拽文件到此处</p>
+                <p class="upload-hint">支持 PDF、DOC、DOCX 格式,最大 10MB</p>
+                <div class="upload-actions">
+                  <button mat-stroked-button color="primary">
+                    <mat-icon>folder_open</mat-icon>
+                    选择文件
+                  </button>
+                </div>
+              </div>
+            </div>
+            
+            <!-- 分析结果展示 -->
+            @if (showAnalysisResults) {
+              <div class="analysis-results">
+                <!-- 岗位匹配维度标签 -->
+                <div class="match-dimensions">
+                  <h4>
+                    <mat-icon>label</mat-icon>
+                    岗位匹配维度
+                  </h4>
+                  <div class="dimension-tags">
+                    @for (dimension of matchDimensions; track dimension.id) {
+                      <mat-chip-set>
+                        <mat-chip [class]="'match-level-' + dimension.level">
+                          <mat-icon>{{dimension.icon}}</mat-icon>
+                          {{dimension.name}}
+                          <span class="match-score">{{dimension.score}}%</span>
+                        </mat-chip>
+                      </mat-chip-set>
+                    }
                   </div>
-                  <div class="performance-metrics">
-                    <div class="metric">
-                      <span class="metric-label">项目完成率</span>
-                      <mat-progress-bar mode="determinate" [value]="dept.completionRate"></mat-progress-bar>
-                      <span class="metric-value">{{dept.completionRate}}%</span>
+                </div>
+
+                <!-- 推荐结论及原因说明 -->
+                <div class="recommendation-section">
+                  <h4>
+                    <mat-icon>psychology</mat-icon>
+                    推荐结论
+                  </h4>
+                  <div class="recommendation-card" [class]="'recommendation-' + recommendation.level">
+                    <div class="recommendation-header">
+                      <mat-icon>{{recommendation.icon}}</mat-icon>
+                      <span class="recommendation-title">{{recommendation.title}}</span>
+                      <mat-chip [class]="'level-' + recommendation.level">{{recommendation.levelText}}</mat-chip>
                     </div>
-                    <div class="metric">
-                      <span class="metric-label">优秀作品率</span>
-                      <mat-progress-bar mode="determinate" [value]="dept.excellentWorkRate"></mat-progress-bar>
-                      <span class="metric-value">{{dept.excellentWorkRate}}%</span>
+                    <div class="recommendation-content">
+                      <p class="recommendation-summary">{{recommendation.summary}}</p>
+                      <div class="recommendation-reasons">
+                        <h5>推荐原因:</h5>
+                        <ul>
+                          @for (reason of recommendation.reasons; track $index) {
+                            <li>{{reason}}</li>
+                          }
+                        </ul>
+                      </div>
+                      <div class="recommendation-concerns" *ngIf="recommendation.concerns.length > 0">
+                        <h5>需要关注:</h5>
+                        <ul>
+                          @for (concern of recommendation.concerns; track $index) {
+                            <li>{{concern}}</li>
+                          }
+                        </ul>
+                      </div>
                     </div>
-                    <div class="metric">
-                      <span class="metric-label">客户满意度</span>
-                      <mat-progress-bar mode="determinate" [value]="dept.satisfactionRate"></mat-progress-bar>
-                      <span class="metric-value">{{dept.satisfactionRate}}%</span>
+                  </div>
+                </div>
+
+                <!-- 简历初筛信息列表 -->
+                <div class="screening-info">
+                  <h4>
+                    <mat-icon>checklist</mat-icon>
+                    简历初筛信息
+                  </h4>
+                  <div class="screening-list">
+                    @for (item of screeningInfo; track item.id) {
+                      <div class="screening-item" [class]="'status-' + item.status">
+                        <div class="screening-icon">
+                          <mat-icon>{{item.icon}}</mat-icon>
+                        </div>
+                        <div class="screening-content">
+                          <div class="screening-title">{{item.title}}</div>
+                          <div class="screening-detail">{{item.detail}}</div>
+                        </div>
+                        <div class="screening-status">
+                          <mat-chip [class]="'status-' + item.status">{{item.statusText}}</mat-chip>
+                        </div>
+                      </div>
+                    }
+                  </div>
+                </div>
+              </div>
+            }
+          </mat-card-content>
+        </mat-card>
+
+        <!-- 招聘流程跟踪 -->
+        <mat-card class="recruitment-stages">
+          <mat-card-header>
+            <mat-card-title>
+              <mat-icon>timeline</mat-icon>
+              招聘流程跟踪
+            </mat-card-title>
+            <div class="stage-actions">
+              <button mat-icon-button (click)="refreshRecruitmentData()">
+                <mat-icon>refresh</mat-icon>
+              </button>
+            </div>
+          </mat-card-header>
+          <mat-card-content>
+            <div class="stages-timeline">
+              @for (stage of recruitmentStages; track stage.id) {
+                <div class="timeline-item" [class]="'status-' + stage.status" (click)="openStageDetails(stage)">
+                  <div class="timeline-marker">
+                    <mat-icon>{{stage.icon}}</mat-icon>
+                  </div>
+                  <div class="timeline-content">
+                    <div class="stage-header">
+                      <h5>{{stage.title}}</h5>
+                      <mat-chip [class]="'status-' + stage.status">{{stage.statusText}}</mat-chip>
                     </div>
-                    <div class="metric">
-                      <span class="metric-label">逾期率</span>
-                      <mat-progress-bar mode="determinate" [value]="dept.overdueRate" color="warn"></mat-progress-bar>
-                      <span class="metric-value">{{dept.overdueRate}}%</span>
+                    <div class="stage-stats">
+                      <div class="stat-item">
+                        <mat-icon>people</mat-icon>
+                        <span>{{stage.candidateCount}}人</span>
+                      </div>
+                      <div class="stat-item">
+                        <mat-icon>percent</mat-icon>
+                        <span>通过率 {{stage.passRate}}%</span>
+                      </div>
+                    </div>
+                    <div class="stage-details">
+                      <div class="detail-row">
+                        <span class="label">评估人:</span>
+                        <span class="value">{{stage.evaluator || '待分配'}}</span>
+                      </div>
+                      <div class="detail-row">
+                        <span class="label">最近更新:</span>
+                        <span class="value">{{stage.lastUpdate | date:'MM-dd HH:mm'}}</span>
+                      </div>
+                      @if (stage.nextAction) {
+                        <div class="detail-row next-action">
+                          <mat-icon>arrow_forward</mat-icon>
+                          <span>{{stage.nextAction}}</span>
+                        </div>
+                      }
                     </div>
                   </div>
+                  <div class="timeline-connector" *ngIf="!$last"></div>
                 </div>
               }
+            </div>
+
+            <!-- 试用期跟踪关联入口 -->
+            <div class="probation-link-section">
+              <mat-card class="probation-link-card">
+                <mat-card-content>
+                  <div class="link-header">
+                    <mat-icon>link</mat-icon>
+                    <h4>试用期跟踪</h4>
+                  </div>
+                  <p>已入职员工的试用期跟踪与绩效管理</p>
+                  <div class="link-actions">
+                    <button mat-raised-button color="primary" (click)="navigateToOnboarding()">
+                      <mat-icon>person_add</mat-icon>
+                      查看新人跟进
+                    </button>
+                    <button mat-stroked-button (click)="viewProbationReports()">
+                      <mat-icon>assessment</mat-icon>
+                      试用期报告
+                    </button>
+                  </div>
+                </mat-card-content>
+              </mat-card>
+            </div>
+          </mat-card-content>
+        </mat-card>
+      </div>
+    </div>
+  }
+
+  <!-- 绩效统计与分析页面 -->
+  @if (activeTab === 'performance') {
+    <div class="performance-page">
+      <div class="content-layout">
+        <!-- 筛选控件 -->
+        <mat-card class="filter-section ios-style">
+          <mat-card-header>
+            <mat-card-title>
+              <mat-icon>tune</mat-icon>
+              筛选条件
+            </mat-card-title>
+            <div class="filter-actions">
+              <button mat-icon-button (click)="resetFilters()" matTooltip="重置筛选">
+                <mat-icon>refresh</mat-icon>
+              </button>
+            </div>
+          </mat-card-header>
+          <mat-card-content>
+            <div class="filter-controls ios-filters">
+              <div class="filter-group">
+                <label class="filter-label">部门</label>
+                <mat-form-field appearance="outline" class="ios-select">
+                  <mat-select [(value)]="selectedDepartment" (selectionChange)="onDepartmentChange($event)">
+                    <mat-option value="">
+                      <div class="option-content">
+                        <mat-icon>business</mat-icon>
+                        <span>全部部门</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="design">
+                      <div class="option-content">
+                        <mat-icon>palette</mat-icon>
+                        <span>设计部</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="dev">
+                      <div class="option-content">
+                        <mat-icon>code</mat-icon>
+                        <span>开发部</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="product">
+                      <div class="option-content">
+                        <mat-icon>inventory</mat-icon>
+                        <span>产品部</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="marketing">
+                      <div class="option-content">
+                        <mat-icon>campaign</mat-icon>
+                        <span>市场部</span>
+                      </div>
+                    </mat-option>
+                  </mat-select>
+                </mat-form-field>
+              </div>
+              
+              <div class="filter-group">
+                <label class="filter-label">职级</label>
+                <mat-form-field appearance="outline" class="ios-select">
+                  <mat-select [(value)]="selectedLevel" (selectionChange)="onLevelChange($event)">
+                    <mat-option value="">
+                      <div class="option-content">
+                        <mat-icon>work</mat-icon>
+                        <span>全部职级</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="junior">
+                      <div class="option-content">
+                        <mat-icon>person</mat-icon>
+                        <span>初级</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="middle">
+                      <div class="option-content">
+                        <mat-icon>person_outline</mat-icon>
+                        <span>中级</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="senior">
+                      <div class="option-content">
+                        <mat-icon>supervisor_account</mat-icon>
+                        <span>高级</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="lead">
+                      <div class="option-content">
+                        <mat-icon>manage_accounts</mat-icon>
+                        <span>主管</span>
+                      </div>
+                    </mat-option>
+                  </mat-select>
+                </mat-form-field>
+              </div>
+              
+              <div class="filter-group">
+                <label class="filter-label">入职时间</label>
+                <mat-form-field appearance="outline" class="ios-select">
+                  <mat-select [(value)]="selectedTimeRange" (selectionChange)="onTimeRangeChange($event)">
+                    <mat-option value="month">
+                      <div class="option-content">
+                        <mat-icon>today</mat-icon>
+                        <span>本月</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="quarter">
+                      <div class="option-content">
+                        <mat-icon>date_range</mat-icon>
+                        <span>本季度</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="half-year">
+                      <div class="option-content">
+                        <mat-icon>event</mat-icon>
+                        <span>半年内</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="year">
+                      <div class="option-content">
+                        <mat-icon>calendar_today</mat-icon>
+                        <span>本年度</span>
+                      </div>
+                    </mat-option>
+                    <mat-option value="all">
+                      <div class="option-content">
+                        <mat-icon>all_inclusive</mat-icon>
+                        <span>全部时间</span>
+                      </div>
+                    </mat-option>
+                  </mat-select>
+                </mat-form-field>
+              </div>
+              
+              <div class="filter-actions-group">
+                <button mat-raised-button color="primary" class="ios-button primary" (click)="applyFilters()" [disabled]="isFilterLoading">
+                  @if (isFilterLoading) {
+                    <div class="loading-spinner"></div>
+                  } @else {
+                    <mat-icon>search</mat-icon>
+                  }
+                  <span>{{ isFilterLoading ? '筛选中...' : '应用筛选' }}</span>
+                </button>
+                
+                <button mat-stroked-button class="ios-button secondary" (click)="exportData()" [disabled]="isFilterLoading">
+                  <mat-icon>download</mat-icon>
+                  <span>导出数据</span>
+                </button>
+              </div>
+            </div>
+            
+            <!-- 快速筛选标签 -->
+            <div class="quick-filters">
+              <span class="quick-filter-label">快速筛选:</span>
+              <div class="quick-filter-chips">
+                <mat-chip-set>
+                  <mat-chip (click)="applyQuickFilter('high-performers')" [class.selected]="quickFilter === 'high-performers'">
+                    <mat-icon>star</mat-icon>
+                    高绩效员工
+                  </mat-chip>
+                  <mat-chip (click)="applyQuickFilter('new-employees')" [class.selected]="quickFilter === 'new-employees'">
+                    <mat-icon>person_add</mat-icon>
+                    新入职员工
+                  </mat-chip>
+                  <mat-chip (click)="applyQuickFilter('at-risk')" [class.selected]="quickFilter === 'at-risk'">
+                    <mat-icon>warning</mat-icon>
+                    风险员工
+                  </mat-chip>
+                  <mat-chip (click)="applyQuickFilter('promotion-ready')" [class.selected]="quickFilter === 'promotion-ready'">
+                    <mat-icon>trending_up</mat-icon>
+                    晋升候选
+                  </mat-chip>
+                </mat-chip-set>
+              </div>
+            </div>
+          </mat-card-content>
+        </mat-card>
+
+        <!-- 绩效指标展示 -->
+        <div class="performance-metrics-container">
+          <div class="metrics-header">
+            <h2>核心绩效指标</h2>
+            <div class="metrics-actions">
+              <button mat-icon-button class="refresh-btn" (click)="refreshMetrics()">
+                <mat-icon>refresh</mat-icon>
+              </button>
+              <button mat-stroked-button class="export-btn" (click)="exportMetrics()">
+                <mat-icon>file_download</mat-icon>
+                导出报告
+              </button>
+            </div>
+          </div>
+          
+          <div class="performance-metrics-grid">
+            @for (metric of performanceMetrics; track metric.id) {
+              <mat-card class="metric-card" [class]="metric.status">
+                <mat-card-content>
+                  <div class="metric-icon-wrapper">
+                    <mat-icon [class]="metric.iconClass">{{ metric.icon }}</mat-icon>
+                  </div>
+                  
+                  <div class="metric-content">
+                    <div class="metric-header">
+                      <h3>{{ metric.title }}</h3>
+                      <span class="metric-period">{{ metric.period }}</span>
+                    </div>
+                    
+                    <div class="metric-value-section">
+                      <div class="metric-value">{{ metric.value }}</div>
+                      <div class="metric-unit">{{ metric.unit }}</div>
+                    </div>
+                    
+                    <div class="metric-trend" [class]="metric.trend.type">
+                      <mat-icon>{{ metric.trend.icon }}</mat-icon>
+                      <span>{{ metric.trend.value }}</span>
+                      <span class="trend-label">{{ metric.trend.label }}</span>
+                    </div>
+                    
+                    <div class="metric-details">
+                      <div class="detail-item">
+                        <span class="detail-label">目标值:</span>
+                        <span class="detail-value">{{ metric.target }}</span>
+                      </div>
+                      <div class="detail-item">
+                        <span class="detail-label">达成率:</span>
+                        <span class="detail-value" [class]="metric.achievementClass">{{ metric.achievement }}</span>
+                      </div>
+                    </div>
+                    
+                    <div class="metric-progress">
+                      <mat-progress-bar 
+                        mode="determinate" 
+                        [value]="metric.progressValue"
+                        [class]="metric.progressClass">
+                      </mat-progress-bar>
+                    </div>
+                  </div>
+                  
+                  <div class="metric-actions">
+                    <button mat-icon-button class="detail-btn" (click)="viewMetricDetails(metric.id)">
+                      <mat-icon>visibility</mat-icon>
+                    </button>
+                    <button mat-icon-button class="trend-btn" (click)="viewMetricTrend(metric.id)">
+                      <mat-icon>show_chart</mat-icon>
+                    </button>
+                  </div>
+                </mat-card-content>
+              </mat-card>
+            }
+          </div>
+        </div>
+
+        <!-- 绩效对比表 -->
+        <div class="performance-comparison-section">
+          <mat-card class="comparison-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>compare_arrows</mat-icon>
+                绩效对比分析
+              </mat-card-title>
+              <div class="comparison-actions">
+                <mat-button-toggle-group [(value)]="comparisonMode" (change)="onComparisonModeChange($event)">
+                  <mat-button-toggle value="horizontal">
+                    <mat-icon>view_column</mat-icon>
+                    横向对比
+                  </mat-button-toggle>
+                  <mat-button-toggle value="vertical">
+                    <mat-icon>view_agenda</mat-icon>
+                    纵向对比
+                  </mat-button-toggle>
+                </mat-button-toggle-group>
+                
+                <button mat-stroked-button class="add-comparison-btn" (click)="addComparisonItem()">
+                  <mat-icon>add</mat-icon>
+                  添加对比项
+                </button>
+              </div>
+            </mat-card-header>
+            
+            <mat-card-content>
+              <!-- 对比选择器 -->
+              <div class="comparison-selectors">
+                <div class="selector-group">
+                  <label>对比维度:</label>
+                  <mat-form-field appearance="outline">
+                    <mat-select [(value)]="selectedComparisonDimension" (selectionChange)="updateComparison()">
+                      <mat-option value="department">部门对比</mat-option>
+                      <mat-option value="period">时期对比</mat-option>
+                      <mat-option value="individual">个人对比</mat-option>
+                      <mat-option value="project">项目对比</mat-option>
+                    </mat-select>
+                  </mat-form-field>
+                </div>
+                
+                <div class="selector-group">
+                  <label>对比指标:</label>
+                  <mat-form-field appearance="outline">
+                    <mat-select [(value)]="selectedComparisonMetric" multiple (selectionChange)="updateComparison()">
+                      <mat-option value="completion">完成率</mat-option>
+                      <mat-option value="quality">质量评分</mat-option>
+                      <mat-option value="efficiency">效率指数</mat-option>
+                      <mat-option value="satisfaction">满意度</mat-option>
+                      <mat-option value="innovation">创新度</mat-option>
+                    </mat-select>
+                  </mat-form-field>
+                </div>
+              </div>
+
+              <!-- 横向对比表格 -->
+              @if (comparisonMode === 'horizontal') {
+                <div class="horizontal-comparison">
+                  <table mat-table [dataSource]="horizontalComparisonData" class="comparison-table">
+                    <!-- 名称列 -->
+                    <ng-container matColumnDef="name">
+                      <th mat-header-cell *matHeaderCellDef>对比项目</th>
+                      <td mat-cell *matCellDef="let element">
+                        <div class="comparison-item-name">
+                          <mat-icon [class]="element.iconClass">{{ element.icon }}</mat-icon>
+                          <span>{{ element.name }}</span>
+                        </div>
+                      </td>
+                    </ng-container>
+
+                    <!-- 动态指标列 -->
+                    @for (metric of selectedComparisonMetric; track metric) {
+                      <ng-container [matColumnDef]="metric">
+                        <th mat-header-cell *matHeaderCellDef>{{ getMetricDisplayName(metric) }}</th>
+                        <td mat-cell *matCellDef="let element">
+                          <div class="metric-cell">
+                            <span class="metric-value" [class]="getMetricClass(element[metric])">
+                              {{ element[metric] }}
+                            </span>
+                            <div class="metric-bar">
+                              <div class="bar-fill" [style.width.%]="getMetricPercentage(element[metric], metric)"></div>
+                            </div>
+                          </div>
+                        </td>
+                      </ng-container>
+                    }
+
+                    <!-- 操作列 -->
+                    <ng-container matColumnDef="actions">
+                      <th mat-header-cell *matHeaderCellDef>操作</th>
+                      <td mat-cell *matCellDef="let element">
+                        <button mat-icon-button (click)="viewComparisonDetails(element.id)">
+                          <mat-icon>visibility</mat-icon>
+                        </button>
+                        <button mat-icon-button (click)="removeComparisonItem(element.id)">
+                          <mat-icon>delete</mat-icon>
+                        </button>
+                      </td>
+                    </ng-container>
+
+                    <tr mat-header-row *matHeaderRowDef="horizontalDisplayedColumns"></tr>
+                    <tr mat-row *matRowDef="let row; columns: horizontalDisplayedColumns;"></tr>
+                  </table>
+                </div>
+              }
+
+              <!-- 纵向对比卡片 -->
+              @if (comparisonMode === 'vertical') {
+                <div class="vertical-comparison">
+                  @for (item of verticalComparisonData; track item.id) {
+                    <mat-card class="comparison-item-card">
+                      <mat-card-header>
+                        <div class="comparison-item-header">
+                          <mat-icon [class]="item.iconClass">{{ item.icon }}</mat-icon>
+                          <div class="item-info">
+                            <h3>{{ item.name }}</h3>
+                            <span class="item-category">{{ item.category }}</span>
+                          </div>
+                        </div>
+                        <div class="item-actions">
+                          <button mat-icon-button (click)="viewComparisonDetails(item.id)">
+                            <mat-icon>visibility</mat-icon>
+                          </button>
+                          <button mat-icon-button (click)="removeComparisonItem(item.id)">
+                            <mat-icon>delete</mat-icon>
+                          </button>
+                        </div>
+                      </mat-card-header>
+                      
+                      <mat-card-content>
+                        <div class="metrics-grid">
+                          @for (metric of selectedComparisonMetric; track metric) {
+                            <div class="metric-item">
+                              <div class="metric-label">{{ getMetricDisplayName(metric) }}</div>
+                              <div class="metric-value-container">
+                                <span class="metric-value" [class]="getMetricClass(item[metric])">
+                                  {{ item[metric] }}
+                                </span>
+                                <mat-progress-bar 
+                                  mode="determinate" 
+                                  [value]="getMetricPercentage(item[metric], metric)"
+                                  [class]="getProgressBarClass(item[metric])">
+                                </mat-progress-bar>
+                              </div>
+                            </div>
+                          }
+                        </div>
+                        
+                        <div class="comparison-summary">
+                          <div class="summary-item">
+                            <span class="summary-label">综合评分:</span>
+                            <span class="summary-value" [class]="getOverallScoreClass(item.overallScore)">
+                              {{ item.overallScore }}分
+                            </span>
+                          </div>
+                          <div class="summary-item">
+                            <span class="summary-label">排名:</span>
+                            <span class="summary-value rank">
+                              第{{ item.rank }}名
+                            </span>
+                          </div>
+                        </div>
+                      </mat-card-content>
+                    </mat-card>
+                  }
+                </div>
+              }
+
+              <!-- 对比图表 -->
+              <div class="comparison-chart-section">
+                <div class="chart-header">
+                  <h3>对比趋势图</h3>
+                  <mat-button-toggle-group [(value)]="chartType">
+                    <mat-button-toggle value="bar">
+                      <mat-icon>bar_chart</mat-icon>
+                    </mat-button-toggle>
+                    <mat-button-toggle value="line">
+                      <mat-icon>show_chart</mat-icon>
+                    </mat-button-toggle>
+                    <mat-button-toggle value="radar">
+                      <mat-icon>radar</mat-icon>
+                    </mat-button-toggle>
+                  </mat-button-toggle-group>
+                </div>
+                <div class="chart-container">
+                  <canvas #comparisonChart width="800" height="400"></canvas>
+                </div>
+              </div>
             </mat-card-content>
           </mat-card>
         </div>
@@ -317,10 +1108,10 @@
             </mat-card-header>
             <mat-card-content>
               @for (checkpoint of onboardingCheckpoints; track checkpoint.id) {
-                <div class="checkpoint-item">
+                <div class="checkpoint-item" [attr.data-checkpoint-id]="checkpoint.id">
                   <mat-checkbox
                     [checked]="checkpoint.completed"
-                    (change)="checkpoint.completed = $any($event).checked">
+                    (change)="onCheckpointChange(checkpoint, $event)">
                   </mat-checkbox>
                   <div class="checkpoint-content">
                     <h4 class="checkpoint-title">{{checkpoint.title}}</h4>

文件差異過大導致無法顯示
+ 2080 - 223
src/app/pages/hr/dashboard/dashboard.scss


+ 1361 - 90
src/app/pages/hr/dashboard/dashboard.ts

@@ -9,6 +9,11 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
 import { MatChipsModule } from '@angular/material/chips';
 import { MatProgressBarModule } from '@angular/material/progress-bar';
 import { MatBadgeModule } from '@angular/material/badge';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSelectModule } from '@angular/material/select';
+import { MatInputModule } from '@angular/material/input';
+import { MatTableModule } from '@angular/material/table';
+import { MatButtonToggleModule } from '@angular/material/button-toggle';
 import { DragDropModule, CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
 import { Chart, ChartConfiguration, registerables } from 'chart.js';
 import { trigger, state, style, transition, animate } from '@angular/animations';
@@ -20,7 +25,7 @@ export interface TodoItem {
   description: string;
   priority: 'high' | 'medium' | 'low';
   status: 'pending' | 'completed' | 'in_progress';
-  type: 'resume' | 'onboarding' | 'promotion' | 'resignation';
+  type: 'resume' | 'onboarding' | 'resignation';
 }
 
 export interface RankDistribution {
@@ -44,29 +49,88 @@ export interface DepartmentPerformance {
   overdueRate: number;
 }
 
-export interface PromotionRule {
+
+
+export interface OnboardingCheckpoint {
   id: number;
   title: string;
   description: string;
-  conditions: string[];
+  dueDate: Date;
+  completed: boolean;
+  interviewTemplate: string[];
 }
 
-export interface PromotionSuggestion {
-  employeeId: number;
-  employeeName: string;
-  currentRank: string;
-  suggestedRank: string;
+// AI简历分析相关接口
+export interface MatchDimension {
+  id: number;
+  name: string;
+  score: number;
+  level: 'high' | 'medium' | 'low';
+  icon: string;
+}
+
+export interface Recommendation {
+  title: string;
+  level: 'recommend' | 'consider' | 'reject';
+  levelText: string;
+  icon: string;
+  summary: string;
   reasons: string[];
-  status: 'pending' | 'approved' | 'rejected';
+  concerns: string[];
 }
 
-export interface OnboardingCheckpoint {
+export interface ScreeningInfo {
   id: number;
   title: string;
-  description: string;
-  dueDate: Date;
-  completed: boolean;
-  interviewTemplate: string[];
+  detail: string;
+  status: 'pass' | 'warning' | 'fail';
+  statusText: string;
+  icon: string;
+}
+
+export interface RecruitmentStage {
+  id: string;
+  title: string;
+  status: 'completed' | 'active' | 'pending' | 'blocked';
+  statusText: string;
+  icon: string;
+  candidateCount: number;
+  passRate: number;
+  evaluator?: string;
+  lastUpdate: Date;
+  nextAction?: string;
+  evaluationResults?: EvaluationResult[];
+}
+
+export interface EvaluationResult {
+  candidateName: string;
+  result: 'pass' | 'fail' | 'pending';
+  evaluator: string;
+  evaluationTime: Date;
+  score?: number;
+  comments?: string;
+}
+
+export interface PerformanceMetric {
+  id: string;
+  title: string;
+  value: string;
+  unit: string;
+  target: string;
+  achievement: string;
+  achievementClass: string;
+  period: string;
+  icon: string;
+  iconClass: string;
+  status: 'excellent' | 'good' | 'warning' | 'poor';
+  trend: {
+    type: 'positive' | 'negative' | 'neutral';
+    value: string;
+    label: string;
+    icon: string;
+  };
+  progressValue: number;
+  progressClass: string;
 }
 
 @Component({
@@ -83,7 +147,12 @@ export interface OnboardingCheckpoint {
     MatChipsModule,
     MatProgressBarModule,
     MatBadgeModule,
-    DragDropModule
+    MatFormFieldModule,
+    MatSelectModule,
+    MatInputModule,
+    DragDropModule,
+    MatTableModule,
+    MatButtonToggleModule
   ],
   templateUrl: './dashboard.html',
   styleUrls: ['./dashboard.scss'],
@@ -108,7 +177,7 @@ export class Dashboard implements OnInit, AfterViewInit {
   private lineChart!: Chart;
   private radarChart!: Chart;
   // 当前激活的标签页
-  activeTab: 'visualization' | 'promotion' | 'onboarding' = 'visualization';
+  activeTab: 'visualization' | 'recruitment' | 'performance' | 'onboarding' = 'visualization';
   
   // 待办事项是否展开
   isTodoExpanded = false;
@@ -135,13 +204,7 @@ export class Dashboard implements OnInit, AfterViewInit {
       priority: 'medium',
       dueDate: '2024-01-28'
     },
-    {
-      id: 3,
-      title: '晋升审核',
-      description: '审核中级设计师晋升申请',
-      priority: 'high',
-      dueDate: '2024-01-30'
-    },
+
     {
       id: 4,
       title: '离职面谈',
@@ -169,14 +232,7 @@ export class Dashboard implements OnInit, AfterViewInit {
       status: 'pending',
       type: 'onboarding'
     },
-    {
-      id: 3,
-      title: '晋升审核',
-      description: '审核中级设计师晋升申请',
-      priority: 'high',
-      status: 'pending',
-      type: 'promotion'
-    },
+
     {
       id: 4,
       title: '离职面谈',
@@ -250,60 +306,7 @@ export class Dashboard implements OnInit, AfterViewInit {
     }
   ];
 
-  promotionRules: PromotionRule[] = [
-    {
-      id: 1,
-      title: '初级→中级晋升标准',
-      description: '设计师晋升中级标准',
-      conditions: [
-        '连续3个月优秀作品率超过80%',
-        '逾期率低于5%',
-        '客户满意度评分4.5以上',
-        '至少完成12个主要项目'
-      ]
-    },
-    {
-      id: 2,
-      title: '中级→高级晋升标准',
-      description: '设计师晋升高级标准',
-      conditions: [
-        '连续6个月优秀作品率超过85%',
-        '逾期率低于3%',
-        '客户满意度评分4.8以上',
-        '带领过至少2个大型项目',
-        '有 mentorship 经验'
-      ]
-    }
-  ];
 
-  promotionSuggestions: PromotionSuggestion[] = [
-    {
-      employeeId: 1001,
-      employeeName: '张三',
-      currentRank: '初级设计师',
-      suggestedRank: '中级设计师',
-      reasons: [
-        '连续3个月优秀作品率85%',
-        '逾期率仅2%',
-        '客户满意度4.7分',
-        '已完成15个主要项目'
-      ],
-      status: 'pending'
-    },
-    {
-      employeeId: 1002,
-      employeeName: '李四',
-      currentRank: '中级设计师',
-      suggestedRank: '高级设计师',
-      reasons: [
-        '连续6个月优秀作品率88%',
-        '逾期率1.5%',
-        '客户满意度4.9分',
-        '成功带领3个大型项目'
-      ],
-      status: 'pending'
-    }
-  ];
 
   onboardingCheckpoints: OnboardingCheckpoint[] = [
     {
@@ -361,9 +364,689 @@ export class Dashboard implements OnInit, AfterViewInit {
     }, 100);
   }
 
+  ngOnDestroy() {
+    // 销毁所有图表实例,防止内存泄漏
+    if (this.pieChart) {
+      this.pieChart.destroy();
+    }
+    if (this.lineChart) {
+      this.lineChart.destroy();
+    }
+    if (this.radarChart) {
+      this.radarChart.destroy();
+    }
+  }
+
   // 切换标签页
-  switchTab(tab: 'visualization' | 'promotion' | 'onboarding') {
+  switchTab(tab: 'visualization' | 'recruitment' | 'performance' | 'onboarding') {
     this.activeTab = tab;
+    
+    // 如果切换到数据可视化页面,重新初始化图表
+    if (tab === 'visualization') {
+      setTimeout(() => this.initializeCharts(), 100);
+    }
+  }
+
+  // 绩效指标数据
+  performanceMetrics: PerformanceMetric[] = [
+    {
+      id: 'project-completion',
+      title: '项目完成率',
+      value: '89',
+      unit: '%',
+      target: '85%',
+      achievement: '104.7%',
+      achievementClass: 'excellent',
+      period: '本月',
+      icon: 'assignment_turned_in',
+      iconClass: 'success-icon',
+      status: 'excellent',
+      trend: {
+        type: 'positive',
+        value: '+5.2%',
+        label: '较上月',
+        icon: 'trending_up'
+      },
+      progressValue: 89,
+      progressClass: 'success-progress'
+    },
+    {
+      id: 'quality-rate',
+      title: '优秀作品率',
+      value: '76',
+      unit: '%',
+      target: '80%',
+      achievement: '95.0%',
+      achievementClass: 'good',
+      period: '本月',
+      icon: 'star',
+      iconClass: 'warning-icon',
+      status: 'good',
+      trend: {
+        type: 'positive',
+        value: '+2.8%',
+        label: '较上月',
+        icon: 'trending_up'
+      },
+      progressValue: 76,
+      progressClass: 'warning-progress'
+    },
+    {
+      id: 'satisfaction',
+      title: '客户满意度',
+      value: '4.6',
+      unit: '/5.0',
+      target: '4.5',
+      achievement: '102.2%',
+      achievementClass: 'excellent',
+      period: '本月',
+      icon: 'sentiment_satisfied',
+      iconClass: 'success-icon',
+      status: 'excellent',
+      trend: {
+        type: 'positive',
+        value: '+0.3',
+        label: '较上月',
+        icon: 'trending_up'
+      },
+      progressValue: 92,
+      progressClass: 'success-progress'
+    },
+    {
+      id: 'overdue-rate',
+      title: '项目逾期率',
+      value: '8',
+      unit: '%',
+      target: '≤10%',
+      achievement: '120.0%',
+      achievementClass: 'good',
+      period: '本月',
+      icon: 'schedule',
+      iconClass: 'success-icon',
+      status: 'good',
+      trend: {
+        type: 'positive',
+        value: '-1.5%',
+        label: '较上月',
+        icon: 'trending_down'
+      },
+      progressValue: 20,
+      progressClass: 'success-progress'
+    },
+    {
+      id: 'team-efficiency',
+      title: '团队效率指数',
+      value: '92',
+      unit: '分',
+      target: '90分',
+      achievement: '102.2%',
+      achievementClass: 'excellent',
+      period: '本月',
+      icon: 'groups',
+      iconClass: 'success-icon',
+      status: 'excellent',
+      trend: {
+        type: 'positive',
+        value: '+4.1',
+        label: '较上月',
+        icon: 'trending_up'
+      },
+      progressValue: 92,
+      progressClass: 'success-progress'
+    }
+  ];
+
+  // 筛选相关属性
+  selectedDepartment: string = '';
+  selectedLevel: string = '';
+  selectedTimeRange: string = 'month';
+  isFilterLoading: boolean = false;
+  quickFilter: string = '';
+
+  // 绩效对比相关属性
+  comparisonMode: 'horizontal' | 'vertical' = 'horizontal';
+  selectedComparisonDimension: string = 'department';
+  selectedComparisonMetric: string[] = ['completion', 'quality'];
+  chartType: 'bar' | 'line' | 'radar' = 'bar';
+  
+  horizontalComparisonData: any[] = [
+    {
+      id: 1,
+      name: '技术部',
+      icon: 'code',
+      iconClass: 'tech-icon',
+      completion: '92%',
+      quality: '88%',
+      efficiency: '85%',
+      satisfaction: '90%',
+      innovation: '95%'
+    },
+    {
+      id: 2,
+      name: '设计部',
+      icon: 'palette',
+      iconClass: 'design-icon',
+      completion: '88%',
+      quality: '92%',
+      efficiency: '82%',
+      satisfaction: '87%',
+      innovation: '90%'
+    },
+    {
+      id: 3,
+      name: '产品部',
+      icon: 'lightbulb',
+      iconClass: 'product-icon',
+      completion: '85%',
+      quality: '85%',
+      efficiency: '88%',
+      satisfaction: '85%',
+      innovation: '88%'
+    },
+    {
+      id: 4,
+      name: '运营部',
+      icon: 'trending_up',
+      iconClass: 'operation-icon',
+      completion: '90%',
+      quality: '83%',
+      efficiency: '90%',
+      satisfaction: '88%',
+      innovation: '82%'
+    }
+  ];
+
+  verticalComparisonData: any[] = [
+    {
+      id: 1,
+      name: '技术部',
+      category: '研发部门',
+      icon: 'code',
+      iconClass: 'tech-icon',
+      completion: '92%',
+      quality: '88%',
+      efficiency: '85%',
+      satisfaction: '90%',
+      innovation: '95%',
+      overallScore: 90,
+      rank: 1
+    },
+    {
+      id: 2,
+      name: '设计部',
+      category: '创意部门',
+      icon: 'palette',
+      iconClass: 'design-icon',
+      completion: '88%',
+      quality: '92%',
+      efficiency: '82%',
+      satisfaction: '87%',
+      innovation: '90%',
+      overallScore: 88,
+      rank: 2
+    },
+    {
+      id: 3,
+      name: '产品部',
+      category: '策略部门',
+      icon: 'lightbulb',
+      iconClass: 'product-icon',
+      completion: '85%',
+      quality: '85%',
+      efficiency: '88%',
+      satisfaction: '85%',
+      innovation: '88%',
+      overallScore: 86,
+      rank: 3
+    },
+    {
+      id: 4,
+      name: '运营部',
+      category: '执行部门',
+      icon: 'trending_up',
+      iconClass: 'operation-icon',
+      completion: '90%',
+      quality: '83%',
+      efficiency: '90%',
+      satisfaction: '88%',
+      innovation: '82%',
+      overallScore: 87,
+      rank: 4
+    }
+  ];
+
+  horizontalDisplayedColumns: string[] = ['name', 'completion', 'quality', 'actions'];
+
+  // 离职原因分析相关属性
+  resignationTimeRange: string = 'quarter';
+  reasonsChartType: 'pie' | 'doughnut' | 'bar' = 'pie';
+  trendsTimeframe: 'monthly' | 'quarterly' | 'yearly' = 'monthly';
+  
+  totalResignations: number = 45;
+  resignationRate: number = 8.5;
+  averageTenure: number = 18;
+  resignationCost: number = 125;
+  
+  resignationDepartments = [
+    { id: 'tech', name: '技术部', count: 15, selected: true },
+    { id: 'design', name: '设计部', count: 8, selected: true },
+    { id: 'product', name: '产品部', count: 12, selected: true },
+    { id: 'operation', name: '运营部', count: 10, selected: true }
+  ];
+  
+  resignationLevels = [
+    { id: 'junior', name: '初级', count: 18, selected: true },
+    { id: 'middle', name: '中级', count: 20, selected: true },
+    { id: 'senior', name: '高级', count: 7, selected: true }
+  ];
+  
+  resignationReasons = [
+    {
+      id: 'salary',
+      name: '薪资待遇',
+      category: 'compensation',
+      categoryName: '薪酬福利',
+      icon: 'attach_money',
+      percentage: 28.5,
+      count: 13,
+      description: '薪资水平低于市场平均水平,缺乏有竞争力的薪酬体系',
+      trend: { direction: 'up', value: 5.2 }
+    },
+    {
+      id: 'career',
+      name: '职业发展',
+      category: 'development',
+      categoryName: '发展机会',
+      icon: 'trending_up',
+      percentage: 22.3,
+      count: 10,
+      description: '缺乏明确的职业发展路径和晋升机会',
+      trend: { direction: 'down', value: 2.1 }
+    },
+    {
+      id: 'workload',
+      name: '工作压力',
+      category: 'worklife',
+      categoryName: '工作环境',
+      icon: 'work',
+      percentage: 18.7,
+      count: 8,
+      description: '工作强度过大,工作与生活平衡难以维持',
+      trend: { direction: 'up', value: 3.5 }
+    },
+    {
+      id: 'management',
+      name: '管理问题',
+      category: 'management',
+      categoryName: '管理层面',
+      icon: 'supervisor_account',
+      percentage: 15.2,
+      count: 7,
+      description: '管理方式不当,缺乏有效的沟通和反馈机制',
+      trend: { direction: 'down', value: 1.8 }
+    },
+    {
+      id: 'culture',
+      name: '企业文化',
+      category: 'culture',
+      categoryName: '文化氛围',
+      icon: 'groups',
+      percentage: 10.1,
+      count: 5,
+      description: '企业文化与个人价值观不匹配,团队氛围不佳',
+      trend: { direction: 'up', value: 2.3 }
+    },
+    {
+      id: 'personal',
+      name: '个人原因',
+      category: 'personal',
+      categoryName: '个人因素',
+      icon: 'person',
+      percentage: 5.2,
+      count: 2,
+      description: '个人家庭、健康等因素导致的离职',
+      trend: { direction: 'down', value: 0.8 }
+    }
+  ];
+
+  // AI简历分析相关属性
+  isDragOver: boolean = false;
+  showAnalysisResults: boolean = false;
+  
+  matchDimensions: MatchDimension[] = [
+    { id: 1, name: '建模经验', score: 92, level: 'high', icon: 'view_in_ar' },
+    { id: 2, name: 'UI设计', score: 85, level: 'high', icon: 'design_services' },
+    { id: 3, name: '用户体验', score: 78, level: 'medium', icon: 'psychology' },
+    { id: 4, name: '团队协作', score: 88, level: 'high', icon: 'groups' },
+    { id: 5, name: '项目管理', score: 65, level: 'medium', icon: 'task_alt' }
+  ];
+
+  recommendation: Recommendation = {
+    title: '强烈推荐进入面试环节',
+    level: 'recommend',
+    levelText: '推荐',
+    icon: 'thumb_up',
+    summary: '候选人在核心技能方面表现优秀,具备丰富的建模经验和良好的设计基础,建议安排技术面试。',
+    reasons: [
+      '3年以上3D建模经验,熟练掌握Maya、Blender等主流软件',
+      'UI设计基础扎实,有完整的项目作品集',
+      '具备良好的团队协作能力和沟通技巧',
+      '学习能力强,能够快速适应新技术和工具'
+    ],
+    concerns: [
+      '项目管理经验相对较少,需要在实际工作中加强',
+      '对公司业务领域了解有限,需要一定的适应期'
+    ]
+  };
+
+  screeningInfo: ScreeningInfo[] = [
+    { id: 1, title: '学历要求', detail: '本科及以上学历', status: 'pass', statusText: '符合', icon: 'school' },
+    { id: 2, title: '工作经验', detail: '3年相关工作经验', status: 'pass', statusText: '符合', icon: 'work' },
+    { id: 3, title: '技能匹配', detail: '核心技能匹配度85%', status: 'pass', statusText: '优秀', icon: 'star' },
+    { id: 4, title: '薪资期望', detail: '期望薪资15K-18K', status: 'warning', statusText: '偏高', icon: 'payments' },
+    { id: 5, title: '到岗时间', detail: '可立即到岗', status: 'pass', statusText: '符合', icon: 'schedule' }
+  ];
+
+  // 招聘阶段数据
+  recruitmentStages: RecruitmentStage[] = [
+    {
+      id: 'resume-screening',
+      title: '简历初筛',
+      status: 'completed',
+      statusText: '已完成',
+      icon: 'description',
+      candidateCount: 45,
+      passRate: 65,
+      evaluator: '张经理',
+      lastUpdate: new Date('2024-01-15T10:30:00'),
+      nextAction: '进入面试环节',
+      evaluationResults: [
+        {
+          candidateName: '李小明',
+          result: 'pass',
+          evaluator: '张经理',
+          evaluationTime: new Date('2024-01-15T09:00:00'),
+          score: 85,
+          comments: '技能匹配度高,经验丰富'
+        }
+      ]
+    },
+    {
+      id: 'interview-assessment',
+      title: '面试评估',
+      status: 'active',
+      statusText: '进行中',
+      icon: 'record_voice_over',
+      candidateCount: 29,
+      passRate: 72,
+      evaluator: '王总监',
+      lastUpdate: new Date('2024-01-16T14:20:00'),
+      nextAction: '安排技术面试',
+      evaluationResults: []
+    },
+    {
+      id: 'onboarding-evaluation',
+      title: '入职评定',
+      status: 'pending',
+      statusText: '待开始',
+      icon: 'how_to_reg',
+      candidateCount: 21,
+      passRate: 90,
+      evaluator: '人事部',
+      lastUpdate: new Date('2024-01-14T16:45:00'),
+      nextAction: '准备入职材料'
+    },
+    {
+      id: 'probation-tracking',
+      title: '试用期跟踪',
+      status: 'active',
+      statusText: '跟踪中',
+      icon: 'trending_up',
+      candidateCount: 18,
+      passRate: 88,
+      evaluator: '直属主管',
+      lastUpdate: new Date('2024-01-16T11:15:00'),
+      nextAction: '月度评估'
+    }
+  ];
+
+  // 打开晋升规则弹窗
+  openPromotionRules(): void {
+    // 这里可以打开一个对话框显示晋升规则
+    console.log('打开晋升规则弹窗');
+    // 临时实现:显示alert
+    alert('晋升规则:\n\n初级→中级:连续3个月优秀作品率超过80%,逾期率低于5%,客户满意度4.5以上\n\n中级→高级:连续6个月优秀作品率超过85%,逾期率低于3%,客户满意度4.8以上,有mentorship经验');
+  }
+
+  // 招聘相关方法
+  uploadResume() {
+    // 模拟文件上传过程
+    const input = document.createElement('input');
+    input.type = 'file';
+    input.accept = '.pdf,.doc,.docx';
+    input.onchange = (event: any) => {
+      const file = event.target.files[0];
+      if (file) {
+        this.handleFileUpload(file);
+      }
+    };
+    input.click();
+  }
+
+  // 拖放相关方法
+  onDragOver(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.isDragOver = true;
+  }
+
+  onDragLeave(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.isDragOver = false;
+  }
+
+  onFileDrop(event: DragEvent) {
+    event.preventDefault();
+    event.stopPropagation();
+    this.isDragOver = false;
+    
+    const files = event.dataTransfer?.files;
+    if (files && files.length > 0) {
+      const file = files[0];
+      this.handleFileUpload(file);
+    }
+  }
+
+  private handleFileUpload(file: File) {
+    // 验证文件类型
+    const allowedTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
+    if (!allowedTypes.includes(file.type)) {
+      this.showUploadError('不支持的文件格式,请上传PDF、DOC或DOCX文件');
+      return;
+    }
+
+    // 验证文件大小 (10MB)
+    if (file.size > 10 * 1024 * 1024) {
+      this.showUploadError('文件大小超过10MB限制');
+      return;
+    }
+
+    // 开始上传和分析
+    this.showUploadFeedback(file.name);
+    setTimeout(() => {
+      this.showAnalysisResults = true;
+      console.log('简历分析完成:', file.name);
+    }, 3000);
+  }
+
+  // 招聘阶段相关方法
+  refreshRecruitmentData(): void {
+    // 刷新招聘数据
+    console.log('刷新招聘数据');
+    // 这里可以调用API刷新数据
+  }
+
+  openStageDetails(stage: RecruitmentStage): void {
+    console.log('打开阶段详情:', stage);
+    // 这里可以打开详情弹窗或导航到详情页面
+  }
+
+  navigateToOnboarding(): void {
+    console.log('导航到新人跟进模块');
+    // 这里可以使用Router导航到新人跟进页面
+  }
+
+  viewProbationReports(): void {
+    console.log('查看试用期报告');
+    // 这里可以打开试用期报告页面
+  }
+
+  // 绩效筛选相关方法
+  onDepartmentChange(event: any): void {
+    console.log('部门筛选变更:', event.value);
+    this.selectedDepartment = event.value;
+  }
+
+  onLevelChange(event: any): void {
+    console.log('职级筛选变更:', event.value);
+    this.selectedLevel = event.value;
+  }
+
+  onTimeRangeChange(event: any): void {
+    console.log('时间范围变更:', event.value);
+    this.selectedTimeRange = event.value;
+  }
+
+  resetFilters(): void {
+    this.selectedDepartment = '';
+    this.selectedLevel = '';
+    this.selectedTimeRange = 'month';
+    this.quickFilter = '';
+    console.log('重置筛选条件');
+    this.applyFilters();
+  }
+
+  exportData(): void {
+    console.log('导出数据');
+    // 这里可以实现数据导出功能
+  }
+
+  applyQuickFilter(filterType: string): void {
+    this.quickFilter = this.quickFilter === filterType ? '' : filterType;
+    console.log('应用快速筛选:', filterType);
+    this.applyFilters();
+  }
+
+  private showUploadError(message: string) {
+    // 创建错误提示元素
+    const errorDiv = document.createElement('div');
+    errorDiv.className = 'upload-error-feedback';
+    errorDiv.innerHTML = `
+      <div class="error-content">
+        <mat-icon>error</mat-icon>
+        <span>${message}</span>
+      </div>
+    `;
+    
+    document.body.appendChild(errorDiv);
+    
+    // 3秒后移除
+    setTimeout(() => {
+      if (errorDiv.parentNode) {
+        errorDiv.parentNode.removeChild(errorDiv);
+      }
+    }, 3000);
+  }
+
+  // 显示上传反馈
+  showUploadFeedback(fileName: string) {
+    // 创建临时反馈元素
+    const feedback = document.createElement('div');
+    feedback.className = 'upload-feedback';
+    feedback.innerHTML = `
+      <mat-icon>check_circle</mat-icon>
+      <span>简历 "${fileName}" 上传成功!</span>
+    `;
+    feedback.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: #4CAF50;
+      color: white;
+      padding: 12px 20px;
+      border-radius: 8px;
+      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+      z-index: 1000;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      animation: slideInRight 0.3s ease-out;
+    `;
+    
+    document.body.appendChild(feedback);
+    
+    // 3秒后移除反馈
+    setTimeout(() => {
+      feedback.style.animation = 'slideOutRight 0.3s ease-in';
+      setTimeout(() => {
+        document.body.removeChild(feedback);
+      }, 300);
+    }, 3000);
+  }
+
+  // 绩效相关方法
+  applyFilters() {
+    // 显示加载状态
+    this.isFilterLoading = true;
+    
+    // 模拟筛选过程
+    setTimeout(() => {
+      this.isFilterLoading = false;
+      
+      // 应用筛选条件
+      console.log('应用筛选条件:', {
+        department: this.selectedDepartment,
+        timeRange: this.selectedTimeRange
+      });
+      
+      // 显示筛选成功反馈
+      this.showFilterFeedback();
+    }, 1000);
+  }
+
+  // 显示筛选反馈
+  showFilterFeedback() {
+    const feedback = document.createElement('div');
+    feedback.className = 'filter-feedback';
+    feedback.innerHTML = `
+      <mat-icon>filter_list</mat-icon>
+      <span>筛选条件已应用</span>
+    `;
+    feedback.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: #2196F3;
+      color: white;
+      padding: 12px 20px;
+      border-radius: 8px;
+      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+      z-index: 1000;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      animation: slideInRight 0.3s ease-out;
+    `;
+    
+    document.body.appendChild(feedback);
+    
+    setTimeout(() => {
+      feedback.style.animation = 'slideOutRight 0.3s ease-in';
+      setTimeout(() => {
+        document.body.removeChild(feedback);
+      }, 300);
+    }, 2000);
   }
 
 
@@ -613,11 +1296,10 @@ export class Dashboard implements OnInit, AfterViewInit {
 
   getTypeLabel(type: string): string {
     switch (type) {
-      case 'resume': return '简历初筛';
-      case 'onboarding': return '入职评定';
-      case 'promotion': return '晋升审核';
-      case 'resignation': return '离职面谈';
-      default: return '其他';
+      case 'resume': return '简历筛选';
+      case 'onboarding': return '入职跟进';
+      case 'resignation': return '离职处理';
+      default: return type;
     }
   }
 
@@ -647,4 +1329,593 @@ export class Dashboard implements OnInit, AfterViewInit {
   handleButtonPress(action: 'press' | 'release') {
     this.isButtonPressed = action === 'press';
   }
+
+  // 处理检查点状态变化
+  onCheckpointChange(checkpoint: OnboardingCheckpoint, event: any) {
+    checkpoint.completed = event.checked;
+    
+    // 显示状态变化反馈
+    this.showCheckpointFeedback(checkpoint.title, checkpoint.completed);
+    
+    // 如果完成,添加完成动画效果
+    if (checkpoint.completed) {
+      this.animateCheckpointCompletion(checkpoint.id);
+    }
+  }
+
+  // 显示检查点反馈
+  showCheckpointFeedback(title: string, completed: boolean) {
+    const feedback = document.createElement('div');
+    feedback.className = 'checkpoint-feedback';
+    feedback.innerHTML = `
+      <mat-icon>${completed ? 'check_circle' : 'radio_button_unchecked'}</mat-icon>
+      <span>${completed ? '已完成' : '已取消'}: ${title}</span>
+    `;
+    feedback.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: ${completed ? '#4CAF50' : '#FF9800'};
+      color: white;
+      padding: 12px 20px;
+      border-radius: 8px;
+      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+      z-index: 1000;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      animation: slideInRight 0.3s ease-out;
+      max-width: 300px;
+    `;
+    
+    document.body.appendChild(feedback);
+    
+    setTimeout(() => {
+      feedback.style.animation = 'slideOutRight 0.3s ease-in';
+      setTimeout(() => {
+        document.body.removeChild(feedback);
+      }, 300);
+    }, 2500);
+  }
+
+  // 检查点完成动画
+  animateCheckpointCompletion(checkpointId: number) {
+    const element = document.querySelector(`[data-checkpoint-id="${checkpointId}"]`);
+    if (element) {
+      element.classList.add('completed-animation');
+      setTimeout(() => {
+        element.classList.remove('completed-animation');
+      }, 600);
+    }
+  }
+
+  // 新人进度更新
+  updateNewbieProgress(newbieId: number, progress: number) {
+    const newbie = this.newbieList.find(n => n.id === newbieId);
+    if (newbie) {
+      newbie.progress = Math.min(100, Math.max(0, progress));
+      this.showProgressFeedback(newbie.name, newbie.progress);
+    }
+  }
+
+  // 显示进度反馈
+  showProgressFeedback(name: string, progress: number) {
+    const feedback = document.createElement('div');
+    feedback.className = 'progress-feedback';
+    feedback.innerHTML = `
+      <mat-icon>trending_up</mat-icon>
+      <span>${name} 的进度已更新至 ${progress}%</span>
+    `;
+    feedback.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: #9C27B0;
+      color: white;
+      padding: 12px 20px;
+      border-radius: 8px;
+      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+      z-index: 1000;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      animation: slideInRight 0.3s ease-out;
+    `;
+    
+    document.body.appendChild(feedback);
+    
+    setTimeout(() => {
+      feedback.style.animation = 'slideOutRight 0.3s ease-in';
+      setTimeout(() => {
+        document.body.removeChild(feedback);
+      }, 300);
+    }, 2000);
+  }
+
+  // 绩效指标相关方法
+  refreshMetrics() {
+    console.log('刷新绩效指标数据');
+    // 模拟数据刷新
+    this.performanceMetrics.forEach(metric => {
+      // 随机更新数值以模拟实时数据
+      const currentValue = parseInt(metric.value);
+      const variation = Math.random() * 4 - 2; // -2 到 +2 的随机变化
+      const newValue = Math.max(0, Math.min(100, currentValue + variation));
+      metric.value = Math.round(newValue).toString();
+      
+      // 更新进度条值
+      if (metric.id === 'overdue-rate') {
+        metric.progressValue = Math.max(0, 100 - newValue); // 逾期率反向显示
+      } else {
+        metric.progressValue = newValue;
+      }
+    });
+    
+    this.showMetricsRefreshFeedback();
+  }
+
+  exportMetrics() {
+    console.log('导出绩效指标报告');
+    // 模拟导出功能
+    const reportData = {
+      exportTime: new Date().toISOString(),
+      metrics: this.performanceMetrics.map(metric => ({
+        title: metric.title,
+        value: metric.value + metric.unit,
+        target: metric.target,
+        achievement: metric.achievement,
+        trend: metric.trend.value + ' ' + metric.trend.label
+      }))
+    };
+    
+    console.log('报告数据:', reportData);
+    this.showExportFeedback();
+  }
+
+  viewMetricDetails(metricId: string) {
+    console.log('查看指标详情:', metricId);
+    const metric = this.performanceMetrics.find(m => m.id === metricId);
+    if (metric) {
+      // 这里可以打开详情对话框或导航到详情页面
+      console.log('指标详情:', metric);
+    }
+  }
+
+  viewMetricTrend(metricId: string) {
+    console.log('查看指标趋势:', metricId);
+    const metric = this.performanceMetrics.find(m => m.id === metricId);
+    if (metric) {
+      // 这里可以打开趋势图表对话框
+      console.log('指标趋势:', metric);
+    }
+  }
+
+  private showMetricsRefreshFeedback() {
+    const feedback = document.createElement('div');
+    feedback.className = 'metrics-feedback';
+    feedback.innerHTML = `
+      <mat-icon>refresh</mat-icon>
+      <span>绩效指标已刷新</span>
+    `;
+    feedback.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: #4CAF50;
+      color: white;
+      padding: 12px 20px;
+      border-radius: 8px;
+      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+      z-index: 1000;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      animation: slideInRight 0.3s ease-out;
+    `;
+    
+    document.body.appendChild(feedback);
+    
+    setTimeout(() => {
+      feedback.style.animation = 'slideOutRight 0.3s ease-in';
+      setTimeout(() => {
+        document.body.removeChild(feedback);
+      }, 300);
+    }, 2000);
+  }
+
+  private showExportFeedback() {
+    const feedback = document.createElement('div');
+    feedback.className = 'export-feedback';
+    feedback.innerHTML = `
+      <mat-icon>file_download</mat-icon>
+      <span>报告导出成功</span>
+    `;
+    feedback.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: #2196F3;
+      color: white;
+      padding: 12px 20px;
+      border-radius: 8px;
+      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+      z-index: 1000;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      animation: slideInRight 0.3s ease-out;
+    `;
+    
+    document.body.appendChild(feedback);
+    
+    setTimeout(() => {
+      feedback.style.animation = 'slideOutRight 0.3s ease-in';
+      setTimeout(() => {
+        document.body.removeChild(feedback);
+      }, 300);
+    }, 2000);
+  }
+
+  // 绩效对比相关方法
+  onComparisonModeChange(event: any): void {
+    this.comparisonMode = event.value;
+    this.updateComparison();
+  }
+
+  updateComparison(): void {
+    // 更新显示的列
+    this.horizontalDisplayedColumns = ['name', ...this.selectedComparisonMetric, 'actions'];
+    
+    // 根据对比维度更新数据
+    this.updateComparisonData();
+  }
+
+  private updateComparisonData(): void {
+    // 模拟根据不同维度更新数据
+    switch (this.selectedComparisonDimension) {
+      case 'department':
+        // 部门对比数据已经设置
+        break;
+      case 'period':
+        this.updatePeriodComparisonData();
+        break;
+      case 'individual':
+        this.updateIndividualComparisonData();
+        break;
+      case 'project':
+        this.updateProjectComparisonData();
+        break;
+    }
+  }
+
+  private updatePeriodComparisonData(): void {
+    this.horizontalComparisonData = [
+      {
+        id: 1,
+        name: '2024年Q1',
+        icon: 'calendar_today',
+        iconClass: 'period-icon',
+        completion: '88%',
+        quality: '85%',
+        efficiency: '82%',
+        satisfaction: '87%',
+        innovation: '80%'
+      },
+      {
+        id: 2,
+        name: '2024年Q2',
+        icon: 'calendar_today',
+        iconClass: 'period-icon',
+        completion: '90%',
+        quality: '88%',
+        efficiency: '85%',
+        satisfaction: '89%',
+        innovation: '85%'
+      },
+      {
+        id: 3,
+        name: '2024年Q3',
+        icon: 'calendar_today',
+        iconClass: 'period-icon',
+        completion: '92%',
+        quality: '90%',
+        efficiency: '88%',
+        satisfaction: '91%',
+        innovation: '88%'
+      }
+    ];
+
+    this.verticalComparisonData = this.horizontalComparisonData.map((item, index) => ({
+      ...item,
+      category: '季度数据',
+      overallScore: 85 + index * 3,
+      rank: index + 1
+    }));
+  }
+
+  private updateIndividualComparisonData(): void {
+    this.horizontalComparisonData = [
+      {
+        id: 1,
+        name: '张三',
+        icon: 'person',
+        iconClass: 'person-icon',
+        completion: '95%',
+        quality: '92%',
+        efficiency: '88%',
+        satisfaction: '94%',
+        innovation: '90%'
+      },
+      {
+        id: 2,
+        name: '李四',
+        icon: 'person',
+        iconClass: 'person-icon',
+        completion: '88%',
+        quality: '90%',
+        efficiency: '92%',
+        satisfaction: '87%',
+        innovation: '85%'
+      },
+      {
+        id: 3,
+        name: '王五',
+        icon: 'person',
+        iconClass: 'person-icon',
+        completion: '90%',
+        quality: '85%',
+        efficiency: '90%',
+        satisfaction: '88%',
+        innovation: '92%'
+      }
+    ];
+
+    this.verticalComparisonData = this.horizontalComparisonData.map((item, index) => ({
+      ...item,
+      category: '员工个人',
+      overallScore: 90 - index * 2,
+      rank: index + 1
+    }));
+  }
+
+  private updateProjectComparisonData(): void {
+    this.horizontalComparisonData = [
+      {
+        id: 1,
+        name: '项目Alpha',
+        icon: 'work',
+        iconClass: 'project-icon',
+        completion: '95%',
+        quality: '90%',
+        efficiency: '85%',
+        satisfaction: '92%',
+        innovation: '88%'
+      },
+      {
+        id: 2,
+        name: '项目Beta',
+        icon: 'work',
+        iconClass: 'project-icon',
+        completion: '88%',
+        quality: '88%',
+        efficiency: '90%',
+        satisfaction: '85%',
+        innovation: '90%'
+      },
+      {
+        id: 3,
+        name: '项目Gamma',
+        icon: 'work',
+        iconClass: 'project-icon',
+        completion: '92%',
+        quality: '85%',
+        efficiency: '88%',
+        satisfaction: '90%',
+        innovation: '85%'
+      }
+    ];
+
+    this.verticalComparisonData = this.horizontalComparisonData.map((item, index) => ({
+      ...item,
+      category: '项目数据',
+      overallScore: 88 + index,
+      rank: index + 1
+    }));
+  }
+
+  addComparisonItem(): void {
+    // 模拟添加对比项
+    const newId = Math.max(...this.horizontalComparisonData.map(item => item.id)) + 1;
+    const newItem = {
+      id: newId,
+      name: `新增项目${newId}`,
+      icon: 'add_circle',
+      iconClass: 'new-icon',
+      completion: '85%',
+      quality: '80%',
+      efficiency: '82%',
+      satisfaction: '85%',
+      innovation: '78%'
+    };
+
+    this.horizontalComparisonData.push(newItem);
+    this.verticalComparisonData.push({
+      ...newItem,
+      category: '新增项目',
+      overallScore: 82,
+      rank: this.verticalComparisonData.length + 1
+    });
+
+    this.showAddItemFeedback();
+  }
+
+  removeComparisonItem(id: number): void {
+    this.horizontalComparisonData = this.horizontalComparisonData.filter(item => item.id !== id);
+    this.verticalComparisonData = this.verticalComparisonData.filter(item => item.id !== id);
+    this.showRemoveItemFeedback();
+  }
+
+  viewComparisonDetails(id: number): void {
+    const item = this.horizontalComparisonData.find(item => item.id === id);
+    if (item) {
+      console.log('查看详情:', item);
+      // 这里可以打开详情弹窗或跳转到详情页面
+    }
+  }
+
+  getMetricDisplayName(metric: string): string {
+    const metricNames: { [key: string]: string } = {
+      completion: '完成率',
+      quality: '质量评分',
+      efficiency: '效率指数',
+      satisfaction: '满意度',
+      innovation: '创新度'
+    };
+    return metricNames[metric] || metric;
+  }
+
+  // 离职原因分析相关方法
+  updateResignationData(): void {
+    // 根据时间范围更新数据
+    console.log('更新离职数据,时间范围:', this.resignationTimeRange);
+    // 这里可以调用API获取对应时间范围的数据
+  }
+
+  toggleDepartmentFilter(deptId: string): void {
+    const dept = this.resignationDepartments.find(d => d.id === deptId);
+    if (dept) {
+      dept.selected = !dept.selected;
+      this.updateFilteredResignationData();
+    }
+  }
+
+  toggleLevelFilter(levelId: string): void {
+    const level = this.resignationLevels.find(l => l.id === levelId);
+    if (level) {
+      level.selected = !level.selected;
+      this.updateFilteredResignationData();
+    }
+  }
+
+  updateFilteredResignationData(): void {
+    // 根据筛选条件更新数据
+    const selectedDepts = this.resignationDepartments.filter(d => d.selected);
+    const selectedLevels = this.resignationLevels.filter(l => l.selected);
+    
+    console.log('筛选条件更新:', { selectedDepts, selectedLevels });
+    // 这里可以重新计算统计数据和图表数据
+  }
+
+  exportResignationAnalysis(): void {
+    console.log('导出离职分析报告');
+    // 这里可以生成Excel或PDF报告
+    this.showExportFeedback();
+  }
+
+  viewReasonDetails(reasonId: string): void {
+    const reason = this.resignationReasons.find(r => r.id === reasonId);
+    if (reason) {
+      console.log('查看离职原因详情:', reason);
+      // 这里可以打开详情弹窗显示更多信息
+    }
+  }
+
+  viewImprovementPlan(reasonId: string): void {
+    const reason = this.resignationReasons.find(r => r.id === reasonId);
+    if (reason) {
+      console.log('查看改进建议:', reason);
+      // 这里可以显示针对该离职原因的改进建议
+    }
+  }
+
+  getMetricClass(value: string): string {
+    const numValue = parseInt(value);
+    if (numValue >= 90) return 'metric-excellent';
+    if (numValue >= 80) return 'metric-good';
+    if (numValue >= 70) return 'metric-average';
+    return 'metric-poor';
+  }
+
+  getMetricPercentage(value: string, metric: string): number {
+    return parseInt(value);
+  }
+
+  getProgressBarClass(value: string): string {
+    const numValue = parseInt(value);
+    if (numValue >= 90) return 'progress-excellent';
+    if (numValue >= 80) return 'progress-good';
+    if (numValue >= 70) return 'progress-average';
+    return 'progress-poor';
+  }
+
+  getOverallScoreClass(score: number): string {
+    if (score >= 90) return 'score-excellent';
+    if (score >= 80) return 'score-good';
+    if (score >= 70) return 'score-average';
+    return 'score-poor';
+  }
+
+  private showAddItemFeedback(): void {
+    const feedback = document.createElement('div');
+    feedback.className = 'add-item-feedback';
+    feedback.innerHTML = `
+      <div class="feedback-content">
+        <mat-icon>add_circle</mat-icon>
+        <span>对比项添加成功!</span>
+      </div>
+    `;
+    feedback.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: linear-gradient(135deg, #2196F3, #1976D2);
+      color: white;
+      padding: 16px 24px;
+      border-radius: 12px;
+      box-shadow: 0 8px 32px rgba(33, 150, 243, 0.3);
+      z-index: 1000;
+      animation: slideInRight 0.3s ease-out;
+    `;
+    
+    document.body.appendChild(feedback);
+    
+    setTimeout(() => {
+      feedback.style.animation = 'slideOutRight 0.3s ease-in';
+      setTimeout(() => {
+        document.body.removeChild(feedback);
+      }, 300);
+    }, 2000);
+  }
+
+  private showRemoveItemFeedback(): void {
+    const feedback = document.createElement('div');
+    feedback.className = 'remove-item-feedback';
+    feedback.innerHTML = `
+      <div class="feedback-content">
+        <mat-icon>remove_circle</mat-icon>
+        <span>对比项删除成功!</span>
+      </div>
+    `;
+    feedback.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: linear-gradient(135deg, #FF5722, #D84315);
+      color: white;
+      padding: 16px 24px;
+      border-radius: 12px;
+      box-shadow: 0 8px 32px rgba(255, 87, 34, 0.3);
+      z-index: 1000;
+      animation: slideInRight 0.3s ease-out;
+    `;
+    
+    document.body.appendChild(feedback);
+    
+    setTimeout(() => {
+      feedback.style.animation = 'slideOutRight 0.3s ease-in';
+      setTimeout(() => {
+        document.body.removeChild(feedback);
+      }, 300);
+    }, 2000);
+  }
 }

+ 2 - 0
src/app/pages/hr/hr-layout/hr-layout.html

@@ -34,6 +34,8 @@
         </a>
 
 
+
+
       </mat-nav-list>
 
       <!-- 导航栏底部 -->

+ 607 - 0
src/app/pages/hr/recruitment-performance/recruitment-performance.html

@@ -0,0 +1,607 @@
+<div class="recruitment-performance-container">
+  <!-- 页面顶部导航按钮 -->
+  <div class="top-navigation">
+    <div class="nav-buttons">
+      <button 
+        mat-raised-button 
+        [class.active]="activeTab() === 0"
+        (click)="switchTab(0)"
+        class="nav-button">
+        <mat-icon>psychology</mat-icon>
+        招聘流程优化
+      </button>
+      <button 
+        mat-raised-button 
+        [class.active]="activeTab() === 1"
+        (click)="switchTab(1)"
+        class="nav-button">
+        <mat-icon>analytics</mat-icon>
+        绩效统计与分析
+      </button>
+    </div>
+  </div>
+
+  <!-- 招聘流程优化模块 -->
+  @if (activeTab() === 0) {
+    <div class="recruitment-optimization">
+      <!-- AI简历分析功能区 -->
+      <mat-card class="ai-analysis-section">
+        <mat-card-header>
+          <mat-card-title>
+            <mat-icon>smart_toy</mat-icon>
+            AI 简历分析
+          </mat-card-title>
+        </mat-card-header>
+        <mat-card-content>
+          <!-- 简历上传区域 -->
+          <div class="upload-area">
+            <div class="upload-zone" (click)="fileInput.click()">
+              <mat-icon class="upload-icon">cloud_upload</mat-icon>
+              <p>点击上传简历或拖拽文件到此处</p>
+              <p class="upload-hint">支持 PDF、DOC、DOCX 格式</p>
+              <input #fileInput type="file" hidden accept=".pdf,.doc,.docx" (change)="onResumeUpload($event)">
+            </div>
+          </div>
+
+          <!-- 分析结果展示 -->
+          @if (selectedResume()) {
+            <div class="analysis-results">
+              <div class="result-header">
+                <h3>{{ selectedResume()!.fileName }}</h3>
+                <span class="upload-time">上传时间:{{ selectedResume()!.uploadTime | date:'yyyy-MM-dd HH:mm' }}</span>
+              </div>
+
+              @if (selectedResume()!.status === 'processing') {
+                <div class="processing-state">
+                  <mat-spinner diameter="40"></mat-spinner>
+                  <p>AI正在分析简历,请稍候...</p>
+                </div>
+              }
+
+              @if (selectedResume()!.status === 'completed' && selectedResume()!.analysisResult) {
+                <div class="completed-analysis">
+                  <!-- 推荐结论 -->
+                  <div class="recommendation-section">
+                    <div class="recommendation-badge" [class]="selectedResume()!.analysisResult!.recommendation">
+                      {{ selectedResume()!.analysisResult!.recommendation }}
+                    </div>
+                    <p class="recommendation-reason">{{ selectedResume()!.analysisResult!.reason }}</p>
+                  </div>
+
+                  <!-- 岗位匹配维度标签 -->
+                  <div class="skills-analysis">
+                    <h4>核心技能分析</h4>
+                    <div class="skills-grid">
+                      @for (skill of selectedResume()!.analysisResult!.coreSkills; track skill.name) {
+                        <div class="skill-item" [class.matched]="skill.matched">
+                          <span class="skill-name">{{ skill.name }}</span>
+                          <div class="skill-score">
+                            <mat-progress-bar mode="determinate" [value]="skill.score"></mat-progress-bar>
+                            <span class="score-text">{{ skill.score }}%</span>
+                          </div>
+                        </div>
+                      }
+                    </div>
+                    <div class="skills-summary">
+                      <span class="average-score">平均分:{{ calculateAverageScore(selectedResume()!.analysisResult!.coreSkills) }}%</span>
+                      <span class="matched-count">匹配技能:{{ getMatchedSkillsCount(selectedResume()!) }}/{{ selectedResume()!.analysisResult!.coreSkills.length }}</span>
+                    </div>
+                  </div>
+
+                  <!-- 简历初筛信息 -->
+                  <div class="screening-info">
+                    <h4>简历初筛信息</h4>
+                    <div class="info-grid">
+                      <div class="info-item">
+                        <label>学历背景:</label>
+                        <span>{{ selectedResume()!.analysisResult!.screeningInfo.education }}</span>
+                      </div>
+                      <div class="info-item">
+                        <label>工作年限:</label>
+                        <span>{{ selectedResume()!.analysisResult!.screeningInfo.workYears }}</span>
+                      </div>
+                      <div class="info-item">
+                        <label>核心技能:</label>
+                        <mat-chip-set>
+                          @for (skill of selectedResume()!.analysisResult!.screeningInfo.coreSkills; track skill) {
+                            <mat-chip>{{ skill }}</mat-chip>
+                          }
+                        </mat-chip-set>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              }
+            </div>
+          }
+
+          <!-- 历史分析记录 -->
+          @if (resumeAnalyses().length > 0) {
+            <div class="analysis-history">
+              <h4>分析记录</h4>
+              <div class="history-list">
+                @for (analysis of resumeAnalyses(); track analysis.id) {
+                  <div class="history-item" [class.selected]="selectedResume()?.id === analysis.id" (click)="selectedResume.set(analysis)">
+                    <div class="item-info">
+                      <span class="file-name">{{ analysis.fileName }}</span>
+                      <span class="upload-time">{{ analysis.uploadTime | date:'MM-dd HH:mm' }}</span>
+                    </div>
+                    <div class="item-status">
+                      @if (analysis.status === 'processing') {
+                        <mat-icon class="status-icon processing">hourglass_empty</mat-icon>
+                      }
+                      @if (analysis.status === 'completed') {
+                        <mat-icon class="status-icon completed">check_circle</mat-icon>
+                      }
+                      @if (analysis.status === 'failed') {
+                        <mat-icon class="status-icon failed">error</mat-icon>
+                      }
+                    </div>
+                  </div>
+                }
+              </div>
+            </div>
+          }
+        </mat-card-content>
+      </mat-card>
+
+      <!-- 招聘四阶段进度展示 -->
+      <mat-card class="recruitment-phases">
+        <mat-card-header>
+          <mat-card-title>
+            <mat-icon>analytics</mat-icon>
+            招聘四阶段进度统计
+          </mat-card-title>
+        </mat-card-header>
+        <mat-card-content>
+          <div class="phases-overview">
+            @for (phase of recruitmentPhases; track phase.name) {
+              <div class="phase-card" [class]="getPhaseStatus(phase.name)">
+                <div class="phase-header">
+                  <mat-icon [style.color]="phase.color">{{ phase.icon }}</mat-icon>
+                  <h4>{{ phase.name }}</h4>
+                </div>
+                <div class="phase-content">
+                  <div class="phase-stats">
+                    <div class="stat-item">
+                      <span class="stat-label">候选人数</span>
+                      <span class="stat-value">{{ getPhaseCount(phase.name) }}</span>
+                    </div>
+                    <div class="stat-item">
+                      <span class="stat-label">通过率</span>
+                      <span class="stat-value">{{ getPhasePassRate(phase.name) }}%</span>
+                    </div>
+                  </div>
+                  <mat-progress-bar 
+                    mode="determinate" 
+                    [value]="getPhasePassRate(phase.name)"
+                    [color]="getPhaseStatus(phase.name) === 'completed' ? 'primary' : 'accent'">
+                  </mat-progress-bar>
+                  <p class="phase-description">{{ phase.description }}</p>
+                </div>
+                <div class="phase-status">
+                  @if (getPhaseStatus(phase.name) === 'completed') {
+                    <mat-icon class="status-icon completed">check_circle</mat-icon>
+                    <span>已完成</span>
+                  } @else if (getPhaseStatus(phase.name) === 'in-progress') {
+                    <mat-icon class="status-icon in-progress">schedule</mat-icon>
+                    <span>进行中</span>
+                  } @else {
+                    <mat-icon class="status-icon pending">radio_button_unchecked</mat-icon>
+                    <span>待开始</span>
+                  }
+                </div>
+              </div>
+            }
+          </div>
+        </mat-card-content>
+      </mat-card>
+
+      <!-- 招聘流程跟踪 -->
+      <mat-card class="recruitment-stages">
+        <mat-card-header>
+          <mat-card-title>
+            <mat-icon>timeline</mat-icon>
+            招聘流程跟踪
+          </mat-card-title>
+        </mat-card-header>
+        <mat-card-content>
+          <!-- 当前状态概览 -->
+          <div class="current-status">
+            <div class="status-info">
+              <h4>当前状态:{{ getCurrentStageStatus() }}</h4>
+              <mat-progress-bar mode="determinate" [value]="getStageProgress()" class="progress-bar"></mat-progress-bar>
+              <span class="progress-text">进度:{{ getStageProgress() }}%</span>
+            </div>
+          </div>
+
+          <!-- 阶段时间线 -->
+          <div class="stages-timeline">
+            @for (stage of recruitmentStages(); track $index) {
+              <div class="timeline-item">
+                <div class="timeline-marker"></div>
+                <div class="timeline-content">
+                  <div class="stage-header">
+                    <h5>{{ stage.stage }}</h5>
+                    <span class="stage-result" [class]="stage.result">{{ stage.result }}</span>
+                  </div>
+                  <div class="stage-details">
+                    <p><strong>评估人:</strong>{{ stage.evaluator }}</p>
+                    <p><strong>评估时间:</strong>{{ stage.evaluationTime | date:'yyyy-MM-dd HH:mm' }}</p>
+                    @if (stage.comments) {
+                      <p><strong>备注:</strong>{{ stage.comments }}</p>
+                    }
+                  </div>
+                </div>
+              </div>
+            }
+          </div>
+
+          <!-- 添加新阶段 -->
+          <div class="add-stage-form">
+            <h4>添加流程记录</h4>
+            <div class="form-row">
+              <mat-form-field appearance="outline">
+                <mat-label>阶段</mat-label>
+                <mat-select [(ngModel)]="newStage.stage">
+                  <mat-option value="简历初筛">简历初筛</mat-option>
+                  <mat-option value="面试评估">面试评估</mat-option>
+                  <mat-option value="入职评定">入职评定</mat-option>
+                  <mat-option value="试用期跟踪">试用期跟踪</mat-option>
+                </mat-select>
+              </mat-form-field>
+
+              <mat-form-field appearance="outline">
+                <mat-label>结果</mat-label>
+                <mat-select [(ngModel)]="newStage.result">
+                  <mat-option value="通过">通过</mat-option>
+                  <mat-option value="待定">待定</mat-option>
+                  <mat-option value="不通过">不通过</mat-option>
+                </mat-select>
+              </mat-form-field>
+
+              <mat-form-field appearance="outline">
+                <mat-label>评估人</mat-label>
+                <input matInput [(ngModel)]="newStage.evaluator">
+              </mat-form-field>
+            </div>
+
+            <mat-form-field appearance="outline" class="full-width">
+              <mat-label>备注</mat-label>
+              <textarea matInput rows="3" [(ngModel)]="newStage.comments"></textarea>
+            </mat-form-field>
+
+            <div class="form-actions">
+              <button mat-raised-button color="primary" (click)="addRecruitmentStage()" [disabled]="!newStage.evaluator.trim()">
+                <mat-icon>add</mat-icon>
+                添加记录
+              </button>
+            </div>
+          </div>
+
+          <!-- 试用期跟踪关联 -->
+          <div class="probation-tracking">
+            <h4>试用期跟踪</h4>
+            <div class="tracking-info">
+              <p>与新人跟进模块关联,实时跟踪试用期表现</p>
+              <div class="tracking-metrics">
+                <div class="metric-item">
+                  <span class="metric-label">绩效得分:</span>
+                  <span class="metric-value">85分</span>
+                </div>
+                <div class="metric-item">
+                  <span class="metric-label">改进记录:</span>
+                  <span class="metric-value">3条</span>
+                </div>
+              </div>
+              <button mat-stroked-button color="primary">
+                <mat-icon>open_in_new</mat-icon>
+                查看详细跟进
+              </button>
+            </div>
+          </div>
+        </mat-card-content>
+      </mat-card>
+    </div>
+  }
+
+  <!-- 绩效统计与分析模块 -->
+  @if (activeTab() === 1) {
+    <div class="performance-analysis">
+      <!-- 筛选控件 -->
+      <mat-card class="filter-section">
+        <mat-card-content>
+          <div class="filter-controls">
+            <mat-form-field appearance="outline">
+              <mat-label>部门</mat-label>
+              <mat-select [(ngModel)]="filterDepartment" (selectionChange)="applyFilters()">
+                <mat-option value="">全部部门</mat-option>
+                @for (dept of getDepartments(); track dept) {
+                  <mat-option [value]="dept">{{ dept }}</mat-option>
+                }
+              </mat-select>
+            </mat-form-field>
+
+            <mat-form-field appearance="outline">
+              <mat-label>职级</mat-label>
+              <mat-select [(ngModel)]="filterPositionLevel" (selectionChange)="applyFilters()">
+                <mat-option value="">全部职级</mat-option>
+                <mat-option value="高级">高级</mat-option>
+                <mat-option value="中级">中级</mat-option>
+                <mat-option value="初级">初级</mat-option>
+              </mat-select>
+            </mat-form-field>
+
+            <mat-form-field appearance="outline">
+              <mat-label>入职时间</mat-label>
+              <input matInput type="month" [(ngModel)]="filterHireDate" (change)="applyFilters()">
+            </mat-form-field>
+
+            <div class="filter-actions">
+              <button mat-raised-button color="primary" (click)="applyFilters()">
+                <mat-icon>search</mat-icon>
+                筛选
+              </button>
+              <button mat-stroked-button (click)="resetFilters()">
+                <mat-icon>refresh</mat-icon>
+                重置
+              </button>
+            </div>
+          </div>
+        </mat-card-content>
+      </mat-card>
+
+      <!-- 核心指标展示区 -->
+      <div class="metrics-overview">
+        <div class="metrics-grid">
+          <mat-card class="metric-card">
+            <mat-card-content>
+              <div class="metric-header">
+                <mat-icon>assignment_turned_in</mat-icon>
+                <h3>项目完成率</h3>
+              </div>
+              <div class="metric-value">{{ calculateOverallAverage().projectCompletionRate | number:'1.0-0' }}%</div>
+              <div class="metric-trend positive">
+                <mat-icon>trending_up</mat-icon>
+                <span>+5.2%</span>
+              </div>
+            </mat-card-content>
+          </mat-card>
+
+          <mat-card class="metric-card">
+            <mat-card-content>
+              <div class="metric-header">
+                <mat-icon>star</mat-icon>
+                <h3>优秀工作率</h3>
+              </div>
+              <div class="metric-value">{{ calculateOverallAverage().excellentWorkRate | number:'1.0-0' }}%</div>
+              <div class="metric-trend positive">
+                <mat-icon>trending_up</mat-icon>
+                <span>+2.1%</span>
+              </div>
+            </mat-card-content>
+          </mat-card>
+
+          <mat-card class="metric-card">
+            <mat-card-content>
+              <div class="metric-header">
+                <mat-icon>sentiment_satisfied</mat-icon>
+                <h3>客户满意度</h3>
+              </div>
+              <div class="metric-value">{{ calculateOverallAverage().customerSatisfaction | number:'1.0-0' }}%</div>
+              <div class="metric-trend neutral">
+                <mat-icon>trending_flat</mat-icon>
+                <span>0%</span>
+              </div>
+            </mat-card-content>
+          </mat-card>
+
+          <mat-card class="metric-card">
+            <mat-card-content>
+              <div class="metric-header">
+                <mat-icon>schedule</mat-icon>
+                <h3>逾期率</h3>
+              </div>
+              <div class="metric-value">{{ calculateOverallAverage().overdueRate | number:'1.0-1' }}%</div>
+              <div class="metric-trend negative">
+                <mat-icon>trending_down</mat-icon>
+                <span>-1.5%</span>
+              </div>
+            </mat-card-content>
+          </mat-card>
+
+          <mat-card class="metric-card">
+            <mat-card-content>
+              <div class="metric-header">
+                <mat-icon>school</mat-icon>
+                <h3>培训完成率</h3>
+              </div>
+              <div class="metric-value">{{ calculateOverallAverage().trainingCompletionRate | number:'1.0-0' }}%</div>
+              <div class="metric-trend positive">
+                <mat-icon>trending_up</mat-icon>
+                <span>+3.8%</span>
+              </div>
+            </mat-card-content>
+          </mat-card>
+        </div>
+      </div>
+
+      <!-- 绩效对比表 -->
+      <mat-card class="comparison-table">
+        <mat-card-header>
+          <mat-card-title>
+            <mat-icon>compare_arrows</mat-icon>
+            绩效对比分析
+          </mat-card-title>
+        </mat-card-header>
+        <mat-card-content>
+          <div class="comparison-tabs">
+            <button mat-stroked-button class="active">同职级对比</button>
+            <button mat-stroked-button>历史对比</button>
+          </div>
+
+          <div class="comparison-content">
+            <div class="department-comparison">
+              @for (dept of getDepartments(); track dept) {
+                <div class="dept-section">
+                  <h4>{{ dept }}</h4>
+                  <div class="metrics-comparison">
+                    <div class="comparison-item">
+                      <span class="metric-name">项目完成率</span>
+                      <div class="comparison-bar">
+                        <mat-progress-bar mode="determinate" [value]="calculateDepartmentAverage(dept).projectCompletionRate"></mat-progress-bar>
+                        <span class="value">{{ calculateDepartmentAverage(dept).projectCompletionRate }}%</span>
+                      </div>
+                    </div>
+                    <div class="comparison-item">
+                      <span class="metric-name">优秀工作率</span>
+                      <div class="comparison-bar">
+                        <mat-progress-bar mode="determinate" [value]="calculateDepartmentAverage(dept).excellentWorkRate"></mat-progress-bar>
+                        <span class="value">{{ calculateDepartmentAverage(dept).excellentWorkRate }}%</span>
+                      </div>
+                    </div>
+                    <div class="comparison-item">
+                      <span class="metric-name">客户满意度</span>
+                      <div class="comparison-bar">
+                        <mat-progress-bar mode="determinate" [value]="calculateDepartmentAverage(dept).customerSatisfaction"></mat-progress-bar>
+                        <span class="value">{{ calculateDepartmentAverage(dept).customerSatisfaction }}%</span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              }
+            </div>
+          </div>
+        </mat-card-content>
+      </mat-card>
+
+      <!-- 离职原因分析 -->
+      <mat-card class="turnover-analysis">
+        <mat-card-header>
+          <mat-card-title>
+            <mat-icon>exit_to_app</mat-icon>
+            离职原因分析
+          </mat-card-title>
+        </mat-card-header>
+        <mat-card-content>
+          <!-- 筛选控件 -->
+          <div class="turnover-filters">
+            <mat-form-field appearance="outline">
+              <mat-label>部门</mat-label>
+              <mat-select [(ngModel)]="filterTurnoverDepartment">
+                <mat-option value="">全部部门</mat-option>
+                @for (dept of getDepartments(); track dept) {
+                  <mat-option [value]="dept">{{ dept }}</mat-option>
+                }
+              </mat-select>
+            </mat-form-field>
+
+            <mat-form-field appearance="outline">
+              <mat-label>时间范围</mat-label>
+              <mat-select [(ngModel)]="filterTurnoverDateRange">
+                <mat-option value="">全部时间</mat-option>
+                <mat-option value="last3months">近3个月</mat-option>
+                <mat-option value="last6months">近6个月</mat-option>
+                <mat-option value="lastyear">近1年</mat-option>
+              </mat-select>
+            </mat-form-field>
+
+            <div class="filter-actions">
+              <button mat-raised-button color="primary" (click)="applyTurnoverFilters()">
+                <mat-icon>filter_list</mat-icon>
+                应用筛选
+              </button>
+              <button mat-stroked-button (click)="resetTurnoverFilters()">
+                <mat-icon>clear</mat-icon>
+                重置
+              </button>
+            </div>
+          </div>
+
+          <!-- 分类筛选 -->
+          <div class="category-filters">
+            <mat-chip-set>
+              <mat-chip selected>全部员工</mat-chip>
+              <mat-chip>新人离职</mat-chip>
+              <mat-chip>资深员工离职</mat-chip>
+            </mat-chip-set>
+          </div>
+
+          <!-- 总体离职情况 -->
+          <div class="overall-turnover">
+            <h4>总体离职情况</h4>
+            <div class="turnover-stats">
+              @for (stat of getTurnoverStats(); track stat.reason) {
+                <div class="stat-item">
+                  <div class="stat-header">
+                    <span class="reason-name">{{ stat.reason }}</span>
+                    <span class="reason-count">{{ stat.totalCount }}人</span>
+                  </div>
+                  <div class="stat-bar">
+                    <mat-progress-bar 
+                      mode="determinate" 
+                      [value]="stat.totalPercentage"
+                      [style.--mdc-linear-progress-active-indicator-color]="getReasonColor(stat.reason)">
+                    </mat-progress-bar>
+                    <span class="percentage">{{ stat.totalPercentage }}%</span>
+                  </div>
+                </div>
+              }
+            </div>
+          </div>
+
+          <!-- 分类离职分析 -->
+          <div class="category-analysis">
+            <h4>分类离职分析</h4>
+            <div class="analysis-grid">
+              @for (analysis of turnoverAnalyses(); track analysis.category) {
+                <div class="analysis-section">
+                  <h5>{{ analysis.category }}</h5>
+                  <div class="reasons-list">
+                    @for (reason of analysis.reasons; track reason.reason) {
+                      <div class="reason-item">
+                        <span class="reason-label">{{ reason.reason }}</span>
+                        <div class="reason-stats">
+                          <mat-progress-bar 
+                            mode="determinate" 
+                            [value]="reason.percentage"
+                            [style.--mdc-linear-progress-active-indicator-color]="getReasonColor(reason.reason)">
+                          </mat-progress-bar>
+                          <span class="stats-text">{{ reason.count }}人 ({{ reason.percentage }}%)</span>
+                        </div>
+                      </div>
+                    }
+                  </div>
+                </div>
+              }
+            </div>
+          </div>
+
+          <!-- 图表展示 -->
+          <div class="charts-section">
+            <div class="charts-grid">
+              <div class="chart-container">
+                <div #turnoverPieChart class="pie-chart"></div>
+              </div>
+              <div class="chart-container">
+                <div #categoryPieChart class="pie-chart"></div>
+              </div>
+            </div>
+          </div>
+
+          <!-- 导出操作 -->
+          <div class="export-actions">
+            <button mat-raised-button color="primary" (click)="generateTurnoverReport()">
+              <mat-icon>file_download</mat-icon>
+              导出离职分析报告
+            </button>
+            <button mat-stroked-button (click)="generatePerformanceReport()">
+              <mat-icon>assessment</mat-icon>
+              生成绩效报告
+            </button>
+          </div>
+        </mat-card-content>
+      </mat-card>
+    </div>
+  }
+</div>

+ 1582 - 0
src/app/pages/hr/recruitment-performance/recruitment-performance.scss

@@ -0,0 +1,1582 @@
+.recruitment-performance-container {
+  padding: 20px;
+  background: #f2f2f7; // iOS系统背景色
+  min-height: 100vh;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+
+  // iOS风格顶部导航
+  .top-navigation {
+    margin-bottom: 20px;
+    
+    .nav-buttons {
+      display: flex;
+      gap: 8px;
+      justify-content: center;
+      padding: 6px;
+      background: rgba(255, 255, 255, 0.85);
+      backdrop-filter: blur(20px);
+      border-radius: 14px;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+      
+      .nav-button {
+        min-width: 160px;
+        height: 40px;
+        border-radius: 10px;
+        font-size: 15px;
+        font-weight: 500;
+        background: transparent;
+        color: #007AFF;
+        border: none;
+        transition: all 0.15s ease;
+        flex: 1;
+        
+        mat-icon {
+          margin-right: 6px;
+        }
+        
+        &:hover {
+          background: rgba(0, 122, 255, 0.08);
+        }
+        
+        &:active {
+          transform: scale(0.97);
+        }
+        
+        &.active {
+          background: #007AFF;
+          color: white;
+          box-shadow: 0 1px 4px rgba(0, 122, 255, 0.25);
+          font-weight: 600;
+        }
+      }
+    }
+  }
+
+  // iOS风格卡片样式
+  mat-card {
+    border-radius: 16px;
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+    border: 0.5px solid rgba(0, 0, 0, 0.04);
+    background: rgba(255, 255, 255, 0.9);
+    backdrop-filter: blur(20px);
+    margin-bottom: 20px;
+    transition: all 0.2s ease;
+    
+    &:hover {
+      transform: translateY(-1px);
+      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+    }
+    
+    &:active {
+      transform: scale(0.995);
+    }
+    
+    mat-card-header {
+      padding: 20px 24px 16px;
+      
+      mat-card-title {
+        display: flex;
+        align-items: center;
+        font-size: 22px;
+        font-weight: 600;
+        color: #1d1d1f;
+        letter-spacing: -0.5px;
+        
+        mat-icon {
+          margin-right: 12px;
+          color: #007AFF;
+          font-size: 24px;
+        }
+      }
+    }
+    
+    mat-card-content {
+      padding: 0 24px 24px;
+    }
+  }
+
+  // 招聘四阶段进度展示
+  .recruitment-phases {
+    .phases-overview {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+      gap: 24px;
+      margin-top: 16px;
+      
+      .phase-card {
+        background: rgba(255, 255, 255, 0.9);
+        border-radius: 16px;
+        padding: 24px;
+        border: 2px solid transparent;
+        transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+        position: relative;
+        overflow: hidden;
+        
+        &::before {
+          content: '';
+          position: absolute;
+          top: 0;
+          left: 0;
+          right: 0;
+          height: 4px;
+          background: linear-gradient(90deg, #e0e0e0, #e0e0e0);
+          transition: all 0.3s ease;
+        }
+        
+        &.completed::before {
+          background: linear-gradient(90deg, #4CAF50, #45a049);
+        }
+        
+        &.in-progress::before {
+          background: linear-gradient(90deg, #FF9800, #f57c00);
+        }
+        
+        &.pending::before {
+          background: linear-gradient(90deg, #e0e0e0, #e0e0e0);
+        }
+        
+        &:hover {
+          transform: translateY(-4px);
+          box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
+          border-color: rgba(102, 126, 234, 0.3);
+        }
+        
+        .phase-header {
+          display: flex;
+          align-items: center;
+          margin-bottom: 20px;
+          
+          mat-icon {
+            font-size: 32px;
+            width: 32px;
+            height: 32px;
+            margin-right: 16px;
+          }
+          
+          h4 {
+            margin: 0;
+            font-size: 18px;
+            font-weight: 600;
+            color: #333;
+          }
+        }
+        
+        .phase-content {
+          margin-bottom: 20px;
+          
+          .phase-stats {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 16px;
+            
+            .stat-item {
+              text-align: center;
+              
+              .stat-label {
+                display: block;
+                font-size: 12px;
+                color: #666;
+                margin-bottom: 4px;
+              }
+              
+              .stat-value {
+                display: block;
+                font-size: 20px;
+                font-weight: 600;
+                color: #333;
+              }
+            }
+          }
+          
+          mat-progress-bar {
+            margin-bottom: 12px;
+            height: 8px;
+            border-radius: 4px;
+            
+            ::ng-deep .mat-progress-bar-fill::after {
+              border-radius: 4px;
+            }
+            
+            ::ng-deep .mat-progress-bar-buffer {
+              border-radius: 4px;
+            }
+          }
+          
+          .phase-description {
+            font-size: 14px;
+            color: #666;
+            line-height: 1.5;
+            margin: 0;
+          }
+        }
+        
+        .phase-status {
+          display: flex;
+          align-items: center;
+          font-size: 14px;
+          font-weight: 500;
+          
+          .status-icon {
+            margin-right: 8px;
+            font-size: 18px;
+            
+            &.completed {
+              color: #4CAF50;
+            }
+            
+            &.in-progress {
+              color: #FF9800;
+            }
+            
+            &.pending {
+              color: #e0e0e0;
+            }
+          }
+        }
+      }
+    }
+}
+
+// 响应式布局
+@media (max-width: 768px) {
+  .recruitment-performance-container {
+    padding: 16px;
+    
+    .top-navigation {
+      .nav-buttons {
+        flex-direction: column;
+        gap: 8px;
+        
+        .nav-button {
+          min-width: auto;
+          width: 100%;
+          height: 44px;
+        }
+      }
+    }
+    
+    mat-card {
+      margin-bottom: 16px;
+      
+      mat-card-header {
+        padding: 16px 20px 12px;
+        
+        mat-card-title {
+          font-size: 20px;
+          
+          mat-icon {
+            margin-right: 8px;
+            font-size: 20px;
+          }
+        }
+      }
+      
+      mat-card-content {
+        padding: 0 20px 20px;
+      }
+    }
+    
+    // 招聘四阶段进度展示
+    .recruitment-phases {
+      grid-template-columns: 1fr;
+      gap: 12px;
+      
+      .phase-card {
+        padding: 16px;
+        
+        .phase-header {
+          .phase-icon {
+            width: 32px;
+            height: 32px;
+            font-size: 16px;
+          }
+          
+          .phase-title {
+            font-size: 16px;
+          }
+        }
+        
+        .phase-content {
+          .phase-stats {
+            flex-direction: column;
+            gap: 8px;
+            
+            .stat-item {
+              .stat-value {
+                font-size: 20px;
+              }
+              
+              .stat-label {
+                font-size: 12px;
+              }
+            }
+          }
+        }
+      }
+    }
+    
+    // 绩效统计模块
+    .performance-analysis {
+      .filter-section {
+        flex-direction: column;
+        gap: 12px;
+        
+        mat-form-field {
+          min-width: auto;
+          width: 100%;
+        }
+        
+        .filter-actions {
+          justify-content: stretch;
+          
+          button {
+            flex: 1;
+          }
+        }
+      }
+      
+      .metrics-grid {
+        grid-template-columns: repeat(2, 1fr);
+        gap: 12px;
+        
+        .metric-card {
+          padding: 16px;
+          
+          .metric-value {
+            font-size: 24px;
+          }
+          
+          .metric-label {
+            font-size: 12px;
+          }
+        }
+      }
+    }
+    
+    // 离职分析模块
+    .turnover-analysis {
+      .filter-section {
+        flex-direction: column;
+        gap: 12px;
+        
+        mat-form-field {
+          min-width: auto;
+          width: 100%;
+        }
+        
+        .filter-actions {
+          justify-content: stretch;
+          
+          button {
+            flex: 1;
+          }
+        }
+      }
+      
+      .analysis-grid {
+        grid-template-columns: 1fr;
+        gap: 16px;
+      }
+      
+      .charts-grid {
+        grid-template-columns: 1fr;
+        gap: 16px;
+        
+        .chart-container {
+          padding: 16px;
+          
+          .pie-chart {
+            height: 300px;
+          }
+        }
+      }
+      
+      .export-actions {
+        flex-direction: column;
+        gap: 12px;
+        
+        button {
+          width: 100%;
+        }
+      }
+    }
+  }
+}
+
+@media (max-width: 480px) {
+  .recruitment-performance-container {
+    padding: 12px;
+    
+    mat-card {
+      border-radius: 12px;
+      
+      mat-card-header {
+        padding: 12px 16px 8px;
+        
+        mat-card-title {
+          font-size: 18px;
+        }
+      }
+      
+      mat-card-content {
+        padding: 0 16px 16px;
+      }
+    }
+    
+    .metrics-grid {
+      grid-template-columns: 1fr !important;
+      gap: 8px;
+    }
+    
+    .charts-grid {
+      .pie-chart {
+        height: 250px !important;
+      }
+    }
+  }
+}
+
+// 离职分析模块
+.turnover-analysis {
+  .filter-section {
+    display: flex;
+    gap: 16px;
+    margin-bottom: 24px;
+    flex-wrap: wrap;
+    
+    mat-form-field {
+      min-width: 200px;
+    }
+    
+    .filter-actions {
+      display: flex;
+      gap: 12px;
+      align-items: flex-end;
+      
+      button {
+        height: 36px;
+        border-radius: 10px;
+        font-weight: 500;
+        font-size: 15px;
+        transition: all 0.15s ease;
+        
+        &[color="primary"] {
+          background: #007AFF;
+          border: none;
+          color: white;
+          
+          &:hover {
+            background: #0056CC;
+            transform: translateY(-1px);
+            box-shadow: 0 2px 8px rgba(0, 122, 255, 0.3);
+          }
+          
+          &:active {
+            transform: scale(0.96);
+          }
+        }
+        
+        &[mat-stroked-button] {
+          border: 1px solid #007AFF;
+          color: #007AFF;
+          background: transparent;
+          
+          &:hover {
+            background: rgba(0, 122, 255, 0.08);
+          }
+          
+          &:active {
+            transform: scale(0.96);
+          }
+        }
+      }
+    }
+  }
+  
+  .category-filters {
+    margin-bottom: 24px;
+    
+    mat-chip-set {
+      display: flex;
+      gap: 8px;
+      
+      mat-chip {
+        border-radius: 20px;
+        font-weight: 500;
+        
+        &[selected] {
+          background: linear-gradient(135deg, #667eea, #764ba2);
+          color: white;
+        }
+      }
+    }
+  }
+  
+  .overall-turnover {
+    margin-bottom: 32px;
+    
+    h4 {
+      margin-bottom: 20px;
+      color: #333;
+      font-weight: 600;
+      font-size: 18px;
+    }
+    
+    .turnover-stats {
+      display: grid;
+      gap: 16px;
+      
+      .stat-item {
+        padding: 20px;
+        background: #fff;
+        border-radius: 12px;
+        border: 1px solid #e0e0e0;
+        transition: all 0.3s ease;
+        
+        &:hover {
+          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+          transform: translateY(-2px);
+        }
+        
+        .stat-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 12px;
+          
+          .reason-name {
+            font-weight: 600;
+            color: #333;
+            font-size: 16px;
+          }
+          
+          .reason-count {
+            font-weight: 700;
+            color: #667eea;
+            font-size: 18px;
+          }
+        }
+        
+        .stat-bar {
+          display: flex;
+          align-items: center;
+          gap: 12px;
+          
+          mat-progress-bar {
+            flex: 1;
+            height: 8px;
+            border-radius: 4px;
+          }
+          
+          .percentage {
+            font-weight: 600;
+            color: #666;
+            min-width: 40px;
+            text-align: right;
+          }
+        }
+      }
+    }
+  }
+  
+  .category-analysis {
+    margin-bottom: 32px;
+    
+    h4 {
+      margin-bottom: 20px;
+      color: #333;
+      font-weight: 600;
+      font-size: 18px;
+    }
+    
+    .analysis-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
+      gap: 24px;
+      
+      .analysis-section {
+        padding: 24px;
+        background: #fff;
+        border-radius: 16px;
+        border: 1px solid #e0e0e0;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+        
+        h5 {
+          margin-bottom: 20px;
+          color: #333;
+          font-weight: 600;
+          font-size: 16px;
+          padding-bottom: 12px;
+          border-bottom: 2px solid #f0f0f0;
+        }
+        
+        .reasons-list {
+          display: grid;
+          gap: 16px;
+          
+          .reason-item {
+            padding: 16px;
+            background: #f8f9fa;
+            border-radius: 12px;
+            transition: all 0.3s ease;
+            
+            &:hover {
+              background: #f0f2f5;
+            }
+            
+            .reason-label {
+              display: block;
+              font-weight: 600;
+              color: #333;
+              margin-bottom: 12px;
+            }
+            
+            .reason-stats {
+              display: flex;
+              align-items: center;
+              gap: 12px;
+              
+              mat-progress-bar {
+                flex: 1;
+                height: 6px;
+                border-radius: 3px;
+              }
+              
+              .stats-text {
+                font-weight: 500;
+                color: #666;
+                font-size: 14px;
+                min-width: 80px;
+                text-align: right;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  
+  .charts-section {
+    margin-bottom: 32px;
+    
+    .charts-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
+      gap: 24px;
+      
+      .chart-container {
+        padding: 24px;
+        background: #fff;
+        border-radius: 16px;
+        border: 1px solid #e0e0e0;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+        
+        .pie-chart {
+          width: 100%;
+          height: 400px;
+        }
+      }
+    }
+  }
+  
+  .export-actions {
+    display: flex;
+    gap: 16px;
+    justify-content: center;
+    padding: 24px 0;
+    
+    button {
+      padding: 12px 24px;
+      border-radius: 8px;
+      font-weight: 500;
+      
+      &[color="primary"] {
+        background: linear-gradient(135deg, #667eea, #764ba2);
+        border: none;
+        
+        &:hover {
+          background: linear-gradient(135deg, #5a6fd8, #6a4190);
+        }
+      }
+      
+      mat-icon {
+        margin-right: 8px;
+      }
+    }
+  }
+}
+
+// 招聘流程优化模块
+  .recruitment-optimization {
+    .ai-analysis-section {
+      .upload-area {
+        margin-bottom: 32px;
+        
+        .upload-zone {
+          border: 2px dashed #667eea;
+          border-radius: 16px;
+          padding: 48px 24px;
+          text-align: center;
+          background: linear-gradient(135deg, rgba(102, 126, 234, 0.05) 0%, rgba(118, 75, 162, 0.05) 100%);
+          cursor: pointer;
+          transition: all 0.3s ease;
+          
+          &:hover {
+            border-color: #764ba2;
+            background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
+            transform: translateY(-2px);
+          }
+          
+          .upload-icon {
+            font-size: 48px;
+            color: #667eea;
+            margin-bottom: 16px;
+          }
+          
+          p {
+            margin: 8px 0;
+            font-size: 16px;
+            color: #333;
+            
+            &.upload-hint {
+              font-size: 14px;
+              color: #666;
+            }
+          }
+        }
+      }
+      
+      .analysis-results {
+        .result-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 24px;
+          padding-bottom: 16px;
+          border-bottom: 1px solid #eee;
+          
+          h3 {
+            margin: 0;
+            color: #333;
+            font-weight: 600;
+          }
+          
+          .upload-time {
+            color: #666;
+            font-size: 14px;
+          }
+        }
+        
+        .processing-state {
+          text-align: center;
+          padding: 48px 24px;
+          
+          mat-spinner {
+            margin-bottom: 16px;
+          }
+          
+          p {
+            color: #666;
+            font-size: 16px;
+          }
+        }
+        
+        .completed-analysis {
+          .recommendation-section {
+            margin-bottom: 32px;
+            text-align: center;
+            
+            .recommendation-badge {
+              display: inline-block;
+              padding: 12px 24px;
+              border-radius: 20px;
+              font-size: 16px;
+              font-weight: 600;
+              margin-bottom: 16px;
+              
+              &.推荐 {
+                background: linear-gradient(135deg, #4CAF50, #45a049);
+                color: white;
+              }
+              
+              &.不推荐 {
+                background: linear-gradient(135deg, #f44336, #d32f2f);
+                color: white;
+              }
+              
+              &.待定 {
+                background: linear-gradient(135deg, #ff9800, #f57c00);
+                color: white;
+              }
+            }
+            
+            .recommendation-reason {
+              color: #666;
+              font-size: 16px;
+              line-height: 1.6;
+            }
+          }
+          
+          .skills-analysis {
+            margin-bottom: 32px;
+            
+            h4 {
+              margin-bottom: 20px;
+              color: #333;
+              font-weight: 600;
+            }
+            
+            .skills-grid {
+              display: grid;
+              grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+              gap: 16px;
+              margin-bottom: 20px;
+              
+              .skill-item {
+                padding: 16px;
+                border-radius: 12px;
+                background: #f8f9fa;
+                border: 2px solid transparent;
+                transition: all 0.3s ease;
+                
+                &.matched {
+                  border-color: #4CAF50;
+                  background: rgba(76, 175, 80, 0.05);
+                }
+                
+                .skill-name {
+                  display: block;
+                  font-weight: 600;
+                  margin-bottom: 8px;
+                  color: #333;
+                }
+                
+                .skill-score {
+                  display: flex;
+                  align-items: center;
+                  gap: 12px;
+                  
+                  mat-progress-bar {
+                    flex: 1;
+                    height: 8px;
+                    border-radius: 4px;
+                  }
+                  
+                  .score-text {
+                    font-weight: 600;
+                    color: #667eea;
+                    min-width: 40px;
+                  }
+                }
+              }
+            }
+            
+            .skills-summary {
+              display: flex;
+              justify-content: space-between;
+              padding: 16px;
+              background: rgba(102, 126, 234, 0.05);
+              border-radius: 12px;
+              
+              span {
+                font-weight: 600;
+                color: #333;
+              }
+            }
+          }
+          
+          .screening-info {
+            h4 {
+              margin-bottom: 20px;
+              color: #333;
+              font-weight: 600;
+            }
+            
+            .info-grid {
+              display: grid;
+              gap: 16px;
+              
+              .info-item {
+                display: flex;
+                align-items: center;
+                padding: 12px 0;
+                border-bottom: 1px solid #eee;
+                
+                &:last-child {
+                  border-bottom: none;
+                }
+                
+                label {
+                  font-weight: 600;
+                  color: #333;
+                  min-width: 100px;
+                }
+                
+                span {
+                  color: #666;
+                }
+                
+                mat-chip-set {
+                  mat-chip {
+                    background: rgba(102, 126, 234, 0.1);
+                    color: #667eea;
+                    border: 1px solid rgba(102, 126, 234, 0.2);
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      
+      .analysis-history {
+        margin-top: 32px;
+        
+        h4 {
+          margin-bottom: 16px;
+          color: #333;
+          font-weight: 600;
+        }
+        
+        .history-list {
+          .history-item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 16px;
+            border-radius: 12px;
+            background: #f8f9fa;
+            margin-bottom: 8px;
+            cursor: pointer;
+            transition: all 0.3s ease;
+            
+            &:hover {
+              background: #e9ecef;
+              transform: translateX(4px);
+            }
+            
+            &.selected {
+              background: rgba(102, 126, 234, 0.1);
+              border: 2px solid #667eea;
+            }
+            
+            .item-info {
+              .file-name {
+                display: block;
+                font-weight: 600;
+                color: #333;
+                margin-bottom: 4px;
+              }
+              
+              .upload-time {
+                font-size: 12px;
+                color: #666;
+              }
+            }
+            
+            .item-status {
+              .status-icon {
+                &.processing {
+                  color: #ff9800;
+                }
+                
+                &.completed {
+                  color: #4CAF50;
+                }
+                
+                &.failed {
+                  color: #f44336;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    
+    .recruitment-stages {
+      .current-status {
+        margin-bottom: 32px;
+        padding: 24px;
+        background: linear-gradient(135deg, rgba(102, 126, 234, 0.05) 0%, rgba(118, 75, 162, 0.05) 100%);
+        border-radius: 16px;
+        
+        .status-info {
+          h4 {
+            margin-bottom: 16px;
+            color: #333;
+            font-weight: 600;
+          }
+          
+          .progress-bar {
+            height: 8px;
+            border-radius: 4px;
+            margin-bottom: 8px;
+          }
+          
+          .progress-text {
+            font-size: 14px;
+            color: #666;
+          }
+        }
+      }
+      
+      .stages-timeline {
+        margin-bottom: 32px;
+        
+        .timeline-item {
+          display: flex;
+          margin-bottom: 24px;
+          
+          .timeline-marker {
+            width: 16px;
+            height: 16px;
+            border-radius: 50%;
+            background: #667eea;
+            margin-right: 16px;
+            margin-top: 4px;
+            flex-shrink: 0;
+          }
+          
+          .timeline-content {
+            flex: 1;
+            
+            .stage-header {
+              display: flex;
+              align-items: center;
+              gap: 12px;
+              margin-bottom: 8px;
+              
+              h5 {
+                margin: 0;
+                color: #333;
+                font-weight: 600;
+              }
+              
+              .stage-result {
+                padding: 4px 12px;
+                border-radius: 12px;
+                font-size: 12px;
+                font-weight: 600;
+                
+                &.通过 {
+                  background: rgba(76, 175, 80, 0.1);
+                  color: #4CAF50;
+                }
+                
+                &.不通过 {
+                  background: rgba(244, 67, 54, 0.1);
+                  color: #f44336;
+                }
+                
+                &.待定 {
+                  background: rgba(255, 152, 0, 0.1);
+                  color: #ff9800;
+                }
+              }
+            }
+            
+            .stage-details {
+              color: #666;
+              font-size: 14px;
+              line-height: 1.6;
+              
+              p {
+                margin: 4px 0;
+              }
+            }
+          }
+        }
+      }
+      
+      .add-stage-form {
+        padding: 24px;
+        background: #f8f9fa;
+        border-radius: 16px;
+        
+        h4 {
+          margin-bottom: 20px;
+          color: #333;
+          font-weight: 600;
+        }
+        
+        .form-row {
+          display: grid;
+          grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+          gap: 16px;
+          margin-bottom: 16px;
+        }
+        
+        .full-width {
+          width: 100%;
+        }
+        
+        .form-actions {
+          display: flex;
+          justify-content: flex-end;
+          margin-top: 16px;
+          
+          button {
+            border-radius: 20px;
+            padding: 0 24px;
+          }
+        }
+      }
+      
+      .probation-tracking {
+        padding: 24px;
+        background: linear-gradient(135deg, rgba(76, 175, 80, 0.05) 0%, rgba(67, 160, 71, 0.05) 100%);
+        border-radius: 16px;
+        
+        h4 {
+          margin-bottom: 16px;
+          color: #333;
+          font-weight: 600;
+        }
+        
+        .tracking-info {
+          p {
+            color: #666;
+            margin-bottom: 16px;
+          }
+          
+          .tracking-metrics {
+            display: flex;
+            gap: 24px;
+            margin-bottom: 16px;
+            
+            .metric-item {
+              .metric-label {
+                font-weight: 600;
+                color: #333;
+              }
+              
+              .metric-value {
+                color: #4CAF50;
+                font-weight: 600;
+              }
+            }
+          }
+          
+          button {
+            border-radius: 20px;
+          }
+        }
+      }
+    }
+  }
+
+  // 绩效统计与分析模块
+  .performance-analysis {
+    .filter-section {
+      .filter-controls {
+        display: grid;
+        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+        gap: 16px;
+        align-items: end;
+        
+        .filter-actions {
+          display: flex;
+          gap: 12px;
+          
+          button {
+            border-radius: 20px;
+            padding: 0 20px;
+          }
+        }
+      }
+    }
+    
+    .metrics-overview {
+      margin-bottom: 32px;
+      
+      .metrics-grid {
+        display: grid;
+        grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
+        gap: 20px;
+        
+        .metric-card {
+          background: linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.7) 100%);
+          
+          mat-card-content {
+            padding: 24px;
+            
+            .metric-header {
+              display: flex;
+              align-items: center;
+              margin-bottom: 16px;
+              
+              mat-icon {
+                font-size: 24px;
+                margin-right: 12px;
+                color: #667eea;
+              }
+              
+              h3 {
+                margin: 0;
+                font-size: 16px;
+                font-weight: 600;
+                color: #333;
+              }
+            }
+            
+            .metric-value {
+              font-size: 32px;
+              font-weight: 700;
+              color: #333;
+              margin-bottom: 12px;
+            }
+            
+            .metric-trend {
+              display: flex;
+              align-items: center;
+              font-size: 14px;
+              font-weight: 600;
+              
+              mat-icon {
+                font-size: 18px;
+                margin-right: 4px;
+              }
+              
+              &.positive {
+                color: #4CAF50;
+              }
+              
+              &.negative {
+                color: #f44336;
+              }
+              
+              &.neutral {
+                color: #666;
+              }
+            }
+          }
+        }
+      }
+    }
+    
+    .comparison-table {
+      .comparison-tabs {
+        display: flex;
+        gap: 12px;
+        margin-bottom: 24px;
+        
+        button {
+          border-radius: 20px;
+          
+          &.active {
+            background: #667eea;
+            color: white;
+          }
+        }
+      }
+      
+      .comparison-content {
+        .department-comparison {
+          .dept-section {
+            margin-bottom: 32px;
+            
+            h4 {
+              margin-bottom: 20px;
+              color: #333;
+              font-weight: 600;
+              padding-bottom: 8px;
+              border-bottom: 2px solid #667eea;
+            }
+            
+            .metrics-comparison {
+              .comparison-item {
+                display: flex;
+                align-items: center;
+                margin-bottom: 16px;
+                
+                .metric-name {
+                  min-width: 120px;
+                  font-weight: 600;
+                  color: #333;
+                }
+                
+                .comparison-bar {
+                  flex: 1;
+                  display: flex;
+                  align-items: center;
+                  gap: 12px;
+                  
+                  mat-progress-bar {
+                    flex: 1;
+                    height: 8px;
+                    border-radius: 4px;
+                  }
+                  
+                  .value {
+                    font-weight: 600;
+                    color: #667eea;
+                    min-width: 40px;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    
+    .turnover-analysis {
+      .turnover-filters {
+        display: grid;
+        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+        gap: 16px;
+        align-items: end;
+        margin-bottom: 24px;
+        
+        .filter-actions {
+          display: flex;
+          gap: 12px;
+          
+          button {
+            border-radius: 20px;
+          }
+        }
+      }
+      
+      .category-filters {
+        margin-bottom: 32px;
+        
+        mat-chip-set {
+          mat-chip {
+            border-radius: 16px;
+            
+            &[selected] {
+              background: #667eea;
+              color: white;
+            }
+          }
+        }
+      }
+      
+      .overall-turnover {
+        margin-bottom: 32px;
+        
+        h4 {
+          margin-bottom: 20px;
+          color: #333;
+          font-weight: 600;
+        }
+        
+        .turnover-stats {
+          .stat-item {
+            margin-bottom: 16px;
+            
+            .stat-header {
+              display: flex;
+              justify-content: space-between;
+              align-items: center;
+              margin-bottom: 8px;
+              
+              .reason-name {
+                font-weight: 600;
+                color: #333;
+              }
+              
+              .reason-count {
+                color: #666;
+                font-size: 14px;
+              }
+            }
+            
+            .stat-bar {
+              display: flex;
+              align-items: center;
+              gap: 12px;
+              
+              mat-progress-bar {
+                flex: 1;
+                height: 8px;
+                border-radius: 4px;
+              }
+              
+              .percentage {
+                font-weight: 600;
+                color: #333;
+                min-width: 40px;
+              }
+            }
+          }
+        }
+      }
+      
+      .category-analysis {
+        margin-bottom: 32px;
+        
+        h4 {
+          margin-bottom: 20px;
+          color: #333;
+          font-weight: 600;
+        }
+        
+        .analysis-grid {
+          display: grid;
+          grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+          gap: 24px;
+          
+          .analysis-section {
+            padding: 20px;
+            background: #f8f9fa;
+            border-radius: 16px;
+            
+            h5 {
+              margin-bottom: 16px;
+              color: #333;
+              font-weight: 600;
+            }
+            
+            .reasons-list {
+              .reason-item {
+                margin-bottom: 12px;
+                
+                .reason-label {
+                  display: block;
+                  font-weight: 600;
+                  color: #333;
+                  margin-bottom: 8px;
+                }
+                
+                .reason-stats {
+                  display: flex;
+                  align-items: center;
+                  gap: 12px;
+                  
+                  mat-progress-bar {
+                    flex: 1;
+                    height: 6px;
+                    border-radius: 3px;
+                  }
+                  
+                  .stats-text {
+                    font-size: 12px;
+                    color: #666;
+                    min-width: 80px;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      
+      .charts-section {
+        margin-bottom: 32px;
+        
+        .charts-grid {
+          display: grid;
+          grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
+          gap: 24px;
+          
+          .chart-container {
+            background: #f8f9fa;
+            border-radius: 16px;
+            padding: 20px;
+            
+            .pie-chart {
+              width: 100%;
+              height: 300px;
+            }
+          }
+        }
+      }
+      
+      .export-actions {
+        display: flex;
+        gap: 16px;
+        justify-content: center;
+        
+        button {
+          border-radius: 20px;
+          padding: 0 24px;
+        }
+      }
+    }
+  }
+
+  // 响应式设计
+  @media (max-width: 768px) {
+    padding: 16px;
+    
+    .top-navigation {
+      .nav-buttons {
+        flex-direction: column;
+        align-items: center;
+        
+        .nav-button {
+          width: 100%;
+          max-width: 300px;
+        }
+      }
+    }
+    
+    .metrics-overview {
+      .metrics-grid {
+        grid-template-columns: 1fr;
+      }
+    }
+    
+    .turnover-analysis {
+      .charts-section {
+        .charts-grid {
+          grid-template-columns: 1fr;
+        }
+      }
+      
+      .category-analysis {
+        .analysis-grid {
+          grid-template-columns: 1fr;
+        }
+      }
+    }
+    
+    .filter-section {
+      .filter-controls {
+        grid-template-columns: 1fr;
+        
+        .filter-actions {
+          justify-content: center;
+        }
+      }
+    }
+    
+    .add-stage-form {
+      .form-row {
+        grid-template-columns: 1fr;
+      }
+    }
+  }
+
+  @media (max-width: 480px) {
+    padding: 12px;
+    
+    mat-card {
+      mat-card-header,
+      mat-card-content {
+        padding: 16px;
+      }
+    }
+    
+    .metric-card {
+      mat-card-content {
+        padding: 16px;
+        
+        .metric-value {
+          font-size: 24px;
+        }
+      }
+    }
+    
+    .export-actions {
+      flex-direction: column;
+      
+      button {
+        width: 100%;
+      }
+    }
+  }
+}

+ 978 - 0
src/app/pages/hr/recruitment-performance/recruitment-performance.ts

@@ -0,0 +1,978 @@
+import { Component, signal, ViewChild, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { MatButtonModule } from '@angular/material/button';
+import { MatIconModule } from '@angular/material/icon';
+import { MatCardModule } from '@angular/material/card';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSelectModule } from '@angular/material/select';
+import { MatInputModule } from '@angular/material/input';
+import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { MatChipsModule } from '@angular/material/chips';
+import { MatExpansionModule } from '@angular/material/expansion';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { FormsModule } from '@angular/forms';
+import * as echarts from 'echarts';
+
+interface ResumeAnalysis {
+  id: string;
+  fileName: string;
+  uploadTime: Date;
+  status: 'processing' | 'completed' | 'failed';
+  analysisResult?: {
+    recommendation: '推荐' | '不推荐' | '待定';
+    reason: string;
+    coreSkills: Array<{
+      name: string;
+      score: number;
+      matched: boolean;
+    }>;
+    screeningInfo: {
+      education: string;
+      workYears: string;
+      coreSkills: string[];
+    };
+  };
+}
+
+interface RecruitmentStage {
+  stage: string;
+  result: string;
+  evaluator: string;
+  evaluationTime: Date;
+  comments?: string;
+}
+
+interface PerformanceMetric {
+  department: string;
+  positionLevel: string;
+  projectCompletionRate: number;
+  excellentWorkRate: number;
+  customerSatisfaction: number;
+  overdueRate: number;
+  trainingCompletionRate: number;
+}
+
+interface TurnoverAnalysis {
+  category: string;
+  reasons: Array<{
+    reason: string;
+    count: number;
+    percentage: number;
+  }>;
+}
+
+@Component({
+  selector: 'app-recruitment-performance',
+  standalone: true,
+  imports: [
+    CommonModule,
+    MatButtonModule,
+    MatIconModule,
+    MatCardModule,
+    MatFormFieldModule,
+    MatSelectModule,
+    MatInputModule,
+    MatProgressBarModule,
+    MatChipsModule,
+    MatExpansionModule,
+    MatProgressSpinnerModule,
+    MatTooltipModule,
+    FormsModule
+  ],
+  templateUrl: './recruitment-performance.html',
+  styleUrls: ['./recruitment-performance.scss']
+})
+export class RecruitmentPerformanceComponent implements AfterViewInit, OnDestroy {
+  // 页面状态管理
+  activeTab = signal(0);
+  
+  // AI简历分析相关
+  resumeAnalyses = signal<ResumeAnalysis[]>([]);
+  selectedResume = signal<ResumeAnalysis | null>(null);
+  
+  // 招聘流程跟踪
+  recruitmentStages = signal<RecruitmentStage[]>([]);
+  newStage = {
+    stage: '简历初筛',
+    result: '通过',
+    evaluator: '',
+    comments: ''
+  };
+
+  // 招聘四阶段定义
+  recruitmentPhases = [
+    {
+      name: '简历初筛',
+      description: '筛选符合基本要求的简历',
+      icon: 'description',
+      color: '#2196F3'
+    },
+    {
+      name: '面试评估',
+      description: '技能和文化匹配度评估',
+      icon: 'person',
+      color: '#FF9800'
+    },
+    {
+      name: '入职评定',
+      description: '最终录用决定和入职准备',
+      icon: 'how_to_reg',
+      color: '#4CAF50'
+    },
+    {
+      name: '试用期跟踪',
+      description: '试用期表现跟踪和评估',
+      icon: 'track_changes',
+      color: '#9C27B0'
+    }
+  ];
+
+  // 招聘统计数据
+  recruitmentStats = signal({
+    totalCandidates: 156,
+    resumeScreened: 89,
+    interviewed: 34,
+    hired: 12,
+    onProbation: 8
+  });
+  
+  // ECharts 实例
+  @ViewChild('turnoverPieChart', { static: false }) turnoverPieChart!: ElementRef;
+  @ViewChild('categoryPieChart', { static: false }) categoryPieChart!: ElementRef;
+  private turnoverChart: echarts.ECharts | null = null;
+  private categoryChart: echarts.ECharts | null = null;
+  
+  // 筛选表单数据
+  filterForm = {
+    department: '',
+    dateRange: '',
+    position: '',
+    performanceLevel: ''
+  };
+  filterDepartment = '';
+  filterPositionLevel = '';
+  filterHireDate = '';
+  filterTurnoverDepartment = '';
+  filterTurnoverDateRange = '';
+
+  // 筛选选项
+  departments = ['技术部', '产品部', '设计部', '市场部', '销售部', '人事部'];
+  positions = ['初级', '中级', '高级', '专家', '主管', '经理'];
+  performanceLevels = ['优秀', '良好', '一般', '待改进'];
+  dateRanges = [
+    { value: 'current_month', label: '本月' },
+    { value: 'last_month', label: '上月' },
+    { value: 'current_quarter', label: '本季度' },
+    { value: 'last_quarter', label: '上季度' },
+    { value: 'current_year', label: '本年度' },
+    { value: 'last_year', label: '去年' }
+  ];
+  
+  // 绩效统计数据
+  performanceMetrics = signal<PerformanceMetric[]>([
+    {
+      department: '设计部',
+      positionLevel: '高级',
+      projectCompletionRate: 95,
+      excellentWorkRate: 88,
+      customerSatisfaction: 92,
+      overdueRate: 5,
+      trainingCompletionRate: 100
+    },
+    {
+      department: '设计部',
+      positionLevel: '中级',
+      projectCompletionRate: 87,
+      excellentWorkRate: 75,
+      customerSatisfaction: 85,
+      overdueRate: 12,
+      trainingCompletionRate: 95
+    },
+    {
+      department: '技术部',
+      positionLevel: '高级',
+      projectCompletionRate: 92,
+      excellentWorkRate: 82,
+      customerSatisfaction: 89,
+      overdueRate: 8,
+      trainingCompletionRate: 98
+    },
+    {
+      department: '技术部',
+      positionLevel: '中级',
+      projectCompletionRate: 85,
+      excellentWorkRate: 70,
+      customerSatisfaction: 82,
+      overdueRate: 15,
+      trainingCompletionRate: 90
+    },
+    {
+      department: '市场部',
+      positionLevel: '高级',
+      projectCompletionRate: 90,
+      excellentWorkRate: 78,
+      customerSatisfaction: 88,
+      overdueRate: 10,
+      trainingCompletionRate: 96
+    }
+  ]);
+  
+  // 离职分析数据
+  turnoverAnalyses = signal<TurnoverAnalysis[]>([
+    {
+      category: '新人离职',
+      reasons: [
+        { reason: '工作压力大', count: 12, percentage: 35 },
+        { reason: '薪资不满', count: 8, percentage: 24 },
+        { reason: '发展空间有限', count: 7, percentage: 21 },
+        { reason: '团队氛围', count: 4, percentage: 12 },
+        { reason: '其他', count: 3, percentage: 8 }
+      ]
+    },
+    {
+      category: '资深员工离职',
+      reasons: [
+        { reason: '职业发展', count: 15, percentage: 42 },
+        { reason: '薪资待遇', count: 10, percentage: 28 },
+        { reason: '工作内容', count: 6, percentage: 17 },
+        { reason: '管理问题', count: 3, percentage: 8 },
+        { reason: '其他', count: 2, percentage: 5 }
+      ]
+    }
+  ]);
+
+  ngAfterViewInit() {
+    // 初始化模拟数据
+    this.initializeMockData();
+    
+    // 延迟初始化图表,确保DOM已渲染
+    setTimeout(() => {
+      this.initializeCharts();
+    }, 100);
+  }
+
+  ngOnDestroy() {
+    // 清理图表实例
+    if (this.turnoverChart) {
+      this.turnoverChart.dispose();
+    }
+    if (this.categoryChart) {
+      this.categoryChart.dispose();
+    }
+  }
+
+  private initializeMockData() {
+    // 模拟简历分析数据
+    const mockAnalyses: ResumeAnalysis[] = [
+      {
+        id: '1',
+        fileName: '张三_UI设计师_简历.pdf',
+        uploadTime: new Date('2024-01-15T10:30:00'),
+        status: 'completed',
+        analysisResult: {
+          recommendation: '推荐',
+          reason: '具备丰富的UI设计经验,技能匹配度高,作品质量优秀',
+          coreSkills: [
+            { name: 'Figma', score: 95, matched: true },
+            { name: 'Sketch', score: 88, matched: true },
+            { name: 'Adobe XD', score: 92, matched: true },
+            { name: '用户体验设计', score: 85, matched: true },
+            { name: '原型设计', score: 90, matched: true }
+          ],
+          screeningInfo: {
+            education: '本科',
+            workYears: '3-5年',
+            coreSkills: ['UI设计', '交互设计', '用户体验']
+          }
+        }
+      },
+      {
+        id: '2',
+        fileName: '李四_前端开发_简历.pdf',
+        uploadTime: new Date('2024-01-16T14:20:00'),
+        status: 'completed',
+        analysisResult: {
+          recommendation: '待定',
+          reason: '技术能力符合要求,但项目经验相对较少,建议进一步面试评估',
+          coreSkills: [
+            { name: 'Vue.js', score: 82, matched: true },
+            { name: 'React', score: 75, matched: false },
+            { name: 'TypeScript', score: 78, matched: true },
+            { name: 'Node.js', score: 65, matched: false },
+            { name: '前端工程化', score: 70, matched: true }
+          ],
+          screeningInfo: {
+            education: '本科',
+            workYears: '1-3年',
+            coreSkills: ['Vue.js', 'JavaScript', 'CSS3']
+          }
+        }
+      }
+    ];
+    
+    this.resumeAnalyses.set(mockAnalyses);
+    this.selectedResume.set(mockAnalyses[0]);
+    
+    // 模拟招聘流程数据
+    const mockStages: RecruitmentStage[] = [
+      {
+        stage: '简历初筛',
+        result: '通过',
+        evaluator: '王经理',
+        evaluationTime: new Date('2024-01-15T16:00:00'),
+        comments: '简历质量较高,技能匹配度好'
+      },
+      {
+        stage: '面试评估',
+        result: '通过',
+        evaluator: '李主管',
+        evaluationTime: new Date('2024-01-18T10:00:00'),
+        comments: '面试表现优秀,沟通能力强,技术功底扎实'
+      }
+    ];
+    
+    this.recruitmentStages.set(mockStages);
+  }
+
+  private initializeCharts() {
+    if (this.turnoverPieChart?.nativeElement) {
+      this.initTurnoverChart();
+    }
+    if (this.categoryPieChart?.nativeElement) {
+      this.initCategoryChart();
+    }
+  }
+
+  private initTurnoverChart() {
+    this.turnoverChart = echarts.init(this.turnoverPieChart.nativeElement);
+    
+    const option = {
+      title: {
+        text: '总体离职原因分布',
+        left: 'center',
+        textStyle: {
+          fontSize: 16,
+          fontWeight: 'normal'
+        }
+      },
+      tooltip: {
+        trigger: 'item',
+        formatter: '{a} <br/>{b}: {c} ({d}%)'
+      },
+      legend: {
+        orient: 'vertical',
+        left: 'left',
+        data: ['工作压力大', '薪资不满', '发展空间有限', '职业发展', '团队氛围']
+      },
+      series: [
+        {
+          name: '离职原因',
+          type: 'pie',
+          radius: '50%',
+          data: [
+            { value: 27, name: '工作压力大' },
+            { value: 18, name: '薪资不满' },
+            { value: 13, name: '发展空间有限' },
+            { value: 15, name: '职业发展' },
+            { value: 7, name: '团队氛围' }
+          ],
+          emphasis: {
+            itemStyle: {
+              shadowBlur: 10,
+              shadowOffsetX: 0,
+              shadowColor: 'rgba(0, 0, 0, 0.5)'
+            }
+          }
+        }
+      ]
+    };
+    
+    this.turnoverChart.setOption(option);
+  }
+
+  private initCategoryChart() {
+    this.categoryChart = echarts.init(this.categoryPieChart.nativeElement);
+    
+    const option = {
+      title: {
+        text: '分类离职原因对比',
+        left: 'center',
+        textStyle: {
+          fontSize: 16,
+          fontWeight: 'normal'
+        }
+      },
+      tooltip: {
+        trigger: 'item',
+        formatter: '{a} <br/>{b}: {c} ({d}%)'
+      },
+      legend: {
+        orient: 'vertical',
+        left: 'left',
+        data: ['新人离职', '资深员工离职']
+      },
+      series: [
+        {
+          name: '离职类别',
+          type: 'pie',
+          radius: ['40%', '70%'],
+          avoidLabelOverlap: false,
+          data: [
+            { value: 34, name: '新人离职' },
+            { value: 36, name: '资深员工离职' }
+          ],
+          emphasis: {
+            itemStyle: {
+              shadowBlur: 10,
+              shadowOffsetX: 0,
+              shadowColor: 'rgba(0, 0, 0, 0.5)'
+            }
+          }
+        }
+      ]
+    };
+    
+    this.categoryChart.setOption(option);
+  }
+
+  // 切换标签页
+  switchTab(index: number) {
+    this.activeTab.set(index);
+    
+    // 如果切换到绩效分析页面,重新初始化图表
+    if (index === 1) {
+      setTimeout(() => {
+        this.initializeCharts();
+      }, 100);
+    }
+  }
+
+
+
+  // 简历上传处理
+  onResumeUpload(event: any) {
+    const file = event.target.files[0];
+    if (file) {
+      const newAnalysis: ResumeAnalysis = {
+        id: Date.now().toString(),
+        fileName: file.name,
+        uploadTime: new Date(),
+        status: 'processing'
+      };
+      
+      this.resumeAnalyses.update(analyses => [...analyses, newAnalysis]);
+      
+      // 模拟AI分析过程
+      setTimeout(() => {
+        this.simulateAIAnalysis(newAnalysis.id);
+      }, 3000);
+    }
+  }
+
+  private simulateAIAnalysis(analysisId: string) {
+    this.resumeAnalyses.update(analyses => 
+      analyses.map(analysis => 
+        analysis.id === analysisId 
+          ? {
+              ...analysis,
+              status: 'completed' as const,
+              analysisResult: {
+                recommendation: '推荐' as const,
+                reason: '候选人技能匹配度较高,具备相关工作经验',
+                coreSkills: [
+                  { name: '专业技能', score: 85, matched: true },
+                  { name: '工作经验', score: 78, matched: true },
+                  { name: '学历背景', score: 90, matched: true }
+                ],
+                screeningInfo: {
+                  education: '本科',
+                  workYears: '2-3年',
+                  coreSkills: ['专业技能', '沟通能力']
+                }
+              }
+            }
+          : analysis
+      )
+    );
+  }
+
+  // 添加招聘阶段
+  addRecruitmentStage() {
+    if (this.newStage.evaluator.trim()) {
+      const newStageRecord: RecruitmentStage = {
+        ...this.newStage,
+        evaluationTime: new Date()
+      };
+      
+      this.recruitmentStages.update(stages => [...stages, newStageRecord]);
+      
+      // 重置表单
+      this.newStage = {
+        stage: '简历初筛',
+        result: '通过',
+        evaluator: '',
+        comments: ''
+      };
+    }
+  }
+
+  // 获取当前阶段状态
+  getCurrentStageStatus(): string {
+    const stages = this.recruitmentStages();
+    if (stages.length === 0) return '未开始';
+    
+    const lastStage = stages[stages.length - 1];
+    return `${lastStage.stage} - ${lastStage.result}`;
+  }
+
+  // 获取阶段进度
+  getStageProgress(): number {
+    const stages = this.recruitmentStages();
+    const totalStages = 4; // 简历初筛、面试评估、入职评定、试用期跟踪
+    return Math.round((stages.length / totalStages) * 100);
+  }
+
+  // 计算各阶段通过率
+  getPhasePassRate(phaseName: string): number {
+    const stats = this.recruitmentStats();
+    switch (phaseName) {
+      case '简历初筛':
+        return Math.round((stats.resumeScreened / stats.totalCandidates) * 100);
+      case '面试评估':
+        return Math.round((stats.interviewed / stats.resumeScreened) * 100);
+      case '入职评定':
+        return Math.round((stats.hired / stats.interviewed) * 100);
+      case '试用期跟踪':
+        return Math.round((stats.onProbation / stats.hired) * 100);
+      default:
+        return 0;
+    }
+  }
+
+  // 获取阶段候选人数量
+  getPhaseCount(phaseName: string): number {
+    const stats = this.recruitmentStats();
+    switch (phaseName) {
+      case '简历初筛':
+        return stats.resumeScreened;
+      case '面试评估':
+        return stats.interviewed;
+      case '入职评定':
+        return stats.hired;
+      case '试用期跟踪':
+        return stats.onProbation;
+      default:
+        return 0;
+    }
+  }
+
+  // 获取阶段状态
+  getPhaseStatus(phaseName: string): 'completed' | 'in-progress' | 'pending' {
+    const stages = this.recruitmentStages();
+    const hasStage = stages.some(stage => stage.stage === phaseName);
+    
+    if (hasStage) {
+      const stageIndex = this.recruitmentPhases.findIndex(phase => phase.name === phaseName);
+      const currentStageIndex = this.recruitmentPhases.findIndex(phase => 
+        phase.name === stages[stages.length - 1]?.stage
+      );
+      
+      if (stageIndex < currentStageIndex) return 'completed';
+      if (stageIndex === currentStageIndex) return 'in-progress';
+    }
+    
+    return 'pending';
+  }
+
+  // 计算平均分数
+  calculateAverageScore(skills: Array<{score: number}>): number {
+    if (!skills || skills.length === 0) return 0;
+    const total = skills.reduce((sum, skill) => sum + skill.score, 0);
+    return Math.round(total / skills.length);
+  }
+
+  // 获取匹配技能数量
+  getMatchedSkillsCount(analysis: ResumeAnalysis): number {
+    if (!analysis.analysisResult?.coreSkills) return 0;
+    return analysis.analysisResult.coreSkills.filter(skill => skill.matched).length;
+  }
+
+  // 获取部门列表
+  getDepartments(): string[] {
+    const departments = this.performanceMetrics().map(metric => metric.department);
+    return [...new Set(departments)];
+  }
+
+  // 计算部门平均值
+  calculateDepartmentAverage(department: string) {
+    const deptMetrics = this.performanceMetrics().filter(metric => metric.department === department);
+    
+    if (deptMetrics.length === 0) {
+      return {
+        projectCompletionRate: 0,
+        excellentWorkRate: 0,
+        customerSatisfaction: 0,
+        overdueRate: 0,
+        trainingCompletionRate: 0
+      };
+    }
+    
+    const totals = deptMetrics.reduce((acc, metric) => ({
+      projectCompletionRate: acc.projectCompletionRate + metric.projectCompletionRate,
+      excellentWorkRate: acc.excellentWorkRate + metric.excellentWorkRate,
+      customerSatisfaction: acc.customerSatisfaction + metric.customerSatisfaction,
+      overdueRate: acc.overdueRate + metric.overdueRate,
+      trainingCompletionRate: acc.trainingCompletionRate + metric.trainingCompletionRate
+    }), {
+      projectCompletionRate: 0,
+      excellentWorkRate: 0,
+      customerSatisfaction: 0,
+      overdueRate: 0,
+      trainingCompletionRate: 0
+    });
+    
+    const count = deptMetrics.length;
+    return {
+      projectCompletionRate: Math.round(totals.projectCompletionRate / count),
+      excellentWorkRate: Math.round(totals.excellentWorkRate / count),
+      customerSatisfaction: Math.round(totals.customerSatisfaction / count),
+      overdueRate: Math.round(totals.overdueRate / count),
+      trainingCompletionRate: Math.round(totals.trainingCompletionRate / count)
+    };
+  }
+
+  // 获取离职统计数据
+  getTurnoverStats() {
+    const allReasons = this.turnoverAnalyses().flatMap(analysis => analysis.reasons);
+    const reasonMap = new Map<string, { totalCount: number; totalPercentage: number }>();
+    
+    allReasons.forEach(reason => {
+      if (reasonMap.has(reason.reason)) {
+        const existing = reasonMap.get(reason.reason)!;
+        reasonMap.set(reason.reason, {
+          totalCount: existing.totalCount + reason.count,
+          totalPercentage: existing.totalPercentage + reason.percentage
+        });
+      } else {
+        reasonMap.set(reason.reason, {
+          totalCount: reason.count,
+          totalPercentage: reason.percentage
+        });
+      }
+    });
+    
+    return Array.from(reasonMap.entries()).map(([reason, data]) => ({
+      reason,
+      totalCount: data.totalCount,
+      totalPercentage: Math.round(data.totalPercentage / 2) // 平均值
+    }));
+  }
+
+  // 获取离职原因颜色
+  public getReasonColor(reason: string): string {
+    const colorMap: { [key: string]: string } = {
+      '工作压力大': '#ff6b6b',
+      '薪资不满': '#ffa726',
+      '发展空间有限': '#42a5f5',
+      '职业发展': '#66bb6a',
+      '团队氛围': '#ab47bc',
+      '工作内容': '#26c6da',
+      '管理问题': '#ef5350',
+      '其他': '#bdbdbd'
+    };
+    return colorMap[reason] || '#bdbdbd';
+  }
+
+  // 应用离职筛选
+  applyTurnoverFilters() {
+    // 根据筛选条件重新加载数据
+    const filteredData = this.getFilteredTurnoverData();
+    this.updateTurnoverCharts(filteredData);
+    
+    console.log('应用筛选:', {
+      department: this.filterTurnoverDepartment,
+      dateRange: this.filterTurnoverDateRange
+    });
+  }
+
+  // 重置离职筛选
+  resetTurnoverFilters() {
+    this.filterTurnoverDepartment = '';
+    this.filterTurnoverDateRange = '';
+    
+    // 重置图表数据
+    this.updateTurnoverCharts();
+  }
+
+  // 获取筛选后的离职数据
+  private getFilteredTurnoverData() {
+    let filteredAnalyses = [...this.turnoverAnalyses()];
+    
+    // 根据部门筛选
+    if (this.filterTurnoverDepartment) {
+      // 这里可以根据实际需求添加部门筛选逻辑
+      // 目前保持原数据
+    }
+    
+    // 根据时间范围筛选
+    if (this.filterTurnoverDateRange) {
+      // 根据时间范围调整数据
+      const multiplier = this.getTimeRangeMultiplier(this.filterTurnoverDateRange);
+      filteredAnalyses = filteredAnalyses.map(analysis => ({
+        ...analysis,
+        reasons: analysis.reasons.map(reason => ({
+          ...reason,
+          count: Math.round(reason.count * multiplier),
+          percentage: Math.round(reason.percentage * multiplier)
+        }))
+      }));
+    }
+    
+    return filteredAnalyses;
+  }
+
+  // 获取时间范围乘数
+  private getTimeRangeMultiplier(dateRange: string): number {
+    switch (dateRange) {
+      case 'last3months': return 0.25;
+      case 'last6months': return 0.5;
+      case 'lastyear': return 1;
+      default: return 1;
+    }
+  }
+
+  // 更新离职图表
+  private updateTurnoverCharts(filteredData?: TurnoverAnalysis[]) {
+    const data = filteredData || this.turnoverAnalyses();
+    
+    if (this.turnoverChart) {
+      this.updateTurnoverPieChart(data);
+    }
+    
+    if (this.categoryChart) {
+      this.updateCategoryPieChart(data);
+    }
+  }
+
+  // 更新总体离职原因饼图
+  private updateTurnoverPieChart(data: TurnoverAnalysis[]) {
+    const allReasons = data.flatMap(analysis => analysis.reasons);
+    const reasonMap = new Map<string, number>();
+    
+    allReasons.forEach(reason => {
+      const current = reasonMap.get(reason.reason) || 0;
+      reasonMap.set(reason.reason, current + reason.count);
+    });
+    
+    const chartData = Array.from(reasonMap.entries()).map(([name, value]) => ({
+      name,
+      value,
+      itemStyle: {
+        color: this.getReasonColor(name)
+      }
+    }));
+    
+    const option = {
+      series: [{
+        data: chartData
+      }]
+    };
+    
+    this.turnoverChart?.setOption(option);
+  }
+
+  // 更新分类离职饼图
+  private updateCategoryPieChart(data: TurnoverAnalysis[]) {
+    const chartData = data.map(analysis => {
+      const totalCount = analysis.reasons.reduce((sum, reason) => sum + reason.count, 0);
+      return {
+        name: analysis.category,
+        value: totalCount
+      };
+    });
+    
+    const option = {
+      series: [{
+        data: chartData
+      }]
+    };
+    
+    this.categoryChart?.setOption(option);
+  }
+
+  // 生成离职分析报告
+  generateTurnoverReport() {
+    const stats = this.getTurnoverStats();
+    const totalTurnover = stats.reduce((sum, stat) => sum + stat.totalCount, 0);
+    
+    const reportData = {
+      title: '离职分析报告',
+      generateTime: new Date().toLocaleString(),
+      summary: {
+        totalTurnover,
+        mainReasons: stats.slice(0, 3).map(stat => ({
+          reason: stat.reason,
+          count: stat.totalCount,
+          percentage: stat.totalPercentage
+        }))
+      },
+      details: this.turnoverAnalyses(),
+      filters: {
+        department: this.filterTurnoverDepartment || '全部',
+        dateRange: this.filterTurnoverDateRange || '全部时间'
+      }
+    };
+    
+    console.log('生成离职分析报告:', reportData);
+    // 这里可以实现实际的报告导出功能
+  }
+
+  // 生成绩效报告
+  generatePerformanceReport() {
+    const overallStats = this.calculateOverallAverage();
+    const departmentStats = this.getDepartments().map(dept => ({
+      department: dept,
+      stats: this.calculateDepartmentAverage(dept)
+    }));
+    
+    const reportData = {
+      title: '绩效分析报告',
+      generateTime: new Date().toLocaleString(),
+      overall: overallStats,
+      departments: departmentStats,
+      filters: this.filterForm
+    };
+    
+    console.log('生成绩效报告:', reportData);
+    // 这里可以实现实际的报告导出功能
+  }
+
+  // 筛选绩效数据
+  getFilteredPerformanceMetrics() {
+    let filtered = this.performanceMetrics();
+    
+    if (this.filterForm.department) {
+      filtered = filtered.filter(metric => metric.department === this.filterForm.department);
+    }
+    
+    if (this.filterForm.position) {
+      filtered = filtered.filter(metric => metric.positionLevel === this.filterForm.position);
+    }
+    
+    if (this.filterForm.performanceLevel) {
+      filtered = filtered.filter(metric => {
+        const overall = this.calculateEmployeeOverall(metric);
+        switch (this.filterForm.performanceLevel) {
+          case '优秀': return overall >= 90;
+          case '良好': return overall >= 80 && overall < 90;
+          case '一般': return overall >= 70 && overall < 80;
+          case '待改进': return overall < 70;
+          default: return true;
+        }
+      });
+    }
+    
+    return filtered;
+  }
+
+  // 计算员工综合评分
+  calculateEmployeeOverall(metric: PerformanceMetric) {
+    return Math.round((
+      metric.projectCompletionRate + 
+      metric.excellentWorkRate + 
+      metric.customerSatisfaction + 
+      (100 - metric.overdueRate) + 
+      metric.trainingCompletionRate
+    ) / 5);
+  }
+
+  // 应用筛选
+  applyFilters() {
+    // 重新计算筛选后的数据
+    const filteredMetrics = this.getFilteredPerformanceMetrics();
+    
+    // 更新图表数据
+    this.updateChartsWithFilteredData(filteredMetrics);
+  }
+
+  // 重置筛选
+  resetFilters() {
+    this.filterForm = {
+      department: '',
+      dateRange: '',
+      position: '',
+      performanceLevel: ''
+    };
+    this.applyFilters();
+  }
+
+  // 更新图表数据
+  updateChartsWithFilteredData(filteredMetrics: PerformanceMetric[]) {
+    // 这里可以根据筛选后的数据更新图表
+    // 暂时保持原有逻辑
+  }
+
+  // 计算整体平均绩效
+  calculateOverallAverage() {
+    const metrics = this.getFilteredPerformanceMetrics();
+    if (metrics.length === 0) {
+      return {
+        overall: 0,
+        projectCompletionRate: 0,
+        excellentWorkRate: 0,
+        customerSatisfaction: 0,
+        overdueRate: 0,
+        trainingCompletionRate: 0
+      };
+    }
+    
+    const totals = metrics.reduce((acc, metric) => ({
+      projectCompletionRate: acc.projectCompletionRate + metric.projectCompletionRate,
+      excellentWorkRate: acc.excellentWorkRate + metric.excellentWorkRate,
+      customerSatisfaction: acc.customerSatisfaction + metric.customerSatisfaction,
+      overdueRate: acc.overdueRate + metric.overdueRate,
+      trainingCompletionRate: acc.trainingCompletionRate + metric.trainingCompletionRate
+    }), {
+      projectCompletionRate: 0,
+      excellentWorkRate: 0,
+      customerSatisfaction: 0,
+      overdueRate: 0,
+      trainingCompletionRate: 0
+    });
+    
+    const count = metrics.length;
+    const overall = Math.round((
+      totals.projectCompletionRate + 
+      totals.excellentWorkRate + 
+      totals.customerSatisfaction + 
+      (100 - totals.overdueRate) + 
+      totals.trainingCompletionRate
+    ) / (count * 5));
+    
+    return {
+      overall,
+      projectCompletionRate: Math.round(totals.projectCompletionRate / count),
+      excellentWorkRate: Math.round(totals.excellentWorkRate / count),
+      customerSatisfaction: Math.round(totals.customerSatisfaction / count),
+      overdueRate: Math.round(totals.overdueRate / count),
+      trainingCompletionRate: Math.round(totals.trainingCompletionRate / count)
+    };
+  }
+
+  // 计算离职率
+  calculateTurnoverRate(): number {
+    const totalEmployees = this.performanceMetrics().length;
+    const totalTurnover = this.getTurnoverStats().reduce((sum, stat) => sum + stat.totalCount, 0);
+    
+    if (totalEmployees === 0) return 0;
+    return (totalTurnover / (totalEmployees + totalTurnover)) * 100;
+  }
+
+  // 导出报表
+  exportReport(templateId: string) {
+    // 模拟导出报表
+    console.log('导出报表:', templateId);
+    // 这里可以调用后端API导出对应的报表
+  }
+}

部分文件因文件數量過多而無法顯示