浏览代码

feat:customer10

徐福静0235668 11 小时之前
父节点
当前提交
7848f058a0
共有 27 个文件被更改,包括 3550 次插入1566 次删除
  1. 16 0
      src/app/pages/customer-service/consultation-order/consultation-order-dialog.component.html
  2. 111 0
      src/app/pages/customer-service/consultation-order/consultation-order-dialog.component.scss
  3. 40 0
      src/app/pages/customer-service/consultation-order/consultation-order-dialog.component.ts
  4. 48 55
      src/app/pages/customer-service/consultation-order/consultation-order.html
  5. 69 2
      src/app/pages/customer-service/consultation-order/consultation-order.scss
  6. 62 99
      src/app/pages/customer-service/consultation-order/consultation-order.ts
  7. 25 0
      src/app/pages/customer-service/create-project-modal/create-project-modal.component.html
  8. 6 0
      src/app/pages/customer-service/create-project-modal/create-project-modal.component.scss
  9. 30 0
      src/app/pages/customer-service/create-project-modal/create-project-modal.component.ts
  10. 1 6
      src/app/pages/customer-service/customer-service-layout/customer-service-layout.html
  11. 80 63
      src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.html
  12. 204 751
      src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.scss
  13. 94 391
      src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.ts
  14. 188 0
      src/app/pages/customer-service/project-detail/project-detail.html
  15. 516 0
      src/app/pages/customer-service/project-detail/project-detail.scss
  16. 274 5
      src/app/pages/customer-service/project-detail/project-detail.ts
  17. 2 28
      src/app/pages/customer-service/project-list/project-list.html
  18. 1 1
      src/app/pages/customer-service/project-list/project-list.scss
  19. 34 66
      src/app/pages/customer-service/project-list/project-list.ts
  20. 3 96
      src/app/pages/designer/project-detail/project-detail.html
  21. 9 2
      src/app/pages/designer/project-detail/project-detail.ts
  22. 125 1
      src/app/pages/team-leader/dashboard/dashboard.html
  23. 357 0
      src/app/pages/team-leader/dashboard/dashboard.scss
  24. 252 0
      src/app/pages/team-leader/dashboard/dashboard.ts
  25. 230 0
      src/app/shared/components/consultation-order-panel/consultation-order-panel.component.html
  26. 566 0
      src/app/shared/components/consultation-order-panel/consultation-order-panel.component.scss
  27. 207 0
      src/app/shared/components/consultation-order-panel/consultation-order-panel.component.ts

+ 16 - 0
src/app/pages/customer-service/consultation-order/consultation-order-dialog.component.html

@@ -0,0 +1,16 @@
+<div class="consultation-order-dialog">
+  <!-- 弹窗头部 -->
+  <div class="dialog-header">
+    <h2 class="dialog-title">创建新项目</h2>
+    <button class="close-button" (click)="onClose()" mat-icon-button>
+      <mat-icon>close</mat-icon>
+    </button>
+  </div>
+
+  <!-- 弹窗内容 -->
+  <div class="dialog-content">
+    <app-consultation-order 
+      (orderCreated)="onOrderCreated($event)">
+    </app-consultation-order>
+  </div>
+</div>

+ 111 - 0
src/app/pages/customer-service/consultation-order/consultation-order-dialog.component.scss

@@ -0,0 +1,111 @@
+@use '../../../shared/styles/variables';
+@use '../../../shared/styles/ios-theme' as ios;
+
+.consultation-order-dialog {
+  // 弹窗容器样式
+  .mat-mdc-dialog-container .mdc-dialog__surface {
+    border-radius: ios.$ios-radius-lg;
+    background: ios.$ios-card-background;
+    box-shadow: ios.$ios-shadow-lg;
+    border: 1px solid ios.$ios-border;
+    min-width: 800px;
+    max-width: 1000px;
+    max-height: 90vh;
+    overflow: hidden;
+  }
+
+  .dialog-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: ios.$ios-spacing-lg ios.$ios-spacing-lg ios.$ios-spacing-md;
+    border-bottom: 1px solid ios.$ios-border;
+    background: ios.$ios-background;
+
+    .dialog-title {
+      color: ios.$ios-text-primary;
+      font-weight: ios.$ios-font-weight-semibold;
+      font-family: ios.$ios-font-family;
+      font-size: ios.$ios-font-size-lg;
+      margin: 0;
+    }
+
+    .close-button {
+      color: ios.$ios-text-secondary;
+      transition: color 0.3s ease;
+
+      &:hover {
+        color: ios.$ios-primary;
+      }
+    }
+  }
+
+  .dialog-content {
+    padding: 0;
+    max-height: calc(90vh - 80px);
+    overflow-y: auto;
+
+    // 确保咨询订单组件内部样式正常
+    app-consultation-order {
+      display: block;
+      height: 100%;
+
+      ::ng-deep {
+        .consultation-order-container {
+          height: 100%;
+          border-radius: 0;
+          box-shadow: none;
+          margin: 0;
+
+          .dashboard-header {
+            border-radius: 0;
+            margin: 0;
+          }
+
+          .dashboard-content {
+            max-height: calc(90vh - 140px);
+            overflow-y: auto;
+            padding: ios.$ios-spacing-md;
+          }
+        }
+      }
+    }
+  }
+
+  // 响应式设计
+  @media (max-width: 1024px) {
+    .mat-mdc-dialog-container .mdc-dialog__surface {
+      min-width: 90vw;
+      max-width: 95vw;
+      margin: ios.$ios-spacing-md;
+    }
+  }
+
+  @media (max-width: 768px) {
+    .mat-mdc-dialog-container .mdc-dialog__surface {
+      min-width: 95vw;
+      max-width: 95vw;
+      margin: ios.$ios-spacing-sm;
+    }
+
+    .dialog-header {
+      padding: ios.$ios-spacing-md;
+
+      .dialog-title {
+        font-size: ios.$ios-font-size-md;
+      }
+    }
+
+    .dialog-content {
+      app-consultation-order {
+        ::ng-deep {
+          .consultation-order-container {
+            .dashboard-content {
+              padding: ios.$ios-spacing-sm;
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 40 - 0
src/app/pages/customer-service/consultation-order/consultation-order-dialog.component.ts

@@ -0,0 +1,40 @@
+import { Component, Inject, Output, EventEmitter } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { MatButtonModule } from '@angular/material/button';
+import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { MatIconModule } from '@angular/material/icon';
+import { ConsultationOrder } from './consultation-order';
+
+@Component({
+  selector: 'app-consultation-order-dialog',
+  standalone: true,
+  imports: [
+    CommonModule,
+    MatButtonModule,
+    MatDialogModule,
+    MatIconModule,
+    ConsultationOrder
+  ],
+  templateUrl: './consultation-order-dialog.component.html',
+  styleUrls: ['./consultation-order-dialog.component.scss']
+})
+export class ConsultationOrderDialogComponent {
+  @Output() orderCreated = new EventEmitter<any>();
+
+  constructor(
+    public dialogRef: MatDialogRef<ConsultationOrderDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: any
+  ) {}
+
+  onClose(): void {
+    this.dialogRef.close();
+  }
+
+  // 监听订单创建成功事件
+  onOrderCreated(orderData: any): void {
+    // 发出订单创建事件
+    this.orderCreated.emit(orderData);
+    // 关闭弹窗并返回订单数据
+    this.dialogRef.close(orderData);
+  }
+}

+ 48 - 55
src/app/pages/customer-service/consultation-order/consultation-order.html

@@ -1,8 +1,18 @@
 <div class="consultation-order-container">
   <!-- Dashboard风格页面头部 -->
   <header class="page-header">
-    <h1>创建订单</h1>
-    <div class="header-meta">通过小程序或人工方式创建新订单</div>
+    <!-- 返回按钮 -->
+    <button class="back-button" (click)="goBackToProjectList()" title="返回项目列表">
+      <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+        <path d="m15 18-6-6 6-6"/>
+      </svg>
+      <span>返回</span>
+    </button>
+    
+    <div class="header-content">
+      <h1>创建订单</h1>
+      <div class="header-meta">通过小程序或人工方式创建新订单</div>
+    </div>
     
     <!-- 成功提示 -->
     @if (showSuccessMessage()) {
@@ -66,17 +76,13 @@
               <button 
                 class="search-action-btn"
                 (click)="quickFillCustomerInfo(searchKeyword())"
-                [disabled]="!searchKeyword().trim() || isSyncing()"
+                [disabled]="!searchKeyword().trim()"
               >
-                @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>
-                  匹配
-                }
+                <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>
             
@@ -153,30 +159,12 @@
               重新选择
             </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>
 
     <!-- 新客户快速填写表单 -->
-    @if (!selectedCustomer() && orderCreationMethod() === 'manual') {
+    @if (!selectedCustomer()) {
       <section class="new-customer-form">
         <div class="form-header">
           <h3>新客户信息</h3>
@@ -221,49 +209,54 @@
             </svg>
             收起
           </button>
-          <button class="btn-primary btn-sm" (click)="syncProjectInfo()" [disabled]="isSyncing()">
-            @if (isSyncing()) {
-              <mat-spinner diameter="16"></mat-spinner>
-            }
-            @if (!isSyncing()) {
-              <span>从聊天记录提取</span>
-            }
-          </button>
         </div>
       </div>
 
       <div class="card-content">
         <form [formGroup]="requirementForm" class="requirement-form">
-          <div class="form-grid">
+          <!-- 第一行:装修类型、首付款、首稿时间 -->
+          <div class="form-row">
+            <div class="form-field">
+              <label for="decorationType" class="field-label">装修类型 <span class="required">*</span></label>
+              <select id="decorationType" formControlName="decorationType" class="field-select">
+                <option value="">请选择装修类型</option>
+                <option value="家装">家装</option>
+                <option value="工装">工装</option>
+              </select>
+            </div>
             <div class="form-field">
-              <label for="style" class="field-label">装修风格 <span class="required">*</span></label>
+              <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="firstDraftDate" class="field-label">首稿时间 <span class="required">*</span></label>
+              <input type="date" id="firstDraftDate" formControlName="firstDraftDate" class="field-input">
+            </div>
+          </div>
+          
+          <!-- 第二行:装修风格、项目小组(选填) -->
+          <div class="form-row">
+            <div class="form-field">
+              <label for="style" class="field-label">装修风格</label>
               <select id="style" formControlName="style" class="field-select">
-                <option value="">请选择装修风格</option>
+                <option value="">请选择装修风格(选填)</option>
                 @for (style of styleOptions; track style) {
                   <option [value]="style">{{ style }}</option>
                 }
               </select>
             </div>
             <div class="form-field">
-              <label for="projectGroup" class="field-label">项目小组 <span class="required">*</span></label>
+              <label for="projectGroup" class="field-label">项目小组</label>
               <select id="projectGroup" formControlName="projectGroup" class="field-select">
-                <option value="">请选择项目小组</option>
+                <option value="">请选择项目小组(选填)</option>
                 @for (group of projectGroupOptions; track group) {
                   <option [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>
         </form>
       </div>

+ 69 - 2
src/app/pages/customer-service/consultation-order/consultation-order.scss

@@ -623,9 +623,10 @@ $card-padding: 16px;
 
 // iOS风格页面头部样式
 .page-header {
-  text-align: center;
+  display: flex;
+  align-items: center;
   margin-bottom: 32px;
-  padding: 32px 0;
+  padding: 32px;
   background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
   border-radius: 16px;
   box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
@@ -641,6 +642,54 @@ $card-padding: 16px;
     height: 2px;
     background: linear-gradient(90deg, #007AFF 0%, #34C759 100%);
   }
+
+  // 返回按钮样式
+  .back-button {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    padding: 12px 16px;
+    background: rgba(0, 122, 255, 0.1);
+    border: 1px solid rgba(0, 122, 255, 0.2);
+    border-radius: 12px;
+    color: #007AFF;
+    font-size: 14px;
+    font-weight: 600;
+    cursor: pointer;
+    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+    margin-right: 24px;
+    min-width: 80px;
+    
+    &:hover {
+      background: rgba(0, 122, 255, 0.15);
+      border-color: rgba(0, 122, 255, 0.3);
+      transform: translateY(-1px);
+      box-shadow: 0 4px 12px rgba(0, 122, 255, 0.2);
+    }
+    
+    &:active {
+      transform: translateY(0);
+      box-shadow: 0 2px 6px rgba(0, 122, 255, 0.15);
+    }
+    
+    svg {
+      transition: transform 0.3s ease;
+    }
+    
+    &:hover svg {
+      transform: translateX(-2px);
+    }
+    
+    span {
+      font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC', sans-serif;
+    }
+  }
+
+  // 头部内容区域
+  .header-content {
+    flex: 1;
+    text-align: center;
+  }
   
   h1 {
     font-size: 36px;
@@ -1212,6 +1261,24 @@ $card-padding: 16px;
   }
 }
 
+// 表单行布局 - 支持多行表单
+.form-row {
+  display: grid;
+  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+  gap: 20px;
+  margin-bottom: 20px;
+  
+  &:last-child {
+    margin-bottom: 0;
+  }
+  
+  @media (max-width: 768px) {
+    grid-template-columns: 1fr;
+    gap: 16px;
+    margin-bottom: 16px;
+  }
+}
+
 // iOS风格表单字段样式
 .form-field {
   display: flex;

+ 62 - 99
src/app/pages/customer-service/consultation-order/consultation-order.ts

@@ -1,7 +1,7 @@
-import { Component, signal, Inject } from '@angular/core';
+import { Component, signal, Inject, Output, EventEmitter } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
-import { RouterModule } from '@angular/router';
+import { Router, RouterModule } from '@angular/router';
 import { ProjectService } from '../../../services/project.service';
 import { MatChipInputEvent } from '@angular/material/chips';
 import { COMMA, ENTER } from '@angular/cdk/keycodes';
@@ -98,15 +98,14 @@ export class ConsultationOrder {
   isSubmitting = signal(false);
   // 成功提示显示状态
   showSuccessMessage = signal(false);
-  // 订单创建方式
-  orderCreationMethod = signal<'miniprogram' | 'manual'>('miniprogram');
-  // 同步状态
-  isSyncing = signal(false);
   // 下单时间(自动生成)
   orderTime = signal<string>('');
   // 项目需求卡片展开状态
   isRequirementCardExpanded = signal(false);
 
+  // 订单创建成功事件
+  @Output() orderCreated = new EventEmitter<any>();
+
   // 需求表单
   requirementForm: FormGroup;
   // 客户表单
@@ -157,24 +156,24 @@ export class ConsultationOrder {
     private fb: FormBuilder,
     private projectService: ProjectService,
     private snackBar: MatSnackBar,
-    private dialog: MatDialog
+    private dialog: MatDialog,
+    private router: Router
   ) {
     // 初始化需求表单(保留兼容性)
     this.requirementForm = this.fb.group({
-      style: ['', Validators.required],
+      decorationType: ['', Validators.required], // 装修类型(必填)
+      downPayment: ['', [Validators.required, Validators.min(0)]], // 首付款(必填)
+      firstDraftDate: ['', Validators.required], // 首稿时间(必填)
+      style: [''], // 装修风格(选填)
+      projectGroup: [''], // 项目小组(选填)
       budget: ['', Validators.required],
       area: ['', [Validators.required, Validators.min(1)]],
       houseType: [''], // 改为非必填
       floor: ['', Validators.min(1)],
-      decorationType: [''], // 改为非必填
       preferredDesigner: [''],
       specialRequirements: [''],
       referenceCases: [[]],
-      // 新增字段
-      projectGroup: ['', Validators.required], // 项目小组
-      downPayment: ['', [Validators.required, Validators.min(0)]], // 首付款
-      priceDetails: [''], // 价格明细
-      firstDraftDate: ['', Validators.required] // 首稿时间
+      priceDetails: [''] // 价格明细
     });
 
     // 初始化客户表单
@@ -403,9 +402,25 @@ export class ConsultationOrder {
         this.isSubmitting.set(false);
         this.showSuccessMessage.set(true);
         
-        // 3秒后隐藏成功提示
+        // 3秒后隐藏成功提示并跳转
         setTimeout(() => {
           this.showSuccessMessage.set(false);
+          
+          // 发出订单创建成功事件,用于关闭弹窗
+          const orderData = {
+            orderId: 'mock-9',
+            customerName: formData.customerInfo.name,
+            projectId: 'mock-9'
+          };
+          this.orderCreated.emit(orderData);
+          
+          // 跳转到项目详情页面
+          this.router.navigate(['/customer-service/project-detail/mock-9'], {
+            queryParams: {
+              role: 'customer_service',
+              activeTab: 'overview'
+            }
+          });
         }, 3000);
       }, 1500);
     }
@@ -465,7 +480,27 @@ export class ConsultationOrder {
         if (res?.success) {
           this.showSuccessMessage.set(true);
           this.snackBar.open('项目创建成功', '关闭', { duration: 2000 });
-          setTimeout(() => this.showSuccessMessage.set(false), 2500);
+          
+          // 延迟跳转到项目详情页面
+          setTimeout(() => {
+            this.showSuccessMessage.set(false);
+            
+            // 发出订单创建成功事件,用于关闭弹窗
+            const orderData = {
+              orderId: 'mock-9',
+              customerName: nameCtrl.value,
+              projectId: 'mock-9'
+            };
+            this.orderCreated.emit(orderData);
+            
+            // 跳转到项目详情页面
+            this.router.navigate(['/customer-service/project-detail/mock-9'], {
+              queryParams: {
+                role: 'customer_service',
+                activeTab: 'overview'
+              }
+            });
+          }, 2500);
         } else {
           this.snackBar.open('创建失败,请稍后重试', '关闭', { duration: 3000 });
         }
@@ -528,86 +563,7 @@ export class ConsultationOrder {
     });
   }
 
-  /**
-   * 切换订单创建方式
-   */
-  switchOrderCreationMethod(method: 'miniprogram' | 'manual') {
-    this.orderCreationMethod.set(method);
-    if (method === 'miniprogram') {
-      // 切换到小程序模式时,清空手动填写的信息
-      this.clearSelectedCustomer();
-    }
-  }
 
-  /**
-   * 同步小程序客户信息
-   */
-  syncMiniprogramCustomerInfo() {
-    this.isSyncing.set(true);
-    
-    // 模拟从小程序数据库同步客户信息
-    setTimeout(() => {
-      // 这里应该调用实际的API来获取小程序客户信息
-      const mockCustomerData = {
-        id: 'mp_' + Date.now(),
-        name: '张三',
-        phone: '13800138000',
-        wechat: 'zhangsan_wx',
-        customerType: '新客户',
-        source: '小程序注册',
-        avatar: '',
-        demandType: 'comprehensive',
-        preferenceTags: ['现代简约', '环保材料'],
-        followUpStatus: 'quotation'
-      };
-
-      this.selectedCustomer.set(mockCustomerData);
-      this.customerForm.patchValue({
-        name: mockCustomerData.name,
-        phone: mockCustomerData.phone,
-        wechat: mockCustomerData.wechat,
-        customerType: mockCustomerData.customerType,
-        source: mockCustomerData.source,
-        demandType: mockCustomerData.demandType,
-        followUpStatus: mockCustomerData.followUpStatus
-      });
-
-      this.preferenceTags = [...mockCustomerData.preferenceTags];
-      this.isSyncing.set(false);
-      this.snackBar.open('客户信息同步成功', '确定', { duration: 2000 });
-    }, 1500);
-  }
-
-  /**
-   * 同步项目信息
-   */
-  syncProjectInfo() {
-    this.isSyncing.set(true);
-    
-    // 模拟从数据库同步项目信息
-    setTimeout(() => {
-      // 这里应该调用实际的API来获取项目信息
-      const mockProjectData = {
-        style: '现代简约',
-        budget: '10-20万',
-        area: 120,
-        houseType: '三室两厅',
-        floor: 15,
-        decorationType: '全包',
-        preferredDesigner: '张设计师',
-        specialRequirements: '需要环保材料,注重收纳空间',
-        // 新增字段的模拟数据
-        projectGroup: '设计一组',
-        downPayment: 50000,
-        priceDetails: '设计费:15000元\n施工费:180000元\n主材费:120000元\n软装费:35000元',
-        firstDraftDate: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString().split('T')[0] // 14天后
-      };
-
-      this.requirementForm.patchValue(mockProjectData);
-      this.isSyncing.set(false);
-      this.snackBar.open('项目信息同步成功', '确定', { duration: 2000 });
-    }, 1500);
-  }
 
   /**
    * 快速填写客户信息(通过姓名或手机号)
@@ -617,8 +573,6 @@ export class ConsultationOrder {
       return;
     }
 
-    this.isSyncing.set(true);
-    
     // 模拟根据姓名或手机号查询客户信息
     setTimeout(() => {
       // 这里应该调用实际的API来查询客户信息
@@ -647,7 +601,6 @@ export class ConsultationOrder {
       });
 
       this.preferenceTags = [...mockCustomer.preferenceTags];
-      this.isSyncing.set(false);
       this.snackBar.open('客户信息填写完成', '确定', { duration: 2000 });
     }, 1000);
   }
@@ -729,7 +682,9 @@ export class ConsultationOrder {
     const orderData = {
       customer: this.customerForm.value,
       project: this.projectForm.value,
-      orderTime: this.orderTime()
+      orderTime: this.orderTime(),
+      orderId: 'mock-' + Date.now(), // 模拟订单ID
+      status: 'created'
     };
 
     // 模拟提交
@@ -743,10 +698,18 @@ export class ConsultationOrder {
         verticalPosition: 'top'
       });
 
+      // 发射订单创建成功事件
+      this.orderCreated.emit(orderData);
+
       // 3秒后隐藏成功消息
       setTimeout(() => {
         this.showSuccessMessage.set(false);
       }, 3000);
     }, 2000);
   }
+
+  // 返回项目列表页面
+  goBackToProjectList() {
+    this.router.navigate(['/customer-service/project-list']);
+  }
 }

+ 25 - 0
src/app/pages/customer-service/create-project-modal/create-project-modal.component.html

@@ -0,0 +1,25 @@
+<!-- 创建项目模态框组件 -->
+<div class="create-project-modal">
+  <div class="modal-header">
+    <h2>创建新项目</h2>
+    <button type="button" class="close-btn" (click)="onClose()">
+      <span>&times;</span>
+    </button>
+  </div>
+  
+  <div class="modal-body">
+    <!-- 咨询订单组件 -->
+    <app-consultation-order
+      (orderCreated)="onOrderCreated($event)">
+    </app-consultation-order>
+  </div>
+  
+  <div class="modal-footer">
+    <button type="button" class="btn btn-secondary" (click)="onClose()">
+      取消
+    </button>
+    <button type="button" class="btn btn-primary" (click)="onSave()">
+      保存
+    </button>
+  </div>
+</div>

+ 6 - 0
src/app/pages/customer-service/create-project-modal/create-project-modal.component.scss

@@ -0,0 +1,6 @@
+/* 这个样式文件只是为了解决编译错误而创建 */
+/* 实际样式应该使用 consultation-order-dialog 的样式 */
+
+:host {
+  display: block;
+}

+ 30 - 0
src/app/pages/customer-service/create-project-modal/create-project-modal.component.ts

@@ -0,0 +1,30 @@
+import { Component, Output, EventEmitter } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ConsultationOrder } from '../consultation-order/consultation-order';
+
+@Component({
+  selector: 'app-create-project-modal',
+  standalone: true,
+  imports: [
+    CommonModule,
+    ConsultationOrder
+  ],
+  templateUrl: './create-project-modal.component.html',
+  styleUrls: ['./create-project-modal.component.scss']
+})
+export class CreateProjectModalComponent {
+  @Output() modalClosed = new EventEmitter<void>();
+  @Output() projectCreated = new EventEmitter<any>();
+
+  onClose(): void {
+    this.modalClosed.emit();
+  }
+
+  onSave(): void {
+    // 保存逻辑
+  }
+
+  onOrderCreated(orderData: any): void {
+    this.projectCreated.emit(orderData);
+  }
+}

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

@@ -88,12 +88,7 @@
         </svg>
         <span>工作台</span>
       </a>
-      <a routerLink="/customer-service/consultation-order" class="nav-item" routerLinkActive="active">
-        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-          <path d="M16 3h5v5M8 3H3v5M12 19l-7-7 7-7M16 21h5v-5M8 21H3v-5"></path>
-        </svg>
-        <span>创建订单</span>
-      </a>
+
       <a routerLink="/customer-service/project-list" class="nav-item" routerLinkActive="active">
         <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
           <line x1="8" y1="6" x2="21" y2="6"></line>

+ 80 - 63
src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.html

@@ -1,82 +1,99 @@
-@if (consultations && consultations.length > 0) {
-  <div class="ios-container">
-    <header class="ios-header">
-      <button class="ios-back-btn" (click)="goBack()">
-        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-          <path d="M19 12H5M12 19l-7-7 7-7"/>
-        </svg>
-      </button>
-      <h1>客户咨询记录</h1>
-    </header>
+<div class="ios-container">
+  <!-- iOS风格头部导航 -->
+  <div class="ios-header">
+    <button class="ios-back-btn" (click)="goBack()">
+      <svg viewBox="0 0 24 24" fill="currentColor">
+        <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
+      </svg>
+    </button>
+    <h1>客户咨询</h1>
+  </div>
 
-    <div class="ios-content">
-      <div class="search-bar">
-        <input type="text" placeholder="搜索咨询记录..." [(ngModel)]="searchKeyword" (input)="filterConsultations()">
-        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-          <circle cx="11" cy="11" r="8"/>
-          <line x1="21" y1="21" x2="16.65" y2="16.65"/>
-        </svg>
-      </div>
+  <!-- iOS风格内容区域 -->
+  <div class="ios-content">
+    <!-- iOS风格搜索栏 -->
+    <div class="search-bar">
+      <svg viewBox="0 0 24 24" fill="currentColor">
+        <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
+      </svg>
+      <input 
+        type="text" 
+        placeholder="搜索客户姓名或咨询内容..."
+        [(ngModel)]="searchTerm"
+        (input)="onSearch()"
+      />
+    </div>
 
+    <!-- 咨询列表 -->
+    @if (filteredConsultations.length > 0) {
       <div class="consultation-list">
-        @for (item of filteredConsultations; track item.id) {
-          <div class="consultation-card" [class.urgent]="item.priority === 'high'">
+        @for (consultation of filteredConsultations; track consultation.id) {
+          <div 
+            class="consultation-card"
+            [class.urgent]="consultation.priority === 'urgent'"
+            (click)="viewConsultation(consultation)"
+          >
+            <!-- 卡片头部 -->
             <div class="card-header">
               <div class="customer-info">
-                <div class="avatar" [style.background-color]="getAvatarColor(item.customer)">
-                  {{item.customer.charAt(0)}}
+                <div class="avatar">
+                  {{ consultation.customerName.charAt(0) }}
                 </div>
                 <div>
-                  <h3>{{item.customer}}</h3>
-                  <p class="time">{{item.time}}</p>
+                  <h3>{{ consultation.customerName }}</h3>
+                  <p class="time">{{ consultation.createdAt | date:'MM-dd HH:mm' }}</p>
                 </div>
               </div>
-              <span class="status-badge" [class.urgent]="item.priority === 'high'">
-                {{item.priority === 'high' ? '紧急' : '普通'}}
-              </span>
+              <div 
+                class="status-badge"
+                [class.urgent]="consultation.priority === 'urgent'"
+              >
+                @if (consultation.priority === 'urgent') {
+                  紧急
+                } @else {
+                  普通
+                }
+              </div>
             </div>
-            <p class="content">{{item.content}}</p>
+
+            <!-- 咨询内容 -->
+            <p class="content">{{ consultation.content }}</p>
+
+            <!-- 卡片底部操作按钮 -->
             <div class="card-footer">
-              <button class="ios-btn primary" (click)="viewDetails(item)">查看详情</button>
-              <button class="ios-btn secondary" (click)="assignHandler(item)">分配处理</button>
+              <button 
+                class="ios-btn primary"
+                (click)="handleConsultation(consultation, $event)"
+              >
+                处理咨询
+              </button>
+              <button 
+                class="ios-btn secondary"
+                (click)="viewDetails(consultation, $event)"
+              >
+                查看详情
+              </button>
             </div>
           </div>
         }
       </div>
-
-      @if (filteredConsultations.length === 0 && searchKeyword) {
-        <div class="empty-state">
-          <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
-            <circle cx="11" cy="11" r="8"></circle>
-            <path d="m21 21-4.35-4.35"></path>
+    } @else {
+      <!-- 空状态 -->
+      <div class="empty-state">
+        @if (searchTerm) {
+          <svg width="64" height="64" viewBox="0 0 24 24" fill="currentColor">
+            <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
           </svg>
           <h3>未找到匹配记录</h3>
-          <p>尝试其他关键词搜索</p>
-        </div>
-      }
-    </div>
-  </div>
-}
-@else {
-  <div class="ios-container">
-    <header class="ios-header">
-      <button class="ios-back-btn" (click)="goBack()">
-        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
-          <path d="M19 12H5M12 19l-7-7 7-7"/>
-        </svg>
-      </button>
-      <h1>客户咨询记录</h1>
-    </header>
-
-    <div class="ios-content">
-      <div class="empty-state">
-        <svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
-          <circle cx="11" cy="11" r="8"></circle>
-          <path d="m21 21-4.35-4.35"></path>
-        </svg>
-        <h3>暂无咨询记录</h3>
-        <p>还没有客户咨询记录</p>
+          <p>请尝试其他搜索关键词</p>
+        } @else {
+          <svg width="64" height="64" viewBox="0 0 24 24" fill="currentColor">
+            <path d="M20 6h-2.18c.11-.31.18-.65.18-1a2.996 2.996 0 0 0-5.5-1.65l-.5.67-.5-.68C10.96 2.54 10.05 2 9 2 7.34 2 6 3.34 6 5c0 .35.07.69.18 1H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-5-2c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zM9 4c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1z"/>
+          </svg>
+          <h3>暂无咨询记录</h3>
+          <p>当前没有客户咨询记录</p>
+        }
       </div>
-    </div>
+    }
   </div>
-}
+</div>

+ 204 - 751
src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.scss

@@ -1,13 +1,6 @@
 @import "../../../customer-service-styles.scss";
 
-// 全部客户咨询页面 - iOS风格
-.consultation-container {
-  min-height: 100vh;
-  background: linear-gradient(135deg, #f2f2f7 0%, #e5e5ea 100%);
-  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
-}
-
-// iOS容器样式
+// iOS风格咨询列表页面
 .ios-container {
   min-height: 100vh;
   background: linear-gradient(135deg, #f2f2f7 0%, #e5e5ea 100%);
@@ -16,178 +9,61 @@
 
 // iOS头部导航
 .ios-header {
-  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+  background: rgba(255, 255, 255, 0.95);
+  backdrop-filter: blur(20px);
+  -webkit-backdrop-filter: blur(20px);
   border-bottom: 1px solid rgba(0, 0, 0, 0.05);
   padding: 16px 20px;
   display: flex;
   align-items: center;
-  gap: 12px;
+  gap: 16px;
   position: sticky;
   top: 0;
   z-index: 100;
-  box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08);
-  backdrop-filter: blur(20px);
-  -webkit-backdrop-filter: blur(20px);
+  box-shadow: 0 1px 20px rgba(0, 0, 0, 0.08);
 
   .ios-back-btn {
-    background-color: #F2F3F5;
-    color: #1D2129;
-    border: 1px solid #E5E6EB;
-    border-radius: 8px;
-    padding: 8px 16px;
-    font-size: 14px;
-    font-weight: 500;
+    background: rgba(120, 120, 128, 0.12);
+    border: none;
+    border-radius: 10px;
+    padding: 8px;
+    color: #007AFF;
     cursor: pointer;
-    transition: all 0.2s ease-in-out;
-    display: inline-flex;
+    transition: all 0.2s ease;
+    display: flex;
     align-items: center;
     justify-content: center;
-    min-height: 40px;
-    white-space: nowrap;
+    width: 40px;
+    height: 40px;
     
     &:hover {
-      background-color: #F7F8FA;
-      transform: translateY(-1px);
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-      border-color: rgba(22, 93, 255, 0.3);
+      background: rgba(120, 120, 128, 0.16);
+      transform: scale(1.05);
     }
     
     &:active {
-      transform: translateY(0);
-      background-color: #F2F3F5;
-      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+      transform: scale(0.95);
+      background: rgba(120, 120, 128, 0.2);
     }
-    
-    &:focus {
-      outline: 2px solid rgba(22, 93, 255, 0.3);
-      outline-offset: 2px;
+
+    svg {
+      width: 20px;
+      height: 20px;
     }
   }
 
   h1 {
-    font-size: 24px;
-    font-weight: 700;
+    font-size: 22px;
+    font-weight: 600;
     color: #1d1d1f;
     margin: 0;
-    line-height: 1.2;
     letter-spacing: -0.3px;
   }
 }
 
-// 页面头部 - iOS风格
-.page-header {
-  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
-  padding: 20px 24px;
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  position: sticky;
-  top: 0;
-  z-index: 100;
-  box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08);
-  backdrop-filter: blur(20px);
-  -webkit-backdrop-filter: blur(20px);
-
-  .header-left {
-    display: flex;
-    align-items: center;
-    gap: 16px;
-  }
-
-  .back-btn {
-    background-color: #F2F3F5;
-    color: #1D2129;
-    border: 1px solid #E5E6EB;
-    border-radius: 8px;
-    padding: 8px 16px;
-    font-size: 14px;
-    font-weight: 500;
-    cursor: pointer;
-    transition: all 0.2s ease-in-out;
-    display: inline-flex;
-    align-items: center;
-    justify-content: center;
-    min-height: 40px;
-    white-space: nowrap;
-    
-    &:hover {
-      background-color: #F7F8FA;
-      transform: translateY(-1px);
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-      border-color: rgba(22, 93, 255, 0.3);
-    }
-    
-    &:active {
-      transform: translateY(0);
-      background-color: #F2F3F5;
-      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-    }
-    
-    &:focus {
-      outline: 2px solid rgba(22, 93, 255, 0.3);
-      outline-offset: 2px;
-    }
-  }
-
-  .header-title {
-    h1 {
-      font-size: 28px;
-      font-weight: 700;
-      color: #1d1d1f;
-      margin: 0;
-      line-height: 1.2;
-      letter-spacing: -0.5px;
-    }
-
-    .subtitle {
-      font-size: 15px;
-      color: #8e8e93;
-      margin: 6px 0 0;
-      line-height: 1.4;
-      font-weight: 500;
-    }
-  }
-
-  .header-actions {
-    .refresh-btn {
-      display: flex;
-      align-items: center;
-      gap: 8px;
-      padding: 12px 18px;
-      border: 1px solid rgba(0, 0, 0, 0.08);
-      background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-      border-radius: 12px;
-      color: #007AFF;
-      font-size: 14px;
-      font-weight: 600;
-      cursor: pointer;
-      transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-
-      &:hover:not(:disabled) {
-        background: linear-gradient(135deg, #007AFF 0%, #0062CC 100%);
-        border-color: rgba(0, 0, 0, 0.1);
-        color: #ffffff;
-        transform: translateY(-1px);
-        box-shadow: 0 4px 16px rgba(0, 122, 255, 0.3), inset 0 1px 2px rgba(255, 255, 255, 0.2);
-      }
-
-      &:disabled {
-        opacity: 0.6;
-        cursor: not-allowed;
-      }
-
-      svg.spinning {
-        animation: spin 1s linear infinite;
-      }
-    }
-  }
-}
-
 // iOS内容区域
 .ios-content {
-  padding: 20px;
+  padding: 16px 20px 32px;
   max-width: 800px;
   margin: 0 auto;
 }
@@ -195,723 +71,300 @@
 // iOS搜索栏
 .search-bar {
   position: relative;
-  margin-bottom: 24px;
+  margin-bottom: 20px;
 
   input {
     width: 100%;
-    padding: 16px 48px 16px 16px;
-    border: 1px solid rgba(0, 0, 0, 0.1);
-    border-radius: 16px;
+    padding: 12px 16px 12px 44px;
+    border: none;
+    border-radius: 12px;
     font-size: 16px;
-    background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+    background: rgba(120, 120, 128, 0.12);
+    transition: all 0.3s ease;
     outline: none;
-    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(255, 255, 255, 0.8);
+    color: #1d1d1f;
+    box-sizing: border-box;
 
     &::placeholder {
-      color: #8e8e93;
+      color: rgba(60, 60, 67, 0.6);
     }
 
     &:focus {
-      border-color: #007AFF;
-      background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-      box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.15), inset 0 2px 4px rgba(0, 0, 0, 0.05);
+      background: rgba(255, 255, 255, 0.9);
+      box-shadow: 0 0 0 1px rgba(0, 122, 255, 0.4);
     }
   }
 
   svg {
     position: absolute;
-    right: 16px;
+    left: 14px;
     top: 50%;
     transform: translateY(-50%);
-    color: #8e8e93;
+    color: rgba(60, 60, 67, 0.6);
     pointer-events: none;
+    width: 16px;
+    height: 16px;
   }
 }
 
-  .search-container {
-    margin-bottom: 20px;
-
-    .search-input-wrapper {
-      position: relative;
-      max-width: 500px;
-
-      .search-icon {
-        position: absolute;
-        left: 16px;
-        top: 50%;
-        transform: translateY(-50%);
-        color: #94a3b8;
-        z-index: 2;
-      }
-
-      .search-input {
-        width: 100%;
-        padding: 16px 16px 16px 48px;
-        border: 1px solid rgba(0, 0, 0, 0.1);
-        border-radius: 16px;
-        font-size: 16px;
-        background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
-        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
-        outline: none;
-        box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(255, 255, 255, 0.8);
-
-        &::placeholder {
-          color: #8e8e93;
-        }
-
-        &:focus {
-          border-color: #007AFF;
-          background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-          box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.15), inset 0 2px 4px rgba(0, 0, 0, 0.05);
-        }
-      }
-
-      .clear-search {
-        position: absolute;
-        right: 12px;
-        top: 50%;
-        transform: translateY(-50%);
-        width: 24px;
-        height: 24px;
-        border: none;
-        background: #e2e8f0;
-        border-radius: 50%;
-        color: #64748b;
-        cursor: pointer;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        transition: all 0.2s ease;
-
-        &:hover {
-          background: #cbd5e1;
-          color: #475569;
-        }
-      }
-    }
-  }
-
-  .filter-chips {
-      display: flex;
-      gap: 12px;
-      flex-wrap: wrap;
-
-      .filter-chip {
-        display: flex;
-        align-items: center;
-        gap: 8px;
-        padding: 12px 18px;
-        border: 1px solid rgba(0, 0, 0, 0.08);
-        background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-        border-radius: 20px;
-        color: #6c757d;
-        font-size: 14px;
-        font-weight: 500;
-        cursor: pointer;
-        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
-        position: relative;
-        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-
-        &:hover {
-          border-color: rgba(0, 122, 255, 0.3);
-          background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
-          transform: translateY(-1px);
-          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-        }
-
-        &.active {
-          border-color: #007AFF;
-          background: linear-gradient(135deg, #007AFF 0%, #0062CC 100%);
-          color: #ffffff;
-          box-shadow: 0 4px 16px rgba(0, 122, 255, 0.3), inset 0 1px 2px rgba(255, 255, 255, 0.2);
-
-          .chip-count {
-            background: rgba(255, 255, 255, 0.2);
-          color: #ffffff;
-        }
-      }
-
-      .chip-count {
-        background: #e2e8f0;
-        color: #64748b;
-        padding: 2px 8px;
-        border-radius: 10px;
-        font-size: 12px;
-        font-weight: 600;
-        min-width: 20px;
-        text-align: center;
-      }
-    }
-  }
-.filter-chips {
+// 咨询列表容器
+.consultation-list {
   display: flex;
+  flex-direction: column;
   gap: 12px;
-  flex-wrap: wrap;
-
-  .filter-chip {
-    display: flex;
-    align-items: center;
-    gap: 8px;
-    padding: 12px 18px;
-    border: 1px solid rgba(0, 0, 0, 0.08);
-    background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-    border-radius: 20px;
-    color: #6c757d;
-    font-size: 14px;
-    font-weight: 500;
-    cursor: pointer;
-    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
-    position: relative;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-
-    &:hover {
-      border-color: rgba(0, 122, 255, 0.3);
-      background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
-      transform: translateY(-1px);
-      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-    }
-
-    &.active {
-      border-color: #007AFF;
-      background: linear-gradient(135deg, #007AFF 0%, #0062CC 100%);
-      color: #ffffff;
-      box-shadow: 0 4px 16px rgba(0, 122, 255, 0.3), inset 0 1px 2px rgba(255, 255, 255, 0.2);
-
-      .chip-count {
-        background: rgba(255, 255, 255, 0.2);
-        color: #ffffff;
-      }
-    }
-
-    .chip-count {
-      background: #e2e8f0;
-      color: #64748b;
-      padding: 2px 8px;
-      border-radius: 10px;
-      font-size: 12px;
-      font-weight: 600;
-      min-width: 20px;
-      text-align: center;
-    }
-  }
 }
 
-/* 咨询内容区域 */
-.consultation-content {
-  padding: 24px;
-  min-height: 400px;
-
-  .loading-state {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    padding: 80px 20px;
-    color: #8e8e93;
-
-    .loading-spinner {
-      width: 40px;
-      height: 40px;
-      border: 3px solid #e2e8f0;
-      border-top: 3px solid #3b82f6;
-      border-radius: 50%;
-      animation: spin 1s linear infinite;
-      margin-bottom: 16px;
-    }
-
-    p {
-      font-size: 18px;
-      margin: 0;
-      font-weight: 500;
-    }
-  }
-
-  .empty-state {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    padding: 80px 20px;
-    text-align: center;
-    color: #8e8e93;
-
-    svg {
-      margin-bottom: 24px;
-      opacity: 0.6;
-      width: 80px;
-      height: 80px;
-    }
-
-    h3 {
-      font-size: 20px;
-      font-weight: 700;
-      color: #1d1d1f;
-      margin: 0 0 12px;
-      letter-spacing: -0.3px;
-    }
-
-    p {
-      font-size: 16px;
-      color: #8e8e93;
-      margin: 0;
-      font-weight: 500;
-    }
-  }
-
-  .consultation-list {
-    display: flex;
-    flex-direction: column;
-    gap: 16px;
-    margin-bottom: 24px;
-  }
-
-  // iOS咨询卡片
-  .consultation-card {
-    background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-    border: 1px solid rgba(0, 0, 0, 0.05);
-    border-radius: 20px;
-    padding: 24px;
-    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
-    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-    backdrop-filter: blur(20px);
-    -webkit-backdrop-filter: blur(20px);
-
-    &:hover {
-      transform: translateY(-2px);
-      box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-    }
-
-    &.urgent {
-      border: 2px solid #FF3B30;
-      background: linear-gradient(135deg, #ffffff 0%, #fff5f5 100%);
-    }
-
-    .card-header {
-      display: flex;
-      align-items: center;
-      justify-content: space-between;
-      margin-bottom: 16px;
-
-      .customer-info {
-        display: flex;
-        align-items: center;
-        gap: 12px;
-
-        .avatar {
-          width: 48px;
-          height: 48px;
-          border-radius: 16px;
-          display: flex;
-          align-items: center;
-          justify-content: center;
-          font-weight: 700;
-          font-size: 18px;
-          color: white;
-          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-        }
-
-        h3 {
-          font-size: 18px;
-          font-weight: 600;
-          color: #1d1d1f;
-          margin: 0 0 4px;
-        }
-
-        .time {
-          font-size: 14px;
-          color: #8e8e93;
-          margin: 0;
-          font-weight: 500;
-        }
-      }
-
-      .status-badge {
-        padding: 8px 12px;
-        border-radius: 12px;
-        font-size: 12px;
-        font-weight: 600;
-        background: linear-gradient(135deg, #e5f4ff 0%, #cce7ff 100%);
-        color: #007AFF;
-        border: 1px solid rgba(0, 122, 255, 0.2);
-
-        &.urgent {
-          background: linear-gradient(135deg, #ffe5e5 0%, #ffcccc 100%);
-          color: #FF3B30;
-          border: 1px solid rgba(255, 59, 48, 0.2);
-        }
-      }
-    }
-
-    .content {
-      font-size: 16px;
-      color: #3c3c43;
-      line-height: 1.6;
-      margin: 0 0 20px;
-      font-weight: 500;
-    }
-
-    .card-footer {
-      display: flex;
-      gap: 12px;
-
-      .ios-btn {
-        flex: 1;
-        padding: 12px 20px;
-        border: none;
-        border-radius: 12px;
-        font-size: 14px;
-        font-weight: 600;
-        cursor: pointer;
-        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        gap: 8px;
-
-        &.primary {
-          background: linear-gradient(135deg, #007AFF 0%, #0062CC 100%);
-          color: white;
-          box-shadow: 0 2px 8px rgba(0, 122, 255, 0.3);
-
-          &:hover {
-            transform: translateY(-1px);
-            box-shadow: 0 4px 16px rgba(0, 122, 255, 0.4);
-          }
-        }
-
-        &.secondary {
-          background: linear-gradient(135deg, #f2f2f7 0%, #e5e5ea 100%);
-          color: #8e8e93;
-          border: 1px solid rgba(0, 0, 0, 0.1);
-
-          &:hover {
-            background: linear-gradient(135deg, #e5e5ea 0%, #d1d1d6 100%);
-            transform: translateY(-1px);
-          }
-        }
-      }
-    }
-  }
-}
-
-// 咨询条目
-.consultation-item {
-  background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+// iOS风格横条卡片
+.consultation-card {
+  background: rgba(255, 255, 255, 0.9);
+  backdrop-filter: blur(20px);
+  -webkit-backdrop-filter: blur(20px);
+  border-radius: 16px;
+  padding: 16px;
   border: 1px solid rgba(0, 0, 0, 0.05);
-  border-radius: 20px;
-  padding: 24px;
   transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
   cursor: pointer;
-  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-  backdrop-filter: blur(10px);
-  -webkit-backdrop-filter: blur(10px);
   position: relative;
   overflow: hidden;
 
   &:hover {
-    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.8);
-    transform: translateY(-4px);
+    transform: translateY(-2px);
+    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+    border-color: rgba(0, 122, 255, 0.2);
   }
 
-  &.urgent {
-    border-left: 4px solid #FF3B30;
-    background: linear-gradient(135deg, #ffebee 0%, #ffffff 100%);
+  &:active {
+    transform: translateY(0);
+    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
   }
 
-  &.sensitive {
-    border-left: 4px solid #FF9500;
-    background: linear-gradient(135deg, #fff3e0 0%, #ffffff 100%);
-  }
+  // 紧急状态样式
+  &.urgent {
+    border-left: 4px solid #FF3B30;
+    background: linear-gradient(135deg, rgba(255, 59, 48, 0.05) 0%, rgba(255, 255, 255, 0.9) 100%);
 
-  &.overdue {
-    border-left: 4px solid #FF2D55;
-    background: linear-gradient(135deg, #ffebee 0%, #ffffff 100%);
+    .status-badge.urgent {
+      background: linear-gradient(135deg, #FF3B30 0%, #FF6B6B 100%);
+      color: white;
+    }
   }
 
-  .item-header {
+  // 卡片头部
+  .card-header {
     display: flex;
-    align-items: flex-start;
+    align-items: center;
     justify-content: space-between;
-    margin-bottom: 16px;
+    margin-bottom: 12px;
 
-    .customer-section {
+    .customer-info {
       display: flex;
       align-items: center;
       gap: 12px;
       flex: 1;
 
-      .customer-avatar {
-        width: 52px;
-        height: 52px;
-        border-radius: 16px;
+      .avatar {
+        width: 44px;
+        height: 44px;
+        border-radius: 22px;
         display: flex;
         align-items: center;
         justify-content: center;
-        color: #ffffff;
-        font-size: 20px;
-        font-weight: 700;
-        flex-shrink: 0;
+        font-weight: 600;
+        font-size: 16px;
+        color: white;
         background: linear-gradient(135deg, #007AFF 0%, #5856D6 100%);
-        box-shadow: 0 4px 12px rgba(0, 122, 255, 0.3);
+        box-shadow: 0 2px 8px rgba(0, 122, 255, 0.3);
       }
 
-      .customer-details {
+      div {
         flex: 1;
+        min-width: 0;
 
-        .customer-name {
-          font-size: 20px;
-          font-weight: 700;
+        h3 {
+          font-size: 17px;
+          font-weight: 600;
           color: #1d1d1f;
-          margin: 0 0 6px;
+          margin: 0 0 2px 0;
           line-height: 1.3;
-          letter-spacing: -0.3px;
         }
 
-        .customer-meta {
-          display: flex;
-          align-items: center;
-          gap: 8px;
-          font-size: 14px;
-          color: #8e8e93;
+        .time {
+          font-size: 13px;
+          color: rgba(60, 60, 67, 0.6);
+          margin: 0;
           font-weight: 500;
-
-          .separator {
-            color: #c7c7cc;
-          }
-
-          .reply-status {
-            &.overdue {
-              color: #FF3B30;
-              font-weight: 600;
-            }
-          }
         }
       }
     }
 
-    .priority-badges {
-      display: flex;
-      gap: 8px;
-      flex-shrink: 0;
-
-      .priority-badge {
-        display: flex;
-        align-items: center;
-        gap: 4px;
-        padding: 8px 12px;
-        border-radius: 14px;
-        font-size: 12px;
-        font-weight: 600;
-        text-transform: uppercase;
-        letter-spacing: 0.5px;
-        backdrop-filter: blur(10px);
-        -webkit-backdrop-filter: blur(10px);
-
-        &.urgent {
-          background: rgba(255, 59, 48, 0.1);
-          color: #FF3B30;
-          border: 1px solid rgba(255, 59, 48, 0.2);
-        }
-
-        &.sensitive {
-          background: rgba(255, 149, 0, 0.1);
-          color: #FF9500;
-          border: 1px solid rgba(255, 149, 0, 0.2);
-        }
+    .status-badge {
+      padding: 6px 12px;
+      border-radius: 20px;
+      font-size: 12px;
+      font-weight: 600;
+      background: rgba(120, 120, 128, 0.12);
+      color: rgba(60, 60, 67, 0.8);
+      white-space: nowrap;
+
+      &.urgent {
+        background: linear-gradient(135deg, #FF3B30 0%, #FF6B6B 100%);
+        color: white;
+        box-shadow: 0 2px 8px rgba(255, 59, 48, 0.3);
       }
     }
   }
 
-  .consultation-content-text {
-    margin-bottom: 24px;
-
-    p {
-      font-size: 16px;
-      line-height: 1.7;
-      color: #3c3c43;
-      margin: 0;
-      font-weight: 500;
-
-      :global(mark) {
-        background: rgba(255, 149, 0, 0.15);
-        color: #FF9500;
-        padding: 2px 6px;
-        border-radius: 6px;
-        font-weight: 600;
-      }
-    }
+  // 咨询内容
+  .content {
+    font-size: 15px;
+    color: rgba(60, 60, 67, 0.8);
+    line-height: 1.4;
+    margin: 0 0 16px 0;
+    display: -webkit-box;
+    -webkit-line-clamp: 2;
+    -webkit-box-orient: vertical;
+    overflow: hidden;
+    font-weight: 400;
   }
 
-  .item-actions {
+  // 卡片底部操作按钮
+  .card-footer {
     display: flex;
-    gap: 12px;
-    flex-wrap: wrap;
+    gap: 8px;
+    align-items: center;
 
-    .action-btn {
-      display: flex;
-      align-items: center;
-      gap: 8px;
-      padding: 12px 18px;
-      border-radius: 12px;
+    .ios-btn {
+      padding: 8px 16px;
+      border-radius: 20px;
       font-size: 14px;
       font-weight: 600;
-      cursor: pointer;
-      transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
       border: none;
-      outline: none;
-      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-
-      &:disabled {
-        opacity: 0.6;
-        cursor: not-allowed;
-      }
+      cursor: pointer;
+      transition: all 0.2s ease;
+      flex: 1;
+      text-align: center;
 
       &.primary {
         background: linear-gradient(135deg, #007AFF 0%, #5856D6 100%);
-        color: #ffffff;
+        color: white;
+        box-shadow: 0 2px 8px rgba(0, 122, 255, 0.3);
+
+        &:hover {
+          transform: translateY(-1px);
+          box-shadow: 0 4px 12px rgba(0, 122, 255, 0.4);
+        }
 
-        &:hover:not(:disabled) {
-          background: linear-gradient(135deg, #0062CC 0%, #4A4AB8 100%);
-          transform: translateY(-2px);
-          box-shadow: 0 6px 20px rgba(0, 122, 255, 0.4);
+        &:active {
+          transform: translateY(0);
+          box-shadow: 0 2px 6px rgba(0, 122, 255, 0.3);
         }
       }
 
       &.secondary {
-        background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
-        color: #6c757d;
-        border: 1px solid rgba(0, 0, 0, 0.08);
+        background: rgba(120, 120, 128, 0.12);
+        color: #007AFF;
 
         &:hover {
-          background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
-          border-color: rgba(0, 0, 0, 0.15);
+          background: rgba(120, 120, 128, 0.16);
           transform: translateY(-1px);
-          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
         }
-      }
-
-      &.tertiary {
-        background: linear-gradient(135deg, #34C759 0%, #30B855 100%);
-        color: #ffffff;
-        border: none;
 
-        &:hover {
-          background: linear-gradient(135deg, #30B855 0%, #2DA54A 100%);
-          transform: translateY(-2px);
-          box-shadow: 0 6px 20px rgba(52, 199, 89, 0.4);
+        &:active {
+          transform: translateY(0);
+          background: rgba(120, 120, 128, 0.2);
         }
       }
     }
   }
 }
 
-// 动画
-@keyframes spin {
-  from {
-    transform: rotate(0deg);
+// 空状态样式
+.empty-state {
+  text-align: center;
+  padding: 60px 20px;
+  color: rgba(60, 60, 67, 0.6);
+
+  svg {
+    margin-bottom: 16px;
+    opacity: 0.5;
   }
-  to {
-    transform: rotate(360deg);
+
+  h3 {
+    font-size: 20px;
+    font-weight: 600;
+    color: rgba(60, 60, 67, 0.8);
+    margin: 0 0 8px 0;
+  }
+
+  p {
+    font-size: 15px;
+    color: rgba(60, 60, 67, 0.6);
+    margin: 0;
+    font-weight: 400;
   }
 }
 
 // 响应式设计
 @media (max-width: 768px) {
-  .page-header {
-    padding: 16px 20px;
-
-    .header-title h1 {
-      font-size: 20px;
-    }
-
-    .header-actions .refresh-btn {
-      padding: 8px 12px;
-      font-size: 13px;
-    }
+  .ios-content {
+    padding: 16px;
   }
 
-  .search-filter-section {
-    padding: 20px;
+  .consultation-card {
+    .card-header {
+      .customer-info {
+        .avatar {
+          width: 40px;
+          height: 40px;
+          border-radius: 20px;
+          font-size: 14px;
+        }
 
-    .search-container .search-input-wrapper .search-input {
-      font-size: 16px; // 防止iOS缩放
+        div h3 {
+          font-size: 16px;
+        }
+      }
     }
 
-    .filter-chips {
+    .card-footer {
+      flex-direction: column;
       gap: 8px;
 
-      .filter-chip {
-        padding: 8px 12px;
-        font-size: 13px;
+      .ios-btn {
+        width: 100%;
       }
     }
   }
+}
 
-  .consultation-content {
-    padding: 20px;
-
-    .consultation-item {
-      padding: 16px;
-
-      .item-header {
-        .customer-section {
-          .customer-avatar {
-            width: 40px;
-            height: 40px;
-            font-size: 16px;
-          }
-
-          .customer-details .customer-name {
-            font-size: 16px;
-          }
-        }
-      }
-
-      .consultation-content-text p {
-        font-size: 15px;
-      }
-
-      .item-actions {
-        gap: 8px;
-
-        .action-btn {
-          padding: 8px 12px;
-          font-size: 13px;
-        }
-      }
-    }
+// 动画效果
+@keyframes slideInUp {
+  from {
+    opacity: 0;
+    transform: translateY(20px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
   }
 }
 
-@media (max-width: 480px) {
-  .page-header {
-    .header-left {
-      gap: 12px;
-    }
+.consultation-card {
+  animation: slideInUp 0.3s ease-out;
+}
 
-    .header-title h1 {
-      font-size: 18px;
-    }
+// 加载动画
+@keyframes pulse {
+  0%, 100% {
+    opacity: 1;
   }
+  50% {
+    opacity: 0.5;
+  }
+}
 
-  .consultation-item {
-    .item-header {
-      flex-direction: column;
-      align-items: flex-start;
-      gap: 12px;
-
-      .priority-badges {
-        align-self: flex-end;
-      }
-    }
-
-    .item-actions {
-      .action-btn {
-        flex: 1;
-        justify-content: center;
-        min-width: 0;
-      }
-    }
+.loading {
+  .consultation-card {
+    animation: pulse 1.5s ease-in-out infinite;
   }
 }

+ 94 - 391
src/app/pages/customer-service/dashboard/pages/consultation-list/consultation-list.component.ts

@@ -1,453 +1,156 @@
 import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { RouterModule, ActivatedRoute } from '@angular/router';
+import { RouterModule, Router } from '@angular/router';
 import { FormsModule } from '@angular/forms';
 
 @Component({
   selector: 'app-consultation-list',
   standalone: true,
   imports: [CommonModule, RouterModule, FormsModule],
-  template: `
-    <div class="consultation-container">
-      <!-- 页面头部 -->
-      <header class="page-header">
-        <div class="header-left">
-          <button class="back-btn" (click)="goBack()">
-            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <path d="M19 12H5M12 19l-7-7 7-7"/>
-            </svg>
-          </button>
-          <div class="header-title">
-            <h1>客户咨询记录</h1>
-            <p class="subtitle">共 {{ filteredConsultations.length }} 条咨询记录</p>
-          </div>
-        </div>
-        <div class="header-actions">
-          <button class="refresh-btn" (click)="refreshData()" [disabled]="isLoading">
-            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" [class.spinning]="isLoading">
-              <polyline points="23 4 23 10 17 10"></polyline>
-              <polyline points="1 20 1 14 7 14"></polyline>
-              <path d="m20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>
-            </svg>
-            刷新
-          </button>
-        </div>
-      </header>
-
-      <!-- 搜索和筛选区域 -->
-      <div class="search-filter-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>
-            <input 
-              type="text" 
-              placeholder="搜索客户姓名、咨询内容..." 
-              [(ngModel)]="searchKeyword" 
-              (input)="applyFilters()"
-              class="search-input"
-            >
-            <button *ngIf="searchKeyword" class="clear-search" (click)="clearSearch()">
-              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                <line x1="18" y1="6" x2="6" y2="18"></line>
-                <line x1="6" y1="6" x2="18" y2="18"></line>
-              </svg>
-            </button>
-          </div>
-        </div>
-        
-        <div class="filter-chips">
-          <button 
-            class="filter-chip" 
-            [class.active]="filterUnrepliedOver1h" 
-            (click)="toggleFilter('unreplied')"
-          >
-            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <circle cx="12" cy="12" r="10"></circle>
-              <polyline points="12 6 12 12 16 14"></polyline>
-            </svg>
-            未回复超1小时
-            <span *ngIf="filterUnrepliedOver1h" class="chip-count">{{ getUnrepliedCount() }}</span>
-          </button>
-          <button 
-            class="filter-chip" 
-            [class.active]="filterSensitive" 
-            (click)="toggleFilter('sensitive')"
-          >
-            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
-            </svg>
-            含敏感词
-            <span *ngIf="filterSensitive" class="chip-count">{{ getSensitiveCount() }}</span>
-          </button>
-          <button 
-            class="filter-chip" 
-            [class.active]="filterHighPriority" 
-            (click)="toggleFilter('priority')"
-          >
-            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-              <path d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"></path>
-            </svg>
-            紧急咨询
-            <span *ngIf="filterHighPriority" class="chip-count">{{ getHighPriorityCount() }}</span>
-          </button>
-        </div>
-      </div>
-
-      <!-- 咨询列表 -->
-      <div class="consultation-content">
-        <div *ngIf="isLoading" class="loading-state">
-          <div class="loading-spinner"></div>
-          <p>加载中...</p>
-        </div>
-
-        <div *ngIf="!isLoading && filteredConsultations.length === 0" class="empty-state">
-          <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
-            <circle cx="11" cy="11" r="8"></circle>
-            <path d="m21 21-4.35-4.35"></path>
-          </svg>
-          <h3>暂无咨询记录</h3>
-          <p>{{ searchKeyword ? '没有找到匹配的咨询记录' : '还没有客户咨询记录' }}</p>
-        </div>
-
-        <div *ngIf="!isLoading && filteredConsultations.length > 0" class="consultation-list">
-          <div 
-            class="consultation-item" 
-            *ngFor="let item of filteredConsultations; trackBy: trackByConsultation"
-            [class.urgent]="item.priority === 'high'"
-            [class.sensitive]="containsSensitiveWords(item.content)"
-            [class.overdue]="isOverdue(item)"
-          >
-            <div class="item-header">
-              <div class="customer-section">
-                <div class="customer-avatar" [style.background-color]="getAvatarColor(item.customer)">
-                  {{ item.customer.charAt(0) }}
-                </div>
-                <div class="customer-details">
-                  <h3 class="customer-name">{{ item.customer }}</h3>
-                  <div class="customer-meta">
-                    <span class="consultation-time">{{ formatTime(item.time) }}</span>
-                    <span class="separator">•</span>
-                    <span class="reply-status" [class.overdue]="isOverdue(item)">
-                      {{ getReplyStatus(item) }}
-                    </span>
-                  </div>
-                </div>
-              </div>
-              <div class="priority-badges">
-                <span *ngIf="item.priority === 'high'" class="priority-badge urgent">
-                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                    <path d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"></path>
-                  </svg>
-                  紧急
-                </span>
-                <span *ngIf="containsSensitiveWords(item.content)" class="priority-badge sensitive">
-                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                    <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path>
-                  </svg>
-                  敏感词
-                </span>
-              </div>
-            </div>
-            
-            <div class="consultation-content-text">
-              <p [innerHTML]="highlightKeyword(item.content)"></p>
-            </div>
-            
-            <div class="item-actions">
-              <button 
-                class="action-btn primary" 
-                (click)="syncToWeChat(item)"
-                [disabled]="item.syncing"
-              >
-                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                  <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
-                </svg>
-                <span *ngIf="!item.syncing">同步到企微</span>
-                <span *ngIf="item.syncing">同步中...</span>
-              </button>
-              <button class="action-btn secondary" (click)="viewDetails(item)">
-                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                  <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
-                  <circle cx="12" cy="12" r="3"></circle>
-                </svg>
-                查看详情
-              </button>
-              <button class="action-btn tertiary" (click)="markAsReplied(item)">
-                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                  <polyline points="20 6 9 17 4 12"></polyline>
-                </svg>
-                标记已回复
-              </button>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  `,
-  styles: [`
-    .toolbar { display:flex; justify-content: space-between; align-items:center; gap:12px; margin-bottom: 12px; }
-    .quick-filters { display:flex; gap: 16px; color:#636366; font-size:14px; }
-    .quick-filters input { margin-right:6px; }
-    .search-bar { position: relative; }
-    .search-bar input { width: 260px; padding: 10px 14px 10px 36px; border-radius: 10px; border: 1px solid #d1d1d6; background: #f7f7fb; }
-    .search-bar svg { position:absolute; left: 10px; top: 50%; transform: translateY(-50%); color:#8e8e93; }
-  `]
+  templateUrl: './consultation-list.component.html',
+  styleUrls: ['./consultation-list.component.scss']
 })
 export class ConsultationListComponent implements OnInit {
+  // 咨询数据
   consultations = [
     {
       id: '1',
-      customer: '张先生', 
-      time: '10:30', 
-      content: '咨询关于厨房改造的预算和工期,希望能在下个月开始施工', 
-      priority: 'normal', 
-      lastReplyMinutes: 30, 
-      weComUserId: 'zhangxiansheng',
-      syncing: false,
-      replied: false
+      customerName: '张先生',
+      content: '咨询关于厨房改造的预算和工期,希望能在下个月开始施工,请尽快联系我',
+      priority: 'normal',
+      createdAt: new Date('2024-01-15T10:30:00'),
+      status: 'pending'
     },
     {
       id: '2',
-      customer: '李女士', 
-      time: '11:45', 
-      content: '询问客厅设计风格建议,发手机给你,希望尽快联系', 
-      priority: 'high', 
-      lastReplyMinutes: 120, 
-      weComUserId: 'linnvshi',
-      syncing: false,
-      replied: false
+      customerName: '李女士',
+      content: '询问客厅设计风格建议,希望能提供一些现代简约风格的方案参考',
+      priority: 'urgent',
+      createdAt: new Date('2024-01-15T11:45:00'),
+      status: 'pending'
     },
     {
       id: '3',
-      customer: '王先生', 
-      time: '14:20', 
-      content: '需要全屋设计方案咨询,发邮箱吧,预算在20万左右', 
-      priority: 'normal', 
-      lastReplyMinutes: 75, 
-      weComUserId: 'wangxiansheng',
-      syncing: false,
-      replied: false
+      customerName: '王先生',
+      content: '需要全屋设计方案咨询,预算在20万左右,希望能安排设计师上门测量',
+      priority: 'normal',
+      createdAt: new Date('2024-01-15T14:20:00'),
+      status: 'pending'
     },
     {
       id: '4',
-      customer: '陈女士', 
-      time: '09:15', 
-      content: '想了解卧室装修的具体流程和注意事项', 
-      priority: 'normal', 
-      lastReplyMinutes: 15, 
-      weComUserId: 'chennvshi',
-      syncing: false,
-      replied: true
+      customerName: '陈女士',
+      content: '想了解卧室装修的具体流程和注意事项,特别是环保材料的选择',
+      priority: 'normal',
+      createdAt: new Date('2024-01-15T09:15:00'),
+      status: 'completed'
     },
     {
       id: '5',
-      customer: '刘先生', 
-      time: '16:30', 
-      content: '紧急!明天要看房,需要设计师现场指导,找不到人联系', 
-      priority: 'high', 
-      lastReplyMinutes: 180, 
-      weComUserId: 'liuxiansheng',
-      syncing: false,
-      replied: false
+      customerName: '刘先生',
+      content: '紧急!明天要看房,需要设计师现场指导,请务必今天联系我',
+      priority: 'urgent',
+      createdAt: new Date('2024-01-15T16:30:00'),
+      status: 'pending'
     }
   ];
 
   filteredConsultations = [...this.consultations];
-  searchKeyword = '';
-  filterUnrepliedOver1h = false;
-  filterSensitive = false;
-  filterHighPriority = false;
-  isLoading = false;
-
-  private sensitivePatterns = /(发手机|发邮箱|找不到人|微信|QQ|电话|联系方式)/;
+  searchTerm = '';
 
-  constructor(private route: ActivatedRoute) {}
+  constructor(private router: Router) {}
 
   ngOnInit(): void {
-    this.route.queryParams.subscribe(params => {
-      const q = params['q'];
-      if (q) {
-        this.searchKeyword = q;
-      }
-      this.applyFilters();
-    });
+    this.onSearch();
   }
 
-  // 搜索过滤功能
-  filterConsultations() {
-    if (!this.searchKeyword.trim()) {
+  // 搜索功能
+  onSearch(): void {
+    if (!this.searchTerm.trim()) {
       this.filteredConsultations = [...this.consultations];
       return;
     }
 
-    const keyword = this.searchKeyword.toLowerCase();
-    this.filteredConsultations = this.consultations.filter(item => 
-      item.customer.toLowerCase().includes(keyword) ||
-      item.content.toLowerCase().includes(keyword)
+    this.filteredConsultations = this.consultations.filter(consultation =>
+      consultation.customerName.toLowerCase().includes(this.searchTerm.toLowerCase()) ||
+      consultation.content.toLowerCase().includes(this.searchTerm.toLowerCase())
     );
   }
 
-  applyFilters(): void {
-    this.filteredConsultations = this.consultations.filter(item => {
-      const matchesKeyword = !this.searchKeyword || 
-        item.customer.toLowerCase().includes(this.searchKeyword.toLowerCase()) || 
-        item.content.toLowerCase().includes(this.searchKeyword.toLowerCase());
-      const matchesUnreplied = !this.filterUnrepliedOver1h || item.lastReplyMinutes > 60;
-      const matchesSensitive = !this.filterSensitive || this.containsSensitiveWords(item.content);
-      const matchesPriority = !this.filterHighPriority || item.priority === 'high';
-      return matchesKeyword && matchesUnreplied && matchesSensitive && matchesPriority;
-    });
+  // 查看咨询详情
+  viewConsultation(consultation: any): void {
+    console.log('查看咨询:', consultation);
+    // 这里可以导航到详情页面
   }
 
-  toggleFilter(type: string): void {
-    switch (type) {
-      case 'unreplied':
-        this.filterUnrepliedOver1h = !this.filterUnrepliedOver1h;
-        break;
-      case 'sensitive':
-        this.filterSensitive = !this.filterSensitive;
-        break;
-      case 'priority':
-        this.filterHighPriority = !this.filterHighPriority;
-        break;
-    }
-    this.applyFilters();
-  }
-
-  clearSearch(): void {
-    this.searchKeyword = '';
-    this.applyFilters();
+  // 处理咨询
+  handleConsultation(consultation: any, event: Event): void {
+    event.stopPropagation();
+    console.log('处理咨询:', consultation);
   }
 
-  refreshData(): void {
-    this.isLoading = true;
-    // 模拟数据刷新
-    setTimeout(() => {
-      this.isLoading = false;
-      this.applyFilters();
-    }, 1000);
+  // 查看详情
+  viewDetails(consultation: any, event: Event): void {
+    event.stopPropagation();
+    console.log('查看详情:', consultation);
   }
 
-  containsSensitiveWords(content: string): boolean {
-    return this.sensitivePatterns.test(content);
+  // 返回上一页
+  goBack(): void {
+    this.router.navigate(['/customer-service']);
   }
 
-  isOverdue(item: any): boolean {
-    return item.lastReplyMinutes > 60 && !item.replied;
+  // 获取优先级标签
+  getPriorityLabel(priority: string): string {
+    switch (priority) {
+      case 'urgent':
+        return '紧急';
+      case 'high':
+        return '高';
+      case 'normal':
+        return '普通';
+      case 'low':
+        return '低';
+      default:
+        return '普通';
+    }
   }
 
-  getReplyStatus(item: any): string {
-    if (item.replied) {
-      return '已回复';
+  // 获取状态标签
+  getStatusLabel(status: string): string {
+    switch (status) {
+      case 'pending':
+        return '待处理';
+      case 'processing':
+        return '处理中';
+      case 'completed':
+        return '已完成';
+      default:
+        return '待处理';
     }
-    if (item.lastReplyMinutes > 60) {
-      return `超时 ${Math.floor(item.lastReplyMinutes / 60)} 小时`;
-    }
-    return `${item.lastReplyMinutes} 分钟前`;
   }
 
-  formatTime(time: string): string {
-    return `今天 ${time}`;
+  // 格式化时间
+  formatTime(date: Date): string {
+    const now = new Date();
+    const diff = now.getTime() - date.getTime();
+    const minutes = Math.floor(diff / (1000 * 60));
+    const hours = Math.floor(diff / (1000 * 60 * 60));
+    const days = Math.floor(diff / (1000 * 60 * 60 * 24));
+
+    if (minutes < 60) {
+      return `${minutes}分钟前`;
+    } else if (hours < 24) {
+      return `${hours}小时前`;
+    } else {
+      return `${days}天前`;
+    }
   }
 
+  // 获取头像颜色
   getAvatarColor(name: string): string {
     const colors = ['#007AFF', '#34C759', '#FF9500', '#FF3B30', '#AF52DE', '#5AC8FA'];
     const index = name.charCodeAt(0) % colors.length;
     return colors[index];
   }
-
-  highlightKeyword(content: string): string {
-    if (!this.searchKeyword) return content;
-    const regex = new RegExp(`(${this.searchKeyword})`, 'gi');
-    return content.replace(regex, '<mark>$1</mark>');
-  }
-
-  trackByConsultation(index: number, item: any): string {
-    return item.id;
-  }
-
-  getUnrepliedCount(): number {
-    return this.consultations.filter(item => item.lastReplyMinutes > 60 && !item.replied).length;
-  }
-
-  getSensitiveCount(): number {
-    return this.consultations.filter(item => this.containsSensitiveWords(item.content)).length;
-  }
-
-  getHighPriorityCount(): number {
-    return this.consultations.filter(item => item.priority === 'high').length;
-  }
-
-  syncToWeChat(item: any): void {
-    item.syncing = true;
-    
-    try {
-      // 尝试打开企业微信应用
-      const wecomUrl = `wxwork://message/?username=${item.weComUserId}`;
-      window.open(wecomUrl, '_blank');
-      
-      // 模拟同步过程
-      setTimeout(() => {
-        item.syncing = false;
-        // 显示成功提示
-        this.showToast('已成功同步到企业微信');
-      }, 2000);
-      
-      // 备选方案:打开企业微信网页版
-      setTimeout(() => {
-        const webUrl = `https://work.weixin.qq.com/wework_admin/frame#index`;
-        window.open(webUrl, '_blank');
-      }, 1000);
-    } catch (error) {
-      console.error('同步到企业微信失败:', error);
-      item.syncing = false;
-      this.showToast('同步失败,请检查企业微信客户端', 'error');
-    }
-  }
-
-  viewDetails(item: any): void {
-    // 这里可以导航到详情页面或打开模态框
-    console.log('查看详情:', item);
-    this.showToast(`正在查看 ${item.customer} 的咨询详情`);
-  }
-
-  markAsReplied(item: any): void {
-    item.replied = true;
-    this.showToast(`已标记 ${item.customer} 的咨询为已回复`);
-    this.applyFilters();
-  }
-
-  private showToast(message: string, type: 'success' | 'error' = 'success'): void {
-    // 简单的提示实现,实际项目中可以使用更完善的提示组件
-    const toast = document.createElement('div');
-    toast.textContent = message;
-    toast.style.cssText = `
-      position: fixed;
-      top: 20px;
-      right: 20px;
-      background: ${type === 'success' ? '#34C759' : '#FF3B30'};
-      color: white;
-      padding: 12px 20px;
-      border-radius: 8px;
-      z-index: 10000;
-      font-size: 14px;
-      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
-    `;
-    document.body.appendChild(toast);
-    
-    setTimeout(() => {
-      document.body.removeChild(toast);
-    }, 3000);
-  }
-
-  openWeCom(item: any): void {
-    this.syncToWeChat(item);
-  }
-
-  goBack() {
-    window.history.back();
-  }
 }

+ 188 - 0
src/app/pages/customer-service/project-detail/project-detail.html

@@ -375,6 +375,194 @@
                 </div>
               </div>
             </div>
+            
+            <!-- 订单创建板块 -->
+            <div class="order-creation-section">
+              <div class="section-header">
+                <h4 class="section-title">
+                  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                    <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
+                    <polyline points="14 2 14 8 20 8"></polyline>
+                    <line x1="16" y1="13" x2="8" y2="13"></line>
+                    <line x1="16" y1="17" x2="8" y2="17"></line>
+                  </svg>
+                  订单创建
+                </h4>
+                <button class="toggle-btn" (click)="toggleOrderCreation()" [class.expanded]="isOrderCreationExpanded()">
+                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                    <polyline points="6 9 12 15 18 9"></polyline>
+                  </svg>
+                </button>
+              </div>
+              
+              <div class="order-creation-content" [class.expanded]="isOrderCreationExpanded()">
+                <div class="order-creation-container">
+                  <div class="scrollable-content">
+                    <!-- 客户信息长条栏 -->
+                    <section class="customer-info-bar">
+                    <div class="customer-bar-container">
+                      <!-- 左侧客户搜索和信息 -->
+                      <div class="customer-search-area">
+                        @if (!selectedOrderCustomer()) {
+                          <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]="orderSearchKeyword()" 
+                              (ngModelChange)="orderSearchKeyword.set($event); searchOrderCustomer()"
+                              placeholder="输入客户姓名或手机号快速匹配老客户..."
+                              class="customer-search-input"
+                              autocomplete="off"
+                              (keyup.enter)="quickFillOrderCustomerInfo(orderSearchKeyword())"
+                            />
+                            <button 
+                              class="search-action-btn"
+                              (click)="quickFillOrderCustomerInfo(orderSearchKeyword())"
+                              [disabled]="!orderSearchKeyword().trim()"
+                            >
+                              <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>
+                          
+                          <!-- 搜索结果下拉 -->
+                          @if (orderSearchResults().length > 0) {
+                            <div class="search-dropdown">
+                              <div class="dropdown-header">
+                                <span>找到 {{ orderSearchResults().length }} 位客户</span>
+                              </div>
+                              @for (customer of orderSearchResults(); track customer.id) {
+                                <div class="customer-option" (click)="selectOrderCustomer(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">
+                                    <span class="tag">{{ customer.customerType }}</span>
+                                  </div>
+                                </div>
+                              }
+                            </div>
+                          }
+                        } @else {
+                          <!-- 已选择客户信息展示 -->
+                          <div class="selected-customer-info">
+                            <div class="customer-avatar-lg">
+                              @if (selectedOrderCustomer()?.avatar) {
+                                <img [src]="selectedOrderCustomer()?.avatar" [alt]="selectedOrderCustomer()?.name">
+                              } @else {
+                                <span>{{ selectedOrderCustomer()?.name?.charAt(0) }}</span>
+                              }
+                            </div>
+                            <div class="customer-main-info">
+                              <div class="customer-name">{{ selectedOrderCustomer()?.name }}</div>
+                              <div class="customer-phone">{{ selectedOrderCustomer()?.phone }}</div>
+                              <div class="customer-type">{{ selectedOrderCustomer()?.customerType }}</div>
+                            </div>
+                            <button class="clear-customer-btn" (click)="clearOrderCustomer()">
+                              <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>
+                  </section>
+
+                  <!-- 项目需求表单 -->
+                  <section class="requirement-section">
+                    <div class="section-header">
+                      <h3>项目需求</h3>
+                    </div>
+                    <form [formGroup]="orderRequirementForm" class="requirement-form">
+                      <div class="form-row">
+                        <div class="form-group">
+                          <label for="projectType">项目类型 <span class="required">*</span></label>
+                          <select id="projectType" formControlName="projectType" class="field-select">
+                            <option value="">请选择项目类型</option>
+                            <option value="residential">住宅设计</option>
+                            <option value="commercial">商业空间</option>
+                            <option value="office">办公空间</option>
+                            <option value="restaurant">餐饮空间</option>
+                          </select>
+                        </div>
+                        <div class="form-group">
+                          <label for="area">面积 <span class="required">*</span></label>
+                          <div class="input-with-unit">
+                            <input type="number" id="area" formControlName="area" class="field-input" placeholder="请输入面积">
+                            <span class="input-unit">㎡</span>
+                          </div>
+                        </div>
+                      </div>
+                      
+                      <div class="form-row">
+                        <div class="form-group">
+                          <label for="style">装修风格</label>
+                          <select id="style" formControlName="style" class="field-select">
+                            <option value="">请选择装修风格</option>
+                            @for (style of decorationStyles; track style.value) {
+                              <option [value]="style.value">{{ style.label }}</option>
+                            }
+                          </select>
+                        </div>
+                        <div class="form-group">
+                          <label for="budget">预算范围</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-50">20-50万</option>
+                            <option value="50+">50万以上</option>
+                          </select>
+                        </div>
+                      </div>
+                      
+                      <div class="form-group full-width">
+                        <label for="requirements">具体需求</label>
+                        <textarea id="requirements" formControlName="requirements" class="field-textarea" placeholder="请详细描述您的设计需求..."></textarea>
+                      </div>
+                    </form>
+                  </section>
+                  </div>
+
+                  <!-- 操作按钮 -->
+                  <div class="order-actions">
+                    <button class="secondary-btn" (click)="resetOrderForm()">
+                      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                        <polyline points="1 4 1 10 7 10"></polyline>
+                        <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path>
+                      </svg>
+                      重置
+                    </button>
+                    <button class="primary-btn" (click)="createOrder()" [disabled]="!isOrderFormValid()">
+                      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                        <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
+                        <polyline points="22 4 12 14.01 9 11.01"></polyline>
+                      </svg>
+                      创建订单
+                    </button>
+                  </div>
+                </div>
+              </div>
+            </div>
           </div>
         }
 

+ 516 - 0
src/app/pages/customer-service/project-detail/project-detail.scss

@@ -37,6 +37,522 @@ $bg-white: $background-primary;
   }
 }
 
+// 订单创建板块样式 - iOS风格固定区域设计
+.order-creation-section {
+  background: $background-secondary;
+  border-radius: $border-radius;
+  margin-top: 20px;
+  box-shadow: $shadow-sm;
+  overflow: hidden;
+  transition: $transition;
+  position: relative;
+
+  .section-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 16px 20px;
+    background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%);
+    border-bottom: 1px solid $border-color;
+    cursor: pointer;
+    transition: $transition;
+    position: sticky;
+    top: 0;
+    z-index: 10;
+
+    &:hover {
+      background: linear-gradient(135deg, #f0f2ff 0%, #e8ebff 100%);
+    }
+
+    .section-title {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      margin: 0;
+      font-size: 16px;
+      font-weight: 600;
+      color: $text-primary;
+
+      svg {
+        color: $primary-color;
+      }
+    }
+
+    .toggle-btn {
+      background: none;
+      border: none;
+      padding: 8px;
+      border-radius: 8px;
+      cursor: pointer;
+      transition: $transition;
+      color: $text-secondary;
+
+      &:hover {
+        background: rgba($primary-color, 0.1);
+        color: $primary-color;
+      }
+
+      &.expanded {
+        transform: rotate(180deg);
+      }
+
+      svg {
+        transition: $transition;
+      }
+    }
+  }
+
+  .order-creation-content {
+    height: 0;
+    overflow: hidden;
+    transition: height 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+
+    &.expanded {
+      height: 600px; // 固定高度
+      transition: height 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
+    }
+  }
+
+  .order-creation-container {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    background: $background-primary;
+  }
+
+  // 可滚动内容区域
+  .scrollable-content {
+    flex: 1;
+    overflow-y: auto;
+    padding: 20px;
+    
+    // iOS风格滚动条
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+    
+    &::-webkit-scrollbar-track {
+      background: transparent;
+    }
+    
+    &::-webkit-scrollbar-thumb {
+      background: rgba($text-tertiary, 0.3);
+      border-radius: 3px;
+      
+      &:hover {
+        background: rgba($text-tertiary, 0.5);
+      }
+    }
+  }
+
+  // 客户信息长条栏样式
+  .customer-info-bar {
+    background: $background-secondary;
+    border-radius: $border-radius;
+    padding: 16px;
+    margin-bottom: 20px;
+    border: 1px solid $border-color;
+    box-shadow: $shadow-sm;
+
+    .customer-bar-container {
+      width: 100%;
+    }
+
+    .customer-search-area {
+      position: relative;
+    }
+
+    .search-input-container {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+      background: $background-secondary;
+      border: 1px solid $border-color;
+      border-radius: 10px;
+      padding: 12px 16px;
+      transition: $transition;
+
+      &:focus-within {
+        border-color: $primary-color;
+        box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
+      }
+
+      .search-icon {
+        color: $text-tertiary;
+        flex-shrink: 0;
+      }
+
+      .customer-search-input {
+        flex: 1;
+        border: none;
+        outline: none;
+        background: none;
+        font-size: 14px;
+        color: $text-primary;
+
+        &::placeholder {
+          color: $text-tertiary;
+        }
+      }
+
+      .search-action-btn {
+        background: $primary-color;
+        color: white;
+        border: none;
+        border-radius: 6px;
+        padding: 6px 12px;
+        font-size: 12px;
+        cursor: pointer;
+        transition: $transition;
+        display: flex;
+        align-items: center;
+        gap: 4px;
+
+        &:hover:not(:disabled) {
+          background: $primary-dark;
+        }
+
+        &:disabled {
+          background: $text-tertiary;
+          cursor: not-allowed;
+        }
+      }
+    }
+
+    // 搜索结果下拉
+    .search-dropdown {
+      position: absolute;
+      top: 100%;
+      left: 0;
+      right: 0;
+      background: $background-secondary;
+      border: 1px solid $border-color;
+      border-radius: 10px;
+      margin-top: 4px;
+      box-shadow: $shadow-lg;
+      z-index: 1000;
+      max-height: 300px;
+      overflow-y: auto;
+
+      .dropdown-header {
+        padding: 12px 16px;
+        background: $background-primary;
+        border-bottom: 1px solid $border-color;
+        font-size: 12px;
+        color: $text-secondary;
+        font-weight: 500;
+      }
+
+      .customer-option {
+        display: flex;
+        align-items: center;
+        gap: 12px;
+        padding: 12px 16px;
+        cursor: pointer;
+        transition: $transition;
+
+        &:hover {
+          background: $background-primary;
+        }
+
+        .customer-avatar-sm {
+          width: 36px;
+          height: 36px;
+          border-radius: 18px;
+          background: $primary-color;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          color: white;
+          font-weight: 600;
+          font-size: 14px;
+          flex-shrink: 0;
+
+          img {
+            width: 100%;
+            height: 100%;
+            border-radius: 18px;
+            object-fit: cover;
+          }
+        }
+
+        .customer-details {
+          flex: 1;
+
+          .customer-name {
+            font-weight: 500;
+            color: $text-primary;
+            margin-bottom: 2px;
+          }
+
+          .customer-phone {
+            font-size: 12px;
+            color: $text-secondary;
+          }
+        }
+
+        .customer-tags {
+          .tag {
+            background: $background-primary;
+            color: $text-secondary;
+            padding: 2px 8px;
+            border-radius: 4px;
+            font-size: 11px;
+            font-weight: 500;
+          }
+        }
+      }
+    }
+
+    // 已选择客户信息展示
+    .selected-customer-info {
+      display: flex;
+      align-items: center;
+      gap: 16px;
+      background: $background-secondary;
+      border: 1px solid $success-color;
+      border-radius: 10px;
+      padding: 16px;
+
+      .customer-avatar-lg {
+        width: 48px;
+        height: 48px;
+        border-radius: 24px;
+        background: $primary-color;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        color: white;
+        font-weight: 600;
+        font-size: 18px;
+        flex-shrink: 0;
+
+        img {
+          width: 100%;
+          height: 100%;
+          border-radius: 24px;
+          object-fit: cover;
+        }
+      }
+
+      .customer-main-info {
+        flex: 1;
+
+        .customer-name {
+          font-weight: 600;
+          color: $text-primary;
+          margin-bottom: 4px;
+          font-size: 16px;
+        }
+
+        .customer-phone {
+          color: $text-secondary;
+          margin-bottom: 2px;
+          font-size: 14px;
+        }
+
+        .customer-type {
+          background: $success-color;
+          color: white;
+          padding: 2px 8px;
+          border-radius: 4px;
+          font-size: 11px;
+          font-weight: 500;
+          display: inline-block;
+        }
+      }
+
+      .clear-customer-btn {
+        background: $background-primary;
+        color: $text-secondary;
+        border: 1px solid $border-color;
+        border-radius: 6px;
+        padding: 8px 12px;
+        font-size: 12px;
+        cursor: pointer;
+        transition: $transition;
+        display: flex;
+        align-items: center;
+        gap: 4px;
+
+        &:hover {
+          background: $danger-color;
+          color: white;
+          border-color: $danger-color;
+        }
+      }
+    }
+  }
+
+  // 项目需求表单样式
+  .requirement-section {
+    background: $background-secondary;
+    border-radius: $border-radius;
+    padding: 16px;
+    margin-bottom: 20px;
+    border: 1px solid $border-color;
+    box-shadow: $shadow-sm;
+
+    .section-header {
+      margin-bottom: 16px;
+
+      h3 {
+        margin: 0;
+        font-size: 16px;
+        font-weight: 600;
+        color: $text-primary;
+      }
+    }
+
+    .requirement-form {
+      .form-row {
+        display: flex;
+        gap: 16px;
+        margin-bottom: 16px;
+
+        @media (max-width: 768px) {
+          flex-direction: column;
+          gap: 12px;
+        }
+      }
+
+      .form-group {
+        flex: 1;
+
+        &.full-width {
+          width: 100%;
+        }
+
+        label {
+          display: block;
+          margin-bottom: 6px;
+          font-weight: 500;
+          color: $text-primary;
+          font-size: 14px;
+
+          .required {
+            color: $danger-color;
+            margin-left: 2px;
+          }
+        }
+
+        .field-input,
+        .field-select,
+        .field-textarea {
+          width: 100%;
+          padding: 12px 16px;
+          border: 1px solid $border-color;
+          border-radius: 8px;
+          font-size: 14px;
+          color: $text-primary;
+          background: $background-secondary;
+          transition: $transition;
+
+          &:focus {
+            outline: none;
+            border-color: $primary-color;
+            box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
+          }
+
+          &::placeholder {
+            color: $text-tertiary;
+          }
+        }
+
+        .field-textarea {
+          min-height: 80px;
+          resize: vertical;
+        }
+
+        .input-with-unit {
+          position: relative;
+          display: flex;
+          align-items: center;
+
+          .field-input {
+            padding-right: 40px;
+          }
+
+          .input-unit {
+            position: absolute;
+            right: 16px;
+            color: $text-secondary;
+            font-size: 14px;
+            pointer-events: none;
+          }
+        }
+      }
+    }
+  }
+
+  // 底部固定按钮区域
+  .order-actions {
+    position: sticky;
+    bottom: 0;
+    background: $background-secondary;
+    border-top: 1px solid $border-color;
+    padding: 16px 20px;
+    display: flex;
+    gap: 12px;
+    justify-content: flex-end;
+    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
+    z-index: 5;
+
+    .secondary-btn,
+    .primary-btn {
+      padding: 12px 24px;
+      border-radius: 10px;
+      font-size: 14px;
+      font-weight: 600;
+      cursor: pointer;
+      transition: $transition;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      border: none;
+      min-width: 120px;
+      justify-content: center;
+
+      svg {
+        width: 16px;
+        height: 16px;
+      }
+    }
+
+    .secondary-btn {
+      background: $background-primary;
+      color: $text-secondary;
+      border: 1px solid $border-color;
+
+      &:hover {
+        background: $background-tertiary;
+        color: $text-primary;
+        transform: translateY(-1px);
+        box-shadow: $shadow-sm;
+      }
+    }
+
+    .primary-btn {
+      background: $primary-color;
+      color: white;
+      box-shadow: $shadow-sm;
+
+      &:hover:not(:disabled) {
+        background: $primary-dark;
+        transform: translateY(-1px);
+        box-shadow: $shadow-md;
+      }
+
+      &:disabled {
+        background: $text-tertiary;
+        cursor: not-allowed;
+        transform: none;
+        box-shadow: none;
+      }
+    }
+  }
+}
+
 // Members & Requirements — iOS styled details and micro-interactions
 .project-detail-container {
   // Members tab

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

@@ -1,7 +1,7 @@
 import { Component, OnInit, signal, computed, ViewChild, AfterViewChecked } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { RouterModule, ActivatedRoute } from '@angular/router';
+import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { RouterModule, ActivatedRoute, Router } from '@angular/router';
 import { MatDialog, MatDialogModule } from '@angular/material/dialog';
 import { ProjectService } from '../../../services/project.service';
 import { Project, Task, Message, FileItem, CustomerFeedback, Milestone } from '../../../models/project.model';
@@ -54,6 +54,21 @@ interface HistoricalFeedback {
   response?: string;
 }
 
+// 定义客户接口
+interface Customer {
+  id: string;
+  name: string;
+  phone: string;
+  avatar?: string;
+  customerType: string;
+}
+
+// 定义装修风格选项接口
+interface DecorationStyle {
+  value: string;
+  label: string;
+}
+
 @Component({
   selector: 'app-project-detail',
   standalone: true,
@@ -187,14 +202,44 @@ export class ProjectDetail implements OnInit, AfterViewChecked {
     return Math.round((completedTasks / this.tasks().length) * 100);
   });
   
+  // 订单创建相关属性
+  isOrderCreationExpanded = signal(false);
+  orderSearchKeyword = signal('');
+  orderSearchResults = signal<Customer[]>([]);
+  selectedOrderCustomer = signal<Customer | null>(null);
+  orderRequirementForm: FormGroup;
+  
+  // 装修风格选项
+  decorationStyles: DecorationStyle[] = [
+    { value: 'modern', label: '现代简约' },
+    { value: 'chinese', label: '中式' },
+    { value: 'european', label: '欧式' },
+    { value: 'american', label: '美式' },
+    { value: 'nordic', label: '北欧' },
+    { value: 'industrial', label: '工业风' },
+    { value: 'mediterranean', label: '地中海' },
+    { value: 'japanese', label: '日式' }
+  ];
+
   constructor(
     private route: ActivatedRoute,
     private projectService: ProjectService,
-    private dialog: MatDialog
+    private dialog: MatDialog,
+    private fb: FormBuilder,
+    private router: Router
   ) {
     // 获取路由参数中的项目ID
-    this.route.paramMap.subscribe(params => {
-      this.projectId = params.get('id') || '';
+    this.route.params.subscribe(params => {
+      this.projectId = params['id'] || '';
+    });
+    
+    // 初始化订单表单
+    this.orderRequirementForm = this.fb.group({
+      projectType: ['', Validators.required],
+      area: ['', [Validators.required, Validators.min(1)]],
+      style: [''],
+      budget: [''],
+      requirements: ['']
     });
   }
   
@@ -848,4 +893,228 @@ export class ProjectDetail implements OnInit, AfterViewChecked {
       }
     });
   }
+
+  // 订单创建相关方法
+  toggleOrderCreation(): void {
+    this.isOrderCreationExpanded.set(!this.isOrderCreationExpanded());
+  }
+
+  searchOrderCustomer(): void {
+    const keyword = this.orderSearchKeyword().trim();
+    if (!keyword) {
+      this.orderSearchResults.set([]);
+      return;
+    }
+
+    // 模拟客户搜索
+    const mockCustomers: Customer[] = [
+      {
+        id: '1',
+        name: '张三',
+        phone: '13800138001',
+        avatar: '',
+        customerType: 'VIP客户'
+      },
+      {
+        id: '2',
+        name: '李四',
+        phone: '13800138002',
+        avatar: '',
+        customerType: '普通客户'
+      },
+      {
+        id: '3',
+        name: '王五',
+        phone: '13800138003',
+        avatar: '',
+        customerType: '新客户'
+      }
+    ];
+
+    const results = mockCustomers.filter(customer => 
+      customer.name.includes(keyword) || customer.phone.includes(keyword)
+    );
+    
+    this.orderSearchResults.set(results);
+  }
+
+  selectOrderCustomer(customer: Customer): void {
+    this.selectedOrderCustomer.set(customer);
+    this.orderSearchResults.set([]);
+    this.orderSearchKeyword.set('');
+  }
+
+  clearOrderCustomer(): void {
+    this.selectedOrderCustomer.set(null);
+    this.orderSearchKeyword.set('');
+    this.orderSearchResults.set([]);
+  }
+
+  quickFillOrderCustomerInfo(keyword: string): void {
+    // 快速填充客户信息的逻辑
+    if (keyword.trim()) {
+      const newCustomer: Customer = {
+        id: 'new-' + Date.now(),
+        name: keyword,
+        phone: '',
+        customerType: '新客户'
+      };
+      this.selectedOrderCustomer.set(newCustomer);
+      this.orderSearchKeyword.set('');
+    }
+  }
+
+  isOrderFormValid(): boolean {
+    return this.orderRequirementForm.valid && this.selectedOrderCustomer() !== null;
+  }
+
+  resetOrderForm(): void {
+    this.orderRequirementForm.reset();
+    this.clearOrderCustomer();
+    
+    // 重置创建按钮状态
+    const createBtn = document.querySelector('.primary-btn') as HTMLButtonElement;
+    if (createBtn) {
+      createBtn.disabled = false;
+      createBtn.innerHTML = `
+        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+          <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
+          <polyline points="22 4 12 14.01 9 11.01"></polyline>
+        </svg>
+        创建订单
+      `;
+    }
+  }
+
+  createOrder(): void {
+    if (!this.isOrderFormValid()) {
+      return;
+    }
+
+    const orderData = {
+      customer: this.selectedOrderCustomer(),
+      requirements: this.orderRequirementForm.value,
+      createTime: new Date(),
+      orderId: 'ORD-' + Date.now(),
+      status: 'pending'
+    };
+
+    console.log('创建订单:', orderData);
+
+    // 显示创建中状态
+    const createBtn = document.querySelector('.primary-btn') as HTMLButtonElement;
+    if (createBtn) {
+      createBtn.disabled = true;
+      createBtn.innerHTML = `
+        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+          <path d="M21 12a9 9 0 11-6.219-8.56"></path>
+        </svg>
+        创建中...
+      `;
+    }
+
+    // 模拟订单创建API调用
+    setTimeout(() => {
+      // 生成新的项目ID
+      const newProjectId = 'PRJ-' + Date.now();
+      
+      // 显示成功提示
+      this.showOrderCreationSuccess(orderData.orderId, newProjectId);
+      
+      // 重置表单
+      this.resetOrderForm();
+      
+      // 收起订单创建板块
+      this.isOrderCreationExpanded.set(false);
+      
+      // 延迟跳转到新创建的项目详情页面
+      setTimeout(() => {
+        this.router.navigate(['/customer-service/project-detail', newProjectId], {
+          queryParams: {
+            role: 'customer_service',
+            activeTab: 'overview',
+            fromOrder: 'true'
+          }
+        });
+      }, 2000);
+    }, 1500);
+  }
+
+  private showOrderCreationSuccess(orderId: string, projectId: string): void {
+    // 创建成功提示元素
+    const successMessage = document.createElement('div');
+    successMessage.className = 'order-success-toast';
+    successMessage.innerHTML = `
+      <div class="success-content">
+        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+          <path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
+          <polyline points="22 4 12 14.01 9 11.01"></polyline>
+        </svg>
+        <div class="success-text">
+          <h4>订单创建成功!</h4>
+          <p>订单号:${orderId}</p>
+          <p>项目ID:${projectId}</p>
+          <p>即将跳转到项目详情页面...</p>
+        </div>
+      </div>
+    `;
+
+    // 添加样式
+    successMessage.style.cssText = `
+      position: fixed;
+      top: 20px;
+      right: 20px;
+      background: #34C759;
+      color: white;
+      padding: 16px 20px;
+      border-radius: 12px;
+      box-shadow: 0 10px 25px rgba(52, 199, 89, 0.3);
+      z-index: 10000;
+      animation: slideInRight 0.3s ease-out;
+    `;
+
+    // 添加动画样式
+    const style = document.createElement('style');
+    style.textContent = `
+      @keyframes slideInRight {
+        from {
+          transform: translateX(100%);
+          opacity: 0;
+        }
+        to {
+          transform: translateX(0);
+          opacity: 1;
+        }
+      }
+      .order-success-toast .success-content {
+        display: flex;
+        align-items: center;
+        gap: 12px;
+      }
+      .order-success-toast .success-text h4 {
+        margin: 0 0 4px 0;
+        font-size: 16px;
+        font-weight: 600;
+      }
+      .order-success-toast .success-text p {
+        margin: 2px 0;
+        font-size: 14px;
+        opacity: 0.9;
+      }
+    `;
+    document.head.appendChild(style);
+
+    // 添加到页面
+    document.body.appendChild(successMessage);
+
+    // 3秒后移除提示
+    setTimeout(() => {
+      if (successMessage.parentNode) {
+        successMessage.parentNode.removeChild(successMessage);
+      }
+      if (style.parentNode) {
+        style.parentNode.removeChild(style);
+      }
+    }, 3000);
+  }
 }

+ 2 - 28
src/app/pages/customer-service/project-list/project-list.html

@@ -31,7 +31,7 @@
             <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()">
+          <button class="add-project-btn" (click)="navigateToCreateOrder()">
             <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
               <line x1="12" y1="5" x2="12" y2="19"></line>
               <line x1="5" y1="12" x2="19" y2="12"></line>
@@ -254,32 +254,7 @@
         }
       }
 
-      <!-- 添加项目弹窗 -->
-      @if (createModalVisible()) {
-        <div class="modal-backdrop" (click)="cancelCreateProject()"></div>
-        <div class="modal">
-          <div class="modal-header">
-            <h3>添加项目</h3>
-            <button class="close-btn" (click)="cancelCreateProject()">✖</button>
-          </div>
-          <div class="modal-body">
-            <div class="form-item">
-              <label>客户名称</label>
-              <input type="text" [value]="newCustomerName()" (input)="newCustomerName.set($any($event.target).value)" placeholder="请输入客户名称" />
-            </div>
-            <div class="form-item">
-              <label>核心需求</label>
-              <textarea rows="4" [value]="newRequirement()" (input)="newRequirement.set($any($event.target).value)" placeholder="请输入客户核心需求...">
-              </textarea>
-            </div>
-            <div class="tip">仅需填写以上两项,后续信息在详情页补充</div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn-secondary" (click)="cancelCreateProject()">取消</button>
-            <button class="btn-primary" (click)="submitCreateProject()">提交创建</button>
-          </div>
-        </div>
-      }
+
 
       <!-- 视图:监控大盘模式 -->
       @if (viewMode() === 'dashboard') {
@@ -297,4 +272,3 @@
         </div>
       }
     </div>
-</div>

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

@@ -1196,4 +1196,4 @@ $transition: all 0.3s ease;
       }
     }
   }
-}
+}

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

@@ -1,8 +1,10 @@
-import { Component, OnInit, signal, computed } from '@angular/core';
+import { Component, OnInit, signal, computed, Inject } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
 import { Router, RouterModule } from '@angular/router';
+import { MatDialog, MatDialogModule } from '@angular/material/dialog';
 import { ProjectService } from '../../../services/project.service';
+import { ConsultationOrderDialogComponent } from '../consultation-order/consultation-order-dialog.component';
 import { Project, ProjectStatus, ProjectStage } from '../../../models/project.model';
 
 // 定义项目列表项接口,包含计算后的属性
@@ -16,7 +18,7 @@ interface ProjectListItem extends Project {
 @Component({
   selector: 'app-project-list',
   standalone: true,
-  imports: [CommonModule, FormsModule, RouterModule],
+  imports: [CommonModule, FormsModule, RouterModule, MatDialogModule],
   templateUrl: './project-list.html',
   styleUrls: ['./project-list.scss', '../customer-service-styles.scss']
 })
@@ -38,11 +40,6 @@ export class ProjectList implements OnInit {
     { id: 'done', name: '已完成' }
   ] as const;
 
-  // 创建项目弹窗
-  createModalVisible = signal(false);
-  newCustomerName = signal('');
-  newRequirement = signal('');
-
   // 基础项目集合(服务端返回 + 本地生成),用于二次处理
   private baseProjects: Project[] = [];
 
@@ -101,7 +98,11 @@ export class ProjectList implements OnInit {
     { value: 'name', label: '项目名称' }
   ];
   
-  constructor(private projectService: ProjectService, private router: Router) {}
+  constructor(
+    private projectService: ProjectService, 
+    private router: Router,
+    private dialog: MatDialog
+  ) {}
   
   ngOnInit(): void {
     // 读取上次的视图记忆
@@ -426,67 +427,34 @@ export class ProjectList implements OnInit {
 
   // 新增:直接进入沟通管理(消息)标签
   navigateToMessages(project: ProjectListItem) {
-    this.router.navigate(['/customer-service/project-detail', project.id], {
-      queryParams: { role: 'customer_service', activeTab: 'messages' }
-    });
-  }
-  
-  // 打开/关闭创建项目弹窗
-  openCreateProjectModal() {
-    this.newCustomerName.set('');
-    this.newRequirement.set('');
-    this.createModalVisible.set(true);
-  }
-
-  cancelCreateProject() {
-    this.createModalVisible.set(false);
+    this.router.navigate(['/customer-service/messages'], { queryParams: { projectId: project.id } });
   }
 
-  // 提交创建项目(最小必填:客户名称 + 核心需求)
-  submitCreateProject() {
-    const customerName = this.newCustomerName().trim();
-    const requirementText = this.newRequirement().trim();
-    if (!customerName || !requirementText) {
-      alert('请填写客户名称和核心需求');
-      return;
-    }
-
-    const payload = {
-      customerId: 'temp-' + Date.now(),
-      customerName,
-      requirement: requirementText,
-      referenceCases: [],
-      tags: { followUpStatus: '待分配' }
-    };
+  // 导航到创建订单页面
+  navigateToCreateOrder() {
+    // 打开咨询订单弹窗
+    const dialogRef = this.dialog.open(ConsultationOrderDialogComponent, {
+      width: '900px',
+      maxWidth: '95vw',
+      maxHeight: '90vh',
+      panelClass: 'consultation-order-dialog'
+    });
 
-    this.projectService.createProject(payload).subscribe(res => {
-      if (res.success) {
-        // 组装前端项目对象(默认待分配:无assignee)
-        const now = new Date();
-        const deadline = new Date(now.getTime() + 14 * 24 * 60 * 60 * 1000);
-        const newProject: Project = {
-          id: res.projectId,
-          name: `${customerName} 项目`,
-          customerName,
-          customerTags: [],
-          highPriorityNeeds: [],
-          status: '进行中',
-          currentStage: '需求沟通',
-          createdAt: now,
-          deadline: deadline,
-          assigneeId: '',
-          assigneeName: '',
-          skillsRequired: []
-        };
-        this.baseProjects = [newProject, ...this.baseProjects];
-        this.processProjects(this.baseProjects);
-        this.createModalVisible.set(false);
-        // 新建后滚动到“待分配”列顶部
-        setTimeout(() => {
-          const el = document.querySelector('.kanban-column[data-col="pending"]');
-          el?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
-        }, 0);
-      }
+    // 监听订单创建成功事件
+    dialogRef.componentInstance.orderCreated.subscribe((orderData: any) => {
+      // 关闭弹窗
+      dialogRef.close();
+      
+      // 跳转到新创建的项目详情页面
+      this.router.navigate([
+        '/customer-service/project-detail', 
+        orderData.orderId
+      ], {
+        queryParams: { 
+          role: 'customer_service', 
+          activeTab: 'overview'
+        }
+      });
     });
   }
 }

+ 3 - 96
src/app/pages/designer/project-detail/project-detail.html

@@ -207,23 +207,9 @@
                     <!-- 直接复用原阶段内容卡片:按stage匹配显示 -->
                     <div class="vertical-stage-body">
                       @if (stage === '订单创建') {
-                        <app-order-creation-card
-                          [orderCreationMethod]="orderCreationMethod"
-                          (orderCreationMethodChange)="orderCreationMethod = $event"
-                          [isSyncing]="isSyncing"
-                          [orderTime]="orderTime"
-                          [customerSearchKeyword]="customerSearchKeyword"
-                          (customerSearchKeywordChange)="customerSearchKeyword = $event"
-                          [customerSearchResults]="customerSearchResults"
-                          [selectedCustomer]="selectedOrderCustomer"
-                          (searchCustomer)="searchCustomer()"
-                          (selectCustomer)="selectCustomer($event)"
-                          (clearSelectedCustomer)="clearSelectedCustomer()"
-                          (syncMiniprogram)="syncMiniprogramCustomerInfo()"
-                          [customerForm]="customerForm"
-                          [demandTypes]="demandTypes"
-                          [followUpStatus]="followUpStatus"
-                        ></app-order-creation-card>
+                        <app-consultation-order-panel
+                          (formSubmit)="onConsultationOrderSubmit($event)"
+                        ></app-consultation-order-panel>
                       } @else if (stage === '需求沟通') {
                         <app-requirements-confirm-card></app-requirements-confirm-card>
                       } @else if (stage === '方案确认') {
@@ -307,7 +293,6 @@
                                 </label>
                                 <span class="check-status">{{ item.isPassed ? '已通过' : '待处理' }}</span>
                               </div>
-<<<<<<< HEAD
                             }
                           </div>
                         </div>
@@ -351,84 +336,6 @@
                                                 <line x1="6" y1="6" x2="18" y2="18"></line>
                                               </svg>
                                             </button>
-=======
-                              <div class="vertical-stage-body">
-                                <!-- 复用原模板各阶段的具体内容(示例:尾款结算等) -->
-                                @if (stage === '尾款结算') {
-                                  @if (settlements.length > 0) {
-                                    <div class="settlement-table">
-                                      <table>
-                                        <thead>
-                                          <tr>
-                                            <th>阶段</th>
-                                            <th>比例</th>
-                                            <th>金额</th>
-                                            <th>状态</th>
-                                            <th>时间</th>
-                                          </tr>
-                                        </thead>
-                                        <tbody>
-                                          @for (st of settlements; track st.id) {
-                                            <tr>
-                                              <td>{{ st.stage }}</td>
-                                              <td>{{ st.percentage }}%</td>
-                                              <td>¥{{ st.amount | number:'1.0-0' }}</td>
-                                              <td>{{ st.status }}</td>
-                                              <td>{{ (st.settledAt || st.createdAt) | date:'MM-dd HH:mm' }}</td>
-                                            </tr>
-                                          }
-                                        </tbody>
-                                      </table>
-                                    </div>
-                                  }
-                                }
-                                @if (stage === '客户评价') {
-                                  <div class="empty">此处可扩展客户评价表单/列表</div>
-                                }
-                                @if (stage === '投诉处理') {
-                                  <div class="empty">此处可扩展投诉处理流程/记录</div>
-                                }
-                                @if (stage === '订单创建') {
-                                  <div>
-                                    <div style="display:flex; gap:12px; align-items:center; margin-bottom:12px; flex-wrap: wrap;">
-                                      <div style="display:flex; gap:8px; align-items:center;">
-                                        <button class="secondary-btn" [class.active]="orderCreationMethod === 'miniprogram'" (click)="orderCreationMethod = 'miniprogram'">小程序同步</button>
-                                        <button class="secondary-btn" [class.active]="orderCreationMethod === 'manual'" (click)="orderCreationMethod = 'manual'">手动录入</button>
-                                      </div>
-                                      <span class="hint">下单时间:{{ orderTime }}</span>
-                                    </div>
-
-                                    @if (orderCreationMethod === 'miniprogram') {
-                                      <div style="display:flex; gap:12px; align-items:center; margin-bottom:12px;">
-                                        <button class="primary-btn" [disabled]="isSyncing" (click)="syncMiniprogramCustomerInfo()">{{ isSyncing ? '同步中...' : '从小程序同步客户信息' }}</button>
-                                        <span class="hint">点击同步后将自动填充客户姓名、手机号、微信等信息</span>
-                                      </div>
-                                    }
-
-                                    <div style="border-top:1px solid #e5e7eb; padding-top:12px; margin-top:4px;"></div>
-
-                                    <div style="margin-bottom:12px; display:flex; gap:8px; align-items:center; flex-wrap: wrap;">
-                                      <input type="text" placeholder="搜索客户姓名或手机号" [(ngModel)]="customerSearchKeyword" (ngModelChange)="searchCustomer()" style="flex:1 1 260px; padding:8px 10px; border:1px solid #d1d5db; border-radius:6px;" />
-                                      <button class="secondary-btn" (click)="searchCustomer()">搜索</button>
-                                      @if (selectedOrderCustomer) {
-                                        <div style="display:flex; gap:8px; align-items:center; background:#f3f4f6; padding:6px 10px; border-radius:9999px;">
-                                          <span>已选客户:{{ selectedOrderCustomer.name }}({{ selectedOrderCustomer.phone }})</span>
-                                          <button class="link danger" (click)="clearSelectedCustomer()">清除</button>
-                                        </div>
-                                      }
-                                    </div>
-
-                                    @if (customerSearchResults.length > 0) {
-                                      <div style="border:1px solid #e5e7eb; border-radius:8px; padding:8px; margin-bottom:12px; max-height:200px; overflow:auto;">
-                                        @for (c of customerSearchResults; track c.id) {
-                                          <div style="display:flex; justify-content:space-between; align-items:center; padding:6px 4px; border-bottom:1px dashed #f3f4f6;">
-                                            <div style="display:flex; gap:8px; align-items:center;">
-                                              <span style="font-weight:500;">{{ c.name }}</span>
-                                              <span style="color:#6b7280;">{{ c.phone }}</span>
-                                              @if (c.wechat) { <span style="color:#9ca3af;">wx: {{ c.wechat }}</span> }
-                                            </div>
-                                            <button class="link" (click)="selectCustomer(c)">选择</button>
->>>>>>> 0648016df9d2fd422344c75eef9d0e437f9c8f12
                                           </div>
                                         </div>
                                       </div>

+ 9 - 2
src/app/pages/designer/project-detail/project-detail.ts

@@ -12,7 +12,7 @@ import {
   Settlement,
   ProjectStage
 } from '../../../models/project.model';
-import { OrderCreationCardComponent } from '../../../shared/components/order-creation-card/order-creation-card';
+import { ConsultationOrderPanelComponent } from '../../../shared/components/consultation-order-panel/consultation-order-panel.component';
 import { RequirementsConfirmCardComponent } from '../../../shared/components/requirements-confirm-card/requirements-confirm-card';
 import { SettlementCardComponent } from '../../../shared/components/settlement-card/settlement-card';
 import { CustomerReviewCardComponent } from '../../../shared/components/customer-review-card/customer-review-card';
@@ -61,7 +61,7 @@ type SectionKey = 'order' | 'requirements' | 'delivery' | 'aftercare';
 @Component({
   selector: 'app-project-detail',
   standalone: true,
-  imports: [CommonModule, FormsModule, ReactiveFormsModule, OrderCreationCardComponent, RequirementsConfirmCardComponent, SettlementCardComponent, CustomerReviewCardComponent, ComplaintCardComponent, VerticalNavComponent],
+  imports: [CommonModule, FormsModule, ReactiveFormsModule, ConsultationOrderPanelComponent, RequirementsConfirmCardComponent, SettlementCardComponent, CustomerReviewCardComponent, ComplaintCardComponent, VerticalNavComponent],
   templateUrl: './project-detail.html',
   styleUrls: ['./project-detail.scss', './debug-styles.scss']
 })
@@ -1480,4 +1480,11 @@ export class ProjectDetail implements OnInit, OnDestroy {
     // 实现文件预览逻辑
     window.open(file.url, '_blank');
   }
+
+  // 处理咨询订单表单提交
+  onConsultationOrderSubmit(formData: any): void {
+    console.log('咨询订单表单提交:', formData);
+    // 这里可以添加处理表单提交的逻辑
+    // 例如:保存订单信息、更新项目状态等
+  }
 }

+ 125 - 1
src/app/pages/team-leader/dashboard/dashboard.html

@@ -317,4 +317,128 @@
       </div>
     </div>
   }
-</main>
+</main>
+
+<!-- 员工详情面板 -->
+@if (showEmployeeDetailPanel && selectedEmployeeDetail) {
+  <div class="employee-detail-overlay" (click)="closeEmployeeDetailPanel()">
+    <div class="employee-detail-panel" (click)="$event.stopPropagation()">
+      <!-- 面板头部 -->
+      <div class="panel-header">
+        <h3 class="panel-title">
+          <svg class="icon-user" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+            <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
+            <circle cx="12" cy="7" r="4"></circle>
+          </svg>
+          {{ selectedEmployeeDetail.name }} 详情
+        </h3>
+        <button class="btn-close" (click)="closeEmployeeDetailPanel()">
+          <svg 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 class="panel-content">
+        <!-- 负载概况栏 -->
+        <div class="section workload-section">
+          <div class="section-header">
+            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+              <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
+              <line x1="9" y1="9" x2="15" y2="9"></line>
+              <line x1="9" y1="15" x2="15" y2="15"></line>
+            </svg>
+            <h4>负载概况</h4>
+          </div>
+          <div class="workload-info">
+            <div class="workload-stat">
+              <span class="stat-label">当前负责项目数:</span>
+              <span class="stat-value" [class]="selectedEmployeeDetail.currentProjects >= 3 ? 'high-workload' : 'normal-workload'">
+                {{ selectedEmployeeDetail.currentProjects }} 个
+              </span>
+            </div>
+            @if (selectedEmployeeDetail.projectNames.length > 0) {
+              <div class="project-list">
+                <span class="project-label">核心项目:</span>
+                <div class="project-tags">
+                  @for (projectName of selectedEmployeeDetail.projectNames; track $index) {
+                    <span class="project-tag">{{ projectName }}</span>
+                  }
+                  @if (selectedEmployeeDetail.currentProjects > selectedEmployeeDetail.projectNames.length) {
+                    <span class="project-tag more">+{{ selectedEmployeeDetail.currentProjects - selectedEmployeeDetail.projectNames.length }}</span>
+                  }
+                </div>
+              </div>
+            }
+          </div>
+        </div>
+
+        <!-- 请假明细栏 -->
+        <div class="section leave-section">
+          <div class="section-header">
+            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+              <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
+              <line x1="16" y1="2" x2="16" y2="6"></line>
+              <line x1="8" y1="2" x2="8" y2="6"></line>
+              <line x1="3" y1="10" x2="21" y2="10"></line>
+            </svg>
+            <h4>请假明细(未来7天)</h4>
+          </div>
+          <div class="leave-table">
+            @if (selectedEmployeeDetail.leaveRecords.length > 0) {
+              <table>
+                <thead>
+                  <tr>
+                    <th>日期</th>
+                    <th>状态</th>
+                    <th>备注</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  @for (record of selectedEmployeeDetail.leaveRecords; track record.id) {
+                    <tr [class]="record.isLeave ? 'leave-day' : 'work-day'">
+                      <td>{{ record.date | date:'M月d日' }}</td>
+                      <td>
+                        <span class="status-badge" [class]="record.isLeave ? 'leave' : 'work'">
+                          {{ record.isLeave ? '请假' : '正常' }}
+                        </span>
+                      </td>
+                      <td>{{ record.isLeave ? getLeaveTypeText(record.leaveType) : '-' }}</td>
+                    </tr>
+                  }
+                </tbody>
+              </table>
+            } @else {
+              <div class="no-leave">
+                <svg class="no-data-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                  <circle cx="12" cy="12" r="10"></circle>
+                  <path d="M8 14s1.5 2 4 2 4-2 4-2"></path>
+                  <line x1="9" y1="9" x2="9.01" y2="9"></line>
+                  <line x1="15" y1="9" x2="15.01" y2="9"></line>
+                </svg>
+                <p>未来7天无请假安排</p>
+              </div>
+            }
+          </div>
+        </div>
+
+        <!-- 红色标记说明 -->
+        <div class="section explanation-section">
+          <div class="section-header">
+            <svg class="section-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+              <circle cx="12" cy="12" r="10"></circle>
+              <line x1="12" y1="8" x2="12" y2="12"></line>
+              <line x1="12" y1="16" x2="12.01" y2="16"></line>
+            </svg>
+            <h4>红色标记说明</h4>
+          </div>
+          <div class="explanation-content">
+            <p class="explanation-text">{{ selectedEmployeeDetail.redMarkExplanation }}</p>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+}

+ 357 - 0
src/app/pages/team-leader/dashboard/dashboard.scss

@@ -1045,4 +1045,361 @@
   .project-kanban {
     .kanban-header, .kanban-body { grid-template-columns: 1fr; }
   }
+}
+
+/* 员工详情面板样式 */
+.employee-detail-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  backdrop-filter: blur(4px);
+  z-index: 1000;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 20px;
+  animation: fadeIn 0.3s ease-out;
+}
+
+.employee-detail-panel {
+  background: #ffffff;
+  border-radius: 16px;
+  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
+  max-width: 600px;
+  width: 100%;
+  max-height: 80vh;
+  overflow: hidden;
+  animation: slideUp 0.3s ease-out;
+  
+  .panel-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 24px 24px 16px;
+    border-bottom: 1px solid #f1f5f9;
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    color: white;
+    
+    .panel-title {
+      display: flex;
+      align-items: center;
+      gap: 12px;
+      margin: 0;
+      font-size: 20px;
+      font-weight: 600;
+      
+      .icon-user {
+        width: 24px;
+        height: 24px;
+        stroke-width: 2;
+      }
+    }
+    
+    .btn-close {
+      background: rgba(255, 255, 255, 0.2);
+      border: none;
+      border-radius: 8px;
+      width: 36px;
+      height: 36px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      
+      svg {
+        width: 18px;
+        height: 18px;
+        stroke: white;
+      }
+      
+      &:hover {
+        background: rgba(255, 255, 255, 0.3);
+        transform: scale(1.05);
+      }
+    }
+  }
+  
+  .panel-content {
+    padding: 24px;
+    max-height: calc(80vh - 100px);
+    overflow-y: auto;
+    
+    .section {
+      margin-bottom: 24px;
+      
+      &:last-child {
+        margin-bottom: 0;
+      }
+      
+      .section-header {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        margin-bottom: 16px;
+        
+        .section-icon {
+          width: 20px;
+          height: 20px;
+          stroke: #667eea;
+          stroke-width: 2;
+        }
+        
+        h4 {
+          margin: 0;
+          font-size: 16px;
+          font-weight: 600;
+          color: #1e293b;
+        }
+      }
+    }
+    
+    // 负载概况样式
+    .workload-section {
+      .workload-info {
+        background: #f8fafc;
+        border-radius: 12px;
+        padding: 20px;
+        border: 1px solid #e2e8f0;
+        
+        .workload-stat {
+          display: flex;
+          align-items: center;
+          gap: 8px;
+          margin-bottom: 16px;
+          
+          .stat-label {
+            font-size: 14px;
+            color: #64748b;
+            font-weight: 500;
+          }
+          
+          .stat-value {
+            font-size: 18px;
+            font-weight: 700;
+            padding: 4px 12px;
+            border-radius: 20px;
+            
+            &.normal-workload {
+              color: #059669;
+              background: #d1fae5;
+            }
+            
+            &.high-workload {
+              color: #dc2626;
+              background: #fee2e2;
+            }
+          }
+        }
+        
+        .project-list {
+          .project-label {
+            font-size: 14px;
+            color: #64748b;
+            font-weight: 500;
+            margin-bottom: 8px;
+            display: block;
+          }
+          
+          .project-tags {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 8px;
+            
+            .project-tag {
+              background: #667eea;
+              color: white;
+              padding: 4px 12px;
+              border-radius: 16px;
+              font-size: 12px;
+              font-weight: 500;
+              
+              &.more {
+                background: #94a3b8;
+              }
+            }
+          }
+        }
+      }
+    }
+    
+    // 请假明细样式
+    .leave-section {
+      .leave-table {
+        background: #ffffff;
+        border-radius: 12px;
+        border: 1px solid #e2e8f0;
+        overflow: hidden;
+        
+        table {
+          width: 100%;
+          border-collapse: collapse;
+          
+          thead {
+            background: #f8fafc;
+            
+            th {
+              padding: 12px 16px;
+              text-align: left;
+              font-size: 14px;
+              font-weight: 600;
+              color: #374151;
+              border-bottom: 1px solid #e5e7eb;
+            }
+          }
+          
+          tbody {
+            tr {
+              transition: background-color 0.2s ease;
+              
+              &:hover {
+                background: #f9fafb;
+              }
+              
+              &.leave-day {
+                background: #fef2f2;
+                
+                &:hover {
+                  background: #fee2e2;
+                }
+              }
+              
+              td {
+                padding: 12px 16px;
+                font-size: 14px;
+                color: #374151;
+                border-bottom: 1px solid #f1f5f9;
+                
+                &:last-child {
+                  border-bottom: none;
+                }
+              }
+            }
+            
+            tr:last-child td {
+              border-bottom: none;
+            }
+          }
+          
+          .status-badge {
+            padding: 4px 8px;
+            border-radius: 12px;
+            font-size: 12px;
+            font-weight: 500;
+            
+            &.work {
+              background: #d1fae5;
+              color: #059669;
+            }
+            
+            &.leave {
+              background: #fee2e2;
+              color: #dc2626;
+            }
+          }
+        }
+        
+        .no-leave {
+          padding: 40px 20px;
+          text-align: center;
+          color: #64748b;
+          
+          .no-data-icon {
+            width: 48px;
+            height: 48px;
+            margin: 0 auto 16px;
+            stroke: #94a3b8;
+            stroke-width: 1.5;
+          }
+          
+          p {
+            margin: 0;
+            font-size: 14px;
+          }
+        }
+      }
+    }
+    
+    // 红色标记说明样式
+    .explanation-section {
+      .explanation-content {
+        background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
+        border: 1px solid #f59e0b;
+        border-radius: 12px;
+        padding: 16px;
+        
+        .explanation-text {
+          margin: 0;
+          font-size: 14px;
+          color: #92400e;
+          line-height: 1.5;
+          font-weight: 500;
+        }
+      }
+    }
+  }
+}
+
+// 动画效果
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+
+@keyframes slideUp {
+  from {
+    opacity: 0;
+    transform: translateY(30px) scale(0.95);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0) scale(1);
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .employee-detail-overlay {
+    padding: 10px;
+    
+    .employee-detail-panel {
+      max-width: 100%;
+      max-height: 90vh;
+      
+      .panel-header {
+        padding: 20px 20px 12px;
+        
+        .panel-title {
+          font-size: 18px;
+        }
+      }
+      
+      .panel-content {
+        padding: 20px;
+        
+        .section {
+          margin-bottom: 20px;
+        }
+        
+        .workload-section .workload-info {
+          padding: 16px;
+        }
+        
+        .leave-section .leave-table table {
+          font-size: 13px;
+          
+          th, td {
+            padding: 10px 12px;
+          }
+        }
+      }
+    }
+  }
 }

+ 252 - 0
src/app/pages/team-leader/dashboard/dashboard.ts

@@ -52,6 +52,25 @@ interface TodoTask {
   targetId: string;
 }
 
+// 员工请假记录接口
+interface LeaveRecord {
+  id: string;
+  employeeName: string;
+  date: string; // YYYY-MM-DD 格式
+  isLeave: boolean;
+  leaveType?: 'sick' | 'personal' | 'annual' | 'other'; // 请假类型
+  reason?: string; // 请假原因
+}
+
+// 员工详情面板数据接口
+interface EmployeeDetail {
+  name: string;
+  currentProjects: number; // 当前负责项目数
+  projectNames: string[]; // 项目名称列表(用于显示)
+  leaveRecords: LeaveRecord[]; // 未来7天请假记录
+  redMarkExplanation: string; // 红色标记说明
+}
+
 declare const echarts: any;
 @Component({
   selector: 'app-dashboard',
@@ -134,6 +153,45 @@ export class Dashboard implements OnInit, OnDestroy {
   ganttScale: 'week' | 'month' = 'week';
   // 新增:甘特模式(项目 / 设计师排班)
   ganttMode: 'project' | 'designer' = 'project';
+
+  // 个人详情面板相关属性
+  showEmployeeDetailPanel: boolean = false;
+  selectedEmployeeDetail: EmployeeDetail | null = null;
+  
+  // 员工请假数据(模拟数据)
+  private leaveRecords: LeaveRecord[] = [
+    { id: '1', employeeName: '张三', date: '2024-01-20', isLeave: true, leaveType: 'personal', reason: '事假' },
+    { id: '2', employeeName: '张三', date: '2024-01-21', isLeave: false },
+    { id: '3', employeeName: '张三', date: '2024-01-22', isLeave: false },
+    { id: '4', employeeName: '张三', date: '2024-01-23', isLeave: false },
+    { id: '5', employeeName: '张三', date: '2024-01-24', isLeave: false },
+    { id: '6', employeeName: '张三', date: '2024-01-25', isLeave: false },
+    { id: '7', employeeName: '张三', date: '2024-01-26', isLeave: false },
+    
+    { id: '8', employeeName: '李四', date: '2024-01-20', isLeave: false },
+    { id: '9', employeeName: '李四', date: '2024-01-21', isLeave: true, leaveType: 'sick', reason: '病假' },
+    { id: '10', employeeName: '李四', date: '2024-01-22', isLeave: true, leaveType: 'sick', reason: '病假' },
+    { id: '11', employeeName: '李四', date: '2024-01-23', isLeave: false },
+    { id: '12', employeeName: '李四', date: '2024-01-24', isLeave: false },
+    { id: '13', employeeName: '李四', date: '2024-01-25', isLeave: false },
+    { id: '14', employeeName: '李四', date: '2024-01-26', isLeave: false },
+    
+    { id: '15', employeeName: '王五', date: '2024-01-20', isLeave: false },
+    { id: '16', employeeName: '王五', date: '2024-01-21', isLeave: false },
+    { id: '17', employeeName: '王五', date: '2024-01-22', isLeave: false },
+    { id: '18', employeeName: '王五', date: '2024-01-23', isLeave: true, leaveType: 'annual', reason: '年假' },
+    { id: '19', employeeName: '王五', date: '2024-01-24', isLeave: false },
+    { id: '20', employeeName: '王五', date: '2024-01-25', isLeave: false },
+    { id: '21', employeeName: '王五', date: '2024-01-26', isLeave: false },
+    
+    { id: '22', employeeName: '赵六', date: '2024-01-20', isLeave: false },
+    { id: '23', employeeName: '赵六', date: '2024-01-21', isLeave: false },
+    { id: '24', employeeName: '赵六', date: '2024-01-22', isLeave: false },
+    { id: '25', employeeName: '赵六', date: '2024-01-23', isLeave: false },
+    { id: '26', employeeName: '赵六', date: '2024-01-24', isLeave: false },
+    { id: '27', employeeName: '赵六', date: '2024-01-25', isLeave: false },
+    { id: '28', employeeName: '赵六', date: '2024-01-26', isLeave: false }
+  ];
   constructor(private projectService: ProjectService, private router: Router) {}
 
   ngOnInit(): void {
@@ -658,6 +716,21 @@ export class Dashboard implements OnInit, OnDestroy {
     const el = this.ganttChartRef.nativeElement;
     if (!this.ganttChart) {
       this.ganttChart = echarts.init(el);
+      
+      // 添加点击事件监听器
+      this.ganttChart.on('click', (params: any) => {
+        if (params.componentType === 'series' && params.seriesType === 'custom') {
+          // 获取点击的员工名称(从y轴类目数据中获取)
+          const yAxisData = this.ganttChart.getOption().yAxis[0].data;
+          if (yAxisData && params.dataIndex !== undefined) {
+            const employeeName = yAxisData[params.value[0]];
+            if (employeeName && employeeName !== '未分配') {
+              this.onEmployeeClick(employeeName);
+            }
+          }
+        }
+      });
+      
       window.addEventListener('resize', () => {
         this.ganttChart && this.ganttChart.resize();
       });
@@ -757,6 +830,9 @@ export class Dashboard implements OnInit, OnDestroy {
     const preservedStart = typeof prevOpt?.dataZoom?.[0]?.start === 'number' ? prevOpt.dataZoom[0].start : 0;
     const preservedEnd = typeof prevOpt?.dataZoom?.[0]?.end === 'number' ? prevOpt.dataZoom[0].end : defaultEndPercent;
 
+    // 生成请假覆盖层数据
+    const leaveOverlayData = this.generateLeaveOverlayData(categories, xMin, xMax);
+
     const option = {
       backgroundColor: 'transparent',
       tooltip: {
@@ -804,8 +880,10 @@ export class Dashboard implements OnInit, OnDestroy {
         { type: 'inside', yAxisIndex: 0, zoomOnMouseWheel: true, moveOnMouseMove: true, moveOnMouseWheel: true }
       ],
       series: [
+        // 项目条形图系列
         {
           type: 'custom',
+          name: '项目进度',
           renderItem: (params: any, api: any) => {
             const categoryIndex = api.value(0);
             const start = api.coord([api.value(1), categoryIndex]);
@@ -835,6 +913,34 @@ export class Dashboard implements OnInit, OnDestroy {
             label: { formatter: '今日', color: '#ef4444', fontSize: 10, position: 'end' },
             data: [ { xAxis: todayTs } ]
           }
+        },
+        // 请假覆盖层系列
+        {
+          type: 'custom',
+          name: '请假/繁忙标记',
+          renderItem: (params: any, api: any) => {
+            const categoryIndex = api.value(0);
+            const start = api.coord([api.value(1), categoryIndex]);
+            const end = api.coord([api.value(2), categoryIndex]);
+            const height = Math.max(api.size([0, 1])[1] * 0.8, 12); // 稍微高一点,覆盖项目条
+            const rectShape = echarts.graphic.clipRectByRect({
+              x: start[0],
+              y: start[1] - height / 2,
+              width: Math.max(end[0] - start[0], 2),
+              height
+            }, {
+              x: params.coordSys.x,
+              y: params.coordSys.y,
+              width: params.coordSys.width,
+              height: params.coordSys.height
+            });
+            return rectShape ? { type: 'rect', shape: rectShape, style: api.style() } : undefined;
+          },
+          encode: { x: [1, 2], y: 0 },
+          data: leaveOverlayData,
+          itemStyle: { borderRadius: 4 },
+          emphasis: { focus: 'self' },
+          z: 10 // 确保覆盖层在项目条之上
         }
       ]
     };
@@ -1289,4 +1395,150 @@ export class Dashboard implements OnInit, OnDestroy {
     this.selectedStatus = 'all';
     this.applyFilters();
   }
+
+  // 处理甘特图员工点击事件
+  onEmployeeClick(employeeName: string): void {
+    if (!employeeName || employeeName === '未分配') {
+      return;
+    }
+    
+    // 生成员工详情数据
+    this.selectedEmployeeDetail = this.generateEmployeeDetail(employeeName);
+    this.showEmployeeDetailPanel = true;
+  }
+
+  // 生成员工详情数据
+  private generateEmployeeDetail(employeeName: string): EmployeeDetail {
+    // 获取该员工负责的项目
+    const employeeProjects = this.filteredProjects.filter(p => p.designerName === employeeName);
+    const currentProjects = employeeProjects.length;
+    const projectNames = employeeProjects.slice(0, 3).map(p => p.name); // 最多显示3个项目名称
+    
+    // 获取该员工的请假记录(未来7天)
+    const today = new Date();
+    const next7Days = Array.from({ length: 7 }, (_, i) => {
+      const date = new Date(today);
+      date.setDate(today.getDate() + i);
+      return date.toISOString().split('T')[0]; // YYYY-MM-DD 格式
+    });
+    
+    const employeeLeaveRecords = this.leaveRecords.filter(record => 
+      record.employeeName === employeeName && next7Days.includes(record.date)
+    );
+    
+    // 生成红色标记说明
+    const redMarkExplanation = this.generateRedMarkExplanation(employeeName, employeeLeaveRecords, currentProjects);
+    
+    return {
+      name: employeeName,
+      currentProjects,
+      projectNames,
+      leaveRecords: employeeLeaveRecords,
+      redMarkExplanation
+    };
+  }
+
+  // 生成红色标记说明
+  private generateRedMarkExplanation(employeeName: string, leaveRecords: LeaveRecord[], projectCount: number): string {
+    const explanations: string[] = [];
+    
+    // 检查请假情况
+    const leaveDays = leaveRecords.filter(record => record.isLeave);
+    if (leaveDays.length > 0) {
+      leaveDays.forEach(leave => {
+        const date = new Date(leave.date);
+        const dateStr = `${date.getMonth() + 1}月${date.getDate()}日`;
+        explanations.push(`${dateStr}(${leave.reason || '请假'})`);
+      });
+    }
+    
+    // 检查项目繁忙情况
+    if (projectCount >= 3) {
+      const today = new Date();
+      const dateStr = `${today.getMonth() + 1}月${today.getDate()}日`;
+      explanations.push(`${dateStr}(${projectCount}个项目繁忙)`);
+    }
+    
+    if (explanations.length === 0) {
+      return '当前无红色标记时段';
+    }
+    
+    return `甘特图中红色时段说明:${explanations.map((exp, index) => `${index + 1}${exp}`).join(';')}`;
+  }
+
+  // 关闭员工详情面板
+  closeEmployeeDetailPanel(): void {
+    this.showEmployeeDetailPanel = false;
+    this.selectedEmployeeDetail = null;
+  }
+
+  // 获取请假类型显示文本
+  getLeaveTypeText(leaveType?: string): string {
+    const typeMap: Record<string, string> = {
+      'sick': '病假',
+      'personal': '事假',
+      'annual': '年假',
+      'other': '其他'
+    };
+    return typeMap[leaveType || ''] || '请假';
+  }
+
+  // 生成请假覆盖层数据
+  private generateLeaveOverlayData(categories: string[], xMin: number, xMax: number): any[] {
+    const DAY = 24 * 60 * 60 * 1000;
+    const overlayData: any[] = [];
+
+    categories.forEach((employeeName, yIndex) => {
+      // 获取该员工在时间范围内的请假记录
+      const employeeLeaves = this.leaveRecords.filter(record => {
+        if (record.employeeName !== employeeName || !record.isLeave) {
+          return false;
+        }
+        
+        const recordDate = new Date(record.date).getTime();
+        return recordDate >= xMin && recordDate <= xMax;
+      });
+
+      // 为每个请假日期创建覆盖层
+      employeeLeaves.forEach(leave => {
+        const leaveDate = new Date(leave.date);
+        const startOfDay = new Date(leaveDate.getFullYear(), leaveDate.getMonth(), leaveDate.getDate()).getTime();
+        const endOfDay = startOfDay + DAY - 1;
+
+        overlayData.push({
+          name: `${employeeName} - ${this.getLeaveTypeText(leave.leaveType)}`,
+          value: [yIndex, startOfDay, endOfDay, employeeName, leave.leaveType, leave.reason],
+          itemStyle: { 
+            color: 'rgba(239, 68, 68, 0.6)', // 半透明红色
+            borderColor: '#ef4444',
+            borderWidth: 1
+          }
+        });
+      });
+
+      // 检查项目繁忙情况,如果项目数>=3,也添加红色标记
+      const employeeProjects = this.filteredProjects.filter(p => p.designerName === employeeName);
+      if (employeeProjects.length >= 3) {
+        // 在当前日期添加繁忙标记
+        const today = new Date();
+        const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
+        const endOfToday = startOfToday + DAY - 1;
+
+        if (startOfToday >= xMin && startOfToday <= xMax) {
+          overlayData.push({
+            name: `${employeeName} - 项目繁忙(${employeeProjects.length}个项目)`,
+            value: [yIndex, startOfToday, endOfToday, employeeName, 'busy', `负责${employeeProjects.length}个项目`],
+            itemStyle: { 
+              color: 'rgba(239, 68, 68, 0.4)', // 稍微透明的红色
+              borderColor: '#ef4444',
+              borderWidth: 1,
+              borderType: 'dashed' // 虚线边框区分请假和繁忙
+            }
+          });
+        }
+      }
+    });
+
+    return overlayData;
+  }
 }

+ 230 - 0
src/app/shared/components/consultation-order-panel/consultation-order-panel.component.html

@@ -0,0 +1,230 @@
+<div class="consultation-order-panel">
+  <!-- 面板头部 -->
+  <div class="panel-header">
+    <h1 class="panel-title">创建咨询订单</h1>
+    <p class="panel-subtitle">填写客户信息和项目需求</p>
+  </div>
+
+  <!-- 可滚动内容区域 -->
+  <div class="panel-content">
+    <!-- 客户信息栏 -->
+    <section class="customer-info-section">
+      <h2 class="section-title">客户信息</h2>
+      
+      @if (!selectedCustomer) {
+        <!-- 客户搜索 -->
+        <div class="search-container">
+          <input 
+            type="text" 
+            [(ngModel)]="searchKeyword" 
+            (ngModelChange)="searchCustomer()"
+            placeholder="输入客户姓名或手机号搜索..."
+            class="search-input"
+            autocomplete="off"
+          />
+          <button class="search-btn" (click)="searchCustomer()">搜索</button>
+        </div>
+        
+        <!-- 搜索结果 -->
+        @if (searchResults.length > 0) {
+          <div class="search-results">
+            @for (customer of searchResults; track customer.id) {
+              <div class="result-item" (click)="selectCustomer(customer)">
+                <div class="customer-name">{{ customer.name }}</div>
+                <div class="customer-info">{{ customer.phone }}</div>
+              </div>
+            }
+          </div>
+        }
+      } @else {
+        <!-- 已选择客户 -->
+        <div class="selected-customer">
+          <div class="customer-details">
+            <div class="customer-name">{{ selectedCustomer.name }}</div>
+            <div class="customer-phone">{{ selectedCustomer.phone }}</div>
+          </div>
+          <button class="clear-btn" (click)="clearSelectedCustomer()">重新选择</button>
+        </div>
+      }
+    </section>
+
+    <!-- 新客户表单 -->
+    @if (!selectedCustomer) {
+      <section class="new-customer-form">
+        <h3 class="form-title">新客户信息</h3>
+        <form [formGroup]="customerForm">
+          <div class="form-row">
+            <div class="form-group">
+              <label for="name">客户姓名 *</label>
+              <input type="text" id="name" formControlName="name" placeholder="请输入客户姓名">
+            </div>
+            <div class="form-group">
+              <label for="phone">手机号码 *</label>
+              <input type="tel" id="phone" formControlName="phone" placeholder="请输入手机号码">
+            </div>
+          </div>
+          <div class="form-row">
+            <div class="form-group">
+              <label for="wechat">微信号</label>
+              <input type="text" id="wechat" formControlName="wechat" placeholder="请输入微信号(选填)">
+            </div>
+            <div class="form-group">
+              <label for="customerType">客户类型</label>
+              <select id="customerType" formControlName="customerType">
+                <option value="">请选择客户类型</option>
+                <option value="新客户">新客户</option>
+                <option value="老客户">老客户</option>
+                <option value="转介绍">转介绍</option>
+              </select>
+            </div>
+          </div>
+        </form>
+      </section>
+    }
+
+    <!-- 项目需求卡片 -->
+    <section class="requirements-card">
+      <div class="card-header" (click)="isRequirementCardExpanded = !isRequirementCardExpanded">
+        <h3 class="card-title">项目需求</h3>
+        <span class="toggle-icon" [class.expanded]="isRequirementCardExpanded">▼</span>
+      </div>
+      
+      @if (isRequirementCardExpanded) {
+        <div class="card-content">
+          <form [formGroup]="requirementForm">
+            <!-- 基本信息 -->
+            <div class="form-row">
+              <div class="form-group">
+                <label for="decorationType">装修类型 *</label>
+                <select id="decorationType" formControlName="decorationType">
+                  <option value="">请选择装修类型</option>
+                  <option value="家装">家装</option>
+                  <option value="工装">工装</option>
+                </select>
+              </div>
+              <div class="form-group">
+                <label for="downPayment">首付款 *</label>
+                <input type="number" id="downPayment" formControlName="downPayment" placeholder="请输入首付款金额">
+              </div>
+            </div>
+            
+            <div class="form-row">
+              <div class="form-group">
+                <label for="firstDraftDate">首稿时间 *</label>
+                <input type="date" id="firstDraftDate" formControlName="firstDraftDate">
+              </div>
+              <div class="form-group">
+                <label for="style">装修风格</label>
+                <select id="style" formControlName="style">
+                  <option value="">请选择装修风格</option>
+                  @for (style of styleOptions; track style) {
+                    <option [value]="style">{{ style }}</option>
+                  }
+                </select>
+              </div>
+            </div>
+
+            <!-- 详细需求 -->
+            <div class="form-row">
+              <div class="form-group">
+                <label for="spaceRequirements">涉及空间</label>
+                <textarea 
+                  id="spaceRequirements" 
+                  formControlName="spaceRequirements" 
+                  rows="3" 
+                  placeholder="请描述涉及的空间,如:客厅、卧室、厨房等"
+                ></textarea>
+              </div>
+            </div>
+
+            <div class="form-row">
+              <div class="form-group">
+                <label for="designAngles">设计角度</label>
+                <textarea 
+                  id="designAngles" 
+                  formControlName="designAngles" 
+                  rows="3" 
+                  placeholder="请明确各个空间的展示角度"
+                ></textarea>
+              </div>
+            </div>
+
+            <div class="form-row">
+              <div class="form-group">
+                <label for="specialAreaHandling">特殊区域处理</label>
+                <textarea 
+                  id="specialAreaHandling" 
+                  formControlName="specialAreaHandling" 
+                  rows="3" 
+                  placeholder="请描述特殊区域的处理要求"
+                ></textarea>
+              </div>
+            </div>
+
+            <div class="form-row">
+              <div class="form-group">
+                <label for="materialRequirements">材质要求</label>
+                <textarea 
+                  id="materialRequirements" 
+                  formControlName="materialRequirements" 
+                  rows="3" 
+                  placeholder="请描述具体的材质要求"
+                ></textarea>
+              </div>
+            </div>
+
+            <div class="form-row">
+              <div class="form-group">
+                <label for="lightingRequirements">灯光要求</label>
+                <textarea 
+                  id="lightingRequirements" 
+                  formControlName="lightingRequirements" 
+                  rows="3" 
+                  placeholder="请描述灯光设计要求"
+                ></textarea>
+              </div>
+            </div>
+
+            <!-- 偏好标签 -->
+            <div class="tags-section">
+              <h4 class="tags-title">偏好标签</h4>
+              <div class="tags-container">
+                @for (tag of preferenceTags; track tag) {
+                  <span class="tag">
+                    {{ tag }}
+                    <button type="button" class="remove-tag" (click)="removePreferenceTag(tag)">×</button>
+                  </span>
+                }
+              </div>
+              <div class="tag-input-container">
+                <input 
+                  type="text" 
+                  [(ngModel)]="newTag" 
+                  placeholder="添加偏好标签"
+                  class="tag-input"
+                  (keyup.enter)="addPreferenceTag(newTag)"
+                />
+                <button type="button" class="add-tag-btn" (click)="addPreferenceTag(newTag)">添加</button>
+              </div>
+            </div>
+          </form>
+        </div>
+      }
+    </section>
+  </div>
+
+  <!-- 底部提交区域 -->
+  <div class="panel-footer">
+    <button 
+      class="submit-btn" 
+      (click)="submitForm()"
+      [disabled]="isSubmitting || !customerForm.valid || !requirementForm.valid"
+    >
+      @if (isSubmitting) {
+        提交中...
+      } @else {
+        创建项目
+      }
+    </button>
+  </div>
+</div>

+ 566 - 0
src/app/shared/components/consultation-order-panel/consultation-order-panel.component.scss

@@ -0,0 +1,566 @@
+// iOS风格变量定义
+$ios-primary: #007AFF;
+$ios-primary-dark: #0062CC;
+$ios-secondary: #34C759;
+$ios-success: #34C759;
+$ios-warning: #FF9500;
+$ios-danger: #FF3B30;
+$ios-text-primary: #000000;
+$ios-text-secondary: #3C3C43;
+$ios-text-tertiary: #8E8E93;
+$ios-border: #D1D1D6;
+$ios-background: #FFFFFF;
+$ios-background-secondary: #F2F2F7;
+$ios-background-tertiary: #E5E5EA;
+$ios-shadow-sm: 0 1px 3px rgba(0,0,0,0.1);
+$ios-shadow-md: 0 4px 10px rgba(0,0,0,0.1);
+$ios-shadow-lg: 0 10px 30px rgba(0,0,0,0.1);
+$ios-radius: 10px;
+$ios-radius-lg: 16px;
+$ios-transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+$ios-font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif;
+$ios-spacing-xs: 4px;
+$ios-spacing-sm: 8px;
+$ios-spacing-md: 16px;
+$ios-spacing-lg: 24px;
+$ios-spacing-xl: 32px;
+
+// 咨询订单面板样式 - 适配固定区域
+.consultation-order-panel {
+  background: $ios-background;
+  border-radius: $ios-radius-lg;
+  box-shadow: $ios-shadow-md;
+  height: 100%;
+  max-height: 600px;
+  display: flex;
+  flex-direction: column;
+  font-family: $ios-font-family;
+  border: 1px solid $ios-border;
+  overflow: hidden;
+
+  // 面板头部
+  .panel-header {
+    padding: $ios-spacing-md $ios-spacing-lg;
+    background: linear-gradient(135deg, $ios-background 0%, $ios-background-secondary 100%);
+    border-bottom: 1px solid $ios-border;
+    flex-shrink: 0;
+
+    .panel-title {
+      font-size: 18px;
+      font-weight: 600;
+      color: $ios-text-primary;
+      margin: 0;
+    }
+
+    .panel-subtitle {
+      font-size: 14px;
+      color: $ios-text-secondary;
+      margin: 4px 0 0 0;
+    }
+  }
+
+  // 可滚动内容区域
+  .panel-content {
+    flex: 1;
+    overflow-y: auto;
+    padding: $ios-spacing-md $ios-spacing-lg;
+    
+    // iOS风格滚动条
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+    
+    &::-webkit-scrollbar-track {
+      background: $ios-background-secondary;
+      border-radius: 3px;
+    }
+    
+    &::-webkit-scrollbar-thumb {
+      background: $ios-text-tertiary;
+      border-radius: 3px;
+      
+      &:hover {
+        background: $ios-text-secondary;
+      }
+    }
+  }
+
+  // 客户信息栏
+  .customer-info-section {
+    margin-bottom: $ios-spacing-lg;
+    padding: $ios-spacing-md;
+    background: $ios-background-secondary;
+    border-radius: $ios-radius;
+    border: 1px solid $ios-border;
+
+    .section-title {
+      font-size: 16px;
+      font-weight: 600;
+      color: $ios-text-primary;
+      margin-bottom: $ios-spacing-md;
+    }
+
+    .search-container {
+      display: flex;
+      align-items: center;
+      gap: $ios-spacing-sm;
+      margin-bottom: $ios-spacing-sm;
+
+      .search-input {
+        flex: 1;
+        padding: 12px $ios-spacing-md;
+        border: 2px solid $ios-border;
+        border-radius: $ios-radius;
+        font-size: 16px;
+        background: $ios-background;
+        transition: $ios-transition;
+
+        &:focus {
+          outline: none;
+          border-color: $ios-primary;
+          box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1);
+        }
+
+        &::placeholder {
+          color: $ios-text-tertiary;
+        }
+      }
+
+      .search-btn {
+        padding: 12px $ios-spacing-md;
+        background: $ios-primary;
+        color: $ios-background;
+        border: none;
+        border-radius: $ios-radius;
+        cursor: pointer;
+        font-size: 16px;
+        font-weight: 500;
+        transition: $ios-transition;
+
+        &:hover {
+          background: $ios-primary-dark;
+          transform: translateY(-1px);
+        }
+
+        &:active {
+          transform: translateY(0);
+        }
+      }
+    }
+
+    .search-results {
+      max-height: 200px;
+      overflow-y: auto;
+      border: 1px solid $ios-border;
+      border-radius: $ios-radius;
+      background: $ios-background;
+      margin-top: $ios-spacing-sm;
+
+      .result-item {
+        padding: $ios-spacing-md;
+        cursor: pointer;
+        border-bottom: 1px solid $ios-border;
+        transition: $ios-transition;
+
+        &:hover {
+          background: $ios-background-secondary;
+        }
+
+        &:last-child {
+          border-bottom: none;
+        }
+
+        .customer-name {
+          font-weight: 500;
+          color: $ios-text-primary;
+        }
+
+        .customer-info {
+          font-size: 14px;
+          color: $ios-text-secondary;
+          margin-top: 2px;
+        }
+      }
+    }
+
+    .selected-customer {
+      padding: $ios-spacing-md;
+      background: rgba($ios-primary, 0.1);
+      border-radius: $ios-radius;
+      border: 1px solid rgba($ios-primary, 0.2);
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: $ios-spacing-sm;
+
+      .customer-details {
+        .customer-name {
+          font-weight: 600;
+          color: $ios-text-primary;
+        }
+
+        .customer-phone {
+          font-size: 14px;
+          color: $ios-text-secondary;
+          margin-top: 2px;
+        }
+      }
+
+      .clear-btn {
+        background: $ios-danger;
+        color: $ios-background;
+        border: none;
+        border-radius: 6px;
+        padding: 6px 12px;
+        cursor: pointer;
+        font-size: 14px;
+        font-weight: 500;
+        transition: $ios-transition;
+
+        &:hover {
+          background: darken($ios-danger, 10%);
+          transform: translateY(-1px);
+        }
+      }
+    }
+  }
+
+  // 新客户表单
+  .new-customer-form {
+    margin-bottom: $ios-spacing-lg;
+    padding: $ios-spacing-md;
+    background: $ios-background-secondary;
+    border-radius: $ios-radius;
+    border: 1px solid $ios-border;
+
+    .form-title {
+      font-size: 16px;
+      font-weight: 600;
+      margin-bottom: $ios-spacing-md;
+      color: $ios-text-primary;
+    }
+
+    .form-row {
+      display: flex;
+      gap: $ios-spacing-md;
+      margin-bottom: $ios-spacing-md;
+
+      @media (max-width: 768px) {
+        flex-direction: column;
+        gap: $ios-spacing-sm;
+      }
+
+      .form-group {
+        flex: 1;
+
+        label {
+          display: block;
+          margin-bottom: $ios-spacing-xs;
+          font-size: 14px;
+          font-weight: 500;
+          color: $ios-text-primary;
+        }
+
+        input, select, textarea {
+          width: 100%;
+          padding: 12px $ios-spacing-md;
+          border: 2px solid $ios-border;
+          border-radius: $ios-radius;
+          font-size: 16px;
+          background: $ios-background;
+          transition: $ios-transition;
+          box-sizing: border-box;
+
+          &:focus {
+            outline: none;
+            border-color: $ios-primary;
+            box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1);
+          }
+
+          &::placeholder {
+            color: $ios-text-tertiary;
+          }
+        }
+
+        textarea {
+          resize: vertical;
+          min-height: 80px;
+          font-family: $ios-font-family;
+        }
+
+        select {
+          cursor: pointer;
+        }
+      }
+    }
+  }
+
+  // 项目需求卡片
+  .requirements-card {
+    background: $ios-background;
+    border: 1px solid $ios-border;
+    border-radius: $ios-radius;
+    margin-bottom: $ios-spacing-md;
+    overflow: hidden;
+
+    .card-header {
+      padding: $ios-spacing-md;
+      background: linear-gradient(135deg, $ios-background-secondary 0%, $ios-background-tertiary 100%);
+      border-bottom: 1px solid $ios-border;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      cursor: pointer;
+      transition: $ios-transition;
+
+      &:hover {
+        background: linear-gradient(135deg, $ios-background-tertiary 0%, $ios-border 100%);
+      }
+
+      .card-title {
+        font-size: 16px;
+        font-weight: 600;
+        color: $ios-text-primary;
+      }
+
+      .toggle-icon {
+        color: $ios-text-secondary;
+        transition: transform 0.3s ease;
+        font-size: 18px;
+
+        &.expanded {
+          transform: rotate(180deg);
+        }
+      }
+    }
+
+    .card-content {
+      padding: $ios-spacing-md;
+      max-height: 500px;
+      overflow-y: auto;
+
+      // iOS风格滚动条
+      &::-webkit-scrollbar {
+        width: 6px;
+      }
+      
+      &::-webkit-scrollbar-track {
+        background: $ios-background-secondary;
+        border-radius: 3px;
+      }
+      
+      &::-webkit-scrollbar-thumb {
+        background: $ios-text-tertiary;
+        border-radius: 3px;
+        
+        &:hover {
+          background: $ios-text-secondary;
+        }
+      }
+
+      .form-row {
+        display: flex;
+        gap: $ios-spacing-md;
+        margin-bottom: $ios-spacing-md;
+
+        @media (max-width: 768px) {
+          flex-direction: column;
+          gap: $ios-spacing-sm;
+        }
+
+        .form-group {
+          flex: 1;
+
+          label {
+            display: block;
+            margin-bottom: $ios-spacing-xs;
+            font-size: 14px;
+            font-weight: 500;
+            color: $ios-text-primary;
+          }
+
+          input, select, textarea {
+            width: 100%;
+            padding: 12px $ios-spacing-md;
+            border: 2px solid $ios-border;
+            border-radius: $ios-radius;
+            font-size: 16px;
+            background: $ios-background;
+            transition: $ios-transition;
+            box-sizing: border-box;
+
+            &:focus {
+              outline: none;
+              border-color: $ios-primary;
+              box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1);
+            }
+
+            &::placeholder {
+              color: $ios-text-tertiary;
+            }
+          }
+
+          select {
+            cursor: pointer;
+          }
+        }
+      }
+
+      .tags-section {
+        margin-top: $ios-spacing-md;
+
+        .tags-title {
+          font-size: 14px;
+          font-weight: 600;
+          margin-bottom: $ios-spacing-sm;
+          color: $ios-text-primary;
+        }
+
+        .tags-container {
+          display: flex;
+          flex-wrap: wrap;
+          gap: $ios-spacing-sm;
+          margin-bottom: $ios-spacing-md;
+
+          .tag {
+            padding: 6px 12px;
+            background: rgba($ios-primary, 0.1);
+            border: 1px solid rgba($ios-primary, 0.2);
+            border-radius: 20px;
+            font-size: 14px;
+            color: $ios-primary;
+            display: flex;
+            align-items: center;
+            gap: $ios-spacing-xs;
+            transition: $ios-transition;
+
+            &:hover {
+              background: rgba($ios-primary, 0.15);
+            }
+
+            .remove-tag {
+              background: none;
+              border: none;
+              color: $ios-primary;
+              cursor: pointer;
+              font-size: 16px;
+              padding: 0;
+              width: 18px;
+              height: 18px;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+              border-radius: 50%;
+              transition: $ios-transition;
+
+              &:hover {
+                background: rgba($ios-danger, 0.1);
+                color: $ios-danger;
+              }
+            }
+          }
+        }
+
+        .tag-input-container {
+          display: flex;
+          gap: $ios-spacing-sm;
+
+          .tag-input {
+            flex: 1;
+            padding: 10px $ios-spacing-md;
+            border: 2px solid $ios-border;
+            border-radius: $ios-radius;
+            font-size: 14px;
+            background: $ios-background;
+            transition: $ios-transition;
+
+            &:focus {
+              outline: none;
+              border-color: $ios-primary;
+              box-shadow: 0 0 0 4px rgba(0, 122, 255, 0.1);
+            }
+
+            &::placeholder {
+              color: $ios-text-tertiary;
+            }
+          }
+
+          .add-tag-btn {
+            padding: 10px $ios-spacing-md;
+            background: $ios-secondary;
+            color: $ios-background;
+            border: none;
+            border-radius: $ios-radius;
+            cursor: pointer;
+            font-size: 14px;
+            font-weight: 500;
+            transition: $ios-transition;
+
+            &:hover {
+              background: darken($ios-secondary, 10%);
+              transform: translateY(-1px);
+            }
+
+            &:active {
+              transform: translateY(0);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // 底部提交区域
+  .panel-footer {
+    padding: $ios-spacing-md $ios-spacing-lg;
+    background: $ios-background-secondary;
+    border-top: 1px solid $ios-border;
+    flex-shrink: 0;
+
+    .submit-btn {
+      width: 100%;
+      padding: $ios-spacing-md;
+      background: linear-gradient(135deg, $ios-primary 0%, $ios-primary-dark 100%);
+      color: $ios-background;
+      border: none;
+      border-radius: $ios-radius;
+      font-size: 16px;
+      font-weight: 600;
+      cursor: pointer;
+      transition: $ios-transition;
+      box-shadow: $ios-shadow-sm;
+
+      &:hover {
+        transform: translateY(-2px);
+        box-shadow: $ios-shadow-md;
+      }
+
+      &:active {
+        transform: translateY(0);
+        box-shadow: $ios-shadow-sm;
+      }
+
+      &:disabled {
+        background: $ios-text-tertiary;
+        cursor: not-allowed;
+        transform: none;
+        box-shadow: none;
+      }
+    }
+  }
+
+  // 响应式设计
+  @media (max-width: 768px) {
+    .panel-header {
+      padding: $ios-spacing-md;
+    }
+
+    .panel-content {
+      padding: $ios-spacing-md;
+    }
+
+    .panel-footer {
+      padding: $ios-spacing-md;
+    }
+  }
+}

+ 207 - 0
src/app/shared/components/consultation-order-panel/consultation-order-panel.component.ts

@@ -0,0 +1,207 @@
+import { Component, EventEmitter, Output } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { MatChipsModule } from '@angular/material/chips';
+import { MatIconModule } from '@angular/material/icon';
+
+// 定义客户信息接口
+interface Customer {
+  id: string;
+  name: string;
+  phone: string;
+  wechat?: string;
+  avatar?: string;
+  customerType?: string;
+  source?: string;
+  remark?: string;
+  demandType?: string;
+  preferenceTags?: string[];
+  followUpStatus?: string;
+}
+
+@Component({
+  selector: 'app-consultation-order-panel',
+  standalone: true,
+  imports: [
+    CommonModule,
+    FormsModule,
+    ReactiveFormsModule,
+    MatChipsModule,
+    MatIconModule
+  ],
+  templateUrl: './consultation-order-panel.component.html',
+  styleUrls: ['./consultation-order-panel.component.scss']
+})
+export class ConsultationOrderPanelComponent {
+  @Output() orderCreated = new EventEmitter<any>();
+
+  // 搜索客户关键词
+  searchKeyword = '';
+  // 搜索结果列表
+  searchResults: Customer[] = [];
+  // 选中的客户
+  selectedCustomer: Customer | null = null;
+  // 表单提交状态
+  isSubmitting = false;
+  // 项目需求卡片展开状态
+  isRequirementCardExpanded = false;
+
+  // 需求表单
+  requirementForm: FormGroup;
+  // 客户表单
+  customerForm: FormGroup;
+
+  // 样式选项
+  styleOptions = [
+    '现代简约', '北欧风', '工业风', '新中式', '法式轻奢', '日式', '美式', '混搭'
+  ];
+
+  // 项目小组选项
+  projectGroupOptions = [
+    '设计一组', '设计二组', '设计三组', '高端定制组', '软装设计组'
+  ];
+
+  // 偏好标签选项
+  preferenceTagOptions = [
+    '柔和色系', '明亮色系', '深色系', '中性色系',
+    '环保材料', '实木', '大理石', '瓷砖', '地板', '墙纸',
+    '现代简约', '北欧风格', '中式风格', '美式风格', '工业风',
+    '智能家电', '收纳空间', '开放式厨房', '大窗户'
+  ];
+
+  preferenceTags: string[] = [];
+  // 新标签输入
+  newTag = '';
+
+  constructor(private fb: FormBuilder) {
+    // 初始化需求表单
+    this.requirementForm = this.fb.group({
+      decorationType: ['', Validators.required],
+      downPayment: ['', [Validators.required, Validators.min(0)]],
+      firstDraftDate: ['', Validators.required],
+      style: [''],
+      projectGroup: [''],
+      budget: ['', Validators.required],
+      area: ['', [Validators.required, Validators.min(1)]],
+      houseType: [''],
+      floor: ['', Validators.min(1)],
+      preferredDesigner: [''],
+      specialRequirements: [''],
+      referenceCases: [[]],
+      priceDetails: [''],
+      // 新增字段
+      spaceRequirements: [''],
+      designAngles: [''],
+      specialAreaHandling: [''],
+      materialRequirements: [''],
+      lightingRequirements: ['']
+    });
+
+    // 初始化客户表单
+    this.customerForm = this.fb.group({
+      name: ['', Validators.required],
+      phone: ['', [Validators.required, Validators.pattern(/^1[3-9]\d{9}$/)]],
+      wechat: [''],
+      customerType: ['新客户'],
+      source: [''],
+      remark: [''],
+      demandType: [''],
+      followUpStatus: ['']
+    });
+  }
+
+  // 搜索客户
+  searchCustomer() {
+    if (this.searchKeyword.length >= 2) {
+      // 模拟搜索结果
+      this.searchResults = [
+        {
+          id: '1',
+          name: '张先生',
+          phone: '138****5678',
+          customerType: '老客户',
+          source: '官网咨询',
+          avatar: "data:image/svg+xml,%3Csvg width='64' height='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23E6E6E6'/%3E%3Ctext x='50%25' y='50%25' font-family='Arial' font-size='13.333333333333334' font-weight='bold' text-anchor='middle' fill='%23555555' dy='0.3em'%3EIMG%3C/text%3E%3C/svg%3E"
+        },
+        {
+          id: '2',
+          name: '李女士',
+          phone: '139****1234',
+          customerType: 'VIP客户',
+          source: '推荐介绍',
+          avatar: "data:image/svg+xml,%3Csvg width='65' height='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='%23DCDCDC'/%3E%3Ctext x='50%25' y='50%25' font-family='Arial' font-size='13.333333333333334' font-weight='bold' text-anchor='middle' fill='%23555555' dy='0.3em'%3EIMG%3C/text%3E%3C/svg%3E"
+        }
+      ];
+    }
+  }
+
+  // 选择客户
+  selectCustomer(customer: Customer) {
+    this.selectedCustomer = customer;
+    // 填充客户表单
+    this.customerForm.patchValue({
+      name: customer.name,
+      phone: customer.phone,
+      wechat: customer.wechat || '',
+      customerType: customer.customerType || '新客户',
+      source: customer.source || '',
+      remark: customer.remark || ''
+    });
+    
+    // 清空搜索结果
+    this.searchResults = [];
+    this.searchKeyword = '';
+  }
+
+  // 清除选中的客户
+  clearSelectedCustomer() {
+    this.selectedCustomer = null;
+    this.customerForm.reset({
+      customerType: '新客户'
+    });
+  }
+
+  // 添加偏好标签
+  addPreferenceTag(tag: string): void {
+    if (tag && !this.preferenceTags.includes(tag)) {
+      this.preferenceTags.push(tag);
+      this.newTag = ''; // 清空输入框
+    }
+  }
+
+  // 删除偏好标签
+  removePreferenceTag(tag: string): void {
+    const index = this.preferenceTags.indexOf(tag);
+    if (index >= 0) {
+      this.preferenceTags.splice(index, 1);
+    }
+  }
+
+  // 提交表单
+  submitForm() {
+    if (this.customerForm.valid && this.requirementForm.valid) {
+      this.isSubmitting = true;
+      
+      const formData = {
+        customerInfo: this.customerForm.value,
+        requirementInfo: this.requirementForm.value,
+        preferenceTags: this.preferenceTags,
+        createdAt: new Date()
+      };
+
+      // 模拟提交请求
+      setTimeout(() => {
+        this.isSubmitting = false;
+        this.orderCreated.emit(formData);
+        
+        // 重置表单
+        this.customerForm.reset({
+          customerType: '新客户'
+        });
+        this.requirementForm.reset();
+        this.preferenceTags = [];
+        this.selectedCustomer = null;
+      }, 1000);
+    }
+  }
+}