Prechádzať zdrojové kódy

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

0235711 1 deň pred
rodič
commit
47b0135b84
24 zmenil súbory, kde vykonal 4928 pridanie a 3703 odobranie
  1. 20 4
      package-lock.json
  2. 2 1
      package.json
  3. 5 3
      src/app/app.routes.ts
  4. 153 0
      src/app/pages/customer-service/case-library/case-detail-panel.component.html
  5. 382 0
      src/app/pages/customer-service/case-library/case-detail-panel.component.scss
  6. 57 0
      src/app/pages/customer-service/case-library/case-detail-panel.component.ts
  7. 300 365
      src/app/pages/customer-service/case-library/case-library.html
  8. 756 1209
      src/app/pages/customer-service/case-library/case-library.scss
  9. 433 398
      src/app/pages/customer-service/case-library/case-library.ts
  10. 155 302
      src/app/pages/customer-service/consultation-order/consultation-order.html
  11. 737 0
      src/app/pages/customer-service/consultation-order/consultation-order.scss
  12. 136 9
      src/app/pages/customer-service/consultation-order/consultation-order.ts
  13. 2 1
      src/app/pages/customer-service/customer-service-layout/customer-service-layout.html
  14. 17 0
      src/app/pages/customer-service/project-list/project-list.html
  15. 38 0
      src/app/pages/customer-service/project-list/project-list.scss
  16. 5 5
      src/app/pages/customer-service/project-list/project-list.ts
  17. 2 2
      src/app/pages/designer/project-detail/project-detail.html
  18. 311 215
      src/app/pages/hr/dashboard/dashboard.html
  19. 803 880
      src/app/pages/hr/dashboard/dashboard.scss
  20. 578 309
      src/app/pages/hr/dashboard/dashboard.ts
  21. 9 0
      src/assets/images/case-1-cover.svg
  22. 9 0
      src/assets/images/case-2-cover.svg
  23. 9 0
      src/assets/images/case-3-cover.svg
  24. 9 0
      src/assets/images/case-4-cover.svg

+ 20 - 4
package-lock.json

@@ -8,7 +8,8 @@
       "name": "yss-project",
       "version": "0.0.0",
       "dependencies": {
-        "@angular/cdk": "^20.2.2",
+        "@angular/animations": "^20.3.1",
+        "@angular/cdk": "^20.2.4",
         "@angular/common": "^20.1.0",
         "@angular/compiler": "^20.1.0",
         "@angular/core": "^20.1.0",
@@ -433,6 +434,21 @@
         "typescript": "*"
       }
     },
+    "node_modules/@angular/animations": {
+      "version": "20.3.1",
+      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.1.tgz",
+      "integrity": "sha512-mexSwaikVE2s+GDhB9fuagEvxbnKHWsqLlO7/R2nY9tTUxBO3drWe3p0D5GxG/EsEyzZU+86ED867q/JmAiVvw==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "engines": {
+        "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+      },
+      "peerDependencies": {
+        "@angular/core": "20.3.1"
+      }
+    },
     "node_modules/@angular/build": {
       "version": "20.2.2",
       "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.2.2.tgz",
@@ -533,9 +549,9 @@
       }
     },
     "node_modules/@angular/cdk": {
-      "version": "20.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.2.tgz",
-      "integrity": "sha512-jLvIMmFI8zoi6vAu1Aszua59GmhqBOtsVfkwLUGg5Hi86DI/inJr9BznNX2EKDtaulYMGZCmDgsltXQXeqP5Lg==",
+      "version": "20.2.4",
+      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.4.tgz",
+      "integrity": "sha512-5UzrN854pnQH+Qw6XZRxx2zWkcOxKrzWPLXe+gHFxFhxWUZfJKGcTJeAj8bnmyb+C3lqBbGpoNQPQ8pFXQGEaQ==",
       "license": "MIT",
       "dependencies": {
         "parse5": "^8.0.0",

+ 2 - 1
package.json

@@ -21,7 +21,8 @@
   },
   "private": true,
   "dependencies": {
-    "@angular/cdk": "^20.2.2",
+    "@angular/animations": "^20.3.1",
+    "@angular/cdk": "^20.2.4",
     "@angular/common": "^20.1.0",
     "@angular/compiler": "^20.1.0",
     "@angular/core": "^20.1.0",

+ 5 - 3
src/app/app.routes.ts

@@ -10,6 +10,7 @@ import { ConsultationOrder } from './pages/customer-service/consultation-order/c
 import { ProjectList } from './pages/customer-service/project-list/project-list';
 import { ProjectDetail } from './pages/customer-service/project-detail/project-detail';
 import { CaseLibrary } from './pages/customer-service/case-library/case-library';
+
 // 客服工作台子页面
 import { ConsultationListComponent } from './pages/customer-service/dashboard/pages/consultation-list/consultation-list.component';
 import { AssignmentListComponent } from './pages/customer-service/dashboard/pages/assignment-list/assignment-list.component';
@@ -66,6 +67,7 @@ export const routes: Routes = [
       { path: 'project-list', component: ProjectList, title: '项目列表' },
       { path: 'project-detail/:id', component: DesignerProjectDetail, title: '项目详情' },
       { path: 'case-library', component: CaseLibrary, title: '案例库' },
+
       // 工作台子页面路由
       { path: 'consultation-list', component: ConsultationListComponent, title: '咨询列表' },
       { path: 'assignment-list', component: AssignmentListComponent, title: '待派单列表' },
@@ -117,10 +119,10 @@ export const routes: Routes = [
     path: 'hr',
     component: HrLayout,
     children: [
-      { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
       { path: 'dashboard', component: HrDashboard, title: '人事看板' },
-      { path: 'employee-records', component: EmployeeRecords, title: '花名册与档案库' },
-      { path: 'attendance', component: Attendance, title: '考勤统计' }
+      { path: 'employee-records', component: EmployeeRecords, title: '员工档案' },
+      { path: 'attendance', component: Attendance, title: '考勤管理' },
+      { path: '', redirectTo: 'dashboard', pathMatch: 'full' }
     ]
   },
 

+ 153 - 0
src/app/pages/customer-service/case-library/case-detail-panel.component.html

@@ -0,0 +1,153 @@
+<div class="case-detail-panel">
+  <!-- 头部 -->
+  <div class="panel-header">
+    <h2 class="panel-title">案例详情</h2>
+    <button class="close-btn" (click)="closePanel()">
+      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+        <line x1="18" y1="6" x2="6" y2="18"></line>
+        <line x1="6" y1="6" x2="18" y2="18"></line>
+      </svg>
+    </button>
+  </div>
+
+  <!-- 内容区域 -->
+  <div class="panel-content">
+    <!-- 封面图片 -->
+    <div class="cover-image">
+      <img [src]="case.coverImage" [alt]="case.name" class="cover-img">
+      <div class="image-overlay">
+        <div class="case-badges">
+          <span class="badge project-type">{{ case.projectType }}</span>
+          <span class="badge space-type">{{ case.spaceType }}</span>
+          <span class="badge rendering-level">{{ case.renderingLevel }}</span>
+        </div>
+      </div>
+    </div>
+
+    <!-- 基本信息 -->
+    <div class="basic-info">
+      <h1 class="case-name">{{ case.name }}</h1>
+      
+      <div class="meta-grid">
+        <div class="meta-item">
+          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+            <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
+            <circle cx="12" cy="7" r="4"></circle>
+          </svg>
+          <div class="meta-content">
+            <span class="meta-label">设计师</span>
+            <span class="meta-value">{{ case.designer }}</span>
+            @if (isInternalUser) {
+              <span class="team-badge">{{ case.team }}</span>
+            }
+          </div>
+        </div>
+
+        <div class="meta-item">
+          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+            <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
+            <line x1="3" y1="9" x2="21" y2="9"></line>
+          </svg>
+          <div class="meta-content">
+            <span class="meta-label">面积</span>
+            <span class="meta-value">{{ case.area }}㎡</span>
+          </div>
+        </div>
+
+        <div class="meta-item">
+          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+            <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
+            <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
+          </svg>
+          <div class="meta-content">
+            <span class="meta-label">浏览量</span>
+            <span class="meta-value">{{ case.viewCount }}</span>
+          </div>
+        </div>
+
+        <div class="meta-item">
+          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+            <circle cx="12" cy="12" r="10"></circle>
+            <polyline points="12 6 12 12 16 14"></polyline>
+          </svg>
+          <div class="meta-content">
+            <span class="meta-label">创建时间</span>
+            <span class="meta-value">{{ getFormattedDate(case.createdAt) }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 风格标签 -->
+    <div class="style-section">
+      <h3 class="section-title">设计风格</h3>
+      <div class="style-tags">
+        @for (tag of case.styleTags; track $index) {
+          <span class="style-tag">{{ tag }}</span>
+        }
+      </div>
+    </div>
+
+    <!-- 客户评价 -->
+    @if (case.customerReview) {
+      <div class="review-section">
+        <h3 class="section-title">客户评价</h3>
+        <div class="review-content">
+          <div class="quote-icon">"</div>
+          <p class="review-text">{{ case.customerReview }}</p>
+        </div>
+      </div>
+    }
+
+    <!-- 设计师内部信息 -->
+    @if (isInternalUser) {
+      <div class="internal-section">
+        <h3 class="section-title">内部信息</h3>
+        <div class="internal-grid">
+          <div class="internal-item">
+            <span class="internal-label">案例等级</span>
+            <span class="internal-badge" [class.excellent]="case.isExcellent">
+              {{ case.isExcellent ? '优秀案例' : '普通案例' }}
+            </span>
+          </div>
+          <div class="internal-item">
+            <span class="internal-label">分享次数</span>
+            <span class="internal-value">{{ case.shareCount }}</span>
+          </div>
+          <div class="internal-item">
+            <span class="internal-label">收藏次数</span>
+            <span class="internal-value">{{ case.favoriteCount }}</span>
+          </div>
+        </div>
+      </div>
+    }
+  </div>
+
+  <!-- 底部操作栏 -->
+  <div class="panel-footer">
+    <button 
+      class="btn btn-secondary" 
+      (click)="onShare()"
+    >
+      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+        <circle cx="18" cy="5" r="3"></circle>
+        <circle cx="6" cy="12" r="3"></circle>
+        <circle cx="18" cy="19" r="3"></circle>
+        <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
+        <line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
+      </svg>
+      分享案例
+    </button>
+    
+    <button 
+      class="btn btn-primary" 
+      [class.active]="case.isFavorite"
+      (click)="onToggleFavorite()"
+    >
+      <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
+        <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
+      </svg>
+      {{ case.isFavorite ? '已收藏' : '收藏案例' }}
+    </button>
+  </div>
+</div>

+ 382 - 0
src/app/pages/customer-service/case-library/case-detail-panel.component.scss

@@ -0,0 +1,382 @@
+/* iOS风格案例详情面板样式 */
+
+.case-detail-panel {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  width: 400px;
+  background: #ffffff;
+  box-shadow: -2px 0 20px rgba(0, 0, 0, 0.15);
+  z-index: 1000;
+  display: flex;
+  flex-direction: column;
+  border-left: 1px solid #e5e5e7;
+  
+  /* iOS风格滚动 */
+  overflow-y: auto;
+  -webkit-overflow-scrolling: touch;
+  scrollbar-width: none;
+  &::-webkit-scrollbar {
+    display: none;
+  }
+}
+
+/* 面板头部 */
+.panel-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20px 24px;
+  background: #f5f5f7;
+  border-bottom: 1px solid #e5e5e7;
+  position: sticky;
+  top: 0;
+  z-index: 10;
+  
+  .panel-title {
+    font-size: 20px;
+    font-weight: 600;
+    color: #1d1d1f;
+    margin: 0;
+  }
+  
+  .close-btn {
+    background: none;
+    border: none;
+    padding: 8px;
+    border-radius: 50%;
+    cursor: pointer;
+    color: #86868b;
+    transition: all 0.2s ease;
+    
+    &:hover {
+      background: rgba(0, 0, 0, 0.1);
+      color: #1d1d1f;
+    }
+    
+    &:active {
+      transform: scale(0.95);
+    }
+  }
+}
+
+/* 面板内容 */
+.panel-content {
+  flex: 1;
+  padding: 0;
+  overflow-y: auto;
+}
+
+/* 封面图片 */
+.cover-image {
+  position: relative;
+  height: 250px;
+  overflow: hidden;
+  
+  .cover-img {
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+  }
+  
+  .image-overlay {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    padding: 16px;
+    background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
+    
+    .case-badges {
+      display: flex;
+      gap: 8px;
+      flex-wrap: wrap;
+      
+      .badge {
+        padding: 6px 12px;
+        border-radius: 16px;
+        font-size: 12px;
+        font-weight: 500;
+        color: white;
+        background: rgba(255, 255, 255, 0.2);
+        backdrop-filter: blur(10px);
+        border: 1px solid rgba(255, 255, 255, 0.3);
+      }
+    }
+  }
+}
+
+/* 基本信息 */
+.basic-info {
+  padding: 24px;
+  border-bottom: 1px solid #f2f2f7;
+  
+  .case-name {
+    font-size: 24px;
+    font-weight: 600;
+    color: #1d1d1f;
+    margin: 0 0 20px 0;
+    line-height: 1.3;
+  }
+  
+  .meta-grid {
+    display: grid;
+    grid-template-columns: 1fr 1fr;
+    gap: 16px;
+    
+    .meta-item {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+      
+      svg {
+        color: #86868b;
+        flex-shrink: 0;
+      }
+      
+      .meta-content {
+        display: flex;
+        flex-direction: column;
+        gap: 2px;
+        
+        .meta-label {
+          font-size: 12px;
+          color: #86868b;
+          font-weight: 400;
+        }
+        
+        .meta-value {
+          font-size: 14px;
+          color: #1d1d1f;
+          font-weight: 500;
+        }
+        
+        .team-badge {
+          font-size: 11px;
+          color: #007aff;
+          background: rgba(0, 122, 255, 0.1);
+          padding: 2px 6px;
+          border-radius: 4px;
+          margin-top: 2px;
+        }
+      }
+    }
+  }
+}
+
+/* 分区标题 */
+.section-title {
+  font-size: 18px;
+  font-weight: 600;
+  color: #1d1d1f;
+  margin: 0 0 16px 0;
+  padding: 0 24px;
+}
+
+/* 风格标签 */
+.style-section {
+  padding: 24px 24px 0 24px;
+  
+  .style-tags {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+    
+    .style-tag {
+      padding: 8px 16px;
+      background: #f2f2f7;
+      border-radius: 20px;
+      font-size: 14px;
+      color: #1d1d1f;
+      font-weight: 500;
+      border: 1px solid #e5e5e7;
+    }
+  }
+}
+
+/* 客户评价 */
+.review-section {
+  padding: 24px;
+  border-top: 1px solid #f2f2f7;
+  
+  .review-content {
+    position: relative;
+    
+    .quote-icon {
+      position: absolute;
+      top: -8px;
+      left: -12px;
+      font-size: 48px;
+      color: #f2f2f7;
+      font-weight: 600;
+      line-height: 1;
+    }
+    
+    .review-text {
+      font-size: 16px;
+      line-height: 1.6;
+      color: #1d1d1f;
+      margin: 0;
+      font-style: italic;
+      position: relative;
+      z-index: 1;
+    }
+  }
+}
+
+/* 内部信息 */
+.internal-section {
+  padding: 24px;
+  background: #f5f5f7;
+  border-radius: 12px;
+  margin: 24px;
+  
+  .internal-grid {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
+    gap: 16px;
+    
+    .internal-item {
+      display: flex;
+      flex-direction: column;
+      gap: 4px;
+      
+      .internal-label {
+        font-size: 12px;
+        color: #86868b;
+        font-weight: 400;
+      }
+      
+      .internal-value {
+        font-size: 16px;
+        color: #1d1d1f;
+        font-weight: 600;
+      }
+      
+      .internal-badge {
+        padding: 4px 8px;
+        border-radius: 6px;
+        font-size: 12px;
+        font-weight: 500;
+        color: white;
+        background: #34c759;
+        
+        &.excellent {
+          background: #ff9500;
+        }
+      }
+    }
+  }
+}
+
+/* 面板底部 */
+.panel-footer {
+  padding: 20px 24px;
+  background: #ffffff;
+  border-top: 1px solid #e5e5e7;
+  display: flex;
+  gap: 12px;
+  position: sticky;
+  bottom: 0;
+  z-index: 10;
+  
+  .btn {
+    flex: 1;
+    padding: 14px 20px;
+    border-radius: 12px;
+    font-size: 16px;
+    font-weight: 500;
+    border: none;
+    cursor: pointer;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 8px;
+    transition: all 0.2s ease;
+    
+    &:active {
+      transform: scale(0.98);
+    }
+    
+    &.btn-secondary {
+      background: #f2f2f7;
+      color: #1d1d1f;
+      
+      &:hover {
+        background: #e5e5e7;
+      }
+    }
+    
+    &.btn-primary {
+      background: #007aff;
+      color: white;
+      
+      &:hover {
+        background: #0051a8;
+      }
+      
+      &.active {
+        background: #34c759;
+        
+        &:hover {
+          background: #248a3d;
+        }
+      }
+    }
+  }
+}
+
+/* 响应式设计 */
+@media (max-width: 480px) {
+  .case-detail-panel {
+    width: 100%;
+    right: 0;
+    left: 0;
+    border-left: none;
+    border-right: none;
+  }
+  
+  .basic-info {
+    .meta-grid {
+      grid-template-columns: 1fr;
+    }
+  }
+  
+  .internal-section {
+    .internal-grid {
+      grid-template-columns: 1fr;
+    }
+  }
+}
+
+/* iOS风格动画 */
+@keyframes slideInRight {
+  from {
+    transform: translateX(100%);
+    opacity: 0;
+  }
+  to {
+    transform: translateX(0);
+    opacity: 1;
+  }
+}
+
+@keyframes slideOutRight {
+  from {
+    transform: translateX(0);
+    opacity: 1;
+  }
+  to {
+    transform: translateX(100%);
+    opacity: 0;
+  }
+}
+
+.case-detail-panel {
+  animation: slideInRight 0.3s ease-out;
+  
+  &.closing {
+    animation: slideOutRight 0.3s ease-in;
+  }
+}

+ 57 - 0
src/app/pages/customer-service/case-library/case-detail-panel.component.ts

@@ -0,0 +1,57 @@
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+interface Case {
+  id: string;
+  name: string;
+  coverImage: string;
+  projectType: '工装' | '家装';
+  spaceType: '平层' | '复式' | '别墅' | '自建房';
+  renderingLevel: '高端' | '中端' | '低端';
+  designer: string;
+  team: string;
+  area: number;
+  styleTags: string[];
+  customerReview?: string;
+  viewCount: number;
+  shareCount: number;
+  favoriteCount: number;
+  isFavorite: boolean;
+  isExcellent: boolean;
+  createdAt: Date;
+}
+
+@Component({
+  selector: 'app-case-detail-panel',
+  standalone: true,
+  imports: [CommonModule],
+  templateUrl: './case-detail-panel.component.html',
+  styleUrls: ['./case-detail-panel.component.scss']
+})
+export class CaseDetailPanelComponent {
+  @Input() case!: Case;
+  @Input() isInternalUser: boolean = false;
+  @Output() close = new EventEmitter<void>();
+  @Output() toggleFavorite = new EventEmitter<Case>();
+  @Output() share = new EventEmitter<Case>();
+
+  closePanel() {
+    this.close.emit();
+  }
+
+  onToggleFavorite() {
+    this.toggleFavorite.emit(this.case);
+  }
+
+  onShare() {
+    this.share.emit(this.case);
+  }
+
+  getFormattedDate(date: Date): string {
+    return new Intl.DateTimeFormat('zh-CN', {
+      year: 'numeric',
+      month: 'long',
+      day: 'numeric'
+    }).format(new Date(date));
+  }
+}

+ 300 - 365
src/app/pages/customer-service/case-library/case-library.html

@@ -1,400 +1,335 @@
 <div class="case-library-container">
-  <!-- 中间内容区 -->
-  <div class="content-wrapper">
-      <!-- 欢迎区域 -->
-      <section class="welcome-section">
-        <h2>案例库</h2>
-        <p>今天是 {{ currentDate.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' }) }},为客户提供最佳的设计参考</p>
-      </section>
-
-      <!-- 筛选区域(固定在顶部) -->
-      <section class="filter-section">
-        <div class="filter-header">
-          <button class="filter-toggle-btn" (click)="toggleFilterPanel()">
-            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-              <line x1="4" y1="10" x2="20" y2="10"></line>
-              <line x1="4" y1="14" x2="20" y2="14"></line>
-              <line x1="4" y1="18" x2="13" y2="18"></line>
-            </svg>
-            <span>高级筛选</span>
-          </button>
-          <button class="reset-filter-btn" (click)="resetFilters()">
-            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-              <polyline points="23 4 23 10 17 10"></polyline>
-              <polyline points="1 20 1 14 7 14"></polyline>
-              <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
-            </svg>
-            <span>重置筛选</span>
-          </button>
-        </div>
+  <!-- 页面头部 -->
+  <div class="page-header">
+    <h1>案例库</h1>
+    <div class="header-actions">
+      <button class="btn btn-primary" (click)="showStatistics()">
+        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <path d="M3 3v18h18"></path>
+          <path d="m19 9-5 5-4-4-3 3"></path>
+        </svg>
+        数据统计
+      </button>
+    </div>
+  </div>
 
-        <!-- 高级筛选面板 -->
-        <div class="filter-panel" [class.show]="showFilterPanel()">
-          <form [formGroup]="filterForm" class="filter-form">
-            <!-- 第一行:主要筛选项 -->
-            <div class="filter-row primary-filters">
-              <div class="filter-group">
-                <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>
-                  @for (type of houseTypeOptions; track type) {
-                    <option [value]="type">{{ type }}</option>
-                  }
-                </select>
-              </div>
-              
-              <div class="filter-group">
-                <label>价格范围</label>
-                <select formControlName="price">
-                  <option value="">全部价格</option>
-                  @for (price of priceOptions; track price) {
-                    <option [value]="price">{{ price }}</option>
-                  }
-                </select>
-              </div>
-              
-              <div class="filter-group">
-                <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>
+  <!-- 统计模块 -->
+  @if (showStatsPanel) {
+    <div class="stats-panel">
+      <div class="stats-grid">
+        <div class="stat-card">
+          <h3>Top5 分享案例</h3>
+          <div class="stat-list">
+            @for (item of topSharedCases; track item.id) {
+              <div class="stat-item">
+                <span class="case-name">{{ item.name }}</span>
+                <span class="stat-value">{{ item.shareCount }} 次分享</span>
               </div>
-            </div>
-            
-            <!-- 第三行:高级筛选 -->
-            <div class="filter-row advanced-filters">
-              <div class="filter-group">
-                <label>子类型</label>
-                <select formControlName="subType">
-                  <option value="">全部子类型</option>
-                  @for (subType of subTypeOptions; track subType) {
-                    <option [value]="subType">{{ subType }}</option>
-                  }
-                </select>
-              </div>
-              
-              <div class="filter-group">
-                <label>渲染级别</label>
-                <select formControlName="renderingLevel">
-                  <option value="">全部级别</option>
-                  @for (level of renderingLevelOptions; track level) {
-                    <option [value]="level">{{ level }}</option>
-                  }
-                </select>
-              </div>
-              
-              <div class="filter-group checkbox-group">
-                <label class="favorite-checkbox">
-                  <input type="checkbox" formControlName="favorite" />
-                  <span class="checkbox-text">只看收藏</span>
-                </label>
-              </div>
-            </div>
-          </form>
-        </div>
-      </section>
-
-      <!-- 案例展示区域 -->
-      <section class="cases-section">
-        <div class="section-header">
-          <h3>精选案例 <span class="cases-count">({{ filteredCases().length }})</span></h3>
+            }
+          </div>
         </div>
         
-        <!-- 案例网格(瀑布流布局) -->
-        <div class="cases-grid">
-          <div *ngIf="filteredCases().length === 0" class="empty-state">
-            <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-              <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
-              <circle cx="8.5" cy="8.5" r="1.5"></circle>
-              <polyline points="21 15 16 10 5 21"></polyline>
-            </svg>
-            <p>未找到符合条件的案例</p>
-            <button class="btn-reset" (click)="resetFilters()">重置筛选条件</button>
-          </div>
-          
-          <div *ngFor="let caseItem of paginatedCases()" class="case-card" (click)="viewCaseDetails(caseItem)">
-            <div class="case-image-container">
-              <img [src]="caseItem.coverImage" [alt]="caseItem.name" class="case-image">
-              <div class="case-overlay">
-                <button class="favorite-btn" (click)="$event.stopPropagation(); toggleFavorite(caseItem.id)">
-                  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-                    <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
-                  </svg>
-                  <span *ngIf="caseItem.isFavorite">已收藏</span>
-                  <span *ngIf="!caseItem.isFavorite">收藏</span>
-                </button>
-                <button class="share-btn" (click)="$event.stopPropagation(); shareCase(caseItem.id)">
-                  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-                    <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"></path>
-                    <polyline points="16 6 12 2 8 6"></polyline>
-                    <line x1="12" y1="2" x2="12" y2="15"></line>
-                  </svg>
-                  <span>分享</span>
-                </button>
+        <div class="stat-card">
+          <h3>客户最喜欢案例风格</h3>
+          <div class="stat-list">
+            @for (item of favoriteStyles; track item.style) {
+              <div class="stat-item">
+                <span class="style-name">{{ item.style }}</span>
+                <span class="stat-value">{{ item.count }} 次收藏</span>
               </div>
-            </div>
-            
-            <div class="case-info">
-              <h4 class="case-name">{{ caseItem.name }}</h4>
-              
-              <div class="case-meta">
-                <div class="meta-item">
-                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-                    <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
-                    <circle cx="12" cy="7" r="4"></circle>
-                  </svg>
-                  <span>{{ caseItem.designer }}</span>
-                </div>
-                <div class="meta-item">
-                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-                    <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
-                  </svg>
-                  <span>{{ caseItem.area }}㎡</span>
-                </div>
-                <div class="meta-item">
-                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-                    <path d="M14 10h4.764a2 2 0 0 1 1.789 2.894l-3.5 7A2 2 0 0 1 15.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 0 0-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2h2.5"></path>
-                  </svg>
-                  <span>{{ caseItem.views }}浏览</span>
-                </div>
-              </div>
-              
-              <div class="case-tags">
-                <span *ngFor="let tag of caseItem.tags" class="tag">{{ tag }}</span>
-              </div>
-            </div>
+            }
           </div>
         </div>
         
-        <!-- 分页控件 -->
-        <div class="pagination" *ngIf="totalPages() > 1">
-          <button class="page-btn" (click)="prevPage()" [disabled]="currentPage() === 1">
-            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-              <polyline points="15 18 9 12 15 6"></polyline>
-            </svg>
-          </button>
-          
-          <ng-container *ngFor="let page of pageNumbers()">
-            <button 
-              *ngIf="page !== -1; else ellipsis"
-              class="page-btn"
-              [class.active]="page === currentPage()"
-              (click)="goToPage(page)"
-            >
-              {{ page }}
-            </button>
-            <ng-template #ellipsis>
-              <div class="pagination-ellipsis">...</div>
-            </ng-template>
-          </ng-container>
-          
-          <button class="page-btn" (click)="nextPage()" [disabled]="currentPage() === totalPages()">
-            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-              <polyline points="9 18 15 12 9 6"></polyline>
-            </svg>
-          </button>
+        <div class="stat-card">
+          <h3>设计师作品推荐率</h3>
+          <div class="stat-list">
+            @for (item of designerRecommendations; track item.designer) {
+              <div class="stat-item">
+                <span class="designer-name">{{ item.designer }}</span>
+                <span class="stat-value">{{ item.rate }}% 推荐率</span>
+              </div>
+            }
+          </div>
         </div>
-      </section>
+      </div>
     </div>
+  }
 
-  <!-- 案例详情模态框 -->
-  <div class="case-modal" *ngIf="selectedCase()" (click)="closeCaseDetails()">
-    <div class="modal-content" (click)="$event.stopPropagation()">
-      <button class="close-btn" (click)="closeCaseDetails()">
-        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-          <line x1="18" y1="6" x2="6" y2="18"></line>
-          <line x1="6" y1="6" x2="18" y2="18"></line>
+  <!-- 筛选栏 -->
+  <div class="filter-bar">
+    <div class="filter-group">
+      <div class="search-box">
+        <input 
+          type="text" 
+          placeholder="搜索案例名称、设计师或关键词..."
+          [formControl]="searchControl"
+          class="search-input"
+        >
+        <svg class="search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <circle cx="11" cy="11" r="8"></circle>
+          <path d="m21 21-4.3-4.3"></path>
         </svg>
-      </button>
-      
-      <div class="case-detail-header">
-        <h2>{{ selectedCase()?.name }}</h2>
-        <div class="case-detail-meta">
-          <span>{{ selectedCase()?.designer }}</span>
-          <span>{{ selectedCase()?.area }}㎡</span>
-          <span>{{ formatDate(selectedCase()?.createdAt!) }}</span>
-        </div>
       </div>
-      
-      <!-- 案例图片轮播 -->
-      <div class="case-image-gallery">
-        <div class="main-image">
-          <img [src]="selectedCase()?.coverImage" [alt]="selectedCase()?.name">
-        </div>
-        <div class="thumbnails">
+    </div>
+
+    <div class="filter-group">
+      <select [formControl]="projectTypeControl" class="filter-select">
+        <option value="">项目类型</option>
+        <option value="工装">工装</option>
+        <option value="家装">家装</option>
+      </select>
+
+      <select [formControl]="spaceTypeControl" class="filter-select">
+        <option value="">空间类型</option>
+        <option value="平层">平层</option>
+        <option value="复式">复式</option>
+        <option value="别墅">别墅</option>
+        <option value="自建房">自建房</option>
+      </select>
+
+      <select [formControl]="renderingLevelControl" class="filter-select">
+        <option value="">渲染水平</option>
+        <option value="高端">高端</option>
+        <option value="中端">中端</option>
+        <option value="低端">低端</option>
+      </select>
+
+      <select [formControl]="styleControl" class="filter-select">
+        <option value="">设计风格</option>
+        <option value="现代">现代</option>
+        <option value="中式">中式</option>
+        <option value="欧式">欧式</option>
+        <option value="美式">美式</option>
+        <option value="日式">日式</option>
+        <option value="工业风">工业风</option>
+        <option value="极简风">极简风</option>
+        <option value="轻奢风">轻奢风</option>
+      </select>
+
+      <select [formControl]="areaRangeControl" class="filter-select">
+        <option value="">面积范围</option>
+        <option value="0-50">50㎡以下</option>
+        <option value="50-100">50-100㎡</option>
+        <option value="100-150">100-150㎡</option>
+        <option value="150-200">150-200㎡</option>
+        <option value="200+">200㎡以上</option>
+      </select>
+    </div>
+
+    <div class="filter-actions">
+      <button class="btn btn-secondary" (click)="resetFilters()">
+        重置筛选
+      </button>
+      <button class="btn btn-primary" (click)="applyFilters()">
+        应用筛选
+      </button>
+    </div>
+  </div>
+
+  <!-- 案例网格 -->
+  <div class="cases-grid">
+    @for (caseItem of paginatedCases; track caseItem.id) {
+      <div class="case-card">
+        <!-- 图片容器 -->
+        <div class="case-image-container">
           <img 
-            *ngFor="let image of selectedCase()?.detailImages"
-            [src]="image"
-            [alt]="selectedCase()?.name"
-            class="thumbnail"
+            [src]="caseItem.coverImage" 
+            [alt]="caseItem.name"
+            class="case-image"
+            (click)="viewCaseDetail(caseItem)"
           >
-        </div>
-      </div>
-      
-      <!-- 案例详情信息 -->
-      <div class="case-detail-info">
-        <div class="info-section">
-          <h3>案例详情</h3>
-          <p>{{ selectedCase()?.description }}</p>
-          <p>本案例采用了{{ selectedCase()?.style }}风格设计,为{{ selectedCase()?.houseType }}户型,面积{{ selectedCase()?.area }}平方米。设计师{{ selectedCase()?.designer }}根据客户需求,融合了现代美学与实用功能,打造了舒适且富有个性的居住空间。</p>
-        </div>
-        
-        <div class="info-section">
-          <h3>基本信息</h3>
-          <div class="info-grid">
-            <div class="info-item">
-              <label>风格</label>
-              <span>{{ getSelectedCaseStyle() }}</span>
-            </div>
-            <div class="info-item">
-              <label>户型</label>
-              <span>{{ selectedCase()?.houseType }}</span>
-            </div>
-            <div class="info-item">
-              <label>楼盘</label>
-              <span>{{ selectedCase()?.property }}</span>
-            </div>
-            <div class="info-item">
-              <label>面积</label>
-              <span>{{ selectedCase()?.area }}㎡</span>
-            </div>
-            <div class="info-item">
-              <label>分类</label>
-              <span>{{ selectedCase()?.category }}</span>
-            </div>
-            <div class="info-item">
-              <label>项目类型</label>
-              <span>{{ selectedCase()?.projectType }}</span>
-            </div>
-            <div class="info-item">
-              <label>细分类型</label>
-              <span>{{ selectedCase()?.subType }}</span>
-            </div>
-            <div class="info-item">
-              <label>渲染水平</label>
-              <span>{{ selectedCase()?.renderingLevel }}</span>
-            </div>
-            <div class="info-item">
-              <label>浏览次数</label>
-              <span>{{ selectedCase()?.views }}</span>
+          
+          <!-- 图片覆盖层 -->
+          <div class="image-overlay">
+            <div class="case-badges">
+              <span class="badge project-type">{{ caseItem.projectType }}</span>
+              <span class="badge space-type">{{ caseItem.spaceType }}</span>
+              <span class="badge rendering-level">{{ caseItem.renderingLevel }}</span>
             </div>
-            <div class="info-item">
-              <label>收藏次数</label>
-              <span>{{ selectedCase()?.favoriteCount }}</span>
+            
+            <div class="action-buttons">
+              <button 
+                class="btn-icon favorite-btn" 
+                [class.active]="caseItem.isFavorite"
+                (click)="toggleFavorite(caseItem)"
+              >
+                <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
+                  <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
+                </svg>
+              </button>
+              
+              <button class="btn-icon share-btn" (click)="shareCase(caseItem)">
+                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+                  <circle cx="18" cy="5" r="3"></circle>
+                  <circle cx="6" cy="12" r="3"></circle>
+                  <circle cx="18" cy="19" r="3"></circle>
+                  <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
+                  <line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
+                </svg>
+              </button>
             </div>
-            <div class="info-item">
-              <label>喜欢次数</label>
-              <span>{{ selectedCase()?.likeCount }}</span>
+          </div>
+        </div>
+
+        <!-- 案例信息 -->
+        <div class="case-info">
+          <div class="case-header">
+            <h3 class="case-name" (click)="viewCaseDetail(caseItem)">{{ caseItem.name }}</h3>
+            <button class="info-share-btn" (click)="shareCase(caseItem)" title="分享案例">
+              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+                <circle cx="18" cy="5" r="3"></circle>
+                <circle cx="6" cy="12" r="3"></circle>
+                <circle cx="18" cy="19" r="3"></circle>
+                <line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
+                <line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
+              </svg>
+            </button>
+          </div>
+          
+          <div class="case-meta">
+            <div class="meta-item">
+              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+                <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
+                <circle cx="12" cy="7" r="4"></circle>
+              </svg>
+              <span>{{ caseItem.designer }}</span>
+              @if (isInternalUser) {
+                <span class="team-badge">{{ caseItem.team }}</span>
+              }
             </div>
-            <div class="info-item">
-              <label>分享次数</label>
-              <span>{{ selectedCase()?.shareCount }}</span>
+            
+            <div class="meta-item">
+              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+                <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
+                <line x1="3" y1="9" x2="21" y2="9"></line>
+              </svg>
+              <span>{{ caseItem.area }}㎡</span>
             </div>
-            <div class="info-item">
-              <label>转化率</label>
-              <span>{{ selectedCase()?.conversionRate }}%</span>
+            
+            <div class="meta-item">
+              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+                <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
+                <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
+              </svg>
+              <span>{{ caseItem.viewCount }} 浏览</span>
             </div>
           </div>
-        </div>
-        
-        <div class="info-section">
-          <h3>标签</h3>
-          <div class="tags-container">
-            <span *ngFor="let tag of selectedCase()?.tags" class="tag">{{ tag }}</span>
+
+          <!-- 风格标签 -->
+          <div class="case-tags">
+            @for (tag of caseItem.styleTags; track $index) {
+              <span class="tag">{{ tag }}</span>
+            }
           </div>
+
+          <!-- 客户评价 -->
+          @if (caseItem.customerReview) {
+            <div class="customer-review">
+              <p class="review-text">"{{ caseItem.customerReview }}"</p>
+            </div>
+          }
+
+          <!-- 设计师内部信息 -->
+          @if (isInternalUser) {
+            <div class="internal-info">
+              <div class="internal-badge" [class.excellent]="caseItem.isExcellent">
+                {{ caseItem.isExcellent ? '优秀案例库' : '普通案例' }}
+              </div>
+              <div class="internal-stats">
+                <span>分享: {{ caseItem.shareCount }}</span>
+                <span>收藏: {{ caseItem.favoriteCount }}</span>
+              </div>
+            </div>
+          }
         </div>
       </div>
-      
-      <!-- 操作按钮 -->
-      <div class="case-actions">
-        <button 
-          class="primary-btn"
-          (click)="toggleFavorite(selectedCase()?.id!)"
-        >
-          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-            <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path>
-          </svg>
-          <span *ngIf="selectedCase()?.isFavorite">已收藏</span>
-          <span *ngIf="!selectedCase()?.isFavorite">收藏案例</span>
-        </button>
-        <button class="secondary-btn" (click)="shareCase(selectedCase()?.id!)">
-          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-            <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"></path>
-            <polyline points="16 6 12 2 8 6"></polyline>
-            <line x1="12" y1="2" x2="12" y2="15"></line>
-          </svg>
-          <span>分享案例</span>
-        </button>
-        <button class="secondary-btn">
-          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-            <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
-          </svg>
-          <span>查看原图</span>
-        </button>
+    } @empty {
+      <div class="empty-state">
+        <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor">
+          <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
+          <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
+        </svg>
+        <h3>暂无案例</h3>
+        <p>尝试调整筛选条件或刷新页面</p>
+        <button class="btn btn-primary" (click)="resetFilters()">重置筛选</button>
       </div>
-    </div>
+    }
   </div>
 
-  <!-- 分享弹窗 -->
-  <div class="share-modal" *ngIf="showShareModal()" (click)="closeShareModal()">
-    <div class="share-modal-content" (click)="$event.stopPropagation()">
-      <button class="close-btn" (click)="closeShareModal()">
-        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
-          <path d="M6 6L18 18M18 6L6 18" stroke="#666" stroke-width="2" stroke-linecap="round"/>
-        </svg>
+  <!-- 分页控件 -->
+  @if (filteredCases.length > 0) {
+    <div class="pagination">
+      <button 
+        class="pagination-btn" 
+        [disabled]="currentPage === 1"
+        (click)="previousPage()"
+      >
+        上一页
       </button>
-  
-      <h3>分享案例</h3>
-      <p class="share-tip">复制链接发送给客户,或扫码打开案例页</p>
-  
-      <div class="share-body">
-        <div class="share-link-box">
-          <input class="share-link-input" [value]="shareLink()" readonly />
-          <button class="btn-primary" (click)="copyShareLink()">复制链接</button>
-          <button class="btn-secondary" (click)="openShareLink()">打开</button>
+      
+      <span class="page-info">第 {{ currentPage }} 页 / 共 {{ totalPages }} 页 ({{ filteredCases.length }} 个案例)</span>
+      
+      <button 
+        class="pagination-btn" 
+        [disabled]="currentPage === totalPages"
+        (click)="nextPage()"
+      >
+        下一页
+      </button>
+    </div>
+  }
+
+  <!-- 案例详情面板 -->
+  @if (selectedCase) {
+    <app-case-detail-panel
+      [case]="selectedCase"
+      [isInternalUser]="isInternalUser"
+      (close)="closeCaseDetail()"
+      (toggleFavorite)="toggleFavorite($event)"
+      (share)="shareCase($event)"
+    ></app-case-detail-panel>
+  }
+
+  <!-- 分享弹窗 -->
+  @if (selectedCaseForShare) {
+    <div class="share-modal" (click)="closeShareModal()">
+      <div class="share-content" (click)="$event.stopPropagation()">
+        <div class="share-header">
+          <h3>分享案例</h3>
+          <button class="close-btn" (click)="closeShareModal()">×</button>
         </div>
-  
-        <div class="qr-box">
-          <img *ngIf="qrDataUrl(); else qrPlaceholder" [src]="qrDataUrl()" alt="分享二维码" width="160" height="160" />
-          <ng-template #qrPlaceholder>
-            <div class="qr-placeholder">二维码生成中或不可用</div>
-          </ng-template>
-          <div class="qr-actions" *ngIf="qrDataUrl()">
-            <button class="btn-secondary" (click)="downloadQrCode()">下载二维码</button>
+        
+        <div class="share-options">
+          <div class="qr-code">
+            <img [src]="generateQRCode(selectedCaseForShare)" alt="分享二维码">
+            <p>扫描二维码分享</p>
+          </div>
+          
+          <div class="share-links">
+            <div class="share-link">
+              <input 
+                type="text" 
+                [value]="generateShareLink(selectedCaseForShare)" 
+                readonly
+                class="link-input"
+              >
+              <button class="btn btn-secondary" (click)="copyShareLink()">复制链接</button>
+            </div>
+            
+            <div class="social-share">
+              <button class="btn btn-primary" (click)="shareToWeCom()">
+                <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
+                  <path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path>
+                  <rect x="2" y="9" width="4" height="12"></rect>
+                  <circle cx="4" cy="4" r="2"></circle>
+                </svg>
+                分享到企业微信
+              </button>
+            </div>
           </div>
         </div>
       </div>
     </div>
-  </div>
+  }
 </div>

+ 756 - 1209
src/app/pages/customer-service/case-library/case-library.scss

@@ -1,1321 +1,868 @@
-// 全局变量定义
-$primary-color: #165DFF;
-$primary-dark: #0E42CB;
-$secondary-color: #4E5BA6;
-$success-color: #00B42A;
-$warning-color: #FF7D00;
-$danger-color: #F53F3F;
-$text-primary: #1D2129;
-$text-secondary: #4E5969;
-$text-tertiary: #86909C;
-$text-light: #C9CDD4; // 新增浅色文本变量
-$border-color: #E5E6EB;
-$background-primary: #FFFFFF;
-$background-secondary: #F2F3F5;
-$background-tertiary: #F7F8FA;
-$shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
-$shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
-$shadow-lg: 0 10px 30px rgba(0, 0, 0, 0.1);
-$border-radius: 8px;
-$transition: all 0.3s ease;
+/* 颜色变量 */
+$primary-color: #007aff;
+$primary-dark: #0051a8;
+$success-color: #34c759;
+$warning-color: #ff9500;
+$error-color: #ff3b30;
+$text-primary: #1d1d1f;
+$text-secondary: #86868b;
+$text-muted: #a1a1aa;
+$background-light: #f5f5f7;
+$border-color: #d2d2d7;
+$white: #ffffff;
+
+// Gray colors
+$gray-50: #f9fafb;
+$gray-100: #f3f4f6;
+$gray-200: #e5e7eb;
+$gray-300: #d1d5db;
+$gray-400: #9ca3af;
+$gray-500: #6b7280;
+$gray-600: #4b5563;
+
+// Green colors
+$green-200: #bbf7d0;
+$green-600: #16a34a;
+
+// Red colors
+$red-500: #ef4444;
 
-// 主容器
 .case-library-container {
-  display: flex;
-  flex-direction: column;
-  height: 100vh;
-  background-color: $background-secondary;
-  color: $text-primary;
-  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
-}
-
-// 顶部导航栏
-.top-navbar {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding: 0 24px;
-  height: 64px;
-  background-color: $background-primary;
-  border-bottom: 1px solid $border-color;
-  box-shadow: $shadow-sm;
-  position: sticky;
-  top: 0;
-  z-index: 1000;
-
-  .navbar-left {
-    display: flex;
-    align-items: center;
-    gap: 16px;
-  }
-
-  .menu-toggle {
-    display: none;
-    background: none;
-    border: none;
-    cursor: pointer;
-    color: $text-primary;
-    padding: 8px;
-    transition: $transition;
-
-    &:hover {
-      color: $primary-color;
-    }
-  }
-
-  .app-title {
-    font-size: 20px;
-    font-weight: 600;
-    color: $primary-color;
-  }
-
-  .navbar-center {
-    flex: 1;
-    max-width: 400px;
-    margin: 0 32px;
-  }
-
-  .search-container {
-    display: flex;
-    align-items: center;
-    background-color: $background-tertiary;
-    border-radius: 20px;
-    padding: 8px 16px;
-    height: 36px;
-
-    .search-input {
-      flex: 1;
-      border: none;
-      background: none;
-      outline: none;
-      font-size: 14px;
-      color: $text-primary;
-
-      &::placeholder {
-        color: $text-tertiary;
-      }
-    }
-
-    .search-button {
-      background: none;
-      border: none;
-      cursor: pointer;
-      color: $text-tertiary;
-      padding: 4px;
-      transition: $transition;
-
-      &:hover {
-        color: $primary-color;
-      }
-    }
-  }
-
-  .navbar-right {
-    display: flex;
-    align-items: center;
-    gap: 16px;
-  }
-
-  .notification-btn {
-    position: relative;
-    background: none;
-    border: none;
-    cursor: pointer;
-    color: $text-secondary;
-    padding: 8px;
-    transition: $transition;
-
-    &:hover {
-      color: $primary-color;
-    }
-
-    .notification-badge {
-      position: absolute;
-      top: 0;
-      right: 0;
-      background-color: $danger-color;
-      color: white;
-      font-size: 10px;
-      padding: 2px 6px;
-      border-radius: 10px;
-      min-width: 16px;
-      text-align: center;
-    }
-  }
-// 在分页相关样式中添加省略号样式
-.pagination-ellipsis {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 36px;
-  height: 36px;
-  font-size: 14px;
-  color: $text-light;
-  cursor: default;
-}
-  .user-profile {
-    display: flex;
-    align-items: center;
-    gap: 8px;
-
-    .user-avatar {
-      width: 36px;
-      height: 36px;
-      border-radius: 50%;
-      object-fit: cover;
-    }
-
-    .user-name {
-      font-size: 14px;
-      font-weight: 500;
-      color: $text-primary;
-    }
-  }
-}
-
-// 主要内容区
-.dashboard-content {
-  display: flex;
-  flex: 1;
-  overflow: hidden;
-}
-
-// 左侧侧边栏
-.sidebar {
-  width: 220px;
-  background-color: $background-primary;
-  border-right: 1px solid $border-color;
-  display: flex;
-  flex-direction: column;
-  transition: $transition;
-
-  .sidebar-nav {
-    flex: 1;
-    padding: 16px 0;
-
-    .nav-item {
-      display: flex;
-      align-items: center;
-      gap: 12px;
-      padding: 12px 24px;
-      color: $text-secondary;
-      text-decoration: none;
-      border-left: 3px solid transparent;
-      transition: $transition;
-
-      &:hover {
-        background-color: $background-tertiary;
-        color: $primary-color;
-      }
-
-      &.active {
-        color: $primary-color;
-        background-color: color-mix(in srgb, $primary-color 5%, transparent);
-        border-left-color: $primary-color;
-        font-weight: 500;
-      }
-    }
-  }
-
-  .sidebar-footer {
-    padding: 16px 24px;
-    border-top: 1px solid $border-color;
-
-    .storage-info {
-      margin-bottom: 16px;
-      font-size: 12px;
-      color: $text-tertiary;
-    }
-
-    .logout-btn {
-      display: flex;
-      align-items: center;
-      gap: 8px;
-
-      padding: 8px 12px;
-      background: none;
-      border: 1px solid $border-color;
-      border-radius: $border-radius;
-      color: $text-secondary;
-      cursor: pointer;
-      font-size: 14px;
-      transition: $transition;
-
-      &:hover {
-        background-color: $background-tertiary;
-        border-color: $danger-color;
-        color: $danger-color;
-      }
-    }
-  }
-}
-
-// 中间内容区
-.content-wrapper {
-  flex: 1;
-  overflow-y: auto;
   padding: 24px;
-}
-
-// 欢迎区域
-.welcome-section {
-  margin-bottom: 24px;
-
-  h2 {
-    font-size: 24px;
-    font-weight: 600;
-    margin-bottom: 8px;
-    color: $text-primary;
-  }
-
-  p {
-    font-size: 14px;
-    color: $text-secondary;
-  }
-}
-
-// 筛选区域
-.filter-section {
-  background-color: $background-primary;
-  border-radius: $border-radius;
-  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,
-.reset-filter-btn {
-  display: flex;
-  align-items: center;
-  gap: 6px;
-  padding: 8px 16px;
-  background-color: $background-tertiary;
-  border: 1px solid $border-color;
-  border-radius: $border-radius;
-  color: $text-secondary;
-  cursor: pointer;
-  font-size: 14px;
-  transition: $transition;
-
-  &:hover {
-    background-color: $background-secondary;
-    border-color: $primary-color;
-    color: $primary-color;
-  }
-}
-
-.filter-panel {
-  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;
+  max-width: 1440px;
+  margin: 0 auto;
   
-  &.show {
-    opacity: 1;
-    transform: translateY(0);
-  }
-  
-  &:not(.show) {
-    opacity: 0;
-    transform: translateY(-10px);
-    pointer-events: none;
-  }
-}
-
-.filter-form {
-  .filter-row {
-    display: flex;
-    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 {
-    display: flex;
-    flex-direction: column;
-    gap: 8px;
-    
-    label {
-      font-size: 14px;
-      font-weight: 600;
-      color: #374151;
-      margin-bottom: 4px;
-    }
-    
-    select {
-      padding: 10px 12px;
-      border: 2px solid #e5e7eb;
-      border-radius: 8px;
-      font-size: 14px;
-      background: white;
-      color: #374151;
-      transition: all 0.2s ease;
-      position: relative;
-      z-index: 10;
-      
-      &:focus {
-        outline: none;
-        border-color: #3b82f6;
-        box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-      }
-      
-      &:hover {
-        border-color: #d1d5db;
-      }
-    }
-  }
-  
-  // 风格选择器样式
-  .style-checkboxes {
-    display: flex;
-    flex-wrap: wrap;
-    gap: 12px;
-    margin-top: 8px;
-  }
-  
-  .style-checkbox {
-    display: flex;
-    align-items: center;
-    cursor: pointer;
-    
-    input[type="checkbox"] {
-      display: none;
-    }
-    
-    .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);
-    }
-  }
-  
-  // 收藏复选框样式
-  .favorite-checkbox {
+  .page-header {
     display: flex;
+    justify-content: space-between;
     align-items: center;
-    gap: 8px;
-    cursor: pointer;
-    padding: 10px 16px;
-    background: white;
-    border: 2px solid #e5e7eb;
-    border-radius: 8px;
-    transition: all 0.2s ease;
+    margin-bottom: 32px;
     
-    &:hover {
-      border-color: #f59e0b;
-      background: #fef3c7;
-    }
-    
-    input[type="checkbox"] {
-      width: 18px;
-      height: 18px;
-      accent-color: #f59e0b;
-    }
-    
-    .checkbox-text {
-      font-size: 14px;
-      font-weight: 500;
-      color: #374151;
-    }
-    
-    input[type="checkbox"]:checked ~ .checkbox-text {
-      color: #f59e0b;
+    h1 {
+      font-size: 28px;
       font-weight: 600;
-    }
-  }
-}
-
-// 案例展示区域优化
-.cases-grid {
-  display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
-  gap: 24px;
-  margin-top: 24px;
-}
-
-.case-card {
-  background: white;
-  border-radius: 16px;
-  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.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;
+      color: $text-primary;
+      margin: 0;
     }
     
-    .case-details {
-      display: flex;
-      flex-wrap: wrap;
-      gap: 12px;
-      margin-bottom: 16px;
-      
-      .detail-item {
+    .header-actions {
+      .btn {
         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;
+        gap: 8px;
+        padding: 10px 16px;
+        border-radius: 8px;
         font-weight: 500;
-      }
-    }
-  }
-}
-
-// 响应式设计
-@media (max-width: 768px) {
-  .filter-form {
-    .filter-row {
-      flex-direction: column;
-      gap: 16px;
-      
-      &.primary-filters,
-      &.advanced-filters {
-        .filter-group {
-          width: 100%;
+        transition: all 0.2s ease;
+        
+        &:hover {
+          transform: translateY(-1px);
+          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
         }
       }
     }
-    
-    .style-checkboxes {
-      justify-content: center;
-    }
   }
   
-  .cases-grid {
-    grid-template-columns: 1fr;
-    gap: 16px;
-  }
-}
-
-/* 优化的筛选表单布局 */
-.filter-form {
-  padding: 12px 0 8px;
-}
-.filter-row {
-  display: grid;
-  grid-template-columns: repeat(12, 1fr);
-  gap: 12px 16px;
-  margin-bottom: 10px;
-}
-.filter-group { grid-column: span 3; }
-@media (max-width: 1200px) { .filter-group { grid-column: span 4; } }
-@media (max-width: 900px) { .filter-group { grid-column: span 6; } }
-@media (max-width: 640px) { .filter-group { grid-column: span 12; } }
-
-.checkbox-group {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 8px 10px;
-}
-.checkbox-item { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
-.checkbox-item input { accent-color: #1e5eff; }
-
-.range-inputs { display: inline-flex; align-items: center; gap: 6px; }
-.range-inputs input { width: 110px; }
-
-/* 瀑布流布局 */
-.cases-grid {
-  column-count: 1;
-  column-gap: 16px;
-}
-@media (min-width: 768px) { .cases-grid { column-count: 2; } }
-@media (min-width: 1200px) { .cases-grid { column-count: 3; } }
-@media (min-width: 1600px) { .cases-grid { column-count: 4; } }
-
-.case-card {
-  display: inline-block; // 关键:配合 columns
-  width: 100%;
-  break-inside: avoid;
-  margin: 0 0 16px;
-  border-radius: 12px;
-  background: #fff;
-  box-shadow: 0 6px 18px rgba(0,0,0,0.06);
-  overflow: hidden;
-  transition: transform .18s ease, box-shadow .18s ease;
-}
-.case-card:hover { transform: translateY(-2px); box-shadow: 0 10px 24px rgba(0,0,0,0.08); }
-
-.case-image-container { position: relative; }
-.case-image { width: 100%; height: auto; display: block; }
-
-.case-overlay {
-  position: absolute;
-  inset: 0;
-  display: flex;
-  align-items: flex-end;
-  justify-content: space-between;
-  padding: 10px;
-  opacity: 0;
-  background: linear-gradient(to top, rgba(0,0,0,0.35), rgba(0,0,0,0.0));
-  transition: opacity .2s ease;
-}
-.case-card:hover .case-overlay { opacity: 1; }
-
-.favorite-btn, .share-btn {
-  display: inline-flex;
-  align-items: center;
-  gap: 6px;
-  padding: 6px 10px;
-  color: #fff;
-  background: rgba(255,255,255,0.1);
-  border: 1px solid rgba(255,255,255,0.3);
-  border-radius: 8px;
-  backdrop-filter: blur(2px);
-  cursor: pointer;
-}
-.favorite-btn:hover, .share-btn:hover { background: rgba(255,255,255,0.2); }
-
-.case-info { padding: 12px; }
-.case-name { font-size: 15px; margin: 0 0 6px; }
-.case-meta { display: flex; gap: 12px; color: #667085; font-size: 12px; }
-.case-meta .meta-item { display: inline-flex; align-items: center; gap: 6px; }
-.case-tags { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; }
-.case-tags .tag { padding: 2px 8px; border-radius: 999px; background: #f3f7ff; color: #1e5eff; font-size: 12px; }
-
-/* 空状态 */
-.empty-state { text-align: center; color: #98a2b3; padding: 40px 0; }
-.btn-reset { margin-top: 10px; padding: 6px 12px; border-radius: 6px; border: 1px solid #d0d5dd; background: #fff; cursor: pointer; }
-
-/* 分页省略号 */
-.pagination-ellipsis { padding: 0 6px; color: #98a2b3; display: inline-flex; align-items: center; }
-
-/* 案例详情模态框优化 */
-.case-modal { position: fixed; inset: 0; background: rgba(17,24,39,0.45); backdrop-filter: blur(2px); z-index: 100; display: flex; align-items: center; justify-content: center; padding: 24px; }
-.case-modal .modal-content { width: min(980px, 92vw); max-height: 92vh; overflow: auto; border-radius: 12px; background: #fff; position: relative; box-shadow: 0 20px 48px rgba(0,0,0,0.18); }
-.case-modal .close-btn { position: absolute; right: 12px; top: 12px; background: #fff; border: 1px solid #e5e7eb; border-radius: 999px; width: 36px; height: 36px; display: grid; place-items: center; cursor: pointer; }
-
-.case-image-gallery { padding: 12px; }
-.case-image-gallery .main-image img { width: 100%; border-radius: 10px; }
-.case-image-gallery .thumbnails { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-top: 10px; }
-.case-image-gallery .thumbnail { width: 100%; border-radius: 8px; }
-
-.info-section { padding: 12px; }
-.info-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px 14px; }
-@media (max-width: 900px) { .info-grid { grid-template-columns: repeat(2, 1fr); } }
-.info-item label { color: #98a2b3; font-size: 12px; }
-.info-item span { color: #111827; font-size: 14px; }
-
-.case-actions { padding: 12px; display: flex; gap: 10px; border-top: 1px solid #f2f4f7; }
-.primary-btn, .secondary-btn { display: inline-flex; align-items: center; gap: 8px; border-radius: 8px; padding: 8px 12px; cursor: pointer; border: 1px solid transparent; }
-.primary-btn { background: linear-gradient(135deg, #1e5eff, #4f8cff); color: #fff; box-shadow: 0 6px 16px rgba(30,94,255,0.25); }
-.secondary-btn { background: #f8fafc; color: #1f2937; border-color: #e5e7eb; }
-
-/* 分享弹窗 */
-.share-modal { position: fixed; inset: 0; background: rgba(17,24,39,0.45); z-index: 110; display: flex; align-items: center; justify-content: center; padding: 24px; }
-.share-modal-content { width: min(520px, 92vw); background: #fff; border-radius: 12px; box-shadow: 0 18px 44px rgba(0,0,0,0.16); position: relative; padding: 18px; }
-.share-modal .close-btn { position: absolute; right: 12px; top: 12px; background: #fff; border: 1px solid #e5e7eb; border-radius: 999px; width: 36px; height: 36px; display: grid; place-items: center; cursor: pointer; }
-.share-modal h3 { margin: 0 0 6px; font-size: 18px; }
-.share-tip { color: #667085; font-size: 13px; margin-bottom: 12px; }
-.share-body { display: flex; gap: 12px; align-items: flex-start; }
-.share-link-box { flex: 1; display: flex; gap: 8px; }
-.share-link-input { flex: 1; height: 36px; padding: 0 10px; border: 1px solid #e5e7eb; border-radius: 8px; font-size: 13px; }
-.btn-primary { height: 36px; padding: 0 12px; border-radius: 8px; color: #fff; background: #1e5eff; border: 1px solid #1e5eff; cursor: pointer; }
-.qr-box { width: 160px; height: 160px; border: 1px dashed #e5e7eb; border-radius: 8px; display: grid; place-items: center; color: #98a2b3; font-size: 12px; }
-
-/* 响应式微调 */
-@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;
+  .stats-panel {
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    border-radius: 12px;
+    padding: 24px;
     margin-bottom: 24px;
-    align-items: flex-end;
+    color: white;
+    box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
     
-    &:last-child {
-      margin-bottom: 0;
-    }
-    
-    // 主要筛选项样式
-    &.primary-filters {
-      .filter-group {
-        flex: 1;
-        min-width: 200px;
+    .stats-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+      gap: 20px;
+      
+      .stat-card {
+        background: rgba(255, 255, 255, 0.1);
+        border-radius: 8px;
+        padding: 16px;
+        backdrop-filter: blur(10px);
+        
+        h3 {
+          margin: 0 0 16px 0;
+          font-size: 16px;
+          font-weight: 600;
+        }
+        
+        .stat-list {
+          .stat-item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 8px 0;
+            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+            
+            &:last-child {
+              border-bottom: none;
+            }
+            
+            .case-name, .style-name, .designer-name {
+              font-weight: 500;
+            }
+            
+            .stat-value {
+              color: rgba(255, 255, 255, 0.8);
+              font-size: 14px;
+            }
+          }
+        }
       }
     }
-    
-    // 风格筛选样式
-    &.style-filters {
-      .style-group {
-        width: 100%;
+  }
+  
+  .filter-bar {
+    background: white;
+    border-radius: 12px;
+    padding: 24px;
+    margin-bottom: 32px;
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+    border: 1px solid $border-color;
+    position: sticky;
+    top: 20px;
+    z-index: 100;
+    transition: all 0.3s ease;
+    
+    .filter-group {
+      display: flex;
+      gap: 16px;
+      margin-bottom: 16px;
+      flex-wrap: wrap;
+      
+      &:last-child {
+        margin-bottom: 0;
       }
       
-      padding: 20px;
-      background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
-      border-radius: 16px;
-      border: 1px solid #e2e8f0;
-    }
-    
-    // 高级筛选样式
-    &.advanced-filters {
-      .filter-group {
+      @media (max-width: 768px) {
+        flex-direction: column;
+        gap: 12px;
+        
+        .search-box {
+          min-width: unset;
+          max-width: unset;
+        }
+        
+        .filter-select {
+          min-width: unset;
+        }
+      }
+      
+      .search-box {
+        position: relative;
         flex: 1;
+        min-width: 250px;
+        max-width: 400px;
         
-        &.checkbox-group {
-          display: flex;
-          align-items: center;
-          justify-content: center;
+        .search-input {
+          width: 100%;
+          padding: 12px 16px 12px 40px;
+          border: 1px solid $border-color;
+          border-radius: 8px;
+          font-size: 14px;
+          transition: border-color 0.2s ease;
+          
+          &:focus {
+            outline: none;
+            border-color: $primary-color;
+            box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
+          }
+        }
+        
+        .search-icon {
+          position: absolute;
+          left: 16px;
+          top: 50%;
+          transform: translateY(-50%);
+          color: $text-secondary;
         }
       }
-    }
-  }
-  
-  .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;
+      .filter-select {
+        padding: 12px 16px;
+        border: 1px solid $border-color;
+        border-radius: 8px;
+        font-size: 14px;
+        background: white;
+        min-width: 140px;
+        cursor: pointer;
+        transition: border-color 0.2s ease;
+        
+        &:focus {
+          outline: none;
+          border-color: $primary-color;
+        }
       }
     }
     
-    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);
+    .filter-actions {
+      display: flex;
+      gap: 12px;
+      justify-content: flex-end;
       
-      &: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);
+      @media (max-width: 768px) {
+        justify-content: stretch;
+        
+        .btn {
+          flex: 1;
+        }
       }
       
-      &:hover {
-        border-color: #d1d5db;
-        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
+      .btn {
+        padding: 10px 20px;
+        border-radius: 8px;
+        font-weight: 500;
+        transition: all 0.2s ease;
+        
+        &:hover {
+          transform: translateY(-1px);
+        }
+        
+        &.btn-secondary {
+          background: white;
+          border: 1px solid $border-color;
+          color: $text-primary;
+          
+          &:hover {
+            background: $gray-50;
+          }
+        }
+        
+        &.btn-primary {
+          background: $primary-color;
+          border: 1px solid $primary-color;
+          color: white;
+          
+          &:hover {
+          background: #0051a8; // 手动计算的深色版本
+        }
+        }
       }
     }
   }
   
-  // 风格选择器样式
-  .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;
-    }
+  .cases-grid {
+    display: grid;
+    grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
+    gap: 24px;
+    margin-bottom: 32px;
     
-    .style-tag {
-      padding: 10px 20px;
+    .case-card {
       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;
+      border-radius: 12px;
       overflow: hidden;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+      transition: all 0.3s ease;
+      border: 1px solid $border-color;
       
-      &::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 {
+        transform: translateY(-4px);
+        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+        
+        .case-image {
+          transform: scale(1.05);
+        }
+        
+        .image-overlay {
+          opacity: 1;
+        }
       }
       
-      &:hover {
-        border-color: #3b82f6;
-        color: #3b82f6;
-        transform: translateY(-2px);
-        box-shadow: 0 8px 16px rgba(59, 130, 246, 0.2);
+      .case-image-container {
+        position: sticky;
+        top: 20px; /* 距离顶部20px */
+        z-index: 10;
+        overflow: hidden;
+        height: 240px;
+        
+        .case-image {
+          width: 100%;
+          height: 100%;
+          object-fit: cover;
+          transition: transform 0.3s ease;
+          cursor: pointer;
+        }
         
-        &::before {
-          left: 100%;
+        .image-overlay {
+          position: absolute;
+          top: 0;
+          left: 0;
+          right: 0;
+          bottom: 0;
+          background: linear-gradient(
+            to bottom,
+            rgba(0, 0, 0, 0.3) 0%,
+            rgba(0, 0, 0, 0.1) 50%,
+            rgba(0, 0, 0, 0.8) 100%
+          );
+          opacity: 0;
+          transition: opacity 0.3s ease;
+          display: flex;
+          flex-direction: column;
+          justify-content: space-between;
+          padding: 16px;
+          
+          .case-badges {
+            display: flex;
+            gap: 8px;
+            flex-wrap: wrap;
+            
+            .badge {
+              padding: 4px 8px;
+              border-radius: 4px;
+              font-size: 12px;
+              font-weight: 500;
+              color: white;
+              
+              &.project-type {
+                background: rgba(79, 70, 229, 0.9);
+              }
+              
+              &.space-type {
+                background: rgba(245, 158, 11, 0.9);
+              }
+              
+              &.rendering-level {
+                background: rgba(16, 185, 129, 0.9);
+              }
+            }
+          }
+          
+          .action-buttons {
+            display: flex;
+            gap: 12px;
+            justify-content: flex-end;
+            
+            .btn-icon {
+              width: 40px;
+              height: 40px;
+              border-radius: 50%;
+              border: none;
+              background: rgba(255, 255, 255, 0.9);
+              color: $text-primary;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              cursor: pointer;
+              transition: all 0.2s ease;
+              backdrop-filter: blur(10px);
+              
+              &:hover {
+                background: white;
+                transform: scale(1.1);
+                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+              }
+              
+              &.favorite-btn {
+                &.active {
+                  background: $red-500;
+                  color: white;
+                }
+                
+                &:hover:not(.active) {
+                  color: $red-500;
+                }
+              }
+              
+              &.share-btn {
+                &:hover {
+                  background: $primary-color;
+                  color: white;
+                }
+              }
+            }
+          }
+        }
+      }
+      
+      .case-info {
+        padding: 20px;
+        
+        .case-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: flex-start;
+          margin-bottom: 12px;
+          
+          .case-name {
+            font-size: 18px;
+            font-weight: 600;
+            color: $text-primary;
+            margin: 0;
+            cursor: pointer;
+            transition: color 0.2s ease;
+            flex: 1;
+            margin-right: 12px;
+            
+            &:hover {
+              color: $primary-color;
+            }
+          }
+          
+          .info-share-btn {
+            width: 32px;
+            height: 32px;
+            border-radius: 6px;
+            border: 1px solid $border-color;
+            background: white;
+            color: $text-muted;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+            transition: all 0.2s ease;
+            flex-shrink: 0;
+            
+            &:hover {
+              background: $primary-color;
+              color: white;
+              border-color: $primary-color;
+              transform: scale(1.05);
+            }
+            
+            svg {
+              stroke-width: 2;
+            }
+          }
+        }
+        
+        .case-meta {
+          display: flex;
+          flex-direction: column;
+          gap: 8px;
+          margin-bottom: 16px;
+          
+          .meta-item {
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            font-size: 14px;
+            color: $text-secondary;
+            
+            svg {
+              color: $text-muted;
+            }
+            
+            .team-badge {
+              background: $gray-100;
+              color: $text-secondary;
+              padding: 2px 6px;
+              border-radius: 4px;
+              font-size: 12px;
+              margin-left: 8px;
+            }
+          }
+        }
+        
+        .case-tags {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 6px;
+          margin-bottom: 16px;
+          
+          .tag {
+            background: $gray-100;
+            color: $text-secondary;
+            padding: 4px 8px;
+            border-radius: 16px;
+            font-size: 12px;
+            font-weight: 500;
+          }
+        }
+        
+        .customer-review {
+          background: $gray-50;
+          padding: 12px;
+          border-radius: 8px;
+          border-left: 4px solid $primary-color;
+          margin-bottom: 16px;
+          
+          .review-text {
+            margin: 0;
+            font-size: 14px;
+            color: $text-secondary;
+            font-style: italic;
+            line-height: 1.5;
+          }
+        }
+        
+        .internal-info {
+          border-top: 1px solid $border-color;
+          padding-top: 16px;
+          
+          .internal-badge {
+            display: inline-block;
+            padding: 4px 8px;
+            border-radius: 4px;
+            font-size: 12px;
+            font-weight: 500;
+            margin-bottom: 8px;
+            
+            &.excellent {
+              background: rgba(34, 197, 94, 0.1);
+              color: $green-600;
+              border: 1px solid $green-200;
+            }
+            
+            &:not(.excellent) {
+              background: $gray-100;
+              color: $text-secondary;
+            }
+          }
+          
+          .internal-stats {
+            display: flex;
+            gap: 16px;
+            font-size: 12px;
+            color: $text-muted;
+            
+            span {
+              display: flex;
+              align-items: center;
+              gap: 4px;
+            }
+          }
         }
       }
-    }
-    
-    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);
-    }
+  .empty-state {
+    text-align: center;
+    padding: 80px 20px;
+    color: $text-secondary;
     
-    input[type="checkbox"] {
-      width: 20px;
-      height: 20px;
-      accent-color: #f59e0b;
+    svg {
+      color: $gray-300;
+      margin-bottom: 16px;
     }
     
-    .checkbox-text {
-      font-size: 14px;
+    h3 {
+      font-size: 20px;
       font-weight: 600;
-      color: #374151;
+      margin: 0 0 8px 0;
     }
     
-    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;
+    p {
+      margin: 0 0 24px 0;
+      font-size: 16px;
     }
   }
   
-  .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);
-    }
+  .pagination {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    gap: 16px;
+    margin-top: 32px;
     
-    // 添加渐变遮罩
-    &::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;
+    .pagination-btn {
+      padding: 10px 20px;
+      border: 1px solid $border-color;
+      border-radius: 8px;
+      background: white;
+      color: $text-primary;
+      font-weight: 500;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      
+      &:hover:not(:disabled) {
+        background: $gray-50;
+        border-color: $gray-300;
+      }
+      
+      &:disabled {
+        opacity: 0.5;
+        cursor: not-allowed;
+      }
     }
     
-    &:hover::after {
-      opacity: 1;
+    .page-info {
+      color: $text-secondary;
+      font-size: 14px;
     }
   }
   
-  .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;
-    }
+  .share-modal {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.4);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    z-index: 1000;
+    backdrop-filter: blur(8px);
+    animation: modalFadeIn 0.3s ease;
     
-    .case-details {
-      display: flex;
-      flex-wrap: wrap;
-      gap: 16px;
-      margin-bottom: 20px;
+    .share-content {
+      background: #f8f9fa;
+      border-radius: 16px;
+      padding: 0;
+      max-width: 380px;
+      width: 90%;
+      box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
+      overflow: hidden;
       
-      .detail-item {
+      .share-header {
         display: flex;
+        justify-content: space-between;
         align-items: center;
-        gap: 6px;
-        font-size: 13px;
-        color: #6b7280;
-        background: #f8fafc;
-        padding: 6px 12px;
-        border-radius: 8px;
+        padding: 20px 24px 16px;
+        background: white;
+        border-bottom: 1px solid #e5e5ea;
         
-        .label {
+        h3 {
+          margin: 0;
+          font-size: 18px;
           font-weight: 600;
+          color: #000;
         }
         
-        .value {
-          color: #374151;
-          font-weight: 500;
+        .close-btn {
+          background: none;
+          border: none;
+          font-size: 28px;
+          cursor: pointer;
+          color: #8e8e93;
+          padding: 0;
+          width: 44px;
+          height: 44px;
+          border-radius: 50%;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          transition: background-color 0.2s ease;
+          
+          &:hover {
+            background: #f1f1f1;
+          }
         }
       }
-    }
-    
-    .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;
+      .share-options {
+        padding: 24px;
+        background: white;
         
-        &:hover {
-          background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
-          color: white;
-          transform: translateY(-1px);
+        .qr-code {
+          text-align: center;
+          margin-bottom: 24px;
+          padding: 20px;
+          background: #f8f9fa;
+          border-radius: 12px;
+          
+          img {
+            width: 140px;
+            height: 140px;
+            margin-bottom: 16px;
+            border-radius: 12px;
+            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+          }
+          
+          p {
+            margin: 0;
+            font-size: 15px;
+            color: #8e8e93;
+            font-weight: 500;
+          }
+        }
+        
+        .share-links {
+          .share-link {
+            display: flex;
+            gap: 12px;
+            margin-bottom: 20px;
+            
+            .link-input {
+              flex: 1;
+              padding: 14px 16px;
+              border: 1px solid #c7c7cc;
+              border-radius: 10px;
+              font-size: 15px;
+              background: white;
+              color: #000;
+              font-family: -apple-system, BlinkMacSystemFont, sans-serif;
+              
+              &:focus {
+                outline: none;
+                border-color: #007aff;
+              }
+            }
+            
+            .btn {
+              padding: 14px 20px;
+              border-radius: 10px;
+              font-weight: 500;
+              font-size: 15px;
+              font-family: -apple-system, BlinkMacSystemFont, sans-serif;
+              
+              &.btn-secondary {
+                background: #007aff;
+                border: none;
+                color: white;
+                
+                &:hover {
+                  background: #0056d6;
+                }
+              }
+            }
+          }
+          
+          .social-share {
+            .btn {
+              display: flex;
+              align-items: center;
+              gap: 12px;
+              width: 100%;
+              justify-content: center;
+              padding: 16px;
+              background: #007aff;
+              border: none;
+              border-radius: 12px;
+              color: white;
+              font-weight: 500;
+              font-size: 16px;
+              font-family: -apple-system, BlinkMacSystemFont, sans-serif;
+              transition: background-color 0.2s ease;
+              
+              &:hover {
+                background: #0056d6;
+              }
+              
+              svg {
+                width: 20px;
+                height: 20px;
+              }
+            }
+          }
         }
       }
     }
   }
-}
-
-// 加载状态
-.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;
+  @keyframes modalFadeIn {
+    from {
+      opacity: 0;
+      backdrop-filter: blur(0px);
+    }
+    to {
+      opacity: 1;
+      backdrop-filter: blur(8px);
+    }
   }
 }
 
 // 响应式设计
 @media (max-width: 1024px) {
-  .cases-grid {
-    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
-    gap: 20px;
+  .case-library-container {
+    padding: 16px;
+    
+    .cases-grid {
+      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+      gap: 20px;
+    }
+    
+    .filter-bar {
+      .filter-group {
+        .search-box {
+          min-width: 250px;
+        }
+      }
+    }
   }
 }
 
 @media (max-width: 768px) {
   .case-library-container {
-    padding: 16px;
-  }
-  
-  .filter-panel {
-    padding: 20px;
-    border-radius: 16px;
-  }
-  
-  .filter-form {
-    .filter-row {
+    .page-header {
       flex-direction: column;
       gap: 16px;
+      align-items: stretch;
       
-      &.primary-filters,
-      &.advanced-filters {
-        .filter-group {
+      .header-actions {
+        .btn {
           width: 100%;
+          justify-content: center;
+        }
+      }
+    }
+    
+    .stats-panel {
+      .stats-grid {
+        grid-template-columns: 1fr;
+      }
+    }
+    
+    .filter-bar {
+      .filter-group {
+        .search-box {
+          min-width: 100%;
+        }
+        
+        .filter-select {
+          min-width: 120px;
         }
       }
       
-      &.style-filters {
-        padding: 16px;
+      .filter-actions {
+        justify-content: stretch;
+        
+        .btn {
+          flex: 1;
+        }
       }
     }
     
-    .style-checkboxes {
-      justify-content: center;
-      gap: 12px;
+    .cases-grid {
+      grid-template-columns: 1fr;
     }
-  }
-  
-  .cases-grid {
-    grid-template-columns: 1fr;
-    gap: 16px;
-  }
-  
-  .case-card {
-    .case-info {
-      padding: 20px;
+    
+    .share-modal {
+      .share-content {
+        .share-options {
+          grid-template-columns: 1fr;
+          gap: 20px;
+          
+          .qr-code {
+            order: 2;
+          }
+          
+          .share-links {
+            order: 1;
+          }
+        }
+      }
     }
   }
 }
 
 @media (max-width: 480px) {
-  .page-header {
-    h1 {
-      font-size: 24px;
+  .case-library-container {
+    padding: 12px;
+    
+    .filter-bar {
+      padding: 16px;
+      
+      .filter-group {
+        .filter-select {
+          min-width: 100px;
+          font-size: 13px;
+        }
+      }
     }
-  }
-  
-  .filter-toggle {
-    width: 100%;
-    margin-bottom: 16px;
-  }
-  
-  .style-checkboxes {
-    .style-tag {
-      padding: 8px 16px;
-      font-size: 13px;
+    
+    .case-card {
+      .case-image-container {
+        height: 200px;
+      }
+      
+      .case-info {
+        padding: 16px;
+      }
     }
   }
-}
-
-// ... existing code ...
+}

+ 433 - 398
src/app/pages/customer-service/case-library/case-library.ts

@@ -1,468 +1,503 @@
-import { Component, OnInit, signal, computed } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup } from '@angular/forms';
-import { RouterModule, ActivatedRoute } from '@angular/router';
-import * as QRCode from 'qrcode';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { FormControl } from '@angular/forms';
+import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
+import { CaseDetailPanelComponent } from './case-detail-panel.component';
 
-// 定义案例接口
-interface CaseItem {
+interface Case {
   id: string;
   name: string;
-  category: string;
-  style: string[];
-  houseType: string;
-  property: string;
-  designer: string;
-  area: number;
-  createdAt: Date;
   coverImage: string;
-  detailImages: string[];
-  isFavorite: boolean;
-  tags: string[];
-  views: number;
-  description: string;
-  // 新增字段
   projectType: '工装' | '家装';
-  subType: '平层' | '复式' | '别墅' | '自建房' | '其他';
-  renderingLevel: '高端' | '中端';
+  spaceType: '平层' | '复式' | '别墅' | '自建房';
+  renderingLevel: '高端' | '中端' | '低端';
+  designer: string;
+  team: string;
+  area: number;
+  styleTags: string[];
+  customerReview?: string;
+  viewCount: number;
   shareCount: number;
   favoriteCount: number;
-  likeCount: number;
-  conversionRate: number; // 0-100
+  isFavorite: boolean;
+  isExcellent: boolean;
+  createdAt: Date;
+}
+
+interface StatItem {
+  id: string;
+  name: string;
+  shareCount: number;
+}
+
+interface StyleStat {
+  style: string;
+  count: number;
+}
+
+interface DesignerStat {
+  designer: string;
+  rate: number;
 }
 
 @Component({
   selector: 'app-case-library',
   standalone: true,
-  imports: [CommonModule, FormsModule, ReactiveFormsModule, RouterModule],
+  imports: [CommonModule, FormsModule, ReactiveFormsModule, CaseDetailPanelComponent],
   templateUrl: './case-library.html',
-  styleUrls: ['./case-library.scss', '../customer-service-styles.scss']
+  styleUrls: ['./case-library.scss']
 })
 export class CaseLibrary implements OnInit {
-  // 当前日期
-  currentDate = new Date();
+  // 表单控件
+  searchControl = new FormControl('');
+  projectTypeControl = new FormControl('');
+  spaceTypeControl = new FormControl('');
+  renderingLevelControl = new FormControl('');
+  styleControl = new FormControl('');
+  areaRangeControl = new FormControl('');
+
+  // 数据
+  cases: Case[] = [];
+  filteredCases: Case[] = [];
   
-  // 搜索关键词
-  searchTerm = signal('');
+  // 统计数据
+  topSharedCases: StatItem[] = [];
+  favoriteStyles: StyleStat[] = [];
+  designerRecommendations: DesignerStat[] = [];
   
-  // 分享弹窗
-  showShareModal = signal(false);
-  shareLink = signal('');
-  qrDataUrl = signal('');
-  sharedCaseId = signal<string | null>(null);
-
-  // 筛选表单
-  filterForm: FormGroup;
+  // 状态
+  showStatsPanel = false;
+  selectedCase: Case | null = null; // 用于详情面板
+  selectedCaseForShare: Case | null = null; // 用于分享模态框
+  currentPage = 1;
+  itemsPerPage = 10; // 每页显示10个案例
+  totalPages = 1;
   
-  // 案例列表
-  cases = signal<CaseItem[]>([]);
+  // 用户类型(模拟)
+  isInternalUser = true; // 可根据实际用户权限设置
   
-  // 筛选后的案例
-  filteredCases = computed(() => {
-    let result = [...this.cases()];
-    
-    // 应用搜索筛选
-    if (this.searchTerm()) {
-      const searchLower = this.searchTerm().toLowerCase();
-      result = result.filter(caseItem => 
-        caseItem.name.toLowerCase().includes(searchLower) ||
-        caseItem.designer.toLowerCase().includes(searchLower) ||
-        caseItem.description.toLowerCase().includes(searchLower) ||
-        caseItem.tags.some(tag => tag.toLowerCase().includes(searchLower))
-      );
-    }
-    
-    // 应用表单筛选
-    const filters = this.filterForm.value as any;
-    
-    if (filters.style && filters.style.length > 0) {
-      result = result.filter(caseItem => 
-        caseItem.style.some((s: string) => filters.style.includes(s))
-      );
-    }
+  // 行为追踪
+  private pageStartTime = Date.now();
+  private caseViewStartTimes = new Map<string, number>();
+
+  ngOnInit() {
+    this.initializeData();
+    this.setupFilterListeners();
+    this.setupBehaviorTracking();
+  }
+  
+  private setupBehaviorTracking() {
+    // 记录页面访问
+    this.recordBehavior('page_view', 'case-library', {
+      timestamp: new Date().toISOString()
+    });
     
-    if (filters.houseType) {
-      result = result.filter(caseItem => caseItem.houseType === filters.houseType);
-    }
+    // 页面卸载时记录停留时长
+    window.addEventListener('beforeunload', () => {
+      const stayDuration = Date.now() - this.pageStartTime;
+      this.recordBehavior('page_stay', 'case-library', {
+        duration: stayDuration,
+        durationMinutes: Math.round(stayDuration / 60000 * 100) / 100
+      });
+    });
+  }
+
+  private initializeData() {
+    // 模拟案例数据
+    this.cases = this.generateMockCases();
+    this.filteredCases = [...this.cases];
+    this.updatePagination();
     
+    // 初始化统计数据
+    this.initializeStats();
+  }
 
+  private setupFilterListeners() {
+    // 搜索框防抖
+    this.searchControl.valueChanges.pipe(
+      debounceTime(300),
+      distinctUntilChanged()
+    ).subscribe(() => this.applyFilters());
 
-    if (filters.projectType) {
-      result = result.filter(caseItem => caseItem.projectType === filters.projectType);
-    }
+    // 其他筛选条件变化
+    [
+      this.projectTypeControl,
+      this.spaceTypeControl,
+      this.renderingLevelControl,
+      this.styleControl,
+      this.areaRangeControl
+    ].forEach(control => {
+      control.valueChanges.subscribe(() => this.applyFilters());
+    });
+  }
 
-    if (filters.subType) {
-      result = result.filter(caseItem => caseItem.subType === filters.subType);
-    }
+  private generateMockCases(): Case[] {
+    const mockCases: Case[] = [];
+    const projectTypes: ('工装' | '家装')[] = ['工装', '家装'];
+    const spaceTypes: ('平层' | '复式' | '别墅' | '自建房')[] = ['平层', '复式', '别墅', '自建房'];
+    const renderingLevels: ('高端' | '中端' | '低端')[] = ['高端', '中端', '低端'];
+    const styles = ['现代', '中式', '欧式', '美式', '日式', '工业风', '极简风', '轻奢风'];
+    const designers = ['张三', '李四', '王五', '赵六', '钱七'];
+    const teams = ['设计一组', '设计二组', '设计三组', '设计四组'];
 
-    if (filters.renderingLevel) {
-      result = result.filter(caseItem => caseItem.renderingLevel === filters.renderingLevel);
-    }
+    for (let i = 1; i <= 50; i++) {
+      const projectType = projectTypes[Math.floor(Math.random() * projectTypes.length)];
+      const spaceType = spaceTypes[Math.floor(Math.random() * spaceTypes.length)];
+      const renderingLevel = renderingLevels[Math.floor(Math.random() * renderingLevels.length)];
+      const styleCount = Math.floor(Math.random() * 3) + 1;
+      const styleTags = Array.from({ length: styleCount }, () => 
+        styles[Math.floor(Math.random() * styles.length)]
+      );
 
-    // 价格筛选(基于案例的预估价格范围)
-    if (filters.price) {
-      // 这里可以根据实际业务逻辑来筛选价格
-      // 暂时保留所有案例,实际项目中需要根据案例的价格字段进行筛选
-    }
-    
-    if (filters.favorite) {
-      result = result.filter(caseItem => caseItem.isFavorite);
+      mockCases.push({
+        id: `case-${i}`,
+        name: `${projectType}${spaceType}设计案例 ${i}`,
+        coverImage: this.generatePlaceholderImage(400, 300, i),
+        projectType,
+        spaceType,
+        renderingLevel,
+        designer: designers[Math.floor(Math.random() * designers.length)],
+        team: teams[Math.floor(Math.random() * teams.length)],
+        area: Math.floor(Math.random() * 200) + 50,
+        styleTags: [...new Set(styleTags)], // 去重
+        customerReview: Math.random() > 0.3 ? `客户非常满意这次${projectType}设计,${spaceType}空间利用得很合理` : undefined,
+        viewCount: Math.floor(Math.random() * 1000),
+        shareCount: Math.floor(Math.random() * 100),
+        favoriteCount: Math.floor(Math.random() * 50),
+        isFavorite: Math.random() > 0.7,
+        isExcellent: Math.random() > 0.5,
+        createdAt: new Date(Date.now() - Math.floor(Math.random() * 365 * 24 * 60 * 60 * 1000))
+      });
     }
 
-    // 排序
-    if (filters.sortBy) {
-      switch (filters.sortBy) {
-        case 'views':
-          result.sort((a, b) => b.views - a.views);
-          break;
-        case 'shares':
-          result.sort((a, b) => b.shareCount - a.shareCount);
-          break;
-        case 'conversion':
-          result.sort((a, b) => b.conversionRate - a.conversionRate);
-          break;
-        case 'createdAt':
-          result.sort((a, b) => +b.createdAt - +a.createdAt);
-          break;
-      }
-    } else {
-      // 默认按创建时间倒序
-      result.sort((a, b) => +b.createdAt - +a.createdAt);
-    }
+    return mockCases;
+  }
+
+  private generatePlaceholderImage(width: number, height: number, seed: number): string {
+    return `https://picsum.photos/seed/${seed}/${width}/${height}`;
+  }
+
+  private initializeStats() {
+    // Top5 分享案例
+    this.topSharedCases = this.cases
+      .sort((a, b) => b.shareCount - a.shareCount)
+      .slice(0, 5)
+      .map(caseItem => ({
+        id: caseItem.id,
+        name: caseItem.name,
+        shareCount: caseItem.shareCount
+      }));
+
+    // 客户最喜欢案例风格
+    const styleCounts = new Map<string, number>();
+    this.cases.forEach(caseItem => {
+      caseItem.styleTags.forEach(style => {
+        styleCounts.set(style, (styleCounts.get(style) || 0) + caseItem.favoriteCount);
+      });
+    });
     
-    return result;
-  });
-  
-  // 显示筛选面板
-  showFilterPanel = signal(false);
-  
-  // 当前查看的案例详情
-  selectedCase = signal<CaseItem | null>(null);
-  
-  // 分页信息
-  currentPage = signal(1);
-  itemsPerPage = signal(12);
-  
-  // 分页后的案例
-  paginatedCases = computed(() => {
-    const startIndex = (this.currentPage() - 1) * this.itemsPerPage();
-    return this.filteredCases().slice(startIndex, startIndex + this.itemsPerPage());
-  });
-  
-  // 总页数
-  totalPages = computed(() => {
-    return Math.ceil(this.filteredCases().length / this.itemsPerPage());
-  });
-  
-  // 筛选选项
-  styleOptions = ['现代简约', '北欧风', '工业风', '新中式', '法式轻奢', '日式', '美式', '混搭'];
-  houseTypeOptions = ['一室一厅', '两室一厅', '两室两厅', '三室一厅', '三室两厅', '四室两厅', '复式', '别墅', '其他'];
-  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' },
-    { label: '分享最多', value: 'shares' },
-    { label: '转化率最高', value: 'conversion' }
-  ];
-  
-  constructor(private fb: FormBuilder, private route: ActivatedRoute) {
-    // 初始化筛选表单
-    this.filterForm = this.fb.group({
-      style: [[]],
-      houseType: [''],
-      projectType: [''],
-      subType: [''],
-      renderingLevel: [''],
-      price: [''],
-      favorite: [false],
-      sortBy: ['createdAt']
+    this.favoriteStyles = Array.from(styleCounts.entries())
+      .sort(([, a], [, b]) => b - a)
+      .slice(0, 5)
+      .map(([style, count]) => ({ style, count }));
+
+    // 设计师作品推荐率
+    const designerStats = new Map<string, { total: number; excellent: number }>();
+    this.cases.forEach(caseItem => {
+      const stats = designerStats.get(caseItem.designer) || { total: 0, excellent: 0 };
+      stats.total++;
+      if (caseItem.isExcellent) stats.excellent++;
+      designerStats.set(caseItem.designer, stats);
     });
+
+    this.designerRecommendations = Array.from(designerStats.entries())
+      .map(([designer, stats]) => ({
+        designer,
+        rate: Math.round((stats.excellent / stats.total) * 100)
+      }))
+      .sort((a, b) => b.rate - a.rate)
+      .slice(0, 5);
   }
-  
-  ngOnInit(): void {
-    // 加载模拟案例数据
-    this.loadCases();
-    
-    // 读取分享链接参数并打开对应案例详情
-    this.route.queryParamMap.subscribe(params => {
-      const caseId = params.get('case');
-      if (caseId) {
-        const item = this.cases().find(c => c.id === caseId);
-        if (item) {
-          this.viewCaseDetails(item);
+
+  applyFilters() {
+    const searchTerm = this.searchControl.value?.toLowerCase() || '';
+    const projectType = this.projectTypeControl.value;
+    const spaceType = this.spaceTypeControl.value;
+    const renderingLevel = this.renderingLevelControl.value;
+    const style = this.styleControl.value;
+    const areaRange = this.areaRangeControl.value;
+
+    this.filteredCases = this.cases.filter(caseItem => {
+      // 搜索条件
+      if (searchTerm && !(
+        caseItem.name.toLowerCase().includes(searchTerm) ||
+        caseItem.designer.toLowerCase().includes(searchTerm) ||
+        caseItem.styleTags.some(tag => tag.toLowerCase().includes(searchTerm))
+      )) {
+        return false;
+      }
+
+      // 项目类型筛选
+      if (projectType && caseItem.projectType !== projectType) {
+        return false;
+      }
+
+      // 空间类型筛选
+      if (spaceType && caseItem.spaceType !== spaceType) {
+        return false;
+      }
+
+      // 渲染水平筛选
+      if (renderingLevel && caseItem.renderingLevel !== renderingLevel) {
+        return false;
+      }
+
+      // 风格筛选
+      if (style && !caseItem.styleTags.includes(style)) {
+        return false;
+      }
+
+      // 面积范围筛选
+      if (areaRange) {
+        const [min, max] = areaRange.split('-').map(Number);
+        if (max === undefined) {
+          if (caseItem.area < min) return false;
+        } else if (caseItem.area < min || caseItem.area > max) {
+          return false;
         }
       }
+
+      return true;
     });
+
+    this.currentPage = 1;
+    this.updatePagination();
   }
-  
-  // 加载案例数据
-  loadCases(): void {
-    // 本地占位图集合
-    const LOCAL_IMAGES = [
-      '/assets/images/portfolio-1.svg',
-      '/assets/images/portfolio-2.svg',
-      '/assets/images/portfolio-3.svg',
-      '/assets/images/portfolio-4.svg'
-    ];
-
-    const rand = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min;
-    const pick = <T,>(arr: T[]): T => arr[Math.floor(Math.random() * arr.length)];
-
-    // 模拟API请求获取案例数据
-    const mockCases: CaseItem[] = Array.from({ length: 24 }, (_, i) => {
-      const cover = LOCAL_IMAGES[i % LOCAL_IMAGES.length];
-      const details = Array.from({ length: 4 }, (_, j) => LOCAL_IMAGES[(i + j) % LOCAL_IMAGES.length]);
-      const projectType = pick(this.projectTypeOptions);
-      const subType = pick(this.subTypeOptions);
-      const renderingLevel = pick(this.renderingLevelOptions);
-      const createdAt = new Date(Date.now() - rand(0, 365) * 24 * 60 * 60 * 1000);
-      const views = rand(100, 3000);
-      const shareCount = rand(10, 500);
-      const favoriteCount = rand(5, 400);
-      const likeCount = rand(10, 800);
-      const conversionRate = Number((Math.random() * 30 + 5).toFixed(1)); // 5% - 35%
-
-      return {
-        id: `case-${i + 1}`,
-        name: `${pick(this.styleOptions)}风格 ${pick(this.houseTypeOptions)}设计`,
-        category: pick(['客厅', '卧室', '厨房', '浴室', '书房', '餐厅']),
-        style: [pick(this.styleOptions)],
-        houseType: pick(this.houseTypeOptions),
-        property: pick(['万科', '绿城', '保利', '龙湖', '融创']),
-        designer: pick(['张设计', '李设计', '王设计', '赵设计', '陈设计']),
-        area: rand(50, 150),
-        createdAt,
-        coverImage: cover,
-        detailImages: details,
-        isFavorite: Math.random() > 0.7,
-        tags: ['热门', '精选', '新上传', '高性价比', '业主好评'].filter(() => Math.random() > 0.5),
-        views,
-        description: '这是一个精美的' + pick(['现代简约', '北欧风', '新中式']) + '风格设计案例,融合了功能性与美学,为客户打造了舒适宜人的居住环境。',
-        projectType,
-        subType,
-        renderingLevel,
-        shareCount,
-        favoriteCount,
-        likeCount,
-        conversionRate
-      };
-    });
+
+  resetFilters() {
+    this.searchControl.setValue('');
+    this.projectTypeControl.setValue('');
+    this.spaceTypeControl.setValue('');
+    this.renderingLevelControl.setValue('');
+    this.styleControl.setValue('');
+    this.areaRangeControl.setValue('');
     
-    this.cases.set(mockCases);
+    this.filteredCases = [...this.cases];
+    this.currentPage = 1;
+    this.updatePagination();
   }
-  
-  // 切换收藏状态(同时更新收藏计数)
-  toggleFavorite(caseId: string): void {
-    this.cases.set(
-      this.cases().map(caseItem => {
-        if (caseItem.id === caseId) {
-          const isFav = !caseItem.isFavorite;
-          const favoriteCount = Math.max(0, caseItem.favoriteCount + (isFav ? 1 : -1));
-          return { ...caseItem, isFavorite: isFav, favoriteCount };
-        }
-        return caseItem;
-      })
-    );
-  }
-  
-  // 查看案例详情(增加浏览量)
-  viewCaseDetails(caseItem: CaseItem): void {
-    this.selectedCase.set(caseItem);
-    // 增加浏览量
-    this.cases.set(
-      this.cases().map(item => 
-        item.id === caseItem.id 
-          ? { ...item, views: item.views + 1 }
-          : item
-      )
-    );
-  }
-  
-  // 关闭案例详情
-  closeCaseDetails(): void {
-    this.selectedCase.set(null);
-  }
-  
-  // 分享案例:生成链接、复制并展示弹窗,同时更新分享计数
-  async shareCase(caseId: string): Promise<void> {
-    const link = this.getShareLink(caseId);
-    this.shareLink.set(link);
-    this.showShareModal.set(true);
-    this.sharedCaseId.set(caseId);
-
-    // 生成二维码
-    await this.generateQrCode(link);
-
-    // 分享计数 +1
-    this.cases.set(
-      this.cases().map(item => item.id === caseId ? { ...item, shareCount: item.shareCount + 1 } : item)
-    );
-
-    // 尝试自动复制
-    try {
-      await navigator.clipboard.writeText(link);
-    } catch {
-      // 忽略复制失败(例如非安全上下文),用户可手动复制
+
+  updatePagination() {
+    this.totalPages = Math.ceil(this.filteredCases.length / this.itemsPerPage);
+    if (this.currentPage > this.totalPages) {
+      this.currentPage = this.totalPages || 1;
     }
   }
 
-  getShareLink(caseId: string): string {
-    const base = window.location.origin;
-    return `${base}/customer-service/case-library?case=${encodeURIComponent(caseId)}`;
+  get paginatedCases(): Case[] {
+    const startIndex = (this.currentPage - 1) * this.itemsPerPage;
+    return this.filteredCases.slice(startIndex, startIndex + this.itemsPerPage);
   }
 
-  async copyShareLink(): Promise<void> {
-    const link = this.shareLink();
-    try {
-      await navigator.clipboard.writeText(link);
-      alert('链接已复制到剪贴板');
-    } catch {
-      alert('复制失败,请手动选择链接复制');
+  nextPage() {
+    if (this.currentPage < this.totalPages) {
+      this.currentPage++;
     }
   }
 
-  // 生成二维码
-  private async generateQrCode(text: string): Promise<void> {
-    try {
-      const url = await QRCode.toDataURL(text, { width: 160, margin: 1 });
-      this.qrDataUrl.set(url);
-    } catch (e) {
-      console.error('生成二维码失败', e);
-      this.qrDataUrl.set('');
+  previousPage() {
+    if (this.currentPage > 1) {
+      this.currentPage--;
     }
   }
 
-  downloadQrCode(): void {
-    const dataUrl = this.qrDataUrl();
-    if (!dataUrl) { return; }
-    const a = document.createElement('a');
-    const name = this.sharedCaseId() ? `${this.sharedCaseId()}-qr.png` : 'case-qr.png';
-    a.href = dataUrl;
-    a.download = name;
-    document.body.appendChild(a);
-    a.click();
-    document.body.removeChild(a);
+  showStatistics() {
+    this.showStatsPanel = !this.showStatsPanel;
   }
 
-  openShareLink(): void {
-    const link = this.shareLink();
-    if (link) {
-      window.open(link, '_blank', 'noopener');
+  viewCaseDetail(caseItem: Case) {
+    // 记录案例查看开始时间
+    this.caseViewStartTimes.set(caseItem.id, Date.now());
+    
+    // 增加浏览次数
+    caseItem.viewCount++;
+    
+    // 记录浏览行为
+    this.recordBehavior('case_view', caseItem.id, {
+      caseName: caseItem.name,
+      designer: caseItem.designer,
+      projectType: caseItem.projectType,
+      spaceType: caseItem.spaceType
+    });
+    
+    // 设置当前选中的案例以显示详情面板
+    this.selectedCase = caseItem;
+  }
+
+  closeCaseDetail() {
+    // 记录案例查看时长
+    if (this.selectedCase) {
+      const viewStartTime = this.caseViewStartTimes.get(this.selectedCase.id);
+      if (viewStartTime) {
+        const viewDuration = Date.now() - viewStartTime;
+        this.recordBehavior('case_view_duration', this.selectedCase.id, {
+          duration: viewDuration,
+          durationSeconds: Math.round(viewDuration / 1000)
+        });
+        this.caseViewStartTimes.delete(this.selectedCase.id);
+      }
     }
+    
+    this.selectedCase = null;
   }
 
-  closeShareModal(): void {
-    this.showShareModal.set(false);
-    this.qrDataUrl.set('');
-    this.sharedCaseId.set(null);
+  toggleFavorite(caseItem: Case) {
+    const wasLiked = caseItem.isFavorite;
+    caseItem.isFavorite = !caseItem.isFavorite;
+    
+    if (caseItem.isFavorite) {
+      caseItem.favoriteCount++;
+      this.showToast('已收藏该案例', 'success');
+      
+      // 记录收藏行为
+      this.recordBehavior('case_favorite', caseItem.id, {
+        action: 'add',
+        caseName: caseItem.name,
+        designer: caseItem.designer
+      });
+    } else {
+      caseItem.favoriteCount = Math.max(0, caseItem.favoriteCount - 1);
+      this.showToast('已取消收藏', 'info');
+      
+      // 记录取消收藏行为
+      this.recordBehavior('case_favorite', caseItem.id, {
+        action: 'remove',
+        caseName: caseItem.name,
+        designer: caseItem.designer
+      });
+    }
   }
-  
-  // 重置筛选条件
-  resetFilters(): void {
-    this.filterForm.reset({
-      style: [],
-      houseType: '',
-      projectType: '',
-      subType: '',
-      renderingLevel: '',
-      price: '',
-      favorite: false,
-      sortBy: 'createdAt'
+
+  shareCase(caseItem: Case) {
+    this.selectedCaseForShare = caseItem;
+    caseItem.shareCount++;
+    
+    // 记录分享行为数据
+    this.recordBehavior('share', caseItem.id, {
+      caseName: caseItem.name,
+      designer: caseItem.designer,
+      projectType: caseItem.projectType
     });
-    this.searchTerm.set('');
-    this.currentPage.set(1);
-  }
-  
-  // 切换筛选面板
-  toggleFilterPanel(): void {
-    this.showFilterPanel.set(!this.showFilterPanel());
-  }
-  
-  // 分页导航
-  goToPage(page: number): void {
-    if (page >= 1 && page <= this.totalPages()) {
-      this.currentPage.set(page);
-    }
   }
-  
-  // 上一页
-  prevPage(): void {
-    this.goToPage(this.currentPage() - 1);
+
+  closeShareModal() {
+    this.selectedCaseForShare = null;
   }
-  
-  // 下一页
-  nextPage(): void {
-    this.goToPage(this.currentPage() + 1);
+
+  generateQRCode(caseItem: Case): string {
+    // 实际项目中应使用二维码生成库,如 qrcode.js
+    const qrData = this.generateShareLink(caseItem);
+    // 这里返回一个模拟的二维码图片
+    const svgContent = `
+      <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
+        <rect width="200" height="200" fill="white"/>
+        <rect x="20" y="20" width="160" height="160" fill="black"/>
+        <rect x="30" y="30" width="140" height="140" fill="white"/>
+        <text x="100" y="105" text-anchor="middle" font-size="12" fill="black">案例二维码</text>
+        <text x="100" y="125" text-anchor="middle" font-size="10" fill="gray">${caseItem.name}</text>
+      </svg>
+    `;
+    // 使用 encodeURIComponent 来正确处理SVG内容
+    const encodedSVG = encodeURIComponent(svgContent);
+    return `data:image/svg+xml;charset=utf-8,${encodedSVG}`;
   }
-  
-  // 格式化日期
-  formatDate(date: Date): string {
-    return new Date(date).toLocaleDateString('zh-CN', {
-      month: '2-digit',
-      day: '2-digit',
-      year: 'numeric'
-    });
+
+  generateShareLink(caseItem: Case): string {
+    return `${window.location.origin}/case/${caseItem.id}?from=share&designer=${encodeURIComponent(caseItem.designer)}`;
   }
-  // 智能页码生成
-  pageNumbers = computed(() => {
-    const pages = [] as number[];
-    const total = this.totalPages();
-    const current = this.currentPage();
-    
-    // 显示当前页及前后2页,加上第一页和最后一页
-    const start = Math.max(1, current - 2);
-    const end = Math.min(total, current + 2);
-    
-    if (start > 1) {
-      pages.push(1);
-      if (start > 2) {
-        pages.push(-1); // 用-1表示省略号
-      }
+
+  copyShareLink() {
+    if (this.selectedCase) {
+      const link = this.generateShareLink(this.selectedCase);
+      navigator.clipboard.writeText(link).then(() => {
+        this.showToast('链接已复制到剪贴板,可直接分享给客户!', 'success');
+        
+        // 记录复制行为
+        this.recordBehavior('copy_link', this.selectedCase!.id, {
+          link: link
+        });
+      }).catch(err => {
+        this.showToast('复制失败,请手动复制链接', 'error');
+        console.error('复制链接失败:', err);
+      });
     }
-    
-    for (let i = start; i <= end; i++) {
-      pages.push(i);
+  }
+
+  shareToWeCom() {
+    if (this.selectedCase) {
+      // 实际项目中应集成企业微信分享SDK
+      const shareData = {
+        title: `${this.selectedCase.name} - ${this.selectedCase.designer}设计作品`,
+        description: `${this.selectedCase.projectType} | ${this.selectedCase.spaceType} | ${this.selectedCase.area}㎡`,
+        link: this.generateShareLink(this.selectedCase),
+        imgUrl: this.selectedCase.coverImage
+      };
+      
+      // 模拟企业微信分享
+      console.log('分享到企业微信:', shareData);
+      this.showToast('已调用企业微信分享', 'success');
+      
+      // 记录企业微信分享行为
+      this.recordBehavior('share_wecom', this.selectedCase.id, shareData);
+      
+      this.closeShareModal();
     }
+  }
+
+  // 新增:行为数据记录方法
+  private recordBehavior(action: string, caseId: string, data?: any) {
+    const behaviorData = {
+      action,
+      caseId,
+      timestamp: new Date().toISOString(),
+      userAgent: navigator.userAgent,
+      data: data || {}
+    };
     
-    if (end < total) {
-      if (end < total - 1) {
-        pages.push(-1); // 用-1表示省略号
-      }
-      pages.push(total);
-    }
+    // 实际项目中应发送到后端API
+    console.log('记录用户行为:', behaviorData);
     
-    return pages;
-  });
-  
-  // 格式化样式显示的辅助方法
-  getStyleDisplay(caseItem: CaseItem | null | undefined): string {
-    if (!caseItem || !caseItem.style) {
-      return '';
-    }
-    return Array.isArray(caseItem.style) ? caseItem.style.join('、') : String(caseItem.style);
+    // 模拟存储到本地(实际应发送到服务器)
+    const behaviors = JSON.parse(localStorage.getItem('caseBehaviors') || '[]');
+    behaviors.push(behaviorData);
+    localStorage.setItem('caseBehaviors', JSON.stringify(behaviors));
   }
 
-  // 获取当前选中案例的样式显示
-  getSelectedCaseStyle(): string {
-    return this.getStyleDisplay(this.selectedCase());
-  }
-  
-  // 修复 onStyleChange 方法中的类型安全问题
-  onStyleChange(style: string, isChecked: boolean): void {
-    const currentStyles = (this.filterForm.get('style')?.value || []) as string[];
-    let updatedStyles: string[];
+  // 新增:显示提示消息
+  private showToast(message: string, type: 'success' | 'error' | 'info' = 'info') {
+    // 实际项目中应使用专业的Toast组件
+    const toast = document.createElement('div');
+    toast.className = `toast toast-${type}`;
+    toast.textContent = message;
+    toast.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      padding: 12px 20px;
+      border-radius: 8px;
+      color: white;
+      font-weight: 500;
+      z-index: 10000;
+      animation: slideIn 0.3s ease;
+      background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
+    `;
     
-    if (isChecked) {
-      // 如果勾选,则添加风格(避免重复)
-      updatedStyles = [...new Set([...currentStyles, style])];
-    } else {
-      // 如果取消勾选,则移除风格
-      updatedStyles = currentStyles.filter(s => s !== style);
-    }
+    document.body.appendChild(toast);
     
-    this.filterForm.patchValue({ style: updatedStyles });
+    setTimeout(() => {
+      toast.style.animation = 'slideOut 0.3s ease';
+      setTimeout(() => document.body.removeChild(toast), 300);
+    }, 3000);
   }
 }

+ 155 - 302
src/app/pages/customer-service/consultation-order/consultation-order.html

@@ -80,171 +80,161 @@
       </button>
     </div>
 
-    <!-- 客户信息卡片 -->
-    <section class="info-card customer-card">
-      <div class="card-header">
-        <div class="header-left">
-          <div class="icon-wrapper customer-icon">
-            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
-              <circle cx="12" cy="7" r="4"></circle>
-            </svg>
-          </div>
-          <div class="header-text">
-            <h2>客户信息</h2>
-            <p>搜索或新建客户档案</p>
-          </div>
-        </div>
-        <div class="header-actions">
-          <div class="order-time" *ngIf="orderTime()">
-            <span class="time-label">下单时间:</span>
-            <span class="time-value">{{ orderTime() }}</span>
-          </div>
-          <button 
-            *ngIf="orderCreationMethod() === 'miniprogram'" 
-            class="btn-primary btn-sm sync-btn" 
-            (click)="syncMiniprogramCustomerInfo()"
-            [disabled]="isSyncing()"
-          >
-            <mat-spinner *ngIf="isSyncing()" diameter="16" class="sync-spinner"></mat-spinner>
-            <svg *ngIf="!isSyncing()" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <polyline points="23 4 23 10 17 10"></polyline>
-              <polyline points="1 20 1 14 7 14"></polyline>
-              <path d="m3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
-            </svg>
-            {{ isSyncing() ? '同步中...' : '同步客户信息' }}
-          </button>
-          <button *ngIf="selectedCustomer()" class="btn-ghost btn-sm" (click)="clearSelectedCustomer()">
-            <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>
-        </div>
-      </div>
-      
-      <div class="card-content">
-        <!-- 客户搜索区域 -->
-        <div *ngIf="!selectedCustomer() && orderCreationMethod() === 'manual'" class="customer-search-section">
-          <div class="search-container">
-            <div class="search-input-wrapper">
-              <svg class="search-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                <circle cx="11" cy="11" r="8"></circle>
-                <path d="m21 21-4.35-4.35"></path>
-              </svg>
+    <!-- 客户信息长条栏 -->
+    <section class="customer-info-bar">
+      <div class="customer-bar-container">
+        <!-- 左侧客户搜索和信息 -->
+        <div class="customer-search-area">
+          @if (!selectedCustomer()) {
+            <div class="search-input-container">
+              <div class="search-icon">
+                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                  <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
+                  <circle cx="12" cy="7" r="4"></circle>
+                </svg>
+              </div>
               <input 
                 type="text" 
                 [ngModel]="searchKeyword()" 
                 (ngModelChange)="searchKeyword.set($event); searchCustomer()"
-                placeholder="输入客户姓名或手机号快速填写..."
-                class="search-input"
+                placeholder="输入客户姓名或手机号快速匹配老客户..."
+                class="customer-search-input"
                 autocomplete="off"
                 (keyup.enter)="quickFillCustomerInfo(searchKeyword())"
               />
               <button 
-                class="quick-fill-btn"
+                class="search-action-btn"
                 (click)="quickFillCustomerInfo(searchKeyword())"
                 [disabled]="!searchKeyword().trim() || isSyncing()"
               >
-                <mat-spinner *ngIf="isSyncing()" diameter="16"></mat-spinner>
-                <span *ngIf="!isSyncing()">快速填写</span>
+                @if (isSyncing()) {
+                  <mat-spinner diameter="16"></mat-spinner>
+                } @else {
+                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                    <path d="M9 11l3 3 8-8"></path>
+                    <path d="M21 12c0 4.97-4.03 9-9 9s-9-4.03-9-9 4.03-9 9-9c1.51 0 2.93.37 4.18 1.03"></path>
+                  </svg>
+                  匹配
+                }
               </button>
             </div>
-            <div class="search-hint">
-              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                <circle cx="12" cy="12" r="10"></circle>
-                <path d="m9 12 2 2 4-4"></path>
-              </svg>
-              <span>直接输入姓名/手机号,按回车或点击"快速填写"自动匹配客户信息</span>
-            </div>
-          </div>
-          
-          <!-- 搜索结果 -->
-          <div *ngIf="searchResults().length > 0" class="search-results">
-            <div class="results-header">
-              <span class="results-count">找到 {{ searchResults().length }} 位客户</span>
-            </div>
-            <div class="customer-list">
-              <div *ngFor="let customer of searchResults()" class="customer-item" (click)="selectCustomer(customer)">
-                <div class="customer-avatar">
-                  <img [src]="customer.avatar" [alt]="customer.name" *ngIf="customer.avatar">
-                  <div *ngIf="!customer.avatar" class="avatar-placeholder">
-                    {{ customer.name.charAt(0) }}
-                  </div>
+            
+            <!-- 搜索结果下拉 -->
+            @if (searchResults().length > 0) {
+              <div class="search-dropdown">
+                <div class="dropdown-header">
+                  <span>找到 {{ searchResults().length }} 位客户</span>
                 </div>
-                <div class="customer-info">
-                  <div class="customer-name">{{ customer.name }}</div>
-                  <div class="customer-phone">{{ customer.phone }}</div>
-                  <div class="customer-tags" *ngIf="customer.customerType || customer.source">
-                    <span *ngIf="customer.customerType" class="tag type-tag">{{ customer.customerType }}</span>
-                    <span *ngIf="customer.source" class="tag source-tag">{{ customer.source }}</span>
+                @for (customer of searchResults(); track customer.id) {
+                  <div class="customer-option" (click)="selectCustomer(customer)">
+                    <div class="customer-avatar-sm">
+                      @if (customer.avatar) {
+                        <img [src]="customer.avatar" [alt]="customer.name">
+                      } @else {
+                        <span>{{ customer.name.charAt(0) }}</span>
+                      }
+                    </div>
+                    <div class="customer-details">
+                      <div class="customer-name">{{ customer.name }}</div>
+                      <div class="customer-phone">{{ customer.phone }}</div>
+                    </div>
+                    <div class="customer-tags">
+                      @if (customer.customerType) {
+                        <span class="tag">{{ customer.customerType }}</span>
+                      }
+                    </div>
                   </div>
-                </div>
-                <div class="select-indicator">
-                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                    <polyline points="9 18 15 12 9 6"></polyline>
-                  </svg>
-                </div>
+                }
               </div>
-            </div>
-          </div>
-        </div>
-        <!-- 客户信息表单 -->
-        <form [formGroup]="customerForm" class="customer-form">
-          <!-- 基本信息组 -->
-          <div class="form-section">
-            <h3 class="section-title">基本信息</h3>
-            <div class="form-grid">
-              <div class="form-field">
-                <label for="name" class="field-label">客户姓名 <span class="required">*</span></label>
-                <input type="text" id="name" formControlName="name" placeholder="请输入客户姓名" class="field-input">
+            }
+          } @else {
+            <!-- 已选择客户信息展示 -->
+            <div class="selected-customer-info">
+              <div class="customer-avatar-lg">
+                @if (selectedCustomer()?.avatar) {
+                  <img [src]="selectedCustomer()?.avatar" [alt]="selectedCustomer()?.name">
+                } @else {
+                  <span>{{ selectedCustomer()?.name?.charAt(0) }}</span>
+                }
               </div>
-              <div class="form-field">
-                <label for="phone" class="field-label">手机号码 <span class="required">*</span></label>
-                <input type="tel" id="phone" formControlName="phone" placeholder="请输入手机号码" class="field-input">
+              <div class="customer-main-info">
+                <div class="customer-name-lg">{{ selectedCustomer()?.name }}</div>
+                <div class="customer-contact">
+                  <span class="phone">{{ selectedCustomer()?.phone }}</span>
+                  @if (selectedCustomer()?.wechat) {
+                    <span class="wechat">微信: {{ selectedCustomer()?.wechat }}</span>
+                  }
+                </div>
               </div>
-              <div class="form-field">
-                <label for="wechat" class="field-label">微信账号 <span class="optional">(可选)</span></label>
-                <input type="text" id="wechat" formControlName="wechat" placeholder="请输入微信账号" class="field-input">
+              <div class="customer-history">
+                <div class="history-item">
+                  <span class="label">合作项目:</span>
+                  <span class="value">3个项目</span>
+                </div>
+                <div class="history-item">
+                  <span class="label">历史反馈:</span>
+                  <span class="value">满意度95%</span>
+                </div>
               </div>
             </div>
-          </div>
-          
-          <!-- 分类信息组 -->
-          <div class="form-section">
-            <h3 class="section-title">分类信息 <span class="section-subtitle">(可选填写,便于客户管理)</span></h3>
-            <div class="form-grid">
-              <div class="form-field">
-                <label for="customerType" class="field-label">客户类型 <span class="optional">(可选)</span></label>
-                <select id="customerType" formControlName="customerType" class="field-select">
-                  <option value="">请选择客户类型</option>
-                  <option value="新客户">新客户</option>
-                  <option value="老客户">老客户</option>
-                  <option value="VIP客户">VIP客户</option>
-                </select>
-              </div>
+          }
+        </div>
+        
+        <!-- 右侧操作按钮 -->
+        <div class="customer-actions">
+          @if (selectedCustomer()) {
+            <button class="action-btn secondary" (click)="clearSelectedCustomer()">
+              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                <path d="M3 6h18"></path>
+                <path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path>
+                <path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path>
+              </svg>
+              重新选择
+            </button>
+          }
+          @if (orderCreationMethod() === 'miniprogram') {
+            <button 
+              class="action-btn primary" 
+              (click)="syncMiniprogramCustomerInfo()"
+              [disabled]="isSyncing()"
+            >
+              @if (isSyncing()) {
+                <mat-spinner diameter="16"></mat-spinner>
+              } @else {
+                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                  <polyline points="23 4 23 10 17 10"></polyline>
+                  <polyline points="1 20 1 14 7 14"></polyline>
+                  <path d="m3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
+                </svg>
+              }
+              {{ isSyncing() ? '同步中...' : '同步小程序' }}
+            </button>
+          }
+        </div>
+      </div>
+    </section>
 
-              <div class="form-field">
-                <label for="demandType" class="field-label">需求类型 <span class="optional">(可选)</span></label>
-                <select id="demandType" formControlName="demandType" class="field-select">
-                  <option value="">请选择需求类型</option>
-                  <option *ngFor="let type of demandTypes" [value]="type.value">{{ type.label }}</option>
-                </select>
-              </div>
-              <div class="form-field">
-                <label for="followUpStatus" class="field-label">跟进状态 <span class="optional">(可选)</span></label>
-                <select id="followUpStatus" formControlName="followUpStatus" class="field-select">
-                  <option value="">请选择跟进状态</option>
-                  <option *ngFor="let status of followUpStatus" [value]="status.value">{{ status.label }}</option>
-                </select>
-              </div>
+    <!-- 新客户快速填写表单 -->
+    @if (!selectedCustomer() && orderCreationMethod() === 'manual') {
+      <section class="new-customer-form">
+        <div class="form-header">
+          <h3>新客户信息</h3>
+          <p>仅需填写基本信息,其他信息可通过企业微信聊天记录补充</p>
+        </div>
+        <form [formGroup]="customerForm" class="simple-customer-form">
+          <div class="form-row">
+            <div class="form-field">
+              <label for="name" class="field-label">客户姓名 <span class="required">*</span></label>
+              <input type="text" id="name" formControlName="name" placeholder="请输入客户姓名" class="field-input">
+            </div>
+            <div class="form-field">
+              <label for="phone" class="field-label">手机号码 <span class="required">*</span></label>
+              <input type="tel" id="phone" formControlName="phone" placeholder="请输入手机号码" class="field-input">
             </div>
           </div>
-          
         </form>
-      </div>
-    </section>
+      </section>
+    }
 
     <!-- 项目需求卡片(可折叠) -->
     <section class="info-card requirement-card" *ngIf="isRequirementCardExpanded()">
@@ -258,7 +248,7 @@
           </div>
           <div class="header-text">
             <h2>项目需求</h2>
-            <p>项目需求、风格、小组匹配等信息</p>
+            <p>项目基本信息配置</p>
           </div>
         </div>
         <div class="header-actions">
@@ -277,176 +267,39 @@
       </div>
 
       <div class="card-content">
-
-       <form [formGroup]="requirementForm" class="requirement-form">
-          <!-- 基础需求组 -->
-          <div class="form-section">
-            <h3 class="section-title">基础需求</h3>
-            <div class="form-grid">
-              <div class="form-field">
-                <label for="style" class="field-label">装修风格 <span class="required">*</span></label>
-                <select id="style" formControlName="style" class="field-select">
-                  <option value="">请选择装修风格</option>
-                  <option *ngFor="let style of styleOptions" [value]="style">{{ style }}</option>
-                </select>
-              </div>
-              <div class="form-field">
-                <label for="budget" class="field-label">预算范围 <span class="required">*</span></label>
-                <select id="budget" formControlName="budget" class="field-select">
-                  <option value="">请选择预算范围</option>
-                  <option value="5-10万">5-10万</option>
-                  <option value="10-20万">10-20万</option>
-                  <option value="20-30万">20-30万</option>
-                  <option value="30-50万">30-50万</option>
-                  <option value="50万以上">50万以上</option>
-                </select>
-              </div>
+        <form [formGroup]="requirementForm" class="requirement-form">
+          <div class="form-grid">
+            <div class="form-field">
+              <label for="style" class="field-label">装修风格 <span class="required">*</span></label>
+              <select id="style" formControlName="style" class="field-select">
+                <option value="">请选择装修风格</option>
+                <option *ngFor="let style of styleOptions" [value]="style">{{ style }}</option>
+              </select>
             </div>
-          </div>
-          
-          
-          <!-- 项目管理组 -->
-          <div class="form-section">
-            <h3 class="section-title">项目管理</h3>
-            <div class="form-grid">
-              <div class="form-field">
-                <label for="projectGroup" class="field-label">项目小组 <span class="required">*</span></label>
-                <select id="projectGroup" formControlName="projectGroup" class="field-select">
-                  <option value="">请选择项目小组</option>
-                  <option *ngFor="let group of projectGroupOptions" [value]="group">{{ group }}</option>
-                </select>
-              </div>
-              <div class="form-field">
-                <label for="firstDraftDate" class="field-label">首稿时间 <span class="required">*</span></label>
-                <input type="date" id="firstDraftDate" formControlName="firstDraftDate" class="field-input">
-              </div>
-              <div class="form-field">
-                <label for="downPayment" class="field-label">首付款 <span class="required">*</span></label>
-                <div class="input-with-unit">
-                  <input type="number" id="downPayment" formControlName="downPayment" placeholder="请输入首付款金额" class="field-input">
-                  <span class="input-unit">元</span>
-                </div>
-              </div>
+            <div class="form-field">
+              <label for="projectGroup" class="field-label">项目小组 <span class="required">*</span></label>
+              <select id="projectGroup" formControlName="projectGroup" class="field-select">
+                <option value="">请选择项目小组</option>
+                <option *ngFor="let group of projectGroupOptions" [value]="group">{{ group }}</option>
+              </select>
             </div>
-            <div class="form-field full-width">
-              <label for="priceDetails" class="field-label">价格明细</label>
-              <textarea id="priceDetails" formControlName="priceDetails" rows="4" placeholder="可通过聊天或复制聊天记录提取价格明细信息" class="field-textarea"></textarea>
+            <div class="form-field">
+              <label for="firstDraftDate" class="field-label">首稿时间 <span class="required">*</span></label>
+              <input type="date" id="firstDraftDate" formControlName="firstDraftDate" class="field-input">
             </div>
-          </div>
-
-          <!-- 其他需求组 -->
-          <div class="form-section">
-            <h3 class="section-title">其他需求</h3>
-            <div class="form-grid">
-              <div class="form-field">
-                <label for="preferredDesigner" class="field-label">意向设计师</label>
-                <input type="text" id="preferredDesigner" formControlName="preferredDesigner" placeholder="请输入意向设计师姓名" class="field-input">
+            <div class="form-field">
+              <label for="downPayment" class="field-label">首付款 <span class="required">*</span></label>
+              <div class="input-with-unit">
+                <input type="number" id="downPayment" formControlName="downPayment" placeholder="请输入首付款金额" class="field-input">
+                <span class="input-unit">元</span>
               </div>
             </div>
-            <div class="form-field full-width">
-              <label for="specialRequirements" class="field-label">特殊需求</label>
-              <textarea id="specialRequirements" formControlName="specialRequirements" rows="4" placeholder="请详细描述特殊需求或关注点" class="field-textarea"></textarea>
-            </div>
           </div>
         </form>
       </div>
     </section>
 
-    <!-- 报价与案例匹配卡片 -->
-    <section class="info-card price-match-card">
-      <div class="card-header">
-        <div class="header-left">
-          <div class="icon-wrapper price-icon">
-            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <rect x="2" y="6" width="20" height="12" rx="2"></rect>
-              <path d="M12 6v4"></path>
-              <path d="M2 10h20"></path>
-            </svg>
-          </div>
-          <div class="header-text">
-            <h2>报价与案例匹配</h2>
-            <p>智能匹配相似案例和预估报价</p>
-          </div>
-        </div>
-      </div>
-      
-      <div class="card-content">
-        <!-- 预估报价区域 -->
-        <div class="price-section">
-          <div class="price-card">
-            <div class="price-header">
-              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                <circle cx="12" cy="12" r="10"></circle>
-                <path d="M12 6v6l4 2"></path>
-              </svg>
-              <span>预估报价范围</span>
-            </div>
-            <div class="price-value">
-              {{ estimatedPriceRange() || '请填写需求信息以获取报价' }}
-            </div>
-          </div>
-        </div>
-        
-        <!-- 匹配案例区域 -->
-        <div class="cases-section" *ngIf="matchedCases().length > 0">
-          <div class="section-header">
-            <h3>推荐案例</h3>
-            <span class="section-subtitle">点击选择参考案例</span>
-          </div>
-          <div class="cases-grid">
-            <div *ngFor="let caseItem of matchedCases()" class="case-card" (click)="selectReferenceCase(caseItem)">
-              <div class="case-image-wrapper">
-                <img [src]="caseItem.imageUrl" [alt]="caseItem.name" class="case-image">
-                <div class="similarity-badge">{{ caseItem.similarity }}%</div>
-              </div>
-              <div class="case-content">
-                <h4 class="case-name">{{ caseItem.name }}</h4>
-                <div class="case-meta">
-                  <span class="case-designer">
-                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                      <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
-                      <circle cx="12" cy="7" r="4"></circle>
-                    </svg>
-                    {{ caseItem.designer }}
-                  </span>
-                  <span class="case-area">
-                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                      <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
-                    </svg>
-                    {{ caseItem.area }}
-                  </span>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-        
-        <!-- 已选案例区域 -->
-        <div *ngIf="requirementForm.get('referenceCases')?.value.length > 0" class="selected-cases-section">
-          <div class="section-header">
-            <h3>已选参考案例</h3>
-            <span class="section-subtitle">{{ requirementForm.get('referenceCases')?.value.length }} 个案例</span>
-          </div>
-          <div class="selected-cases-list">
-            <div *ngFor="let caseId of requirementForm.get('referenceCases')?.value" class="selected-case-item">
-              <div class="case-info">
-                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                  <path d="M9 11l3 3 8-8"></path>
-                  <path d="M21 12c0 4.97-4.03 9-9 9s-9-4.03-9-9 4.03-9 9-9c1.51 0 2.93.37 4.18 1.03"></path>
-                </svg>
-                <span>案例 #{{ caseId }}</span>
-              </div>
-              <button class="remove-case-btn" (click)="removeReferenceCase(caseId)">
-                <svg width="14" height="14" 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>
-            </div>
-          </div>
-        </div>
-      </div>
-    </section>
+
 
     <section class="action-section">
       <div class="action-buttons">

+ 737 - 0
src/app/pages/customer-service/consultation-order/consultation-order.scss

@@ -36,6 +36,542 @@ $card-padding: 16px;
   }
 }
 
+// 客户信息长条栏样式
+.customer-info-bar {
+  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+  border-radius: 16px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+  padding: 24px;
+  margin-bottom: 24px;
+  border: 1px solid rgba(0, 122, 255, 0.1);
+  transition: all 0.3s ease;
+  
+  &:hover {
+    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
+    transform: translateY(-1px);
+  }
+  
+  .customer-bar-container {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    gap: 24px;
+    
+    @media (max-width: 768px) {
+      flex-direction: column;
+      gap: 16px;
+    }
+  }
+  
+  .customer-search-area {
+    flex: 1;
+    position: relative;
+    
+    .search-input-container {
+      display: flex;
+      align-items: center;
+      background: #ffffff;
+      border: 2px solid #e5e5ea;
+      border-radius: 12px;
+      padding: 12px 16px;
+      transition: all 0.3s ease;
+      
+      &:focus-within {
+        border-color: #007AFF;
+        box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1);
+      }
+      
+      .search-icon {
+        color: #8e8e93;
+        margin-right: 12px;
+        
+        svg {
+          width: 20px;
+          height: 20px;
+        }
+      }
+      
+      .customer-search-input {
+        flex: 1;
+        border: none;
+        outline: none;
+        font-size: 16px;
+        color: #1d1d1f;
+        background: transparent;
+        
+        &::placeholder {
+          color: #8e8e93;
+        }
+      }
+      
+      .search-action-btn {
+        background: #007AFF;
+        color: white;
+        border: none;
+        border-radius: 8px;
+        padding: 8px 16px;
+        font-size: 14px;
+        font-weight: 500;
+        cursor: pointer;
+        transition: all 0.3s ease;
+        display: flex;
+        align-items: center;
+        gap: 6px;
+        
+        &:hover {
+          background: #0062CC;
+          transform: translateY(-1px);
+        }
+        
+        &:disabled {
+          background: #d1d1d6;
+          cursor: not-allowed;
+          transform: none;
+        }
+      }
+    }
+    
+    // 搜索结果下拉
+    .search-dropdown {
+      position: absolute;
+      top: 100%;
+      left: 0;
+      right: 0;
+      background: white;
+      border-radius: 12px;
+      box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
+      border: 1px solid #e5e5ea;
+      margin-top: 8px;
+      z-index: 1000;
+      max-height: 300px;
+      overflow-y: auto;
+      
+      .dropdown-header {
+        padding: 12px 16px;
+        border-bottom: 1px solid #f2f2f7;
+        font-size: 14px;
+        color: #8e8e93;
+        font-weight: 500;
+      }
+      
+      .customer-option {
+        display: flex;
+        align-items: center;
+        padding: 12px 16px;
+        cursor: pointer;
+        transition: all 0.2s ease;
+        
+        &:hover {
+          background: #f2f2f7;
+        }
+        
+        .customer-avatar-sm {
+          width: 40px;
+          height: 40px;
+          border-radius: 50%;
+          background: #007AFF;
+          color: white;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          font-weight: 600;
+          margin-right: 12px;
+          
+          img {
+            width: 100%;
+            height: 100%;
+            border-radius: 50%;
+            object-fit: cover;
+          }
+        }
+        
+        .customer-details {
+          flex: 1;
+          
+          .customer-name {
+            font-weight: 600;
+            color: #1d1d1f;
+            margin-bottom: 2px;
+          }
+          
+          .customer-phone {
+            font-size: 14px;
+            color: #8e8e93;
+          }
+        }
+        
+        .customer-tags {
+          .tag {
+            background: #e5f4ff;
+            color: #007AFF;
+            padding: 4px 8px;
+            border-radius: 6px;
+            font-size: 12px;
+            font-weight: 500;
+          }
+        }
+      }
+    }
+    
+    // 已选择客户信息展示
+    .selected-customer-info {
+      display: flex;
+      align-items: center;
+      gap: 16px;
+      
+      .customer-avatar-lg {
+        width: 60px;
+        height: 60px;
+        border-radius: 50%;
+        background: #007AFF;
+        color: white;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-weight: 700;
+        font-size: 24px;
+        
+        img {
+          width: 100%;
+          height: 100%;
+          border-radius: 50%;
+          object-fit: cover;
+        }
+      }
+      
+      .customer-main-info {
+        flex: 1;
+        
+        .customer-name-lg {
+          font-size: 20px;
+          font-weight: 700;
+          color: #1d1d1f;
+          margin-bottom: 4px;
+        }
+        
+        .customer-contact {
+          display: flex;
+          gap: 16px;
+          
+          .phone, .wechat {
+            font-size: 14px;
+            color: #8e8e93;
+          }
+        }
+      }
+      
+      .customer-history {
+        display: flex;
+        flex-direction: column;
+        gap: 4px;
+        
+        .history-item {
+          display: flex;
+          gap: 8px;
+          font-size: 14px;
+          
+          .label {
+            color: #8e8e93;
+            font-weight: 500;
+          }
+          
+          .value {
+            color: #007AFF;
+            font-weight: 600;
+          }
+        }
+      }
+    }
+  }
+  
+  .customer-actions {
+    display: flex;
+    gap: 12px;
+    
+    .action-btn {
+      padding: 10px 16px;
+      border-radius: 8px;
+      font-size: 14px;
+      font-weight: 500;
+      cursor: pointer;
+      transition: all 0.3s ease;
+      display: flex;
+      align-items: center;
+      gap: 6px;
+      border: none;
+      
+      &.primary {
+        background: #007AFF;
+        color: white;
+        
+        &:hover {
+          background: #0062CC;
+          transform: translateY(-1px);
+        }
+      }
+      
+      &.secondary {
+        background: #f2f2f7;
+        color: #8e8e93;
+        
+        &:hover {
+          background: #e5e5ea;
+          color: #1d1d1f;
+        }
+      }
+      
+      &:disabled {
+        opacity: 0.5;
+        cursor: not-allowed;
+        transform: none;
+      }
+    }
+  }
+}
+
+// 新客户表单样式
+.new-customer-form {
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
+  padding: 24px;
+  margin-bottom: 24px;
+  border: 1px solid #f2f2f7;
+  max-width: 100%;
+  overflow: hidden; // 防止内容溢出
+  
+  .form-header {
+    margin-bottom: 20px;
+    
+    h3 {
+      font-size: 18px;
+      font-weight: 600;
+      color: #1d1d1f;
+      margin: 0 0 6px 0;
+    }
+    
+    p {
+      font-size: 14px;
+      color: #8e8e93;
+      margin: 0;
+      line-height: 1.4;
+    }
+  }
+  
+  .simple-customer-form {
+    .form-row {
+      display: grid;
+      grid-template-columns: 1fr 1fr;
+      gap: 20px;
+      align-items: start;
+      width: 100%;
+      
+      @media (max-width: 992px) {
+        gap: 16px;
+      }
+      
+      @media (max-width: 768px) {
+        grid-template-columns: 1fr;
+        gap: 16px;
+      }
+      
+      @media (max-width: 480px) {
+        gap: 12px;
+      }
+    }
+    
+    .form-field {
+      display: flex;
+      flex-direction: column;
+      min-width: 0; // 防止flex项目溢出
+      
+      .field-label {
+        display: block;
+        font-size: 14px;
+        font-weight: 500;
+        color: #1d1d1f;
+        margin-bottom: 8px;
+        white-space: nowrap;
+        
+        .required {
+          color: #ff3b30;
+        }
+      }
+      
+      .field-input {
+        width: 100%;
+        min-width: 0; // 防止输入框溢出
+        padding: 12px 16px;
+        border: 2px solid #e5e5ea;
+        border-radius: 8px;
+        font-size: 16px;
+        transition: all 0.3s ease;
+        background: white;
+        box-sizing: border-box; // 确保padding不会导致溢出
+        
+        &:focus {
+          outline: none;
+          border-color: #007AFF;
+          box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1);
+        }
+        
+        &::placeholder {
+          color: #8e8e93;
+        }
+        
+        &:invalid {
+          border-color: #ff3b30;
+        }
+      }
+    }
+  }
+}
+
+// 项目配置卡片样式
+.project-config-card {
+  background: white;
+  border-radius: 16px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+  padding: 24px;
+  margin-bottom: 24px;
+  border: 1px solid rgba(0, 122, 255, 0.1);
+  
+  .config-header {
+    margin-bottom: 24px;
+    
+    h2 {
+      font-size: 20px;
+      font-weight: 700;
+      color: #1d1d1f;
+      margin: 0 0 4px 0;
+    }
+    
+    p {
+      font-size: 14px;
+      color: #8e8e93;
+      margin: 0;
+    }
+  }
+  
+  .project-config-form {
+    .config-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+      gap: 20px;
+      
+      @media (max-width: 768px) {
+        grid-template-columns: 1fr;
+      }
+    }
+    
+    .config-item {
+      background: #f8f9fa;
+      border-radius: 12px;
+      padding: 16px;
+      border: 1px solid #e5e5ea;
+      transition: all 0.3s ease;
+      
+      &:hover {
+        border-color: #007AFF;
+        box-shadow: 0 4px 12px rgba(0, 122, 255, 0.1);
+      }
+      
+      .config-label {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        margin-bottom: 12px;
+        font-size: 14px;
+        font-weight: 600;
+        color: #1d1d1f;
+        
+        svg {
+          color: #007AFF;
+        }
+      }
+      
+      .config-select, .config-input {
+        width: 100%;
+        padding: 10px 12px;
+        border: 1px solid #d1d1d6;
+        border-radius: 8px;
+        font-size: 14px;
+        background: white;
+        transition: all 0.3s ease;
+        
+        &:focus {
+          outline: none;
+          border-color: #007AFF;
+          box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.1);
+        }
+      }
+      
+      .payment-input-group {
+        display: flex;
+        align-items: center;
+        background: white;
+        border: 1px solid #d1d1d6;
+        border-radius: 8px;
+        overflow: hidden;
+        transition: all 0.3s ease;
+        
+        &:focus-within {
+          border-color: #007AFF;
+          box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.1);
+        }
+        
+        .payment-input {
+          flex: 1;
+          border: none;
+          padding: 10px 12px;
+          
+          &:focus {
+            outline: none;
+            box-shadow: none;
+          }
+        }
+        
+        .currency-unit {
+          padding: 10px 12px;
+          background: #f2f2f7;
+          color: #8e8e93;
+          font-size: 14px;
+          font-weight: 500;
+        }
+      }
+      
+      .confirmation-group {
+        .confirmation-checkbox {
+          display: flex;
+          align-items: center;
+          gap: 8px;
+          cursor: pointer;
+          
+          input[type="checkbox"] {
+            width: 18px;
+            height: 18px;
+            accent-color: #007AFF;
+          }
+          
+          .checkbox-text {
+            font-size: 14px;
+            color: #1d1d1f;
+          }
+        }
+      }
+      
+      .payment-details {
+        display: flex;
+        gap: 8px;
+        
+        .small {
+          flex: 1;
+        }
+      }
+    }
+  }
+}
+
 // 主表单容器 - dashboard卡片风格
 .order-form {
   background-color: #ffffff;
@@ -462,6 +998,9 @@ $card-padding: 16px;
   border-bottom: 1px solid rgba(0, 0, 0, 0.08);
   background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%);
   position: relative;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
   
   &::after {
     content: '';
@@ -488,6 +1027,38 @@ $card-padding: 16px;
     gap: 12px;
   }
   
+  .header-actions {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    flex-shrink: 0;
+    
+    @media (max-width: 768px) {
+      gap: 8px;
+      flex-direction: column-reverse;
+      align-items: flex-end;
+    }
+    
+    @media (max-width: 480px) {
+      flex-direction: row;
+      gap: 6px;
+      
+      .btn-sm {
+        padding: 6px 12px;
+        font-size: 13px;
+        
+        svg {
+          width: 14px;
+          height: 14px;
+        }
+        
+        span {
+          display: none;
+        }
+      }
+    }
+  }
+  
   .icon-wrapper {
     width: 32px;
     height: 32px;
@@ -1633,6 +2204,172 @@ $card-padding: 16px;
   }
 }
 
+// 现代化按钮样式
+.btn-ghost {
+  background: rgba(255, 255, 255, 0.8);
+  border: 1px solid rgba(0, 0, 0, 0.08);
+  color: #6b7280;
+  font-weight: 500;
+  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+  backdrop-filter: blur(8px);
+  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.4), transparent);
+    transition: left 0.5s ease;
+  }
+  
+  &:hover {
+    background: rgba(248, 250, 252, 0.95);
+    border-color: rgba(0, 0, 0, 0.12);
+    color: #374151;
+    transform: translateY(-1px);
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+    
+    &::before {
+      left: 100%;
+    }
+  }
+  
+  &:active {
+    transform: translateY(0);
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06);
+  }
+}
+
+.btn-sm {
+  padding: 8px 16px;
+  font-size: 14px;
+  border-radius: 8px;
+  display: inline-flex;
+  align-items: center;
+  gap: 6px;
+  cursor: pointer;
+  border: none;
+  outline: none;
+  
+  svg {
+    width: 16px;
+    height: 16px;
+    transition: transform 0.2s ease;
+  }
+  
+  &:hover svg {
+    transform: scale(1.1);
+  }
+}
+
+// 专门的收起按钮样式
+.btn-ghost.btn-sm {
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+  
+  &:hover {
+    color: #ef4444;
+    border-color: rgba(239, 68, 68, 0.2);
+    background: rgba(254, 242, 242, 0.8);
+    
+    svg {
+      transform: rotate(90deg) scale(1.1);
+    }
+  }
+  
+  &:focus {
+    outline: none;
+    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
+  }
+  
+  &:active {
+    transform: translateY(0) scale(0.98);
+    
+    svg {
+      transform: rotate(90deg) scale(1.05);
+    }
+  }
+}
+
+// 专门的提取按钮样式
+.btn-primary.btn-sm {
+  background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
+  color: white;
+  border: none;
+  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.25);
+  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:not(:disabled) {
+    transform: translateY(-2px);
+    box-shadow: 0 6px 20px rgba(59, 130, 246, 0.4);
+    background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
+    
+    &::before {
+      left: 100%;
+    }
+  }
+  
+  &:active:not(:disabled) {
+    transform: translateY(-1px);
+    box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
+  }
+  
+  &:focus {
+    outline: none;
+    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2), 0 2px 8px rgba(59, 130, 246, 0.25);
+  }
+  
+  &:disabled {
+    opacity: 0.6;
+    cursor: not-allowed;
+    transform: none;
+    box-shadow: 0 2px 4px rgba(59, 130, 246, 0.15);
+    
+    &::before {
+      display: none;
+    }
+  }
+  
+  mat-spinner {
+    width: 16px !important;
+    height: 16px !important;
+    
+    ::ng-deep circle {
+      stroke: white;
+      stroke-width: 3;
+    }
+  }
+  
+  // 加载状态的脉冲效果
+  &:disabled mat-spinner {
+    animation: pulse 1.5s ease-in-out infinite;
+  }
+}
+
+@keyframes pulse {
+  0%, 100% {
+    opacity: 1;
+  }
+  50% {
+    opacity: 0.7;
+  }
+}
+
 // iOS风格操作按钮区域
 .action-section {
   background-color: $background-tertiary;

+ 136 - 9
src/app/pages/customer-service/consultation-order/consultation-order.ts

@@ -113,23 +113,36 @@ export class ConsultationOrder {
   requirementForm: FormGroup;
   // 客户表单
   customerForm: FormGroup;
+  // 项目配置表单
+  projectForm: FormGroup;
 
   // 样式选项
   styleOptions = [
     '现代简约', '北欧风', '工业风', '新中式', '法式轻奢', '日式', '美式', '混搭'
   ];
   
-  // 户型选项
-  houseTypeOptions = [
-    '一室一厅', '两室一厅', '两室两厅', '三室一厅', '三室两厅', '四室两厅', '复式', '别墅', '其他'
-  ];
-  
-  // 装修类型选项
-  decorationTypeOptions = [
-    '全包', '半包', '清包', '旧房翻新', '局部改造'
+  // 装修风格选项(用于项目配置)
+  decorationStyles = [
+    { value: 'modern', label: '现代简约' },
+    { value: 'nordic', label: '北欧风' },
+    { value: 'industrial', label: '工业风' },
+    { value: 'chinese', label: '新中式' },
+    { value: 'french', label: '法式轻奢' },
+    { value: 'japanese', label: '日式' },
+    { value: 'american', label: '美式' },
+    { value: 'mixed', label: '混搭' }
   ];
 
   // 项目小组选项
+  projectGroups = [
+    { value: 'design1', label: '设计一组' },
+    { value: 'design2', label: '设计二组' },
+    { value: 'design3', label: '设计三组' },
+    { value: 'premium', label: '高端定制组' },
+    { value: 'soft', label: '软装设计组' }
+  ];
+
+  // 项目小组选项(兼容性)
   projectGroupOptions = [
     '设计一组', '设计二组', '设计三组', '高端定制组', '软装设计组'
   ];
@@ -148,7 +161,7 @@ export class ConsultationOrder {
     private snackBar: MatSnackBar,
     private dialog: MatDialog
   ) {
-    // 初始化需求表单
+    // 初始化需求表单(保留兼容性)
     this.requirementForm = this.fb.group({
       style: ['', Validators.required],
       budget: ['', Validators.required],
@@ -178,6 +191,16 @@ export class ConsultationOrder {
       followUpStatus: ['']
     });
 
+    // 初始化项目配置表单
+    this.projectForm = this.fb.group({
+      style: ['', Validators.required], // 风格选择
+      projectGroup: ['', Validators.required], // 项目组匹配
+      downPaymentSetting: ['', Validators.required], // 首付款设置
+      downPaymentAmount: ['', [Validators.required, Validators.min(0)]], // 首付款填写
+      firstDraftConfirm: [false, Validators.requiredTrue], // 首稿时间确认
+      firstDraftDate: ['', Validators.required] // 首稿时间设置
+    });
+
     // 自动生成下单时间
     this.orderTime.set(new Date().toLocaleString('zh-CN', {
       year: 'numeric',
@@ -262,6 +285,12 @@ export class ConsultationOrder {
       source: customer.source || '',
       remark: customer.remark || ''
     });
+    
+    // 如果是老客户,自动填充历史信息
+    if (customer.customerType === '老客户' || customer.customerType === 'VIP客户') {
+      this.loadCustomerHistory(customer.id);
+    }
+    
     // 清空搜索结果
     this.searchResults.set([]);
     this.searchKeyword.set('');
@@ -624,4 +653,102 @@ export class ConsultationOrder {
       this.snackBar.open('客户信息填写完成', '确定', { duration: 2000 });
     }, 1000);
   }
+
+  // 加载客户历史信息
+  loadCustomerHistory(customerId: string) {
+    // 模拟加载客户历史信息
+    const mockHistory = {
+      projects: [
+        { id: '1', name: '三室两厅装修', style: '现代简约', status: '已完成' },
+        { id: '2', name: '厨房改造', style: '北欧风', status: '进行中' }
+      ],
+      feedback: [
+        '对设计师服务很满意',
+        '希望能加快施工进度',
+        '材料质量很好'
+      ],
+      preferences: {
+        style: 'modern',
+        projectGroup: 'design1'
+      }
+    };
+
+    // 根据历史偏好预填充项目配置
+    if (mockHistory.preferences) {
+      this.projectForm.patchValue({
+        style: mockHistory.preferences.style,
+        projectGroup: mockHistory.preferences.projectGroup
+      });
+    }
+
+    this.snackBar.open('已自动填充客户历史偏好信息', '关闭', {
+      duration: 3000,
+      horizontalPosition: 'center',
+      verticalPosition: 'top'
+    });
+  }
+
+  // 创建新客户
+  createNewCustomer() {
+    // 重置表单为新客户状态
+    this.selectedCustomer.set(null);
+    this.customerForm.reset({
+      customerType: '新客户'
+    });
+    this.projectForm.reset();
+    this.searchKeyword.set('');
+    this.searchResults.set([]);
+  }
+
+  // 验证项目配置表单
+  isProjectFormValid(): boolean {
+    return this.projectForm.valid && this.customerForm.valid;
+  }
+
+  // 获取首付款设置选项
+  getDownPaymentOptions() {
+    return [
+      { value: '30', label: '30%' },
+      { value: '50', label: '50%' },
+      { value: '70', label: '70%' },
+      { value: 'custom', label: '自定义' }
+    ];
+  }
+
+  // 提交简化的订单
+  submitSimplifiedOrder() {
+    if (!this.isProjectFormValid()) {
+      this.snackBar.open('请完善必填信息', '关闭', {
+        duration: 3000,
+        horizontalPosition: 'center',
+        verticalPosition: 'top'
+      });
+      return;
+    }
+
+    this.isSubmitting.set(true);
+
+    const orderData = {
+      customer: this.customerForm.value,
+      project: this.projectForm.value,
+      orderTime: this.orderTime()
+    };
+
+    // 模拟提交
+    setTimeout(() => {
+      this.isSubmitting.set(false);
+      this.showSuccessMessage.set(true);
+      
+      this.snackBar.open('订单创建成功!', '关闭', {
+        duration: 3000,
+        horizontalPosition: 'center',
+        verticalPosition: 'top'
+      });
+
+      // 3秒后隐藏成功消息
+      setTimeout(() => {
+        this.showSuccessMessage.set(false);
+      }, 3000);
+    }, 2000);
+  }
 }

+ 2 - 1
src/app/pages/customer-service/customer-service-layout/customer-service-layout.html

@@ -105,7 +105,6 @@
         </svg>
         <span>项目列表</span>
       </a>
-
       <a routerLink="/customer-service/case-library" class="nav-item" routerLinkActive="active">
         <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
           <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
@@ -113,6 +112,8 @@
         </svg>
         <span>案例库</span>
       </a>
+
+
     </nav>
     
     <div class="sidebar-footer">

+ 17 - 0
src/app/pages/customer-service/project-list/project-list.html

@@ -29,6 +29,7 @@
           <div class="view-toggle">
             <button [class.active]="viewMode() === 'card'" (click)="toggleView('card')">卡片</button>
             <button [class.active]="viewMode() === 'list'" (click)="toggleView('list')">列表</button>
+            <button [class.active]="viewMode() === 'dashboard'" (click)="toggleView('dashboard')">监控大盘</button>
           </div>
           <button class="add-project-btn" (click)="openCreateProjectModal()">
             <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
@@ -279,5 +280,21 @@
           </div>
         </div>
       }
+
+      <!-- 视图:监控大盘模式 -->
+      @if (viewMode() === 'dashboard') {
+        <div class="dashboard-container">
+          <!-- 使用iframe嵌入组长端监控大盘,通过CSS隐藏待办任务栏 -->
+          <iframe 
+            src="/team-leader/dashboard" 
+            frameborder="0" 
+            width="100%" 
+            height="100%"
+            style="min-height: 800px;"
+            title="项目监控大盘"
+            onload="const doc = this.contentDocument; doc.querySelector('.todo-section').style.display = 'none'; const header = doc.querySelector('.dashboard-header h1'); if (header && header.textContent.includes('设计组长工作台')) { header.style.display = 'none'; doc.querySelector('.dashboard-metrics').style.marginTop = '20px'; }">
+          </iframe>
+        </div>
+      }
     </div>
 </div>

+ 38 - 0
src/app/pages/customer-service/project-list/project-list.scss

@@ -1158,4 +1158,42 @@ $transition: all 0.3s ease;
 
 .modal .modal-footer .btn-primary:active {
   background: #0E42CB;
+}
+
+// 监控大盘视图样式
+.dashboard-container {
+  width: 100%;
+  height: 100%;
+  min-height: 800px;
+  border: none;
+  
+  iframe {
+    width: 100%;
+    height: 100%;
+    min-height: 800px;
+    border: none;
+    border-radius: 8px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  }
+}
+
+// 视图切换按钮样式优化
+.view-toggle-buttons {
+  .btn-view-toggle {
+    &.active {
+      background-color: $primary-color;
+      color: white;
+      
+      // 监控大盘按钮特殊样式
+      &[data-view="dashboard"] {
+        background-color: #9c27b0; // 紫色主题色
+        border-color: #9c27b0;
+        
+        &:hover {
+          background-color: #7b1fa2;
+          border-color: #7b1fa2;
+        }
+      }
+    }
+  }
 }

+ 5 - 5
src/app/pages/customer-service/project-list/project-list.ts

@@ -27,8 +27,8 @@ export class ProjectList implements OnInit {
   // 原始项目数据(用于筛选)
   allProjects = signal<Project[]>([]);
 
-  // 视图模式:卡片 / 列表(默认卡片)
-  viewMode = signal<'card' | 'list'>('card');
+  // 视图模式:卡片 / 列表 / 监控大盘(默认卡片)
+  viewMode = signal<'card' | 'list' | 'dashboard'>('card');
 
   // 看板列配置
   columns = [
@@ -106,14 +106,14 @@ export class ProjectList implements OnInit {
   ngOnInit(): void {
     // 读取上次的视图记忆
     const saved = localStorage.getItem('cs.viewMode');
-    if (saved === 'card' || saved === 'list') {
-      this.viewMode.set(saved);
+    if (saved === 'card' || saved === 'list' || saved === 'dashboard') {
+      this.viewMode.set(saved as 'card' | 'list' | 'dashboard');
     }
     this.loadProjects();
   }
   
   // 视图切换
-  toggleView(mode: 'card' | 'list') {
+  toggleView(mode: 'card' | 'list' | 'dashboard') {
     if (this.viewMode() !== mode) {
       this.viewMode.set(mode);
       localStorage.setItem('cs.viewMode', mode);

+ 2 - 2
src/app/pages/designer/project-detail/project-detail.html

@@ -80,7 +80,7 @@
                       @for (tag of project.customerTags; track $index) {
                         <span class="tag">{{ tag.source }} · {{ tag.needType }} · {{ tag.preference }} · {{ tag.colorAtmosphere }}</span>
                       }
-                      @if (project.customerTags?.length === 0) { <span class="desc">暂无标签</span> }
+                      @if (project.customerTags.length === 0) { <span class="desc">暂无标签</span> }
                     </div>
                   </div>
                   <div class="tag-section">
@@ -89,7 +89,7 @@
                       @for (need of project.highPriorityNeeds; track $index) {
                         <li>{{ need }}</li>
                       }
-                      @if (project.highPriorityNeeds?.length === 0) { <li class="desc">无</li> }
+                      @if (project.highPriorityNeeds.length === 0) { <li class="desc">无</li> }
                     </ul>
                   </div>
                 </div>

+ 311 - 215
src/app/pages/hr/dashboard/dashboard.html

@@ -1,245 +1,341 @@
-<div class="dashboard-container">
-  <header class="page-header">
-    <h1>人事看板</h1>
-    <p class="page-description">人事数据总览,聚焦入职/离职动态、绩效核心指标、风险预警三大维度</p>
-  </header>
-
-  <!-- 时间维度筛选 -->
-  <div class="filter-bar">
-    <div class="time-filter">
-      <span class="filter-label">时间维度:</span>
-      <div class="filter-buttons">
-        <button mat-button [class.active]="timeFilter() === 'day'" (click)="changeTimeFilter('day')">日</button>
-        <button mat-button [class.active]="timeFilter() === 'week'" (click)="changeTimeFilter('week')">周</button>
-        <button mat-button [class.active]="timeFilter() === 'month'" (click)="changeTimeFilter('month')">月</button>
-      </div>
+<div class="hr-dashboard-container">
+  <!-- 顶部导航按钮 -->
+  <div class="top-navigation">
+    <div class="nav-buttons">
+      <button 
+        mat-raised-button 
+        [class.active]="activeTab === 'visualization'"
+        (click)="switchTab('visualization')"
+        class="nav-button">
+        <mat-icon>analytics</mat-icon>
+        数据可视化
+      </button>
+      <button 
+        mat-raised-button 
+        [class.active]="activeTab === 'promotion'"
+        (click)="switchTab('promotion')"
+        class="nav-button">
+        <mat-icon>trending_up</mat-icon>
+        职级与晋升管理
+      </button>
+      <button 
+        mat-raised-button 
+        [class.active]="activeTab === 'onboarding'"
+        (click)="switchTab('onboarding')"
+        class="nav-button">
+        <mat-icon>person_add</mat-icon>
+        新人跟进管理
+      </button>
     </div>
   </div>
 
-  <!-- 主内容区 -->
-  <div class="dashboard-content">
-    <!-- 入职离职看板 -->
-    <mat-card class="dashboard-card">
-      <mat-card-header>
-        <mat-card-title>
-          <div class="card-title-container">
-            <mat-icon>trending_up</mat-icon>
-            <span>入职离职看板</span>
-          </div>
-        </mat-card-title>
-      </mat-card-header>
-      <mat-card-content>
-        <div class="card-section">
-          <h3>月度入职离职数据</h3>
-          <!-- 用 ECharts 展示分组柱状图(入职/离职) -->
-          <div id="hrMovementChart" class="chart-container"></div>
-        </div>
+  <!-- 数据可视化页面 -->
+  @if (activeTab === 'visualization') {
+    <div class="visualization-page">
+      <div class="main-layout">
+        <!-- 左侧数据展示区域 -->
+        <div class="left-panel">
+          <!-- 职级分布饼图 -->
+          <mat-card class="chart-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>pie_chart</mat-icon>
+                职级分布
+              </mat-card-title>
+              <mat-card-subtitle>设计师职级占比分析</mat-card-subtitle>
+            </mat-card-header>
+            <mat-card-content>
+              <div class="pie-chart-container">
+                <canvas #pieChart></canvas>
+              </div>
+              <div class="chart-legend">
+                @for (item of rankDistribution; track item.level) {
+                  <div class="legend-item">
+                    <div class="legend-color" [style.background-color]="item.color"></div>
+                    <span>{{item.level}}: {{item.percentage}}% ({{item.count}}人)</span>
+                  </div>
+                }
+              </div>
+            </mat-card-content>
+          </mat-card>
 
-        <div class="card-section">
-          <h3>流程进度追踪</h3>
-          <div class="process-tracking">
-            @for (process of pendingProcesses(); track process) {
-              <div class="process-item">
-                <div class="process-header">
-                  <span class="process-title">
-                    {{process.type === 'hire' ? '待审核入职申请' : '待办理离职手续'}}
-                  </span>
-                  <span class="process-count">{{process.count}}个</span>
-                </div>
-                <mat-progress-bar [value]="process.progress" color="primary"></mat-progress-bar>
-                <button mat-button color="primary" class="process-action" (click)="navigateToProcess(process.type)">
-                  查看详情
-                </button>
+          <!-- 入职离职趋势折线图 -->
+          <mat-card class="chart-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>trending_up</mat-icon>
+                入职离职趋势
+              </mat-card-title>
+              <mat-card-subtitle>近6个月人员流动情况</mat-card-subtitle>
+            </mat-card-header>
+            <mat-card-content>
+              <div class="line-chart-container">
+                <canvas #lineChart></canvas>
               </div>
-            }
-          </div>
-        </div>
+              <div class="key-notes">
+                <h4>关键节点</h4>
+                @for (note of keyNotes; track note.month) {
+                  <div class="note-item">
+                    <mat-icon class="note-icon">info</mat-icon>
+                    <span class="note-text">{{note.month}}:{{note.description}}</span>
+                  </div>
+                }
+              </div>
+            </mat-card-content>
+          </mat-card>
 
-        <div class="card-section">
-          <h3>风险预警</h3>
-          <div class="risk-alerts">
-            @for (alert of riskAlerts(); track alert) {
-              <div class="risk-alert">
-                <div class="alert-header">
-                  <mat-icon color="warn">warning</mat-icon>
-                  <span class="alert-title">{{alert.type}}</span>
-                  <span class="alert-count">{{alert.count}}人</span>
-                </div>
-                <div class="alert-employees">
-                  @for (employee of alert.employees; track employee) {
-                    <div class="employee-item">
-                      <span class="employee-name">{{employee.name}}</span>
-                      <span class="employee-position">{{employee.position}}</span>
-                      <span class="employee-department">{{employee.department}}</span>
-                      @if (employee.daysLeft) {
-                        <span class="days-left">剩余{{employee.daysLeft}}天</span>
-                      }
-                    </div>
-                  }
-                </div>
+          <!-- 绩效总览雷达图 -->
+          <mat-card class="chart-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>radar</mat-icon>
+                绩效总览
+              </mat-card-title>
+              <mat-card-subtitle>各部门4个维度绩效对比</mat-card-subtitle>
+            </mat-card-header>
+            <mat-card-content>
+              <div class="radar-chart-container">
+                <canvas #radarChart></canvas>
               </div>
-            }
-          </div>
-        </div>
-      </mat-card-content>
-    </mat-card>
+              <div class="radar-legend">
+                @for (dept of departmentPerformance; track dept.department) {
+                  <div class="legend-item">
+                    <div class="legend-color" [style.background-color]="getDepartmentColor(dept.department)"></div>
+                    <span>{{dept.department}}</span>
+                  </div>
+                }
+              </div>
+            </mat-card-content>
+          </mat-card>
 
-    <!-- 绩效总览看板 -->
-    <mat-card class="dashboard-card">
-      <mat-card-header>
-        <mat-card-title>
-          <div class="card-title-container">
-            <mat-icon>assessment</mat-icon>
-            <span>绩效总览看板</span>
-          </div>
-        </mat-card-title>
-      </mat-card-header>
-      <mat-card-content>
-        <div class="card-section">
-          <h3>核心指标展示</h3>
-          <div class="metrics-container">
-            @for (metric of performanceMetrics(); track metric) {
-              <div class="metric-item">
-                <div class="metric-header">
-                  <span class="metric-name">{{metric.name}}</span>
-                  <div class="metric-values">
-                    <span class="metric-actual">{{metric.actual}}{{metric.unit}}</span>
-                    <span class="metric-target">目标: {{metric.target}}{{metric.unit}}</span>
+          <!-- 关键岗位空缺数 -->
+          <mat-card class="chart-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>work_off</mat-icon>
+                关键岗位空缺
+              </mat-card-title>
+              <mat-card-subtitle>紧急招聘需求</mat-card-subtitle>
+            </mat-card-header>
+            <mat-card-content>
+              <div class="vacancy-list">
+                @for (vacancy of keyVacancies; track vacancy.position) {
+                  <div class="vacancy-item" [class]="getPriorityClass(vacancy.priority)">
+                    <div class="vacancy-icon">
+                      <mat-icon>{{getVacancyIcon(vacancy.priority)}}</mat-icon>
+                    </div>
+                    <div class="vacancy-info">
+                      <h4>{{vacancy.position}}</h4>
+                      <p>空缺:{{vacancy.count}}人</p>
+                      <span class="priority-badge" [class]="'priority-' + vacancy.priority">
+                        {{vacancy.priority === 'high' ? '紧急' : vacancy.priority === 'medium' ? '一般' : '低'}}
+                      </span>
+                    </div>
                   </div>
-                </div>
-                <mat-progress-bar
-                  [value]="(metric.actual / metric.target) * 100"
-                  [color]="getProgressColor(metric.actual, metric.target)">
-                </mat-progress-bar>
+                }
               </div>
-            }
-          </div>
+            </mat-card-content>
+          </mat-card>
+        </div>
 
-          <div class="department-performance">
-            <h4>部门绩效对比</h4>
-            <div class="department-table">
-              <div class="table-header">
-                <div class="table-cell">部门</div>
-                <div class="table-cell">优秀作品率</div>
-                <div class="table-cell">准时交付率</div>
-                <div class="table-cell">客户满意度</div>
+        <!-- 右侧待办事项区域 -->
+        <div class="right-panel">
+          <!-- 待办事项按钮卡片 -->
+          <mat-card class="todo-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>assignment</mat-icon>
+                待办事项列表
+              </mat-card-title>
+              <mat-card-subtitle>点击按钮查看详情</mat-card-subtitle>
+            </mat-card-header>
+            <mat-card-content>
+              <!-- 待办事项按钮卡片 -->
+              <div class="todo-buttons">
+                <button mat-raised-button 
+                        class="todo-button priority-high" 
+                        (click)="toggleTodoList()"
+                        [class.expanded]="showTodoList">
+                  <mat-icon>assignment_turned_in</mat-icon>
+                  <span>查看待办事项</span>
+                  <mat-icon class="expand-icon">{{showTodoList ? 'expand_less' : 'expand_more'}}</mat-icon>
+                </button>
               </div>
-              @for (dept of departmentPerformance(); track dept) {
-                <div class="table-row">
-                  <div class="table-cell">{{dept.name}}</div>
-                  <div class="table-cell">{{dept.excellentWorkRate}}%</div>
-                  <div class="table-cell">{{dept.deliveryOnTimeRate}}%</div>
-                  <div class="table-cell">{{dept.customerSatisfaction}}</div>
+              
+              <!-- 可展开的待办事项列表 -->
+              @if (showTodoList) {
+                <div class="todo-list" [@slideInOut]>
+                  @for (todo of todoList; track todo.id) {
+                    <div class="todo-item" [class]="getPriorityClass(todo.priority)">
+                      <div class="todo-content">
+                        <h4>{{todo.title}}</h4>
+                        <p>{{todo.description}}</p>
+                        <div class="todo-meta">
+                          <span class="priority-badge" [class]="'priority-' + todo.priority">
+                            {{todo.priority === 'high' ? '紧急' : todo.priority === 'medium' ? '一般' : '低'}}
+                          </span>
+                          <span class="due-date">{{todo.dueDate}}</span>
+                        </div>
+                      </div>
+                      <div class="todo-actions">
+                        <button mat-icon-button color="primary">
+                          <mat-icon>edit</mat-icon>
+                        </button>
+                        <button mat-icon-button color="accent">
+                          <mat-icon>check</mat-icon>
+                        </button>
+                      </div>
+                    </div>
+                  }
                 </div>
               }
-            </div>
-          </div>
-        </div>
-
-        <div class="card-section">
-          <h3>绩效等级分布</h3>
-          <!-- 用 ECharts 饼图替换占位块 -->
-          <div id="hrPerformanceDistributionChart" class="chart-container"></div>
+            </mat-card-content>
+          </mat-card>
         </div>
+      </div>
+    </div>
+  }
 
-        <div class="card-section">
-          <h3>扣分项预警</h3>
-          <div class="penalty-warnings">
-            @for (warning of penaltyWarnings(); track warning) {
-              <div class="warning-item">
-                <div class="warning-header">
-                  <mat-icon color="warn">error</mat-icon>
-                  <span class="warning-issue">{{warning.issue}}</span>
-                </div>
-                <div class="warning-details">
-                  <div class="warning-departments">
-                    <h4>高发部门</h4>
-                    @for (dept of warning.departments; track dept) {
-                      <div class="department-item">
-                        <span class="department-name">{{dept.name}}</span>
-                        <span class="department-count">{{dept.count}}次</span>
-                      </div>
-                    }
-                  </div>
-                  <div class="warning-employees">
-                    <h4>高发个人</h4>
-                    @for (emp of warning.employees; track emp) {
-                      <div class="employee-item">
-                        <span class="employee-name">{{emp.name}}</span>
-                        <span class="employee-department">{{emp.department}}</span>
-                        <span class="employee-count">{{emp.count}}次</span>
-                      </div>
+  <!-- 职级与晋升管理页面 -->
+  @if (activeTab === 'promotion') {
+    <div class="promotion-page">
+      <div class="content-layout">
+        <!-- 晋升规则卡片 -->
+        <div class="promotion-rules-section">
+          <mat-card class="rules-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>rule</mat-icon>
+                晋升规则
+              </mat-card-title>
+            </mat-card-header>
+            <mat-card-content>
+              @for (rule of promotionRules; track rule.id) {
+                <div class="rule-item">
+                  <h4 class="rule-title">{{rule.title}}</h4>
+                  <p class="rule-description">{{rule.description}}</p>
+                  <div class="rule-conditions">
+                    @for (condition of rule.conditions; track condition) {
+                      <mat-chip class="condition-chip">{{condition}}</mat-chip>
                     }
                   </div>
                 </div>
-              </div>
-            }
-          </div>
+              }
+            </mat-card-content>
+          </mat-card>
         </div>
-      </mat-card-content>
-    </mat-card>
 
-    <!-- 关键数据看板 -->
-    <mat-card class="dashboard-card">
-      <mat-card-header>
-        <mat-card-title>
-          <div class="card-title-container">
-            <mat-icon>insights</mat-icon>
-            <span>关键数据看板</span>
-          </div>
-        </mat-card-title>
-      </mat-card-header>
-      <mat-card-content>
-        <div class="card-section">
-          <h3>员工结构分析</h3>
-          <div class="structure-analysis">
-            <mat-tab-group>
-              @for (structure of employeeStructures(); track structure) {
-                <mat-tab [label]="structure.category">
-                  <div class="structure-data">
-                    @for (item of structure.data; track item) {
-                      <div class="structure-item">
-                        <div class="structure-header">
-                          <span class="structure-name">{{item.name}}</span>
-                          <span class="structure-count">{{item.count}}人</span>
-                        </div>
-                        <mat-progress-bar value="{{item.percentage}}" color="primary"></mat-progress-bar>
-                        <span class="structure-percentage">{{item.percentage}}%</span>
-                      </div>
-                    }
+        <!-- 部门绩效展示 -->
+        <div class="performance-section">
+          <mat-card class="performance-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>assessment</mat-icon>
+                部门绩效概览
+              </mat-card-title>
+            </mat-card-header>
+            <mat-card-content>
+              @for (dept of departmentPerformance; track dept.department) {
+                <div class="dept-performance-item">
+                  <div class="dept-header">
+                    <h4 class="dept-name">{{dept.department}}</h4>
+                    <div class="overall-score">{{dept.completionRate}}%</div>
+                  </div>
+                  <div class="performance-metrics">
+                    <div class="metric">
+                      <span class="metric-label">项目完成率</span>
+                      <mat-progress-bar mode="determinate" [value]="dept.completionRate"></mat-progress-bar>
+                      <span class="metric-value">{{dept.completionRate}}%</span>
+                    </div>
+                    <div class="metric">
+                      <span class="metric-label">优秀作品率</span>
+                      <mat-progress-bar mode="determinate" [value]="dept.excellentWorkRate"></mat-progress-bar>
+                      <span class="metric-value">{{dept.excellentWorkRate}}%</span>
+                    </div>
+                    <div class="metric">
+                      <span class="metric-label">客户满意度</span>
+                      <mat-progress-bar mode="determinate" [value]="dept.satisfactionRate"></mat-progress-bar>
+                      <span class="metric-value">{{dept.satisfactionRate}}%</span>
+                    </div>
+                    <div class="metric">
+                      <span class="metric-label">逾期率</span>
+                      <mat-progress-bar mode="determinate" [value]="dept.overdueRate" color="warn"></mat-progress-bar>
+                      <span class="metric-value">{{dept.overdueRate}}%</span>
+                    </div>
                   </div>
-                </mat-tab>
+                </div>
               }
-            </mat-tab-group>
-          </div>
+            </mat-card-content>
+          </mat-card>
         </div>
+      </div>
+    </div>
+  }
 
-        <div class="card-section">
-          <h3>异动趋势</h3>
-          <!-- 用 ECharts 折线图替换占位块 -->
-          <div id="hrTrendChart" class="chart-container"></div>
+  <!-- 新人跟进管理页面 -->
+  @if (activeTab === 'onboarding') {
+    <div class="onboarding-page">
+      <div class="content-layout">
+        <!-- 新人列表 -->
+        <div class="newbie-list-section">
+          <mat-card class="newbie-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>group_add</mat-icon>
+                新人列表
+              </mat-card-title>
+            </mat-card-header>
+            <mat-card-content>
+              @for (newbie of newbieList; track newbie.id) {
+                <div class="newbie-item">
+                  <div class="newbie-avatar">
+                    <mat-icon>person</mat-icon>
+                  </div>
+                  <div class="newbie-info">
+                    <h4 class="newbie-name">{{newbie.name}}</h4>
+                    <p class="newbie-position">{{newbie.position}}</p>
+                    <p class="newbie-date">入职日期:{{newbie.joinDate}}</p>
+                  </div>
+                  <div class="newbie-progress">
+                    <mat-progress-bar mode="determinate" [value]="newbie.progress"></mat-progress-bar>
+                    <span class="progress-text">{{newbie.progress}}%</span>
+                  </div>
+                </div>
+              }
+            </mat-card-content>
+          </mat-card>
         </div>
 
-        <div class="card-section">
-          <h3>待办事项提醒</h3>
-          <div class="todo-items">
-            @for (item of todoItems(); track item) {
-              <div class="todo-item" [ngClass]="getPriorityClass(item.priority)">
-                <div class="todo-header">
-                  <span class="todo-task">{{item.task}}</span>
-                  <mat-chip-set>
-                    <mat-chip>{{item.type}}</mat-chip>
-                  </mat-chip-set>
-                </div>
-                <div class="todo-footer">
-                  <span class="todo-due-date">截止日期: {{item.dueDate | date:'yyyy-MM-dd'}}</span>
-                  <span class="todo-priority">{{item.priority === 'high' ? '紧急' : item.priority === 'medium' ? '中等' : '普通'}}</span>
+        <!-- 跟进检查点 -->
+        <div class="checkpoint-section">
+          <mat-card class="checkpoint-card">
+            <mat-card-header>
+              <mat-card-title>
+                <mat-icon>checklist</mat-icon>
+                跟进检查点
+              </mat-card-title>
+            </mat-card-header>
+            <mat-card-content>
+              @for (checkpoint of onboardingCheckpoints; track checkpoint.id) {
+                <div class="checkpoint-item">
+                  <mat-checkbox
+                    [checked]="checkpoint.completed"
+                    (change)="checkpoint.completed = $any($event).checked">
+                  </mat-checkbox>
+                  <div class="checkpoint-content">
+                    <h4 class="checkpoint-title">{{checkpoint.title}}</h4>
+                    <p class="checkpoint-description">{{checkpoint.description}}</p>
+                    <div class="checkpoint-timeline">
+                      <mat-icon>schedule</mat-icon>
+                      <span>{{checkpoint.dueDate | date:'yyyy-MM-dd'}}</span>
+                    </div>
+                  </div>
                 </div>
-              </div>
-            }
-          </div>
+              }
+            </mat-card-content>
+          </mat-card>
         </div>
-      </mat-card-content>
-    </mat-card>
-  </div>
+      </div>
+    </div>
+  }
 </div>

+ 803 - 880
src/app/pages/hr/dashboard/dashboard.scss

@@ -1,969 +1,892 @@
-.dashboard-container {
+.hr-dashboard-container {
   padding: 20px;
-}
-
-.page-header {
-  margin-bottom: 24px;
-  
-  h1 {
-    margin: 0 0 8px 0;
-    font-size: 28px;
-    font-weight: 700; /* 提升标题权重以贴近 Admin 风格 */
-    background: linear-gradient(135deg, #165DFF, #7c3aed);
-    -webkit-background-clip: text;
-    -webkit-text-fill-color: transparent;
-    background-clip: text;
-  }
-  
-  .page-description {
-    margin: 0;
-    color: #4E5969; /* 更接近 Admin 次级文字色 */
-    font-size: 16px;
-  }
-}
-
-.filter-bar {
-  display: flex;
-  align-items: center;
-  margin-bottom: 24px;
-  background-color: white;
-  padding: 12px 16px;
-  border-radius: 8px;
-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
-  
-  .time-filter {
-    display: flex;
-    align-items: center;
-    
-    .filter-label {
-      margin-right: 12px;
-      color: #616161;
-    }
+  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
+  min-height: 100vh;
+  font-family: 'Roboto', sans-serif;
+
+  .top-navigation {
+    margin-bottom: 30px;
     
-    .filter-buttons {
+    .nav-buttons {
       display: flex;
+      gap: 15px;
+      justify-content: center;
+      flex-wrap: wrap;
       
-      button {
-        min-width: 40px;
-        border-radius: 4px;
-        margin-right: 8px;
+      .nav-button {
+        padding: 12px 24px;
+        border-radius: 25px;
+        font-weight: 500;
+        transition: all 0.3s ease;
+        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+        
+        &:hover {
+          transform: translateY(-2px);
+          box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+        }
         
         &.active {
-          background-color: #1a3a6e;
+          background: linear-gradient(45deg, #2196F3, #21CBF3);
           color: white;
+          box-shadow: 0 6px 20px rgba(33, 150, 243, 0.3);
+        }
+        
+        mat-icon {
+          margin-right: 8px;
         }
       }
     }
   }
-}
-
-.dashboard-content {
-  display: grid;
-  grid-template-columns: 1fr;
-  gap: 24px;
-  
-  @media (min-width: 1200px) {
-    grid-template-columns: repeat(2, 1fr);
-    
-    .dashboard-card:last-child {
-      grid-column: span 2;
-    }
-  }
-}
-
-.dashboard-card {
-  border-radius: 12px; /* 统一圆角 */
-  background: #FFFFFF;
-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06); /* $shadow-sm */
-  border: 1px solid rgba(229, 230, 235, 0.8);
-  overflow: hidden;
-  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-  
-  mat-card-header {
-    background-color: #FFFFFF; /* 与 Admin 统一 */
-    padding: 16px 20px;
-    border-bottom: 1px solid #E5E6EB;
-  }
-  
-  .chart-container {
-    width: 100%;
-    height: 320px;
-  }
-  
-  .card-title-container {
-    display: flex;
-    align-items: center;
-    
-    mat-icon {
-      margin-right: 10px;
-      color: #165DFF; /* 主色调 */
-    }
-    
-    span {
-      font-size: 18px;
-      font-weight: 600;
-      color: #1D2129; /* 标题主文字色 */
+
+  // 数据可视化页面样式
+  .visualization-page {
+    .main-layout {
+      display: grid;
+      grid-template-columns: 2fr 1fr;
+      gap: 30px;
+      min-height: 80vh;
+
+      @media (max-width: 1200px) {
+        grid-template-columns: 1fr;
+        gap: 20px;
+      }
     }
-  }
-  
-  mat-card-content {
-    padding: 20px;
-  }
-  
-  &:hover {
-    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); /* $shadow-md */
-    transform: translateY(-4px);
-    border-color: rgba(22, 93, 255, 0.3);
-  }
-}
 
-.card-section {
-  margin-bottom: 24px;
-  
-  &:last-child {
-    margin-bottom: 0;
-  }
-  
-  h3 {
-    margin: 0 0 16px 0;
-    font-size: 16px;
-    font-weight: 600;
-    color: #4E5969;
-    border-left: 4px solid #165DFF; /* 与 Admin 主色一致 */
-    padding-left: 8px;
-  }
-  
-  h4 {
-    margin: 16px 0 8px 0;
-    font-size: 14px;
-    font-weight: 500;
-    color: #616161;
-  }
-}
-
-/* 入职离职看板样式 */
-.data-visualization {
-  display: flex;
-  flex-direction: column;
-  height: 200px;
-  
-  .chart-placeholder {
-    display: flex;
-    justify-content: space-between;
-    align-items: flex-end;
-    height: 160px;
-    margin-bottom: 16px;
-    
-    .chart-bar-container {
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      flex: 1;
+    .left-panel {
+      display: grid;
+      grid-template-columns: 1fr 1fr;
+      gap: 20px;
       
-      .chart-label {
-        margin-top: 8px;
-        font-size: 12px;
-        color: #757575;
+      @media (max-width: 768px) {
+        grid-template-columns: 1fr;
       }
-      
-      .chart-bars {
-        display: flex;
-        align-items: flex-end;
-        height: 100%;
-        width: 100%;
-        justify-content: center;
-        gap: 4px;
-        
-        .chart-bar {
-          width: 20px;
-          position: relative;
-          border-radius: 4px 4px 0 0;
-          
-          &.hired {
-            background-color: #4caf50;
-          }
-          
-          &.resigned {
-            background-color: #f44336;
+
+      .chart-card {
+        background: rgba(255, 255, 255, 0.95);
+        backdrop-filter: blur(10px);
+        border-radius: 20px;
+        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
+        transition: all 0.3s ease;
+        border: 1px solid rgba(255, 255, 255, 0.2);
+
+        &:hover {
+          transform: translateY(-5px);
+          box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15);
+        }
+
+        mat-card-header {
+          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+          color: white;
+          border-radius: 20px 20px 0 0;
+          padding: 20px;
+
+          mat-card-title {
+            display: flex;
+            align-items: center;
+            font-size: 18px;
+            font-weight: 600;
+            margin: 0;
+
+            mat-icon {
+              margin-right: 10px;
+              font-size: 24px;
+            }
           }
-          
-          .bar-value {
-            position: absolute;
-            top: -20px;
-            left: 50%;
-            transform: translateX(-50%);
-            font-size: 12px;
-            color: #616161;
+
+          mat-card-subtitle {
+            color: rgba(255, 255, 255, 0.8);
+            margin-top: 5px;
           }
         }
-      }
-    }
-  }
-  
-  .chart-legend {
-    display: flex;
-    justify-content: center;
-    gap: 16px;
-    
-    .legend-item {
-      display: flex;
-      align-items: center;
-      
-      .legend-color {
-        width: 12px;
-        height: 12px;
-        margin-right: 4px;
-        border-radius: 2px;
-        
-        &.hired {
-          background-color: #4caf50;
-        }
-        
-        &.resigned {
-          background-color: #f44336;
-        }
-        
-        &.top-tier {
-          background-color: #4caf50;
-        }
-        
-        &.mid-tier {
-          background-color: #2196f3;
-        }
-        
-        &.bottom-tier {
-          background-color: #f44336;
+
+        mat-card-content {
+          padding: 25px;
         }
       }
-      
-      span {
-        font-size: 12px;
-        color: #616161;
-      }
-    }
-  }
-}
-
-.process-tracking {
-  display: flex;
-  flex-direction: column;
-  gap: 16px;
-  
-  .process-item {
-    background-color: #f5f5f5;
-    padding: 12px;
-    border-radius: 4px;
-    
-    .process-header {
-      display: flex;
-      justify-content: space-between;
-      margin-bottom: 8px;
-      
-      .process-title {
-        font-weight: 500;
-        color: #424242;
-      }
-      
-      .process-count {
-        font-weight: 500;
-        color: #1a3a6e;
-      }
-    }
-    
-    mat-progress-bar {
-      margin-bottom: 8px;
-    }
-    
-    .process-action {
-      width: 100%;
-    }
-  }
-}
-
-.risk-alerts {
-  display: flex;
-  flex-direction: column;
-  gap: 16px;
-  
-  .risk-alert {
-    background-color: #fff8e1;
-    padding: 12px;
-    border-radius: 4px;
-    border-left: 4px solid #ffc107;
-    
-    .alert-header {
-      display: flex;
-      align-items: center;
-      margin-bottom: 8px;
-      
-      mat-icon {
-        margin-right: 8px;
-        font-size: 20px;
-        height: 20px;
-        width: 20px;
-      }
-      
-      .alert-title {
-        flex: 1;
-        font-weight: 500;
-        color: #424242;
+
+      // 职级分布饼图样式
+      .pie-chart-container {
+        height: 200px;
+        margin-bottom: 20px;
+        background: radial-gradient(circle, #f8f9fa 0%, #e9ecef 100%);
+        border-radius: 15px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 14px;
+        color: #666;
       }
-      
-      .alert-count {
-        font-weight: 500;
-        color: #f44336;
+
+      .chart-legend {
+        display: flex;
+        flex-direction: column;
+        gap: 10px;
+
+        .legend-item {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+          font-size: 14px;
+
+          .legend-color {
+            width: 16px;
+            height: 16px;
+            border-radius: 50%;
+            
+            &.junior { background: #4CAF50; }
+            &.intermediate { background: #FF9800; }
+            &.senior { background: #2196F3; }
+          }
+        }
       }
-    }
-    
-    .alert-employees {
-      display: flex;
-      flex-direction: column;
-      gap: 8px;
-      
-      .employee-item {
+
+      // 折线图样式
+      .line-chart-container {
+        height: 200px;
+        margin-bottom: 20px;
+        background: radial-gradient(circle, #f8f9fa 0%, #e9ecef 100%);
+        border-radius: 15px;
         display: flex;
         align-items: center;
-        background-color: white;
-        padding: 8px;
-        border-radius: 4px;
-        
-        .employee-name {
-          font-weight: 500;
-          margin-right: 8px;
-        }
-        
-        .employee-position,
-        .employee-department {
-          color: #757575;
-          margin-right: 8px;
-          font-size: 12px;
+        justify-content: center;
+        font-size: 14px;
+        color: #666;
+      }
+
+      .key-notes {
+        h4 {
+          color: #333;
+          font-size: 16px;
+          margin-bottom: 15px;
+          font-weight: 600;
         }
-        
-        .days-left {
-          margin-left: auto;
-          background-color: #f44336;
-          color: white;
-          padding: 2px 6px;
-          border-radius: 4px;
-          font-size: 12px;
+
+        .note-item {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+          margin-bottom: 10px;
+          padding: 10px;
+          background: rgba(33, 150, 243, 0.1);
+          border-radius: 10px;
+          border-left: 4px solid #2196F3;
+
+          .note-icon {
+            color: #2196F3;
+            font-size: 18px;
+          }
+
+          .note-text {
+            font-size: 14px;
+            color: #555;
+          }
         }
       }
-    }
-  }
-}
-
-/* 绩效总览看板样式 */
-.metrics-container {
-  display: flex;
-  flex-direction: column;
-  gap: 16px;
-  
-  .metric-item {
-    .metric-header {
-      display: flex;
-      justify-content: space-between;
-      margin-bottom: 8px;
-      
-      .metric-name {
-        font-weight: 500;
-        color: #424242;
+
+      // 雷达图样式
+      .radar-chart-container {
+        height: 200px;
+        margin-bottom: 20px;
+        background: radial-gradient(circle, #f8f9fa 0%, #e9ecef 100%);
+        border-radius: 15px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 14px;
+        color: #666;
       }
-      
-      .metric-values {
+
+      .radar-legend {
         display: flex;
-        gap: 8px;
-        
-        .metric-actual {
-          font-weight: 500;
-          color: #1a3a6e;
-        }
-        
-        .metric-target {
-          color: #757575;
-          font-size: 12px;
+        flex-wrap: wrap;
+        gap: 15px;
+
+        .legend-item {
+          display: flex;
+          align-items: center;
+          gap: 8px;
+          font-size: 14px;
+
+          .legend-color {
+            width: 16px;
+            height: 16px;
+            border-radius: 50%;
+          }
         }
       }
-    }
-  }
-}
-
-.department-table {
-  width: 100%;
-  border-collapse: collapse;
-  margin-top: 16px;
-  
-  .table-header {
-    display: flex;
-    background-color: #f5f5f5;
-    font-weight: 500;
-    color: #424242;
-  }
-  
-  .table-row {
-    display: flex;
-    border-bottom: 1px solid #e0e0e0;
-    
-    &:last-child {
-      border-bottom: none;
-    }
-  }
-  
-  .table-cell {
-    flex: 1;
-    padding: 8px;
-    text-align: center;
-    
-    &:first-child {
-      text-align: left;
-    }
-  }
-}
-
-.performance-distribution {
-  .pie-chart-placeholder {
-    display: flex;
-    height: 40px;
-    border-radius: 20px;
-    overflow: hidden;
-    margin-bottom: 16px;
-    
-    .pie-segment {
-      height: 100%;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      position: relative;
-      
-      &.top-tier {
-        background-color: #4caf50;
-      }
-      
-      &.mid-tier {
-        background-color: #2196f3;
-      }
-      
-      &.bottom-tier {
-        background-color: #f44336;
-      }
-      
-      .segment-label,
-      .segment-value {
-        color: white;
-        font-size: 12px;
-        font-weight: 500;
-        margin: 0 4px;
-      }
-    }
-  }
-}
-
-.penalty-warnings {
-  display: flex;
-  flex-direction: column;
-  gap: 16px;
-  
-  .warning-item {
-    background-color: #f5f5f5;
-    padding: 12px;
-    border-radius: 4px;
-    
-    .warning-header {
-      display: flex;
-      align-items: center;
-      margin-bottom: 12px;
-      
-      mat-icon {
-        margin-right: 8px;
-        font-size: 20px;
-        height: 20px;
-        width: 20px;
-      }
-      
-      .warning-issue {
-        font-weight: 500;
-        color: #424242;
+
+      // 空缺岗位样式
+      .vacancy-grid {
+        display: grid;
+        grid-template-columns: 1fr;
+        gap: 15px;
+
+        .vacancy-item {
+          padding: 15px;
+          border-radius: 12px;
+          border-left: 4px solid;
+          transition: all 0.3s ease;
+
+          &.urgent {
+            background: rgba(244, 67, 54, 0.1);
+            border-left-color: #f44336;
+          }
+
+          &.normal {
+            background: rgba(76, 175, 80, 0.1);
+            border-left-color: #4caf50;
+          }
+
+          &:hover {
+            transform: translateX(5px);
+            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+          }
+
+          .vacancy-header {
+            display: flex;
+            align-items: center;
+            gap: 10px;
+            margin-bottom: 8px;
+
+            mat-icon {
+              font-size: 20px;
+            }
+
+            .position-name {
+              font-weight: 600;
+              color: #333;
+            }
+          }
+
+          .vacancy-count {
+            font-size: 18px;
+            font-weight: 700;
+            color: #2196F3;
+            margin-bottom: 5px;
+          }
+
+          .vacancy-duration {
+            font-size: 12px;
+            color: #666;
+          }
+        }
       }
     }
-    
-    .warning-details {
-      display: flex;
-      gap: 24px;
-      
-      .warning-departments,
-      .warning-employees {
-        flex: 1;
-        
-        h4 {
-          margin-top: 0;
+
+    .right-panel {
+      .todo-card {
+        background: rgba(255, 255, 255, 0.95);
+        backdrop-filter: blur(10px);
+        border-radius: 20px;
+        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
+        border: 1px solid rgba(255, 255, 255, 0.2);
+        height: fit-content;
+
+        mat-card-header {
+          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+          color: white;
+          border-radius: 20px 20px 0 0;
+          padding: 20px;
+
+          .todo-toggle-btn {
+            width: 100%;
+            background: rgba(255, 255, 255, 0.2);
+            color: white;
+            border: 1px solid rgba(255, 255, 255, 0.3);
+            border-radius: 15px;
+            padding: 15px 20px;
+            font-size: 16px;
+            font-weight: 600;
+            transition: all 0.3s ease;
+
+            &:hover {
+              background: rgba(255, 255, 255, 0.3);
+              transform: scale(1.02);
+            }
+
+            mat-icon {
+              margin-right: 10px;
+            }
+
+            .todo-count-chip {
+              margin-left: 10px;
+              background: rgba(255, 255, 255, 0.9);
+              color: #333;
+              font-weight: 700;
+            }
+          }
         }
-        
-        .department-item,
-        .employee-item {
+
+        mat-card-content {
+          padding: 0;
+        }
+
+        .todo-list {
+          max-height: 600px;
+          overflow-y: auto;
+
+          .todo-item {
+            border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+            transition: all 0.3s ease;
+
+            &:hover {
+              background: rgba(33, 150, 243, 0.05);
+            }
+
+            &:last-child {
+              border-bottom: none;
+            }
+
+            &.priority-high {
+              border-left: 4px solid #f44336;
+            }
+
+            &.priority-medium {
+              border-left: 4px solid #ff9800;
+            }
+
+            &.priority-low {
+              border-left: 4px solid #4caf50;
+            }
+
+            .todo-content {
+              padding: 20px;
+
+              .todo-header-row {
+                display: flex;
+                align-items: flex-start;
+                gap: 15px;
+
+                .todo-priority-indicator {
+                  width: 8px;
+                  height: 8px;
+                  border-radius: 50%;
+                  margin-top: 8px;
+                  flex-shrink: 0;
+                }
+
+                .todo-main {
+                  flex: 1;
+                  display: flex;
+                  justify-content: space-between;
+                  align-items: flex-start;
+
+                  .todo-actions {
+                    display: flex;
+                    gap: 15px;
+                    flex: 1;
+
+                    .todo-info {
+                      flex: 1;
+
+                      .todo-title {
+                        margin: 0 0 8px 0;
+                        font-size: 16px;
+                        font-weight: 600;
+                        color: #333;
+                        transition: all 0.3s ease;
+
+                        &.completed {
+                          text-decoration: line-through;
+                          color: #999;
+                        }
+                      }
+
+                      .todo-description {
+                        margin: 0 0 12px 0;
+                        font-size: 14px;
+                        color: #666;
+                        line-height: 1.4;
+                      }
+
+                      .todo-meta {
+                        display: flex;
+                        gap: 8px;
+                        flex-wrap: wrap;
+
+                        .priority-chip {
+                          color: white;
+                          font-size: 12px;
+                          font-weight: 600;
+                          padding: 4px 8px;
+                          border-radius: 12px;
+                        }
+
+                        .type-chip {
+                          background: rgba(33, 150, 243, 0.1);
+                          color: #2196F3;
+                          font-size: 12px;
+                          font-weight: 500;
+                          padding: 4px 8px;
+                          border-radius: 12px;
+                        }
+                      }
+                    }
+                  }
+
+                  .drag-handle {
+                    color: #ccc;
+                    cursor: grab;
+                    padding: 5px;
+                    border-radius: 5px;
+                    transition: all 0.3s ease;
+
+                    &:hover {
+                      color: #999;
+                      background: rgba(0, 0, 0, 0.05);
+                    }
+
+                    &:active {
+                      cursor: grabbing;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+
+      // 关键岗位空缺样式
+      .vacancy-list {
+        .vacancy-item {
           display: flex;
-          justify-content: space-between;
-          padding: 4px 0;
+          align-items: center;
+          padding: 16px;
+          margin-bottom: 12px;
+          border-radius: 8px;
+          background: #fafafa;
+          border-left: 4px solid #e0e0e0;
+          transition: all 0.3s ease;
           
-          .department-name,
-          .employee-name {
-            font-weight: 500;
+          &:hover {
+            transform: translateY(-2px);
+            box-shadow: 0 4px 12px rgba(0,0,0,0.1);
           }
           
-          .department-count,
-          .employee-count {
-            color: #f44336;
-            font-weight: 500;
+          &.priority-high {
+            border-left-color: #f44336;
+            background: #ffebee;
           }
           
-          .employee-department {
-            color: #757575;
-            font-size: 12px;
-            margin-left: 8px;
+          &.priority-medium {
+            border-left-color: #ff9800;
+            background: #fff3e0;
+          }
+          
+          &.priority-low {
+            border-left-color: #4caf50;
+            background: #e8f5e8;
+          }
+          
+          .vacancy-icon {
+            margin-right: 16px;
+            
+            mat-icon {
+              font-size: 32px;
+              width: 32px;
+              height: 32px;
+              color: #666;
+            }
+          }
+          
+          .vacancy-info {
+            flex: 1;
+            
+            h4 {
+              margin: 0 0 8px 0;
+              font-size: 16px;
+              font-weight: 500;
+              color: #333;
+            }
+            
+            p {
+              margin: 0 0 8px 0;
+              color: #666;
+              font-size: 14px;
+            }
+            
+            .priority-badge {
+              padding: 4px 8px;
+              border-radius: 12px;
+              font-size: 12px;
+              font-weight: 500;
+              
+              &.priority-high {
+                background: #ffcdd2;
+                color: #c62828;
+              }
+              
+              &.priority-medium {
+                background: #ffe0b2;
+                color: #ef6c00;
+              }
+              
+              &.priority-low {
+                background: #c8e6c9;
+                color: #2e7d32;
+              }
+            }
           }
         }
       }
     }
   }
-}
-
-/* 关键数据看板样式 */
-.structure-data {
-  padding: 16px 0;
-  
-  .structure-item {
-    margin-bottom: 16px;
-    
-    &:last-child {
-      margin-bottom: 0;
+
+  // 职级与晋升管理页面样式
+  .promotion-page {
+    .content-layout {
+      display: grid;
+      grid-template-columns: 1fr 1fr;
+      gap: 30px;
+
+      @media (max-width: 1200px) {
+        grid-template-columns: 1fr;
+      }
     }
-    
-    .structure-header {
-      display: flex;
-      justify-content: space-between;
-      margin-bottom: 8px;
-      
-      .structure-name {
-        font-weight: 500;
-        color: #424242;
+
+    .rules-card, .performance-card {
+      background: rgba(255, 255, 255, 0.95);
+      backdrop-filter: blur(10px);
+      border-radius: 20px;
+      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
+      border: 1px solid rgba(255, 255, 255, 0.2);
+
+      mat-card-header {
+        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+        color: white;
+        border-radius: 20px 20px 0 0;
+        padding: 20px;
+
+        mat-card-title {
+          display: flex;
+          align-items: center;
+          font-size: 18px;
+          font-weight: 600;
+          margin: 0;
+
+          mat-icon {
+            margin-right: 10px;
+          }
+        }
       }
-      
-      .structure-count {
-        font-weight: 500;
-        color: #1a3a6e;
+
+      mat-card-content {
+        padding: 25px;
       }
     }
-    
-    .structure-percentage {
-      display: block;
-      text-align: right;
-      margin-top: 4px;
-      font-size: 12px;
-      color: #757575;
+
+    .rule-item {
+      margin-bottom: 25px;
+      padding: 20px;
+      background: rgba(33, 150, 243, 0.05);
+      border-radius: 15px;
+      border-left: 4px solid #2196F3;
+
+      .rule-title {
+        color: #333;
+        font-size: 16px;
+        font-weight: 600;
+        margin-bottom: 10px;
+      }
+
+      .rule-description {
+        color: #666;
+        font-size: 14px;
+        margin-bottom: 15px;
+        line-height: 1.5;
+      }
+
+      .rule-conditions {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 8px;
+
+        .condition-chip {
+          background: rgba(76, 175, 80, 0.1);
+          color: #4caf50;
+          font-size: 12px;
+          padding: 6px 12px;
+          border-radius: 15px;
+          border: 1px solid rgba(76, 175, 80, 0.3);
+        }
+      }
     }
-  }
-}
-
-.movement-trends {
-  height: 200px;
-  
-  .line-chart-placeholder {
-    position: relative;
-    height: 160px;
-    margin-bottom: 16px;
-    border-bottom: 1px solid #e0e0e0;
-    border-left: 1px solid #e0e0e0;
-    
-    .chart-lines {
-      position: absolute;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-      
-      .chart-line {
-        position: absolute;
-        height: 2px;
-        
-        &.hired {
-          background-color: #4caf50;
-          width: 100%;
-          top: 30%;
+
+    .dept-performance-item {
+      margin-bottom: 25px;
+      padding: 20px;
+      background: rgba(255, 255, 255, 0.8);
+      border-radius: 15px;
+      box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
+
+      .dept-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 20px;
+
+        .dept-name {
+          color: #333;
+          font-size: 18px;
+          font-weight: 600;
+          margin: 0;
         }
-        
-        &.resigned {
-          background-color: #f44336;
-          width: 100%;
-          top: 60%;
+
+        .overall-score {
+          background: linear-gradient(45deg, #4CAF50, #8BC34A);
+          color: white;
+          padding: 8px 16px;
+          border-radius: 20px;
+          font-weight: 700;
+          font-size: 16px;
         }
       }
-    }
-    
-    .chart-points {
-      position: absolute;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-      
-      .chart-point-group {
-        position: absolute;
-        bottom: 0;
-        transform: translateX(-50%);
-        
-        .chart-point {
-          position: absolute;
-          width: 8px;
-          height: 8px;
-          border-radius: 50%;
-          transform: translate(-50%, 50%);
-          
-          &.hired {
-            background-color: #4caf50;
+
+      .performance-metrics {
+        .metric {
+          display: flex;
+          align-items: center;
+          gap: 15px;
+          margin-bottom: 15px;
+
+          .metric-label {
+            min-width: 100px;
+            font-size: 14px;
+            color: #666;
+            font-weight: 500;
           }
-          
-          &.resigned {
-            background-color: #f44336;
+
+          mat-progress-bar {
+            flex: 1;
+            height: 8px;
+            border-radius: 4px;
+          }
+
+          .metric-value {
+            min-width: 50px;
+            text-align: right;
+            font-weight: 600;
+            color: #333;
           }
-        }
-        
-        .chart-label {
-          position: absolute;
-          bottom: -20px;
-          left: 50%;
-          transform: translateX(-50%);
-          font-size: 12px;
-          color: #757575;
         }
       }
     }
   }
-}
-
-.todo-items {
-  display: flex;
-  flex-direction: column;
-  gap: 12px;
-  
-  .todo-item {
-    background-color: #f5f5f5;
-    padding: 12px;
-    border-radius: 4px;
-    border-left: 4px solid #9e9e9e;
-    
-    &.priority-high {
-      border-left-color: #f44336;
-    }
-    
-    &.priority-medium {
-      border-left-color: #ff9800;
-    }
-    
-    &.priority-low {
-      border-left-color: #4caf50;
+
+  // 新人跟进管理页面样式
+  .onboarding-page {
+    .content-layout {
+      display: grid;
+      grid-template-columns: 1fr 1fr;
+      gap: 30px;
+
+      @media (max-width: 1200px) {
+        grid-template-columns: 1fr;
+      }
     }
-    
-    .todo-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: flex-start;
-      margin-bottom: 8px;
-      
-      .todo-task {
-        font-weight: 500;
-        color: #424242;
-        margin-right: 8px;
+
+    .newbie-card, .checkpoint-card {
+      background: rgba(255, 255, 255, 0.95);
+      backdrop-filter: blur(10px);
+      border-radius: 20px;
+      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
+      border: 1px solid rgba(255, 255, 255, 0.2);
+
+      mat-card-header {
+        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+        color: white;
+        border-radius: 20px 20px 0 0;
+        padding: 20px;
+
+        mat-card-title {
+          display: flex;
+          align-items: center;
+          font-size: 18px;
+          font-weight: 600;
+          margin: 0;
+
+          mat-icon {
+            margin-right: 10px;
+          }
+        }
+      }
+
+      mat-card-content {
+        padding: 25px;
       }
     }
-    
-    .todo-footer {
+
+    .newbie-item {
       display: flex;
-      justify-content: space-between;
-      
-      .todo-due-date {
-        font-size: 12px;
-        color: #757575;
+      align-items: center;
+      gap: 15px;
+      padding: 15px;
+      margin-bottom: 15px;
+      background: rgba(33, 150, 243, 0.05);
+      border-radius: 15px;
+      transition: all 0.3s ease;
+
+      &:hover {
+        background: rgba(33, 150, 243, 0.1);
+        transform: translateX(5px);
       }
-      
-      .todo-priority {
-        font-size: 12px;
-        font-weight: 500;
-        
-        .priority-high & {
-          color: #f44336;
+
+      .newbie-avatar {
+        width: 50px;
+        height: 50px;
+        background: linear-gradient(45deg, #2196F3, #21CBF3);
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        color: white;
+
+        mat-icon {
+          font-size: 24px;
         }
-        
-        .priority-medium & {
-          color: #ff9800;
+      }
+
+      .newbie-info {
+        flex: 1;
+
+        .newbie-name {
+          margin: 0 0 5px 0;
+          font-size: 16px;
+          font-weight: 600;
+          color: #333;
         }
-        
-        .priority-low & {
-          color: #4caf50;
+
+        .newbie-position {
+          margin: 0 0 5px 0;
+          font-size: 14px;
+          color: #666;
+        }
+
+        .newbie-date {
+          margin: 0;
+          font-size: 12px;
+          color: #999;
+        }
+      }
+
+      .newbie-progress {
+        display: flex;
+        align-items: center;
+        gap: 10px;
+        min-width: 120px;
+
+        mat-progress-bar {
+          flex: 1;
+          height: 6px;
+          border-radius: 3px;
+        }
+
+        .progress-text {
+          font-size: 14px;
+          font-weight: 600;
+          color: #333;
         }
       }
     }
-  }
-}
-
-/* 修复Material图标显示问题 */
-.dashboard-container mat-icon {
-  font-family: 'Material Icons' !important;
-  -webkit-font-feature-settings: 'liga';
-  font-feature-settings: 'liga';
-  -webkit-font-smoothing: antialiased;
-  font-size: 22px;
-  line-height: 1;
-}
-
-/* 优化卡片标题区域 */
-.card-title-container {
-  display: flex;
-  align-items: center;
-  gap: 12px;
-  
-  mat-icon {
-    background: linear-gradient(135deg, #e6f7ff 0%, #f3e8ff 100%);
-    color: #165DFF;
-    padding: 8px;
-    border-radius: 50%;
-    font-size: 20px;
-    width: 36px;
-    height: 36px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-  }
-}
-
-/* 美化进度条 */
-mat-progress-bar {
-  border-radius: 8px;
-  overflow: hidden;
-  height: 8px;
-  
-  .mdc-linear-progress__bar-inner {
-    border-radius: 8px;
-  }
-}
-
-/* 优化表格样式 */
-.department-table {
-  background: #fff;
-  border-radius: 8px;
-  overflow: hidden;
-  border: 1px solid #e5e6eb;
-  
-  .table-header {
-    background: linear-gradient(180deg, #f7f9fc 0%, #eef3ff 100%);
-    font-weight: 600;
-    color: #1a3a6e;
-  }
-  
-  .table-row {
-    border-bottom: 1px solid #f0f0f0;
-    
-    &:hover {
-      background-color: #f8f9fa;
-    }
-    
-    &:last-child {
-      border-bottom: none;
-    }
-  }
-  
-  .table-cell {
-    padding: 12px 16px;
-    text-align: center;
-    
-    &:first-child {
-      text-align: left;
-      font-weight: 500;
-    }
-  }
-}
-
-/* 优化指标卡片 */
-.metrics-container {
-  display: grid;
-  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
-  gap: 16px;
-  margin-bottom: 24px;
-  
-  .metric-item {
-    background: #fff;
-    border: 1px solid #e5e6eb;
-    border-radius: 8px;
-    padding: 16px;
-    transition: all 0.2s ease;
-    
-    &:hover {
-      box-shadow: 0 4px 12px rgba(22, 93, 255, 0.1);
-      border-color: #165DFF;
-    }
-    
-    .metric-header {
+
+    .checkpoint-item {
       display: flex;
-      justify-content: space-between;
-      align-items: flex-start;
-      margin-bottom: 12px;
-      
-      .metric-name {
-        font-weight: 500;
-        color: #1d2129;
-      }
-      
-      .metric-values {
-        display: flex;
-        flex-direction: column;
-        align-items: flex-end;
-        
-        .metric-actual {
-          font-size: 18px;
+      gap: 15px;
+      padding: 15px;
+      margin-bottom: 15px;
+      background: rgba(76, 175, 80, 0.05);
+      border-radius: 15px;
+      border-left: 4px solid #4caf50;
+
+      .checkpoint-content {
+        flex: 1;
+
+        .checkpoint-title {
+          margin: 0 0 8px 0;
+          font-size: 16px;
           font-weight: 600;
-          color: #165DFF;
+          color: #333;
         }
-        
-        .metric-target {
+
+        .checkpoint-description {
+          margin: 0 0 10px 0;
+          font-size: 14px;
+          color: #666;
+          line-height: 1.4;
+        }
+
+        .checkpoint-timeline {
+          display: flex;
+          align-items: center;
+          gap: 5px;
           font-size: 12px;
-          color: #86909c;
+          color: #999;
+
+          mat-icon {
+            font-size: 16px;
+          }
         }
       }
     }
   }
-}
-
-/* 优化警告项样式 */
-.warning-item, .risk-alert {
-  border-radius: 8px;
-  border: 1px solid #ffd666;
-  background: linear-gradient(135deg, #fff7e6 0%, #fffbf0 100%);
-  
-  .warning-header, .alert-header {
-    display: flex;
-    align-items: center;
-    gap: 8px;
-    margin-bottom: 12px;
-    
-    mat-icon {
-      color: #fa8c16;
-      background: rgba(250, 140, 22, 0.1);
-      padding: 4px;
-      border-radius: 50%;
-    }
-    
-    .warning-issue, .alert-title {
-      font-weight: 500;
-      color: #d46b08;
-    }
-  }
-}
-
-/* 优化待办事项 */
-.todo-items {
-  display: flex;
-  flex-direction: column;
-  gap: 12px;
-  
-  .todo-item {
-    background: #fff;
-    border: 1px solid #e5e6eb;
-    border-radius: 8px;
-    padding: 16px;
-    transition: all 0.2s ease;
-    
-    &.high-priority {
-      border-left: 4px solid #ff4d4f;
-    }
-    
-    &.medium-priority {
-      border-left: 4px solid #faad14;
-    }
-    
-    &.low-priority {
-      border-left: 4px solid #52c41a;
-    }
-    
-    &:hover {
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-    }
-    
-    .todo-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 8px;
-      
-      .todo-task {
-        font-weight: 500;
-        color: #1d2129;
-      }
-    }
-    
-    .todo-footer {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      font-size: 12px;
-      color: #86909c;
-      
-      .todo-priority {
-        padding: 2px 8px;
-        border-radius: 12px;
-        background: #f2f3f5;
-        color: #4e5969;
+
+  // 响应式设计
+  @media (max-width: 768px) {
+    padding: 15px;
+
+    .top-navigation {
+      margin-bottom: 20px;
+
+      .nav-buttons {
+        .nav-button {
+          padding: 10px 16px;
+          font-size: 14px;
+        }
       }
     }
-  }
-}
-
-/* 优化结构分析 */
-.structure-analysis {
-  .structure-item {
-    background: #fff;
-    border: 1px solid #e5e6eb;
-    border-radius: 8px;
-    padding: 16px;
-    margin-bottom: 12px;
-    
-    .structure-header {
-      display: flex;
-      justify-content: space-between;
-      align-items: center;
-      margin-bottom: 8px;
-      
-      .structure-name {
-        font-weight: 500;
-        color: #1d2129;
+
+    .visualization-page {
+      .main-layout {
+        gap: 15px;
       }
-      
-      .structure-count {
-        font-weight: 600;
-        color: #165DFF;
+
+      .left-panel {
+        gap: 15px;
+
+        .chart-card {
+          mat-card-header {
+            padding: 15px;
+
+            mat-card-title {
+              font-size: 16px;
+            }
+          }
+
+          mat-card-content {
+            padding: 15px;
+          }
+        }
       }
     }
-    
-    .structure-percentage {
-      font-size: 12px;
-      color: #86909c;
-      margin-top: 4px;
-      display: block;
-    }
   }
-}
 
-/* 响应式优化 */
-@media (max-width: 768px) {
-  .dashboard-content {
-    grid-template-columns: 1fr;
+  // 滚动条样式
+  ::-webkit-scrollbar {
+    width: 8px;
   }
-  
-  .metrics-container {
-    grid-template-columns: 1fr;
+
+  ::-webkit-scrollbar-track {
+    background: rgba(0, 0, 0, 0.1);
+    border-radius: 4px;
   }
-  
-  .department-table {
-    font-size: 14px;
-    
-    .table-cell {
-      padding: 8px 12px;
+
+  ::-webkit-scrollbar-thumb {
+    background: rgba(0, 0, 0, 0.3);
+    border-radius: 4px;
+
+    &:hover {
+      background: rgba(0, 0, 0, 0.5);
     }
   }
 }

+ 578 - 309
src/app/pages/hr/dashboard/dashboard.ts

@@ -1,84 +1,72 @@
-import { Component, OnInit, AfterViewInit, OnDestroy, signal } from '@angular/core';
+import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { RouterModule } from '@angular/router';
 import { MatCardModule } from '@angular/material/card';
 import { MatButtonModule } from '@angular/material/button';
-import { MatIconModule } from '@angular/material/icon';
 import { MatTabsModule } from '@angular/material/tabs';
-import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { MatIconModule } from '@angular/material/icon';
+import { MatCheckboxModule } from '@angular/material/checkbox';
 import { MatChipsModule } from '@angular/material/chips';
-import { MatSelectModule } from '@angular/material/select';
-import { FormsModule } from '@angular/forms';
-
-// 模拟数据接口
-interface EmployeeMovement {
-  month: string;
-  hired: number;
-  resigned: number;
-  turnoverRate: number;
-}
-
-interface DepartmentData {
-  name: string;
-  hired: number;
-  resigned: number;
-  turnoverRate: number;
-}
+import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { MatBadgeModule } from '@angular/material/badge';
+import { DragDropModule, CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
+import { Chart, ChartConfiguration, registerables } from 'chart.js';
+import { trigger, state, style, transition, animate } from '@angular/animations';
 
-interface PendingProcess {
-  type: 'hire' | 'resign';
-  count: number;
-  progress: number;
+// 数据模型定义
+export interface TodoItem {
+  id: number;
+  title: string;
+  description: string;
+  priority: 'high' | 'medium' | 'low';
+  status: 'pending' | 'completed' | 'in_progress';
+  type: 'resume' | 'onboarding' | 'promotion' | 'resignation';
 }
 
-interface RiskAlert {
-  type: string;
-  employees: {name: string; position: string; department: string; daysLeft?: number}[];
-  count: number;
+export interface RankDistribution {
+  junior: number;
+  intermediate: number;
+  senior: number;
 }
 
-interface PerformanceMetric {
-  name: string;
-  target: number;
-  actual: number;
-  unit: string;
+export interface MonthlyData {
+  month: string;
+  hired: number;
+  left: number;
+  notes?: string;
 }
 
-interface DepartmentPerformance {
-  name: string;
+export interface DepartmentPerformance {
+  department: string;
+  completionRate: number;
   excellentWorkRate: number;
-  deliveryOnTimeRate: number;
-  customerSatisfaction: number;
+  satisfactionRate: number;
+  overdueRate: number;
 }
 
-interface PerformanceTier {
-  name: string;
-  percentage: number;
-  count: number;
+export interface PromotionRule {
+  id: number;
+  title: string;
+  description: string;
+  conditions: string[];
 }
 
-interface PenaltyWarning {
-  issue: string;
-  departments: {name: string; count: number}[];
-  employees: {name: string; department: string; count: number}[];
+export interface PromotionSuggestion {
+  employeeId: number;
+  employeeName: string;
+  currentRank: string;
+  suggestedRank: string;
+  reasons: string[];
+  status: 'pending' | 'approved' | 'rejected';
 }
 
-interface EmployeeStructure {
-  category: string;
-  data: {name: string; count: number; percentage: number}[];
-}
-
-interface MovementTrend {
-  month: string;
-  hired: number;
-  resigned: number;
-}
-
-interface TodoItem {
-  task: string;
+export interface OnboardingCheckpoint {
+  id: number;
+  title: string;
+  description: string;
   dueDate: Date;
-  priority: 'high' | 'medium' | 'low';
-  type: string;
+  completed: boolean;
+  interviewTemplate: string[];
 }
 
 @Component({
@@ -89,293 +77,574 @@ interface TodoItem {
     RouterModule,
     MatCardModule,
     MatButtonModule,
-    MatIconModule,
     MatTabsModule,
-    MatProgressBarModule,
+    MatIconModule,
+    MatCheckboxModule,
     MatChipsModule,
-    MatSelectModule,
-    FormsModule
+    MatProgressBarModule,
+    MatBadgeModule,
+    DragDropModule
   ],
   templateUrl: './dashboard.html',
-  styleUrls: ['./dashboard.scss']
+  styleUrls: ['./dashboard.scss'],
+  animations: [
+    trigger('slideInOut', [
+      transition(':enter', [
+        style({ height: '0', opacity: 0, overflow: 'hidden' }),
+        animate('300ms ease-in-out', style({ height: '*', opacity: 1 }))
+      ]),
+      transition(':leave', [
+        animate('300ms ease-in-out', style({ height: '0', opacity: 0, overflow: 'hidden' }))
+      ])
+    ])
+  ]
 })
-export class Dashboard implements OnInit, AfterViewInit, OnDestroy {
-  // 时间筛选
-  timeFilter = signal('month');
-
-  // 图表实例
-  private movementChart: any | null = null;
-  private performanceChart: any | null = null;
-  private trendChart: any | null = null;
-  // 入职离职数据
-  employeeMovements = signal<EmployeeMovement[]>([
-    { month: '1月', hired: 12, resigned: 5, turnoverRate: 3.2 },
-    { month: '2月', hired: 8, resigned: 4, turnoverRate: 2.5 },
-    { month: '3月', hired: 15, resigned: 6, turnoverRate: 3.8 },
-    { month: '4月', hired: 10, resigned: 8, turnoverRate: 5.1 },
-    { month: '5月', hired: 14, resigned: 7, turnoverRate: 4.2 },
-    { month: '6月', hired: 18, resigned: 5, turnoverRate: 2.9 }
-  ]);
+export class Dashboard implements OnInit, AfterViewInit {
+  @ViewChild('pieChart', { static: false }) pieChartRef!: ElementRef<HTMLCanvasElement>;
+  @ViewChild('lineChart', { static: false }) lineChartRef!: ElementRef<HTMLCanvasElement>;
+  @ViewChild('radarChart', { static: false }) radarChartRef!: ElementRef<HTMLCanvasElement>;
   
-  departmentData = signal<DepartmentData[]>([
-    { name: '设计部', hired: 8, resigned: 3, turnoverRate: 4.2 },
-    { name: '客服部', hired: 5, resigned: 2, turnoverRate: 3.1 },
-    { name: '技术部', hired: 12, resigned: 4, turnoverRate: 5.3 },
-    { name: '行政部', hired: 3, resigned: 1, turnoverRate: 2.8 }
-  ]);
+  private pieChart!: Chart;
+  private lineChart!: Chart;
+  private radarChart!: Chart;
+  // 当前激活的标签页
+  activeTab: 'visualization' | 'promotion' | 'onboarding' = 'visualization';
   
-  pendingProcesses = signal<PendingProcess[]>([
-    { type: 'hire', count: 8, progress: 65 },
-    { type: 'resign', count: 3, progress: 40 }
-  ]);
+  // 待办事项是否展开
+  isTodoExpanded = false;
   
-  riskAlerts = signal<RiskAlert[]>([
-    { 
-      type: '试用期即将到期', 
-      employees: [
-        { name: '张三', position: '设计师', department: '设计部', daysLeft: 7 },
-        { name: '李四', position: '客服专员', department: '客服部', daysLeft: 10 },
-        { name: '王五', position: '前端开发', department: '技术部', daysLeft: 15 }
-      ],
-      count: 3
+  // 当前页面
+  currentPage: string = 'dashboard';
+  
+  // 待办事项展开状态
+  showTodoList: boolean = false;
+
+  // 待办事项列表(用于右侧展示)
+  todoList = [
+    {
+      id: 1,
+      title: '简历初筛',
+      description: '筛选新收到的设计师简历',
+      priority: 'high',
+      dueDate: '2024-01-25'
     },
-    { 
-      type: '离职关键岗位', 
-      employees: [
-        { name: '赵六', position: '高级设计师', department: '设计部' },
-        { name: '钱七', position: '技术组长', department: '技术部' }
-      ],
-      count: 2
+    {
+      id: 2,
+      title: '入职评定',
+      description: '完成新员工入职评定表',
+      priority: 'medium',
+      dueDate: '2024-01-28'
+    },
+    {
+      id: 3,
+      title: '晋升审核',
+      description: '审核中级设计师晋升申请',
+      priority: 'high',
+      dueDate: '2024-01-30'
+    },
+    {
+      id: 4,
+      title: '离职面谈',
+      description: '安排资深设计师离职面谈',
+      priority: 'medium',
+      dueDate: '2024-02-02'
     }
-  ]);
-  
-  // 绩效数据
-  performanceMetrics = signal<PerformanceMetric[]>([
-    { name: '优秀作品率', target: 80, actual: 76, unit: '%' },
-    { name: '项目交付准时率', target: 95, actual: 92, unit: '%' },
-    { name: '客户满意度评分', target: 4.5, actual: 4.3, unit: '分' }
-  ]);
-  
-  departmentPerformance = signal<DepartmentPerformance[]>([
-    { name: '设计部', excellentWorkRate: 78, deliveryOnTimeRate: 94, customerSatisfaction: 4.4 },
-    { name: '客服部', excellentWorkRate: 82, deliveryOnTimeRate: 96, customerSatisfaction: 4.6 },
-    { name: '技术部', excellentWorkRate: 75, deliveryOnTimeRate: 90, customerSatisfaction: 4.2 },
-    { name: '行政部', excellentWorkRate: 80, deliveryOnTimeRate: 95, customerSatisfaction: 4.5 }
-  ]);
+  ];
   
-  performanceTiers = signal<PerformanceTier[]>([
-    { name: '头部20%', percentage: 20, count: 24 },
-    { name: '中部70%', percentage: 70, count: 84 },
-    { name: '尾部10%', percentage: 10, count: 12 }
-  ]);
-  
-  penaltyWarnings = signal<PenaltyWarning[]>([
-    { 
-      issue: '项目延期', 
-      departments: [
-        { name: '设计部', count: 5 },
-        { name: '技术部', count: 3 }
-      ],
-      employees: [
-        { name: '张三', department: '设计部', count: 2 },
-        { name: '李四', department: '技术部', count: 2 }
+  // 模拟数据
+  todoItems: TodoItem[] = [
+    {
+      id: 1,
+      title: '简历初筛',
+      description: '筛选新收到的设计师简历',
+      priority: 'high',
+      status: 'pending',
+      type: 'resume'
+    },
+    {
+      id: 2,
+      title: '入职评定',
+      description: '完成新员工入职评定表',
+      priority: 'medium',
+      status: 'pending',
+      type: 'onboarding'
+    },
+    {
+      id: 3,
+      title: '晋升审核',
+      description: '审核中级设计师晋升申请',
+      priority: 'high',
+      status: 'pending',
+      type: 'promotion'
+    },
+    {
+      id: 4,
+      title: '离职面谈',
+      description: '安排资深设计师离职面谈',
+      priority: 'medium',
+      status: 'pending',
+      type: 'resignation'
+    }
+  ];
+
+  // 职级分布数据
+  rankDistribution = [
+    { level: '初级设计师', count: 15, percentage: 45, color: '#4CAF50' },
+    { level: '中级设计师', count: 12, percentage: 36, color: '#FF9800' },
+    { level: '高级设计师', count: 6, percentage: 19, color: '#2196F3' }
+  ];
+
+  monthlyHireData: MonthlyData[] = [
+    { month: '10月', hired: 8, left: 3, notes: '秋季招聘高峰' },
+    { month: '11月', hired: 5, left: 2, notes: '' },
+    { month: '12月', hired: 3, left: 4, notes: '年底离职高峰' },
+    { month: '1月', hired: 10, left: 1, notes: '新年新气象' },
+    { month: '2月', hired: 6, left: 2, notes: '' },
+    { month: '3月', hired: 12, left: 3, notes: '春季招聘启动' }
+  ];
+
+  // 关键节点数据
+  keyNotes = [
+    { month: '3月', description: '入职10人:因春季招聘' },
+    { month: '5月', description: '离职5人:因项目不饱和' },
+    { month: '8月', description: '入职15人:暑期实习转正' },
+    { month: '12月', description: '离职8人:年底跳槽高峰' }
+  ];
+
+  // 关键岗位空缺数据
+  keyVacancies = [
+    { position: '高级UI设计师', count: 2, priority: 'high', duration: 45 },
+    { position: '3D建模师', count: 1, priority: 'medium', duration: 20 },
+    { position: '前端开发工程师', count: 1, priority: 'medium', duration: 15 },
+    { position: '产品经理', count: 1, priority: 'high', duration: 60 }
+  ];
+
+  // 新人列表数据
+  newbieList = [
+    { id: 1, name: '张三', position: 'UI设计师', joinDate: '2024-01-15', progress: 75 },
+    { id: 2, name: '李四', position: '前端开发', joinDate: '2024-01-20', progress: 60 },
+    { id: 3, name: '王五', position: '3D建模师', joinDate: '2024-02-01', progress: 40 }
+  ];
+
+  departmentPerformance: DepartmentPerformance[] = [
+    {
+      department: 'UI设计部',
+      completionRate: 92,
+      excellentWorkRate: 78,
+      satisfactionRate: 88,
+      overdueRate: 8
+    },
+    {
+      department: '3D建模部', 
+      completionRate: 85,
+      excellentWorkRate: 82,
+      satisfactionRate: 90,
+      overdueRate: 15
+    },
+    {
+      department: '前端开发部',
+      completionRate: 88,
+      excellentWorkRate: 75,
+      satisfactionRate: 85,
+      overdueRate: 12
+    }
+  ];
+
+  promotionRules: PromotionRule[] = [
+    {
+      id: 1,
+      title: '初级→中级晋升标准',
+      description: '设计师晋升中级标准',
+      conditions: [
+        '连续3个月优秀作品率超过80%',
+        '逾期率低于5%',
+        '客户满意度评分4.5以上',
+        '至少完成12个主要项目'
       ]
     },
-    { 
-      issue: '投诉差评', 
-      departments: [
-        { name: '客服部', count: 4 },
-        { name: '设计部', count: 2 }
-      ],
-      employees: [
-        { name: '王五', department: '客服部', count: 3 },
-        { name: '赵六', department: '设计部', count: 1 }
+    {
+      id: 2,
+      title: '中级→高级晋升标准',
+      description: '设计师晋升高级标准',
+      conditions: [
+        '连续6个月优秀作品率超过85%',
+        '逾期率低于3%',
+        '客户满意度评分4.8以上',
+        '带领过至少2个大型项目',
+        '有 mentorship 经验'
       ]
     }
-  ]);
-  
-  // 关键数据
-  employeeStructures = signal<EmployeeStructure[]>([
+  ];
+
+  promotionSuggestions: PromotionSuggestion[] = [
     {
-      category: '技术等级',
-      data: [
-        { name: '初级', count: 45, percentage: 37.5 },
-        { name: '中级', count: 55, percentage: 45.8 },
-        { name: '高级', count: 20, percentage: 16.7 }
+      employeeId: 1001,
+      employeeName: '张三',
+      currentRank: '初级设计师',
+      suggestedRank: '中级设计师',
+      reasons: [
+        '连续3个月优秀作品率85%',
+        '逾期率仅2%',
+        '客户满意度4.7分',
+        '已完成15个主要项目'
+      ],
+      status: 'pending'
+    },
+    {
+      employeeId: 1002,
+      employeeName: '李四',
+      currentRank: '中级设计师',
+      suggestedRank: '高级设计师',
+      reasons: [
+        '连续6个月优秀作品率88%',
+        '逾期率1.5%',
+        '客户满意度4.9分',
+        '成功带领3个大型项目'
+      ],
+      status: 'pending'
+    }
+  ];
+
+  onboardingCheckpoints: OnboardingCheckpoint[] = [
+    {
+      id: 1,
+      title: '入职1周面谈',
+      description: '了解新人工作适应情况',
+      dueDate: new Date(),
+      completed: false,
+      interviewTemplate: [
+        '工作环境是否适应?',
+        '是否有不清楚的工作流程?',
+        '团队沟通是否顺畅?',
+        '是否需要额外的工作工具?'
       ]
     },
     {
-      category: '岗位类型',
-      data: [
-        { name: '设计师', count: 60, percentage: 50 },
-        { name: '客服', count: 30, percentage: 25 },
-        { name: '技术组长', count: 15, percentage: 12.5 },
-        { name: '其他', count: 15, percentage: 12.5 }
+      id: 2,
+      title: '入职1个月评估',
+      description: '评估新人技能掌握情况',
+      dueDate: new Date(Date.now() + 21 * 24 * 60 * 60 * 1000),
+      completed: false,
+      interviewTemplate: [
+        '主要工作技能掌握程度?',
+        '遇到的最大挑战是什么?',
+        '对团队文化的感受?',
+        '个人职业发展期望?'
       ]
     },
     {
-      category: '部门',
-      data: [
-        { name: '设计部', count: 65, percentage: 54.2 },
-        { name: '客服部', count: 35, percentage: 29.2 },
-        { name: '技术部', count: 20, percentage: 16.6 }
+      id: 3,
+      title: '入职3个月总结',
+      description: '全面评估新人表现',
+      dueDate: new Date(Date.now() + 83 * 24 * 60 * 60 * 1000),
+      completed: false,
+      interviewTemplate: [
+        '工作成果总体评价',
+        '需要改进的技能领域',
+        '长期职业规划讨论',
+        '转正评估准备'
       ]
     }
-  ]);
-  
-  movementTrends = signal<MovementTrend[]>([
-    { month: '1月', hired: 12, resigned: 5 },
-    { month: '2月', hired: 8, resigned: 4 },
-    { month: '3月', hired: 15, resigned: 6 },
-    { month: '4月', hired: 10, resigned: 8 },
-    { month: '5月', hired: 14, resigned: 7 },
-    { month: '6月', hired: 18, resigned: 5 }
-  ]);
-  
-  todoItems = signal<TodoItem[]>([
-    { task: '审核张三绩效表', dueDate: new Date('2023-06-15'), priority: 'high', type: '绩效审核' },
-    { task: '签署李四离职协议', dueDate: new Date('2023-06-12'), priority: 'high', type: '离职手续' },
-    { task: '跟进王五试用期评估', dueDate: new Date('2023-06-20'), priority: 'medium', type: '试用期评估' },
-    { task: '审核新员工入职材料', dueDate: new Date('2023-06-18'), priority: 'medium', type: '入职手续' },
-    { task: '更新部门人员架构图', dueDate: new Date('2023-06-25'), priority: 'low', type: '文档更新' }
-  ]);
-  
+  ];
+
   ngOnInit() {
-    // 实际项目中这里会调用服务获取数据
-  }
-  
-  ngAfterViewInit(): void {
+    // 注册Chart.js组件
+    Chart.register(...registerables);
+    // 初始化图表数据
     this.initCharts();
-    window.addEventListener('resize', this.handleResize);
   }
-  
-  ngOnDestroy(): void {
-    window.removeEventListener('resize', this.handleResize);
-    this.disposeCharts();
+
+  ngAfterViewInit() {
+    // 延迟初始化图表,确保DOM已渲染
+    setTimeout(() => {
+      this.initializeCharts();
+    }, 100);
   }
-  
-  // 切换时间维度
-  changeTimeFilter(filter: string) {
-    this.timeFilter.set(filter);
-    // 实际项目中这里会根据筛选条件重新获取数据
-    // 刷新图表
-    this.initCharts();
+
+  // 切换标签页
+  switchTab(tab: 'visualization' | 'promotion' | 'onboarding') {
+    this.activeTab = tab;
   }
-  
-  // 跳转到对应处理页面
-  navigateToProcess(type: 'hire' | 'resign') {
-    // 实际项目中这里会导航到对应页面
-    console.log(`Navigate to ${type} process page`);
+
+
+
+  // 初始化图表(这里需要后续集成ECharts)
+  private initCharts() {
+    // 图表初始化逻辑将在后续实现
+    console.log('初始化图表数据');
   }
-  
-  // 获取进度条颜色
-  getProgressColor(value: number, target: number): string {
-    const percentage = (value / target) * 100;
-    if (percentage >= 90) return 'primary';
-    if (percentage >= 70) return 'accent';
-    return 'warn';
+
+  // 拖拽排序
+  drop(event: CdkDragDrop<TodoItem[]>) {
+    moveItemInArray(this.todoItems, event.previousIndex, event.currentIndex);
   }
-  
-  // 获取优先级样式类
+
+
+
+  // 获取优先级颜色
+  getPriorityColor(priority: string): string {
+    switch (priority) {
+      case 'high': return '#ff4757';
+      case 'medium': return '#ffa502';
+      case 'low': return '#2ed573';
+      default: return '#a4b0be';
+    }
+  }
+
+  // 获取空缺岗位图标
+  getVacancyIcon(urgency: string): string {
+    switch (urgency) {
+      case 'urgent': return 'warning';
+      case 'normal': return 'info';
+      default: return 'help';
+    }
+  }
+
+  // 获取部门颜色
+  getDepartmentColor(department: string): string {
+    const colors: { [key: string]: string } = {
+      'UI设计部': '#2196F3',
+      '3D建模部': '#4CAF50',
+      '前端开发部': '#FF9800',
+      '产品部': '#9C27B0'
+    };
+    return colors[department] || '#757575';
+  }
+
+  // 获取优先级类名
   getPriorityClass(priority: string): string {
+    return `priority-${priority}`;
+  }
+
+  toggleTodoList(): void {
+    this.showTodoList = !this.showTodoList;
+  }
+
+  // 获取甜甜圈图表特定选项
+  private getDoughnutOptions(): any {
+    return {
+      cutout: '60%'
+    };
+  }
+
+  // 初始化所有图表
+  private initializeCharts() {
+    this.initPieChart();
+    this.initLineChart();
+    this.initRadarChart();
+  }
+
+  // 初始化职级分布饼图
+  private initPieChart() {
+    if (!this.pieChartRef?.nativeElement) return;
+
+    const ctx = this.pieChartRef.nativeElement.getContext('2d');
+    if (!ctx) return;
+
+    const config: ChartConfiguration = {
+      type: 'doughnut',
+      data: {
+        labels: this.rankDistribution.map(item => item.level),
+        datasets: [{
+          data: this.rankDistribution.map(item => item.percentage),
+          backgroundColor: this.rankDistribution.map(item => item.color),
+          borderWidth: 0,
+          hoverBorderWidth: 2,
+          hoverBorderColor: '#fff'
+        }]
+      },
+      options: {
+        responsive: true,
+        maintainAspectRatio: false,
+        plugins: {
+          legend: {
+            display: false
+          },
+          tooltip: {
+            callbacks: {
+              label: (context) => {
+                const label = context.label || '';
+                const value = context.parsed;
+                const count = this.rankDistribution[context.dataIndex].count;
+                return `${label}: ${value}% (${count}人)`;
+              }
+            }
+          }
+        },
+        ...(this.getDoughnutOptions())
+      }
+    };
+
+    this.pieChart = new Chart(ctx, config);
+  }
+
+  // 初始化入职离职趋势折线图
+  private initLineChart() {
+    if (!this.lineChartRef?.nativeElement) return;
+
+    const ctx = this.lineChartRef.nativeElement.getContext('2d');
+    if (!ctx) return;
+
+    const config: ChartConfiguration = {
+      type: 'line',
+      data: {
+        labels: this.monthlyHireData.map(item => item.month),
+        datasets: [
+          {
+            label: '入职人数',
+            data: this.monthlyHireData.map(item => item.hired),
+            borderColor: '#4CAF50',
+            backgroundColor: 'rgba(76, 175, 80, 0.1)',
+            tension: 0.4,
+            fill: true
+          },
+          {
+            label: '离职人数',
+            data: this.monthlyHireData.map(item => item.left),
+            borderColor: '#f44336',
+            backgroundColor: 'rgba(244, 67, 54, 0.1)',
+            tension: 0.4,
+            fill: true
+          }
+        ]
+      },
+      options: {
+        responsive: true,
+        maintainAspectRatio: false,
+        plugins: {
+          legend: {
+            position: 'top'
+          },
+          tooltip: {
+            mode: 'index',
+            intersect: false
+          }
+        },
+        scales: {
+          y: {
+            beginAtZero: true,
+            grid: {
+              color: 'rgba(0, 0, 0, 0.1)'
+            }
+          },
+          x: {
+            grid: {
+              color: 'rgba(0, 0, 0, 0.1)'
+            }
+          }
+        },
+        interaction: {
+          mode: 'nearest',
+          axis: 'x',
+          intersect: false
+        }
+      }
+    };
+
+    this.lineChart = new Chart(ctx, config);
+  }
+
+  // 初始化绩效总览雷达图
+  private initRadarChart() {
+    if (!this.radarChartRef?.nativeElement) return;
+
+    const ctx = this.radarChartRef.nativeElement.getContext('2d');
+    if (!ctx) return;
+
+    const config: ChartConfiguration = {
+      type: 'radar',
+      data: {
+        labels: ['项目完成率', '优秀作品率', '客户满意度', '逾期率'],
+        datasets: this.departmentPerformance.map((dept, index) => ({
+          label: dept.department,
+          data: [
+            dept.completionRate,
+            dept.excellentWorkRate,
+            dept.satisfactionRate,
+            100 - dept.overdueRate // 逾期率转换为正向指标
+          ],
+          borderColor: this.getDepartmentColor(dept.department),
+          backgroundColor: this.getDepartmentColor(dept.department) + '20',
+          pointBackgroundColor: this.getDepartmentColor(dept.department),
+          pointBorderColor: '#fff',
+          pointHoverBackgroundColor: '#fff',
+          pointHoverBorderColor: this.getDepartmentColor(dept.department)
+        }))
+      },
+      options: {
+        responsive: true,
+        maintainAspectRatio: false,
+        plugins: {
+          legend: {
+            position: 'bottom'
+          }
+        },
+        scales: {
+          r: {
+            beginAtZero: true,
+            max: 100,
+            grid: {
+              color: 'rgba(0, 0, 0, 0.1)'
+            },
+            angleLines: {
+              color: 'rgba(0, 0, 0, 0.1)'
+            },
+            pointLabels: {
+              font: {
+                size: 12
+              }
+            }
+          }
+        }
+      }
+    };
+
+    this.radarChart = new Chart(ctx, config);
+  }
+
+  getPriorityLabel(priority: string): string {
     switch (priority) {
-      case 'high': return 'priority-high';
-      case 'medium': return 'priority-medium';
-      case 'low': return 'priority-low';
-      default: return '';
+      case 'high': return '紧急';
+      case 'medium': return '重要';
+      case 'low': return '一般';
+      default: return '未知';
     }
   }
-  
-  // ====== 图表相关 ======
-  private initCharts(): void {
-    this.initMovementChart();
-    this.initPerformanceDistributionChart();
-    this.initTrendChart();
+
+  getTypeLabel(type: string): string {
+    switch (type) {
+      case 'resume': return '简历初筛';
+      case 'onboarding': return '入职评定';
+      case 'promotion': return '晋升审核';
+      case 'resignation': return '离职面谈';
+      default: return '其他';
+    }
   }
-  
-  private disposeCharts(): void {
-    if (this.movementChart) { this.movementChart.dispose(); this.movementChart = null; }
-    if (this.performanceChart) { this.performanceChart.dispose(); this.performanceChart = null; }
-    if (this.trendChart) { this.trendChart.dispose(); this.trendChart = null; }
+
+  getStatusLabel(status: string): string {
+    const statusMap: { [key: string]: string } = {
+      'pending': '待处理',
+      'in_progress': '进行中',
+      'completed': '已完成',
+      'urgent': '紧急',
+      'normal': '普通'
+    };
+    return statusMap[status] || status;
   }
-  
-  private initMovementChart(): void {
-    const el = document.getElementById('hrMovementChart');
-    if (!el) return;
-    this.movementChart?.dispose();
-    // 使用全局 echarts 变量
-    // @ts-ignore
-    this.movementChart = echarts.init(el);
-  
-    const data = this.employeeMovements();
-    const months = data.map(d => d.month);
-    const hired = data.map(d => d.hired);
-    const resigned = data.map(d => d.resigned);
-  
-    this.movementChart.setOption({
-      title: { text: '月度入职/离职', left: 'center', textStyle: { fontSize: 16 } },
-      tooltip: { trigger: 'axis' },
-      legend: { data: ['入职', '离职'] },
-      grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
-      xAxis: { type: 'category', data: months },
-      yAxis: { type: 'value' },
-      series: [
-        { name: '入职', type: 'bar', data: hired, itemStyle: { color: '#165DFF' }, barGap: 0 },
-        { name: '离职', type: 'bar', data: resigned, itemStyle: { color: '#F53F3F' } }
-      ]
-    });
+
+  // 拖拽排序功能
+  onTodoDrop(event: CdkDragDrop<TodoItem[]>): void {
+    moveItemInArray(this.todoItems, event.previousIndex, event.currentIndex);
   }
-  
-  private initPerformanceDistributionChart(): void {
-    const el = document.getElementById('hrPerformanceDistributionChart');
-    if (!el) return;
-    this.performanceChart?.dispose();
-    // @ts-ignore
-    this.performanceChart = echarts.init(el);
-  
-    const tiers = this.performanceTiers();
-    const data = tiers.map(t => ({ value: t.count, name: `${t.name}(${t.count}人)` }));
-  
-    this.performanceChart.setOption({
-      title: { text: '绩效等级分布', left: 'center', textStyle: { fontSize: 16 } },
-      tooltip: { trigger: 'item', formatter: '{b}: {c} 人 ({d}%)' },
-      legend: { orient: 'horizontal', bottom: 0 },
-      series: [{
-        type: 'pie', radius: '65%', center: ['50%', '50%'],
-        data,
-        emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.3)' } }
-      }]
-    });
+
+  // 更新待办事项状态
+  updateTodoStatus(todo: TodoItem, status: 'pending' | 'completed' | 'in_progress'): void {
+    todo.status = status;
   }
-  
-  private initTrendChart(): void {
-    const el = document.getElementById('hrTrendChart');
-    if (!el) return;
-    this.trendChart?.dispose();
-    // @ts-ignore
-    this.trendChart = echarts.init(el);
-  
-    const trend = this.movementTrends();
-    const months = trend.map(t => t.month);
-    const hired = trend.map(t => t.hired);
-    const resigned = trend.map(t => t.resigned);
-  
-    this.trendChart.setOption({
-      title: { text: '异动趋势', left: 'center', textStyle: { fontSize: 16 } },
-      tooltip: { trigger: 'axis' },
-      legend: { data: ['入职', '离职'] },
-      xAxis: { type: 'category', data: months },
-      yAxis: { type: 'value' },
-      series: [
-        { name: '入职', type: 'line', data: hired, smooth: true, lineStyle: { color: '#00B42A' }, itemStyle: { color: '#00B42A' } },
-        { name: '离职', type: 'line', data: resigned, smooth: true, lineStyle: { color: '#F53F3F' }, itemStyle: { color: '#F53F3F' } }
-      ]
-    });
+
+  // 处理按钮按压效果
+  isButtonPressed = false;
+  handleButtonPress(action: 'press' | 'release') {
+    this.isButtonPressed = action === 'press';
   }
-  
-  private handleResize = (): void => {
-    this.movementChart?.resize();
-    this.performanceChart?.resize();
-    this.trendChart?.resize();
-  };
 }

+ 9 - 0
src/assets/images/case-1-cover.svg

@@ -0,0 +1,9 @@
+<svg width="400" height="300" viewBox="0 0 400 300" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect width="400" height="300" fill="#F8FAFC"/>
+  <rect x="50" y="50" width="300" height="200" fill="#E2E8F0" rx="8"/>
+  <rect x="80" y="80" width="240" height="120" fill="#CBD5E1" rx="4"/>
+  <circle cx="120" cy="120" r="20" fill="#94A3B8"/>
+  <rect x="160" y="110" width="120" height="8" fill="#94A3B8" rx="4"/>
+  <rect x="160" y="130" width="80" height="8" fill="#CBD5E1" rx="4"/>
+  <text x="200" y="260" text-anchor="middle" fill="#64748B" font-family="Arial" font-size="14" font-weight="500">现代简约客厅</text>
+</svg>

+ 9 - 0
src/assets/images/case-2-cover.svg

@@ -0,0 +1,9 @@
+<svg width="400" height="300" viewBox="0 0 400 300" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect width="400" height="300" fill="#FEF7F0"/>
+  <rect x="50" y="50" width="300" height="200" fill="#FED7AA" rx="8"/>
+  <rect x="80" y="80" width="240" height="120" fill="#FB923C" rx="4"/>
+  <circle cx="120" cy="120" r="20" fill="#EA580C"/>
+  <rect x="160" y="110" width="120" height="8" fill="#EA580C" rx="4"/>
+  <rect x="160" y="130" width="80" height="8" fill="#FB923C" rx="4"/>
+  <text x="200" y="260" text-anchor="middle" fill="#9A3412" font-family="Arial" font-size="14" font-weight="500">温馨北欧卧室</text>
+</svg>

+ 9 - 0
src/assets/images/case-3-cover.svg

@@ -0,0 +1,9 @@
+<svg width="400" height="300" viewBox="0 0 400 300" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect width="400" height="300" fill="#F0FDF4"/>
+  <rect x="50" y="50" width="300" height="200" fill="#BBF7D0" rx="8"/>
+  <rect x="80" y="80" width="240" height="120" fill="#4ADE80" rx="4"/>
+  <circle cx="120" cy="120" r="20" fill="#16A34A"/>
+  <rect x="160" y="110" width="120" height="8" fill="#16A34A" rx="4"/>
+  <rect x="160" y="130" width="80" height="8" fill="#4ADE80" rx="4"/>
+  <text x="200" y="260" text-anchor="middle" fill="#15803D" font-family="Arial" font-size="14" font-weight="500">工业风餐厅</text>
+</svg>

+ 9 - 0
src/assets/images/case-4-cover.svg

@@ -0,0 +1,9 @@
+<svg width="400" height="300" viewBox="0 0 400 300" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <rect width="400" height="300" fill="#FEF3F2"/>
+  <rect x="50" y="50" width="300" height="200" fill="#FECACA" rx="8"/>
+  <rect x="80" y="80" width="240" height="120" fill="#F87171" rx="4"/>
+  <circle cx="120" cy="120" r="20" fill="#DC2626"/>
+  <rect x="160" y="110" width="120" height="8" fill="#DC2626" rx="4"/>
+  <rect x="160" y="130" width="80" height="8" fill="#F87171" rx="4"/>
+  <text x="200" y="260" text-anchor="middle" fill="#991B1B" font-family="Arial" font-size="14" font-weight="500">中式古典书房</text>
+</svg>