-
Slice Navigator
-
- {safeSlice + 1} / {Math.max(totalSlices, 1)}
-
+
+
+
+ {dicomPreview ? (
+
+
+
+
+ ) : (
+
+ {dicomStatus}
+
+ )}
+
+
+
+
+ {overlayStatus}
+
+ {overlayStats.activeModules}/{visibleModuleCount} 构件 · {overlayStats.segmentCount} 边 · {overlayStats.filledPixels} px
+
+
+
+ {overlayStats.modules.length ? (
+
+ {overlayStats.modules.map((item) => (
+
+
+ {item.name}
+ ID {item.partId}
+ {item.segmentCount} 边
+ {item.filledPixels} px
+
+ ))}
+
+ ) : (
+
+ 当前切片暂无可见构件
+
+ )}
+
+
-
+
+
);
diff --git a/WebSite/src/index.css b/WebSite/src/index.css
index a2cd6ee..eb6b25f 100644
--- a/WebSite/src/index.css
+++ b/WebSite/src/index.css
@@ -116,3 +116,61 @@
.mapping-slice-input:active::-moz-range-thumb {
cursor: grabbing;
}
+
+.mapping-slice-vertical-input {
+ appearance: none;
+ -webkit-appearance: none;
+ background: transparent;
+ height: 100%;
+ inset: 0;
+ position: absolute;
+ width: 100%;
+ direction: rtl;
+ writing-mode: vertical-rl;
+}
+
+.mapping-slice-vertical-input:focus {
+ outline: none;
+}
+
+.mapping-slice-vertical-input::-webkit-slider-runnable-track {
+ background: transparent;
+ border: 0;
+ width: 8px;
+}
+
+.mapping-slice-vertical-input::-webkit-slider-thumb {
+ appearance: none;
+ -webkit-appearance: none;
+ background: #22d3ee;
+ border: 3px solid #0f172a;
+ border-radius: 9999px;
+ box-shadow: 0 0 0 4px rgba(34, 211, 238, 0.16), 0 8px 18px rgba(8, 47, 73, 0.45);
+ cursor: grab;
+ height: 22px;
+ width: 22px;
+}
+
+.mapping-slice-vertical-input::-moz-range-track {
+ background: transparent;
+ border: 0;
+ width: 8px;
+}
+
+.mapping-slice-vertical-input::-moz-range-thumb {
+ background: #22d3ee;
+ border: 3px solid #0f172a;
+ border-radius: 9999px;
+ box-shadow: 0 0 0 4px rgba(34, 211, 238, 0.16), 0 8px 18px rgba(8, 47, 73, 0.45);
+ cursor: grab;
+ height: 16px;
+ width: 16px;
+}
+
+.mapping-slice-vertical-input:active::-webkit-slider-thumb {
+ cursor: grabbing;
+}
+
+.mapping-slice-vertical-input:active::-moz-range-thumb {
+ cursor: grabbing;
+}
diff --git a/工程分析/实现方案-2026-05-20-15-33-38.md b/工程分析/实现方案-2026-05-20-15-33-38.md
new file mode 100644
index 0000000..d68d237
--- /dev/null
+++ b/工程分析/实现方案-2026-05-20-15-33-38.md
@@ -0,0 +1,51 @@
+# 实现方案:右侧竖向 Slice Navigator 与影像遮挡治理
+
+实现方案文档路径:`工程分析/实现方案-2026-05-20-15-33-38.md`
+
+## 修改目标
+
+调整逆向分割映射视图布局:将切片导航从影像底部迁移到右侧竖向栏,并把 Overlay Label Map 的构件统计面板从影像内部移到影像下方,避免遮挡 DICOM 影像。
+
+## 涉及路径
+
+- `WebSite/src/components/ReverseWorkspace.tsx`
+- `工程分析/需求分析-2026-05-20-15-33-38.md`
+- `工程分析/实现方案-2026-05-20-15-33-38.md`
+- `工程分析/测试方案-2026-05-20-15-33-38.md`
+- `工程分析/经验记录.md`
+
+## 技术路线
+
+1. 定位 `VoxelizationMappingView` 中当前底部 `Slice Navigator` 与影像内 Overlay 状态面板。
+2. 将组件整体布局改为横向网格:左侧影像与独立信息区,右侧竖向切片导航栏。
+3. 保留顶部 `Base DICOM`、`Overlay Label Map`、`Z` 状态标签,但缩小为影像角落提示,避免大面积遮挡。
+4. 将构件统计列表改为影像下方独立面板,显示当前 Overlay 状态、构件数、边数、像素数和当前切片构件表。
+5. 为竖向 range 增加内联样式或类名,使用 `writingMode: 'vertical-rl'` 与 `direction: 'rtl'` 实现从上到下浏览切片。
+6. 执行类型检查、构建、部署验证。
+
+## 执行步骤
+
+- 阅读当前 `VoxelizationMappingView` JSX 与相关样式。
+- 修改布局结构和样式。
+- 检查 `mapping-slice-input` 是否有全局 CSS 影响,必要时增加独立竖向类。
+- 运行 `npm run lint` 和 `npm run build`。
+- 重启 `tmux` 服务并验证健康接口和首页。
+- 更新测试方案与经验记录。
+- 精确暂存、提交并推送 Gitea。
+
+## 兼容性与回滚方案
+
+- 该改动只影响前端布局,不改变数据结构和 API。
+- 如竖向 `range` 在某浏览器显示异常,可回滚为右侧竖排按钮加数值输入,或补充 WebKit 专用 CSS。
+- 项目库复用同一组件,因此无需额外复制样式逻辑。
+
+## 预计文件变更
+
+- `WebSite/src/components/ReverseWorkspace.tsx`
+- 本轮工程分析文档与 `工程分析/经验记录.md`
+
+## 提交与部署策略
+
+- 暂存本轮相关代码和工程分析文档。
+- commit message 包含 `2026-05-20-15-33-38`。
+- 推送 Gitea 后重启 `revoxelseg-dicom` 服务,验证 `http://127.0.0.1:4000/api/health` 与首页。
diff --git a/工程分析/测试方案-2026-05-20-15-33-38.md b/工程分析/测试方案-2026-05-20-15-33-38.md
new file mode 100644
index 0000000..5f5c861
--- /dev/null
+++ b/工程分析/测试方案-2026-05-20-15-33-38.md
@@ -0,0 +1,55 @@
+# 测试方案:Slice Navigator 竖向外置与 Overlay 遮挡检查
+
+测试方案文档路径:`工程分析/测试方案-2026-05-20-15-33-38.md`
+
+## 静态检查
+
+- 确认 `VoxelizationMappingView` 的 `Slice Navigator` 不再位于影像画布底部内部。
+- 确认切片导航栏位于影像右侧,并使用竖向 `range`。
+- 确认构件统计面板不再用绝对定位覆盖 DICOM 影像。
+- 确认 `Base DICOM` 和 `Overlay Label Map` 仅作为小标签显示,不遮挡主体区域。
+
+## 构建检查
+
+- 在 `WebSite/` 执行 `npm run lint`。
+- 在 `WebSite/` 执行 `npm run build`。
+
+## 关键业务场景验证
+
+- 逆向工作区中拖动右侧竖向切片条可以切换当前 Z 层。
+- 上下按钮仍可逐层切换。
+- DICOM 原始影像和 Overlay Label Map 不被构件列表遮挡。
+- 项目库中复用的逆向分割映射视图保持可用。
+
+## 医学影像数据相关边界验证
+
+- 不修改 DICOM/STL 原始数据。
+- 不改变体素化、求交、光栅化和导出逻辑。
+- 仅调整浏览控件与信息面板的位置,保证影像主体可审查。
+
+## 部署验证
+
+- 验证 `http://127.0.0.1:4000/api/health`。
+- 验证 `http://127.0.0.1:4000/` 返回 200。
+
+## Git/Gitea 备份验证
+
+- commit message 包含 `2026-05-20-15-33-38`。
+- 推送 Gitea 成功后记录 commit。
+- 确认未暂存历史删除状态、软著材料和运行态文件。
+
+## 风险与回归关注点
+
+- 竖向 range 的浏览器兼容性。
+- 小屏幕下右侧导航栏是否挤压影像宽度。
+- 项目库复用组件后的宽度约束是否仍能正常显示。
+
+## 执行结果
+
+- `npm run lint`:通过,TypeScript 无报错。
+- `npm run build`:通过,Vite 完成生产构建;仅保留当前项目已有的大 chunk 体积提示。
+- 静态确认:`VoxelizationMappingView` 已移除底部横向 `Slice Navigator`,改为右侧竖向 `mapping-slice-vertical-input`。
+- 静态确认:Overlay 构件统计面板已从影像绝对定位层移到影像下方独立区域,不再遮挡 DICOM 画布。
+- 部署验证:已重建 `tmux` 会话 `revoxelseg-dicom`,执行 `npm run serve -- --host 0.0.0.0 --port 4000`。
+- `curl -fsS http://127.0.0.1:4000/api/health`:通过,返回 `{"ok":true,"service":"revoxelseg-dicom",...}`。
+- `curl -I -fsS http://127.0.0.1:4000/`:通过,返回 `HTTP/1.1 200 OK`。
diff --git a/工程分析/经验记录.md b/工程分析/经验记录.md
index 0eec2b8..192ce54 100644
--- a/工程分析/经验记录.md
+++ b/工程分析/经验记录.md
@@ -1297,3 +1297,21 @@ C. 解决问题方案
D. 后续如何避免问题
凡是用户要求两个页面“效果一致”,优先抽取或导出已有真实组件,不再维护第二套近似 UI。涉及密码、权限、删除等高风险管理操作时,必须把资料编辑和凭据修改拆成不同入口,并通过显式标签、校验和反馈减少误操作。
+
+## 2026-05-20-15-33-38 医学影像视图控件不要覆盖审查画布
+
+A. 具体问题
+
+用户指出逆向工作区的 `Slice Navigator` 格式与“DICOM 切片范围”不统一,并且 Overlay Label Map 的构件统计区域会遮挡 DICOM 影像,影响对二维切片和叠加分割结果的审查。
+
+B. 产生问题原因
+
+此前 `VoxelizationMappingView` 为了紧凑展示,把切片导航放在视图底部,同时将 Overlay 状态和构件列表使用绝对定位压在影像画布底部。该设计在普通预览中节省空间,但在医学影像核验场景中会遮挡 DICOM 主体区域。
+
+C. 解决问题方案
+
+将视图结构调整为“影像画布 + 右侧竖向切片导航 + 下方 Overlay 统计面板”:右侧竖向导航使用独立 `mapping-slice-vertical-input`,显示当前 DICOM 切片位置和上下层按钮;Overlay 构件列表移到画布下方,不再覆盖 DICOM 影像。
+
+D. 后续如何避免问题
+
+医学影像主画布应优先保持无遮挡,状态、统计、导航控件默认放在画布外侧。若必须悬浮在影像上,只能使用小尺寸状态标识,并在提交前检查是否遮挡解剖结构或分割边界。
diff --git a/工程分析/需求分析-2026-05-20-15-33-38.md b/工程分析/需求分析-2026-05-20-15-33-38.md
new file mode 100644
index 0000000..750f7ec
--- /dev/null
+++ b/工程分析/需求分析-2026-05-20-15-33-38.md
@@ -0,0 +1,53 @@
+# 需求分析:逆向映射视图切片导航外置与遮挡优化
+
+开始时间:`2026-05-20-15-33-38`
+
+## 原始需求摘要
+
+用户要求修改逆向工作区:
+
+1. 将逆向工作区中 `Slice Navigator` 的格式与“DICOM 切片范围”的格式统一,不要放在图片里面。
+2. `Slice Navigator` 调整为竖向滚动条,放在图片右侧。
+3. `Overlay Label Map` 部分不要遮挡 DICOM 影像。
+
+## 业务目标
+
+- 让二维逆向分割映射视图的切片浏览控件不压住医学影像主体。
+- 保持切片导航与中部工具栏内“DICOM 切片范围”控件在视觉语义上统一。
+- 避免状态说明、构件统计面板遮挡 DICOM 原始影像和分割叠加区域,提升临床审查可读性。
+
+## 输入与输出
+
+输入:
+
+- `WebSite/src/components/ReverseWorkspace.tsx`
+- 复用该组件的 `WebSite/src/components/ProjectLibrary.tsx`
+
+输出:
+
+- `VoxelizationMappingView` 的切片导航从底部内嵌区域改为右侧竖向导航栏。
+- 右侧导航栏显示当前层数、竖向 range 控件和上下切片按钮。
+- 构件统计面板移出影像画布覆盖层,作为影像下方独立信息区展示。
+
+## 影响范围
+
+- 逆向工作区“逆向分割映射视图”。
+- 项目库中复用的“逆向分割映射视图”。
+- 相关 Tailwind 样式和 TypeScript 类型检查。
+
+## 关键约束
+
+- 不改动 STL/DICOM 映射算法,只调整控件布局和遮挡关系。
+- 影像主体区域仍需保持 Base DICOM 与 Overlay Label Map 的标签提示。
+- 竖向切片条需要可拖动、可点击上下按钮、可通过键盘/辅助技术识别。
+- 不能把无关工作区历史删除和软著材料纳入提交。
+
+## 风险点
+
+- 原生 `range` 竖向显示在不同浏览器上需要兼容写法。
+- 切片导航移出底部后,需要保证容器高度和图片区域不会被挤压到不可用。
+- 项目库复用同一组件,布局变化会同步影响项目库,需要保持宽窄视口可用。
+
+## 默认假设
+
+- 用户所说“Overlay Label Map 部分”主要指当前切片构件统计和状态面板遮挡 DICOM 影像,而不是取消分割掩码本身;分割掩码仍应叠加显示。