这是一个典型的"深夜 Bug 奇遇记"。身为开发者,最怕的不是报错,而是那种"看起来好好的,但就是点不动"的静默失效。
今天,我想聊聊我们是如何利用 AI 辅助,像剥洋葱一样,解决了一个困扰用户已久的"待支付弹窗点击失效"问题的。这不仅是一次技术复盘,更是一次关于"人类直觉 + AI 效率"如何深度融合的实战演练。
一、 案发现场:那堵看不见的"透明墙"
想象一下:你选好了心仪的商品,进入订单详情,满怀期待地点击"去支付"。弹窗跳出,你熟练地勾选了 VISA 卡,准备完成最后一步。然而,就在你准备点击"确认支付"时,屏幕仿佛凝固了。
你疯狂点击那个蓝色的按钮,它毫无反应。你尝试点击弹窗的关闭按钮,甚至点击背景,整个页面就像被封在了琥珀里的昆虫,看得见,摸不着。页面上覆盖着一层淡淡的半透明遮罩,仿佛在嘲笑:"别费劲了,此路不通。"
这就是我们收到的用户反馈。通过用户上传的 DevTools 截图,我们捕捉到了一个关键的线索:<body> 标签上被强行注入了一个名为 noclick 的 CSS 类。
在 index.css 中,这个类的定义简单粗暴:pointer-events: none;。
这意味着,整个页面的交互被从物理层面"切断"了。AI 在看到这张截图的第一时间,就通过自然语言处理和图像识别逻辑,敏锐地指出:"这是一个全局禁用点击的逻辑失控导致的界面锁死。"
二、 逻辑考古:在代码迷宫中寻找"锁匠"
面对几万行代码的工程,手动去搜 noclick 就像在森林里找一片特定的叶子。这时候,AI 成了我们的"高精地图"。
我们给 AI 下达了指令:在工程内检索"待支付"、"payment"、"noclick"、"lockButtonId"等关键词,并梳理它们的调用链路。
很快,AI 帮我们串联出了一条隐藏在深处的"作案路径":
起点:订单详情页(order/DetailNew/Life)触发支付弹窗。
中转站:弹窗组件 Pay/Win/Win.js 被唤起,内部调用了核心支付逻辑 Paying()。
核心区域:Pay/Paying/Paying.js 进一步调用 PaySDK.js。
关键动作:在 PaySDK 中,为了防止用户在支付请求发出后多次点击(防止重复扣款),系统会调用 getLockTarget 获取一个目标,并给它加上 noclick 类。
真相大白:
AI 指出了问题的命门:在 PaySDK 的逻辑里,如果调用者没有传入具体的 lockButtonId,getLockTarget 函数会默认返回 document.body。
在 VISA 支付场景下,由于涉及跨境跳转或较长的验证等待,代码执行了"加锁"操作,但由于弹窗组件在调用 Paying() 时忘了传按钮 ID,系统直接反手给整个 body 加上了锁。弹窗虽然在视觉上层级最高,但它本质上也是 body 的子元素。当父节点被禁用了所有点击事件,子节点自然也成了"陪葬品"。
三、 手术方案:从"大砍刀"到"手术刀"
找到了根因,修复方案也就呼之欲出了。我们的目标很明确:防重点击不能丢,但范围必须收窄。
1. 精确制导:只锁按钮,不锁全城
我们修改了 Win.js,为"确认支付"按钮分配了一个唯一的 ID。当用户点击支付时,我们明确告诉 Paying 函数:"请只锁住这个按钮,放过其他的区域。"
2. 状态驱动:增加人情味的 Loading
仅仅禁用点击是不够的。好的交互应该告诉用户"我正在努力工作"。我们引入了 isPaying 状态,当支付进行中,按钮不仅会因为 noclick 无法点击,还会进入 disabled 状态并展示转圈的 loading 动画。
3. 容错机制:别让用户永远等下去
万一网络断了?或者支付接口超时了?如果锁一直不解开,用户就只能刷新页面。我们参考了项目中其他成熟模块的写法,增加了失败与超时的恢复逻辑。通过定时器和轮询机制,一旦检测到支付结束(无论成功或失败),立即移除 noclick。
四、 AI 的二次进化:一场严苛的代码评审
在方案落地阶段,AI 展现出了它作为"高级架构师"的严谨。在 Code Review 环节,AI 对我的初步代码提出了几点"不留情面"的建议:
防御性编程:AI 提醒我,payType.channelName 在某些极端情况下可能是 undefined,直接调用 toLowerCase() 会导致页面白屏。必须加上可选链(?.)或空值判断。
消除"魔法数字":我在代码里随手写了个 3000ms 的超时,AI 建议将其提取为常量 PAYMENT_TIMEOUT,并放在统一的常量定义文件中,以维持项目的可维护性。
一致性检查:AI 对比了项目中 Life 和 Ticket 模块的支付实现,建议我沿用它们的命名规范,确保后续开发者维护时不会感到违和。
这种层层递进的优化,不仅解决了 Bug,更提升了代码的工业级美感。
五、 结语:当技术有了"温度"
回顾整个过程,这次问题的解决并非单纯的代码堆砌。
如果没有 AI,我们可能需要花费数倍的时间在枯燥的代码跳转中;如果没有对用户体验的敬畏,我们可能只是随便修补一下,而忽略了超时恢复和 Loading 提示。
技术本质上是冷的,但解决问题的初衷应该是热的。防重复点击的初衷是为了保护用户的钱包,但如果因为实现手段的粗糙而锁死了用户的操作,这种"保护"就变成了"阻碍"。
通过这次复盘,我们深刻意识到:AI 不是要取代程序员,而是要把程序员从繁琐的"考古"和"捉虫"中解放出来,去思考更重要的事情——如何构建一个既安全又优雅的系统。
现在的订单详情页,那个"待支付"弹窗依然会准时出现。但在 VISA 勾选后的每一次点击里,不再有消失的响应,取而代之的是清晰的反馈和流畅的体验。这就是我们作为开发者,在 AI 时代交给用户的最好答卷。