实现图像标记管理功能,支持预定义标记和用户自定义标记的添加、显示和管理。
FunctionArea.tsx
中的 "Add Mark" 按钮MarkPanel
YYYY-MM-DD HH:mm:ss
classDiagram
class FunctionArea {
+AddMark 按钮
+handleButtonClick()
}
class OperationPanel {
-currentPanel: string
+renderPanel()
+switchToMarkPanel()
}
class MarkPanel {
-inputText: string
-selectedMark: string
-customMarks: string[]
+renderInputArea()
+renderSelectArea()
+renderPredefinedButtons()
+renderDeleteButton()
}
class ViewerContainer {
-selectedViewportIds: string[]
+handleMarkAction()
+addCustomMark()
}
class StackViewer {
+addLMark()
+addRLabel()
+addCustomMark()
+deleteSelectedMark()
}
class MarkPanelSlice {
-customMarks: string[]
-selectedMark: string
+addCustomMarkToList()
+setSelectedMark()
+addMarkToImage()
+deleteSelectedMark()
}
FunctionArea --> OperationPanel : 触发切换
OperationPanel --> MarkPanel : 渲染面板
MarkPanel --> ViewerContainer : 触发标记动作
ViewerContainer --> StackViewer : 调用底层函数
MarkPanelSlice --> MarkPanel : 状态管理
flowchart TD
A[用户点击 AddMark] --> B{是否已显示 MarkPanel?}
B -->|否| C[切换到 MarkPanel]
B -->|是| D[保持当前面板]
C --> E[显示输入框和下拉框]
D --> E
E --> F[用户输入标记文本]
F --> G[点击添加按钮]
G --> H[文本进入下拉框]
H --> I[用户从下拉框选择标记]
I --> J{选择预定义按钮或时间戳?}
J -->|预定义| K[添加预定义标记到图像]
J -->|时间戳| L[添加当前时间到图像]
K --> M[标记显示在图像上]
L --> M
M --> N{需要删除标记?}
N -->|是| O[点击删除标记按钮]
N -->|否| P[完成]
O --> Q[删除选中的标记]
Q --> P
┌─────────────────────────────────────┐
│ ← 标记管理 │
├─────────────────────────────────────┤
│ 自定义标记输入: │
│ ┌─────────────────────────────────┐ │
│ │ [输入框] [添加] │ │
│ └─────────────────────────────────┘ │
│ │
│ 选择要添加的标记: │
│ ┌─────────────────────────────────┐ │
│ │ [下拉框 ▼] │ │
│ └─────────────────────────────────┘ │
│ │
│ 预定义标记按钮: │
│ [拉姿] [仰卧] [俯卧] [斜倚] │
│ [过屈] [过伸] [内旋] [外旋] │
│ [吸气] [呼气] [负重] [无负重] │
│ [时间戳] │
│ │
│ ┌─────────┐ │
│ │ 删除标记 │ │
│ └─────────┘ │
└─────────────────────────────────────┘
interface MarkPanelState {
customMarks: string[]; // 用户添加的自定义标记列表
selectedMark: string; // 当前选中的标记文本
inputText: string; // 输入框中的文本
selectedViewportIds: string[]; // 选中的视口ID
}
const PREDEFINED_MARKS = [
'拉姿', '仰卧', '俯卧', '斜倚',
'过屈', '过伸', '内旋', '外旋',
'吸气', '呼气', '负重', '无负重'
];
const TIMESTAMP_FORMAT = 'YYYY-MM-DD HH:mm:ss';
sequenceDiagram
participant 用户
participant FunctionArea
participant PanelSwitch
participant OperationPanel
participant MarkPanel
participant Redux
participant ViewerContainer
participant StackViewer
用户->>FunctionArea: 点击 AddMark 按钮
FunctionArea->>PanelSwitch: dispatch(switchToMarkPanel())
PanelSwitch->>OperationPanel: currentPanel = 'MarkPanel'
OperationPanel->>MarkPanel: 渲染 MarkPanel
用户->>MarkPanel: 输入标记文本
用户->>MarkPanel: 点击"添加"按钮
MarkPanel->>Redux: dispatch(addCustomMarkToList(text))
Redux->>MarkPanel: 更新下拉框选项列表
用户->>MarkPanel: 从下拉框选择标记
MarkPanel->>Redux: dispatch(setSelectedMark(text))
用户->>MarkPanel: 点击预定义标记按钮
MarkPanel->>Redux: dispatch(addMarkToImage(selectedMark))
Redux->>ViewerContainer: dispatch(addCustomMark(selectedMark))
ViewerContainer->>StackViewer: 调用addCustomMark函数
StackViewer->>StackViewer: 使用LabelTool添加标记到图像
StackViewer->>用户: 显示标记在图像上
用户->>MarkPanel: 点击删除标记按钮
MarkPanel->>Redux: dispatch(deleteSelectedMark())
Redux->>ViewerContainer: dispatch(deleteSelectedMark())
ViewerContainer->>StackViewer: 调用deleteSelectedMark函数
StackViewer->>用户: 从图像上删除标记
面板切换测试
自定义标记测试
预定义标记测试
时间戳测试
删除功能测试
边界情况测试
src/states/view/markPanelSlice.ts
- 管理标记面板状态src/states/panelSwitchSliceForView.ts
- 添加 MarkPanel 切换功能src/pages/view/components/MarkPanel.tsx
- 标记面板组件stack.image.viewer.tsx
- 支持自定义文本标记OperationPanel.tsx
- 添加 MarkPanel 路由FunctionArea.tsx
- 连接 AddMark 按钮到面板切换这个实现方案确保了功能的完整性和代码的可维护性,同时提供了良好的用户体验和扩展性。
点击预定义标记按钮后,标记无法在图像上显示。
发现了两个关键问题:
Action 分发和匹配不一致 ⚠️
MarkPanel.tsx
发送的 action 是 'AddPredefinedMark:拉姿'
(带参数)ViewerContainer.tsx
的 switch case 匹配的是 'AddPredefinedMark'
(不带参数)StackViewer 缺少 id 属性 🔴 (关键问题)
addCustomMark
函数使用 document.getElementById(viewportId)
获取元素修改的文件:
src/pages/view/components/ViewerContainer.tsx
// 在 switch 前添加预处理逻辑
if (action.startsWith('AddPredefinedMark:')) {
const markText = action.substring('AddPredefinedMark:'.length);
selectedViewportIds.forEach((viewportId) => {
addCustomMark(viewportId, markText);
});
dispatch(clearAction());
return;
}
typescript
// 实现删除标记功能
const handleDeleteMark = () => {
dispatch({ type: 'functionArea/setAction', payload: 'Delete Selected Mark' });
};
src/pages/view/components/viewers/stack.image.viewer.tsx
// 添加 id 属性
return (
<div
id={viewportId} // ✅ 添加此行
ref={elementRef}
...
/>
);
修复后,以下功能正常工作:
详细的修复文档:标记功能Bug修复总结