From 464b1aab5933cb596c794959f602d891d1633578 Mon Sep 17 00:00:00 2001 From: admin <572701190@qq.com> Date: Thu, 21 May 2026 01:36:15 +0800 Subject: [PATCH] =?UTF-8?q?2026-05-21-00-58-25=20=E5=A2=9E=E5=8A=A0WebGL?= =?UTF-8?q?=E9=99=8D=E7=BA=A7=E5=B9=B6=E6=9B=B4=E6=96=B0=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebSite/src/components/ReverseWorkspace.tsx | 44 +++++++++++++- 工程分析/实现方案-2026-05-21-00-58-25.md | 53 +++++++++++++++++ 工程分析/测试方案-2026-05-21-00-58-25.md | 63 +++++++++++++++++++++ 工程分析/经验记录.md | 18 ++++++ 工程分析/需求分析-2026-05-21-00-58-25.md | 51 +++++++++++++++++ 5 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 工程分析/实现方案-2026-05-21-00-58-25.md create mode 100644 工程分析/测试方案-2026-05-21-00-58-25.md create mode 100644 工程分析/需求分析-2026-05-21-00-58-25.md diff --git a/WebSite/src/components/ReverseWorkspace.tsx b/WebSite/src/components/ReverseWorkspace.tsx index 42e0e7b..91de1f0 100644 --- a/WebSite/src/components/ReverseWorkspace.tsx +++ b/WebSite/src/components/ReverseWorkspace.tsx @@ -538,6 +538,7 @@ export function FusionThreeView({ const modelPoseRef = useRef(modelPose); const [status, setStatus] = useState('准备融合 DICOM 与 STL'); const [loadProgress, setLoadProgress] = useState(0); + const [webglError, setWebglError] = useState(null); const [axisProjection, setAxisProjection] = useState(defaultAxisProjection); const axisProjectionSignatureRef = useRef(axisProjectionSignature(defaultAxisProjection)); const resetFusionViewRef = useRef<() => void>(() => undefined); @@ -551,6 +552,7 @@ export function FusionThreeView({ if (!container || !volume) return; container.innerHTML = ''; + setWebglError(null); setStatus('正在构建三维融合场景...'); setLoadProgress(8); setAxisProjection(defaultAxisProjection); @@ -568,7 +570,19 @@ export function FusionThreeView({ camera.up.set(0, 0, 1); camera.lookAt(0, 0, 0); - const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + let renderer: THREE.WebGLRenderer; + try { + renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + } catch { + const message = '当前浏览器无法创建 WebGL 三维上下文'; + setStatus(message); + setLoadProgress(100); + setWebglError('三维融合视图暂不可用,请检查浏览器硬件加速、显卡驱动或远程桌面图形支持。二维 DICOM 与逆向分割映射功能仍可继续使用。'); + resetFusionViewRef.current = () => undefined; + return () => { + container.innerHTML = ''; + }; + } renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setSize(width, height); renderer.localClippingEnabled = true; @@ -897,6 +911,15 @@ export function FusionThreeView({ return (
+ {webglError && ( +
+
+ +

三维融合视图无法启动

+

{webglError}

+
+
+ )}
{status}
@@ -953,6 +976,7 @@ function CutSectionPreview({ }) { const containerRef = useRef(null); const modelPoseRef = useRef(modelPose); + const [webglError, setWebglError] = useState(null); useEffect(() => { modelPoseRef.current = modelPose; @@ -963,6 +987,7 @@ function CutSectionPreview({ if (!container || !project || !volume) return; container.innerHTML = ''; + setWebglError(null); let disposed = false; let animationId = 0; const scene = new THREE.Scene(); @@ -975,7 +1000,15 @@ function CutSectionPreview({ camera.up.set(0, 0, 1); camera.lookAt(0, 0, 0); - const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + let renderer: THREE.WebGLRenderer; + try { + renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + } catch { + setWebglError('当前浏览器无法创建 WebGL 三维上下文,STL 切面三维预览暂不可用。'); + return () => { + container.innerHTML = ''; + }; + } renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setSize(width, height); renderer.localClippingEnabled = true; @@ -1218,6 +1251,13 @@ function CutSectionPreview({ return (
+ {webglError && ( +
+
+ {webglError} +
+
+ )} {(!project || !volume) && (
正在载入 STL 切面... diff --git a/工程分析/实现方案-2026-05-21-00-58-25.md b/工程分析/实现方案-2026-05-21-00-58-25.md new file mode 100644 index 0000000..4e34a83 --- /dev/null +++ b/工程分析/实现方案-2026-05-21-00-58-25.md @@ -0,0 +1,53 @@ +# 实现方案-2026-05-21-00-58-25 + +实现方案文档路径:`工程分析/实现方案-2026-05-21-00-58-25.md` + +## 修改目标 + +- 对系统进行静态、构建、API 与浏览器交互测试。 +- 根据测试结果修复真实影响使用的问题。 +- 更新软著说明书、登记表、代码汇总、素材清单,并重新生成说明书截图和 Word 文档。 +- 按项目工作流提交代码与工程分析文档,软著材料不提交。 + +## 涉及路径 + +- 可能涉及:`WebSite/server.ts`、`WebSite/src/components/*`、`WebSite/src/lib/*`、`WebSite/src/types.ts`。 +- 工程分析:`工程分析/需求分析-2026-05-21-00-58-25.md`、`工程分析/实现方案-2026-05-21-00-58-25.md`、`工程分析/测试方案-2026-05-21-00-58-25.md`、`工程分析/经验记录.md`。 +- 软著材料:`新撰写软著文档/`,仅本地更新,不纳入 Gitea。 + +## 技术路线 + +1. 运行 `npm run lint`、`npm run build`、API 健康检查与关键接口抽查。 +2. 使用浏览器自动化访问登录、总体概况、项目库、逆向工作区、系统管理等核心路径,观察控制台错误与页面状态。 +3. 对发现的问题做小范围修复,避免引入新的数据结构风险。 +4. 重新运行测试并部署。 +5. 使用最新界面重新截取说明书图片,更新 Markdown 与 docx。 + +## 执行步骤 + +- 确认服务、依赖、脚本和软著材料现状。 +- 执行静态与构建测试。 +- 执行浏览器回归测试和页面截图。 +- 修复测试中发现的缺陷。 +- 重新生成软著文档和图片。 +- 追加经验记录,精确暂存并提交代码/工程文档。 +- 重新部署并验证服务。 + +## 兼容性与回滚方案 + +- 只修改明确发现的问题和文档内容,不改变默认医学数据。 +- 如某项修复造成构建失败,回退该小范围 patch 并记录原因。 +- 软著材料不提交,必要时可从本地历史文件恢复。 + +## 预计文件变更 + +- 新增本次工程分析三件套。 +- 追加 `工程分析/经验记录.md`。 +- 视测试结果修改少量前后端文件。 +- 本地更新 `新撰写软著文档/` 下 Markdown、docx 和图片。 + +## 提交与部署策略 + +- Gitea commit 只包含本次代码修复和工程分析文档。 +- Commit message 包含 `2026-05-21-00-58-25` 与简要描述。 +- 使用 `tmux` 会话 `revoxelseg-dicom` 重启 `npm run serve -- --host 0.0.0.0 --port 4000`。 diff --git a/工程分析/测试方案-2026-05-21-00-58-25.md b/工程分析/测试方案-2026-05-21-00-58-25.md new file mode 100644 index 0000000..c9d04aa --- /dev/null +++ b/工程分析/测试方案-2026-05-21-00-58-25.md @@ -0,0 +1,63 @@ +# 测试方案-2026-05-21-00-58-25 + +测试方案文档路径:`工程分析/测试方案-2026-05-21-00-58-25.md` + +## 静态检查 + +- `cd WebSite && npm run lint` +- 检查 TypeScript 类型、组件属性和 API 调用签名。 + +## 构建检查 + +- `cd WebSite && npm run build` +- 确认 Vite 生产构建无错误。 + +## 关键业务场景验证 + +- 登录、总体概况、项目库三类数据页、逆向工作区、系统管理工作区可访问。 +- 项目库导入 DICOM/STL 的入口、覆盖提醒、进度/失败反馈可见。 +- 逆向分割结果视图、二维映射视图、Overlay Label Map、位置重置和切片导航布局符合当前功能。 +- 用户管理新增、编辑、改密、冲突提示和删除限制逻辑无明显异常。 + +## 医学影像数据相关边界验证 + +- 默认项目有 DICOM/STL 时可预览,不存在资产时给出导入提示。 +- 大体积/压缩包导入失败时主操作区保留错误,不造成浏览器无反馈。 +- 导出项目及结果响应头文件名符合“项目名_时间”语义。 + +## 软著材料验证 + +- 说明书每个 `## X.` 章节均有图片引用。 +- 图片文件存在且为最新重新拍摄。 +- 代码汇总 Markdown 行数不少于 1600 行。 +- 能重新生成 `.docx` 文件。 + +## 部署验证 + +- `http://127.0.0.1:4000/api/health` +- `http://127.0.0.1:4000/` + +## Git/Gitea 备份验证 + +- 只暂存本次代码和工程分析文档。 +- 不暂存 `新撰写软著文档/`、`3279-STL.zip`、默认医学数据或历史无关删除。 +- `git push` 成功后记录 commit。 + +## 风险与回归关注点 + +- 三维/WebGL 页面加载可能较慢,截图前需等待稳定。 +- 软著截图必须避免局部裁剪和敏感信息暴露。 +- 修复导入或缓存逻辑时要避免跨项目串用旧资产。 + +## 实际执行结果 + +- `npm run lint`:通过。 +- `npm run build`:通过,仅保留 Vite 大包体积提示。 +- `/api/health`:通过。 +- 项目列表接口:确认默认项目与用户项目可读取。 +- 临时 ZIP/STL 导入回归:创建临时项目、上传含 `tiny.stl` 的 ZIP、返回 `modelCount=1` 后删除临时项目,通过。 +- 重名用户接口回归:新增 `admin` 同名账号返回 409 与 `账号已存在`,通过。 +- 导出响应头抽查:`export-bundle?targets=stl` 返回 `filename*` 中文文件名,通过。 +- 浏览器自动化:登录、项目库、DICOM 信息、3D 模型、逆向分割结果、逆向工作区、保存、导出面板、系统管理、退出均可访问;SwiftShader WebGL 模式无 React fatal 错误。 +- WebGL 异常模式:验证三维融合视图显示降级提示,页面未崩溃。 +- 软著材料:23 个章节、23 个图片引用、23 张 `chapter-*.png` 均为 1680x1050;说明书 docx 中 23 个图片位置;代码汇总 10810 行;系统使用视频已刷新为约 48 秒 MP4。 diff --git a/工程分析/经验记录.md b/工程分析/经验记录.md index 72c3e1a..1228c3e 100644 --- a/工程分析/经验记录.md +++ b/工程分析/经验记录.md @@ -1441,3 +1441,21 @@ C. 解决问题方案 D. 后续如何避免问题 所有文件导入、导出、保存这类长操作失败时,都要在主操作路径旁保留显眼错误卡,不能只写入边栏或短暂 toast。后端对 4xx/5xx 的可恢复业务错误应记录足够上下文,尤其是项目 ID、导入类型、文件数量和原始异常消息,方便从用户截图快速定位。 + +## 2026-05-21-00-58-25 三维视图需要 WebGL 降级保护且软著截图要强制视口 + +A. 具体问题 + +自动化浏览器回归进入逆向工作区时,Headless Chrome 在默认图形参数下无法创建 WebGL 上下文,`FusionThreeView` 直接抛出 Three.js 渲染错误,导致工作区组件崩溃。软著截图第一次生成时浏览器实际截图尺寸为 1680x963,与素材清单中约定的 1680x1050 不一致。 + +B. 产生问题原因 + +三维融合视图和 STL 切面预览此前默认 `new THREE.WebGLRenderer` 一定成功,没有捕获无 GPU、远程桌面、浏览器禁用硬件加速或 Headless 图形实现异常。截图脚本只设置了 Chrome 窗口大小,没有通过 DevTools `Emulation.setDeviceMetricsOverride` 强制页面视口,因此截图高度受 Headless 浏览器可用视区影响。 + +C. 解决问题方案 + +在 `FusionThreeView` 与 `CutSectionPreview` 初始化 WebGLRenderer 时增加 try/catch,创建失败时显示三维视图不可用提示,并保留二维 DICOM、逆向分割映射、保存和导出等功能继续可用。软著截图改用 Chrome Headless + SwiftShader WebGL 参数,并通过 DevTools 强制 1680x1050 视口;截图后用文件尺寸、章节图片数量、Word drawing 数量和代码汇总行数做校验。 + +D. 后续如何避免问题 + +所有 WebGL/Three.js 视图都应把渲染器创建失败视为可恢复状态,不能让单个三维画布拖垮整个工作区。自动生成软著或验收截图时,除了设置浏览器窗口,还必须设置设备视口,并在生成后校验图片尺寸、非空像素、章节数量、图片引用和 docx 内嵌图片位置数量。 diff --git a/工程分析/需求分析-2026-05-21-00-58-25.md b/工程分析/需求分析-2026-05-21-00-58-25.md new file mode 100644 index 0000000..95a8152 --- /dev/null +++ b/工程分析/需求分析-2026-05-21-00-58-25.md @@ -0,0 +1,51 @@ +# 需求分析-2026-05-21-00-58-25 + +开始时间:2026-05-21-00-58-25 + +## 原始需求摘要 + +用户要求对当前程序进行细致测试,自主发现并修复问题;同时更新 `新撰写软著文档/` 中的所有材料,按最新功能重新细化说明,并重新拍摄软著说明书中的界面图片。 + +## 业务目标 + +- 提高当前系统在项目库、逆向工作区、导入导出、用户管理和医学影像/模型预览场景下的稳定性。 +- 对自动测试、构建和浏览器交互进行回归检查,发现影响真实使用的问题后直接修复。 +- 让软著说明书、登记表、代码汇总、素材清单和说明书截图与最新功能保持一致。 + +## 输入与输出 + +- 输入: + - 现有前后端代码与运行服务。 + - 默认演示数据 `Head_CT_DICOM/`、`Head_CT_ReConstruct/`。 + - 现有软著材料目录 `新撰写软著文档/`。 +- 输出: + - 必要的程序修复。 + - 本次工程分析三件套与经验记录追加。 + - 更新后的软著 Markdown/Word/图片材料,但软著材料不纳入 Gitea 提交。 + - 重新部署并验证后的服务。 + +## 影响范围 + +- `WebSite/` 前后端程序、测试和构建流程。 +- 项目库、逆向工作区、导入导出、软著截图所依赖的页面展示。 +- `新撰写软著文档/` 下的说明书、登记表、代码汇总、素材清单和截图。 + +## 关键约束 + +- 必须遵循 `工程分析/代码编纂工作流.md`。 +- 不提交软著撰写相关内容到 Gitea。 +- 不混入历史无关删除、大型运行态产物、用户压缩包或默认医学数据的非必要变化。 +- 修复时优先沿用现有 React/Express/TypeScript 结构。 + +## 风险点 + +- 大体积 DICOM/STL/ZIP 导入和三维预览容易造成浏览器内存压力。 +- 软著截图可能包含敏感患者字段,截图前需尽量使用系统页面或脱敏内容。 +- 当前工作树已有历史删除与未跟踪文件,提交时必须精确暂存。 +- 若浏览器自动化无法加载 WebGL 或服务未启动,截图和交互验证需要先部署。 + +## 默认假设 + +- 用户授权本轮自主测试并修复发现的问题。 +- `新撰写软著文档/` 可在本地更新,但不做 Gitea 备份提交。 +- 默认部署端口仍为 `4000`,tmux 会话优先使用 `revoxelseg-dicom`。