Files
workspace/code/fms/问题.md
T
2026-08-26 17:31:31 +08:00

8.8 KiB
Raw Blame History

代码审查问题清单

审查范围:ModuleEditConfigPanel.vue(4510 行)、index.vue、FieldGroupManager.vue、FmsTable.vue 日期:2026-08-26


一、功能性 bug(会真实出错)

1. 子表预览弹窗没有打开入口

P1

  • previewOpen 定义于 ModuleEditConfigPanel.vue:611,弹窗渲染于 1998–2087 行
  • 全文件检索不到任何设置 previewOpen = true 的地方,也没有「预览」按钮
  • 弹窗 :open 永远为 false → 子表预览功能不可达
  • tableColumnRows/previewGroupHeader/列宽拖拽手柄那一整套 WYSIWYG 预览全被闲置

2. libGroup/columnGridGroup 分组配置不一致(跨分组拖拽可能失效)

  • 字段库:libGroup = { name: 'form', pull: 'clone', put: false }(1461 行)
  • 子表列网格:columnGridGroup = { name: 'form' }(1464 行)→ 子表列之间可以互相移动
  • 主表画布网格:内联 :group="{ name: 'form' }"(2165 行),默认 pull: true → 字段库(put: false)往主表画布放 → 会被 SortableJS 拒绝
  • 主表模式其实有自己的 onLibDragEnd(1368 行)兜底逻辑,注释也说"源=字段库,目标列表只收到 add/sort"
  • 这是一个「看起来会被拒、实际靠 onLibDragEnd 兜底」的双轨实现——逻辑相当绕,一旦某个 onMove/onStart/onEnd 时序变化就会暴露。主表拖入的可靠性完全押在 sortable 事件顺序上,比较脆弱。

3. 分组标题重命名有 blur/点击竞态(很可能被覆盖丢改动)

  • commitEditGroupTitle 同时绑定在输入框 @blur 和确认按钮 @mousedown.prevent(1806、1816、1824 行)
  • 在按钮上按下鼠标 → @mousedown.prevent 阻止了默认行为,不会先触发 blur,顺序基本 OK
  • 真正的坑是:直接点「删除分组」或拖拽到其它分组时,输入框先失焦提交、随后 updateGroups/syncList 把 props.groups 换成新数组,但 groupTitleDraft 只在 commit 里清。整体靠时序兜底,多步操作间容易丢改动(详见第 11 条联动问题)。

4. 表格模式下列宽与 b_height 语义混乱

P0

  • formDataColumns(315 行)里 b_height 是「文本域高度」,但 b_height 会被 normalizedRow 统一 Number() 化(160 行);表格模式 tableDataColumns 没有 b_height 列
  • b_width 在 diff/save 时会被完整提交——它既不是后端字段也不是 UI 控件,只是一次拖拽调宽的临时状态,随保存写库会造成脏数据(后端 s_field_edit 若没有该列,update 会因"字段不存在"报错或写进多余列)
  • 栅格宽度口径不一致:主表设计视图用「24 栅格」,但 COLSPAN_OPTIONS(428 行)写的是 整行 24/24 / 2/3 行 16/24 / 半行 12/24…——文本写着 24 栅格,但 spanOf 支持 1~24,b_colspan 默认 24。如果后端 b_colspan 存的是 12 制(计划文档 §10.2 说"12 栅格"),前端按 24 制渲染会导致整行永远多一倍宽。需要和后端表结构核对,目前前后端口径不一致的风险很高。

二、交互体验问题

5. 字段库「点击=添加」与「拖拽=添加」语义不一致

P1

  • 点击字段库项 → selectField(862 行):已加入的字段再点击会被移除(867 行)
  • 拖拽字段到画布 → 已在表单中会被 Message.warning 拒绝(1386 行)
  • 同一动作两种结果,用户容易误删字段。建议点击已加入项改为「定位选中」,把移除收敛到 Delete/删除按钮。

6. 拖拽意图判定在窄卡片上极易误判

  • updateDragIntent(959 行)按「鼠标到卡片四条边的归一化最近距离」决定插入方向(1024-1030 行)
  • 字段卡片通常只有 1/21/4 行宽(约 150300px),宽高比很大,左右方向几乎总是胜出 → 用户想「拖到下一行」时总是落在同行前后
  • 加上 hover 自身只给上/下(998-1009 行),两种判定阈值不一致,操作学习成本高、误操作率高

7. 拖拽期间 dragLine 只清不锁

  • Esc 取消只清 dragLine/dragOverSection(125-129 行),SortableJS 的拖拽会话仍继续
  • 中途 Esc 后继续移动,onDragShadowMove 会重新计算 intent,表现为"取消失效"

8. 撤销栈是「操作级」而非「原子级」,且深度受限

  • pushHistory 只压 snapshotRows(浅拷贝数组),相邻重复快照去重(99 行)
  • onColspanInput(1503)每次 input 事件压栈 → 连续输入数字产生 N 个撤销点
  • onWidthInput(533)同样逐键压栈
  • 列宽拖拽 startColumnResize 压一次但 onColumnResizeMove 每帧改 row.b_width,mouseup 时才 emit → 撤销栈里的中间宽度和最终宽度不一致,Ctrl+Z 会跳到拖拽中间值
  • 这些组合下 30 条 HISTORY_LIMIT 很快就耗尽,且撤销点不直观

9. 删除字段的「撤销提示条」有 8 秒超时但无进度

  • undoTimer 8 秒后清 lastDeleted(1539 行),提示条消失且无倒计时/动画提示
  • 若用户晚于 8 秒想恢复,只能靠 Ctrl+Z(且此时 Ctrl+Z 撤销的是整表快照,会连带恢复已删除的字段布局,可能更糟)

10. 分组方向(左右/上下)开关被隐藏

  • toggleLayout 定义在 FieldGroupManager.vue:111,但只有「分组管理」弹窗里每个节点有该按钮(280-283 行)
  • 主画布上只有 hover 才出现的分组删除按钮,画布上没有任何分组方向切换入口——用户必须打开弹窗才能调左右布局,体验割裂

11. 删除分组直接改动 listConfig/editConfig,但不进撤销栈

  • deleteGroupDirect(760 行)会改 props.listConfig(syncList)并把字段移未分组
  • 但这些改动不推入 history,Ctrl+Z 无法回退分组删除本身(只能回退字段归属)

三、一致性与可维护性

12. formDirection/globalDirection 死代码

P0

  • formDirection = computed(() => globalDirection.value)(644 行)引用的 globalDirection 全文件不存在
  • 该 computed 会在首次求值时抛 ReferenceError,任何路径访问 formDirection 都会崩
  • 目前没人引用它所以没炸,但这是颗定时炸弹

13. 大量字段/状态重复定义

  • FIELD_TYPE_LABELS(416)在 libraryGroups(667)和 controlTypeLabel(468)各用一次,类型集散落在 placeholderOf(481)、defaultWidthOf(512)、SAMPLE_TEXT(628)、field-control 模板(2254-2298)四处,新增类型要改五个地方
  • 属性面板(主表 2527、子表 2385)几乎整段重复,只有宽度/高度两处不同
  • COLSPAN_OPTIONS 只在数据视图用(363 行 editor: { type: 'select', options: () => COLSPAN_OPTIONS }),设计视图属性面板用的是 mm-fdesign__span-control 数字输入框,两处口径(24 制 vs 数字 1-24)分开维护

14. placeholderOf 只读字段被忽略

  • placeholderOf(481 行)返回默认占位符,但 placeholder 在画布控件上是只读展示(tabindex="-1" + pointer-events:none)
  • 属性面板里根本没有占位符编辑入口(只有数据视图的 FmsTable 有 b_placeholder 列)
  • 即设计视图里无法设置占位符——功能存在但 UI 缺失

15. 快捷键在「预览(数据视图)」视图下静默失效

  • onDesignerKeydown 要求 viewMode === 'design'(1569 行),但数据视图的 FmsTable 里 Ctrl+C/V/Z 会被浏览器/表格接管
  • 设计视图的复制/撤销/Delete 快捷键全不生效,且没有任何提示(帮助浮层只在设计视图头部)
  • 用户切到数据视图按 Delete 想删字段会直接没反应

16. 无保存时「重载」与「切换」的确认文案不一致

  • index.vue 用两个不同的弹窗:重载用通用 showConfirm(236-244),切换用专门的 switchConfirm(332-341、1221-1236)
  • 两个弹窗行为基本一致但代码/文案/按钮布局重复
  • 切换弹窗缺「保存并切换失败时的错误提示」路径:onSwitchSave 里 saveModule() 返回 false 时直接留在弹窗,没有给用户反馈为什么失败

建议优先级

优先级 事项 理由
P0 修 formDirection/globalDirection 死代码(#12) 一旦有人引用就崩
P0 统一 24/12 栅格口径,核对 b_colspan 后端字段(#4) 前后端不一致=整行渲染错误
P1 给子表预览加入口或移除死代码(#1) 功能不可达
P1 撤销栈改「原子操作」+ 修复列宽拖拽中间态(#8) 直接影响日常编辑
P1 字段库点击/拖拽语义统一(#5) 防误删
P2 拖拽意图判定、Esc 取消锁定、删除分组入撤销栈等(#6/#7/#11) 打磨体验
P2 占位符编辑入口、分组方向画布入口、数据视图快捷键(#14/#10/#15) 功能缺失