# 经验记录 本文件用于记录项目修改过程中的关键问题与解决方案。每条经验使用四段式结构。 ## 2026-05-04-02-38-48 建立代码编纂工作流 A. 具体问题 当前项目尚无统一的需求分析、实现方案、测试方案、经验沉淀和备份提交流程,后续修改容易缺少可追溯记录。 B. 产生问题原因 项目仍处于早期建设阶段,已有前端工程和医学影像数据资产,但尚未建立工程治理文档与固定执行规范。 C. 解决问题方案 创建 `工程分析/` 目录,新增工程整体分析、代码编纂工作流、本次需求分析、实现方案、测试方案和经验记录文档。后续项目修改必须先写文档,并在实现方案和测试方案阶段等待用户二次人工审核确认。 D. 后续如何避免问题 每次项目修改前先记录时间戳并阅读 `工程分析/工程整体分析.md` 与 `工程分析/经验记录.md`。修改前写入需求、实现和测试文档,确认后再执行,完成后追加经验记录并提交 Gitea 备份。 ## 2026-05-04-02-38-48 Gitea 推送后的本地凭据清理 A. 具体问题 使用带账号信息的一次性推送地址完成 Gitea push 后,本地 `branch.main.remote` 曾记录为带账号信息的 URL。 B. 产生问题原因 `git push -u main` 会把该 `` 记录为当前分支上游,而不是只使用已配置的 `origin` 名称。 C. 解决问题方案 将 `origin` 保持为不含账号信息的仓库地址,并把 `branch.main.remote` 改回 `origin`、`branch.main.merge` 改为 `refs/heads/main`。 D. 后续如何避免问题 后续推送时优先使用已配置好的 `origin`。如果必须临时带认证信息推送,推送后立即检查 `git config --get-regexp 'branch\\.main|remote\\.origin'`,确保本地配置中没有保存账号密码。 ## 2026-05-04-02-38-48 开发服务端口占用 A. 具体问题 本项目默认 Vite 端口 `3000` 已被 `/home/wkmgc/Desktop/Seg_Server` 的 node 服务占用,无法直接作为本项目部署端口。 B. 产生问题原因 同一机器上已有其他项目服务监听 `0.0.0.0:3000`。 C. 解决问题方案 不停止既有服务,改用 `3001` 端口启动当前项目的 Vite 服务,并通过 `curl -I http://127.0.0.1:3001/` 验证返回 `HTTP/1.1 200 OK`。 D. 后续如何避免问题 部署前先使用 `ss -ltnp` 检查目标端口。如果默认端口被占用,优先选择相邻可用端口并在测试方案执行结果中记录实际访问地址。 ## 2026-05-04-02-38-48 后台部署进程托管 A. 具体问题 使用普通 `nohup` 后台启动 Vite 时进程会静默退出,无法稳定保留服务。 B. 产生问题原因 当前命令执行环境会回收普通后台子进程,导致 `nohup` 方式没有形成稳定部署。 C. 解决问题方案 使用 `tmux new-session -d -s revoxelseg-dicom` 托管 Vite 服务,使开发服务脱离当前命令执行会话独立运行。 D. 后续如何避免问题 需要保留长时间运行的开发服务时,优先使用 `tmux` 会话托管,并用 `tmux capture-pane -pt ` 查看启动日志,用 `curl` 验证 HTTP 响应。 ## 2026-05-04-03-08-20 附件 logo 落盘与静态资源引用 A. 具体问题 用户要求将 title 图标、登录页 logo 和左上角 logo 都替换为对话中提供的图片,需要把附件图片变为前端可稳定访问的静态资源。 B. 产生问题原因 前端组件不能直接引用对话附件,必须先将图片保存到项目静态资源目录,再通过固定 URL 引用。 C. 解决问题方案 确认 `/tmp/logo_check.png` 与用户提供的 logo 一致后,将其复制到 `WebSite/public/logo.png`。`index.html` favicon、登录页和侧边栏统一通过 `/logo.png` 引用。 D. 后续如何避免问题 后续涉及用户上传图片替换项目资源时,先在本地确认附件是否已落盘;优先放入 `WebSite/public/` 并使用根路径引用,避免组件间重复存放资源。 ## 2026-05-04-03-08-20 指定端口重新部署 A. 具体问题 用户要求将项目部署到 `http://192.168.3.11:4000/`,需要从原先 `3001` 端口切换到 `4000`。 B. 产生问题原因 项目早前使用 `tmux` 会话 `revoxelseg-dicom` 托管在 `3001`,本次需求指定了新的访问端口。 C. 解决问题方案 先检查 `4000` 端口是否空闲,然后关闭旧 `revoxelseg-dicom` 会话,使用同名 `tmux` 会话启动 Vite:`node ./node_modules/vite/bin/vite.js --host 0.0.0.0 --port 4000 --strictPort`。随后用本机地址和内网地址分别验证 HTTP 200。 D. 后续如何避免问题 每次调整部署端口前先检查端口占用和现有 `tmux` 会话;部署后同时验证 `127.0.0.1` 与目标内网 IP,并把实际访问地址写入测试方案执行结果。 ## 2026-05-04-03-21-40 从纯前端演示升级为前后端协调系统 A. 具体问题 原系统登录、项目列表、用户列表、出厂重置和导出都是前端静态假数据,不同浏览器之间无法共享状态。 B. 产生问题原因 项目初始形态是 Vite/React 前端演示,没有后端 API、共享状态存储和统一部署入口。 C. 解决问题方案 新增 Express 后端 `server.ts`,用同一 `4000` 端口服务 API 和前端页面。后端通过 `WebSite/data/state.json` 维护演示状态,前端通过 `/api/session` 轮询同步登录状态,并将项目、用户、概况、重置和导出功能全部接入 API。 D. 后续如何避免问题 新增跨浏览器共享功能时,默认先判断状态是否必须由后端维护;涉及多浏览器一致性的功能不要放在组件静态数组或浏览器本地状态中。 ## 2026-05-04-03-21-40 默认医学数据项目载入 A. 具体问题 项目列表需要默认载入 `Head_CT_DICOM` 和 `Head_CT_ReConstruct`,恢复演示环境出厂设置后也必须恢复这两个默认数据目录。 B. 产生问题原因 旧项目列表使用硬编码医疗项目示例,和当前仓库中的 DICOM/STL 数据资产没有建立关系。 C. 解决问题方案 后端启动和读取状态时扫描 `Head_CT_DICOM` 的 `.dcm` 数量与 `Head_CT_ReConstruct` 的 `.stl` 文件列表,生成默认项目 `head-ct-demo`。`POST /api/demo/reset` 使用同一逻辑重建默认项目。 D. 后续如何避免问题 演示数据入口统一放在后端默认项目构建函数中,避免多个页面分别硬编码 DICOM/STL 路径或数量。 ## 2026-05-04-03-21-40 NIfTI 导出闭环 A. 具体问题 逆向工作区需要最终生成 `nii` 或 `nii.gz` 格式的分割 mask,而旧界面只有导出按钮,没有后端文件生成能力。 B. 产生问题原因 项目尚未实现真实 STL 到 DICOM 空间的体素化算法,也没有文件导出 API。 C. 解决问题方案 新增 `POST /api/projects/:projectId/export-mask`,后端生成 NIfTI-1 单文件 mask,并按请求输出 `.nii` 或 `.nii.gz`。`.nii.gz` 使用 Node `zlib.gzipSync` 压缩,并通过 `Content-Disposition` 触发下载。 D. 后续如何避免问题 导出类功能需要先定义后端接口、文件格式和校验命令。后续实现真实体素化时,可替换当前演示 mask 生成函数,但保留 API 和下载流程。 ## 2026-05-04-03-21-40 Vite 中间件 HMR 端口冲突 A. 具体问题 Express + Vite 中间件启动时,默认 HMR WebSocket 端口 `24678` 被其他服务占用,日志出现端口冲突。 B. 产生问题原因 同一机器同时运行多个 Vite 服务,默认 HMR 端口可能重复。 C. 解决问题方案 在 `createViteServer` 中指定 `server.hmr.port = 24679`,使本项目后端服务使用独立 HMR 端口。 D. 后续如何避免问题 多项目并行部署时,除了业务端口外,也检查 Vite HMR 端口;发现冲突时为每个项目分配独立 HMR 端口。 ## 2026-05-04-03-50-07 概况统计语义误导 A. 具体问题 项目总数只有 1 时,“已处理项目总数”也显示 1,容易让用户误解为系统已经完成真实处理。 B. 产生问题原因 旧统计把 `status === completed` 直接当作已处理项目,而默认演示项目为了表示数据可用被标记为 `completed`。 C. 解决问题方案 将概况卡片语义改为“已导出 Mask 项目”,后端按 `exportedMaskCount > 0` 统计;默认项目初始为 0,只有实际触发 mask 导出后才计入。 D. 后续如何避免问题 统计卡片必须反映明确业务事件,不要把演示数据可用状态和处理完成状态混在一起。 ## 2026-05-04-03-50-07 DICOM 预览解析 A. 具体问题 项目库 DICOM 影像页看不到真实影像,只显示占位图形。 B. 产生问题原因 前端没有读取 DICOM 像素数据,后端也没有提供切片预览 API。 C. 解决问题方案 新增 `GET /api/projects/:projectId/dicom-preview`,后端解析当前 Little Endian DICOM 的 Rows、Columns、Window、Rescale 和 Pixel Data,返回 base64 灰度像素,前端用 canvas 绘制真实切片。 D. 后续如何避免问题 医学影像可视化应优先验证真实像素是否进入浏览器。后续扩展更多 DICOM 传输语法时,应把解析器替换为成熟 DICOM 库或 Python 预处理服务。 ## 2026-05-04-03-50-07 STL 模型真实渲染 A. 具体问题 项目库 3D 模型页显示的是占位立方体,不是 `Head_CT_ReConstruct` 中的真实 STL。 B. 产生问题原因 前端没有 STLLoader,后端也没有安全暴露 STL 文件。 C. 解决问题方案 新增 `GET /api/projects/:projectId/models/:fileName`,仅允许读取项目 STL 列表中的文件;前端使用 Three.js `STLLoader`、`Bounds` 和 `Center` 加载并自动居中显示模型。 D. 后续如何避免问题 三维模型视图必须加载真实模型文件,不能长期使用占位几何体;后端文件服务要限制文件名和项目白名单,避免任意路径读取。 ## 2026-05-04-03-50-07 Recharts 容器尺寸警告 A. 具体问题 控制台出现 Recharts 警告:图表宽高为 `-1`,需要检查容器尺寸。 B. 产生问题原因 图表在布局尚未稳定时渲染,`ResponsiveContainer` 从父容器拿到异常宽高。 C. 解决问题方案 为图表外层设置 `min-w-0`、固定高度和 `min-h`,并在 chartData 存在后再渲染 `ResponsiveContainer`,高度使用明确数值 `300`。 D. 后续如何避免问题 使用 Recharts 时保证父容器有稳定尺寸;在异步数据未到达前不要提前渲染响应式图表。 ## 2026-05-04-03-50-07 Python 环境引入边界 A. 具体问题 用户提出如果需要 Python 可新建 conda 环境,但本次需求可以在现有 Node/React/Three.js 技术栈中完成。 B. 产生问题原因 DICOM/STL/Mask 功能既可以由前端演示链路实现,也可能进入 Python 医学影像算法链路,需要判断当前阶段是否真的需要 Python。 C. 解决问题方案 本次不创建 conda 环境,避免增加不必要复杂度;README 中说明当前构建方式和后续真实体素化阶段的 conda 环境建议。 D. 后续如何避免问题 只有当需要真实 DICOM 空间解析、STL 体素填充、NIfTI 精确写入或批处理算法时,再引入 Python/conda,并把环境文件纳入项目文档。 ## 2026-05-04-04-12-34 DICOM 三方向预览 A. 具体问题 项目库 DICOM 影像只能看横断面,且右侧切片控制显示为 `NAV` 和 `#0`,不符合医学影像浏览习惯。 B. 产生问题原因 旧前端只把 DICOM 序列当成单一轴向切片数组浏览,后端 DICOM preview API 只返回单张横断面。 C. 解决问题方案 后端 DICOM preview API 增加 `plane=axial|sagittal|coronal` 参数。横断面读取单张 DICOM,矢状面和冠状面从 DICOM 序列逐张采样重建灰度平面。前端增加方向切换,并把右侧控制改为 `第 n / 总数` 的切片语义。 D. 后续如何避免问题 医学影像浏览控件应按方向、当前切片和总切片数表达,不使用模糊的导航标签;多方向重建后续可加入缓存或 Python 预处理优化性能。 ## 2026-05-04-04-12-34 STL 多模型样式控制 A. 具体问题 3D 模型视图只显示单个 STL,右侧状态点无实际意义,用户需要不同 STL 有独立颜色和透明度,并由整体眼睛统一控制显示。 B. 产生问题原因 旧实现把 STL 列表当成选择器,只加载当前选中的一个模型;侧栏状态点只是装饰,没有绑定模型材质。 C. 解决问题方案 前端为每个 STL 建立 `visible`、`color`、`opacity` 状态,同时加载所有可见 STL;每个模型材质绑定对应颜色和透明度,右侧整体眼睛统一切换所有 STL 可见性,删除无意义状态点。 D. 后续如何避免问题 三维列表中的视觉控件必须和真实渲染状态绑定;颜色、透明度、可见性等控件不应只是静态装饰。 ## 2026-05-04-04-12-34 项目管理交互 A. 具体问题 创建项目输入框常驻在项目列表中占空间;项目编辑需要手动保存按钮;项目缺少删除入口和二次确认。 B. 产生问题原因 项目管理功能初版偏向快速可用,没有区分高频浏览和低频管理操作。 C. 解决问题方案 创建项目改为点击 `+` 后弹窗输入;项目名编辑改为失焦或回车自动保存;项目右侧增加删除按钮,点击后必须在确认弹窗中再次确认。 D. 后续如何避免问题 列表页面应减少常驻表单噪声;破坏性操作必须二次确认;轻量编辑可采用失焦保存,但需要避免空名称提交。 ## 2026-05-04-04-58-36 项目列表按钮布局 A. 具体问题 项目列表标题旁的 `+` 创建按钮和侧栏收缩按钮靠得太近,视觉上发生重叠。 B. 产生问题原因 两个操作都放在项目列表标题区右侧,且侧栏宽度固定,未给低频收缩操作独立位置。 C. 解决问题方案 保留 `+` 在标题区,收缩按钮移动到项目列表侧栏中线外侧,并调整容器为 `overflow-visible`,避免按钮被卡片裁剪。 D. 后续如何避免问题 同一区域的高频操作和布局控制应分区放置;绝对定位按钮如果超出容器,要同步检查父容器裁剪策略。 ## 2026-05-04-04-58-36 DICOM 三方向缓存与显示模式 A. 具体问题 矢状面和冠状面切换后图像变化慢或不明显,且 DICOM 只能用单一窗宽窗位显示。 B. 产生问题原因 每次重建非横断面都要重新读取 DICOM 序列,前后端没有把显示模式作为预览参数,也没有复用已解析的体数据。 C. 解决问题方案 后端按显示模式缓存 DICOM 体数据和预览结果,API 增加 `mode=default|bone|soft|contrast`;前端切换方向时重置到对应方向中间层,并提供显示模式分段按钮。 D. 后续如何避免问题 DICOM 多平面重建应优先设计缓存键和窗宽窗位参数;后续接入真实医学影像库时继续保留 plane、slice、mode 的稳定 API 契约。 ## 2026-05-04-04-58-36 STL 大文件预览 A. 具体问题 3D 模型页容易空白,直接加载 9 个原始 STL 总量约 240MB,浏览器解析慢且缺少可靠进度反馈。 B. 产生问题原因 前端承担了原始 STL 解析和渲染的全部工作,大体积二进制模型会阻塞交互并放大 WebGL 环境差异。 C. 解决问题方案 后端新增 STL 二进制采样预览 API,只返回抽样三角面顶点;前端用原生 Three.js 按采样顶点生成 BufferGeometry,并显示加载进度。WebGL 不可用时改用二维 canvas 投影预览兜底。 D. 后续如何避免问题 大模型浏览应区分“预览网格”和“原始精度文件”;列表/项目库优先加载轻量预览,进入精修或导出阶段再读取完整 STL。 ## 2026-05-04-04-58-36 逆向工作区项目上下文与融合视图 A. 具体问题 逆向工作区没有明确显示当前项目,融合视图没有展示 DICOM 与 STL 归一化中心对齐的效果。 B. 产生问题原因 工作区初版更多是流程面板,缺少从项目库传入项目后继续呈现项目上下文和影像/模型叠加结果的状态。 C. 解决问题方案 工作区进入后读取当前项目详情,顶部显示项目名、DICOM 数量、STL 数量和路径;融合视图加载 DICOM 软组织窗切片,并叠加中心对齐的模型轮廓、十字参考线和切片滑块。 D. 后续如何避免问题 跨页面工作流必须在目标页面重新显示当前操作对象;医学影像配准类视图至少应具备影像层、模型层、对齐标识和当前切片控制。 ## 2026-05-04-05-20-16 DICOM 三平面预览与下载 A. 具体问题 DICOM 切片长按不能连续移动,三平面不能旋转,矢状面/冠状面存在大量黑边导致主体像只显示一半,同时缺少当前 PNG 和整套 DICOM 压缩包下载。 B. 产生问题原因 前端切片控制只有原生 range 输入,缺少连续步进逻辑;canvas 绘制没有旋转参数;后端重建平面直接输出完整矩阵,没有对非黑内容边界做裁切;下载链路只覆盖了分割 Mask。 C. 解决问题方案 前端新增上下箭头长按定时步进、左/右 90 度旋转和与显示一致的 PNG 导出;后端 DICOM 文件按自然文件名排序,对重建平面做内容裁切并做轻量边缘增强;新增 `dicom-archive` 接口生成 `tar.gz` 压缩包。 D. 后续如何避免问题 医学影像预览的显示状态应统一由平面、切片、窗宽窗位、旋转角度组成;下载当前视图时复用同一套 canvas 绘制逻辑,避免屏幕显示和导出结果不一致。 ## 2026-05-04-05-20-16 3D 模型加载完成但画布空白 A. 具体问题 项目库 3D 模型页提示加载完成,但用户界面仍可能看不到模型。 B. 产生问题原因 STL 抽样顶点仍保留原始模型坐标,先给 group 位置减中心再缩放时,模型可能被缩放后的坐标体系推离相机视野;WebGL 不可用时二维兜底 canvas 尺寸也依赖容器测量,可能拿到过小尺寸。 C. 解决问题方案 模型加载完成后先计算整体包围盒,将中心偏移直接平移到每个 mesh 的 geometry 顶点,再统一缩放 group 和设置相机;二维兜底 canvas 在容器尺寸不可用时使用父容器尺寸或默认尺寸,保证兜底预览可见。 D. 后续如何避免问题 三维预览应在模型坐标归一化后再设置相机;验证时要覆盖 WebGL 正常路径和 WebGL 不可用兜底路径,并做 canvas 尺寸和非背景像素检查。 ## 2026-05-04-05-20-16 逆向工作区路径信息噪声 A. 具体问题 逆向工作区标题中显示 `Head_CT_DICOM ↔ Head_CT_ReConstruct`,对用户当前操作帮助不大。 B. 产生问题原因 早期为了证明项目数据源接入,将数据目录路径直接放进了页面副标题。 C. 解决问题方案 副标题改为只显示当前项目名称;DICOM 数量和 STL 数量保留在上下文标签中。 D. 后续如何避免问题 工作区首屏应优先显示“当前正在处理哪个项目”和“下一步操作”,底层路径只在诊断、详情或设置区域出现。 ## 2026-05-04-05-41-22 STL 实体化程度与位姿控制 A. 具体问题 3D 模型虽然可以显示,但抽样三角面过少时视觉上偏稀疏,用户希望更接近白色实体 STL 拼装效果,并且能够手动调整整体模型位姿。 B. 产生问题原因 项目库为了避免大体积 STL 造成浏览器卡顿,使用固定低抽样量预览;同时模型 group 只有自动旋转,没有暴露旋转、平移、缩放等用户控制。 C. 解决问题方案 新增“预览/标准/精细”实体化程度,后端 STL preview 抽样上限提升到 `36000`;前端新增白色实体模式、自动旋转开关、旋转 X/Y/Z、平移 X/Y/Z、缩放和重置位姿控制,所有位姿变换作用在整体 group 上。 D. 后续如何避免问题 大模型预览应提供性能档位,而不是在“速度”和“实体感”之间固定取舍;位姿控制必须作用于整体模型容器,避免破坏各 STL 构件的相对拼装关系。 ## 2026-05-04-05-41-22 DICOM 长按切片反馈 A. 具体问题 长按切片上下箭头时,编号会变化,但用户希望图像也有连续变化的运动感。 B. 产生问题原因 前端连续修改 `sliceIndex` 后依赖异步 API 返回更新图像,缺少请求乱序保护和切片切换中的视觉反馈。 C. 解决问题方案 将长按步进间隔缩短到 `95ms`,为 DICOM preview 请求加入递增序号,只允许最新请求更新画面;切片切换时给 canvas 容器增加轻微缩放、亮度和状态提示。 D. 后续如何避免问题 连续浏览医学影像时,必须同时处理“状态连续变化”“图像异步返回”和“旧请求覆盖新请求”三个问题;前端应保留上一帧并提供明确切换反馈。 ## 2026-05-04-05-41-22 逆向工作区标题去重 A. 具体问题 逆向工作区同时出现全局标题和页面内标题,也重复显示“当前项目”。 B. 产生问题原因 页面局部标题和全局 header 没有统一职责,项目上下文既出现在副标题,也出现在标签行。 C. 解决问题方案 保留全局 header 的“逆向工作区”,删除页面内重复标题和副标题;保留并放大当前项目、DICOM 数量、STL 数量标签。 D. 后续如何避免问题 页面级标题应由全局导航或内容区二选一承担;当前对象信息只保留在最醒目的单一位置,减少重复文本造成的噪声。 ## 2026-05-04-05-56-34 DICOM 多平面物理比例 A. 具体问题 矢状面和冠状面只按像素矩阵重建,没有考虑切片间距与单张图像内像素间距,导致图像观感过扁。 B. 产生问题原因 后端重建平面时直接使用 `切片数 x 行/列数` 作为输出尺寸,默认把切片方向和像素方向当成等距网格。 C. 解决问题方案 解析 `PixelSpacing`、`SliceThickness`、`SpacingBetweenSlices` 和 `ImagePositionPatient`;优先用相邻 `ImagePositionPatient` 距离估计真实切片间距,并按 `sliceSpacing` 与像素间距做最近邻重采样,返回 spacing 与 physicalSize。 D. 后续如何避免问题 医学影像任意重建平面都必须带着物理 spacing 计算,不应只看像素数量;当 DICOM tag 缺失时要明确 fallback 来源。 ## 2026-05-04-05-56-34 DICOM 信息面板 A. 具体问题 前端缺少 DICOM 详细信息查询,用户无法看到像素间距、切片间距等判断空间比例的关键信息。 B. 产生问题原因 原有 API 只服务于灰度预览,没有暴露 DICOM 元数据和序列级空间统计。 C. 解决问题方案 新增 `GET /api/projects/:projectId/dicom-info`,返回患者、检查、序列、图像矩阵、窗宽窗位、spacing、物理尺寸和首尾切片位置;前端增加“信息”按钮和 DICOM 详细信息弹窗。 D. 后续如何避免问题 影像显示功能旁应提供可审计的元数据入口,特别是任何影响几何比例、配准和导出的空间参数。 ## 2026-05-04-05-56-34 3D 模型交互控制简化 A. 具体问题 3D 模型页存在不需要的白色实体模式和自动旋转,同时缺少更高细节档位;鼠标拖拽、滚轮等画布操作不能同步到右侧位姿控件。 B. 产生问题原因 前一版位姿控制主要依赖右侧滑块,画布本身只负责渲染;显示开关也偏演示型,没有完全贴近用户的实际浏览习惯。 C. 解决问题方案 移除白色实体和自动旋转;新增“超精细”档,后端 STL 抽样上限提升到 `72000`;画布监听左键旋转、右键或 Shift 平移、滚轮缩放,并回写整体位姿 state。 D. 后续如何避免问题 三维浏览默认应遵循常见交互习惯,UI 控件与鼠标操作必须共享同一份状态;演示型开关要及时剔除,避免干扰核心工作流。 ## 2026-05-07-16-20-46 3D 默认位姿 A. 具体问题 网页端 3D 模型默认位姿看起来不像用户参考图中的正常位姿,打开后更像斜向观察。 B. 产生问题原因 默认 Three.js 相机使用 `(4.5, 3.5, 5)` 斜向等距视角,而用户期望的是接近俯视/轴向的标准视角。 C. 解决问题方案 将默认相机改为俯视方向:`camera.up=(0,1,0)`、`camera.position=(0,0,6)`、`lookAt(0,0,0)`;保留默认位姿滑块为旋转 0、平移 0、缩放 1,重置位姿也回到同一基准。 D. 后续如何避免问题 默认位姿应该由相机预设和模型位姿共同定义;如果用户提供标准视图截图,应优先匹配相机视角,再决定是否需要固定模型 Z 轴校正。 ## 2026-05-07-16-35-52 3D 位姿重置与旋转中心 A. 具体问题 整体位姿只有一个重置按钮,无法分别恢复旋转和平移缩放;同时用户感觉模型旋转中心不在模型正中间,缺少右下角 XYZ 方位参考。 B. 产生问题原因 前端位姿状态虽包含旋转、平移和缩放,但重置操作仍使用单一 `defaultModelPose`;Three.js 预览也使用单 group 同时承载旋转、平移和缩放,层级职责不够清晰;画布缺少固定的方位提示。 C. 解决问题方案 抽出统一的位姿 clamp 方法;新增 `重置旋转位姿` 与 `重置平移缩放位姿`;旋转项增加 ±90° 快捷按钮,平移和缩放增加正负方向快捷步进;Three.js 渲染拆为 `poseGroup` 负责平移、`pivotGroup` 负责围绕整体包围盒中心旋转和缩放;右下角增加 X/Y/Z 方位与旋转角度 overlay。 D. 后续如何避免问题 三维位姿控制应按旋转、平移、缩放分开管理;模型加载后必须先基于所有 STL 的整体包围盒做中心化,再把旋转和缩放应用到中心 pivot 上;涉及交互状态时,滑块、按钮和鼠标操作必须共享同一份 clamp 逻辑。 ## 2026-05-07-16-53-23 STL 抽样中心漂移与动态坐标轴 A. 具体问题 用户旋转模型后切换 `预览/标准/精细/超精细`,模型位置会明显偏移;鼠标拖拽旋转时也感觉旋转中心没有落在模型内部;右下角坐标轴不随旋转位姿变化。 B. 产生问题原因 前端用当前抽样出来的 STL 顶点计算整体包围盒,不同细节档位的抽样集合不同,导致中心点和缩放基准随档位变化;右下角坐标轴是固定 HTML/CSS 图形,没有基于当前旋转矩阵更新。 C. 解决问题方案 后端 STL preview 在遍历完整二进制 STL 时同步计算全量 `bounds`,前端加载时使用所有可见 STL 的全量包围盒合成稳定中心和尺寸,再把抽样 geometry 平移到该中心;右下角坐标轴改为 SVG,根据 `rotateX/Y/Z` 生成 Three.js 旋转矩阵并投影 X/Y/Z 三轴。 D. 后续如何避免问题 任何用于配准、视角稳定、旋转中心的几何参数都必须来自全量模型或稳定元数据,不能来自随性能档位变化的抽样数据;坐标系、状态文字和模型实际位姿应共用同一份 pose 状态。 ## 2026-05-07-17-05-43 模型显示实体档位 A. 具体问题 用户不再需要低质量 `预览` 档位,希望在 `模型显示` 中增加更接近 STL 实体面片的 `实体` 档位。 B. 产生问题原因 原有档位以性能抽样为主,最高 `超精细` 仍受后端 `72000` 三角面上限约束,且材质继续使用用户设置的半透明度,视觉上仍偏点状或半透明预览。 C. 解决问题方案 前端删除 `预览` 档位,新增 `实体` 档位并设置更高请求上限 `200000`;后端 STL preview clamp 同步提升到 `200000`;实体档位下将材质不透明度下限提高到 `0.94`,在保留构件颜色的同时增强实体感。 D. 后续如何避免问题 模型显示档位应明确区分“性能抽样”和“实体查看”;若新增高质量档位,需要同步检查前端请求 limit、后端 clamp、材质表现和浏览器性能边界。 ## 2026-05-07-17-28-34 逆向工作区三维融合视角 A. 具体问题 逆向工作区原来的 `影像与模型融合视角` 只是二维 DICOM 图片和示意轮廓叠加,不能表现 DICOM 体数据、切片范围、STL 模型同场景融合,也不能让 DICOM 和模型作为整体旋转观察。 B. 产生问题原因 早期实现更偏演示界面,没有后端接口提供一段 DICOM 体数据纹理;前端也没有 Three.js 融合场景,只是在二维 canvas 上放置静态标注层。 C. 解决问题方案 新增 `dicom-fusion-volume` 后端接口,按起止切片返回最多 64 张、最大 256 像素边长的轴向 CT 纹理和 spacing/physicalSize;前端逆向工作区新增 Three.js 融合场景,将 DICOM 渲染为黑色长方体和切片纹理,将 STL preview 模型加载到同一场景,并提供切片范围与模型位姿控件。 D. 后续如何避免问题 融合、配准、体素化相关视图应优先使用三维数据结构,而不是二维示意图;DICOM 体数据接口必须限制切片数量和纹理尺寸,保证浏览器交互稳定;模型相对 DICOM 的调整和整体场景观察要分开管理。 ## 2026-05-07-18-11-12 构件层级状态与可视化工具栏 A. 具体问题 项目库构件层级的单个眼睛按钮表现不稳定;构件缺少可编辑的 1 到 255 ID;逆向工作区仍显示 `分割 Mask`,缺少模型显示、位姿保存/选择和构件层级等可视化控制。 B. 产生问题原因 构件样式状态只记录 visible/color/opacity,部分更新路径会用默认值重建对象,容易丢失扩展字段;逆向工作区三维融合视角初版只加载模型,没有把项目库中的模型显示和构件层级控制模式迁移过来。 C. 解决问题方案 扩展构件样式状态为 visible/color/opacity/partId,所有更新都保留既有字段;项目库和逆向工作区均使用 1 到 255 的 ID clamp;新增 `模型库` 复用项目库并默认进入模型页;逆向工作区将中间栏改为 `可视化工具栏`,加入模型显示档位、位姿保存/选择和构件层级,并把这些状态传入 Three.js 模型加载逻辑。 D. 后续如何避免问题 构件层级状态应作为统一结构在不同页面复用;任何新增构件字段都要检查初始化、单项更新、全局更新和默认 fallback 四条路径;逆向工作区的可视化控制应与项目库模型页保持一致,避免用户在两个页面学两套交互。 ## 2026-05-07-18-42-53 构件 ID 跨页面联动 A. 具体问题 项目库 3D 模型和逆向工作区可视化工具栏都能修改构件 ID,但两边原先分别维护本地状态,无法保证 ID、显示隐藏、颜色和透明度一致。 B. 产生问题原因 构件样式属于项目级配置,但旧实现只保存在 React 组件 state 中,页面切换或不同浏览器访问时不会自动共享。 C. 解决问题方案 在项目数据中新增 `moduleStyles` 字段,并新增 `PATCH /api/projects/:projectId/module-styles` 接口。项目库和逆向工作区都读写同一后端状态,服务端统一补齐默认值并将 `partId` 限制在 `1~255`。 D. 后续如何避免问题 凡是需要跨页面、跨浏览器一致的配置项,优先放入后端项目状态;前端可以保留本地 state 提升响应速度,但必须通过 API 持久化并从项目数据恢复。 ## 2026-05-08-01-19-42 融合视角缓存、边界与切割控制 A. 具体问题 融合视角在切片范围变化时需要反复请求 DICOM 体数据;模型旋转中心带有模型偏移,极端旋转后容易看起来脱离 DICOM;同时缺少 DICOM/模型边界、透明度档位和沿 DICOM 帧切割模型的操作入口。 B. 产生问题原因 前一版融合视图以单次加载为主,没有前端缓存点位;模型居中后又把模型组整体设置了 Z 偏移,使旋转 pivot 不完全等同于 DICOM 体中心;三维辅助元素只显示了 DICOM 边线,没有完整的模型边界和切割平面。 C. 解决问题方案 在前端使用 `Map` 按项目、模式和切片终点缓存 `DicomFusionVolume`;DICOM 切片范围增加五个预存点位和一键预存;Three.js 中将模型旋转组保持在 DICOM 原点,把模型自身偏移放入子节点;增加 DICOM 边界、模型边界、DICOM 透明度三档、切割帧滑条和 clipping plane 切割面。 D. 后续如何避免问题 涉及 DICOM 与 STL 配准的旋转、缩放、切割操作,应优先明确坐标系和 pivot 来源,默认以 DICOM 体中心为基准;高频切片请求应先设计缓存键和预取策略,避免 UI 操作直接触发重复网络与纹理构建。 ## 2026-05-08-01-53-07 DICOM 范围变化不改变空间基准 A. 具体问题 DICOM 切片范围变化后,融合视图中的 DICOM 体深度和帧分布会随范围重新计算,导致模型看起来被自动居中或改变了和 DICOM 的原始配准位置;切分开启后也缺少在 DICOM 帧上直观看到 Mask 的反馈。 B. 产生问题原因 后端 `dicom-fusion-volume` 使用当前 `start/end` 的范围长度计算 `physicalSize.depth`;前端又把当前返回的帧均匀铺满整个 DICOM box,而不是按原始 DICOM index 放回完整序列位置。 C. 解决问题方案 后端 physical depth 改为完整序列深度;前端 DICOM slice plane 的 Z 位置改用 `volume.indices[index] / (total - 1)` 映射到完整 DICOM box;切片范围改为 `sliceStart/sliceEnd` 双端点,默认最高切片;切割开启时额外渲染切割帧 DICOM texture,并叠加橙色 Mask 轮廓。 D. 后续如何避免问题 所有配准相关可视化都必须区分“显示范围”和“空间基准”:显示范围可以变化,但 DICOM 物理尺寸、模型缩放基准和坐标原点不能跟着变化;任何切割或 Mask 预览都要明确只是辅助显示,不能修改原始 DICOM/STL 位姿。 ## 2026-05-08-03-03-52 项目定位错误导致控件未修复 A. 具体问题 用户要求将“DICOM 切片范围”的起点、终点合并为一个范围条,但页面仍显示两个上下排列的进度条。 B. 产生问题原因 前一次处理时依据当前工作目录误改了 `Head_CT_Morph`,而用户截图中的真实页面来自 `ReVoxelSeg_DICOM/WebSite/src/components/ReverseWorkspace.tsx`。没有先用截图中的页面文案和 DOM 片段全局定位真实渲染文件,导致改动没有作用到用户看到的程序。 C. 解决问题方案 在 `/home/wkmgc/Desktop` 范围内搜索 `DICOM 切片范围` 和 `三维融合场景已就绪`,定位到正确项目 `ReVoxelSeg_DICOM`。将 `ReverseWorkspace.tsx` 中两个独立 `range` 替换为单条自绘轨道叠加两个端点的范围控件,并在 `index.css` 中隐藏原生 range 轨道、保留可拖动 thumb。 D. 后续如何避免问题 收到 UI 截图或 DOM 片段时,先用页面可见文案、class 片段和组件文本在所有相关项目目录中定位真实源码,再修改代码。若当前仓库内找不到截图中的文本,必须立即扩大搜索范围并向用户说明实际项目位置,不能默认当前工作目录就是目标项目。 ## 2026-05-08-03-13-20 模型切分必须由 DICOM 范围统一驱动 A. 具体问题 逆向工作区初始 DICOM 范围只落在最后一张;模型切分还有独立“帧”滑块,与 DICOM 切片范围割裂;切分开启后额外生成 `CUT MASK` 伪贴图,容易误导用户以为是真实语义分割结果。 B. 产生问题原因 前一版把“DICOM 显示范围”和“模型切割帧”设计成两套状态,并为了给切割反馈绘制了演示性质的二维 mask 纹理,没有把切分严格绑定到 DICOM 起点和终点双帧。 C. 解决问题方案 删除 `cutSlice` 状态和模型切分帧滑块,项目加载时将 `sliceStart` 初始化为 `0`、`sliceEnd` 初始化为最大帧;`FusionThreeView` 改接收 `cutStart/cutEnd`,根据 DICOM 物理深度映射为两张 clipping plane,模型切分启用后只保留两帧之间的中间模型区域;删除 `createCutMaskTexture` 和 `CUT MASK` 贴图调用。 D. 后续如何避免问题 所有模型切分、分割预览、Mask 展示都必须明确数据来源。没有真实体素化或真实语义分割结果时,不应使用伪造 mask 图像;同一业务动作只保留一套权威控制状态,模型切分应默认由 DICOM 切片范围驱动。 ## 2026-05-08-03-23-51 重复入口与辅助显示清理 A. 具体问题 系统同时提供“项目库”和“模型库”两个入口,实际模型库只是复用项目库的模型页,信息架构重复;逆向工作区的 DICOM 范围说明和五点预存按钮已经不必要;模型切分启用后出现红色辅助平面,干扰观察。 B. 产生问题原因 早期为了快速进入模型页新增了独立 `MODELS` 路由和侧边栏入口;DICOM 范围控件在调试缓存阶段加入了预存点位;模型切分为了强调切割位置渲染了半透明平面,但用户当前更需要干净的真实裁切效果。 C. 解决问题方案 删除 `ViewType.MODELS`、侧边栏“模型库”和 `App.tsx` 中对应分支,保留“项目库”统一承载 DICOM、模型、Mask 视图;删除 DICOM 范围说明、五点预存状态和按钮,保留 `fusionVolumeCacheRef` 对实际加载范围的缓存;删除切分辅助平面 Mesh,只保留两张 clipping plane 裁切模型。 D. 后续如何避免问题 新增导航入口前先判断是否是独立业务对象和独立工作流,避免用多个入口指向同一组件状态;辅助视觉元素应在用户确认有价值后保留,医学三维视图中默认少放装饰或调试平面,避免遮挡真实数据。 ## 2026-05-08-03-35-22 Mask 展示改为真实 STL 切面 A. 具体问题 逆向工作区右侧 `Mask 展示` 仍然是二维彩色示意图,并且底部存在“导出进度”栏;用户希望看到切割后的 STL 实体切面。 B. 产生问题原因 旧 `Mask 展示` 是早期演示 UI,没有接入真实 STL 模型,也没有复用 DICOM 范围切割逻辑;导出进度栏展示的是导出状态文本,不是用户当前关注的切面实体结果。 C. 解决问题方案 新增 `CutSectionPreview` Three.js 组件,复用当前项目 STL preview、构件颜色/隐藏状态、模型位姿和 DICOM 切片范围;启用模型切分时使用两张 clipping plane 保留中间区域,并以实体材质展示裁切后的 STL。删除旧二维 Mask 示意结构和底部“导出进度”栏。 D. 后续如何避免问题 右侧结果展示区域应优先呈现真实数据或真实处理结果,避免使用占位式示意图长期冒充结果;如果尚未生成真实语义分割 Mask,应明确展示当前可验证的 STL 切面实体,而不是伪造 Mask 形状。 ## 2026-05-19-22-59-07 工程分析核心文档被删除状态下的恢复 A. 具体问题 本次开始时工作区中大量 `工程分析/` 历史文档处于删除状态,且本地目录不存在;如果直接创建新的短版 `经验记录.md` 或直接暂存整个目录,可能丢失旧知识库或把无关删除混入本次备份。 B. 产生问题原因 这些删除状态在本次操作前已经存在,且 `工程分析/经验记录.md` 在 Git 中已有 795 行历史经验。当前需求又要求读取或创建 `工程分析/`,容易把“恢复核心文档”和“提交所有删除”混为一谈。 C. 解决问题方案 先通过 Git 读取旧 `工程整体分析.md`、`代码编纂工作流.md` 和 `经验记录.md`,确认历史内容;随后只恢复并更新这三个核心文件,新增本次三份时间戳文档和 `AGENTS.md`,暂存时显式列出本次相关路径,避免提交其他历史删除。 D. 后续如何避免问题 每次发现工作区已有删除或修改时,先区分是否属于本次需求;文档备份 commit 要显式暂存文件路径,不能用 `git add .`。对 `经验记录.md` 这类知识库文件,更新前必须确认旧内容仍被保留。 ## 2026-05-19-22-59-07 固化后续代码编纂工作流 A. 具体问题 用户要求后续所有项目修改相关需求都执行固定流程,但仅在对话中说明流程不够稳固,未来进入项目的助手或开发者可能看不到这条约束。 B. 产生问题原因 工作流要求跨越多次会话和多次修改,单靠当前对话记忆不可靠;项目内原有 `代码编纂工作流.md` 也处于工作区删除状态,需要恢复并更新为当前版本。 C. 解决问题方案 更新 `工程分析/代码编纂工作流.md`,明确 0 到 7 步、默认不等待二次确认、文档备份提交和重新部署要求;同时新增根目录 `AGENTS.md`,把后续修改必须读取并执行该工作流作为项目入口约束。 D. 后续如何避免问题 后续任何项目修改前,先读取根目录 `AGENTS.md` 和 `工程分析/代码编纂工作流.md`;若用户提出新流程要求,应同步更新这两个入口文档和经验记录,确保流程约束留在仓库中。 ## 2026-05-19-22-59-07 Gitea HTTP 远端缺少可用凭据 A. 具体问题 本次本地文档备份 commit 已完成,但执行 `git push origin main` 时失败,Git 提示无法读取 `http://192.168.31.5:5002` 的用户名。 B. 产生问题原因 当前 `origin` 使用 HTTP Gitea 地址,执行环境没有交互式用户名输入,也没有可用的凭据助手或已保存认证信息。 C. 解决问题方案 保留本地 commit,不在命令行临时拼接账号密码,也不把凭据信息写入仓库或远端 URL。将推送失败原因记录到测试方案和经验记录中,等待用户提供安全的凭据方式后再推送。 D. 后续如何避免问题 需要 Gitea 远端备份前,先确认远端认证方式。优先使用安全的凭据助手、SSH remote 或用户已配置好的 token;不要把账号密码写进 commit、文档、remote URL 或 shell 历史。 ## 2026-05-19-23-47-31 逆向分割映射视图的数据来源边界 A. 具体问题 用户要求右侧二维视图展示由三维 STL 模型逆向推导的分割掩码 Label Map,并与构件层级严格对应;但当前后端尚未提供医学级真实体素化 Label Map 文件。 B. 产生问题原因 现有系统的真实数据能力主要是 DICOM preview、DICOM fusion volume 和 STL preview 三角面抽样,历史版本的右侧区域也已从伪二维 Mask 改为 STL 实体切面。若直接绘制任意彩色区域,会再次变成无来源 Mask。 C. 解决问题方案 右侧新建 `VoxelizationMappingView`,底层用 DICOM preview 灰度像素作为 Base Layer,上层只根据 STL preview 顶点、当前 Z 切片位置和构件 `moduleStyles` 投影绘制 Overlay Label Map。每个彩色覆盖区域都来自具体 STL 构件,并复用构件颜色、透明度、显示隐藏和 `partId`。 D. 后续如何避免问题 在真实体素化服务接入前,所有 Label Map 类可视化必须明确使用 STL 几何或后端生成结果作为来源;不要重新引入无数据来源的演示 Mask。后续若增加医学级体素化,应保留当前 Base/Overlay UI,但将 Overlay 数据源替换为后端真实 Label Map。 ## 2026-05-19-23-47-31 右侧独立切片导航与左侧范围状态分离 A. 具体问题 右侧二维映射视图需要逐层浏览单张 DICOM 切片,而左侧三维融合视图使用的是 DICOM 切片范围和模型切分区间;如果共用同一状态,拖动右侧滑条会破坏左侧融合范围。 B. 产生问题原因 旧工作区已经有 `sliceStart/sliceEnd` 双端点状态,用于三维 DICOM 范围和 STL clipping plane。右侧新增 Slice Navigator 是单切片校验动作,语义不同。 C. 解决问题方案 新增独立 `mappingSlice` 状态传入 `VoxelizationMappingView`,右侧 Slice Navigator 只修改该状态;左侧 `sliceStart/sliceEnd` 继续驱动三维融合范围和模型切分,两套状态互不覆盖。 D. 后续如何避免问题 新增影像浏览控件前先判断其控制对象是“单切片位置”还是“显示范围/切割范围”。单切片校验使用独立 slice 状态,范围切割使用起止端点状态,避免不同视图之间产生隐式联动。 ## 2026-05-20-00-19-47 右侧映射视图必须复用中部模型位姿 A. 具体问题 右侧“逆向分割映射视图”虽然已经使用 DICOM Base Layer 和 STL Overlay,但 Overlay 计算没有接入中部“模型位姿”状态;用户拖动 X/Y/Z 平移或旋转后,左侧三维视图变化,右侧二维映射仍按旧 STL 原始坐标绘制。 B. 产生问题原因 上一版 `VoxelizationMappingView` 只接收 `moduleStyles`、`slice` 和 STL preview 数据,没有接收 `modelPose`;`drawVoxelOverlayLayer` 直接使用 STL 原始顶点和全局 bounds 计算投影,没有先执行与三维场景一致的归一化、旋转、缩放和平移。 C. 解决问题方案 为 `VoxelizationMappingView` 增加 `modelPose` 入参,由父组件直接传入中部工具栏的当前位姿;在 Overlay 计算前对 STL 顶点执行 `scale -> rotateX -> rotateY -> rotateZ -> translate`,再与当前 Z 轴 DICOM 切片平面求交,并使用 `requestAnimationFrame` 合并高频滑条更新。 D. 后续如何避免问题 凡是右侧二维映射、Mask、Label Map 或导出预览依赖 STL 空间位置时,都必须确认其输入状态包含当前权威位姿;不能让三维视图和二维视图各自维护坐标变换。新增视图前先列出共享状态:位姿、构件样式、切片位置和数据源。 ## 2026-05-20-00-19-47 实体 Mask 填充不能覆盖多构件叠加 A. 具体问题 将截面交线转为实心 Mask 时,如果每个构件直接在主 Overlay canvas 上 `putImageData`,后一个构件的透明像素会覆盖掉前一个构件,导致多构件同时显示时可能只剩最后绘制的构件。 B. 产生问题原因 Canvas 的 `putImageData` 是像素替换操作,不是透明合成操作;即使 ImageData 中某些像素 alpha 为 0,也会把目标 canvas 对应位置写成透明,从而擦掉已有 Overlay。 C. 解决问题方案 每个构件先在离屏 canvas 中生成扫描线射线法填充的实心 Mask,再使用 `drawImage` 以 `source-over` 合成到主 Overlay canvas;边界描边也在合成后按构件颜色与透明度绘制,保留多构件叠加效果。 D. 后续如何避免问题 多层或多构件 Canvas 叠加时,优先使用离屏画布或单次合并后的 ImageData;只有在明确要替换整张图时才使用主 canvas 的 `putImageData`。涉及透明叠加的渲染改动,必须检查“前一层是否会被透明像素擦除”。 ## 2026-05-20-00-38-39 多视图 FOV 对齐必须使用同源物理尺度 A. 具体问题 右侧“逆向分割映射视图”此前使用独立归一化 `viewExtent` 映射 STL 截面,左侧三维融合视图则根据 DICOM 物理尺寸和 `baseExtent` 计算显示尺寸;两侧视场和缩放来源不同,容易出现同一层切片下解剖结构和 Overlay Mask 大小不一致。 B. 产生问题原因 右侧算法只使用 STL bounds 做归一化,没有读取 DICOM `physicalSize`、`Pixel Spacing` 和 slice spacing;同时左侧三维视图过去按当前可见 STL 构件计算 bounds,构件显隐还可能改变左侧模型缩放。 C. 解决问题方案 右侧新增 `getPreviewPhysicalSize`、`getFovCanvasSize` 和同源 `getModelSceneMetrics`,用 DICOM 物理宽高、层厚、总层数和左侧 `baseExtent=4.6` 推导 `dicomWidth/dicomHeight/dicomDepth`、slice Z 与 `modelBaseScale`。左侧三维视图改为始终用全部 STL bounds 建立全局模型尺度,构件显隐只影响 Mesh 是否渲染。 D. 后续如何避免问题 新增任何二维/三维联动视图前,先明确使用哪套物理坐标系和 FOV;DICOM Base Layer、STL Overlay、slice Z 和模型缩放必须从同一组 spacing、physicalSize 与全局 bounds 推导,不能在不同视图中各自定义归一化范围。 ## 2026-05-20-00-38-39 实体 Mask 填充需要补齐内部空洞 A. 具体问题 仅依赖扫描线交点配对填充时,复杂 STL 截面或抽样边界可能产生小孔洞,视觉上仍会像漏隙,不符合“闭合实体区域”Mask 的审查预期。 B. 产生问题原因 Mesh-Plane Intersection 得到的是离散截面线段,浏览器端再进行像素级光栅化;线段精度、重复交点、边界浮点误差和抽样上限都可能让填充区域内部残留透明像素。 C. 解决问题方案 在每个构件的离屏 Mask ImageData 中完成扫描线填充后,从画布四边对透明区域做 flood fill 标记外部背景;任何未被外部连通到的透明像素都视为内部孔洞并填为当前构件颜色,再合成回主 Overlay。 D. 后续如何避免问题 所有实体 Mask 光栅化都应包含“内部孔洞填补”或等价的连通域后处理;验证时不能只看边界是否有线,还要检查内部是否连续饱满。若后续接入后端体素化,也应保留连通域清理策略作为质量检查。 ## 2026-05-20-01-08-38 工具栏空间不足时优先调整栅格比例 A. 具体问题 逆向工作区左侧“影像与模型融合视角”占用桌面端 7 栅格,中部“可视化工具栏”只占 2 栅格,导致三维视图偏大而工具栏过窄,模型位姿和构件层级控制显得拥挤。 B. 产生问题原因 早期布局更偏向三维展示,将主要横向空间给了融合视图;随着中部工具栏承担模型显示、融合显示、切分、位姿和构件层级等操作,2 栅格已经不足以承载密集控件。 C. 解决问题方案 将桌面端三栏比例从 `7 / 2 / 3` 调整为 `6 / 3 / 3`,右侧映射视图保持不变,左侧三维视图让出一格给中部工具栏。 D. 后续如何避免问题 新增工具栏控件后,应重新评估三栏空间分配。操作密集型面板不能长期压缩在过窄栅格内;如果中部继续增加控件,应优先考虑分组、折叠或继续调整栅格比例。 ## 2026-05-20-01-08-38 小步长控制需要同步显示精度 A. 具体问题 用户要求模型位姿平移步长改为 `0.005`,如果只改 slider step,而数值仍按两位小数显示,界面会把部分精细变化四舍五入隐藏。 B. 产生问题原因 旧显示逻辑用 `step < 1 ? 2 : 0` 固定小数位,适合 `0.05` 和 `1`,但不适合 `0.005` 这种三位小数步长。 C. 解决问题方案 新增 `getStepPrecision`,根据 step 本身计算显示小数位;平移 X/Y/Z step 改为 `0.005` 后自动显示三位小数,旋转仍显示整数,缩放仍显示两位小数。 D. 后续如何避免问题 调整任何滑条或步进按钮的 step 时,同步检查数值展示、长按步进和手动输入精度,避免控制精度和显示精度不一致。 ## 2026-05-20-01-38-33 NIfTI 导出必须与 DICOM 体数据同维同距 A. 具体问题 旧的 NII/NII.GZ 导出生成的是固定 `64x64x64` 演示 Mask,用户在 ITK-SNAP 中打开时无法与真实 DICOM 序列对应,表现为尺度、层数和内容都不可信。 B. 产生问题原因 早期导出接口没有读取真实 DICOM Pixel Data、Pixel Spacing 和 slice spacing,而是直接写入一个合成球体数据;这类演示数据适合验证下载链路,但不能用于医学影像工具复核。 C. 解决问题方案 后端新增真实 NIfTI-1 写入链路:DICOM 原始影像导出为 `512x512x300` int16 HU volume,分割影像导出为同维度 uint8 Label Map,并把 spacing 写入 NIfTI header。分割数据复用 STL 构件采样切面、当前位姿变换和扫描线填充逻辑生成,标签值对应构件 `partId`。 D. 后续如何避免问题 任何影像导出功能都必须先确认维度、spacing、datatype、vox_offset 和真实数据来源。不能用固定尺寸演示数据替代生产导出;新增导出后至少用脚本读取 NIfTI header,并确认体素数和 DICOM 序列一致。 ## 2026-05-20-01-38-33 浏览器下载不应依赖 blob:http 临时地址 A. 具体问题 浏览器控制台出现 `blob:http://... was loaded over an insecure connection`,用户误以为导出的 NII.GZ 文件本身或服务部署存在安全错误。 B. 产生问题原因 前端先 `fetch` 后端文件,再用 `URL.createObjectURL(blob)` 生成临时 `blob:http` 地址触发下载;在 HTTP 部署环境下,浏览器会对 blob 来源继承非安全上下文并给出警告。 C. 解决问题方案 将 NIfTI、DICOM 压缩包和多文件导出统一改成后端直链附件下载,由 Express 设置 `Content-Disposition`,前端只创建 `` 触发下载,不再生成 blob URL。 D. 后续如何避免问题 面向大文件、医疗影像和压缩包下载时优先使用后端附件直链。如果必须用 blob,应明确浏览器安全提示的影响;生产环境仍应考虑 HTTPS,但不能把 blob 临时地址当作常规下载路径。 ## 2026-05-20-01-38-33 位姿列表需要进入项目状态而不是组件内存 A. 具体问题 用户保存的可视化工具栏位姿在重新进入项目后消失,造成调好的 STL/DICOM 对齐姿态无法继续复核或用于导出。 B. 产生问题原因 旧实现把 `savedPoses` 放在 `ReverseWorkspace` 组件本地 state 中,页面重新加载或重新进入项目时只会恢复默认、俯视、侧视三组临时位姿,没有写回后端项目状态。 C. 解决问题方案 为项目状态新增 `modelPoses` 字段,后端归一化默认位姿并提供 `PATCH /api/projects/:projectId/model-poses`;前端加载项目时读取 `project.modelPoses`,保存或重命名位姿时立即写回后端。 D. 后续如何避免问题 凡是用户明确“保存”的可视化参数都应进入项目级持久状态,不能只存在于组件 state。新增保存类交互时同时设计读取、写入、归一化和刷新后的回显验证。 ## 2026-05-20-02-02-37 位姿数字输入必须保留可编辑中间态 A. 具体问题 模型位姿从只读数值改为可编辑数值时,如果直接把 `` 完全绑定到 `modelPose`,用户输入负号、小数点或临时清空内容时会被 React 立即回填旧值,导致难以编辑。 B. 产生问题原因 数值输入存在合法提交值和编辑中间态两层语义;`modelPose` 只能存储有限数字,而输入框需要短暂容纳空字符串或尚未完整输入的文本。 C. 解决问题方案 新增 `poseValueDrafts` 保存输入框文本态,并用 `focusedPoseInput` 控制同步范围。输入内容能解析为数字时立即 clamp 后写入 `modelPose`;失焦时统一格式化回与 step 匹配的小数位,非法输入则恢复当前位姿值。 D. 后续如何避免问题 任何需要“可编辑数字 + 实时状态”的控件都应区分 draft value 和 committed value。不要把可能为空或临时非法的输入字符串直接写入业务状态,也不要让格式化逻辑打断用户正在输入的字段。 ## 2026-05-20-02-02-37 导入导出的位姿 JSON 要兼容多种入口 A. 具体问题 位姿导出 JSON 包含 `activePose`、`modelPoses` 和项目元信息;用户导入时也可能拿到单个 `{ pose }` 或直接 pose 对象。如果导入逻辑只认一种结构,会让“导出后再导入”的闭环不稳定。 B. 产生问题原因 导出文件是侧车数据,不是纯数组;同时调试和人工编辑时常会只保留一个 pose 对象。导入端如果没有 schema 容错,就会把可恢复数据误判为无效。 C. 解决问题方案 导入解析按优先级读取 `activePose`、`pose`、直接 pose 对象和 `modelPoses[0].pose`,并对每个字段使用 `poseStepConfig` 做 clamp。若包含 `modelPoses`,则补齐默认/俯视/侧视并通过现有 `PATCH /model-poses` 持久化。 D. 后续如何避免问题 成对设计导入/导出功能时,应把导出样例作为导入测试用例,同时兼容最小可用对象。导入端必须对字段缺失、字符串数字、越界数值和重复 id 做归一化处理。 ## 2026-05-20-02-15-10 三维方向标识必须来自真实世界矩阵 A. 具体问题 右下角 XYZ 标识原先是静态 SVG,无法随模型旋转位姿和三维融合场景拖拽旋转变化;用户调整模型后,标识仍显示固定方向,容易误导“平移 X/Y/Z 后模型会往哪里移动”的判断。 B. 产生问题原因 旧标识只是界面装饰,没有读取 Three.js 中 `fusionRoot` 和 `modelPoseGroup` 的实时变换。模型实际显示方向由场景根节点旋转、模型位姿旋转和相机投影共同决定,静态二维箭头无法表达这个组合结果。 C. 解决问题方案 新增轴向投影辅助函数,在动画循环中读取 `modelPoseGroup` 的 world position 与 world quaternion,将模型局部 X/Y/Z 方向投影到当前 camera 屏幕空间,再驱动右下角小 SVG 的线段终点。使用投影签名去重,只有方向变化时才更新 React 状态。 D. 后续如何避免问题 凡是三维视图中的方向、法向、切面或平移提示,都应从 Three.js 真实对象矩阵或统一坐标变换链路推导,不能手写静态示意。若该提示会随拖拽视角变化,还必须包含场景根节点和相机投影。