feat: field hover highlight, e-signature upload, surgeon signature linkage

- Add signature?: string to User type and 'signature' to FieldType
- Add surgeonSignature field to DEFAULT_FORM_FIELDS (category: 图片)
- UserManage: add canvas-based image compression (max 500px) and signature upload UI
- TemplateManage: add hover highlight on field buttons via direct DOM style manipulation
- TemplateManage: add '图片' category to field library for surgeonSignature insertion
- ReportEditor: auto-fill surgeonSignature with currentUser.signature image or placeholder text
- index.css & print.ts: add .report-signature-img styling (height 2.4em, vertical-align middle)
- Update experience record (#18)
This commit is contained in:
2026-04-17 12:04:23 +08:00
parent 0ff1cbe5f0
commit 424407a17e
10 changed files with 445 additions and 4 deletions

View File

@@ -0,0 +1,161 @@
# 实现方案 — 字段悬浮高亮、电子签上传与手术者签名联动2026-04-17-11-34-24
## 一、修改文件清单
1. `src/types.ts` — 扩展 `User` / `FieldType` / `DEFAULT_FORM_FIELDS`
2. `src/pages/UserManage.tsx` — 电子签上传组件 + 前端压缩逻辑
3. `src/pages/TemplateManage.tsx` — 悬浮高亮 + 图片分类 + 手术者签名插入
4. `src/pages/ReportEditor.tsx``surgeonSignature` 特殊同步逻辑
5. `src/index.css` — 签名图片排版样式 + 打印样式
6. `src/utils/print.ts` — 打印样式中增加签名图片规则
## 二、详细改动
### 2.1 `src/types.ts`
- `User` 接口追加 `signature?: string`
- `FieldType` 扩展为 `'text' | 'single_select' | 'multi_select' | 'time' | 'date' | 'signature'`
- `DEFAULT_FORM_FIELDS` 末尾追加:
```ts
{ key: 'surgeonSignature', label: '手术者签名', category: '图片', type: 'signature', visibleInForm: false, isSystemLocked: true }
```
### 2.2 `src/pages/UserManage.tsx`
#### A. 前端压缩工具函数
```ts
const compressImage = (file: File, maxSize: number = 500): Promise<string> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
const img = new Image();
img.src = e.target?.result as string;
img.onload = () => {
const canvas = document.createElement('canvas');
let { width, height } = img;
if (width > height && width > maxSize) {
height = Math.round((height * maxSize) / width);
width = maxSize;
} else if (height > maxSize) {
width = Math.round((width * maxSize) / height);
height = maxSize;
}
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
if (ctx) {
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
}
resolve(canvas.toDataURL('image/jpeg', 0.8));
};
img.onerror = reject;
};
reader.onerror = reject;
});
};
```
#### B. 上传组件与保存逻辑
- 在模态框表单中("状态"选择器下方或底部按钮上方)增加一个区块:
- 标签:"电子签名"
- 若 `formData.signature` 有值,显示压缩后的预览图(高度限制 64px
- "上传签名" 按钮(`type="button"`),触发隐藏的 `<input type="file" accept="image/*">`。
- "清除签名" 按钮(有值时显示)。
- `handleSubmit` 中保存 `signature` 字段到用户对象。
- 编辑当前登录用户时,同步更新 `storage.set('currentUser', currentCached)`,确保 ReportEditor 能立即读取到最新签名。
### 2.3 `src/pages/TemplateManage.tsx`
#### A. 悬浮高亮
在字段库按钮上增加 `onMouseEnter` 和 `onMouseLeave`
```ts
const highlightField = (key: string, active: boolean) => {
if (!editorRef.current) return;
const el = editorRef.current.querySelector(`[data-bind="${key}"]`) as HTMLElement | null;
if (!el) return;
if (active) {
el.style.transition = 'all 0.2s';
el.style.boxShadow = '0 0 0 2px #3b82f6';
el.style.backgroundColor = '#e0f2fe';
} else {
el.style.boxShadow = '';
el.style.backgroundColor = '';
}
};
```
#### B. 图片分类与手术者签名
- 插入字段分类数组从 `['填空', '单选', '多选', '时间']` 改为 `['填空', '单选', '多选', '时间', '图片']`。
- `surgeonSignature` 字段会自动出现在"图片"分类下,按钮点击逻辑复用 `insertSmartField`(已支持唯一性校验)。
### 2.4 `src/pages/ReportEditor.tsx`
在"Sync form state -> rich text field values"的 `useEffect` 中,对 `fieldKey === 'surgeonSignature'` 做特殊分支:
```ts
if (fieldKey === 'surgeonSignature') {
const signatureData = currentUser?.signature;
if (signatureData) {
const imgHtml = `<img src="${signatureData}" class="report-signature-img" alt="签名" draggable="false" />`;
if (el.innerHTML !== imgHtml) {
el.innerHTML = imgHtml;
el.style.border = 'none';
el.style.backgroundColor = 'transparent';
}
} else {
if (el.innerText !== '【请上传电子签】') {
el.innerText = '【请上传电子签】';
el.style.border = '';
el.style.backgroundColor = '';
}
}
return; // 跳过常规文本同步
}
```
### 2.5 `src/index.css`
增加签名图片样式:
```css
.report-signature-img {
height: 2.4em;
width: auto;
vertical-align: middle;
display: inline-block;
margin: -0.3em 0;
}
```
在 `@media print` 中同步增加:
```css
@media print {
.report-signature-img {
height: 2.4em !important;
width: auto !important;
vertical-align: middle !important;
display: inline-block !important;
margin: -0.3em 0 !important;
}
}
```
### 2.6 `src/utils/print.ts`
在打印 iframe 的 `<style>` 标签内,`.smart-field-wrapper` 规则之后追加:
```css
.report-signature-img {
height: 2.4em;
width: auto;
vertical-align: middle;
display: inline-block;
margin: -0.3em 0;
}
```
## 三、风险与回滚
- **风险**`localStorage` 容量有限,压缩后的签名图片通常在 10~50KB单用户存储安全。
- **风险**:旧用户的 `User` 对象没有 `signature` 字段,读取时为 `undefined`,代码中已通过可选链和默认值处理。
- **回滚**:如出现问题,可回退 6 个文件的修改。

View File

@@ -0,0 +1,49 @@
# 测试方案 — 字段悬浮高亮、电子签上传与手术者签名联动2026-04-17-11-34-24
## 一、编译检查
- 执行 `npm run lint``tsc --noEmit`),确保全量 TypeScript 无编译错误。
## 二、功能验证步骤
### 测试 1TemplateManage 字段悬浮高亮
1. 进入【模板管理】,选择默认模板。
2. 将鼠标悬浮在右侧字段库中的"姓名"按钮上(不点击)。
3. 观察编辑器中"姓名"对应的智能字段方框,确认出现蓝色外发光/背景变浅蓝色高亮。
4. 鼠标移开"姓名"按钮,确认高亮效果消失,字段框恢复原样。
5. 尝试悬浮其他字段按钮(如"手术名称"、"手术日期"),确认高亮定位准确。
### 测试 2UserManage 电子签上传与压缩
1. 进入【用户管理】,点击任意医生用户的"编辑"按钮。
2. 在编辑弹窗中找到"电子签名"区域,点击"上传签名"。
3. 选择一张大于 500×500 像素的本地图片(如 1200×800 的 PNG/JPG
4. 确认上传后预览图显示正常,且图片已被等比例压缩(宽或高最大不超过 500px
5. 点击"保存用户",刷新页面后再次编辑该用户,确认签名图片仍然保留。
6. 点击"清除签名",确认预览图消失;保存后刷新,确认签名已清除。
### 测试 3TemplateManage 新增"手术者签名"字段
1. 进入【模板管理】,查看右侧【插入字段】面板。
2. 确认分类列表中新增"图片"分类,下方有"手术者签名"按钮。
3. 点击"手术者签名"按钮,确认模板中插入一个智能字段方框(`data-bind="surgeonSignature"`)。
4. 再次点击"手术者签名",确认弹出"已存在,请勿重复插入"的提示。
### 测试 4ReportEditor 签名自动填充
1. 确保当前登录用户(如 admin已通过测试 2 上传了电子签。
2. 进入【新建报告】或编辑已有报告,观察模板中的"手术者签名"方框。
3. 确认方框中自动显示了当前登录用户的签名图片(高度约 2 行文字)。
4. 在 UserManage 中清除当前用户的签名,返回 ReportEditor 刷新页面。
5. 确认"手术者签名"方框显示文本"【请上传电子签】"。
### 测试 5签名图片排版与打印效果
1. 在 ReportEditor 中确认签名图片与周围文字行高协调,没有明显撑大段落间距。
2. 点击报告页面的"打印"按钮,在浏览器打印预览中观察签名图片。
3. 确认打印输出中签名图片高度仍然保持约 2 行文字,排版正常。
## 三、预期结果
- `npm run lint` 0 错误。
- TemplateManage 悬浮高亮响应迅速,定位准确。
- UserManage 电子签上传、压缩、清除、持久化均正常。
- TemplateManage 可插入"手术者签名"字段,且唯一性校验生效。
- ReportEditor 能自动根据当前用户签名状态填充图片或提示文本。
- 签名图片在编辑态和打印态均保持约 2 行文字高度,排版美观。

View File

@@ -409,6 +409,50 @@ if ((settings.autoInsertDelay || 0) > 0) {
---
## 记录 18字段悬浮高亮、电子签上传与手术者签名联动
**A. 具体问题**
1. `TemplateManage` 中右侧字段库按钮与编辑器中的字段缺乏视觉关联,用户难以快速定位字段位置。
2. `UserManage` 缺少电子签名上传功能,无法为医生绑定个人签名图。
3. 模板中缺少"手术者签名"字段,报告编辑时无法自动带入医生签名。
4. 签名图片若直接放入 `.field-value` 中,容易撑大行高,影响排版和打印效果。
**B. 产生问题原因**
1. 字段库按钮没有任何与编辑器 DOM 联动的交互反馈机制。
2. 早期设计未考虑医疗文书中的电子签需求,`User` 模型和 `DEFAULT_FORM_FIELDS` 均缺少签名相关定义。
3. 没有针对签名图片设计专门的 CSS 尺寸约束,导致浏览器按原图尺寸渲染,破坏行高。
**C. 解决问题方案**
1. **悬浮高亮**:在 `TemplateManage.tsx` 的字段库按钮上增加 `onMouseEnter` / `onMouseLeave`,直接操作编辑器中对应 `data-bind` 的 `.field-value` 的 `style.boxShadow` 和 `style.backgroundColor`,实现蓝色外发光/背景变浅蓝色的即时高亮反馈。
2. **电子签上传与压缩**
- 在 `UserManage.tsx` 中增加 `compressImage(file, maxSize=500)` 工具函数,利用 Canvas 等比例缩放并填充白色背景,输出 JPEG base64质量 0.8)。
- 在用户编辑/新增弹窗中增加"电子签名"区块:预览图、上传按钮、清除按钮。
- 编辑当前登录用户时同步更新 `storage.set('currentUser', ...)`,确保 ReportEditor 能读取最新签名。
3. **手术者签名字段**
- `types.ts` 中 `User` 增加 `signature?: string``FieldType` 增加 `'signature'``DEFAULT_FORM_FIELDS` 追加 `surgeonSignature`(分类"图片",系统锁定)。
- `TemplateManage` 插入字段分类增加"图片"`surgeonSignature` 自动出现在该分类下。
- `ReportEditor` 的"表单 → 编辑器"同步 `useEffect` 中,对 `fieldKey === 'surgeonSignature'` 做特殊分支:有签名则填充 `<img class="report-signature-img" src="..." />`,无签名则填充文本"【请上传电子签】"。
4. **签名排版优化**
- 在 `index.css` 和 `print.ts` 中定义 `.report-signature-img`
```css
.report-signature-img {
height: 2.4em;
width: auto;
vertical-align: middle;
display: inline-block;
margin: -0.3em 0;
}
```
- 打印媒体查询中同步使用 `!important` 确保打印输出也保持同样尺寸。
**D. 后续如何避免问题**
- 当需要在 React 之外直接操作 DOM 样式实现即时反馈时,优先使用原生事件 + inline style避免触发组件重渲染导致光标丢失
- 任何新增的持久化字段应在类型定义TypeScript interface、默认值DEFAULT_xxx、以及所有相关读写逻辑中同步补齐防止类型不一致。
- 在 `contentEditable` 中插入图片时,务必通过 CSS 对 `height`/`width`/`vertical-align` 做严格约束,避免原图尺寸破坏文本流。
- 涉及打印的样式必须在 iframe 打印模板和 `@media print` 中双端同步,防止打印效果与屏幕预览不一致。
---
## 记录 14智能字段插入间距修复与 Backspace 防误删
**A. 具体问题**

View File

@@ -0,0 +1,54 @@
# 需求分析 — 字段悬浮高亮、电子签上传与手术者签名联动2026-04-17-11-34-24
## 一、需求来源
用户提出四个关联需求:优化 TemplateManage 字段定位体验、增加用户电子签上传功能、在模板中新增手术者签名字段、并优化签名图片在编辑器及打印中的排版表现。
## 二、具体需求拆解
### 需求 1TemplateManage 字段悬浮高亮定位
**期望**:当鼠标悬浮在右侧字段库中的某个字段按钮上时,编辑器中已插入的对应 `data-bind` 字段的 `.field-value` 框会有明显的视觉高亮(如边框发光、背景色变化),帮助用户快速定位该字段在模板中的位置。
### 需求 2UserManage 电子签上传与前端压缩
**期望**
- 在【用户管理】的用户编辑/新增弹窗中增加"电子签名"上传区域。
- 支持从本地选择图片文件PNG/JPG 等)。
- 上传后利用 Canvas 在前端自动等比例压缩,使图片的长、宽最大不超过 500 像素。
- 压缩后的图片以 Base64JPEG质量 0.8,白色背景填充透明 PNG形式存储在用户对象的 `signature` 字段中,并持久化到 `localStorage`
### 需求 3TemplateManage 新增"手术者签名"字段
**期望**
-`DEFAULT_FORM_FIELDS` 中新增一个系统锁定字段 `surgeonSignature`,分类为"图片",类型为 `signature`
- `TemplateManage` 的【插入字段】侧边栏中增加"图片"分类,包含"手术者签名"按钮。
- `ReportEditor` 中,当渲染到 `data-bind="surgeonSignature"` 的智能字段时,自动从 `currentUser.signature` 读取电子签图片并填充到 `.field-value` 中;若当前用户没有上传签名,则显示提示文本"【请上传电子签】"。
### 需求 4签名图片在模板中的排版优化
**期望**
- 签名图片在 `.field-value` 中显示时,高度应恰好约等于 2 行文字(约 `2.4em`),宽度等比例自适应。
- 图片垂直对齐方式需与周围文字协调,避免把行高撑得过大。
- 打印输出时(`printDocument``@media print`),签名图片保持同样的高度约束和排版效果。
## 三、影响范围分析
| 文件 | 改动说明 |
|------|----------|
| `src/types.ts` | `User` 接口增加 `signature?: string``FieldType` 增加 `'signature'``DEFAULT_FORM_FIELDS` 追加 `surgeonSignature` 字段。 |
| `src/pages/UserManage.tsx` | 用户编辑弹窗增加电子签上传组件;增加 `compressImage` 前端压缩工具函数;保存时将 `signature` 写入用户对象。 |
| `src/pages/TemplateManage.tsx` | 插入字段分类增加"图片";字段按钮增加 `onMouseEnter` / `onMouseLeave` 事件实现悬浮高亮;`insertSmartField` 增加 `surgeonSignature` 的 HTML 输出(与普通字段一致但 `data-bind="surgeonSignature"`)。 |
| `src/pages/ReportEditor.tsx` | 在"表单 → 编辑器"同步的 `useEffect` 中,对 `surgeonSignature` 做特殊处理:填充 `<img>` 或提示文本。 |
| `src/index.css` | 增加 `.report-signature-img` 的样式规则(高度 `2.4em`、宽度 `auto``vertical-align: middle` 等);增加打印媒体查询中的签名图片样式。 |
| `src/utils/print.ts` | 在打印 iframe 的 `<style>` 中增加 `.report-signature-img` 的样式规则。 |
## 四、验收标准
- [ ] 鼠标悬浮在 TemplateManage 右侧字段按钮上时,编辑器中对应字段框出现高亮边框/背景变化;移开后恢复。
- [ ] UserManage 中可上传电子签图片,上传后预览显示压缩后的图片。
- [ ] 压缩后的图片宽/高均不超过 500px文件体积显著减小。
- [ ] TemplateManage 的插入字段列表中出现"图片"分类及"手术者签名"按钮,可正常插入。
- [ ] ReportEditor 中,`surgeonSignature` 字段自动显示当前登录用户的电子签图片;无签名时显示"【请上传电子签】"。
- [ ] 签名图片在编辑器中高度约 2 行文字,不破坏行高排版;打印输出效果一致。
- [ ] `npm run lint` 无编译错误。