Quellcode durchsuchen

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

0235711 vor 1 Tag
Ursprung
Commit
b7ee6a4e92

+ 1 - 7
src/app/app.routes.ts

@@ -39,9 +39,6 @@ import { HrLayout } from './pages/hr/hr-layout/hr-layout';
 import { Dashboard as HrDashboard } from './pages/hr/dashboard/dashboard';
 import { EmployeeRecords } from './pages/hr/employee-records/employee-records';
 import { Attendance } from './pages/hr/attendance/attendance';
-import { EmployeeDetailComponent } from './pages/hr/employee-detail/employee-detail';
-
-import { DesignerProfile } from './pages/hr/designer-profile/designer-profile';
 
 // 管理员页面
 import { AdminLayout } from './pages/admin/admin-layout/admin-layout';
@@ -123,10 +120,7 @@ export const routes: Routes = [
       { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
       { path: 'dashboard', component: HrDashboard, title: '人事看板' },
       { path: 'employee-records', component: EmployeeRecords, title: '花名册与档案库' },
-      { path: 'employee-detail/:id', component: EmployeeDetailComponent, title: '员工详情' },
-      { path: 'attendance', component: Attendance, title: '考勤统计' },
-
-      { path: 'designer-profile/:id', component: DesignerProfile, title: '设计师详情' }
+      { path: 'attendance', component: Attendance, title: '考勤统计' }
     ]
   },
 

+ 61 - 63
src/app/pages/customer-service/case-library/case-library.html

@@ -31,95 +31,93 @@
         <!-- 高级筛选面板 -->
         <div class="filter-panel" [class.show]="showFilterPanel()">
           <form [formGroup]="filterForm" class="filter-form">
-            <div class="filter-row">
+            <!-- 第一行:主要筛选项 -->
+            <div class="filter-row primary-filters">
               <div class="filter-group">
-                <label>装修风格</label>
-                <div class="checkbox-group">
-                  <label *ngFor="let style of styleOptions" class="checkbox-item">
-                    <input 
-                      type="checkbox" 
-                      [value]="style"
-                      [checked]="filterForm.get('style')?.value?.includes(style) || false"
-                      (change)="onStyleChange(style, $event.target.checked)"
-                    />
-                    <span>{{ style }}</span>
-                  </label>
-                </div>
+                <label>项目类型</label>
+                <select formControlName="projectType">
+                  <option value="">全部类型</option>
+                  @for (type of projectTypeOptions; track type) {
+                    <option [value]="type">{{ type }}</option>
+                  }
+                </select>
               </div>
               
               <div class="filter-group">
                 <label>户型</label>
                 <select formControlName="houseType">
                   <option value="">全部户型</option>
-                  <option *ngFor="let type of houseTypeOptions" [value]="type">{{ type }}</option>
+                  @for (type of houseTypeOptions; track type) {
+                    <option [value]="type">{{ type }}</option>
+                  }
                 </select>
               </div>
               
               <div class="filter-group">
-                <label>楼盘</label>
-                <select formControlName="property">
-                  <option value="">全部楼盘</option>
-                  <option *ngFor="let property of propertyOptions" [value]="property">{{ property }}</option>
+                <label>价格范围</label>
+                <select formControlName="price">
+                  <option value="">全部价格</option>
+                  @for (price of priceOptions; track price) {
+                    <option [value]="price">{{ price }}</option>
+                  }
                 </select>
               </div>
-            </div>
-            
-            <div class="filter-row">
+              
               <div class="filter-group">
-                <label>项目类型</label>
-                <select formControlName="projectType">
-                  <option value="">全部类型</option>
-                  <option *ngFor="let pt of projectTypeOptions" [value]="pt">{{ pt }}</option>
+                <label>排序方式</label>
+                <select formControlName="sortBy">
+                  @for (option of sortOptions; track option.value) {
+                    <option [value]="option.value">{{ option.label }}</option>
+                  }
                 </select>
               </div>
+            </div>
+            
+            <!-- 第二行:风格选择 -->
+            <div class="filter-row style-filters">
+              <div class="filter-group style-group">
+                <label>设计风格</label>
+                <div class="style-checkboxes">
+                  @for (style of styleOptions; track style) {
+                    <label class="style-checkbox">
+                      <input 
+                        type="checkbox" 
+                        [value]="style"
+                        (change)="onStyleChange(style, $event.target.checked)"
+                      />
+                      <span class="style-tag">{{ style }}</span>
+                    </label>
+                  }
+                </div>
+              </div>
+            </div>
+            
+            <!-- 第三行:高级筛选 -->
+            <div class="filter-row advanced-filters">
               <div class="filter-group">
-                <label>细分类型</label>
+                <label>类型</label>
                 <select formControlName="subType">
-                  <option value="">全部细分</option>
-                  <option *ngFor="let st of subTypeOptions" [value]="st">{{ st }}</option>
+                  <option value="">全部子类型</option>
+                  @for (subType of subTypeOptions; track subType) {
+                    <option [value]="subType">{{ subType }}</option>
+                  }
                 </select>
               </div>
+              
               <div class="filter-group">
-                <label>渲染水平</label>
+                <label>渲染级别</label>
                 <select formControlName="renderingLevel">
-                  <option value="">全部水平</option>
-                  <option *ngFor="let rl of renderingLevelOptions" [value]="rl">{{ rl }}</option>
-                </select>
-              </div>
-              <div class="filter-group">
-                <label>排序</label>
-                <select formControlName="sortBy">
-                  <option *ngFor="let opt of sortOptions" [value]="opt.value">{{ opt.label }}</option>
+                  <option value="">全部级别</option>
+                  @for (level of renderingLevelOptions; track level) {
+                    <option [value]="level">{{ level }}</option>
+                  }
                 </select>
               </div>
-            </div>
-            
-            <div class="filter-row">
-              <div class="filter-group">
-                <label>房屋面积</label>
-                <div class="range-inputs">
-                  <input 
-                    type="number" 
-                    formControlName="minArea"
-                    placeholder="最小面积"
-                    min="0"
-                  />
-                  <span>-</span>
-                  <input 
-                    type="number" 
-                    formControlName="maxArea"
-                    placeholder="最大面积"
-                    min="0"
-                  />
-                  <span>㎡</span>
-                </div>
-              </div>
               
-              <div class="filter-group">
-                <label>收藏案例</label>
-                <label class="checkbox-item full-width">
+              <div class="filter-group checkbox-group">
+                <label class="favorite-checkbox">
                   <input type="checkbox" formControlName="favorite" />
-                  <span>仅显示我收藏的案例</span>
+                  <span class="checkbox-text">只看收藏</span>
                 </label>
               </div>
             </div>

+ 832 - 88
src/app/pages/customer-service/case-library/case-library.scss

@@ -281,11 +281,18 @@ $transition: all 0.3s ease;
   padding: 16px 20px;
   box-shadow: $shadow-sm;
   margin-bottom: 24px;
+  position: sticky;
+  top: 0;
+  z-index: 100; // 降低z-index,避免覆盖模态框
+  backdrop-filter: blur(8px);
+  background-color: rgba(255, 255, 255, 0.95);
+  border-bottom: 1px solid $border-color;
 }
 
 .filter-header {
   display: flex;
   gap: 12px;
+  align-items: center;
 }
 
 .filter-toggle-btn,
@@ -310,142 +317,299 @@ $transition: all 0.3s ease;
 }
 
 .filter-panel {
-  margin-top: 16px;
-  padding-top: 16px;
-  border-top: 1px solid $border-color;
-  display: none;
-  animation: slideDown 0.3s ease;
-}
-
-.filter-panel.show {
-  display: block;
-}
-
-@keyframes slideDown {
-  from {
-    opacity: 0;
-    transform: translateY(-10px);
-  }
-  to {
+  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+  border: 1px solid #e2e8f0;
+  border-radius: 16px;
+  padding: 24px;
+  margin-bottom: 24px;
+  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+  transition: all 0.3s ease;
+  
+  &.show {
     opacity: 1;
     transform: translateY(0);
   }
+  
+  &:not(.show) {
+    opacity: 0;
+    transform: translateY(-10px);
+    pointer-events: none;
+  }
 }
 
 .filter-form {
   .filter-row {
     display: flex;
-    gap: 24px;
-    margin-bottom: 16px;
-    flex-wrap: wrap;
+    gap: 20px;
+    margin-bottom: 20px;
+    align-items: flex-end;
+    
+    &:last-child {
+      margin-bottom: 0;
+    }
+    
+    // 主要筛选项样式
+    &.primary-filters {
+      .filter-group {
+        flex: 1;
+        min-width: 180px;
+      }
+    }
+    
+    // 风格筛选样式
+    &.style-filters {
+      .style-group {
+        width: 100%;
+      }
+    }
+    
+    // 高级筛选样式
+    &.advanced-filters {
+      .filter-group {
+        flex: 1;
+        
+        &.checkbox-group {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+        }
+      }
+    }
   }
   
   .filter-group {
-    flex: 1;
-    min-width: 200px;
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+    
     label {
-      display: block;
       font-size: 14px;
-      font-weight: 500;
-      color: $text-primary;
-      margin-bottom: 8px;
+      font-weight: 600;
+      color: #374151;
+      margin-bottom: 4px;
     }
-    select,
-    input[type="number"] {
-      width: 100%;
-      padding: 8px 12px;
-      border: 1px solid $border-color;
-      border-radius: $border-radius;
+    
+    select {
+      padding: 10px 12px;
+      border: 2px solid #e5e7eb;
+      border-radius: 8px;
       font-size: 14px;
-      transition: $transition;
+      background: white;
+      color: #374151;
+      transition: all 0.2s ease;
+      position: relative;
+      z-index: 10;
+      
       &:focus {
         outline: none;
-        border-color: $primary-color;
-        box-shadow: 0 0 0 3px color-mix(in srgb, $primary-color 10%, transparent);
+        border-color: #3b82f6;
+        box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
+      }
+      
+      &:hover {
+        border-color: #d1d5db;
       }
     }
   }
   
-  .checkbox-group {
+  // 风格选择器样式
+  .style-checkboxes {
     display: flex;
     flex-wrap: wrap;
     gap: 12px;
+    margin-top: 8px;
   }
   
-  .checkbox-item {
+  .style-checkbox {
     display: flex;
     align-items: center;
-    gap: 6px;
-    font-size: 14px;
-    color: $text-secondary;
     cursor: pointer;
+    
     input[type="checkbox"] {
-      width: auto;
+      display: none;
     }
-    &.full-width {
-      width: 100%;
-      justify-content: flex-start;
+    
+    .style-tag {
+      padding: 8px 16px;
+      background: white;
+      border: 2px solid #e5e7eb;
+      border-radius: 20px;
+      font-size: 13px;
+      font-weight: 500;
+      color: #6b7280;
+      transition: all 0.2s ease;
+      white-space: nowrap;
+      
+      &:hover {
+        border-color: #3b82f6;
+        color: #3b82f6;
+        transform: translateY(-1px);
+      }
+    }
+    
+    input[type="checkbox"]:checked + .style-tag {
+      background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
+      border-color: #3b82f6;
+      color: white;
+      box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
     }
   }
   
-  .range-inputs {
+  // 收藏复选框样式
+  .favorite-checkbox {
     display: flex;
     align-items: center;
     gap: 8px;
-    input {
-      flex: 1;
+    cursor: pointer;
+    padding: 10px 16px;
+    background: white;
+    border: 2px solid #e5e7eb;
+    border-radius: 8px;
+    transition: all 0.2s ease;
+    
+    &:hover {
+      border-color: #f59e0b;
+      background: #fef3c7;
     }
-    span {
+    
+    input[type="checkbox"] {
+      width: 18px;
+      height: 18px;
+      accent-color: #f59e0b;
+    }
+    
+    .checkbox-text {
       font-size: 14px;
-      color: $text-secondary;
+      font-weight: 500;
+      color: #374151;
+    }
+    
+    input[type="checkbox"]:checked ~ .checkbox-text {
+      color: #f59e0b;
+      font-weight: 600;
     }
   }
 }
 
-/* 覆盖与新增:筛选区域固定与过渡 */
-.filter-section {
-  position: sticky;
-  top: 0;
-  z-index: 12;
-  background: #fff;
-  padding-top: 8px;
-  border-bottom: 1px solid rgba(0,0,0,0.06);
-  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
-}
-
-.filter-header {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  gap: 12px;
-}
-
-.filter-toggle-btn, .reset-filter-btn {
-  display: inline-flex;
-  align-items: center;
-  gap: 6px;
-  padding: 6px 12px;
-  color: #1e5eff;
-  background: #f3f7ff;
-  border: 1px solid #dbe6ff;
-  border-radius: 6px;
-  cursor: pointer;
-  transition: all .2s ease;
-}
-.filter-toggle-btn:hover, .reset-filter-btn:hover {
-  background: #e8f0ff;
-  box-shadow: 0 2px 8px rgba(30,94,255,0.12);
+// 案例展示区域优化
+.cases-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+  gap: 24px;
+  margin-top: 24px;
 }
 
-.filter-panel {
+.case-card {
+  background: white;
+  border-radius: 16px;
   overflow: hidden;
-  max-height: 0;
-  transition: max-height .28s ease;
+  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+  transition: all 0.3s ease;
+  position: relative;
+  z-index: 1;
+  
+  &:hover {
+    transform: translateY(-8px);
+    box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
+  }
+  
+  .case-image {
+    width: 100%;
+    height: 200px;
+    overflow: hidden;
+    position: relative;
+    
+    img, svg {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+      transition: transform 0.3s ease;
+    }
+    
+    &:hover img,
+    &:hover svg {
+      transform: scale(1.05);
+    }
+  }
+  
+  .case-info {
+    padding: 20px;
+    
+    .case-title {
+      font-size: 18px;
+      font-weight: 700;
+      color: #1f2937;
+      margin-bottom: 8px;
+      line-height: 1.4;
+    }
+    
+    .case-details {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 12px;
+      margin-bottom: 16px;
+      
+      .detail-item {
+        display: flex;
+        align-items: center;
+        gap: 4px;
+        font-size: 13px;
+        color: #6b7280;
+        
+        .label {
+          font-weight: 500;
+        }
+        
+        .value {
+          color: #374151;
+        }
+      }
+    }
+    
+    .case-tags {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 8px;
+      
+      .tag {
+        padding: 4px 8px;
+        background: #f3f4f6;
+        color: #6b7280;
+        border-radius: 6px;
+        font-size: 12px;
+        font-weight: 500;
+      }
+    }
+  }
 }
-.filter-panel.show {
-  max-height: 560px; // 兼容动画高度
+
+// 响应式设计
+@media (max-width: 768px) {
+  .filter-form {
+    .filter-row {
+      flex-direction: column;
+      gap: 16px;
+      
+      &.primary-filters,
+      &.advanced-filters {
+        .filter-group {
+          width: 100%;
+        }
+      }
+    }
+    
+    .style-checkboxes {
+      justify-content: center;
+    }
+  }
+  
+  .cases-grid {
+    grid-template-columns: 1fr;
+    gap: 16px;
+  }
 }
 
+/* 优化的筛选表单布局 */
 .filter-form {
   padding: 12px 0 8px;
 }
@@ -574,4 +738,584 @@ $transition: all 0.3s ease;
 @media (max-width: 720px) {
   .share-body { flex-direction: column; }
   .qr-box { width: 100%; height: 140px; }
-}
+}
+
+// 页面整体容器优化
+.case-library-container {
+  background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 50%, #e2e8f0 100%);
+  min-height: 100vh;
+  padding: 20px;
+}
+
+// 页面标题区域
+.page-header {
+  text-align: center;
+  margin-bottom: 32px;
+  
+  h1 {
+    font-size: 32px;
+    font-weight: 800;
+    background: linear-gradient(135deg, #1f2937 0%, #374151 100%);
+    -webkit-background-clip: text;
+    -webkit-text-fill-color: transparent;
+    background-clip: text;
+    margin-bottom: 8px;
+  }
+  
+  .subtitle {
+    font-size: 16px;
+    color: #6b7280;
+    font-weight: 500;
+  }
+}
+
+// 筛选切换按钮优化
+.filter-toggle {
+  background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
+  color: white;
+  border: none;
+  padding: 12px 24px;
+  border-radius: 12px;
+  font-size: 14px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
+  position: relative;
+  overflow: hidden;
+  
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: -100%;
+    width: 100%;
+    height: 100%;
+    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
+    transition: left 0.5s ease;
+  }
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4);
+    
+    &::before {
+      left: 100%;
+    }
+  }
+  
+  &:active {
+    transform: translateY(0);
+  }
+}
+
+.filter-panel {
+  background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
+  border: 1px solid #e2e8f0;
+  border-radius: 20px;
+  padding: 32px;
+  margin-bottom: 32px;
+  box-shadow: 
+    0 10px 15px -3px rgba(0, 0, 0, 0.1), 
+    0 4px 6px -2px rgba(0, 0, 0, 0.05),
+    inset 0 1px 0 rgba(255, 255, 255, 0.1);
+  transition: all 0.4s 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, #3b82f6, #8b5cf6, #06b6d4, #10b981);
+    background-size: 300% 100%;
+    animation: gradientShift 6s ease infinite;
+  }
+  
+  &.show {
+    opacity: 1;
+    transform: translateY(0) scale(1);
+  }
+  
+  &:not(.show) {
+    opacity: 0;
+    transform: translateY(-20px) scale(0.95);
+    pointer-events: none;
+  }
+}
+
+@keyframes gradientShift {
+  0%, 100% { background-position: 0% 50%; }
+  50% { background-position: 100% 50%; }
+}
+
+.filter-form {
+  .filter-row {
+    display: flex;
+    gap: 24px;
+    margin-bottom: 24px;
+    align-items: flex-end;
+    
+    &:last-child {
+      margin-bottom: 0;
+    }
+    
+    // 主要筛选项样式
+    &.primary-filters {
+      .filter-group {
+        flex: 1;
+        min-width: 200px;
+      }
+    }
+    
+    // 风格筛选样式
+    &.style-filters {
+      .style-group {
+        width: 100%;
+      }
+      
+      padding: 20px;
+      background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+      border-radius: 16px;
+      border: 1px solid #e2e8f0;
+    }
+    
+    // 高级筛选样式
+    &.advanced-filters {
+      .filter-group {
+        flex: 1;
+        
+        &.checkbox-group {
+          display: flex;
+          align-items: center;
+          justify-content: center;
+        }
+      }
+    }
+  }
+  
+  .filter-group {
+    display: flex;
+    flex-direction: column;
+    gap: 10px;
+    
+    label {
+      font-size: 15px;
+      font-weight: 700;
+      color: #374151;
+      margin-bottom: 6px;
+      position: relative;
+      
+      &::after {
+        content: '';
+        position: absolute;
+        bottom: -2px;
+        left: 0;
+        width: 20px;
+        height: 2px;
+        background: linear-gradient(90deg, #3b82f6, #8b5cf6);
+        border-radius: 1px;
+      }
+    }
+    
+    select {
+      padding: 12px 16px;
+      border: 2px solid #e5e7eb;
+      border-radius: 12px;
+      font-size: 14px;
+      background: white;
+      color: #374151;
+      transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+      position: relative;
+      z-index: 10;
+      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+      
+      &:focus {
+        outline: none;
+        border-color: #3b82f6;
+        box-shadow: 
+          0 0 0 4px rgba(59, 130, 246, 0.1),
+          0 4px 12px rgba(59, 130, 246, 0.15);
+        transform: translateY(-1px);
+      }
+      
+      &:hover {
+        border-color: #d1d5db;
+        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
+      }
+    }
+  }
+  
+  // 风格选择器样式
+  .style-checkboxes {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 16px;
+    margin-top: 12px;
+    justify-content: center;
+  }
+  
+  .style-checkbox {
+    display: flex;
+    align-items: center;
+    cursor: pointer;
+    
+    input[type="checkbox"] {
+      display: none;
+    }
+    
+    .style-tag {
+      padding: 10px 20px;
+      background: white;
+      border: 2px solid #e5e7eb;
+      border-radius: 25px;
+      font-size: 14px;
+      font-weight: 600;
+      color: #6b7280;
+      transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+      white-space: nowrap;
+      position: relative;
+      overflow: hidden;
+      
+      &::before {
+        content: '';
+        position: absolute;
+        top: 0;
+        left: -100%;
+        width: 100%;
+        height: 100%;
+        background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
+        transition: left 0.5s ease;
+      }
+      
+      &:hover {
+        border-color: #3b82f6;
+        color: #3b82f6;
+        transform: translateY(-2px);
+        box-shadow: 0 8px 16px rgba(59, 130, 246, 0.2);
+        
+        &::before {
+          left: 100%;
+        }
+      }
+    }
+    
+    input[type="checkbox"]:checked + .style-tag {
+      background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
+      border-color: #3b82f6;
+      color: white;
+      box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4);
+      transform: translateY(-2px);
+    }
+  }
+  
+  // 收藏复选框样式
+  .favorite-checkbox {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    cursor: pointer;
+    padding: 12px 20px;
+    background: white;
+    border: 2px solid #e5e7eb;
+    border-radius: 12px;
+    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+    
+    &:hover {
+      border-color: #f59e0b;
+      background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
+      transform: translateY(-1px);
+      box-shadow: 0 4px 12px rgba(245, 158, 11, 0.2);
+    }
+    
+    input[type="checkbox"] {
+      width: 20px;
+      height: 20px;
+      accent-color: #f59e0b;
+    }
+    
+    .checkbox-text {
+      font-size: 14px;
+      font-weight: 600;
+      color: #374151;
+    }
+    
+    input[type="checkbox"]:checked ~ .checkbox-text {
+      color: #f59e0b;
+      font-weight: 700;
+    }
+  }
+}
+
+// 案例展示区域优化
+.cases-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
+  gap: 28px;
+  margin-top: 32px;
+  padding: 0 4px; // 为阴影留出空间
+}
+
+.case-card {
+  background: white;
+  border-radius: 20px;
+  overflow: hidden;
+  box-shadow: 
+    0 4px 6px -1px rgba(0, 0, 0, 0.1), 
+    0 2px 4px -1px rgba(0, 0, 0, 0.06);
+  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+  position: relative;
+  z-index: 1;
+  border: 1px solid #f3f4f6;
+  
+  &::before {
+    content: '';
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: linear-gradient(135deg, rgba(59, 130, 246, 0.05) 0%, rgba(139, 92, 246, 0.05) 100%);
+    opacity: 0;
+    transition: opacity 0.3s ease;
+    z-index: -1;
+  }
+  
+  &:hover {
+    transform: translateY(-12px) scale(1.02);
+    box-shadow: 
+      0 25px 50px -12px rgba(0, 0, 0, 0.15),
+      0 0 0 1px rgba(59, 130, 246, 0.1);
+    
+    &::before {
+      opacity: 1;
+    }
+  }
+  
+  .case-image {
+    width: 100%;
+    height: 220px;
+    overflow: hidden;
+    position: relative;
+    
+    img, svg {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+      transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+    }
+    
+    &:hover img,
+    &:hover svg {
+      transform: scale(1.08);
+    }
+    
+    // 添加渐变遮罩
+    &::after {
+      content: '';
+      position: absolute;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      height: 60px;
+      background: linear-gradient(to top, rgba(0,0,0,0.3) 0%, transparent 100%);
+      opacity: 0;
+      transition: opacity 0.3s ease;
+    }
+    
+    &:hover::after {
+      opacity: 1;
+    }
+  }
+  
+  .case-info {
+    padding: 24px;
+    
+    .case-title {
+      font-size: 20px;
+      font-weight: 800;
+      color: #1f2937;
+      margin-bottom: 12px;
+      line-height: 1.3;
+      background: linear-gradient(135deg, #1f2937 0%, #374151 100%);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+      background-clip: text;
+    }
+    
+    .case-details {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 16px;
+      margin-bottom: 20px;
+      
+      .detail-item {
+        display: flex;
+        align-items: center;
+        gap: 6px;
+        font-size: 13px;
+        color: #6b7280;
+        background: #f8fafc;
+        padding: 6px 12px;
+        border-radius: 8px;
+        
+        .label {
+          font-weight: 600;
+        }
+        
+        .value {
+          color: #374151;
+          font-weight: 500;
+        }
+      }
+    }
+    
+    .case-tags {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 10px;
+      
+      .tag {
+        padding: 6px 12px;
+        background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
+        color: #6b7280;
+        border-radius: 8px;
+        font-size: 12px;
+        font-weight: 600;
+        border: 1px solid #e5e7eb;
+        transition: all 0.2s ease;
+        
+        &:hover {
+          background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
+          color: white;
+          transform: translateY(-1px);
+        }
+      }
+    }
+  }
+}
+
+// 加载状态
+.loading-state {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 200px;
+  
+  .spinner {
+    width: 40px;
+    height: 40px;
+    border: 4px solid #e5e7eb;
+    border-top: 4px solid #3b82f6;
+    border-radius: 50%;
+    animation: spin 1s linear infinite;
+  }
+}
+
+@keyframes spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+
+// 空状态
+.empty-state {
+  text-align: center;
+  padding: 60px 20px;
+  
+  .empty-icon {
+    font-size: 64px;
+    color: #d1d5db;
+    margin-bottom: 16px;
+  }
+  
+  .empty-title {
+    font-size: 20px;
+    font-weight: 600;
+    color: #6b7280;
+    margin-bottom: 8px;
+  }
+  
+  .empty-description {
+    font-size: 14px;
+    color: #9ca3af;
+  }
+}
+
+// 响应式设计
+@media (max-width: 1024px) {
+  .cases-grid {
+    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+    gap: 20px;
+  }
+}
+
+@media (max-width: 768px) {
+  .case-library-container {
+    padding: 16px;
+  }
+  
+  .filter-panel {
+    padding: 20px;
+    border-radius: 16px;
+  }
+  
+  .filter-form {
+    .filter-row {
+      flex-direction: column;
+      gap: 16px;
+      
+      &.primary-filters,
+      &.advanced-filters {
+        .filter-group {
+          width: 100%;
+        }
+      }
+      
+      &.style-filters {
+        padding: 16px;
+      }
+    }
+    
+    .style-checkboxes {
+      justify-content: center;
+      gap: 12px;
+    }
+  }
+  
+  .cases-grid {
+    grid-template-columns: 1fr;
+    gap: 16px;
+  }
+  
+  .case-card {
+    .case-info {
+      padding: 20px;
+    }
+  }
+}
+
+@media (max-width: 480px) {
+  .page-header {
+    h1 {
+      font-size: 24px;
+    }
+  }
+  
+  .filter-toggle {
+    width: 100%;
+    margin-bottom: 16px;
+  }
+  
+  .style-checkboxes {
+    .style-tag {
+      padding: 8px 16px;
+      font-size: 13px;
+    }
+  }
+}
+
+// ... existing code ...

+ 10 - 18
src/app/pages/customer-service/case-library/case-library.ts

@@ -85,9 +85,7 @@ export class CaseLibrary implements OnInit {
       result = result.filter(caseItem => caseItem.houseType === filters.houseType);
     }
     
-    if (filters.property) {
-      result = result.filter(caseItem => caseItem.property === filters.property);
-    }
+
 
     if (filters.projectType) {
       result = result.filter(caseItem => caseItem.projectType === filters.projectType);
@@ -100,13 +98,11 @@ export class CaseLibrary implements OnInit {
     if (filters.renderingLevel) {
       result = result.filter(caseItem => caseItem.renderingLevel === filters.renderingLevel);
     }
-    
-    if (filters.minArea) {
-      result = result.filter(caseItem => caseItem.area >= Number(filters.minArea));
-    }
-    
-    if (filters.maxArea) {
-      result = result.filter(caseItem => caseItem.area <= Number(filters.maxArea));
+
+    // 价格筛选(基于案例的预估价格范围)
+    if (filters.price) {
+      // 这里可以根据实际业务逻辑来筛选价格
+      // 暂时保留所有案例,实际项目中需要根据案例的价格字段进行筛选
     }
     
     if (filters.favorite) {
@@ -161,10 +157,10 @@ export class CaseLibrary implements OnInit {
   // 筛选选项
   styleOptions = ['现代简约', '北欧风', '工业风', '新中式', '法式轻奢', '日式', '美式', '混搭'];
   houseTypeOptions = ['一室一厅', '两室一厅', '两室两厅', '三室一厅', '三室两厅', '四室两厅', '复式', '别墅', '其他'];
-  propertyOptions = ['万科', '绿城', '保利', '龙湖', '融创', '中海', '碧桂园', '其他'];
   projectTypeOptions: Array<CaseItem['projectType']> = ['工装', '家装'];
   subTypeOptions: Array<CaseItem['subType']> = ['平层', '复式', '别墅', '自建房', '其他'];
   renderingLevelOptions: Array<CaseItem['renderingLevel']> = ['高端', '中端'];
+  priceOptions = ['5万以下', '5-10万', '10-20万', '20-30万', '30-50万', '50万以上'];
   sortOptions = [
     { label: '最新上传', value: 'createdAt' },
     { label: '浏览最多', value: 'views' },
@@ -177,12 +173,10 @@ export class CaseLibrary implements OnInit {
     this.filterForm = this.fb.group({
       style: [[]],
       houseType: [''],
-      property: [''],
       projectType: [''],
       subType: [''],
       renderingLevel: [''],
-      minArea: [''],
-      maxArea: [''],
+      price: [''],
       favorite: [false],
       sortBy: ['createdAt']
     });
@@ -237,7 +231,7 @@ export class CaseLibrary implements OnInit {
         category: pick(['客厅', '卧室', '厨房', '浴室', '书房', '餐厅']),
         style: [pick(this.styleOptions)],
         houseType: pick(this.houseTypeOptions),
-        property: pick(this.propertyOptions),
+        property: pick(['万科', '绿城', '保利', '龙湖', '融创']),
         designer: pick(['张设计', '李设计', '王设计', '赵设计', '陈设计']),
         area: rand(50, 150),
         createdAt,
@@ -371,12 +365,10 @@ export class CaseLibrary implements OnInit {
     this.filterForm.reset({
       style: [],
       houseType: '',
-      property: '',
       projectType: '',
       subType: '',
       renderingLevel: '',
-      minArea: '',
-      maxArea: '',
+      price: '',
       favorite: false,
       sortBy: 'createdAt'
     });

+ 29 - 18
src/app/pages/customer-service/consultation-order/consultation-order.html

@@ -62,6 +62,24 @@
   <!-- 主要内容区域 -->
   <div class="main-content">
 
+    <!-- 右上角项目需求卡片按钮 -->
+    <div class="requirement-card-toggle">
+      <button 
+        class="btn-secondary btn-sm" 
+        (click)="isRequirementCardExpanded.set(!isRequirementCardExpanded())"
+        [class.active]="isRequirementCardExpanded()"
+      >
+        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+          <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
+          <polyline points="14 2 14 8 20 8"></polyline>
+          <line x1="16" y1="13" x2="8" y2="13"></line>
+          <line x1="16" y1="17" x2="8" y2="17"></line>
+          <polyline points="10 9 9 9 8 9"></polyline>
+        </svg>
+        {{ isRequirementCardExpanded() ? '收起项目需求' : '填写项目需求' }}
+      </button>
+    </div>
+
     <!-- 客户信息卡片 -->
     <section class="info-card customer-card">
       <div class="card-header">
@@ -206,10 +224,7 @@
                   <option value="VIP客户">VIP客户</option>
                 </select>
               </div>
-              <div class="form-field">
-                <label for="source" class="field-label">来源渠道 <span class="optional">(可选)</span></label>
-                <input type="text" id="source" formControlName="source" placeholder="如:官网咨询、推荐介绍等" class="field-input">
-              </div>
+
               <div class="form-field">
                 <label for="demandType" class="field-label">需求类型 <span class="optional">(可选)</span></label>
                 <select id="demandType" formControlName="demandType" class="field-select">
@@ -231,8 +246,8 @@
       </div>
     </section>
 
-    <!-- 项目需求卡片 -->
-    <section class="info-card requirement-card">
+    <!-- 项目需求卡片(可折叠) -->
+    <section class="info-card requirement-card" *ngIf="isRequirementCardExpanded()">
       <div class="card-header">
         <div class="header-left">
           <div class="icon-wrapper requirement-icon">
@@ -247,6 +262,13 @@
           </div>
         </div>
         <div class="header-actions">
+          <button class="btn-ghost btn-sm" (click)="isRequirementCardExpanded.set(false)">
+            <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>
+            </svg>
+            收起
+          </button>
           <button class="btn-primary btn-sm" (click)="syncProjectInfo()" [disabled]="isSyncing()">
             <mat-spinner *ngIf="isSyncing()" diameter="16"></mat-spinner>
             <span *ngIf="!isSyncing()">从聊天记录提取</span>
@@ -254,18 +276,7 @@
         </div>
       </div>
 
-      <!-- Minimal 6 fields guide -->
       <div class="card-content">
-      <!-- Minimal 6 fields guide -->
-       <div class="minimal-guide">
-         <span class="guide-title">最小创建需6项:</span>
-         <span class="guide-item">客户姓名</span>
-         <span class="guide-item">手机</span>
-         <span class="guide-item">风格</span>
-         <span class="guide-item">项目小组</span>
-         <span class="guide-item">首付款</span>
-         <span class="guide-item">首稿时间</span>
-       </div>
 
        <form [formGroup]="requirementForm" class="requirement-form">
           <!-- 基础需求组 -->
@@ -442,7 +453,7 @@
         <button 
           class="btn-primary btn-lg" 
           (click)="submitForm()"
-          [disabled]="isSubmitting() || !requirementForm.valid || !customerForm.valid"
+          [disabled]="isSubmitting() || !customerForm.valid"
         >
           <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" *ngIf="!isSubmitting()">
             <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>

+ 5 - 3
src/app/pages/customer-service/consultation-order/consultation-order.ts

@@ -106,6 +106,8 @@ export class ConsultationOrder {
   isSyncing = signal(false);
   // 下单时间(自动生成)
   orderTime = signal<string>('');
+  // 项目需求卡片展开状态
+  isRequirementCardExpanded = signal(false);
 
   // 需求表单
   requirementForm: FormGroup;
@@ -151,9 +153,9 @@ export class ConsultationOrder {
       style: ['', Validators.required],
       budget: ['', Validators.required],
       area: ['', [Validators.required, Validators.min(1)]],
-      houseType: ['', Validators.required],
+      houseType: [''], // 改为非必填
       floor: ['', Validators.min(1)],
-      decorationType: ['', Validators.required],
+      decorationType: [''], // 改为非必填
       preferredDesigner: [''],
       specialRequirements: [''],
       referenceCases: [[]],
@@ -358,7 +360,7 @@ export class ConsultationOrder {
 
   // 提交表单
   submitForm() {
-    if (this.requirementForm.valid && this.customerForm.valid) {
+    if (this.customerForm.valid) {
       this.isSubmitting.set(true);
       
       const formData = {

+ 0 - 529
src/app/pages/hr/designer-profile/designer-profile.html

@@ -1,529 +0,0 @@
-<div class="designer-profile-container" *ngIf="designer() as d">
-  <div class="profile-header">
-    <div class="header-content">
-      <div class="avatar-section">
-        <img [src]="d.avatar || 'assets/images/default-avatar.svg'" alt="设计师头像" class="avatar">
-      </div>
-      <div class="info-section">
-        <h1>{{ d.name }} <span class="position-badge">{{ d.position }}</span></h1>
-        <div class="basic-info">
-          <!-- 头部信息:补充联系电话 -->
-          <div class="info-item">
-            <mat-icon>phone</mat-icon>
-            <span>{{ maskPhone(d.phone) }}</span>
-          </div>
-          <div class="info-item">
-            <mat-icon>business</mat-icon>
-            <span>{{ d.department }}</span>
-          </div>
-          <div class="info-item">
-            <mat-icon>school</mat-icon>
-            <span>{{ d.level }}设计师</span>
-          </div>
-          <div class="info-item">
-            <mat-icon>event</mat-icon>
-            <span>入职时间: {{ d.joinDate }}</span>
-          </div>
-        </div>
-      </div>
-      <div class="action-section">
-        <button mat-raised-button color="primary" (click)="openPortfolioPreview()">
-          <mat-icon>collections</mat-icon>
-          查看作品集
-        </button>
-      </div>
-    </div>
-  </div>
-
-  <mat-tab-group [selectedIndex]="activeTab()" (selectedIndexChange)="changeTab($event)" animationDuration="0ms" class="profile-tabs">
-    <!-- 基础信息标签页 -->
-    <mat-tab label="基础信息">
-      <div class="tab-content">
-        <div class="info-grid">
-          <!-- 技能与风格卡片 -->
-          <mat-card class="info-card skills-card">
-            <mat-card-header>
-              <mat-card-title>技能与专长</mat-card-title>
-            </mat-card-header>
-            <mat-card-content>
-              <div class="section-title">技术技能</div>
-              <div class="skill-chips">
-                <mat-chip-set>
-                  <!-- 技能与风格:改用 @for -->
-                  @for (skill of d.skills; track skill) {
-                    <mat-chip>{{ skill }}</mat-chip>
-                  }
-                </mat-chip-set>
-              </div>
-              
-              <div class="section-title">擅长风格</div>
-              <div class="style-chips">
-                <mat-chip-set>
-                  <!-- 技能与风格:改用 @for -->
-                  @for (style of d.styles; track style) {
-                    <mat-chip color="accent" selected>{{ style }}</mat-chip>
-                  }
-                </mat-chip-set>
-              </div>
-            </mat-card-content>
-          </mat-card>
-
-          <!-- 简历初筛卡片 -->
-          <mat-card class="info-card screening-card">
-            <mat-card-header>
-              <mat-card-title>简历初筛</mat-card-title>
-              <div class="spacer"></div>
-              @if (!editingScreening()) {
-                <button mat-stroked-button color="primary" (click)="startEditScreening()">
-                  <mat-icon>edit</mat-icon>
-                  编辑
-                </button>
-              } @else {
-                <button mat-stroked-button color="primary" (click)="saveScreening()">
-                  <mat-icon>save</mat-icon>
-                  保存
-                </button>
-                <button mat-button color="basic" (click)="cancelEditScreening()">取消</button>
-              }
-            </mat-card-header>
-            <mat-card-content>
-              <div class="resume-section">
-                <div class="section-title">基本信息</div>
-                <div class="kv-list">
-                  <div class="kv-item"><span class="k">姓名</span><span class="v">{{ d.name }}</span></div>
-                  <div class="kv-item"><span class="k">年龄</span><span class="v">{{ d.screening?.basic?.age || '-' }}</span></div>
-                  <div class="kv-item"><span class="k">学历</span><span class="v">{{ d.screening?.basic?.education || '-' }}</span></div>
-                  <div class="kv-item"><span class="k">工作年限</span><span class="v">{{ d.screening?.basic?.years || '-' }}</span></div>
-                  <div class="kv-item"><span class="k">求职岗位</span><span class="v">{{ d.screening?.basic?.targetRole || d.position }}</span></div>
-                </div>
-
-                <div class="section-title mt">核心能力</div>
-                <div class="kv-list">
-                  <div class="kv-item full">
-                   
-                    <span class="v">
-                      @if (d.screening?.core?.skills?.length) {
-                        @for (s of d.screening?.core?.skills || []; track s) {
-                          <mat-chip color="primary" selected>{{ s }}</mat-chip>
-                        }
-                      } @else {
-                        暂无
-                      }
-                    </span>
-                  </div>
-                  <div class="kv-item"><span class="k">相关项目经验</span><span class="v">{{ d.screening?.core?.projects || '-' }}</span></div>
-                 
-                </div>
-
-                <div class="section-title mt">求职意向</div>
-                <div class="kv-list">
-                  <div class="kv-item"><span class="k">期望薪资</span><span class="v">{{ d.screening?.intent?.salary || '-' }}</span></div>
-                  <div class="kv-item"><span class="k">到岗时间</span><span class="v">{{ d.screening?.intent?.onboard || '-' }}</span></div>
-                  <div class="kv-item"><span class="k">工作地点</span><span class="v">{{ d.screening?.intent?.location || '-' }}</span></div>
-                </div>
-
-                <div class="section-title mt">初筛结果</div>
-
-                @if (!editingScreening()) {
-                  <div class="result-row">
-                    <div class="result-status" [ngClass]="getScreeningStatusClass(d.screening?.result?.status)">
-                      <mat-icon>{{ getScreeningStatusIcon(d.screening?.result?.status) }}</mat-icon>
-                      <span>{{ getScreeningStatusText(d.screening?.result?.status) }}</span>
-                    </div>
-                    @if (d.screening?.result?.comment) {
-                      <div class="result-comment">{{ d.screening?.result?.comment }}</div>
-                    }
-                  </div>
-                } @else {
-                  <form [formGroup]="screeningForm" class="screening-form">
-                    <div class="form-row">
-                      <mat-button-toggle-group formControlName="status" class="status-toggle">
-                        <mat-button-toggle value="pass">通过</mat-button-toggle>
-                        <mat-button-toggle value="reject">不通过</mat-button-toggle>
-                        <mat-button-toggle value="pending">待定</mat-button-toggle>
-                      </mat-button-toggle-group>
-                    </div>
-                    
-                    @if (screeningForm.get('status')?.value === 'reject') {
-                      <div class="form-row">
-                        <mat-form-field appearance="outline" class="full-width">
-                          <mat-label>不通过原因</mat-label>
-                          <input matInput formControlName="reason" placeholder="请输入不通过的具体原因">
-                        </mat-form-field>
-                      </div>
-                    }
-                    
-                    <div class="form-row">
-                      <mat-form-field appearance="outline" class="full-width">
-                        <mat-label>备注说明</mat-label>
-                        <textarea matInput formControlName="comment" rows="3" placeholder="请输入初筛备注或建议"></textarea>
-                      </mat-form-field>
-                    </div>
-                  </form>
-                }
-              </div>
-            </mat-card-content>
-          </mat-card>
-
-          <!-- 资质证书卡片 -->
-          <mat-card class="info-card certificates-card">
-            <mat-card-header>
-              <mat-card-title>资质证书</mat-card-title>
-            </mat-card-header>
-            <mat-card-content>
-              <div class="certificate-list">
-                <div class="certificate-item" *ngFor="let cert of d.certificates || []">
-                  <div class="cert-icon">
-                    <mat-icon>verified</mat-icon>
-                  </div>
-                  <div class="cert-details">
-                    <div class="cert-name">{{ cert.name }}</div>
-                    <div class="cert-meta">
-                      <span class="cert-type">{{ cert.type }}</span>
-                      <span class="cert-date">{{ cert.date }}</span>
-                    </div>
-                  </div>
-                </div>
-                <div class="add-certificate" *ngIf="(d.certificates?.length || 0) === 0">
-                  <button mat-stroked-button color="primary">
-                    <mat-icon>add</mat-icon>
-                    添加证书
-                  </button>
-                </div>
-              </div>
-            </mat-card-content>
-          </mat-card>
-
-          <!-- 空档期卡片 -->
-          <mat-card class="info-card availability-card">
-            <mat-card-header>
-              <mat-card-title>技术空档期</mat-card-title>
-            </mat-card-header>
-            <mat-card-content>
-              <div class="availability-info">
-                <div class="availability-status" [ngClass]="{'available': (d.availableDates.length || 0) > 0}">
-                  <mat-icon>{{ (d.availableDates.length || 0) > 0 ? 'check_circle' : 'schedule' }}</mat-icon>
-                  <span>{{ (d.availableDates.length || 0) > 0 ? '当前有空档期' : '当前无空档期' }}</span>
-                </div>
-                <div class="available-dates" *ngIf="(d.availableDates.length || 0) > 0">
-                  <div class="section-title">可接单日期</div>
-                  <div class="date-chips">
-                    <mat-chip-set>
-                      <!-- 空档期:改用 @if/@for -->
-                      <div class="available-dates">
-                        <div class="section-title">可接单日期</div>
-                        <div class="date-chips">
-                          <mat-chip-set>
-                            @for (date of d.availableDates || []; track date) {
-                              <mat-chip color="primary" selected>{{ date }}</mat-chip>
-                            }
-                          </mat-chip-set>
-                        </div>
-                      </div>
-                    </mat-chip-set>
-                  </div>
-                </div>
-              </div>
-            </mat-card-content>
-            <mat-card-actions>
-              <button mat-button color="primary">更新空档期</button>
-            </mat-card-actions>
-          </mat-card>
-
-          <!-- 权限配置卡片 -->
-          <mat-card class="info-card permissions-card">
-            <mat-card-header>
-              <mat-card-title>权限配置</mat-card-title>
-            </mat-card-header>
-            <mat-card-content>
-              <div class="permission-list">
-                <div class="permission-item">
-                  <div class="permission-name">项目数据查看权限</div>
-                  <div class="permission-status granted">已授权</div>
-                </div>
-                <div class="permission-item">
-                  <div class="permission-name">业务费用数据查看</div>
-                  <div class="permission-status denied">未授权</div>
-                </div>
-                <div class="permission-item">
-                  <div class="permission-name">团队绩效数据查看</div>
-                  <div class="permission-status granted">已授权</div>
-                </div>
-                <div class="permission-item">
-                  <div class="permission-name">客户联系信息查看</div>
-                  <div class="permission-status granted">已授权</div>
-                </div>
-              </div>
-            </mat-card-content>
-            <mat-card-actions>
-              <button mat-button color="primary">调整权限</button>
-            </mat-card-actions>
-          </mat-card>
-        </div>
-      </div>
-    </mat-tab>
-
-    <!-- 工作记录标签页 -->
-    <mat-tab label="工作记录">
-      <div class="tab-content">
-        <div class="project-filters">
-          <mat-chip-set>
-            <mat-chip selected>全部项目</mat-chip>
-            <mat-chip>装修公司</mat-chip>
-            <mat-chip>设计工作室</mat-chip>
-            <mat-chip>效果图设计</mat-chip>
-            <mat-chip>建模+渲染</mat-chip>
-          </mat-chip-set>
-        </div>
-
-        <table mat-table [dataSource]="d.projects || []" class="project-table">
-          <!-- 项目名称列 -->
-          <ng-container matColumnDef="name">
-            <th mat-header-cell *matHeaderCellDef>项目名称</th>
-            <td mat-cell *matCellDef="let project">
-              <div class="project-name">{{ project.name }}</div>
-              <div class="project-tags">
-                <span class="tag" *ngFor="let tag of project.tags">{{ tag }}</span>
-              </div>
-            </td>
-          </ng-container>
-
-          <!-- 客户类型列 -->
-          <ng-container matColumnDef="clientType">
-            <th mat-header-cell *matHeaderCellDef>客户类型</th>
-            <td mat-cell *matCellDef="let project">{{ project.clientType }}</td>
-          </ng-container>
-
-          <!-- 项目角色列 -->
-          <ng-container matColumnDef="role">
-            <th mat-header-cell *matHeaderCellDef>项目角色</th>
-            <td mat-cell *matCellDef="let project">{{ project.role }}</td>
-          </ng-container>
-
-          <!-- 交付日期列 -->
-          <ng-container matColumnDef="deliveryDate">
-            <th mat-header-cell *matHeaderCellDef>交付日期</th>
-            <td mat-cell *matCellDef="let project">{{ project.deliveryDate }}</td>
-          </ng-container>
-
-          <!-- 客户评分列 -->
-          <ng-container matColumnDef="clientRating">
-            <th mat-header-cell *matHeaderCellDef>客户评分</th>
-            <td mat-cell *matCellDef="let project">
-              <div class="rating-stars">
-                <mat-icon *ngFor="let star of getRatingStars(project.clientRating)">{{ star }}</mat-icon>
-                <span class="rating-value">{{ project.clientRating }}</span>
-              </div>
-            </td>
-          </ng-container>
-
-          <!-- 操作列 -->
-          <ng-container matColumnDef="actions">
-            <th mat-header-cell *matHeaderCellDef>操作</th>
-            <td mat-cell *matCellDef="let project">
-              <button mat-icon-button matTooltip="查看反馈">
-                <mat-icon>feedback</mat-icon>
-              </button>
-              <button mat-icon-button matTooltip="查看详情">
-                <mat-icon>visibility</mat-icon>
-              </button>
-            </td>
-          </ng-container>
-
-          <tr mat-header-row *matHeaderRowDef="projectColumns"></tr>
-          <tr mat-row *matRowDef="let row; columns: projectColumns;"></tr>
-        </table>
-
-        <div class="substitute-records-section">
-          <h3>代班记录</h3>
-          <div class="empty-state">
-            <mat-icon>event_busy</mat-icon>
-            <p>暂无代班记录</p>
-            <button mat-stroked-button color="primary">
-              <mat-icon>add</mat-icon>
-              添加代班记录
-            </button>
-          </div>
-        </div>
-        </div>
-      </mat-tab>
-
-    <!-- 绩效详情标签页 -->
-    <mat-tab label="绩效详情">
-      <div class="tab-content">
-        <ng-container *ngIf="(d.performance?.length || 0) > 0; else perfEmpty">
-          <div class="performance-summary">
-            <div class="summary-card">
-              <div class="summary-title">客户满意度</div>
-              <div class="summary-value">
-                {{ d.performance[0].customerSatisfaction }}%
-                <mat-icon class="trend-icon" [ngClass]="getPerformanceTrend('customerSatisfaction')">
-                  {{ getPerformanceTrend('customerSatisfaction') === 'up' ? 'trending_up' : 
-                     getPerformanceTrend('customerSatisfaction') === 'down' ? 'trending_down' : 'trending_flat' }}
-                </mat-icon>
-              </div>
-              <mat-progress-bar mode="determinate" [value]="d.performance[0].customerSatisfaction || 0"></mat-progress-bar>
-            </div>
-            
-            <div class="summary-card">
-              <div class="summary-title">优秀作品率</div>
-              <div class="summary-value">
-                {{ d.performance[0].excellentWorkRate }}%
-                <mat-icon class="trend-icon" [ngClass]="getPerformanceTrend('excellentWorkRate')">
-                  {{ getPerformanceTrend('excellentWorkRate') === 'up' ? 'trending_up' : 
-                     getPerformanceTrend('excellentWorkRate') === 'down' ? 'trending_down' : 'trending_flat' }}
-                </mat-icon>
-              </div>
-              <mat-progress-bar mode="determinate" [value]="d.performance[0].excellentWorkRate || 0"></mat-progress-bar>
-            </div>
-            
-            <div class="summary-card">
-              <div class="summary-title">业绩值</div>
-              <div class="summary-value">
-                {{ d.performance[0].performanceValue }}
-                <mat-icon class="trend-icon" [ngClass]="getPerformanceTrend('performanceValue')">
-                  {{ getPerformanceTrend('performanceValue') === 'up' ? 'trending_up' : 
-                     getPerformanceTrend('performanceValue') === 'down' ? 'trending_down' : 'trending_flat' }}
-                </mat-icon>
-              </div>
-              <mat-progress-bar mode="determinate" [value]="d.performance[0].performanceValue || 0"></mat-progress-bar>
-            </div>
-          </div>
-      
-          <div class="performance-comparison">
-            <h3>绩效对比分析</h3>
-            <div class="comparison-chart">
-              <div class="chart-placeholder">
-                <div class="chart-bars">
-                  <div class="chart-bar">
-                    <div class="bar-label">客户满意度</div>
-                    <div class="bar-container">
-                      <div class="bar designer-bar" [style.height.%]="d.performance[0].customerSatisfaction || 0"></div>
-                      <div class="bar average-bar" style="height: 80%;"></div>
-                    </div>
-                    <div class="bar-legend">
-                      <div class="legend-item"><span class="legend-color designer"></span> 设计师</div>
-                      <div class="legend-item"><span class="legend-color average"></span> 部门平均</div>
-                    </div>
-                  </div>
-                  <div class="chart-bar">
-                    <div class="bar-label">优秀作品率</div>
-                    <div class="bar-container">
-                      <div class="bar designer-bar" [style.height.%]="d.performance[0].excellentWorkRate || 0"></div>
-                      <div class="bar average-bar" style="height: 75%;"></div>
-                    </div>
-                  </div>
-                  <div class="chart-bar">
-                    <div class="bar-label">业绩值</div>
-                    <div class="bar-container">
-                      <div class="bar designer-bar" [style.height.%]="d.performance[0].performanceValue || 0"></div>
-                      <div class="bar average-bar" style="height: 78%;"></div>
-                    </div>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-      
-          <div class="performance-details">
-            <h3>绩效明细记录</h3>
-            <table mat-table [dataSource]="d.performance || []" class="performance-table">
-              <!-- 季度列 -->
-              <ng-container matColumnDef="quarter">
-                <th mat-header-cell *matHeaderCellDef>季度</th>
-                <td mat-cell *matCellDef="let item">{{ item.quarter }}</td>
-              </ng-container>
-      
-              <!-- 客户满意度列 -->
-              <ng-container matColumnDef="customerSatisfaction">
-                <th mat-header-cell *matHeaderCellDef>客户满意度</th>
-                <td mat-cell *matCellDef="let item">{{ item.customerSatisfaction }}%</td>
-              </ng-container>
-      
-              <!-- 优秀作品率列 -->
-              <ng-container matColumnDef="excellentWorkRate">
-                <th mat-header-cell *matHeaderCellDef>优秀作品率</th>
-                <td mat-cell *matCellDef="let item">{{ item.excellentWorkRate }}%</td>
-              </ng-container>
-      
-              <!-- 业绩值列 -->
-              <ng-container matColumnDef="performanceValue">
-                <th mat-header-cell *matHeaderCellDef>业绩值</th>
-                <td mat-cell *matCellDef="let item">{{ item.performanceValue }}</td>
-              </ng-container>
-      
-              <!-- 绩效等级列 -->
-              <ng-container matColumnDef="finalGrade">
-                <th mat-header-cell *matHeaderCellDef>绩效等级</th>
-                <td mat-cell *matCellDef="let item">
-                  <span class="grade-badge" [style.background-color]="getPerformanceColor(item.finalGrade)">
-                    {{ item.finalGrade }}
-                  </span>
-                </td>
-              </ng-container>
-      
-              <!-- 操作列 -->
-              <ng-container matColumnDef="actions">
-                <th mat-header-cell *matHeaderCellDef>操作</th>
-                <td mat-cell *matCellDef="let item">
-                  <button mat-icon-button matTooltip="查看扣分项" [matBadge]="item.deductions.length" 
-                    [matBadgeHidden]="item.deductions.length === 0" matBadgeColor="warn">
-                    <mat-icon>error_outline</mat-icon>
-                  </button>
-                  <button mat-icon-button matTooltip="查看详情">
-                    <mat-icon>visibility</mat-icon>
-                  </button>
-                </td>
-              </ng-container>
-      
-              <tr mat-header-row *matHeaderRowDef="performanceColumns"></tr>
-              <tr mat-row *matRowDef="let row; columns: performanceColumns;"></tr>
-            </table>
-          </div>
-      
-          <div class="promotion-history">
-            <h3>晋级记录</h3>
-            <div class="timeline">
-              <div class="timeline-item">
-                <div class="timeline-point"></div>
-                <div class="timeline-content">
-                  <div class="timeline-date">2022-01-15</div>
-                  <div class="timeline-title">晋升为高级设计师</div>
-                  <div class="timeline-description">基于优秀的项目表现和客户满意度,晋升为高级设计师</div>
-                </div>
-              </div>
-              <div class="timeline-item">
-                <div class="timeline-point"></div>
-                <div class="timeline-content">
-                  <div class="timeline-date">2021-03-10</div>
-                  <div class="timeline-title">晋升为中级设计师</div>
-                  <div class="timeline-description">完成技能认证,项目质量稳定,晋升为中级设计师</div>
-                </div>
-              </div>
-              <div class="timeline-item">
-                <div class="timeline-point"></div>
-                <div class="timeline-content">
-                  <div class="timeline-date">2020-05-15</div>
-                  <div class="timeline-title">入职</div>
-                  <div class="timeline-description">作为初级设计师加入公司</div>
-                </div>
-              </div>
-            </div>
-          </div>
-        </ng-container>
-        <ng-template #perfEmpty>
-          <div class="empty-state">
-            <mat-icon>insights</mat-icon>
-            <p>暂无绩效数据</p>
-          </div>
-        </ng-template>
-      </div>
-     </mat-tab>
-  </mat-tab-group>
-</div>
-
-<!-- 加载状态 -->
-<div class="loading-container" *ngIf="!designer()">
-  <mat-spinner diameter="40"></mat-spinner>
-  <p>加载设计师信息中...</p>
-</div>

+ 0 - 1036
src/app/pages/hr/designer-profile/designer-profile.scss

@@ -1,1036 +0,0 @@
-.designer-profile-container {
-  display: flex;
-  flex-direction: column;
-  height: 100%;
-  background-color: #f5f7fa;
-  animation: fadeIn 0.3s ease-in-out;
-  
-  .profile-header {
-    background-color: #fff;
-    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
-    padding: 24px;
-    margin-bottom: 20px;
-    border-radius: 8px;
-    
-    .header-content {
-      display: flex;
-      align-items: center;
-      
-      .avatar-section {
-        margin-right: 24px;
-        
-        .avatar {
-          width: 100px;
-          height: 100px;
-          border-radius: 50%;
-          object-fit: cover;
-          border: 3px solid #fff;
-          box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-        }
-      }
-      
-      .info-section {
-        flex: 1;
-        
-        h1 {
-          margin: 0 0 12px 0;
-          font-size: 24px;
-          font-weight: 500;
-          display: flex;
-          align-items: center;
-          
-          .position-badge {
-            margin-left: 12px;
-            font-size: 14px;
-            background-color: #1a3a6d;
-            color: white;
-            padding: 4px 10px;
-            border-radius: 4px;
-            font-weight: normal;
-          }
-        }
-        
-        .basic-info {
-          display: flex;
-          gap: 24px;
-          
-          .info-item {
-            display: flex;
-            align-items: center;
-            color: #5a6a85;
-            
-            mat-icon {
-              margin-right: 6px;
-              font-size: 18px;
-              height: 18px;
-              width: 18px;
-              line-height: 18px;
-            }
-          }
-        }
-      }
-      
-      .action-section {
-        margin-left: auto;
-      }
-    }
-  }
-  
-  .profile-tabs {
-    flex: 1;
-    
-    ::ng-deep .mat-mdc-tab-header {
-      background-color: white;
-      border-radius: 8px 8px 0 0;
-      padding: 0 16px;
-    }
-    
-    ::ng-deep .mat-mdc-tab-body-wrapper {
-      flex: 1;
-      background-color: white;
-      border-radius: 0 0 8px 8px;
-    }
-  }
-  
-  .tab-content {
-    padding: 24px;
-    height: 100%;
-    overflow-y: auto;
-    animation: slideInUp 0.3s ease-out;
-  }
-  
-  // 基础信息标签页样式
-  .info-grid {
-    display: grid;
-    grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
-    gap: 20px;
-    
-    .info-card {
-      border-radius: 8px;
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
-      
-      mat-card-header {
-        padding: 16px;
-        border-bottom: 1px solid #eee;
-        
-        mat-card-title {
-          margin: 0;
-          font-size: 18px;
-          font-weight: 500;
-          color: #1a3a6d;
-        }
-      }
-      
-      mat-card-content {
-        padding: 16px;
-      }
-      
-      mat-card-actions {
-        padding: 8px 16px 16px;
-        display: flex;
-        justify-content: flex-end;
-      }
-    }
-    
-    .section-title {
-      font-weight: 500;
-      margin-bottom: 12px;
-      color: #5a6a85;
-    }
-    
-    .skill-chips, .style-chips, .date-chips {
-      margin-bottom: 20px;
-      
-      mat-chip-set {
-        display: flex;
-        flex-wrap: wrap;
-        gap: 8px;
-      }
-    }
-    
-    .certificate-list {
-      .certificate-item {
-        display: flex;
-        align-items: center;
-        padding: 12px 0;
-        border-bottom: 1px solid #eee;
-        
-        &:last-child {
-          border-bottom: none;
-        }
-        
-        .cert-icon {
-          margin-right: 16px;
-          
-          mat-icon {
-            color: #4caf50;
-            background-color: rgba(76, 175, 80, 0.1);
-            border-radius: 50%;
-            padding: 6px;
-          }
-        }
-        
-        .cert-details {
-          flex: 1;
-          
-          .cert-name {
-            font-weight: 500;
-            margin-bottom: 4px;
-          }
-          
-          .cert-meta {
-            display: flex;
-            color: #5a6a85;
-            font-size: 13px;
-            
-            .cert-type {
-              margin-right: 12px;
-              padding: 2px 8px;
-              background-color: #e3f2fd;
-              border-radius: 4px;
-            }
-          }
-        }
-      }
-      
-      .add-certificate {
-        display: flex;
-        justify-content: center;
-        padding: 20px 0;
-      }
-    }
-    
-    .availability-info {
-      .availability-status {
-        display: flex;
-        align-items: center;
-        margin-bottom: 16px;
-        color: #f44336;
-        
-        &.available {
-          color: #4caf50;
-        }
-        
-        mat-icon {
-          margin-right: 8px;
-        }
-      }
-    }
-    
-    .permission-list {
-      .permission-item {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        padding: 12px 0;
-        border-bottom: 1px solid #eee;
-        
-        &:last-child {
-          border-bottom: none;
-        }
-        
-        .permission-name {
-          font-weight: 500;
-        }
-        
-        .permission-status {
-          padding: 4px 10px;
-          border-radius: 4px;
-          font-size: 13px;
-          
-          &.granted {
-            background-color: #e8f5e9;
-            color: #2e7d32;
-          }
-          
-          &.denied {
-            background-color: #ffebee;
-            color: #c62828;
-          }
-        }
-      }
-    }
-  }
-  
-  // 工作记录标签页样式
-  .project-filters {
-    margin-bottom: 20px;
-  }
-  
-  .project-table {
-    width: 100%;
-    margin-bottom: 30px;
-    box-shadow: none;
-    border: 1px solid #eee;
-    border-radius: 8px;
-    overflow: hidden;
-    
-    .mat-mdc-header-row {
-      background-color: #f5f7fa;
-    }
-    
-    .mat-mdc-row {
-      &:hover {
-        background-color: #f5f7fa;
-      }
-    }
-    
-    .project-name {
-      font-weight: 500;
-      margin-bottom: 4px;
-    }
-    
-    .project-tags {
-      display: flex;
-      flex-wrap: wrap;
-      gap: 4px;
-      
-      .tag {
-        font-size: 12px;
-        padding: 2px 8px;
-        background-color: #e3f2fd;
-        border-radius: 4px;
-        color: #1565c0;
-      }
-    }
-    
-    .rating-stars {
-      display: flex;
-      align-items: center;
-      
-      mat-icon {
-        color: #ffc107;
-        font-size: 18px;
-        width: 18px;
-        height: 18px;
-        line-height: 18px;
-      }
-      
-      .rating-value {
-        margin-left: 6px;
-        font-weight: 500;
-      }
-    }
-  }
-  
-  .substitute-records-section {
-    h3 {
-      margin-top: 0;
-      color: #1a3a6d;
-      font-weight: 500;
-    }
-    
-    .empty-state {
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-      padding: 40px 0;
-      background-color: #f5f7fa;
-      border-radius: 8px;
-      
-      mat-icon {
-        font-size: 48px;
-        height: 48px;
-        width: 48px;
-        margin-bottom: 16px;
-        color: #9e9e9e;
-      }
-      
-      p {
-        margin-bottom: 16px;
-        color: #5a6a85;
-      }
-    }
-  }
-  
-  // 绩效详情标签页样式
-  .performance-summary {
-    display: grid;
-    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
-    gap: 20px;
-    margin-bottom: 30px;
-    
-    .summary-card {
-      background-color: white;
-      border-radius: 8px;
-      padding: 20px;
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
-      
-      .summary-title {
-        color: #5a6a85;
-        font-size: 14px;
-        margin-bottom: 12px;
-      }
-      
-      .summary-value {
-        font-size: 28px;
-        font-weight: 500;
-        margin-bottom: 12px;
-        display: flex;
-        align-items: center;
-        
-        .trend-icon {
-          margin-left: 8px;
-          font-size: 20px;
-          
-          &.up {
-            color: #4caf50;
-          }
-          
-          &.down {
-            color: #f44336;
-          }
-          
-          &.flat {
-            color: #9e9e9e;
-          }
-        }
-      }
-    }
-  }
-  
-  .performance-comparison {
-    margin-bottom: 30px;
-    
-    h3 {
-      margin-top: 0;
-      color: #1a3a6d;
-      font-weight: 500;
-      margin-bottom: 16px;
-    }
-    
-    .comparison-chart {
-      background-color: white;
-      border-radius: 8px;
-      padding: 20px;
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
-      
-      .chart-placeholder {
-        height: 250px;
-        display: flex;
-        justify-content: center;
-        
-        .chart-bars {
-          display: flex;
-          align-items: flex-end;
-          height: 100%;
-          width: 100%;
-          max-width: 600px;
-          padding-top: 20px;
-          
-          .chart-bar {
-            flex: 1;
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            height: 100%;
-            
-            .bar-label {
-              text-align: center;
-              font-size: 14px;
-              color: #5a6a85;
-              margin-bottom: 10px;
-              font-weight: 500;
-            }
-            
-            .bar-container {
-              height: 70%;
-              width: 60px;
-              position: relative;
-              display: flex;
-              justify-content: center;
-              
-              .bar {
-                width: 24px;
-                position: absolute;
-                bottom: 0;
-                border-radius: 4px 4px 0 0;
-                
-                &.designer-bar {
-                  background-color: #1a3a6d;
-                  left: 8px;
-                }
-                
-                &.average-bar {
-                  background-color: #90caf9;
-                  right: 8px;
-                }
-              }
-            }
-            
-            .bar-legend {
-              display: flex;
-              gap: 12px;
-              margin-top: 12px;
-              
-              .legend-item {
-                display: flex;
-                align-items: center;
-                font-size: 12px;
-                
-                .legend-color {
-                  display: inline-block;
-                  width: 12px;
-                  height: 12px;
-                  margin-right: 4px;
-                  border-radius: 2px;
-                  
-                  &.designer {
-                    background-color: #1a3a6d;
-                  }
-                  
-                  &.average {
-                    background-color: #90caf9;
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  
-  .performance-details {
-    margin-bottom: 30px;
-    
-    h3 {
-      margin-top: 0;
-      color: #1a3a6d;
-      font-weight: 500;
-      margin-bottom: 16px;
-    }
-    
-    .performance-table {
-      width: 100%;
-      box-shadow: none;
-      border: 1px solid #eee;
-      border-radius: 8px;
-      overflow: hidden;
-      
-      .mat-mdc-header-row {
-        background-color: #f5f7fa;
-      }
-      
-      .mat-mdc-row {
-        &:hover {
-          background-color: #f5f7fa;
-        }
-      }
-      
-      .grade-badge {
-        padding: 4px 10px;
-        border-radius: 4px;
-        color: white;
-        font-size: 13px;
-      }
-    }
-  }
-  
-  .promotion-history {
-    h3 {
-      margin-top: 0;
-      color: #1a3a6d;
-      font-weight: 500;
-      margin-bottom: 16px;
-    }
-    
-    .timeline {
-      position: relative;
-      padding-left: 30px;
-      
-      &:before {
-        content: '';
-        position: absolute;
-        left: 7px;
-        top: 0;
-        height: 100%;
-        width: 2px;
-        background-color: #e0e0e0;
-      }
-      
-      .timeline-item {
-        position: relative;
-        padding-bottom: 30px;
-        
-        &:last-child {
-          padding-bottom: 0;
-        }
-        
-        .timeline-point {
-          position: absolute;
-          left: -30px;
-          top: 0;
-          width: 16px;
-          height: 16px;
-          border-radius: 50%;
-          background-color: #1a3a6d;
-          border: 3px solid white;
-          box-shadow: 0 0 0 1px #e0e0e0;
-        }
-        
-        .timeline-content {
-          background-color: white;
-          border-radius: 8px;
-          padding: 16px;
-          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
-          
-          .timeline-date {
-            color: #5a6a85;
-            font-size: 14px;
-            margin-bottom: 8px;
-          }
-          
-          .timeline-title {
-            font-weight: 500;
-            font-size: 16px;
-            margin-bottom: 8px;
-            color: #1a3a6d;
-          }
-          
-          .timeline-description {
-            color: #5a6a85;
-          }
-        }
-      }
-    }
-  }
-}
-
-.loading-container {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  height: 100%;
-  
-  p {
-    margin-top: 16px;
-    color: #5a6a85;
-  }
-}
-
-// 作品集预览对话框样式
-.portfolio-preview-dialog {
-  .mat-mdc-dialog-title {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 0;
-    
-    h2 {
-      margin: 0;
-    }
-  }
-  
-  .mat-mdc-dialog-content {
-    padding-top: 20px;
-    
-    .portfolio-image {
-      width: 100%;
-      border-radius: 8px;
-      margin-bottom: 16px;
-    }
-    
-    .portfolio-info {
-      .info-row {
-        display: flex;
-        margin-bottom: 12px;
-        
-        .info-label {
-          width: 100px;
-          font-weight: 500;
-          color: #5a6a85;
-        }
-        
-        .info-value {
-          flex: 1;
-        }
-        
-        .rating-stars {
-          display: flex;
-          
-          mat-icon {
-            color: #ffc107;
-          }
-        }
-      }
-    }
-  }
-}
-
-// 添加动画关键帧
-@keyframes fadeIn {
-  from { opacity: 0; }
-  to { opacity: 1; }
-}
-
-@keyframes slideInUp {
-  from {
-    transform: translateY(20px);
-    opacity: 0;
-  }
-  to {
-    transform: translateY(0);
-    opacity: 1;
-  }
-}
-
-// 卡片悬停效果
-.info-card, .summary-card, .timeline-content {
-  transition: transform 0.3s ease, box-shadow 0.3s ease;
-  
-  &:hover {
-    transform: translateY(-5px);
-    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
-  }
-}
-
-// 按钮悬停效果
-button.mat-mdc-button, button.mat-mdc-stroked-button, button.mat-mdc-raised-button {
-  transition: all 0.2s ease;
-  
-  &:hover {
-    transform: translateY(-2px);
-  }
-}
-
-// 响应式调整
-@media (max-width: 768px) {
-  .designer-profile-container {
-    .profile-header {
-      .header-content {
-        flex-direction: column;
-        align-items: flex-start;
-        
-        .avatar-section {
-          margin-right: 0;
-          margin-bottom: 16px;
-        }
-        
-        .action-section {
-          margin-left: 0;
-          margin-top: 16px;
-          width: 100%;
-          
-          button {
-            width: 100%;
-          }
-        }
-      }
-    }
-    
-    .info-grid {
-      grid-template-columns: 1fr;
-    }
-    
-    .performance-summary {
-      grid-template-columns: 1fr;
-    }
-  }
-}
-
-// 简历初筛卡片样式
-.screening-card {
-  .card-header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 16px;
-
-    h3 {
-      margin: 0;
-      font-size: 16px;
-      font-weight: 500;
-      color: #1a3a6e;
-    }
-
-    .edit-actions {
-      display: flex;
-      gap: 8px;
-
-      .mat-mdc-button {
-        min-width: auto;
-        padding: 0 12px;
-        height: 32px;
-        font-size: 13px;
-      }
-    }
-  }
-
-  .screening-content {
-    .info-section {
-      margin-bottom: 20px;
-
-      .section-title {
-        font-size: 14px;
-        font-weight: 500;
-        color: #1a3a6e;
-        margin-bottom: 8px;
-        display: flex;
-        align-items: center;
-        gap: 6px;
-
-        mat-icon {
-          font-size: 16px;
-          width: 16px;
-          height: 16px;
-          color: #666;
-        }
-      }
-
-      .info-content {
-        padding-left: 22px;
-        color: #666;
-        font-size: 13px;
-        line-height: 1.5;
-
-        .info-item {
-          margin-bottom: 4px;
-
-          .label {
-            font-weight: 500;
-            color: #333;
-            margin-right: 8px;
-          }
-        }
-
-        .skills-list {
-          display: flex;
-          flex-wrap: wrap;
-          gap: 6px;
-          margin-top: 4px;
-
-          .skill-chip {
-            background-color: #e6f7ff;
-            color: #1a3a6e;
-            padding: 2px 8px;
-            border-radius: 12px;
-            font-size: 12px;
-          }
-        }
-      }
-    }
-
-    .result-section {
-      border-top: 1px solid #f0f0f0;
-      padding-top: 16px;
-
-      .status-display {
-        display: flex;
-        align-items: center;
-        gap: 8px;
-        margin-bottom: 8px;
-
-        .status-icon {
-          font-size: 18px;
-          width: 18px;
-          height: 18px;
-
-          &.status-pass {
-            color: #52c41a;
-          }
-
-          &.status-reject {
-            color: #ff4d4f;
-          }
-
-          &.status-pending {
-            color: #faad14;
-          }
-        }
-
-        .status-text {
-          font-weight: 500;
-          font-size: 14px;
-
-          &.status-pass {
-            color: #52c41a;
-          }
-
-          &.status-reject {
-            color: #ff4d4f;
-          }
-
-          &.status-pending {
-            color: #faad14;
-          }
-        }
-      }
-
-      .comment-text {
-        color: #666;
-        font-size: 13px;
-        line-height: 1.5;
-        margin-top: 8px;
-        padding: 8px 12px;
-        background-color: #f8f9fa;
-        border-radius: 6px;
-        border-left: 3px solid #e6f7ff;
-      }
-    }
-  }
-
-  .screening-form {
-    .form-row {
-      display: flex;
-      gap: 16px;
-      margin-bottom: 16px;
-
-      .form-field {
-        flex: 1;
-
-        .mat-mdc-form-field {
-          width: 100%;
-        }
-      }
-    }
-
-    .status-toggle {
-      margin-bottom: 16px;
-
-      .mat-button-toggle-group {
-        border: 1px solid #d9d9d9;
-        border-radius: 6px;
-        overflow: hidden;
-
-        .mat-button-toggle {
-          border: none;
-          font-size: 13px;
-          padding: 0 16px;
-          height: 36px;
-
-          &.mat-button-toggle-checked {
-            background-color: #1a3a6e;
-            color: white;
-
-            &:hover {
-              background-color: #1a3a6e;
-            }
-          }
-
-          &:not(.mat-button-toggle-checked) {
-            background-color: white;
-            color: #666;
-
-            &:hover {
-              background-color: #f5f5f5;
-            }
-          }
-        }
-      }
-    }
-
-    .form-actions {
-      display: flex;
-      justify-content: flex-end;
-      gap: 8px;
-      margin-top: 16px;
-      padding-top: 16px;
-      border-top: 1px solid #f0f0f0;
-
-      .mat-mdc-button {
-        min-width: 80px;
-        height: 36px;
-        font-size: 13px;
-      }
-    }
-  }
-}
-
-// 状态样式
-.status-pass {
-  color: #52c41a !important;
-}
-
-.status-reject {
-  color: #ff4d4f !important;
-}
-
-.status-pending {
-  color: #faad14 !important;
-}
-
-/* 修复Material图标字体和奇怪字符问题 */
-mat-icon {
-  font-family: 'Material Icons' !important;
-  font-feature-settings: 'liga' 1;
-  -webkit-font-feature-settings: 'liga';
-  -moz-font-feature-settings: 'liga';
-  font-variant-ligatures: common-ligatures;
-  text-rendering: optimizeLegibility;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  font-size: inherit;
-  line-height: inherit;
-  vertical-align: middle;
-  
-  &::before {
-    content: none !important;
-  }
-}
-
-/* 统一按钮图标与文字对齐 */
-button mat-icon {
-  font-size: 18px !important;
-  width: 18px !important;
-  height: 18px !important;
-  line-height: 18px !important;
-  vertical-align: middle;
-}
-
-/* 信息项图标特殊处理 */
-.info-item mat-icon {
-  font-size: 18px !important;
-  width: 18px !important;
-  height: 18px !important;
-  line-height: 18px !important;
-  margin-right: 6px;
-  color: #5a6a85;
-}
-
-/* 趋势图标优化 */
-.trend-icon {
-  font-size: 16px !important;
-  width: 16px !important;
-  height: 16px !important;
-  line-height: 16px !important;
-  
-  &.trending_up {
-    color: #4caf50;
-  }
-  
-  &.trending_down {
-    color: #f44336;
-  }
-  
-  &.trending_flat {
-    color: #ff9800;
-  }
-}
-
-/* 评级星星图标优化 */
-.rating-stars mat-icon {
-  font-size: 16px !important;
-  width: 16px !important;
-  height: 16px !important;
-  line-height: 16px !important;
-  color: #ffc107;
-}
-
-/* 表格操作按钮图标优化 */
-.mat-table mat-icon {
-  font-size: 16px !important;
-  width: 16px !important;
-  height: 16px !important;
-  line-height: 16px !important;
-}
-
-/* 卡片头像图标优化 */
-mat-card-avatar mat-icon {
-  font-size: 24px !important;
-  width: 24px !important;
-  height: 24px !important;
-  line-height: 24px !important;
-}

+ 0 - 553
src/app/pages/hr/designer-profile/designer-profile.ts

@@ -1,553 +0,0 @@
-import { Component, OnInit, signal, inject } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { MatTabsModule } from '@angular/material/tabs';
-import { MatCardModule } from '@angular/material/card';
-import { MatButtonModule } from '@angular/material/button';
-import { MatIconModule } from '@angular/material/icon';
-import { MatChipsModule } from '@angular/material/chips';
-import { MatDividerModule } from '@angular/material/divider';
-import { MatProgressBarModule } from '@angular/material/progress-bar';
-import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
-import { MatTableModule } from '@angular/material/table';
-import { MatBadgeModule } from '@angular/material/badge';
-import { MatDialogModule, MatDialog } from '@angular/material/dialog';
-import { MatTooltipModule } from '@angular/material/tooltip';
-import { ActivatedRoute } from '@angular/router';
-import { FormsModule, ReactiveFormsModule, FormGroup, FormControl } from '@angular/forms';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatInputModule } from '@angular/material/input';
-import { MatButtonToggleModule } from '@angular/material/button-toggle';
-
-// 模拟数据接口
-interface Designer {
-  id: string;
-  name: string;
-  avatar: string;
-  position: string;
-  level: string;
-  department: string;
-  joinDate: string;
-  phone?: string;
-  idNumber?: string;
-  bankCard?: string;
-  skills: string[];
-  styles: string[];
-  availableDates: string[];
-  certificates: {
-    name: string;
-    date: string;
-    type: string;
-  }[];
-  projects: {
-    id: string;
-    name: string;
-    clientType: string;
-    role: string;
-    deliveryDate: string;
-    clientRating: number;
-    tags: string[];
-    feedback: string;
-  }[];
-  performance: {
-    quarter: string;
-    customerSatisfaction: number;
-    excellentWorkRate: number;
-    performanceValue: number;
-    deductions: {
-      reason: string;
-      points: number;
-      date: string;
-    }[];
-    finalGrade: string;
-  }[];
-  // 新增:简历初筛结构
-  screening?: {
-    basic?: {
-      age?: number;
-      education?: string;
-      years?: string | number;
-      targetRole?: string;
-    };
-    core?: {
-      skills?: string[];
-      projects?: string;
-      certs?: string;
-    };
-    intent?: {
-      salary?: string;
-      onboard?: string;
-      location?: string;
-    };
-    result?: {
-      status: 'pass' | 'reject' | 'pending';
-      reason?: string;
-      comment?: string;
-    };
-  };
-}
-
-// 作品集预览对话框组件
-@Component({
-  selector: 'portfolio-preview-dialog',
-  standalone: true,
-  imports: [CommonModule, MatDialogModule, MatButtonModule, MatIconModule],
-  template: `
-    <div class="portfolio-dialog">
-      <div class="dialog-header">
-        <h2>作品集预览</h2>
-        <button mat-icon-button (click)="close()">
-          <mat-icon>close</mat-icon>
-        </button>
-      </div>
-      <div class="dialog-content">
-        <div class="portfolio-gallery">
-          <div class="portfolio-item" *ngFor="let item of portfolioItems">
-            <img [src]="item.imageUrl" [alt]="item.title">
-            <div class="portfolio-info">
-              <h3>{{item.title}}</h3>
-              <p>{{item.description}}</p>
-              <div class="portfolio-tags">
-                <span *ngFor="let tag of item.tags">{{tag}}</span>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  `,
-  styles: [`
-    .portfolio-dialog {
-      padding: 0;
-      max-width: 900px;
-      width: 100%;
-    }
-    .dialog-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      padding: 16px 24px;
-      border-bottom: 1px solid #eee;
-    }
-    .dialog-header h2 {
-      margin: 0;
-      font-size: 20px;
-      color: #1a3a6e;
-    }
-    .dialog-content {
-      padding: 24px;
-      max-height: 70vh;
-      overflow-y: auto;
-    }
-    .portfolio-gallery {
-      display: grid;
-      grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
-      gap: 24px;
-    }
-    .portfolio-item {
-      border-radius: 8px;
-      overflow: hidden;
-      box-shadow: 0 4px 8px rgba(0,0,0,0.1);
-      transition: transform 0.3s;
-    }
-    .portfolio-item:hover {
-      transform: translateY(-5px);
-    }
-    .portfolio-item img {
-      width: 100%;
-      height: 180px;
-      object-fit: cover;
-    }
-    .portfolio-info {
-      padding: 16px;
-    }
-    .portfolio-info h3 {
-      margin: 0 0 8px;
-      font-size: 16px;
-      color: #1a3a6e;
-    }
-    .portfolio-info p {
-      margin: 0 0 12px;
-      font-size: 14px;
-      color: #666;
-    }
-    .portfolio-tags {
-      display: flex;
-      flex-wrap: wrap;
-      gap: 8px;
-    }
-    .portfolio-tags span {
-      background-color: #e6f7ff;
-      color: #1a3a6e;
-      padding: 4px 8px;
-      border-radius: 4px;
-      font-size: 12px;
-    }
-  `]
-})
-export class PortfolioPreviewDialog {
-  portfolioItems = [
-    {
-      imageUrl: 'assets/images/portfolio-1.svg',
-      title: '现代简约风客厅',
-      description: '为装修公司客户打造的现代简约风格客厅效果图',
-      tags: ['客厅', '现代简约', '3D建模']
-    },
-    {
-      imageUrl: 'assets/images/portfolio-2.svg',
-      title: '北欧风卧室',
-      description: '设计工作室委托的北欧风格卧室设计',
-      tags: ['卧室', '北欧风', '软装搭配']
-    },
-    {
-      imageUrl: 'assets/images/portfolio-3.svg',
-      title: '日式风格书房',
-      description: '个人客户定制的日式风格书房设计',
-      tags: ['书房', '日式', '全屋定制']
-    },
-    {
-      imageUrl: 'assets/images/portfolio-4.svg',
-      title: '工业风餐厅',
-      description: '商业空间的工业风格餐厅设计',
-      tags: ['餐厅', '工业风', '商业空间']
-    }
-  ];
-
-  constructor(private dialog: MatDialog) {}
-
-  close() {
-    this.dialog.closeAll();
-  }
-}
-
-@Component({
-  selector: 'app-designer-profile',
-  standalone: true,
-  imports: [
-    CommonModule,
-    MatTabsModule,
-    MatCardModule,
-    MatButtonModule,
-    MatIconModule,
-    MatChipsModule,
-    MatDividerModule,
-    MatProgressBarModule,
-    MatProgressSpinnerModule,
-    MatTableModule,
-    MatBadgeModule,
-    MatDialogModule,
-    MatTooltipModule,
-    FormsModule,
-    ReactiveFormsModule,
-    MatFormFieldModule,
-    MatInputModule,
-    MatButtonToggleModule
-  ],
-  templateUrl: './designer-profile.html',
-  styleUrls: ['./designer-profile.scss']
-})
-export class DesignerProfile implements OnInit {
-  designer = signal<Designer | null>(null);
-  activeTab = signal(0);
-  projectColumns = ['name', 'clientType', 'role', 'deliveryDate', 'clientRating', 'actions'];
-  performanceColumns = ['quarter', 'customerSatisfaction', 'excellentWorkRate', 'performanceValue', 'finalGrade', 'actions'];
-  isLoading = signal(true);
-  projectsLoading = signal(true);
-  performanceLoading = signal(true);
-  
-  // 编辑状态与表单
-  editingScreening = signal(false);
-  screeningForm = new FormGroup({
-    status: new FormControl<'pass' | 'reject' | 'pending'>('pending', { nonNullable: true }),
-    reason: new FormControl<string>(''),
-    comment: new FormControl<string>('')
-  });
-
-  private route = inject(ActivatedRoute);
-  private dialog = inject(MatDialog);
-
-  constructor() {}
-
-  ngOnInit() {
-    // 从路由参数获取设计师ID
-    this.route.paramMap.subscribe(params => {
-      const id = params.get('id');
-      if (id) {
-        this.loadDesignerData(id);
-      }
-    });
-    
-    // 模拟加载项目数据
-    setTimeout(() => {
-      this.projectsLoading.set(false);
-    }, 1500);
-
-    // 模拟加载绩效数据和初始化性能趋势图表数据
-    setTimeout(() => {
-      this.performanceLoading.set(false);
-      const performanceData = this.generatePerformanceTrend();
-      console.log('Performance trend data:', performanceData);
-      // 这里可以添加图表初始化代码
-    }, 2000);
-  }
-
-  loadDesignerData(id: string) {
-    // 模拟API调用加载设计师数据
-    setTimeout(() => {
-      this.designer.set({
-        id,
-        name: '张明',
-        avatar: 'assets/images/default-avatar.svg',
-        position: '高级设计师',
-        level: '高级',
-        department: '设计部-效果图组',
-        joinDate: '2020-05-15',
-        phone: '13800138006',
-        idNumber: '110101199001011234',
-        bankCard: '6222021234567890123',
-        skills: ['3D建模', '渲染', '后期处理', 'CAD制图'],
-        styles: ['现代简约', '北欧风格', '新中式'],
-        availableDates: ['2023-06-15', '2023-06-16', '2023-06-17'],
-        certificates: [
-          { name: '3D效果图高级设计师认证', date: '2021-03-10', type: '技能认证' },
-          { name: '优秀设计师季度奖', date: '2022-12-20', type: '荣誉证书' }
-        ],
-        projects: [
-          {
-            id: 'P001',
-            name: '城市花园小区-89平米-现代简约',
-            clientType: '装修公司',
-            role: '效果图设计',
-            deliveryDate: '2023-05-20',
-            clientRating: 4.8,
-            tags: ['住宅', '现代简约'],
-            feedback: '设计师理解需求准确,效果图质量高,客户非常满意。'
-          },
-          {
-            id: 'P002',
-            name: '星河湾别墅-280平米-新中式',
-            clientType: '设计工作室',
-            role: '建模+渲染',
-            deliveryDate: '2023-04-15',
-            clientRating: 4.5,
-            tags: ['别墅', '新中式'],
-            feedback: '建模细节处理到位,渲染效果自然,符合预期。'
-          },
-          {
-            id: 'P003',
-            name: '商业广场-咖啡厅设计',
-            clientType: '装修公司',
-            role: '全案设计',
-            deliveryDate: '2023-03-10',
-            clientRating: 5.0,
-            tags: ['商业空间', '工业风'],
-            feedback: '从建模到后期一条龙服务,效率高,质量好,客户非常满意。'
-          }
-        ],
-        performance: [
-          {
-            quarter: '2023-Q1',
-            customerSatisfaction: 92,
-            excellentWorkRate: 85,
-            performanceValue: 88,
-            deductions: [
-              { reason: '项目延期', points: 3, date: '2023-02-15' }
-            ],
-            finalGrade: 'A'
-          },
-          {
-            quarter: '2022-Q4',
-            customerSatisfaction: 88,
-            excellentWorkRate: 80,
-            performanceValue: 85,
-            deductions: [],
-            finalGrade: 'A-'
-          },
-          {
-            quarter: '2022-Q3',
-            customerSatisfaction: 85,
-            excellentWorkRate: 78,
-            performanceValue: 82,
-            deductions: [
-              { reason: '客户投诉', points: 5, date: '2022-08-10' }
-            ],
-            finalGrade: 'B+'
-          }
-        ],
-        // 新增:简历初筛模拟数据(英文枚举)
-        screening: {
-          basic: { age: 30, education: '本科', years: '7年', targetRole: '高级效果图设计师' },
-          core: {
-            projects: '住宅/商业空间等10+项目,擅长现代与新中式风格',
-            certs: '3D效果图高级设计师认证'
-          },
-          intent: { salary: '18k-22k', onboard: '1周内', location: '杭州/远程' },
-          result: { status: 'pass', comment: '技能匹配度高,作品质量稳定,可进入面试环节' }
-        }
-      });
-
-      // 预填编辑表单
-      const scr = this.designer()?.screening?.result;
-      this.screeningForm.patchValue({
-        status: scr?.status ?? 'pending',
-        reason: scr?.reason ?? '',
-        comment: scr?.comment ?? ''
-      });
-
-      this.isLoading.set(false);
-    }, 800);
-  }
-
-  openPortfolioPreview() {
-    this.dialog.open(PortfolioPreviewDialog, {
-      width: '960px',
-      panelClass: 'portfolio-dialog-container'
-    });
-  }
-
-  // 隐私字段脱敏
-  maskIdNumber(id?: string): string {
-    if (!id) return '-';
-    return id.replace(/(\d{4})\d{10}(\d{4})/, '$1**********$2');
-  }
-  maskBankCard(card?: string): string {
-    if (!card) return '-';
-    return card.replace(/(\d{4})\d+(\d{4})/, '$1 **** **** **** $2');
-  }
-  maskPhone(phone?: string): string {
-    if (!phone) return '-';
-    return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
-  }
-
-  getPerformanceTrend(metric: 'customerSatisfaction' | 'excellentWorkRate' | 'performanceValue'): string {
-    if (!this.designer() || this.designer()!.performance.length < 2) {
-      return 'stable';
-    }
-
-    const performance = this.designer()!.performance;
-    const current = performance[0][metric];
-    const previous = performance[1][metric];
-
-    if (current > previous + 3) return 'up';
-    if (current < previous - 3) return 'down';
-    return 'stable';
-  }
-
-  // 性能趋势分析
-  generatePerformanceTrend() {
-    // 模拟生成过去12个月的性能数据
-    const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
-    const data = months.map(month => ({
-      month,
-      score: Math.floor(Math.random() * 30) + 70, // 70-100之间的随机分数
-      projects: Math.floor(Math.random() * 5) + 1, // 1-5之间的随机项目数
-      revenue: Math.floor(Math.random() * 10000) + 5000 // 5000-15000之间的随机收入
-    }));
-    
-    // 确保数据有一定的趋势性,而不是完全随机
-    for (let i = 1; i < data.length; i++) {
-      // 让分数有一定的连续性
-      data[i].score = Math.max(70, Math.min(100, 
-        data[i-1].score + (Math.random() > 0.5 ? 1 : -1) * Math.floor(Math.random() * 5)));
-    }
-    
-    return data;
-  }
-
-  getPerformanceColor(grade: string): string {
-    if (grade.startsWith('A')) return '#52c41a';
-    if (grade.startsWith('B')) return '#1890ff';
-    if (grade.startsWith('C')) return '#faad14';
-    return '#f5222d';
-  }
-
-  changeTab(index: number) {
-    this.activeTab.set(index);
-  }
-
-  getRatingStars(rating: number): string[] {
-    const fullStars = Math.floor(rating);
-    const halfStar = rating % 1 >= 0.5;
-    const emptyStars = 5 - fullStars - (halfStar ? 1 : 0);
-    
-    return [
-      ...Array(fullStars).fill('star'),
-      ...(halfStar ? ['star_half'] : []),
-      ...Array(emptyStars).fill('star_border')
-    ];
-  }
-
-  // 简历初筛相关方法
-  startEditScreening() {
-    this.editingScreening.set(true);
-    const scr = this.designer()?.screening?.result;
-    this.screeningForm.patchValue({
-      status: scr?.status ?? 'pending',
-      reason: scr?.reason ?? '',
-      comment: scr?.comment ?? ''
-    });
-  }
-
-  saveScreening() {
-    const formValue = this.screeningForm.value;
-    const currentDesigner = this.designer();
-    
-    if (currentDesigner) {
-      // 更新设计师数据
-      const updatedDesigner = {
-        ...currentDesigner,
-        screening: {
-          ...currentDesigner.screening,
-          result: {
-            status: formValue.status as 'pass' | 'reject' | 'pending',
-            reason: formValue.reason || '',
-            comment: formValue.comment || ''
-          }
-        }
-      };
-      
-      this.designer.set(updatedDesigner);
-      this.editingScreening.set(false);
-      
-      // 这里可以调用API保存数据
-      console.log('保存简历初筛结果:', formValue);
-    }
-  }
-
-  cancelEditScreening() {
-    this.editingScreening.set(false);
-    // 重置表单到原始值
-    const scr = this.designer()?.screening?.result;
-    this.screeningForm.patchValue({
-      status: scr?.status ?? 'pending',
-      reason: scr?.reason ?? '',
-      comment: scr?.comment ?? ''
-    });
-  }
-
-  getScreeningStatusClass(status?: 'pass' | 'reject' | 'pending'): string {
-    switch (status) {
-      case 'pass': return 'status-pass';
-      case 'reject': return 'status-reject';
-      case 'pending': return 'status-pending';
-      default: return 'status-pending';
-    }
-  }
-
-  getScreeningStatusIcon(status?: 'pass' | 'reject' | 'pending'): string {
-    switch (status) {
-      case 'pass': return 'check_circle';
-      case 'reject': return 'cancel';
-      case 'pending': return 'schedule';
-      default: return 'schedule';
-    }
-  }
-
-  getScreeningStatusText(status?: 'pass' | 'reject' | 'pending'): string {
-    switch (status) {
-      case 'pass': return '通过';
-      case 'reject': return '不通过';
-      case 'pending': return '待定';
-      default: return '待定';
-    }
-  }
-}

+ 0 - 308
src/app/pages/hr/employee-detail/employee-detail.html

@@ -1,308 +0,0 @@
-<div class="employee-detail-container" *ngIf="employee() as emp">
-  <!-- iOS风格导航栏 -->
-  <div class="ios-navbar">
-    <button class="nav-back-btn" (click)="goBack()">
-      <mat-icon>chevron_left</mat-icon>
-      <span>返回</span>
-    </button>
-    <h1 class="nav-title">员工详情</h1>
-    <button class="nav-more-btn" [matMenuTriggerFor]="headerMenu">
-      <mat-icon>more_horiz</mat-icon>
-    </button>
-    <mat-menu #headerMenu="matMenu" class="ios-action-menu">
-      <button mat-menu-item (click)="editEmployee()" class="ios-menu-item">
-        <mat-icon>edit</mat-icon>
-        <span>编辑信息</span>
-      </button>
-      <button mat-menu-item (click)="exportEmployee()" class="ios-menu-item">
-        <mat-icon>file_download</mat-icon>
-        <span>导出档案</span>
-      </button>
-      <mat-divider></mat-divider>
-      <button mat-menu-item (click)="deleteEmployee()" class="ios-menu-item danger">
-        <mat-icon>delete</mat-icon>
-        <span>删除员工</span>
-      </button>
-    </mat-menu>
-  </div>
-
-  <!-- iOS风格员工头像区域 -->
-  <div class="ios-profile-header">
-    <div class="profile-avatar">
-      <img [src]="emp.avatar || 'assets/images/default-avatar.svg'" alt="员工头像" class="avatar-image">
-      <div class="status-dot" [ngClass]="getStatusClass(emp.status)"></div>
-    </div>
-    <h2 class="profile-name">{{emp.name}}</h2>
-    <p class="profile-title">{{emp.position}} · {{emp.department}}</p>
-    <div class="profile-actions">
-      <button class="action-btn call-btn" (click)="callEmployee(emp.phone)">
-        <mat-icon>phone</mat-icon>
-      </button>
-      <button class="action-btn message-btn" (click)="emailEmployee(emp.email)">
-        <mat-icon>email</mat-icon>
-      </button>
-      <button class="action-btn share-btn" (click)="shareEmployee()">
-        <mat-icon>share</mat-icon>
-      </button>
-    </div>
-  </div>
-
-  <!-- iOS风格基础信息列表 -->
-  <div class="ios-section">
-    <div class="section-header">
-      <h3>基础信息</h3>
-    </div>
-    <div class="ios-list">
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">姓名</span>
-          <span class="item-value">{{emp.name}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">年龄</span>
-          <span class="item-value">{{calculateAge(emp.birthDate)}}岁</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">学历</span>
-          <span class="item-value">{{emp.education || '未填写'}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">工作年限</span>
-          <span class="item-value">{{emp.workYears || '未填写'}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">求职岗位</span>
-          <span class="item-value">{{emp.position}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">身份证号</span>
-          <span class="item-value">{{maskIdCard(emp.idCard)}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">银行卡号</span>
-          <span class="item-value">{{maskBankCard(emp.bankCard)}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">手机号码</span>
-          <span class="item-value">{{emp.phone}}</span>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- iOS风格审核初筛列表 -->
-  <div class="ios-section">
-    <div class="section-header">
-      <h3>审核初筛</h3>
-    </div>
-    <div class="ios-list">
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">审核状态</span>
-          <div class="status-badge" [ngClass]="getScreeningStatusClass(emp.screeningStatus)">
-            <mat-icon>{{getScreeningStatusIcon(emp.screeningStatus)}}</mat-icon>
-            <span>{{getScreeningStatusText(emp.screeningStatus)}}</span>
-          </div>
-        </div>
-      </div>
-      @if (emp.screeningComment) {
-        <div class="list-item">
-          <div class="item-content">
-            <span class="item-label">审核备注</span>
-            <span class="item-value">{{emp.screeningComment}}</span>
-          </div>
-        </div>
-      }
-      @if (emp.screeningTime) {
-        <div class="list-item">
-          <div class="item-content">
-            <span class="item-label">审核时间</span>
-            <span class="item-value">{{emp.screeningTime | date:'yyyy-MM-dd HH:mm'}}</span>
-          </div>
-        </div>
-      }
-    </div>
-    
-    @if (emp.screeningStatus === 'pending') {
-      <div class="ios-actions">
-        <button class="ios-btn primary" (click)="approveScreening()">
-          <mat-icon>check_circle</mat-icon>
-          通过初筛
-        </button>
-        <button class="ios-btn secondary" (click)="rejectScreening()">
-          <mat-icon>cancel</mat-icon>
-          不通过
-        </button>
-      </div>
-    }
-  </div>
-
-  <!-- iOS风格联系信息列表 -->
-  <div class="ios-section">
-    <div class="section-header">
-      <h3>联系信息</h3>
-    </div>
-    <div class="ios-list">
-      <div class="list-item clickable" (click)="callEmployee(emp.phone)">
-        <div class="item-icon">
-          <mat-icon>phone</mat-icon>
-        </div>
-        <div class="item-content">
-          <span class="item-label">手机号码</span>
-          <span class="item-value">{{emp.phone}}</span>
-        </div>
-        <div class="item-action">
-          <mat-icon>chevron_right</mat-icon>
-        </div>
-      </div>
-      <div class="list-item clickable" (click)="emailEmployee(emp.email)" [class.disabled]="!emp.email">
-        <div class="item-icon">
-          <mat-icon>email</mat-icon>
-        </div>
-        <div class="item-content">
-          <span class="item-label">邮箱地址</span>
-          <span class="item-value">{{emp.email || '未填写'}}</span>
-        </div>
-        <div class="item-action">
-          <mat-icon>chevron_right</mat-icon>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-icon">
-          <mat-icon>location_on</mat-icon>
-        </div>
-        <div class="item-content">
-          <span class="item-label">家庭住址</span>
-          <span class="item-value">{{emp.address || '未填写'}}</span>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- iOS风格工作信息列表 -->
-  <div class="ios-section">
-    <div class="section-header">
-      <h3>工作信息</h3>
-    </div>
-    <div class="ios-list">
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">所属部门</span>
-          <span class="item-value">{{emp.department}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">职位</span>
-          <span class="item-value">{{emp.position}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">员工状态</span>
-          <div class="status-badge" [ngClass]="getStatusClass(emp.status)">
-            {{emp.status}}
-          </div>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">入职日期</span>
-          <span class="item-value">{{emp.hireDate | date:'yyyy年MM月dd日'}}</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">工作年限</span>
-          <span class="item-value">{{calculateWorkYears(emp.hireDate)}}年</span>
-        </div>
-      </div>
-      <div class="list-item">
-        <div class="item-content">
-          <span class="item-label">直属上级</span>
-          <span class="item-value">{{emp.supervisor || '未指定'}}</span>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- iOS风格底部操作按钮 -->
-  <div class="ios-actions">
-    <button class="ios-action-button primary" (click)="editEmployee()">
-      <mat-icon>edit</mat-icon>
-      <span>编辑员工</span>
-    </button>
-    <button class="ios-action-button" (click)="viewAttendance()">
-      <mat-icon>schedule</mat-icon>
-      <span>考勤记录</span>
-    </button>
-    <button class="ios-action-button" (click)="viewSalary()">
-      <mat-icon>attach_money</mat-icon>
-      <span>薪资记录</span>
-    </button>
-  </div>
-</div>
-
-<!-- iOS风格审核对话框 -->
-<div class="ios-modal" [class.show]="showReviewDialog()">
-  <div class="modal-backdrop" (click)="closeReviewDialog()"></div>
-  <div class="modal-content">
-    <div class="modal-header">
-      <h3>审核员工</h3>
-      <button class="close-button" (click)="closeReviewDialog()">
-        <mat-icon>close</mat-icon>
-      </button>
-    </div>
-    <div class="modal-body">
-      <div class="ios-section">
-        <div class="section-header">
-          <h4>审核结果</h4>
-        </div>
-        <div class="ios-list">
-          <div class="list-item clickable" [class.selected]="reviewResult() === 'approved'" (click)="reviewResult.set('approved')">
-            <div class="item-content">
-              <span class="item-label">通过</span>
-            </div>
-            <div class="item-action" *ngIf="reviewResult() === 'approved'">
-              <mat-icon>check</mat-icon>
-            </div>
-          </div>
-          <div class="list-item clickable" [class.selected]="reviewResult() === 'rejected'" (click)="reviewResult.set('rejected')">
-            <div class="item-content">
-              <span class="item-label">拒绝</span>
-            </div>
-            <div class="item-action" *ngIf="reviewResult() === 'rejected'">
-              <mat-icon>check</mat-icon>
-            </div>
-          </div>
-        </div>
-      </div>
-      <div class="ios-section">
-        <div class="section-header">
-          <h4>审核备注</h4>
-        </div>
-        <div class="ios-textarea">
-          <textarea [ngModel]="reviewComment()" (ngModelChange)="reviewComment.set($event)" rows="4" placeholder="请输入审核意见..."></textarea>
-        </div>
-      </div>
-    </div>
-    <div class="modal-actions">
-      <button class="ios-button secondary" (click)="closeReviewDialog()">取消</button>
-      <button class="ios-button primary" (click)="submitReview()">提交审核</button>
-    </div>
-  </div>
-</div>

+ 0 - 596
src/app/pages/hr/employee-detail/employee-detail.scss

@@ -1,596 +0,0 @@
-// iOS风格员工详情页面样式
-.employee-detail-container {
-  background: #f2f2f7;
-  min-height: 100vh;
-  padding: 0;
-  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
-}
-
-// iOS风格导航栏
-.ios-navbar {
-  background: rgba(248, 248, 248, 0.95);
-  backdrop-filter: blur(20px);
-  -webkit-backdrop-filter: blur(20px);
-  border-bottom: 0.5px solid rgba(0, 0, 0, 0.1);
-  padding: 12px 16px;
-  position: sticky;
-  top: 0;
-  z-index: 100;
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  height: 44px;
-
-  .nav-left {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-
-    .back-button {
-      background: none;
-      border: none;
-      padding: 8px;
-      border-radius: 8px;
-      color: #007AFF;
-      cursor: pointer;
-      transition: background-color 0.2s ease;
-
-      &:hover {
-        background: rgba(0, 122, 255, 0.1);
-      }
-
-      mat-icon {
-        font-size: 20px;
-        width: 20px;
-        height: 20px;
-      }
-    }
-
-    .nav-title {
-      font-size: 17px;
-      font-weight: 600;
-      color: #000;
-      margin: 0;
-    }
-  }
-
-  .nav-right {
-    .more-button {
-      background: none;
-      border: none;
-      padding: 8px;
-      border-radius: 8px;
-      color: #007AFF;
-      cursor: pointer;
-      transition: all 0.2s ease;
-
-      &:hover {
-        background: rgba(0, 122, 255, 0.1);
-      }
-
-      mat-icon {
-        font-size: 20px;
-        width: 20px;
-        height: 20px;
-      }
-    }
-  }
-}
-
-// iOS风格头像区域
-.ios-avatar-section {
-  background: linear-gradient(135deg, #007AFF, #5856D6);
-  padding: 32px 16px;
-  text-align: center;
-  color: white;
-
-  .avatar-container {
-    margin-bottom: 16px;
-
-    .employee-avatar {
-      width: 80px;
-      height: 80px;
-      border-radius: 40px;
-      border: 3px solid rgba(255, 255, 255, 0.3);
-      object-fit: cover;
-    }
-  }
-
-  .employee-name {
-    font-size: 24px;
-    font-weight: 600;
-    margin-bottom: 4px;
-  }
-
-  .employee-position {
-    font-size: 16px;
-    opacity: 0.8;
-    margin-bottom: 20px;
-  }
-
-  .quick-actions {
-    display: flex;
-    justify-content: center;
-    gap: 16px;
-
-    .quick-action {
-      background: rgba(255, 255, 255, 0.2);
-      border: none;
-      border-radius: 20px;
-      padding: 8px 16px;
-      color: white;
-      font-size: 14px;
-      font-weight: 500;
-      cursor: pointer;
-      transition: all 0.2s ease;
-      display: flex;
-      align-items: center;
-      gap: 6px;
-
-      &:hover {
-        background: rgba(255, 255, 255, 0.3);
-        transform: translateY(-1px);
-      }
-
-      mat-icon {
-        font-size: 16px;
-        width: 16px;
-        height: 16px;
-      }
-    }
-  }
-}
-
-// iOS风格分组
-.ios-section {
-  margin: 20px 16px;
-
-  .section-header {
-    padding: 0 16px 8px 16px;
-
-    h3, h4 {
-      font-size: 13px;
-      font-weight: 400;
-      color: #6d6d72;
-      text-transform: uppercase;
-      letter-spacing: 0.5px;
-      margin: 0;
-    }
-  }
-}
-
-// iOS风格列表
-.ios-list {
-  background: white;
-  border-radius: 10px;
-  overflow: hidden;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-
-  .list-item {
-    display: flex;
-    align-items: center;
-    padding: 12px 16px;
-    border-bottom: 0.5px solid rgba(60, 60, 67, 0.1);
-    transition: background-color 0.2s ease;
-
-    &:last-child {
-      border-bottom: none;
-    }
-
-    &.clickable {
-      cursor: pointer;
-
-      &:hover {
-        background: rgba(0, 0, 0, 0.04);
-      }
-
-      &:active {
-        background: rgba(0, 0, 0, 0.08);
-      }
-    }
-
-    &.selected {
-      background: rgba(0, 122, 255, 0.1);
-
-      .item-label {
-        color: #007AFF;
-        font-weight: 500;
-      }
-    }
-
-    &.disabled {
-      opacity: 0.5;
-      cursor: not-allowed;
-
-      &:hover {
-        background: transparent;
-      }
-    }
-
-    .item-icon {
-      margin-right: 12px;
-      color: #007AFF;
-
-      mat-icon {
-        font-size: 20px;
-        width: 20px;
-        height: 20px;
-      }
-    }
-
-    .item-content {
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      gap: 2px;
-
-      .item-label {
-        font-size: 17px;
-        color: #000;
-        font-weight: 400;
-      }
-
-      .item-value {
-        font-size: 17px;
-        color: #8e8e93;
-        margin-left: auto;
-      }
-    }
-
-    .item-action {
-      margin-left: 8px;
-      color: #c7c7cc;
-
-      mat-icon {
-        font-size: 18px;
-        width: 18px;
-        height: 18px;
-      }
-    }
-
-    // 双行布局
-    &.two-line .item-content {
-      .item-label {
-        font-size: 17px;
-        color: #000;
-      }
-
-      .item-value {
-        font-size: 15px;
-        color: #8e8e93;
-        margin-left: 0;
-      }
-    }
-  }
-}
-
-// 状态徽章
-.status-badge {
-  display: inline-flex;
-  align-items: center;
-  padding: 4px 8px;
-  border-radius: 12px;
-  font-size: 12px;
-  font-weight: 600;
-  text-transform: uppercase;
-  letter-spacing: 0.5px;
-
-  &.status-active {
-    background: #34c759;
-    color: white;
-  }
-
-  &.status-probation {
-    background: #ff9500;
-    color: white;
-  }
-
-  &.status-resigned {
-    background: #8e8e93;
-    color: white;
-  }
-
-  &.screening-approved {
-    background: #34c759;
-    color: white;
-  }
-
-  &.screening-rejected {
-    background: #ff3b30;
-    color: white;
-  }
-
-  &.screening-pending {
-    background: #ff9500;
-    color: white;
-  }
-}
-
-// iOS风格操作按钮
-.ios-actions {
-  padding: 20px 16px 32px 16px;
-  display: flex;
-  flex-direction: column;
-  gap: 12px;
-
-  .ios-action-button {
-    background: white;
-    border: none;
-    border-radius: 10px;
-    padding: 16px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: 8px;
-    font-size: 17px;
-    font-weight: 500;
-    color: #007AFF;
-    cursor: pointer;
-    transition: all 0.2s ease;
-    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-
-    &:hover {
-      background: rgba(0, 0, 0, 0.04);
-      transform: translateY(-1px);
-    }
-
-    &:active {
-      background: rgba(0, 0, 0, 0.08);
-      transform: translateY(0);
-    }
-
-    &.primary {
-      background: #007AFF;
-      color: white;
-
-      &:hover {
-        background: #0056b3;
-      }
-    }
-
-    mat-icon {
-      font-size: 20px;
-      width: 20px;
-      height: 20px;
-    }
-  }
-}
-
-// iOS风格文本域
-.ios-textarea {
-  background: white;
-  border-radius: 10px;
-  padding: 12px;
-  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-
-  textarea {
-    width: 100%;
-    border: none;
-    outline: none;
-    font-size: 17px;
-    font-family: inherit;
-    resize: vertical;
-    min-height: 80px;
-    background: transparent;
-
-    &::placeholder {
-      color: #c7c7cc;
-    }
-  }
-}
-
-// iOS风格模态框
-.ios-modal {
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  z-index: 1000;
-  display: flex;
-  align-items: flex-end;
-  opacity: 0;
-  visibility: hidden;
-  transition: all 0.3s ease;
-
-  &.show {
-    opacity: 1;
-    visibility: visible;
-
-    .modal-content {
-      transform: translateY(0);
-    }
-  }
-
-  .modal-backdrop {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    background: rgba(0, 0, 0, 0.4);
-  }
-
-  .modal-content {
-    background: #f2f2f7;
-    border-radius: 20px 20px 0 0;
-    width: 100%;
-    max-height: 80vh;
-    overflow-y: auto;
-    transform: translateY(100%);
-    transition: transform 0.3s ease;
-    position: relative;
-
-    .modal-header {
-      background: white;
-      padding: 16px;
-      border-bottom: 0.5px solid rgba(60, 60, 67, 0.1);
-      display: flex;
-      align-items: center;
-      justify-content: space-between;
-      border-radius: 20px 20px 0 0;
-
-      h3 {
-        font-size: 17px;
-        font-weight: 600;
-        margin: 0;
-        color: #000;
-      }
-
-      .close-button {
-        background: none;
-        border: none;
-        padding: 8px;
-        border-radius: 8px;
-        color: #007AFF;
-        cursor: pointer;
-
-        &:hover {
-          background: rgba(0, 122, 255, 0.1);
-        }
-
-        mat-icon {
-          font-size: 20px;
-          width: 20px;
-          height: 20px;
-        }
-      }
-    }
-
-    .modal-body {
-      padding: 20px 0;
-    }
-
-    .modal-actions {
-      padding: 16px;
-      display: flex;
-      gap: 12px;
-
-      .ios-button {
-        flex: 1;
-        background: white;
-        border: none;
-        border-radius: 10px;
-        padding: 16px;
-        font-size: 17px;
-        font-weight: 500;
-        cursor: pointer;
-        transition: all 0.2s ease;
-
-        &.primary {
-          background: #007AFF;
-          color: white;
-
-          &:hover {
-            background: #0056b3;
-          }
-        }
-
-        &.secondary {
-          color: #007AFF;
-
-          &:hover {
-            background: rgba(0, 0, 0, 0.04);
-          }
-        }
-      }
-    }
-  }
-}
-
-// 三点菜单样式(调整透明度)
-:host ::ng-deep .mat-mdc-menu-panel {
-  background: rgba(255, 255, 255, 0.9) !important;
-  backdrop-filter: blur(20px);
-  -webkit-backdrop-filter: blur(20px);
-  border-radius: 12px !important;
-  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2) !important;
-  border: 0.5px solid rgba(0, 0, 0, 0.1);
-  overflow: hidden;
-}
-
-:host ::ng-deep .mat-mdc-menu-item {
-  padding: 12px 16px !important;
-  font-size: 17px !important;
-  color: #000 !important;
-  transition: background-color 0.2s ease !important;
-
-  &:hover {
-    background: rgba(0, 0, 0, 0.04) !important;
-  }
-
-  .mat-icon {
-    margin-right: 12px !important;
-    color: #007AFF !important;
-    font-size: 20px !important;
-    width: 20px !important;
-    height: 20px !important;
-  }
-
-  &.delete-item {
-    color: #ff3b30 !important;
-
-    .mat-icon {
-      color: #ff3b30 !important;
-    }
-  }
-}
-
-// 响应式设计
-@media (max-width: 768px) {
-  .ios-avatar-section {
-    padding: 24px 16px;
-
-    .employee-name {
-      font-size: 20px;
-    }
-
-    .employee-position {
-      font-size: 14px;
-    }
-
-    .quick-actions {
-      flex-direction: column;
-      align-items: center;
-      gap: 8px;
-
-      .quick-action {
-        width: 100%;
-        max-width: 200px;
-        justify-content: center;
-      }
-    }
-  }
-
-  .ios-section {
-    margin: 16px 12px;
-  }
-
-  .ios-actions {
-    padding: 16px 12px 24px 12px;
-  }
-}
-
-// 动画效果
-@keyframes slideInUp {
-  from {
-    opacity: 0;
-    transform: translateY(20px);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-
-.ios-section {
-  animation: slideInUp 0.4s ease-out;
-
-  &:nth-child(2) { animation-delay: 0.1s; }
-  &:nth-child(3) { animation-delay: 0.2s; }
-  &:nth-child(4) { animation-delay: 0.3s; }
-}
-
-.ios-avatar-section {
-  animation: slideInUp 0.4s ease-out;
-}

+ 0 - 362
src/app/pages/hr/employee-detail/employee-detail.ts

@@ -1,362 +0,0 @@
-import { Component, OnInit, signal, computed, inject } from '@angular/core';
-import { CommonModule, Location } from '@angular/common';
-import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
-import { MatButtonModule } from '@angular/material/button';
-import { MatInputModule } from '@angular/material/input';
-import { MatSelectModule } from '@angular/material/select';
-import { MatDialogModule, MatDialog } from '@angular/material/dialog';
-import { MatCardModule } from '@angular/material/card';
-import { MatIconModule } from '@angular/material/icon';
-import { MatChipsModule } from '@angular/material/chips';
-import { MatTooltipModule } from '@angular/material/tooltip';
-import { MatButtonToggleModule } from '@angular/material/button-toggle';
-import { MatDividerModule } from '@angular/material/divider';
-import { MatMenuModule } from '@angular/material/menu';
-import { MatSnackBar } from '@angular/material/snack-bar';
-import { Router, ActivatedRoute } from '@angular/router';
-import { Employee } from '../../../models/hr.model';
-
-@Component({
-  selector: 'app-employee-detail',
-  standalone: true,
-  imports: [
-    CommonModule,
-    FormsModule,
-    ReactiveFormsModule,
-    MatButtonModule,
-    MatInputModule,
-    MatSelectModule,
-    MatDialogModule,
-    MatCardModule,
-    MatIconModule,
-    MatChipsModule,
-    MatTooltipModule,
-    MatButtonToggleModule,
-    MatDividerModule,
-    MatMenuModule
-  ],
-  templateUrl: './employee-detail.html',
-  styleUrls: ['./employee-detail.scss']
-})
-export class EmployeeDetailComponent implements OnInit {
-  private route = inject(ActivatedRoute);
-  private router = inject(Router);
-  private location = inject(Location);
-  private dialog = inject(MatDialog);
-  private snackBar = inject(MatSnackBar);
-  private fb = inject(FormBuilder);
-
-  employee = signal<Employee | null>(null);
-  screeningForm: FormGroup;
-
-  // 审核弹窗状态(Signals)
-  showReviewDialog = signal(false);
-  reviewComment = signal('');
-  reviewResult = signal<'approved' | 'rejected' | ''>('');
-
-  // 模拟员工数据
-  private mockEmployees: Employee[] = [
-    {
-      id: '1',
-      name: '张三',
-      department: '设计部',
-      position: '设计师',
-      employeeId: 'DS001',
-      phone: '13800138001',
-      email: 'zhangsan@example.com',
-      gender: '男',
-      birthDate: new Date('1990-05-15'),
-      hireDate: new Date('2022-01-15'),
-      status: '在职',
-      avatar: 'assets/images/avatar1.jpg',
-      education: '本科',
-      workYears: '3年',
-      idCard: '110101199005151234',
-      bankCard: '6222021234567890123',
-      address: '北京市朝阳区xxx街道xxx号',
-      supervisor: '李经理',
-      screeningStatus: 'approved',
-      screeningComment: '技能匹配度高,工作经验丰富',
-      screeningTime: new Date('2022-01-10')
-    },
-    {
-      id: '2',
-      name: '李四',
-      department: '客服部',
-      position: '客服专员',
-      employeeId: 'CS001',
-      phone: '13800138002',
-      email: 'lisi@example.com',
-      gender: '女',
-      birthDate: new Date('1992-08-20'),
-      hireDate: new Date('2022-03-10'),
-      status: '在职',
-      education: '大专',
-      workYears: '2年',
-      idCard: '110101199208201234',
-      bankCard: '6222021234567890124',
-      address: '北京市海淀区xxx街道xxx号',
-      supervisor: '王经理',
-      screeningStatus: 'pending',
-      screeningTime: undefined
-    },
-    {
-      id: '3',
-      name: '王五',
-      department: '技术部',
-      position: '前端开发',
-      employeeId: 'FE001',
-      phone: '13800138003',
-      email: 'wangwu@example.com',
-      gender: '男',
-      birthDate: new Date('1988-11-15'),
-      hireDate: new Date('2023-01-05'),
-      status: '试用期',
-      education: '硕士',
-      workYears: '5年',
-      idCard: '110101198811151234',
-      bankCard: '6222021234567890125',
-      address: '北京市西城区xxx街道xxx号',
-      supervisor: '赵总监',
-      screeningStatus: 'rejected',
-      screeningComment: '技术能力需要进一步评估',
-      screeningTime: new Date('2023-01-02')
-    }
-  ];
-
-  constructor() {
-    this.screeningForm = this.fb.group({
-      status: ['', Validators.required],
-      comment: ['']
-    });
-  }
-
-  ngOnInit() {
-    const employeeId = this.route.snapshot.paramMap.get('id');
-    if (employeeId) {
-      this.loadEmployee(employeeId);
-    }
-  }
-
-  private loadEmployee(id: string) {
-    // 模拟从服务加载员工数据
-    const emp = this.mockEmployees.find(e => e.id === id);
-    if (emp) {
-      this.employee.set(emp);
-    } else {
-      this.showSnackBar('员工不存在');
-      this.goBack();
-    }
-  }
-
-  goBack() {
-    this.location.back();
-  }
-
-  calculateAge(birthDate: Date): number {
-    if (!birthDate) return 0;
-    const today = new Date();
-    const birth = new Date(birthDate);
-    let age = today.getFullYear() - birth.getFullYear();
-    const monthDiff = today.getMonth() - birth.getMonth();
-    if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
-      age--;
-    }
-    return age;
-  }
-
-  calculateWorkYears(hireDate: Date): number {
-    if (!hireDate) return 0;
-    const today = new Date();
-    const hire = new Date(hireDate);
-    const diffTime = Math.abs(today.getTime() - hire.getTime());
-    const diffYears = Math.floor(diffTime / (1000 * 60 * 60 * 24 * 365));
-    return diffYears;
-  }
-
-  maskIdCard(idCard: string | undefined): string {
-    if (!idCard) return '未提供';
-    return idCard.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2');
-  }
-
-  maskBankCard(bankCard: string | undefined): string {
-    if (!bankCard) return '未提供';
-    return bankCard.replace(/(\d{4})\d{12}(\d{3})/, '$1 **** **** $2');
-  }
-
-  getStatusClass(status: string): string {
-    switch (status) {
-      case '在职': return 'status-active';
-      case '试用期': return 'status-probation';
-      case '离职': return 'status-resigned';
-      default: return '';
-    }
-  }
-
-  getScreeningStatusClass(status: string | undefined): string {
-    switch (status) {
-      case 'approved': return 'status-approved';
-      case 'rejected': return 'status-rejected';
-      case 'pending': return 'status-pending';
-      default: return 'status-unknown';
-    }
-  }
-
-  getScreeningStatusIcon(status: string | undefined): string {
-    switch (status) {
-      case 'approved': return 'check_circle';
-      case 'rejected': return 'cancel';
-      case 'pending': return 'schedule';
-      default: return 'help';
-    }
-  }
-
-  getScreeningStatusText(status: string | undefined): string {
-    switch (status) {
-      case 'approved': return '初筛通过';
-      case 'rejected': return '初筛不通过';
-      case 'pending': return '待审核';
-      default: return '未知状态';
-    }
-  }
-
-  shareEmployee() {
-    if (navigator.share) {
-      navigator.share({
-        title: `员工档案 - ${this.employee()?.name}`,
-        text: `查看${this.employee()?.name}的员工档案信息`,
-        url: window.location.href
-      });
-    } else {
-      // 复制链接到剪贴板
-      navigator.clipboard.writeText(window.location.href);
-      this.showSnackBar('链接已复制到剪贴板');
-    }
-  }
-
-  editEmployee() {
-    this.showSnackBar('编辑功能开发中...');
-  }
-
-  exportEmployee() {
-    this.showSnackBar('导出功能开发中...');
-  }
-
-  deleteEmployee() {
-    this.showSnackBar('删除功能开发中...');
-  }
-
-  editBasicInfo() {
-    this.showSnackBar('编辑基础信息功能开发中...');
-  }
-
-  editContactInfo() {
-    this.showSnackBar('编辑联系信息功能开发中...');
-  }
-
-  editWorkInfo() {
-    this.showSnackBar('编辑工作信息功能开发中...');
-  }
-
-  callEmployee(phone: string) {
-    if (phone) {
-      window.open(`tel:${phone}`);
-    }
-  }
-
-  emailEmployee(email: string) {
-    if (email) {
-      window.open(`mailto:${email}`);
-    }
-  }
-
-  approveScreening() {
-    // 打开审核弹窗(Signals)
-    this.reviewResult.set('approved');
-    this.reviewComment.set('');
-    this.showReviewDialog.set(true);
-  }
-
-  rejectScreening() {
-    // 打开审核弹窗(Signals)
-    this.reviewResult.set('rejected');
-    this.reviewComment.set('');
-    this.showReviewDialog.set(true);
-  }
-
-  private openScreeningDialog() {
-    // 这里应该打开对话框,简化处理直接提交
-    this.submitScreening();
-  }
-
-  submitScreening() {
-    if (this.screeningForm.valid) {
-      const formValue = this.screeningForm.value;
-      const currentEmployee = this.employee();
-      
-      if (currentEmployee) {
-        const updatedEmployee = {
-          ...currentEmployee,
-          screeningStatus: formValue.status,
-          screeningComment: formValue.comment,
-          screeningTime: new Date()
-        };
-        
-        this.employee.set(updatedEmployee);
-        this.showSnackBar('审核结果已保存');
-        this.screeningForm.reset();
-      }
-    }
-  }
-
-
-  viewAttendance() {
-    this.router.navigate(['/hr/attendance'], { 
-      queryParams: { employee: this.employee()?.id } 
-    });
-  }
-
-  viewSalary() {
-    this.showSnackBar('薪资记录功能开发中...');
-  }
-
-  private showSnackBar(message: string) {
-    this.snackBar.open(message, '关闭', {
-      duration: 3000,
-      horizontalPosition: 'center',
-      verticalPosition: 'top'
-    });
-  }
-
-  // 审核对话框方法(Signals)
-  openReviewDialog() {
-    this.showReviewDialog.set(true);
-    this.reviewComment.set('');
-    this.reviewResult.set('');
-  }
-
-  closeReviewDialog() {
-    this.showReviewDialog.set(false);
-    this.reviewComment.set('');
-    this.reviewResult.set('');
-  }
-
-  submitReview() {
-    const currentEmployee = this.employee();
-    if (!this.reviewResult()) {
-      this.showSnackBar('请选择审核结果');
-      return;
-    }
-    if (currentEmployee) {
-      const updatedEmployee: Employee = {
-        ...currentEmployee,
-        screeningStatus: this.reviewResult(),
-        screeningComment: this.reviewComment(),
-        screeningTime: new Date()
-      } as Employee;
-      this.employee.set(updatedEmployee);
-      this.showSnackBar('审核结果已保存');
-    }
-    this.closeReviewDialog();
-  }
-}

+ 0 - 5
src/app/pages/hr/employee-records/employee-records.ts

@@ -811,11 +811,6 @@ export class EmployeeRecords implements OnInit {
   // 进入员工详情(根据角色跳转至相应详情页)
   goToDetails(employee: Employee) {
     // 目前仅实现设计师角色详情,后续可按职位扩展其它角色
-    const isDesigner = employee.department.includes('设计') || employee.position.includes('设计');
-    if (isDesigner) {
-      this.router.navigate(['/hr/designer-profile', employee.id]);
-      return;
-    }
     this.showSnackBar('该角色详情页正在建设中');
   }
   

+ 1 - 7
src/app/pages/hr/hr-layout/hr-layout.html

@@ -25,13 +25,7 @@
           <span matListItemTitle *ngIf="isExpanded">员工信息管理</span>
         </a>
 
-        <!-- 设计师详情入口已移除:根据需求改为从列表进入,无需单独导航 -->
-        <!--
-        <a mat-list-item routerLink="/hr/designer-profile/1" routerLinkActive="active-link">
-          <mat-icon matListItemIcon>person</mat-icon>
-          <span matListItemTitle *ngIf="isExpanded">设计师详情</span>
-        </a>
-        -->
+
 
         <!-- 考勤统计 -->
         <a mat-list-item routerLink="/hr/attendance" routerLinkActive="active-link">

+ 15 - 0
src/assets/images/portfolio-1.svg

@@ -0,0 +1,15 @@
+<svg width="400" height="300" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <linearGradient id="bg1" x1="0%" y1="0%" x2="100%" y2="100%">
+      <stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
+      <stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
+    </linearGradient>
+  </defs>
+  <rect width="400" height="300" fill="url(#bg1)"/>
+  <rect x="50" y="50" width="300" height="200" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.3)" stroke-width="2" rx="8"/>
+  <circle cx="120" cy="120" r="30" fill="rgba(255,255,255,0.2)"/>
+  <rect x="170" y="100" width="120" height="40" fill="rgba(255,255,255,0.2)" rx="4"/>
+  <rect x="170" y="160" width="80" height="20" fill="rgba(255,255,255,0.15)" rx="2"/>
+  <rect x="170" y="190" width="100" height="20" fill="rgba(255,255,255,0.15)" rx="2"/>
+  <text x="200" y="280" font-family="Arial, sans-serif" font-size="16" fill="white" text-anchor="middle">现代简约风格</text>
+</svg>

+ 16 - 0
src/assets/images/portfolio-2.svg

@@ -0,0 +1,16 @@
+<svg width="400" height="300" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <linearGradient id="bg2" x1="0%" y1="0%" x2="100%" y2="100%">
+      <stop offset="0%" style="stop-color:#f093fb;stop-opacity:1" />
+      <stop offset="100%" style="stop-color:#f5576c;stop-opacity:1" />
+    </linearGradient>
+  </defs>
+  <rect width="400" height="300" fill="url(#bg2)"/>
+  <rect x="60" y="60" width="280" height="180" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.3)" stroke-width="2" rx="8"/>
+  <rect x="80" y="80" width="60" height="60" fill="rgba(255,255,255,0.2)" rx="4"/>
+  <rect x="160" y="80" width="60" height="60" fill="rgba(255,255,255,0.2)" rx="4"/>
+  <rect x="240" y="80" width="60" height="60" fill="rgba(255,255,255,0.2)" rx="4"/>
+  <rect x="80" y="160" width="220" height="30" fill="rgba(255,255,255,0.15)" rx="2"/>
+  <rect x="80" y="200" width="160" height="20" fill="rgba(255,255,255,0.15)" rx="2"/>
+  <text x="200" y="280" font-family="Arial, sans-serif" font-size="16" fill="white" text-anchor="middle">北欧风格</text>
+</svg>

+ 16 - 0
src/assets/images/portfolio-3.svg

@@ -0,0 +1,16 @@
+<svg width="400" height="300" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <linearGradient id="bg3" x1="0%" y1="0%" x2="100%" y2="100%">
+      <stop offset="0%" style="stop-color:#4facfe;stop-opacity:1" />
+      <stop offset="100%" style="stop-color:#00f2fe;stop-opacity:1" />
+    </linearGradient>
+  </defs>
+  <rect width="400" height="300" fill="url(#bg3)"/>
+  <rect x="40" y="40" width="320" height="220" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.3)" stroke-width="2" rx="8"/>
+  <rect x="60" y="60" width="120" height="80" fill="rgba(255,255,255,0.2)" rx="4"/>
+  <rect x="200" y="60" width="140" height="40" fill="rgba(255,255,255,0.2)" rx="4"/>
+  <rect x="200" y="120" width="140" height="20" fill="rgba(255,255,255,0.15)" rx="2"/>
+  <rect x="60" y="160" width="280" height="40" fill="rgba(255,255,255,0.15)" rx="2"/>
+  <rect x="60" y="220" width="200" height="20" fill="rgba(255,255,255,0.15)" rx="2"/>
+  <text x="200" y="280" font-family="Arial, sans-serif" font-size="16" fill="white" text-anchor="middle">新中式风格</text>
+</svg>

+ 16 - 0
src/assets/images/portfolio-4.svg

@@ -0,0 +1,16 @@
+<svg width="400" height="300" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <linearGradient id="bg4" x1="0%" y1="0%" x2="100%" y2="100%">
+      <stop offset="0%" style="stop-color:#43e97b;stop-opacity:1" />
+      <stop offset="100%" style="stop-color:#38f9d7;stop-opacity:1" />
+    </linearGradient>
+  </defs>
+  <rect width="400" height="300" fill="url(#bg4)"/>
+  <rect x="50" y="50" width="300" height="200" fill="rgba(255,255,255,0.1)" stroke="rgba(255,255,255,0.3)" stroke-width="2" rx="8"/>
+  <circle cx="150" cy="130" r="25" fill="rgba(255,255,255,0.2)"/>
+  <circle cx="200" cy="130" r="25" fill="rgba(255,255,255,0.2)"/>
+  <circle cx="250" cy="130" r="25" fill="rgba(255,255,255,0.2)"/>
+  <rect x="100" y="180" width="200" height="30" fill="rgba(255,255,255,0.2)" rx="4"/>
+  <rect x="120" y="220" width="160" height="15" fill="rgba(255,255,255,0.15)" rx="2"/>
+  <text x="200" y="280" font-family="Arial, sans-serif" font-size="16" fill="white" text-anchor="middle">工业风格</text>
+</svg>