EMERGENCY_FIX_GUIDE.md 7.2 KB

🚨 紧急修复指南 - 改图工单弹窗无法交互

修复时间

2025-11-19 00:35


🔥 问题根源(已定位)

主要原因:方法调用导致 ngOnChanges 无限循环

<!-- ❌ 问题代码 -->
<app-revision-task-modal
  [availableSpaces]="getAvailableSpacesForRevision()">  <!-- 每次都创建新数组 -->
</app-revision-task-modal>

<app-drag-upload-modal
  [availableSpaces]="getAvailableSpaces()">  <!-- 每次都创建新数组 -->
  [availableStages]="getAvailableStages()">  <!-- 每次都创建新数组 -->
</app-drag-upload-modal>

问题链

Angular 变更检测
    ↓
调用 getAvailableSpacesForRevision()
    ↓
返回新数组引用
    ↓
revision-task-modal 的 ngOnChanges 被触发
    ↓
modal 内部状态更新
    ↓
触发父组件变更检测
    ↓
再次调用 getAvailableSpacesForRevision()
    ↓
无限循环 🔄

结果

  • 控制台疯狂输出日志(见截图)
  • CPU 占用 100%
  • 页面卡顿
  • 弹窗虽显示但无法点击(事件循环被阻塞)

修复内容

1️⃣ 添加缓存属性

文件stage-delivery.component.ts(第126行)

// 缓存的空间和阶段列表(避免频繁创建新数组)
cachedAvailableSpaces: Array<{ id: string; name: string }> = [];
cachedAvailableStages: Array<{ id: string; name: string }> = [];
cachedRevisionSpaces: Array<{ id: string; name: string; selected: boolean }> = [];

2️⃣ 更新缓存方法

文件stage-delivery.component.ts(第2807-2829行)

private updateCachedLists(): void {
  this.cachedAvailableSpaces = this.projectProducts.map(...);
  this.cachedAvailableStages = this.deliveryTypes.map(...);
  this.cachedRevisionSpaces = this.projectProducts.map(...);  // 🆕 新增
}

3️⃣ 修改模板绑定

文件stage-delivery-new.component.html

<!-- ✅ 修复后 -->
<app-revision-task-modal
  [availableSpaces]="cachedRevisionSpaces">  <!-- 属性绑定 -->
</app-revision-task-modal>

<app-drag-upload-modal
  [availableSpaces]="cachedAvailableSpaces">  <!-- 属性绑定 -->
  [availableStages]="cachedAvailableStages">  <!-- 属性绑定 -->
</app-drag-upload-modal>

4️⃣ 减少日志输出

文件drag-upload-modal.component.ts(第116-123行)

ngOnChanges(changes: SimpleChanges) {
  // 🔥 只在关键变化时输出日志
  if (changes['visible'] || changes['droppedFiles']) {
    console.log('🔄 ngOnChanges (关键变化)', ...);
  }
}

🚀 立即执行步骤

步骤 1:强制刷新浏览器(最重要!)

Windows

Ctrl + Shift + R

Mac

Cmd + Shift + R

或者手动清除缓存

  1. F12 打开开发者工具
  2. 右键点击刷新按钮
  3. 选择"清空缓存并硬性重新加载"

步骤 2:检查控制台

刷新后应该看到:

✅ 缓存列表已更新: {空间数量: 2, 阶段数量: 4, 工单空间数量: 2}

不应该再看到

❌ 🔄 ngOnChanges 被调用 (疯狂重复)
❌ 已加载交付文件 (重复打印)

步骤 3:测试弹窗交互

  1. 点击"创建改图任务"

    • ✅ 弹窗显示
    • ✅ 可以选择"小修改"/"大修改"
    • ✅ 可以勾选空间复选框
    • ✅ 可以输入描述
    • ✅ 点击"提交"有响应
  2. 点击"改图工单"

    • ✅ 列表显示
    • ✅ 可以切换标签
    • ✅ 可以展开工单
    • ✅ 所有按钮可点击

🔍 如果还是不行

方案 A:重启开发服务器

# 1. 停止当前服务器
Ctrl + C

# 2. 清除 node_modules 缓存(可选)
rm -rf .angular/cache
# 或 Windows
rd /s /q .angular\cache

# 3. 重新启动
ng serve

方案 B:临时移除 drag-upload-modal

在浏览器控制台执行:

// 临时移除可能干扰的组件
document.querySelector('app-drag-upload-modal')?.remove();

// 然后测试改图工单是否可以点击

方案 C:检查元素层级

在控制台执行:

// 检查所有 modal 的 z-index 和 pointer-events
document.querySelectorAll('[class*="modal"]').forEach(el => {
  const z = window.getComputedStyle(el).zIndex;
  const pe = window.getComputedStyle(el).pointerEvents;
  const display = window.getComputedStyle(el).display;
  console.log(el.className, {
    zIndex: z,
    pointerEvents: pe,
    display: display
  });
});

期望输出

modal-overlay {zIndex: "2400", pointerEvents: "auto", display: "flex"}
modal-container {zIndex: "1", pointerEvents: "auto", display: "flex"}

方案 D:强制设置 z-index

如果弹窗仍被遮挡,在控制台执行:

// 强制提升改图工单弹窗的 z-index
const modal = document.querySelector('.modal-overlay');
if (modal) {
  modal.style.zIndex = '9999';
  console.log('✅ 已强制提升 z-index');
}

📊 z-index 层级图(正确配置)

页面主体:              0
图片库:               1000
拖拽上传弹窗:         2000
工单列表全屏:         2100
消息发送弹窗:         2300
创建工单弹窗:         2400  ← 改图任务弹窗
审批/报价弹窗:        2500  ← 最高

⚠️ WebSocket 错误说明

截图中的 WebSocket 错误:

WebSocket connection to 'ws://127.0.0.1:8080/sockjs-node/...' failed
Error: net::ERR_CONNECTION_REFUSED

这不影响弹窗交互!

  • 这是开发服务器的 Hot Module Replacement (HMR) 功能
  • 可能是端口冲突或服务器配置问题
  • 不会阻止页面功能

如需修复,重启开发服务器即可。


📋 验证清单

刷新前检查

  • 所有文件已保存
  • 终端中 ng serve 显示"Compiled successfully"
  • 没有 TypeScript 编译错误

刷新后检查

  • 控制台显示"缓存列表已更新"
  • 没有频繁的 ngOnChanges 日志
  • CPU 使用率正常(< 30%)

功能检查

  • 创建改图任务弹窗可点击
  • 改图工单列表可点击
  • 所有按钮响应正常
  • 可以输入文字
  • 可以勾选复选框

🎯 技术总结

为什么模板中不能调用方法?

  1. Angular 变更检测机制

    • 每次变更检测都会重新求值模板表达式
    • 开发模式下每次检测会运行两遍
  2. 对象引用比较

    • Angular 通过引用(===)比较输入属性
    • 每次调用方法返回新对象 → 引用不同
    • 触发 ngOnChanges
  3. 性能影响

    • 方法调用 × 变更检测次数 × 2(开发模式)
    • 可能导致每秒数百次调用
    • CPU 占用飙升,页面卡死

正确做法

// ✅ 使用缓存属性
private cachedData: any[] = [];

updateData() {
  this.cachedData = this.compute();  // 只在需要时更新
}

// ❌ 不要在模板中调用方法
getData(): any[] {
  return this.compute();  // 每次变更检测都会调用
}

📞 仍有问题?

提供以下信息:

  1. 控制台完整截图(刷新后)
  2. Elements 面板截图(选中弹窗元素)
  3. Network 面板状态
  4. 执行了哪些修复步骤

修复完成时间:2025-11-19 00:35
修复人:Cascade AI Assistant
状态:✅ 所有代码已修复,等待浏览器刷新生效