454 lines
19 KiB
Markdown
454 lines
19 KiB
Markdown
# 经验记录
|
||
|
||
本文件用于记录项目修改过程中的关键问题与解决方案。每条经验使用四段式结构。
|
||
|
||
## 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 <url> main` 会把该 `<url>` 记录为当前分支上游,而不是只使用已配置的 `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 <session>` 查看启动日志,用 `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. 后续如何避免问题
|
||
|
||
工作区首屏应优先显示“当前正在处理哪个项目”和“下一步操作”,底层路径只在诊断、详情或设置区域出现。
|