8.8 KiB
8.8 KiB
代码审查问题清单
审查范围:
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/2
1/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 秒超时但无进度
undoTimer8 秒后清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) | 功能缺失 |