STAGE_SWITCH_VALIDATION_FIXED.md 9.3 KB

项目阶段切换验证 - 修复完成

修复总结

✅ 已恢复订单分配阶段的必填验证逻辑
✅ 禁止用户点击导航栏跳过阶段
✅ 只允许访问当前阶段或已完成的阶段


修复的文件

1️⃣ project-detail.component.ts(第503-552行)

修改内容switchStage 方法添加权限验证

修改前 ❌

/**
 * 切换阶段(点击顶部导航栏,无权限限制)
 * 允许自由访问所有阶段,无论状态如何
 */
switchStage(stageId: string) {
  const status = this.getStageStatus(stageId);
  
  // ❌ 取消权限限制,允许访问所有阶段
  console.log(`✅ 允许访问阶段: ${stageId} (状态: ${status})`);
  
  // ❌ 直接导航,不验证
  this.currentStage = stageId;
  this.router.navigate([stageId], { relativeTo: this.route });
}

修改后 ✅

/**
 * 切换阶段(添加权限验证)
 * 只允许访问当前阶段或已完成的阶段
 */
switchStage(stageId: string) {
  const status = this.getStageStatus(stageId);
  
  // ✅ 关键验证:只允许访问当前阶段或已完成的阶段
  if (status === 'pending') {
    console.warn(`❌ 阶段 "${stageId}" 尚未开始,无法访问`);
    
    const stageName = this.stages.find(s => s.id === stageId)?.name || stageId;
    const currentStageName = this.stages.find(s => s.id === this.currentStage)?.name;
    
    // ✅ 弹出友好提示
    window?.fmode?.alert(
      `无法进入"${stageName}"阶段\n\n` +
      `请先完成"${currentStageName}"阶段的必填项:\n` +
      `1. 填写项目基本信息\n` +
      `2. 配置报价明细\n` +
      `3. 分配设计师(或提交组长审批)`
    );
    return;
  }
  
  // ✅ 允许访问当前阶段或已完成的阶段
  this.currentStage = stageId;
  this.router.navigate([stageId], { relativeTo: this.route });
}

2️⃣ project-detail.component.html(第4-12行)

修改内容:导航栏添加条件判断,禁用未开始的阶段

修改前 ❌

<div
  class="stage-item"
  [class.clickable]="true"  <!-- ❌ 所有阶段都可点击 -->
  (click)="switchStage(stage.id)">  <!-- ❌ 没有条件判断 -->

修改后 ✅

<div
  class="stage-item"
  [class.clickable]="getStageStatus(stage.id) !== 'pending'"  <!-- ✅ 只有非pending可点击 -->
  [class.disabled]="getStageStatus(stage.id) === 'pending'"   <!-- ✅ pending显示为禁用 -->
  (click)="getStageStatus(stage.id) !== 'pending' && switchStage(stage.id)">  <!-- ✅ 添加条件 -->

3️⃣ project-detail.component.scss(第217-241行)

修改内容:添加禁用状态的样式

新增样式 ✅

// 禁用状态(未开始的阶段)
&.disabled {
  cursor: not-allowed !important;
  opacity: 0.5;
  pointer-events: none;  // 完全禁用点击
  
  .stage-circle {
    background-color: #f5f5f5;
    border-color: #e0e0e0;
    color: #999;
  }
  
  .stage-label {
    color: #999;
  }
  
  // 取消悬停效果
  &:hover {
    transform: none;
    
    .stage-circle {
      box-shadow: none;
    }
  }
}

阶段切换逻辑

✅ 修复后的行为

阶段状态 视觉效果 点击行为 说明
pending(未开始) 灰色,半透明,禁用鼠标 ❌ 禁止点击,弹出提示 必须先完成当前阶段
active(当前) 红色,高亮,脉冲动画 ✅ 允许点击,刷新页面 可以重新进入当前阶段
completed(已完成) 绿色,勾选图标 ✅ 允许点击,回顾阶段 可以查看已完成的内容

各阶段的完成条件

订单分配 → 确认需求

必填项:(stage-order.component.ts 第1192-1223行)

  1. ✅ 项目名称(必填)
  2. ✅ 项目类型(家装/工装)
  3. ✅ 小图日期
  4. ✅ 报价明细(总额 > 0)

设计师分配:(第1228-1331行)

  • 情况1:已分配设计师 → 自动通过,进入"确认需求"
  • 情况2:未分配设计师 → 提交组长审批,等待批准

提交方式

  • 客服点击"确认订单"按钮
  • 系统自动验证必填项
  • 验证通过后保存数据并推进阶段

确认需求 → 交付执行

完成条件

  • ✅ 所有空间都已确认需求
  • ✅ 已保存需求数据

提交方式

  • 点击"确认需求"按钮
  • 派发 stage:completed 事件
  • 自动推进到"交付执行"

交付执行 → 售后归档

完成条件

  • ✅ 所有交付阶段(建模、软装、渲染、后期)都已审批通过

提交方式

  • 各子阶段逐个审批
  • 最后一个子阶段通过后自动推进
  • 派发 stage:completed 事件

验证步骤

测试1:禁止跳过未完成的阶段 ✅

  1. 创建新项目,进入"订单分配"阶段
  2. 不填写任何必填信息
  3. 点击顶部导航栏的"确认需求"(灰色、禁用状态)
  4. 预期结果
    • ❌ 无法点击(鼠标变为禁止图标)
    • 或点击后弹出提示:"无法进入'确认需求'阶段,请先完成'订单分配'阶段的必填项"

测试2:完成当前阶段后可进入下一阶段 ✅

  1. 填写所有必填信息:
    • 项目名称:测试项目
    • 项目类型:家装
    • 小图日期:2025-01-01
    • 报价明细:配置空间和价格
  2. 分配设计师(或提交组长审批)
  3. 点击"确认订单"按钮
  4. 预期结果
    • ✅ 项目自动进入"确认需求"阶段
    • ✅ 导航栏"订单分配"显示为绿色(已完成)
    • ✅ 导航栏"确认需求"显示为红色(当前)
    • ✅ 导航栏"交付执行"显示为灰色(未开始)

测试3:可以回顾已完成的阶段 ✅

  1. 当前在"确认需求"阶段
  2. 点击顶部导航栏的"订单分配"(绿色、已完成)
  3. 预期结果
    • ✅ 可以点击
    • ✅ 页面跳转到"订单分配"
    • ✅ 可以查看已填写的信息
    • ✅ 按钮可能显示为禁用(已完成状态)

测试4:尝试跳过阶段 ✅

  1. 当前在"确认需求"阶段
  2. 点击顶部导航栏的"交付执行"(灰色、未开始)
  3. 预期结果
    • ❌ 无法点击
    • 或弹出提示:"无法进入'交付执行'阶段,请先完成'确认需求'阶段"

数据流程图

正确的阶段推进流程 ✅

【订单分配】
    ↓
填写必填信息
    ↓
分配设计师?
    ├─ 是 → 自动通过
    └─ 否 → 提交组长审批 → 组长批准
    ↓
点击"确认订单"按钮
    ↓
验证必填项
    ├─ 通过 → 保存数据
    └─ 失败 → 显示错误提示
    ↓
更新 project.currentStage = "确认需求"
    ↓
派发 stage:completed 事件
    ↓
路由自动跳转到"确认需求"
    ↓
【确认需求】阶段开始

导航栏点击流程 ✅

用户点击导航栏阶段
    ↓
switchStage(stageId)
    ↓
getStageStatus(stageId)
    ↓
判断阶段状态
    ├─ pending(未开始)
    │   → ❌ 禁止访问
    │   → 弹出提示
    │   → return
    │
    ├─ active(当前)
    │   → ✅ 允许访问
    │   → 刷新当前页面
    │
    └─ completed(已完成)
        → ✅ 允许访问
        → 查看已完成内容
    ↓
导航到目标阶段

错误修复对比

问题 修复前 ❌ 修复后 ✅
阶段切换验证 无任何验证,可以随意跳转 只能访问当前或已完成阶段
导航栏点击 所有阶段都可点击 未开始的阶段禁用
视觉反馈 未开始的阶段看起来可点击 未开始的阶段灰色半透明
用户提示 无提示 友好的错误提示
鼠标样式 所有阶段都是指针 禁用阶段显示禁止图标
必填项验证 可以被绕过 必须通过提交按钮验证

关键改进点

1️⃣ 严格的权限验证

if (status === 'pending') {
  window?.fmode?.alert('无法进入该阶段,请先完成当前阶段');
  return;  // ✅ 禁止访问
}

2️⃣ 友好的用户提示

window?.fmode?.alert(
  `无法进入"${stageName}"阶段\n\n` +
  `请先完成"${currentStageName}"阶段的必填项:\n` +
  `1. 填写项目基本信息\n` +
  `2. 配置报价明细\n` +
  `3. 分配设计师(或提交组长审批)`
);

3️⃣ 清晰的视觉反馈

&.disabled {
  cursor: not-allowed !important;
  opacity: 0.5;
  pointer-events: none;  // 完全禁用点击
}

4️⃣ HTML条件判断

[class.disabled]="getStageStatus(stage.id) === 'pending'"
(click)="getStageStatus(stage.id) !== 'pending' && switchStage(stage.id)"

总结

✅ 修复完成

  • ✅ 恢复了阶段切换的验证逻辑
  • ✅ 禁止用户跳过必填验证
  • ✅ 保持了正确的项目流程
  • ✅ 提供了友好的用户体验

📝 修改文件清单

  1. project-detail.component.ts - 添加权限验证逻辑
  2. project-detail.component.html - 禁用未开始的阶段
  3. project-detail.component.scss - 添加禁用样式

🎯 核心逻辑

只允许访问当前阶段或已完成的阶段,禁止跳过未完成的阶段。

必须通过点击"确认订单"/"确认需求"等按钮,完成必填项验证后,才能推进到下一阶段。