Procházet zdrojové kódy

feat(project-detail): 实现需求阶段自动推进和方案确认功能

添加需求阶段完成事件处理,当所有需求完成时自动推进到方案确认阶段
新增方案确认按钮及样式,点击后自动跳转到建模阶段
添加角色上下文支持,优化客服端订单同步逻辑
0235711 před 1 dnem
rodič
revize
8f34b96a7e

+ 37 - 1
src/app/pages/designer/project-detail/project-detail.html

@@ -330,12 +330,14 @@
                     <div class="vertical-stage-body">
                       @if (stage === '订单创建') {
                         <app-consultation-order-panel
+                          [roleContext]="roleContext"
                           (formSubmit)="onConsultationOrderSubmit($event)"
                         ></app-consultation-order-panel>
                       } @else if (stage === '需求沟通') {
                         <app-requirements-confirm-card 
                           (requirementConfirmed)="syncRequirementKeyInfo($event)"
-                          (progressUpdated)="syncRequirementKeyInfo($event)">
+                          (progressUpdated)="syncRequirementKeyInfo($event)"
+                          (stageCompleted)="onRequirementsStageCompleted($event)">
                         </app-requirements-confirm-card>
                       } @else if (stage === '方案确认') {
                         <!-- 方案确认阶段 - 需求信息展示 -->
@@ -500,6 +502,40 @@
                                 </div>
                               </div>
                             </div>
+                            
+                            <!-- 确认方案按钮 -->
+            <div class="proposal-confirm-actions">
+              <button class="confirm-proposal-btn" 
+                      (click)="confirmProposal()"
+                      style="
+                        appearance: none !important;
+                        border: none !important;
+                        background: linear-gradient(135deg, #007aff 0%, #0066ff 50%, #0051d5 100%) !important;
+                        color: white !important;
+                        padding: 16px 40px !important;
+                        border-radius: 16px !important;
+                        font-size: 16px !important;
+                        font-weight: 600 !important;
+                        cursor: pointer !important;
+                        transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1) !important;
+                        display: flex !important;
+                        align-items: center !important;
+                        gap: 10px !important;
+                        box-shadow: 0 8px 24px rgba(0, 122, 255, 0.25), 0 4px 12px rgba(0, 122, 255, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
+                        min-width: 180px !important;
+                        justify-content: center !important;
+                        position: relative !important;
+                        overflow: hidden !important;
+                        text-transform: none !important;
+                        letter-spacing: normal !important;
+                        line-height: normal !important;
+                      ">
+                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="color: white !important;">
+                  <polyline points="20,6 9,17 4,12"></polyline>
+                </svg>
+                确认方案
+              </button>
+            </div>
                           } @else {
                             <div class="requirement-pending">
                               <div class="pending-icon">

+ 213 - 0
src/app/pages/designer/project-detail/project-detail.scss

@@ -388,6 +388,219 @@
       }
     }
   }
+
+  // 确认方案按钮样式 - 优化版本
+  .proposal-confirm-actions {
+    margin-top: 40px;
+    padding-top: 32px;
+    border-top: 1px solid rgba(0, 0, 0, 0.06);
+    display: flex;
+    justify-content: center;
+    position: relative;
+
+    // 添加背景装饰
+    &::before {
+      content: '';
+      position: absolute;
+      top: 0;
+      left: 50%;
+      transform: translateX(-50%);
+      width: 60px;
+      height: 3px;
+      background: linear-gradient(90deg, transparent 0%, #007aff 50%, transparent 100%);
+      border-radius: 2px;
+    }
+
+    // 使用更高特异性的选择器确保样式生效
+    .proposal-confirm-actions .confirm-proposal-btn,
+    button.confirm-proposal-btn {
+      appearance: none !important;
+      border: none !important;
+      background: linear-gradient(135deg, #007aff 0%, #0066ff 50%, #0051d5 100%) !important;
+      color: white !important;
+      padding: 16px 40px !important;
+      border-radius: 16px !important;
+      font-size: 16px !important;
+      font-weight: 600 !important;
+      cursor: pointer !important;
+      transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1) !important;
+      display: flex !important;
+      align-items: center !important;
+      gap: 10px !important;
+      box-shadow: 
+        0 8px 24px rgba(0, 122, 255, 0.25),
+        0 4px 12px rgba(0, 122, 255, 0.15),
+        inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
+      min-width: 180px !important;
+      justify-content: center !important;
+      position: relative !important;
+      overflow: hidden !important;
+      backdrop-filter: blur(10px) !important;
+      
+      // 重置可能的Material Design样式
+      text-transform: none !important;
+      letter-spacing: normal !important;
+      line-height: normal !important;
+      
+      // 添加内部光泽效果
+      &::before {
+        content: '' !important;
+        position: absolute !important;
+        top: 0 !important;
+        left: -100% !important;
+        width: 100% !important;
+        height: 100% !important;
+        background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.2) 50%, transparent 100%) !important;
+        transition: left 0.6s ease !important;
+      }
+
+      svg {
+        width: 20px !important;
+        height: 20px !important;
+        stroke-width: 2.5 !important;
+        filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1)) !important;
+        transition: transform 0.3s ease !important;
+      }
+
+      // 悬停状态优化
+      &:hover {
+        transform: translateY(-3px) scale(1.02) !important;
+        box-shadow: 
+          0 12px 32px rgba(0, 122, 255, 0.35),
+          0 6px 16px rgba(0, 122, 255, 0.25),
+          inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
+        background: linear-gradient(135deg, #0066ff 0%, #007aff 50%, #0051d5 100%) !important;
+        
+        &::before {
+          left: 100% !important;
+        }
+        
+        svg {
+          transform: scale(1.1) rotate(5deg) !important;
+        }
+      }
+
+      // 点击状态优化
+      &:active {
+        transform: translateY(-1px) scale(0.98) !important;
+        box-shadow: 
+          0 4px 16px rgba(0, 122, 255, 0.3),
+          0 2px 8px rgba(0, 122, 255, 0.2),
+          inset 0 2px 4px rgba(0, 0, 0, 0.1) !important;
+        transition: all 0.15s ease !important;
+      }
+
+      // 焦点状态
+      &:focus {
+        outline: none !important;
+        box-shadow: 
+          0 8px 24px rgba(0, 122, 255, 0.25),
+          0 4px 12px rgba(0, 122, 255, 0.15),
+          0 0 0 3px rgba(0, 122, 255, 0.3) !important;
+      }
+
+      // 禁用状态
+       &:disabled {
+         opacity: 0.6 !important;
+         cursor: not-allowed !important;
+         transform: none !important;
+         box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
+         
+         &:hover {
+           transform: none;
+           box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+         }
+       }
+
+       // 响应式设计
+       @media (max-width: 768px) {
+         padding: 14px 32px;
+         font-size: 15px;
+         min-width: 160px;
+         border-radius: 14px;
+         
+         svg {
+           width: 18px;
+           height: 18px;
+         }
+         
+         &:hover {
+           transform: translateY(-2px) scale(1.01);
+         }
+       }
+
+       @media (max-width: 480px) {
+         padding: 12px 24px;
+         font-size: 14px;
+         min-width: 140px;
+         border-radius: 12px;
+         gap: 8px;
+         
+         svg {
+           width: 16px;
+           height: 16px;
+         }
+         
+         &:hover {
+           transform: translateY(-1px);
+         }
+       }
+
+       // 高对比度模式支持
+       @media (prefers-contrast: high) {
+         border: 2px solid #007aff;
+         box-shadow: 
+           0 4px 12px rgba(0, 0, 0, 0.3),
+           inset 0 1px 0 rgba(255, 255, 255, 0.4);
+       }
+
+       // 减少动画模式支持
+       @media (prefers-reduced-motion: reduce) {
+         transition: none;
+         
+         &::before {
+           transition: none;
+         }
+         
+         svg {
+           transition: none;
+         }
+         
+         &:hover {
+           transform: none;
+           
+           svg {
+             transform: none;
+           }
+         }
+         
+         &:active {
+           transform: none;
+         }
+       }
+     }
+
+     // 响应式容器调整
+     @media (max-width: 768px) {
+       margin-top: 32px;
+       padding-top: 24px;
+       
+       &::before {
+         width: 50px;
+         height: 2px;
+       }
+     }
+
+     @media (max-width: 480px) {
+       margin-top: 24px;
+       padding-top: 20px;
+       
+       &::before {
+         width: 40px;
+         height: 2px;
+       }
+     }
+   }
 }
 
 /* 方案确认阶段样式 */

+ 71 - 1
src/app/pages/designer/project-detail/project-detail.ts

@@ -150,7 +150,7 @@ export class ProjectDetail implements OnInit, OnDestroy {
   pendingRenderLargeItems: Array<{ id: string; name: string; url: string; file: File }> = [];
 
   // 视图上下文:根据路由前缀识别角色视角(客服/设计师/组长)
-  private roleContext: 'customer-service' | 'designer' | 'team-leader' = 'designer';
+  roleContext: 'customer-service' | 'designer' | 'team-leader' = 'designer';
 
   constructor(
     private route: ActivatedRoute,
@@ -1658,6 +1658,41 @@ export class ProjectDetail implements OnInit, OnDestroy {
     }
   }
 
+  // 新增:处理需求阶段完成事件
+  onRequirementsStageCompleted(event: { stage: string; allStagesCompleted: boolean }): void {
+    console.log('需求阶段完成事件:', event);
+    
+    if (event.allStagesCompleted && event.stage === 'requirements-communication') {
+      // 自动推进到方案确认阶段
+      this.currentStage = '方案确认';
+      this.expandedStages['方案确认'] = true;
+      this.expandedStages['需求沟通'] = false;
+      
+      // 更新项目状态
+      this.updateProjectStage('方案确认');
+      
+      console.log('自动推进到方案确认阶段');
+    }
+  }
+
+  // 新增:确认方案方法
+  confirmProposal(): void {
+    console.log('确认方案按钮被点击');
+    
+    // 自动跳转到建模阶段
+    this.currentStage = '建模';
+    this.expandedStages['建模'] = true;
+    this.expandedStages['方案确认'] = false;
+    
+    // 更新项目状态
+    this.updateProjectStage('建模');
+    
+    // 滚动到建模阶段
+    this.scrollToStage('建模');
+    
+    console.log('已跳转到建模阶段');
+  }
+
   // 获取同步的关键信息摘要
   getRequirementSummary(): string[] {
     const summary: string[] = [];
@@ -1736,6 +1771,12 @@ export class ProjectDetail implements OnInit, OnDestroy {
     // 保存订单创建数据
     this.orderCreationData = formData;
     
+    // 根据角色上下文处理数据同步
+    if (formData.roleContext === 'customer-service') {
+      // 客服端创建的订单需要同步到设计师端
+      this.syncOrderToDesignerView(formData);
+    }
+    
     // 更新项目阶段到下一个阶段(需求沟通)
     this.updateProjectStage('需求沟通');
     
@@ -1751,4 +1792,33 @@ export class ProjectDetail implements OnInit, OnDestroy {
     // 显示成功提示
     console.log('订单创建成功,已跳转到需求沟通阶段');
   }
+
+  // 新增:同步订单数据到设计师视图
+  private syncOrderToDesignerView(formData: any): void {
+    // 创建项目数据
+    const projectData = {
+      customerId: formData.customerInfo.id || 'customer-' + Date.now(),
+      customerName: formData.customerInfo.name,
+      requirement: formData.requirementInfo,
+      referenceCases: [],
+      tags: {
+        demandType: formData.customerInfo.demandType,
+        preferenceTags: formData.preferenceTags,
+        followUpStatus: formData.customerInfo.followUpStatus
+      }
+    };
+
+    // 调用项目服务创建项目
+    this.projectService.createProject(projectData).subscribe(
+      result => {
+        if (result.success) {
+          console.log('订单数据已同步到设计师端,项目ID:', result.projectId);
+          // 可以在这里添加成功提示或其他处理逻辑
+        }
+      },
+      error => {
+        console.error('同步订单数据到设计师端失败:', error);
+      }
+    );
+  }
 }

+ 3 - 1
src/app/shared/components/consultation-order-panel/consultation-order-panel.component.ts

@@ -1,4 +1,4 @@
-import { Component, EventEmitter, Output } from '@angular/core';
+import { Component, EventEmitter, Output, Input } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { MatChipsModule } from '@angular/material/chips';
@@ -33,6 +33,7 @@ interface Customer {
   styleUrls: ['./consultation-order-panel.component.scss']
 })
 export class ConsultationOrderPanelComponent {
+  @Input() roleContext: 'customer-service' | 'designer' | 'team-leader' = 'designer';
   @Output() formSubmit = new EventEmitter<any>();
 
   // 搜索客户关键词
@@ -186,6 +187,7 @@ export class ConsultationOrderPanelComponent {
         customerInfo: this.customerForm.value,
         requirementInfo: this.requirementForm.value,
         preferenceTags: this.preferenceTags,
+        roleContext: this.roleContext, // 添加角色上下文信息
         createdAt: new Date()
       };
 

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

@@ -82,6 +82,7 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
   @Input() projectId?: string;
   @Output() requirementConfirmed = new EventEmitter<RequirementItem>();
   @Output() progressUpdated = new EventEmitter<number>();
+  @Output() stageCompleted = new EventEmitter<{ stage: string; allStagesCompleted: boolean }>();
 
   // 表单
   materialForm!: FormGroup;
@@ -1270,6 +1271,14 @@ export class RequirementsConfirmCardComponent implements OnInit, OnDestroy {
     this.stageCompletionStatus.progressReview = this.getProgressPercentage() >= 80;
     
     console.log('阶段完成状态更新:', this.stageCompletionStatus);
+    
+    // 检查是否所有阶段都已完成
+    const allStagesCompleted = Object.values(this.stageCompletionStatus).every(status => status);
+    
+    // 发射阶段完成事件
+    if (allStagesCompleted) {
+      this.stageCompleted.emit({ stage: 'requirements-communication', allStagesCompleted: true });
+    }
   }
 
   // 检查指示器是否有变化