|
@@ -0,0 +1,169 @@
|
|
|
+# 标记功能 Bug 修复总结
|
|
|
+
|
|
|
+## 问题描述
|
|
|
+点击预定义标记按钮后,标记无法在图像上显示。
|
|
|
+
|
|
|
+## 根本原因分析
|
|
|
+
|
|
|
+发现了两个关键问题导致标记功能失效:
|
|
|
+
|
|
|
+### 1. Action 分发和匹配不一致 ⚠️
|
|
|
+
|
|
|
+**问题位置:** `MarkPanel.tsx` 和 `ViewerContainer.tsx`
|
|
|
+
|
|
|
+**问题描述:**
|
|
|
+- `MarkPanel.tsx` 发送的 action 是 `'AddPredefinedMark:拉姿'` (带参数的字符串)
|
|
|
+- `ViewerContainer.tsx` 的 switch case 匹配的是 `'AddPredefinedMark'` (不带参数)
|
|
|
+- 导致 switch 无法匹配,代码走到 default 分支不执行任何操作
|
|
|
+
|
|
|
+**修复方案:**
|
|
|
+在 `ViewerContainer.tsx` 的 useEffect 中,在 switch 语句之前添加预处理逻辑:
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 预处理带参数的 action
|
|
|
+if (action.startsWith('AddPredefinedMark:')) {
|
|
|
+ const markText = action.substring('AddPredefinedMark:'.length);
|
|
|
+ console.log(`添加预定义标记到图像: ${markText}`);
|
|
|
+ selectedViewportIds.forEach((viewportId) => {
|
|
|
+ addCustomMark(viewportId, markText);
|
|
|
+ });
|
|
|
+ dispatch(clearAction());
|
|
|
+ return;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 2. StackViewer 组件缺少 id 属性 🔴 (关键问题)
|
|
|
+
|
|
|
+**问题位置:** `stack.image.viewer.tsx`
|
|
|
+
|
|
|
+**问题描述:**
|
|
|
+- `addCustomMark` 函数使用 `document.getElementById(currentViewportId)` 来获取元素
|
|
|
+- 但 StackViewer 组件渲染的 `<div>` 没有设置 `id` 属性
|
|
|
+- 导致 `getElementById` 返回 `null`,无法获取元素尺寸和添加标记
|
|
|
+
|
|
|
+**修复方案:**
|
|
|
+给 StackViewer 组件的根 div 添加 id 属性:
|
|
|
+
|
|
|
+```typescript
|
|
|
+return (
|
|
|
+ <div
|
|
|
+ id={viewportId} // ✅ 添加此行
|
|
|
+ ref={elementRef}
|
|
|
+ onContextMenu={(e) => e.preventDefault()}
|
|
|
+ style={{...}}
|
|
|
+ />
|
|
|
+);
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 删除标记功能未实现
|
|
|
+
|
|
|
+**问题位置:** `MarkPanel.tsx`
|
|
|
+
|
|
|
+**问题描述:**
|
|
|
+- `handleDeleteMark` 函数只有 TODO 注释,没有实际实现
|
|
|
+
|
|
|
+**修复方案:**
|
|
|
+```typescript
|
|
|
+const handleDeleteMark = () => {
|
|
|
+ // 触发删除选中标记的action
|
|
|
+ dispatch({ type: 'functionArea/setAction', payload: 'Delete Selected Mark' });
|
|
|
+ console.log('删除选中的标记');
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+## 修改的文件
|
|
|
+
|
|
|
+1. **src/pages/view/components/ViewerContainer.tsx**
|
|
|
+ - 在 useEffect 中添加预处理带参数的 action 逻辑
|
|
|
+ - 移除了原本无法匹配的 `case 'AddPredefinedMark'` 分支
|
|
|
+ - 优化了日志输出
|
|
|
+
|
|
|
+2. **src/pages/view/components/MarkPanel.tsx**
|
|
|
+ - 实现了 `handleDeleteMark` 函数
|
|
|
+
|
|
|
+3. **src/pages/view/components/viewers/stack.image.viewer.tsx**
|
|
|
+ - 给 StackViewer 根元素添加 `id={viewportId}` 属性
|
|
|
+
|
|
|
+## 功能验证
|
|
|
+
|
|
|
+修复后,以下功能应该正常工作:
|
|
|
+
|
|
|
+### ✅ 预定义标记
|
|
|
+- 点击任何预定义标记按钮(拉姿、仰卧、俯卧等)
|
|
|
+- 标记文本应该显示在选中视口的图像中心
|
|
|
+
|
|
|
+### ✅ 时间戳标记
|
|
|
+- 点击时间戳按钮
|
|
|
+- 当前时间(格式:YYYY-MM-DD HH:mm:ss)应该显示在图像上
|
|
|
+
|
|
|
+### ✅ 自定义标记
|
|
|
+- 在输入框输入文本并添加到下拉框
|
|
|
+- 从下拉框选择标记
|
|
|
+- 点击"添加"按钮
|
|
|
+- 自定义文本应该显示在图像上
|
|
|
+
|
|
|
+### ✅ 删除标记
|
|
|
+- 点击"删除标记"按钮
|
|
|
+- 图像上的所有 L 和 R 标记应该被删除
|
|
|
+
|
|
|
+## 技术要点
|
|
|
+
|
|
|
+### Action 预处理模式
|
|
|
+对于带参数的 action,使用字符串前缀匹配的方式:
|
|
|
+```typescript
|
|
|
+if (action.startsWith('ActionPrefix:')) {
|
|
|
+ const param = action.substring('ActionPrefix:'.length);
|
|
|
+ // 处理逻辑
|
|
|
+ dispatch(clearAction());
|
|
|
+ return;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### DOM 元素查询
|
|
|
+当底层函数需要通过 DOM API 访问元素时,确保:
|
|
|
+1. 组件渲染的元素有唯一的 `id` 属性
|
|
|
+2. `id` 值与传递给底层函数的 `viewportId` 保持一致
|
|
|
+
|
|
|
+### LabelTool 使用
|
|
|
+使用 Cornerstone 的 LabelTool 添加文本标记:
|
|
|
+```typescript
|
|
|
+toolGroup.setToolActive(LabelTool.toolName, { bindings: [] });
|
|
|
+const position: Types.Point3 = [x, y, 0];
|
|
|
+LabelTool.hydrate(viewportId, position, text);
|
|
|
+toolGroup.setToolPassive(LabelTool.toolName, { removeAllBindings: true });
|
|
|
+```
|
|
|
+
|
|
|
+## 后续改进建议
|
|
|
+
|
|
|
+1. **标记位置优化**
|
|
|
+ - 目前标记都添加在图像中心
|
|
|
+ - 可考虑实现点击位置添加标记
|
|
|
+
|
|
|
+2. **标记样式定制**
|
|
|
+ - 支持自定义标记颜色、字体大小等
|
|
|
+
|
|
|
+3. **标记持久化**
|
|
|
+ - 考虑将自定义标记列表保存到本地存储
|
|
|
+ - 页面刷新后恢复之前添加的自定义标记
|
|
|
+
|
|
|
+4. **删除功能增强**
|
|
|
+ - 目前只能删除 L 和 R 标记
|
|
|
+ - 应该支持删除所有类型的标记,包括自定义标记和时间戳
|
|
|
+
|
|
|
+5. **错误处理**
|
|
|
+ - 添加更完善的错误处理和用户反馈
|
|
|
+ - 当操作失败时给出明确的提示
|
|
|
+
|
|
|
+## 测试建议
|
|
|
+
|
|
|
+1. 在不同的网格布局(1x1, 1x2, 2x1, 2x2)下测试
|
|
|
+2. 测试选中单个和多个视口的情况
|
|
|
+3. 测试快速连续添加多个标记
|
|
|
+4. 测试添加、删除标记的交替操作
|
|
|
+5. 验证标记在图像旋转、翻转后的表现
|
|
|
+
|
|
|
+## 修复日期
|
|
|
+2025年10月22日
|
|
|
+
|
|
|
+## 修复人员
|
|
|
+Cline AI Assistant
|