fix: undo stack, field insertion wrap, backspace/delete precision; feat: signature size limit & isSigned control

- Replace direct DOM remove() with Range+execCommand('delete') in TemplateManage click and keydown handlers to restore undo stack
- Append ​ zero-width space to smart-field-wrapper HTML in insertSmartField and defaultContent.ts to prevent unwanted line breaks
- Refactor ReportEditor surgeonSignature rendering to depend on isSigned field
- Add isSigned to DEFAULT_FORM_FIELDS (single_select: 已签字/未签字)
- Change surgeonSignature to visibleInForm=true, isSystemLocked=false
- Constrain signature image with max-width:120px, max-height:40px, object-fit:contain in CSS and print.ts
- Add weak-blocking signature validation prompts in saveReport('completed')
- Update experience record (#19)
This commit is contained in:
2026-04-17 12:41:07 +08:00
parent 424407a17e
commit f7c7270053
10 changed files with 367 additions and 13 deletions

View File

@@ -453,6 +453,47 @@ if ((settings.autoInsertDelay || 0) > 0) {
---
## 记录 19撤销栈修复、字段删除交互优化与签名字段闭环
**A. 具体问题**
1. `TemplateManage` 中通过红色 × 或键盘删除智能字段后浏览器撤销栈Undo失效点击"撤销"按钮无法恢复。
2. 插入"手术日期"、"手术者签名"等字段后,字段框有时会跳到下一行。
3. Backspace 键无法删除字段Delete 键会误删字段前面的大段文本(如"手术步骤、术中出现的情况及处理:")。
4. 签名图片没有最大尺寸限制;"手术者签名"字段不在 ReportEditor 表单中显示,无法受控管理签字状态。
5. 点击"完成报告"时缺少对签名状态的确认提示。
**B. 产生问题原因**
1. 删除字段时使用了 `target.remove()` 直接操作 DOM绕过了浏览器的原生撤销栈`undo stack`)。
2. 插入的 `smart-field-wrapper` 是 `inline-block` 元素,但其后缺少行内锚点文本节点,浏览器在特定光标位置插入时容易将其挤到新行。
3. `keydown` 拦截逻辑中 `target.remove()` 同样会误删父级块节点WebKit 在边界处对 `contenteditable="false"` inline 元素的处理缺陷)。
4. `surgeonSignature` 字段原先 `visibleInForm: false`,且签名图片样式仅用 `height: 2.4em` 约束,没有 `max-width/max-height` 的硬限制。
5. 完成报告逻辑中缺少针对签名字段的业务校验。
**C. 解决问题方案**
1. **撤销栈修复**:将点击红 × 删除和键盘 Backspace/Delete 删除全部改为 `Range.selectNode(target)` + `document.execCommand('delete')`。这样浏览器会将删除操作记录到撤销栈中,`execCommand('undo')` 可以正确恢复。
2. **防换行**:在 `insertSmartField` 和 `defaultContent.ts` 的 `smartField()` 生成的 HTML 末尾增加 `​`(零宽空格),作为稳定的行内锚点,防止字段被浏览器排到新行。
3. **精准键盘删除**:配合 `Range.selectNode` + `execCommand('delete')`,不再直接 `remove()` DOM 节点,彻底避免误删父级 `<p>` 的问题。
4. **签名尺寸与字段管理**
- `types.ts` 中将 `surgeonSignature` 改为 `visibleInForm: true, isSystemLocked: false`,使其出现在字段管理和右侧表单中。
- 新增 `isSigned` 字段(单选:已签字 / 未签字,默认"未签字")。
- 签名图片样式改为 `max-width: 120px; max-height: 40px; object-fit: contain;`,并在打印样式和 `print.ts` 中同步。
5. **签名同步逻辑重构**`ReportEditor` 中 `surgeonSignature` 的渲染由 `isSigned` 控制:
- `已签字` 且 `currentUser.signature` 存在 → 显示签名图片。
- `已签字` 但无签名图 → 显示 "【请上传电子签】"。
- `未签字` → 显示 "【未签字】"。
6. **完成报告签名校验**`saveReport('completed')` 中,若模板包含 `surgeonSignature`
- 未选择"已签字" → `confirm` 弱阻断提示。
- 已选择"已签字"但无签名图 → `confirm` 弱阻断提示。
- 用户点击"取消"则中断保存,点击"确定"仍可继续保存。
**D. 后续如何避免问题**
- 在 `contentEditable` 中删除元素时,**优先使用 `Range.selectNode` + `execCommand('delete')`** 而非直接 `remove()`,以确保撤销/重做等原生编辑行为正常工作。
- 插入 `inline-block` 或 `inline-flex` 控件时,可在其后追加 `&#8203;` 零宽空格,为浏览器提供稳定的行内文本锚点,减少排版异常。
- 任何需要从"不可见"改为"可见/可配置"的字段,应在 `DEFAULT_FORM_FIELDS`、`Report 类型`、`reportData 初始值` 三处同步更新,防止表单渲染遗漏。
- 对于图片类嵌入内容,应使用 `max-width`/`max-height` + `object-fit: contain` 做硬约束,避免不同来源图片破坏页面布局。
---
## 记录 14智能字段插入间距修复与 Backspace 防误删
**A. 具体问题**