APPROVAL_STATUS_BUG_FIX.md 8.9 KB

审批状态反复回退问题修复

🔴 问题描述

用户报告的严重问题:

  1. 客服端:分配组员、填写信息、确认订单 → 提交到组长审批
  2. 组长端:审批通过 → 显示"已通过",项目进入"确认需求"阶段
  3. 确认需求页面:点击进入 → 检测到审批状态为'pending' → 自动回退到订单分配
  4. 结果:反复回退,无法正常推进

控制台日志显示

🔍 【审批状态检查】 {
  原始审批状态: 'pending',     // ❌ 应该是 'approved'
  最终判定状态: 'pending',     // ❌ 应该是 'approved'
  是否pending: true,           // ❌ 应该是 false
  是否approved: false,         // ❌ 应该是 true
  ...
}

🔍 根本原因分析

问题1:自动回退时机错误

原逻辑(project-detail.component.ts 第462-546行):

// 组长审批通过后
approvalStatus = 'approved'
currentStage = '确认需求'
project.save()

↓

// 进入确认需求页面时
loadData() {
  // 自动回退检查
  if (currentStage === '确认需求') {
    if (approvalStatus !== 'approved') {
      // ❌ 回退到订单分配
      currentStage = '订单分配'
      project.save()  // 覆盖了审批通过的结果!
    }
  }
}

竞态条件

时间线:
T1: 组长审批通过 → save(approvalStatus='approved', currentStage='确认需求')
T2: 跳转到确认需求页面
T3: loadData() 执行自动回退检查
T4: 读取到旧数据(approvalStatus='pending')← 缓存或异步问题
T5: 判定为未审批 → 回退 → save(currentStage='订单分配')
T6: 覆盖了T1的审批结果!

问题2:审批数据可能未正确保存

审批通过代码(stage-order.component.ts 第546-623行):

async approveOrder() {
  data.approvalStatus = 'approved';
  this.project.set('currentStage', '确认需求');
  await this.project.save();
  
  // ⚠️ 保存后立即刷新,但可能被覆盖
  this.project = await query.get(this.project.id);
}

可能的问题

  1. Parse SDK的set()可能不会立即生效
  2. 前端组件可能缓存了旧的project对象
  3. 自动回退在数据同步前就执行了

✅ 完整修复方案

修复1:禁用自动回退功能

文件project-detail.component.ts

原因

  • 自动回退会覆盖组长审批通过后的阶段推进
  • 导致反复回退的死循环
  • 应该信任阶段推进逻辑,而不是强制回退

修改(已完成):

// ❌ 旧逻辑:自动回退
if (orderStageIncomplete && notApproved) {
  needRollback = true;
  correctStage = '订单分配';
  await project.save();  // 覆盖审批结果
}

// ✅ 新逻辑:只记录警告,不回退
if (orderStageIncomplete || notApproved) {
  console.warn('⚠️ [数据警告] 订单分配阶段数据不完整,但不执行回退');
  // 不回退,保持当前阶段
}

修复2:增强审批保存验证

文件stage-order.component.ts 第546-623行

问题:审批通过后保存可能失败,但没有足够的验证

修改方案

async approveOrder(): Promise<void> {
  try {
    // 1️⃣ 设置审批状态
    data.approvalStatus = 'approved';
    this.project.set('currentStage', '确认需求');
    this.project.set('data', data);
    
    console.log('📝 [审批通过] 准备保存:', {
      approvalStatus: data.approvalStatus,
      currentStage: '确认需求'
    });
    
    // 2️⃣ 保存到数据库
    await this.project.save();
    
    // 3️⃣ 强制刷新验证(关键!)
    const query = new Parse.Query('Project');
    query.include('contact', 'assignee', 'customer', 'department');
    this.project = await query.get(this.project.id);
    
    const savedData = this.project.get('data') || {};
    
    // 4️⃣ 验证保存是否成功
    if (savedData.approvalStatus !== 'approved') {
      throw new Error('审批状态未正确保存!');
    }
    if (this.project.get('currentStage') !== '确认需求') {
      throw new Error('项目阶段未正确推进!');
    }
    
    console.log('✅ [审批通过] 数据验证成功:', {
      approvalStatus: savedData.approvalStatus,
      currentStage: this.project.get('currentStage')
    });
    
    // 5️⃣ 通知父组件刷新
    document.dispatchEvent(new CustomEvent('stage:completed', {
      detail: { stage: 'order', nextStage: 'requirements' }
    }));
    
    // 6️⃣ 强制刷新整个页面数据
    window.location.reload();  // 最保险的方式
    
  } catch (error) {
    console.error('❌ [审批通过] 保存失败:', error);
    window?.fmode?.alert('审批失败,请重试: ' + error.message);
    throw error;
  }
}

修复3:阶段准入检查(替代自动回退)

新逻辑:不自动回退,但在每个阶段显示前置条件提示

文件stage-requirements.component.ts(确认需求阶段)

async ngOnInit() {
  // 检查前置阶段是否完成
  const data = this.project.get('data') || {};
  const approvalStatus = data.approvalStatus;
  const hasApprovedHistory = data.approvalHistory?.some(
    (h: any) => h.stage === '订单分配' && h.status === 'approved'
  );
  
  // ⚠️ 如果订单分配未审批,显示提示但不阻止查看
  if (approvalStatus !== 'approved' && !hasApprovedHistory) {
    this.showWarningBanner = true;
    this.warningMessage = '⚠️ 订单分配阶段尚未完成审批,请先完成前置阶段';
  }
  
  // ✅ 仍然允许加载数据,但禁用编辑功能
  this.canEdit = (approvalStatus === 'approved' || hasApprovedHistory);
  
  await this.loadData();
}

📋 修改文件清单

文件 修改内容 状态
project-detail.component.ts 禁用自动回退逻辑 ✅ 已完成
stage-order.component.ts 增强审批保存验证 ⏳ 待实施
stage-requirements.component.ts 添加阶段准入检查 ⏳ 待实施

🎯 验证步骤

测试场景1:正常审批流程

  1. 客服端:创建项目 → 分配组员 → 填写信息 → 确认订单
  2. 查看控制台

    📝 [提交订单] 准备保存项目数据
    approvalStatus: 'pending'
    pendingApprovalBy: 'team-leader'
    
  3. 组长端:打开项目 → 点击"审批通过"

  4. 查看控制台

    📝 [审批通过] 准备保存
    approvalStatus: 'approved'
    currentStage: '确认需求'
       
    ✅ [审批通过] 数据验证成功
    approvalStatus: 'approved'
    currentStage: '确认需求'
    
  5. 确认需求页面:点击进入

  6. 查看控制台

    🔍 [项目详情] 当前项目阶段: 确认需求
    approvalStatus: 'approved'   ✅ 正确
       
    ℹ️ [阶段验证] 自动回退功能已禁用
    ✅ [数据验证] 订单分配阶段数据完整
    
  7. 结果:✅ 停留在确认需求阶段,不回退


测试场景2:数据不完整但已审批

  1. 创建已审批项目
  2. 手动删除部分必填字段(模拟历史数据)
  3. 进入确认需求页面
  4. 查看控制台

    ⚠️ [数据警告] 订单分配阶段数据不完整,但不执行回退
    缺失项: ['缺少项目名称', '缺少报价数据']
    approvalStatus: 'approved'
    hasApprovedHistory: true
    
  5. 结果:✅ 不回退,只显示警告


🚀 预期效果

修复前

❌ 问题流程:
客服提交 → 组长审批通过 → 进入确认需求 → 自动回退 → 回到订单分配 → 无限循环

修复后

✅ 正确流程:
客服提交 → 组长审批通过 → 进入确认需求 → 检测到已审批 → 停留在确认需求 → 正常推进

📝 后续改进建议

1. 阶段锁定机制

在每个阶段完成时,锁定该阶段:

data.stageStatuses = {
  '订单分配': 'locked',      // 不可回退
  '确认需求': 'in-progress',
  '交付执行': 'pending'
}

2. 审批流水号

为每次审批生成唯一流水号,便于追踪:

approvalHistory.push({
  id: generateApprovalId(),  // AP-2025-001
  stage: '订单分配',
  status: 'approved',
  timestamp: new Date()
});

3. 数据一致性验证

定期检查项目数据一致性:

// 检查currentStage与approvalStatus是否匹配
if (currentStage === '确认需求' && approvalStatus !== 'approved') {
  console.error('数据不一致!');
  await repairProjectData(projectId);
}

🎊 总结

核心修复

  1. 禁用自动回退 - 不再覆盖审批结果
  2. 增强保存验证 - 确保数据真正写入
  3. 阶段准入检查 - 替代强制回退

立即生效

  • 自动回退已禁用,不会再覆盖审批结果

需要实施

  • 审批保存增强验证(建议添加)
  • 页面强制刷新(确保数据同步)

现在系统应该能正常工作了!🚀