Răsfoiți Sursa

feet:customer15

徐福静0235668 1 zi în urmă
părinte
comite
897684ca1f

+ 22 - 0
src/app/models/project.model.ts

@@ -1,10 +1,32 @@
+// 需求项目接口
+export interface RequirementItem {
+  id: string;
+  description: string;
+  status: string;
+  priority: 'high' | 'medium' | 'low';
+}
+
+// 客户信息接口
+export interface CustomerInfo {
+  colorPreference?: string;
+  spaceRequirements?: string;
+  materialPreference?: string;
+}
+
 // 项目模型
 export interface Project {
   id: string;
   name: string;
   customerName: string;
+  customerPhone?: string;
+  customerWechat?: string;
+  customerType?: string;
+  customerSource?: string;
+  customerRemark?: string;
+  customerInfo?: CustomerInfo;
   customerTags: CustomerTag[];
   highPriorityNeeds: string[];
+  requirements?: RequirementItem[];
   status: ProjectStatus;
   currentStage: ProjectStage;
   stage: ProjectStage; // 添加stage属性,与currentStage保持一致

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

@@ -270,7 +270,7 @@
         <button 
           class="btn-primary btn-lg" 
           (click)="submitForm()"
-          [disabled]="isSubmitting() || !customerForm.valid"
+          [disabled]="isSubmitting() || !minimalReady()"
         >
           @if (!isSubmitting()) {
             <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">

+ 11 - 13
src/app/pages/customer-service/consultation-order/consultation-order.ts

@@ -386,40 +386,35 @@ export class ConsultationOrder {
 
   // 提交表单
   submitForm() {
-    if (this.customerForm.valid) {
+    // 使用最小必填项判断,解决选择老客户时被掩码手机号导致整体表单无效的问题
+    if (this.minimalReady()) {
       this.isSubmitting.set(true);
-      
       const formData = {
         customerInfo: this.customerForm.value,
         requirementInfo: this.requirementForm.value,
         estimatedPriceRange: this.estimatedPriceRange(),
-        createdAt: new Date()
+        createdAt: new Date(),
+        roleContext: 'customer-service'
       };
-
-      // 模拟提交请求
       setTimeout(() => {
         console.log('提交的表单数据:', formData);
         this.isSubmitting.set(false);
         this.showSuccessMessage.set(true);
-        
-        // 1秒后隐藏成功提示并跳转
         setTimeout(() => {
           this.showSuccessMessage.set(false);
-          
-          // 发出订单创建成功事件,用于关闭弹窗
           const orderData = {
             orderId: 'mock-9',
             customerName: formData.customerInfo.name,
             projectId: 'mock-9'
           };
           this.orderCreated.emit(orderData);
-          
-          // 跳转到设计师项目详情页面,传递客服角色标识
           this.router.navigate(['/designer/project-detail/mock-9'], { 
-            queryParams: { role: 'customer-service' } 
+            queryParams: { role: 'customer-service', activeTab: 'progress' } 
           });
         }, 1000);
       }, 1500);
+    } else {
+      this.snackBar.open('请先填写姓名、手机、风格、项目组、首付款、首稿时间等必填信息', '关闭', { duration: 2500 });
     }
   }
 
@@ -432,8 +427,11 @@ export class ConsultationOrder {
     const downPaymentCtrl = this.requirementForm.get('downPayment');
     const firstDraftDateCtrl = this.requirementForm.get('firstDraftDate');
 
+    const isExisting = !!this.selectedCustomer();
+    const phoneVal = String(phoneCtrl?.value ?? '');
     const nameOk = !!nameCtrl?.value && nameCtrl.valid;
-    const phoneOk = !!phoneCtrl?.value && phoneCtrl.valid;
+    // 若选择了老客户(或VIP),允许使用掩码手机号通过最小必填判断;新客户仍需严格校验
+    const phoneOk = isExisting ? !!phoneVal : (!!phoneCtrl?.value && phoneCtrl.valid);
     const styleOk = !!styleCtrl?.value;
     const groupOk = !!groupCtrl?.value;
     const downPaymentOk = downPaymentCtrl != null && downPaymentCtrl.valid && downPaymentCtrl.value !== null && downPaymentCtrl.value !== '';

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

@@ -475,6 +475,11 @@ $transition: all 0.3s ease;
             color: $success-color;
             background-color: #e8f5e9;
           }
+
+          .stage-active {
+            color: $danger-color;
+            background-color: #ffebee;
+          }
         }
 
         // 进度部分

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

@@ -385,12 +385,16 @@ export class ProjectList implements OnInit, OnDestroy {
 
   getStageClass(stage: string): string {
     switch (stage) {
-      case '需求沟通': return 'stage-requirement';
+      case '需求沟通': return 'stage-communication';
       case '建模': return 'stage-modeling';
-      case '软装': return 'stage-soft';
-      case '渲染': return 'stage-render';
-      case '后期': return 'stage-post';
-      case '投诉处理': return 'stage-issue';
+      case '软装': return 'stage-decoration';
+      case '渲染': return 'stage-rendering';
+      case '后期': return 'stage-postproduction';
+      case '投诉处理': return 'stage-completed';
+      case '订单创建': return 'stage-active';
+      case '方案确认': return 'stage-active';
+      case '尾款结算': return 'stage-completed';
+      case '客户评价': return 'stage-completed';
       default: return '';
     }
   }
@@ -437,10 +441,22 @@ export class ProjectList implements OnInit, OnDestroy {
     return 'req';
   }
 
-  // 详情跳转到设计师项目详情页面,传递客服角色标识
+  // 详情跳转到设计师项目详情页面,传递客服角色标识和当前阶段信息
   navigateToProject(project: ProjectListItem, columnId: 'pending' | 'req' | 'delivery' | 'done') {
+    // 根据columnId映射到对应的阶段
+    const stageMapping = {
+      'pending': '订单创建',
+      'req': project.currentStage || '需求沟通', // 使用项目实际阶段或默认阶段
+      'delivery': project.currentStage || '建模', // 使用项目实际阶段或默认阶段
+      'done': '客户评价'
+    };
+    
     this.router.navigate(['/designer/project-detail', project.id], { 
-      queryParams: { role: 'customer-service' } 
+      queryParams: { 
+        role: 'customer-service',
+        activeTab: 'progress',
+        currentStage: stageMapping[columnId]
+      } 
     });
   }
 

+ 74 - 13
src/app/pages/designer/project-detail/debug-styles.scss

@@ -302,7 +302,7 @@
 }
 .section-btn:hover { transform: translateY(-1px); box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
 .section-btn.completed { background: #e6f7e6; color: $ios-success; border-color: rgba(0,0,0,0.06); }
-.section-btn.active { background: #e8f0fe; color: $ios-primary; border-color: $ios-primary; }
+.section-btn.active { background: #fff2f0; color: #ff4d4f; border-color: #ff4d4f; }
 .section-btn.pending { background: $ios-background; color: $ios-text-secondary; }
 
 .sections-content { margin-top: $ios-spacing-md; }
@@ -417,6 +417,67 @@
   color: $ios-primary !important; /* 标题与强调条呼应 */
 }
 
+/* 客户信息卡片头部和同步状态 */
+.left-column .project-info-card .card-header {
+  display: flex !important;
+  justify-content: space-between !important;
+  align-items: center !important;
+  margin-bottom: 16px !important;
+  padding-bottom: 12px !important;
+  border-bottom: 1px solid #f0f0f0 !important;
+}
+
+.left-column .project-info-card .card-header h2 {
+  margin: 0 !important;
+  font-size: 18px !important;
+  font-weight: 600 !important;
+  color: #262626 !important;
+}
+
+.left-column .project-info-card .sync-status {
+  display: flex !important;
+  align-items: center !important;
+  font-size: 12px !important;
+  color: #8c8c8c !important;
+}
+
+.left-column .project-info-card .sync-status.syncing {
+  color: #1890ff !important;
+}
+
+.left-column .project-info-card .sync-indicator {
+  display: flex !important;
+  align-items: center !important;
+  gap: 4px !important;
+}
+
+.left-column .project-info-card .sync-spinner {
+  width: 12px !important;
+  height: 12px !important;
+  border: 2px solid #f0f0f0 !important;
+  border-top: 2px solid #1890ff !important;
+  border-radius: 50% !important;
+  animation: spin 1s linear infinite !important;
+}
+
+.left-column .project-info-card .sync-time {
+  display: flex !important;
+  align-items: center !important;
+  gap: 4px !important;
+}
+
+.left-column .project-info-card .icon-sync {
+  width: 12px !important;
+  height: 12px !important;
+  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%238c8c8c'%3E%3Cpath d='M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z'/%3E%3C/svg%3E") no-repeat center !important;
+  background-size: contain !important;
+}
+
+@keyframes spin {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
+
 /* 活动阶段卡片:浅红底色突显(更显眼版) */
 .delivery-col.active,
 .vertical-stage-block.active {
@@ -550,7 +611,7 @@
 }
 
 .vertical-stage-header .dot.active {
-  background: #007bff !important;
+  background: #ff4d4f !important;
 }
 
 .vertical-stage-body {
@@ -562,17 +623,17 @@
 
 /* 活动阶段卡片优化 */
 .vertical-stage-block.active {
-  background: #fff8f0 !important;
-  border-color: #ffc069 !important;
-  box-shadow: 0 2px 8px rgba(255, 192, 105, 0.2) !important;
+  background: #fff2f0 !important;
+  border-color: #ffccc7 !important;
+  box-shadow: 0 2px 8px rgba(255, 77, 79, 0.2) !important;
 }
 
 .vertical-stage-block.active .vertical-stage-header h3 {
-  color: #d46b08 !important;
+  color: #ff4d4f !important;
 }
 
 .vertical-stage-block.active .dot {
-  background: #fa8c16 !important;
+  background: #ff4d4f !important;
 }
 
 /* 订单创建阶段完成后的绿色高亮 */
@@ -593,19 +654,19 @@
 
 /* 需求沟通阶段激活时的高亮 */
 .vertical-stage-block[id="stage-requirements-talk"].active {
-  background: linear-gradient(135deg, #e6f7ff 0%, #f0f9ff 100%) !important;
-  border-color: #40a9ff !important;
-  box-shadow: 0 4px 16px rgba(64, 169, 255, 0.2) !important;
+  background: linear-gradient(135deg, #fff2f0 0%, #ffe6e6 100%) !important;
+  border-color: #ff7875 !important;
+  box-shadow: 0 4px 16px rgba(255, 77, 79, 0.2) !important;
   transform: translateY(-2px) !important;
   transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) !important;
 }
 
 .vertical-stage-block[id="stage-requirements-talk"].active .vertical-stage-header h3 {
-  color: #1890ff !important;
+  color: #ff4d4f !important;
   font-weight: 700 !important;
 }
 
 .vertical-stage-block[id="stage-requirements-talk"].active .dot {
-  background: #1890ff !important;
-  box-shadow: 0 0 0 4px rgba(24, 144, 255, 0.2) !important;
+  background: #ff4d4f !important;
+  box-shadow: 0 0 0 4px rgba(255, 77, 79, 0.2) !important;
 }

+ 42 - 13
src/app/pages/designer/project-detail/project-detail.html

@@ -86,14 +86,6 @@
       </div>
     </div>
 
-  <!-- 团队分配弹窗 -->
-  @if (showTeamAssignmentModal) {
-    <app-team-assignment-modal
-      [isVisible]="showTeamAssignmentModal"
-      (closeModal)="closeTeamAssignmentModal()"
-      (confirmAssignment)="confirmTeamAssignment($event)">
-    </app-team-assignment-modal>
-  }
 </div>
 
 <!-- 四大板块按钮组 - 位于项目详情标题区域正下方 -->
@@ -166,7 +158,22 @@
           <!-- 左侧保留 -->
           <div class="left-column">
             <div class="project-info-card card">
-              <h2>客户信息</h2>
+              <div class="card-header">
+                <h2>客户信息</h2>
+                <div class="sync-status" [class.syncing]="isSyncingCustomerInfo">
+                  @if (isSyncingCustomerInfo) {
+                    <span class="sync-indicator">
+                      <span class="sync-spinner"></span>
+                      同步中...
+                    </span>
+                  } @else if (lastSyncTime) {
+                    <span class="sync-time">
+                      <i class="icon-sync"></i>
+                      已同步: {{ formatTime(lastSyncTime) }}
+                    </span>
+                  }
+                </div>
+              </div>
               @if (project) {
                 <div class="info-grid">
                   <!-- 显示订单创建时填写的客户信息,如果有的话 -->
@@ -347,7 +354,8 @@
                         <app-requirements-confirm-card 
                           (requirementConfirmed)="syncRequirementKeyInfo($event)"
                           (progressUpdated)="syncRequirementKeyInfo($event)"
-                          (stageCompleted)="onRequirementsStageCompleted($event)">
+                          (stageCompleted)="onRequirementsStageCompleted($event)"
+                          (dataUpdated)="onRequirementDataUpdated($event)">
                         </app-requirements-confirm-card>
                       } @else if (stage === '方案确认') {
                         <!-- 方案确认阶段 - 需求信息展示 -->
@@ -859,11 +867,32 @@
                           </div>
                         </div>
                       } @else if (stage === '尾款结算') {
-                        <app-settlement-card [settlements]="settlements"></app-settlement-card>
+                        <div class="aftercare-section-container">
+                          <app-settlement-card [settlements]="settlements"></app-settlement-card>
+                        </div>
+                        @if (canEditSection('aftercare')) {
+                          <div class="upload-actions">
+                            <button class="primary-btn" (click)="confirmSettlement()">确认尾款结算完成</button>
+                          </div>
+                        }
                       } @else if (stage === '客户评价') {
-                        <app-customer-review-card [feedbacks]="feedbacks"></app-customer-review-card>
+                        <div class="aftercare-section-container">
+                          <app-customer-review-card [feedbacks]="feedbacks"></app-customer-review-card>
+                        </div>
+                        @if (canEditSection('aftercare')) {
+                          <div class="upload-actions">
+                            <button class="primary-btn" (click)="confirmCustomerReview()">确认客户评价完成</button>
+                          </div>
+                        }
                       } @else if (stage === '投诉处理') {
-                        <app-complaint-card [complaints]="exceptionHistories"></app-complaint-card>
+                        <div class="aftercare-section-container">
+                          <app-complaint-card [complaints]="exceptionHistories"></app-complaint-card>
+                        </div>
+                        @if (canEditSection('aftercare')) {
+                          <div class="upload-actions">
+                            <button class="primary-btn" (click)="confirmComplaint()">确认投诉处理完成</button>
+                          </div>
+                        }
                       }
                     </div>
                   </div>

+ 75 - 4
src/app/pages/designer/project-detail/project-detail.scss

@@ -56,10 +56,10 @@
     }
     
     &.active {
-      background: linear-gradient(135deg, #e8f0fe 0%, #cce7ff 100%);
-      color: $ios-primary;
-      border-color: $ios-primary;
-      box-shadow: 0 0.15rem 0.6rem rgba(0, 122, 255, 0.2);
+      background: linear-gradient(135deg, #fff2f0 0%, #ffe6e6 100%);
+      color: #ff4d4f;
+      border-color: #ff4d4f;
+      box-shadow: 0 0.15rem 0.6rem rgba(255, 77, 79, 0.2);
     }
     
     &.pending {
@@ -2221,6 +2221,65 @@
   }
 }
 
+/* 售后板块统一容器样式 */
+.aftercare-section-container {
+  height: 400px; /* 固定高度 */
+  overflow-y: auto; /* 垂直滚动条 */
+  overflow-x: hidden; /* 隐藏水平滚动条 */
+  border: 1px solid $ios-border;
+  border-radius: $ios-radius-md;
+  background: $ios-background;
+  padding: 16px;
+  margin-bottom: 16px;
+  
+  /* 自定义滚动条样式 */
+  &::-webkit-scrollbar {
+    width: 8px;
+  }
+  
+  &::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 4px;
+  }
+  
+  &::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 4px;
+    
+    &:hover {
+      background: #a8a8a8;
+    }
+  }
+  
+  /* Firefox 滚动条样式 */
+  scrollbar-width: thin;
+  scrollbar-color: #c1c1c1 #f1f1f1;
+  
+  /* 确保内容不会被滚动条遮挡 */
+  box-sizing: border-box;
+  
+  /* 内部组件样式重置 */
+  app-settlement-card,
+  app-customer-review-card,
+  app-complaint-card {
+    display: block;
+    width: 100%;
+    height: auto;
+    
+    /* 移除组件自身的边距和边框,避免重复 */
+    ::ng-deep {
+      .settlement-card,
+      .customer-review-card,
+      .complaint-card {
+        border: none;
+        margin: 0;
+        padding: 0;
+        background: transparent;
+      }
+    }
+  }
+}
+
 // 响应式设计优化
 @media (max-width: 768px) {
   .project-detail-container.designer-page {
@@ -2247,6 +2306,12 @@
       }
     }
   }
+  
+  /* 移动端售后板块容器调整 */
+  .aftercare-section-container {
+    height: 300px; /* 移动端降低高度 */
+    padding: 12px;
+  }
 }
 
 @media (max-width: 480px) {
@@ -2263,4 +2328,10 @@
       }
     }
   }
+  
+  /* 小屏幕设备进一步调整 */
+  .aftercare-section-container {
+    height: 250px;
+    padding: 8px;
+  }
 }

+ 328 - 48
src/app/pages/designer/project-detail/project-detail.ts

@@ -17,7 +17,7 @@ import { RequirementsConfirmCardComponent } from '../../../shared/components/req
 import { SettlementCardComponent } from '../../../shared/components/settlement-card/settlement-card';
 import { CustomerReviewCardComponent } from '../../../shared/components/customer-review-card/customer-review-card';
 import { ComplaintCardComponent } from '../../../shared/components/complaint-card/complaint-card';
-import { TeamAssignmentModalComponent } from '../../../shared/components/team-assignment-modal/team-assignment-modal.component';
+
 import { VerticalNavComponent } from './components/vertical-nav/vertical-nav.component';
 
 interface ExceptionHistory {
@@ -62,7 +62,7 @@ type SectionKey = 'order' | 'requirements' | 'delivery' | 'aftercare';
 @Component({
   selector: 'app-project-detail',
   standalone: true,
-  imports: [CommonModule, FormsModule, ReactiveFormsModule, ConsultationOrderPanelComponent, RequirementsConfirmCardComponent, SettlementCardComponent, CustomerReviewCardComponent, ComplaintCardComponent, TeamAssignmentModalComponent, VerticalNavComponent],
+  imports: [CommonModule, FormsModule, ReactiveFormsModule, ConsultationOrderPanelComponent, RequirementsConfirmCardComponent, SettlementCardComponent, CustomerReviewCardComponent, ComplaintCardComponent, VerticalNavComponent],
   templateUrl: './project-detail.html',
   styleUrls: ['./project-detail.scss', './debug-styles.scss']
 })
@@ -141,7 +141,6 @@ export class ProjectDetail implements OnInit, OnDestroy {
   timelineEvents: TimelineEvent[] = [];
 
   // 团队分配弹窗相关
-  showTeamAssignmentModal = false;
   selectedDesigner: any = null;
   projectData: any = null;
 
@@ -206,7 +205,25 @@ export class ProjectDetail implements OnInit, OnDestroy {
 
   // 检查是否处于订单创建阶段,用于红色高亮显示
   isCurrentOrderCreation(): boolean {
-    return this.project?.currentStage === '订单创建';
+    // 只有当订单创建阶段是当前活跃阶段时才标红显示
+    // 修复逻辑:完成前序环节后才标红当前阶段
+    const currentStage = this.project?.currentStage;
+    if (!currentStage) return false;
+    
+    // 如果当前阶段就是订单创建阶段,说明需要标红显示
+    if (currentStage === '订单创建') return true;
+    
+    // 如果当前阶段在订单创建之后,说明订单创建已完成,不应标红
+    const stageOrder = [
+      '订单创建', '需求沟通', '方案确认', '建模', '软装', 
+      '渲染', '后期', '尾款结算', '客户评价', '投诉处理'
+    ];
+    
+    const currentIndex = stageOrder.indexOf(currentStage);
+    const orderCreationIndex = stageOrder.indexOf('订单创建');
+    
+    // 如果当前阶段在订单创建之后,说明订单创建已完成
+    return currentIndex <= orderCreationIndex;
   }
 
   // 返回工作台
@@ -235,7 +252,8 @@ export class ProjectDetail implements OnInit, OnDestroy {
   // 获取阶段状态:completed/active/pending
   getStageStatus(stage: ProjectStage): 'completed' | 'active' | 'pending' {
     const order = this.stageOrder;
-    const current = this.project?.currentStage as ProjectStage | undefined;
+    // 优先使用 currentStage 属性,如果没有则使用 project.currentStage
+    const current = (this.currentStage as ProjectStage) || (this.project?.currentStage as ProjectStage | undefined);
     const currentIdx = current ? order.indexOf(current) : -1;
     const idx = order.indexOf(stage);
     if (idx === -1) return 'pending';
@@ -273,9 +291,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
       this.loadProjectMembers();
       this.loadProjectFiles();
       this.loadTimelineEvents();
+      
+      // 启动客户信息自动同步
+      this.startAutoSync();
     });
 
-    // 新增:监听查询参数,支持通过 activeTab 设置初始标签页
+    // 新增:监听查询参数,支持通过 activeTab 设置初始标签页和 currentStage 设置当前阶段
     this.route.queryParamMap.subscribe(qp => {
       const raw = qp.get('activeTab');
       const alias: Record<string, 'progress' | 'members' | 'files'> = {
@@ -286,6 +307,26 @@ export class ProjectDetail implements OnInit, OnDestroy {
       if (tab === 'progress' || tab === 'members' || tab === 'files') {
         this.activeTab = tab;
       }
+      
+      // 处理 currentStage 查询参数
+      const currentStageParam = qp.get('currentStage');
+      if (currentStageParam) {
+        this.currentStage = currentStageParam;
+        
+        // 根据当前阶段设置项目状态和展开相应区域
+        this.initializeStageFromRoute(currentStageParam as ProjectStage);
+        
+        // 根据当前阶段自动展开对应的区域
+        const sectionKey = this.getSectionKeyForStage(currentStageParam as ProjectStage);
+        if (sectionKey) {
+          this.expandedSection = sectionKey;
+        }
+        
+        // 延迟滚动到对应阶段
+        setTimeout(() => {
+          this.scrollToStage(currentStageParam as ProjectStage);
+        }, 500);
+      }
     });
     
     // 添加点击事件监听器,当点击页面其他位置时关闭下拉菜单
@@ -310,11 +351,40 @@ export class ProjectDetail implements OnInit, OnDestroy {
     });
   }
 
-  // 在组件销毁时移除事件监听器和清理资源
+  // 新增:根据路由参数初始化阶段状态
+  private initializeStageFromRoute(targetStage: ProjectStage): void {
+    // 设置当前阶段
+    this.currentStage = targetStage;
+    
+    // 根据目标阶段设置之前的阶段为已完成
+    const targetIndex = this.stageOrder.indexOf(targetStage);
+    if (targetIndex > 0) {
+      // 将目标阶段之前的所有阶段设置为已完成
+      for (let i = 0; i < targetIndex; i++) {
+        const stage = this.stageOrder[i];
+        this.expandedStages[stage] = false; // 已完成的阶段收起
+      }
+    }
+    
+    // 展开当前阶段
+    this.expandedStages[targetStage] = true;
+    
+    // 如果项目对象存在,更新项目的当前阶段
+    if (this.project) {
+      this.project.currentStage = targetStage;
+    }
+    
+    // 触发变更检测以更新UI
+    this.cdr.detectChanges();
+  }
   ngOnDestroy(): void {
     if (this.countdownInterval) {
       clearInterval(this.countdownInterval);
     }
+    
+    // 停止自动同步
+    this.stopAutoSync();
+    
     document.removeEventListener('click', this.closeDropdownOnClickOutside);
     // 释放所有 blob 预览 URL
     const revokeList: string[] = [];
@@ -730,7 +800,9 @@ export class ProjectDetail implements OnInit, OnDestroy {
   updateProjectStage(stage: ProjectStage): void {
     if (this.project) {
       this.projectService.updateProjectStage(this.projectId, stage).subscribe(() => {
+        this.currentStage = stage; // 同步更新本地状态
         this.loadProjectDetails(); // 重新加载项目详情
+        this.cdr.detectChanges(); // 触发变更检测以更新导航栏颜色
       });
     }
   }
@@ -741,9 +813,11 @@ export class ProjectDetail implements OnInit, OnDestroy {
     if (idx >= 0 && idx < this.stageOrder.length - 1) {
       const next = this.stageOrder[idx + 1];
       this.updateProjectStage(next);
-      // 可选:更新展开状态,折叠当前、展开下一阶段,提升体验
+      // 更新展开状态,折叠当前、展开下一阶段,提升体验
       if (this.expandedStages[afterStage] !== undefined) this.expandedStages[afterStage] = false as any;
       if (this.expandedStages[next] !== undefined) this.expandedStages[next] = true as any;
+      // 触发变更检测以更新导航栏颜色
+      this.cdr.detectChanges();
     }
   }
   generateReminderMessage(): void {
@@ -1338,6 +1412,21 @@ export class ProjectDetail implements OnInit, OnDestroy {
     this.advanceToNextStage('后期');
   }
 
+  // 新增:尾款结算阶段确认并自动进入下一阶段(客户评价)
+  confirmSettlement(): void {
+    this.advanceToNextStage('尾款结算');
+  }
+
+  // 新增:客户评价阶段确认并自动进入下一阶段(投诉处理)
+  confirmCustomerReview(): void {
+    this.advanceToNextStage('客户评价');
+  }
+
+  // 新增:投诉处理阶段确认并完成项目
+  confirmComplaint(): void {
+    this.advanceToNextStage('投诉处理');
+  }
+
   // 新增:软装阶段 确认上传并自动进入下一阶段(渲染)
   confirmSoftDecorUpload(): void {
     if (this.softDecorImages.length === 0) return;
@@ -1417,16 +1506,27 @@ export class ProjectDetail implements OnInit, OnDestroy {
   // 获取板块状态:completed | 'active' | 'pending'
   getSectionStatus(key: SectionKey): 'completed' | 'active' | 'pending' {
     const current = this.project?.currentStage as ProjectStage | undefined;
-    if (!current) return 'pending';
+    
+    // 如果没有当前阶段(新创建的项目),默认订单创建板块为active(红色)
+    if (!current || current === '订单创建') {
+      return key === 'order' ? 'active' : 'pending';
+    }
 
+    // 获取当前阶段所属的板块
     const currentSection = this.getSectionKeyForStage(current);
     const sectionOrder = this.sections.map(s => s.key);
     const currentIdx = sectionOrder.indexOf(currentSection);
     const idx = sectionOrder.indexOf(key);
+    
     if (idx === -1 || currentIdx === -1) return 'pending';
 
+    // 已完成的板块:当前阶段所在板块之前的所有板块
     if (idx < currentIdx) return 'completed';
+    
+    // 当前进行中的板块:当前阶段所在的板块
     if (idx === currentIdx) return 'active';
+    
+    // 未开始的板块:当前阶段所在板块之后的所有板块
     return 'pending';
   }
 
@@ -1475,6 +1575,11 @@ export class ProjectDetail implements OnInit, OnDestroy {
   isSyncing: boolean = false;
   orderTime: string = '';
 
+  // 客户信息实时同步相关变量
+  isSyncingCustomerInfo: boolean = false;
+  lastSyncTime: Date | null = null;
+  syncInterval: any = null;
+
   customerForm!: FormGroup;
   customerSearchKeyword: string = '';
   customerSearchResults: Array<{ id: string; name: string; phone: string; wechat?: string; avatar?: string; customerType?: string; source?: string; remark?: string }> = [];
@@ -1576,9 +1681,61 @@ export class ProjectDetail implements OnInit, OnDestroy {
         source: '小程序下单'
       });
       this.isSyncing = false;
+      
+      // 触发客户信息同步显示
+      this.syncCustomerInfoDisplay();
     }, 1000);
   }
 
+  // 同步客户信息显示
+  syncCustomerInfoDisplay(): void {
+    this.isSyncingCustomerInfo = true;
+    
+    // 模拟同步过程
+    setTimeout(() => {
+      this.lastSyncTime = new Date();
+      this.isSyncingCustomerInfo = false;
+      
+      console.log('客户信息显示已同步:', this.lastSyncTime);
+    }, 800);
+  }
+
+  // 启动自动同步
+  startAutoSync(): void {
+    if (this.syncInterval) {
+      clearInterval(this.syncInterval);
+    }
+    
+    // 每30秒自动同步一次
+    this.syncInterval = setInterval(() => {
+      this.syncCustomerInfoDisplay();
+    }, 30000);
+  }
+
+  // 停止自动同步
+  stopAutoSync(): void {
+    if (this.syncInterval) {
+      clearInterval(this.syncInterval);
+      this.syncInterval = null;
+    }
+  }
+
+  // 格式化时间显示
+  formatTime(date: Date): string {
+    const now = new Date();
+    const diff = now.getTime() - date.getTime();
+    const minutes = Math.floor(diff / 60000);
+    
+    if (minutes < 1) {
+      return '刚刚';
+    } else if (minutes < 60) {
+      return `${minutes}分钟前`;
+    } else {
+      const hours = Math.floor(minutes / 60);
+      return `${hours}小时前`;
+    }
+  }
+
   downloadFile(file: ProjectFile): void {
     // 实现文件下载逻辑
     const link = document.createElement('a');
@@ -1637,6 +1794,36 @@ export class ProjectDetail implements OnInit, OnDestroy {
         };
       }
 
+      // 新增:实时更新左侧客户信息显示
+      if (this.project) {
+        // 更新项目的客户信息
+        if (requirementData.colorIndicators && requirementData.colorIndicators.length > 0) {
+          this.project.customerInfo = {
+            ...this.project.customerInfo,
+            colorPreference: requirementData.colorIndicators.map((indicator: any) => indicator.name).join(', ')
+          };
+        }
+        
+        // 更新空间结构信息
+        if (requirementData.spaceIndicators && requirementData.spaceIndicators.length > 0) {
+          this.project.customerInfo = {
+            ...this.project.customerInfo,
+            spaceRequirements: requirementData.spaceIndicators.map((indicator: any) => `${indicator.name}: ${indicator.value}`).join(', ')
+          };
+        }
+        
+        // 更新材质偏好
+        if (requirementData.materialIndicators && requirementData.materialIndicators.length > 0) {
+          this.project.customerInfo = {
+            ...this.project.customerInfo,
+            materialPreference: requirementData.materialIndicators.map((indicator: any) => `${indicator.name}: ${indicator.value}%`).join(', ')
+          };
+        }
+        
+        // 触发变更检测以更新UI
+        this.cdr.detectChanges();
+      }
+
       console.log('需求关键信息已同步:', this.requirementKeyInfo);
     } else {
       // 模拟数据用于演示
@@ -1692,16 +1879,8 @@ export class ProjectDetail implements OnInit, OnDestroy {
   confirmProposal(): void {
     console.log('确认方案按钮被点击');
     
-    // 自动跳转到建模阶段
-    this.currentStage = '建模';
-    this.expandedStages['建模'] = true;
-    this.expandedStages['方案确认'] = false;
-    
-    // 更新项目状态
-    this.updateProjectStage('建模');
-    
-    // 滚动到建模阶段
-    this.scrollToStage('建模');
+    // 使用统一的阶段推进方法
+    this.advanceToNextStage('方案确认');
     
     console.log('已跳转到建模阶段');
   }
@@ -1784,26 +1963,54 @@ export class ProjectDetail implements OnInit, OnDestroy {
     // 保存订单创建数据
     this.orderCreationData = formData;
     
+    // 实时更新左侧客户信息显示
+    this.updateCustomerInfoDisplay(formData);
+    
     // 根据角色上下文处理数据同步
     if (formData.roleContext === 'customer-service') {
       // 客服端创建的订单需要同步到设计师端
       this.syncOrderToDesignerView(formData);
     }
     
-    // 更新项目阶段到下一个阶段(需求沟通)
-    this.updateProjectStage('需求沟通');
-    
-    // 展开下一个阶段
-    this.expandedStages['需求沟通'] = true;
-    this.expandedStages['订单创建'] = false;
-    
-    // 滚动到下一个阶段
-    setTimeout(() => {
-      this.scrollToStage('需求沟通');
-    }, 100);
-    
-    // 显示成功提示
-    console.log('订单创建成功,已跳转到需求沟通阶段');
+    // 触发变更检测以更新UI
+    this.cdr.detectChanges();
+  }
+
+  // 新增:更新客户信息显示
+  private updateCustomerInfoDisplay(formData: any): void {
+    if (formData.customerInfo) {
+      // 更新项目对象中的客户信息
+      if (this.project) {
+        this.project.customerName = formData.customerInfo.name;
+        this.project.customerPhone = formData.customerInfo.phone;
+        this.project.customerWechat = formData.customerInfo.wechat;
+        this.project.customerType = formData.customerInfo.customerType;
+        this.project.customerSource = formData.customerInfo.source;
+        this.project.customerRemark = formData.customerInfo.remark;
+      }
+      
+      // 更新客户标签
+      if (formData.preferenceTags) {
+        this.project = {
+          ...this.project,
+          customerTags: formData.preferenceTags
+        } as any;
+      }
+      
+      // 更新需求信息
+      if (formData.requirementInfo) {
+        this.project = {
+          ...this.project,
+          decorationType: formData.requirementInfo.decorationType,
+          downPayment: formData.requirementInfo.downPayment,
+          firstDraftDate: formData.requirementInfo.firstDraftDate,
+          style: formData.requirementInfo.style,
+          spaceRequirements: formData.requirementInfo.spaceRequirements
+        } as any;
+      }
+      
+      console.log('客户信息已实时更新:', this.project);
+    }
   }
 
   // 新增:同步订单数据到设计师视图
@@ -1835,27 +2042,24 @@ export class ProjectDetail implements OnInit, OnDestroy {
     );
   }
 
-  // 关闭团队分配模态框
-  closeTeamAssignmentModal(): void {
-    this.showTeamAssignmentModal = false;
-    this.selectedDesigner = null;
-    this.projectData = null;
-  }
-
   // 确认团队分配
-  confirmTeamAssignment(event: any): void {
-    if (event && event.designer) {
-      this.selectedDesigner = event.designer;
-      console.log('团队分配确认:', event);
+  confirmTeamAssignment(designer: any): void {
+    if (designer) {
+      this.selectedDesigner = designer;
+      console.log('团队分配确认:', designer);
       
       // 这里可以添加实际的团队分配逻辑
       // 例如调用服务来分配设计师到项目
       
-      // 关闭模态框
-      this.closeTeamAssignmentModal();
+      // 进入下一个阶段:需求沟通
+      this.updateProjectStage('需求沟通');
+      this.expandedStages['需求沟通'] = true;
+      this.expandedStages['订单创建'] = false;
       
       // 显示成功消息
-      alert('团队分配成功!');
+      alert('团队分配成功!已进入需求沟通阶段');
+      
+      console.log('团队分配完成,已跳转到需求沟通阶段');
     }
   }
 
@@ -1863,6 +2067,82 @@ export class ProjectDetail implements OnInit, OnDestroy {
   onProjectCreated(projectData: any): void {
     console.log('项目创建完成:', projectData);
     this.projectData = projectData;
-    this.showTeamAssignmentModal = true;
+
+    // 团队分配已在子组件中完成并触发该事件:推进到需求沟通阶段
+    this.updateProjectStage('需求沟通');
+    
+    // 更新项目对象的当前阶段,确保四大板块状态正确显示
+    if (this.project) {
+      this.project.currentStage = '需求沟通';
+    }
+    
+    // 展开需求沟通阶段,收起订单创建阶段
+    this.expandedStages['需求沟通'] = true;
+    this.expandedStages['订单创建'] = false;
+    
+    // 自动展开确认需求板块
+    this.expandedSection = 'requirements';
+
+    // 强制触发变更检测,确保UI更新
+    this.cdr.detectChanges();
+
+    // 延迟滚动到需求沟通阶段,确保DOM更新完成
+    setTimeout(() => {
+      this.scrollToStage('需求沟通');
+      // 再次触发变更检测,确保所有状态都已正确更新
+      this.cdr.detectChanges();
+    }, 100);
+
+    console.log('项目创建成功,已推进到需求沟通阶段,四大板块状态已更新');
+  }
+
+  // 新增:处理实时需求数据更新
+  onRequirementDataUpdated(data: any): void {
+    console.log('收到需求数据更新:', data);
+    
+    // 同步关键信息
+    this.syncRequirementKeyInfo(data);
+    
+    // 更新客户信息显示
+    if (data && this.project) {
+      // 更新项目的客户信息
+      if (data.colorIndicators && data.colorIndicators.length > 0) {
+        this.project.customerInfo = {
+          ...this.project.customerInfo,
+          colorPreference: data.colorIndicators.map((indicator: any) => indicator.name).join(', ')
+        };
+      }
+      
+      // 更新空间结构信息
+      if (data.spaceIndicators && data.spaceIndicators.length > 0) {
+        this.project.customerInfo = {
+          ...this.project.customerInfo,
+          spaceRequirements: data.spaceIndicators.map((indicator: any) => `${indicator.name}: ${indicator.value}`).join(', ')
+        };
+      }
+      
+      // 更新材质偏好
+      if (data.materialIndicators && data.materialIndicators.length > 0) {
+        this.project.customerInfo = {
+          ...this.project.customerInfo,
+          materialPreference: data.materialIndicators.map((indicator: any) => `${indicator.name}: ${indicator.value}%`).join(', ')
+        };
+      }
+      
+      // 更新需求项目
+      if (data.requirementItems && data.requirementItems.length > 0) {
+        this.project.requirements = data.requirementItems.map((item: any) => ({
+          id: item.id,
+          description: item.description,
+          status: item.status,
+          priority: item.priority || 'medium'
+        }));
+      }
+      
+      // 触发变更检测以更新UI
+      this.cdr.detectChanges();
+      
+      console.log('客户信息已实时更新');
+    }
   }
 }

+ 1 - 12
src/app/shared/components/consultation-order-panel/consultation-order-panel.component.html

@@ -117,7 +117,7 @@
               </div>
               <div class="form-group">
                 <label for="budget">预算范围 <span class="required">*</span></label>
-                <input type="text" id="budget" formControlName="budget" placeholder="请输入预算范围">
+                <input type="number" id="budget" formControlName="budget" placeholder="请输入预算金额">
               </div>
             </div>
 
@@ -144,17 +144,6 @@
               </div>
             </div>
 
-            <div class="form-row">
-              <div class="form-group">
-                <label for="budget">预算 *</label>
-                <input type="number" id="budget" formControlName="budget" placeholder="请输入预算金额">
-              </div>
-              <div class="form-group">
-                <label for="area">面积 *</label>
-                <input type="number" id="area" formControlName="area" placeholder="请输入面积(平方米)">
-              </div>
-            </div>
-
             <div class="form-row">
               <div class="form-group">
                 <label for="smallImageTime">小图时间</label>

+ 10 - 9
src/app/shared/components/consultation-order-panel/consultation-order-panel.component.ts

@@ -47,8 +47,8 @@ export class ConsultationOrderPanelComponent {
   selectedCustomer: Customer | null = null;
   // 表单提交状态
   isSubmitting = false;
-  // 项目需求卡片展开状态
-  isRequirementCardExpanded = false;
+  // 项目需求卡片展开状态 - 默认展开以便用户填写必填字段
+  isRequirementCardExpanded = true;
 
   // 需求表单
   requirementForm: FormGroup;
@@ -112,7 +112,7 @@ export class ConsultationOrderPanelComponent {
     // 初始化客户表单
     this.customerForm = this.fb.group({
       name: ['', Validators.required],
-      phone: ['', [Validators.required, Validators.pattern(/^1[3-9]\d{9}$/)]],
+      phone: ['', [Validators.required, Validators.pattern(/^(1[3-9]\d{9}|1[3-9]\d{1}\*{4}\d{4})$/)]],
       wechat: [''],
       customerType: ['新客户'],
       source: [''],
@@ -196,7 +196,7 @@ export class ConsultationOrderPanelComponent {
 
   // 提交表单
   submitForm() {
-    if (this.customerForm.valid && this.requirementForm.valid) {
+    if (this.isFormValid()) {
       this.isSubmitting = true;
       
       const formData = {
@@ -207,11 +207,11 @@ export class ConsultationOrderPanelComponent {
         createdAt: new Date()
       };
 
-      // 模拟提交请求
-      setTimeout(() => {
-        this.isSubmitting = false;
-        this.orderCreated.emit(formData);
-      }, 1000);
+      // 直接触发订单创建事件,不需要延迟
+      this.orderCreated.emit(formData);
+      
+      // 立即显示团队分配弹窗
+      this.showTeamAssignmentModal = true;
     }
   }
 
@@ -224,6 +224,7 @@ export class ConsultationOrderPanelComponent {
   confirmTeamAssignment(designer: Designer) {
     this.selectedDesigner = designer;
     this.showTeamAssignmentModal = false;
+    this.isSubmitting = false; // 重置提交状态
     
     // 发出项目创建成功事件
     const projectData = {

+ 23 - 0
src/app/shared/components/requirements-confirm-card/requirements-confirm-card.ts

@@ -85,6 +85,7 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
   @Output() requirementConfirmed = new EventEmitter<RequirementItem>();
   @Output() progressUpdated = new EventEmitter<number>();
   @Output() stageCompleted = new EventEmitter<{ stage: string; allStagesCompleted: boolean }>();
+  @Output() dataUpdated = new EventEmitter<any>(); // 新增:实时数据更新事件
 
   // 表单
   materialForm!: FormGroup;
@@ -792,6 +793,9 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
     this.triggerAutoSave(); // 触发自动保存
     this.checkStageCompletion(); // 检查阶段完成状态
     
+    // 发射实时数据更新事件
+    this.emitDataUpdate();
+    
     // 强制触发变更检测
     this.cdr.detectChanges();
     console.log('滑动条变更检测已触发');
@@ -822,6 +826,9 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
     
     this.triggerAutoSave();
     
+    // 发射实时数据更新事件
+    this.emitDataUpdate();
+    
     // 强制触发变更检测
     this.cdr.detectChanges();
     console.log('输入框变更检测已触发');
@@ -1460,4 +1467,20 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
       window.open(this.colorAnalysisResult.reportPath, '_blank');
     }
   }
+
+  // 新增:发射实时数据更新事件的方法
+  private emitDataUpdate(): void {
+    const currentData = {
+      colorIndicators: this.colorIndicators || [],
+      spaceIndicators: this.spaceIndicators || [],
+      materialIndicators: this.materialIndicators || [],
+      requirementItems: this.requirementItems || [],
+      materials: this.materials || [],
+      collaborationComments: this.collaborationComments || '',
+      stageCompletionStatus: this.stageCompletionStatus || {}
+    };
+    
+    this.dataUpdated.emit(currentData);
+    console.log('实时数据更新事件已发射:', currentData);
+  }
 }