feat: focus highlight, delete-btn visibility isolation, multi_select crash fix

- Move delete-btn to top-right of smart-field-wrapper via absolute positioning
- Add template-editor-mode class to TemplateManage editor for CSS isolation
- Show delete-btn only on hover/focus-within inside template-editor-mode
- Add .field-value:focus highlight with background darken and blue glow
- Sync defaultContent.ts smartField() HTML structure
- Fix ReportEditor multi_select .map crash with Array.isArray guard
This commit is contained in:
2026-04-17 11:21:32 +08:00
parent db5df13a05
commit 0ff1cbe5f0
8 changed files with 273 additions and 11 deletions

View File

@@ -377,6 +377,38 @@ if ((settings.autoInsertDelay || 0) > 0) {
---
## 记录 17字段聚焦高亮、删除按钮显隐隔离与 multi_select 脏数据崩溃修复
**A. 具体问题**
1. `TemplateManage` 中编辑智能字段时缺少视觉焦点反馈,用户体验不够直观。
2. 红色 × 删除按钮始终显示在字段内部左侧,且在任何包含 `smart-field-wrapper` 的页面(包括 `ReportEditor`)都会显示。
3. `ReportEditor` 加载某些历史报告时崩溃,报错 `(y[x.key] || []).map is not a function`。
**B. 产生问题原因**
1. 之前没有为 `.field-value` 定义 `:focus` 状态的 CSS 样式。
2. `delete-btn` 使用 `display: inline-flex` 默认常驻显示,且没有针对页面做显隐隔离。
3. `multi_select` 字段(如 `surgeon`、`assistant`)的渲染直接对值调用 `.map()`,但旧数据或异常存储可能将其保存为字符串(如 `"张医生"` 而非 `["张医生"]`),导致 `.map` 在字符串上调用时抛出 `TypeError`。
**C. 解决问题方案**
1. **聚焦高亮**:在 `index.css` 中为 `.smart-field-wrapper .field-value:focus` 增加背景色加深(`#e2e8f0`)、边框变深(`#94a3b8`)和蓝色外发光(`box-shadow: 0 0 0 2px rgba(59,130,246,0.25)`)的样式,配合 `transition` 实现平滑反馈。
2. **删除按钮定位与显隐隔离**
- 将 `delete-btn` 从字段内部移到 `.field-value` 之后,并给 `.smart-field-wrapper` 增加 `position:relative`,使 `delete-btn` 可绝对定位到右上角(`top: -8px; right: -8px`)。
- 默认 `display: none`;在 `TemplateManage` 的编辑器容器上增加 `template-editor-mode` class通过 `.template-editor-mode .smart-field-wrapper:hover .delete-btn` 和 `:focus-within .delete-btn` 控制仅在 TemplateManage 中悬浮/聚焦时显示。
- `ReportEditor` 的编辑器容器没有 `template-editor-mode`,因此删除按钮不会显示。
3. **类型安全修复**:在 `ReportEditor.tsx` 的 `multi_select` 渲染分支中,增加 `Array.isArray` 检查:
```ts
const rawValue = (reportData as any)[field.key];
const tags = Array.isArray(rawValue) ? rawValue : (rawValue ? [String(rawValue)] : []);
```
确保无论旧数据是数组、字符串还是空值,都能安全渲染为标签列表。
**D. 后续如何避免问题**
- 任何需要在不同页面显隐不同的 UI 元素,应通过容器级 class 做样式隔离,而不是依赖全局显示/隐藏。
- `contentEditable` 控件的焦点状态必须有明确的视觉反馈(背景/边框/阴影变化),否则用户难以感知当前编辑位置。
- 对从持久化存储读取的数组类型数据,在 React 渲染前务必做 `Array.isArray` 校验,防止历史脏数据导致整页崩溃。
---
## 记录 14智能字段插入间距修复与 Backspace 防误删
**A. 具体问题**