5.4 KiB
feat/sql-editor-split 分支 PR 前完整 Review 与修复计划
Review 结论(基于两路并行审查,所有发现均已在源码逐行核实)
分支整体架构健康:两轮评审(第一轮 R1-R12、第二轮 SP/ST 编号)的修复痕迹全部可确认(registerOpenTab 原子化、事件契约 33 个事件全带 tabId、appTabBar.css 共享样式、恢复顺序修正、拖拽 owner 校验、四组 disabled、AppTabBar 单生产路径)。发现 1 个高优先级功能 bug、4 个中优先级缺陷、若干低优先级问题,全部有明确修复方案。
审查发现(按严重度)
🔴 P0-1 工具栏 EXPLAIN 按钮把 tab UUID 当 SQL 执行(已核实:App.vue:503)
explain: (tabId: string) => tryExplain(tabId) — tryExplain 第一参数是 sqlOverride: string | snapshot,tabId 类型合法地滑过了编译器,点击任何一组的"执行计划"按钮会把 UUID 当 SQL 去 EXPLAIN,必然后端报错。对照正确写法已存在于 App.vue:3140(tryExplain(undefined, { tabId }))。修复:改为 tryExplain(undefined, { tabId }),并补一条 EditorGroup 挂载测试接真实 actions 断言 explain 调用形状(现有测试 mock 了 actions 只断言收到 tabId,是盲区)。
🟡 P1-1 showDirtyTabCloseConfirm 未同步群组(queryStore.ts:2937)
脏 tab 关闭确认直接写 activeTabId.value = tab.id,不切 focusedGroupId、不改组 active — 确认期间共享结果区跟随脏 tab 而组编辑器显示另一个 tab;确认关闭后焦点跳回原组而非脏 tab 所在组。修复:改为 activateTab(tab.id)。
🟡 P1-2 closeTab 空组剪除不修 sizes(queryStore.ts:3188-3194)
对比 removeTabsFromGroups/moveTabToGroup 都走 pruneEmptyGroups→repairGroupSizes,closeTab 的内联剪除漏了 repairGroupSizes:2 组 [50,50] 关掉一组最后一个 tab 后 sizes 仍 [50,50],单 Pane 可能只占半宽直到手动拖动或重启。修复:剪除后调 repairGroupSizes()(或将内联逻辑改调 pruneEmptyGroups)。
🟡 P1-3 他组卸载会杀死进行中的拖拽(EditorGroupTabBar.vue:507/408)
模块级共享拖拽会话,但每个实例的 onUnmounted(cleanupTabDrag) 无条件清空共享状态 — 拖拽进行中用 Ctrl+W 关掉另一组最后一个 tab,该组卸载会把源栏的 ghost/状态一起清掉。修复:cleanupTabDrag 增加 groupTabDrag.sourceGroupId === props.groupId 守卫(仅拖拽源实例清共享态),监听移除仍无条件执行。
🟡 P1-4 AI 自动执行 danger 分支缺 pendingDangerTabId(App.vue:2333-2335)
dangerSql 直接置值打开对话框但未设 pendingDangerTabId(本分支新增机制),确认时 onDangerConfirm 回退到"确认时刻"的全局 active tab;模态期间 Ctrl+数字仍可切 tab,存在目标漂移窗口 — 与同函数 :2330 已正确传 tabId 的 auto_execute 分支不一致。修复:补 pendingDangerSql.value = sql 同处置 pendingDangerTabId 的途径 — 由于该状态在 useSqlExecution 内部,方案为给 App 暴露的路径统一改走 tryExecute(sql, { tabId })(由它统一设置 pending 态),删除手写的 dangerSql/pendingDangerSql/showDangerDialog 三行。
🟢 低优先级(一并修)
- L1 EditorToolbar.vue:89 残留
[TIER-DBG]console.log(全分支唯一新增调试日志,违反指南阶段6)→ 删除。 - L2 querySurfaces.ts:13/:15
focusSearch()/refreshData()接口声明缺 target 参数(实现已是(target: Element | null),契约漂移)→ 补参数声明。 - L3 EditorGroup.vue:126 模板内联单行 if 花括号(指南 §2.6 边缘项)→ 加花括号。
- L4 双指针并发拖拽会话覆盖(EditorGroupTabBar)→ pointerdown 增加"已有活跃会话则忽略"守卫,一行。
已确认无需修复(审查中排除的疑点)
- 收敛机制无无限循环(迟滞单调性可证);watch getter 依赖追踪正确;快捷键路由三处签名全一致;持久化 payload 类型与两 adapter 完全一致;legacy tabs-only 恢复、pinned 过滤后组修复、editorOnly 守卫全部 9 处 emit 点核查通过;跨栏拖拽 click 抑制依赖 DOM click 公共祖先语义,设计正确。
- reorderTab 无生产调用方(仅 app-tests 使用):保留不改,PR 描述中注明。
执行步骤
- P0-1:App.vue:503 改
tryExplain(undefined, { tabId });在 EditorGroup.mount.spec.ts 增加接真实 editorToolbarActions 注入(非 vi.fn 空壳)断言 explain 链路调用形状的用例。 - P1-1:queryStore showDirtyTabCloseConfirm 改
activateTab(tab.id)。 - P1-2:closeTab 空组剪除后调
repairGroupSizes()。 - P1-3:cleanupTabDrag 加源实例守卫;handleTabPointerDown 加活跃会话守卫(兼修 L4)。
- P1-4:AI danger 分支改走
tryExecute(sql, { tabId })统一 pending 态管理。 - L1-L3:删调试日志、补接口参数、模板花括号。
- 验证:每步跑定向 vitest;全部完成后跑
pnpm typecheck+pnpm lint+pnpm build+git diff --check+ 全量pnpm test -- --maxWorkers=4(维持本分支 1224 文件/11980 用例全绿的基线)。 - 输出:修复完成后给出对照本清单的逐项核销报告;PR 描述建议中注明遗留项(ST1 双 ContentArea 架构灰区、GUI 验收未执行,均已在评审文档记录)。
不做的事
- 不做 ST1 ContentArea 物理拆分(1500+ 行搬移,属独立工作项,评审文档已记录为遗留)。
- 不动 reorderTab 死代码(有测试引用,PR 注明即可)。
- 不新增功能;纯修复本 review 清单。