# 标记功能 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 组件渲染的 `
` 没有设置 `id` 属性 - 导致 `getElementById` 返回 `null`,无法获取元素尺寸和添加标记 **修复方案:** 给 StackViewer 组件的根 div 添加 id 属性: ```typescript return (
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