Explorar el Código

解决问题:切换胶片时,残留图像

dengdx hace 1 mes
padre
commit
5d944ccb60

+ 95 - 22
src/pages/output/print/DcmCell.tsx

@@ -36,21 +36,48 @@ const ViewportContainer = ({ imageId, className, currentFilm, indexOfCell }: Vie
   const [renderingEngine, setRenderingEngine] = useState<any>(null);
   const [stackViewport, setStackViewport] = useState<any>(null);
   const [hasImage, setHasImage] = useState<boolean>(false); // 跟踪是否已加载图像
-  // ✅ 用 useMemo 保证 id 只生成一次
-  const viewportId = useMemo(() => `stackViewport-${imageId}-${uuidv4()}`, []);
+  const [currentImageId, setCurrentImageId] = useState<string | null>(null); // 跟踪当前已加载的图像ID
+  // ✅ 用 useMemo 保证 id 只生成一次,包含胶片ID和格子索引确保唯一性
+  const viewportId = useMemo(() =>
+    `stackViewport-${currentFilm.id}-${indexOfCell}-${uuidv4()}`,
+    [currentFilm.id, indexOfCell]
+  );
   const dispatch = useDispatch();
 
+  // 统一的图像加载函数,供两种场景使用
+  const loadImage = async (targetImageId: string, source: 'props' | 'drag' = 'props'): Promise<boolean> => {
+    if (!stackViewport || !targetImageId) return false;
+    
+    try {
+      const fullImageUrl = targetImageId.startsWith('dicomweb:')
+        ? targetImageId
+        : getDcmImageUrl(targetImageId);
+      
+      await stackViewport.setStack([fullImageUrl], 0);
+      stackViewport.render();
+      setHasImage(true);
+      
+      console.log(`[DcmCell] 图像加载成功 (${source}): ${targetImageId}`);
+      return true;
+    } catch (error) {
+      console.error(`[DcmCell] 图像加载失败 (${source}):`, error);
+      setHasImage(false);
+      return false;
+    }
+  };
+
   // 初始化 Cornerstone 渲染引擎
   useEffect(() => {
     // initImageLoader();
 
-    // 创建渲染引擎实例
-    const engineId = 'myRenderingEngineForPrint';
+    // 创建胶片特定的渲染引擎实例,确保状态隔离
+    const engineId = `renderingEngine-${currentFilm.id}`;
     let engine: RenderingEngine | null = cornerstone.getRenderingEngines()?.find(en => en.id === engineId) || null;
     // 不存在则创建
     if (!engine) {
       engine = new RenderingEngine(engineId);
     }
+    setRenderingEngine(engine);
 
     // 配置 Viewport
     if (viewportRef.current) {
@@ -108,7 +135,7 @@ const ViewportContainer = ({ imageId, className, currentFilm, indexOfCell }: Vie
         toolGroup.setToolPassive(cornerstoneTools.WindowLevelTool.toolName);
 
         // 将 viewport 添加到工具组
-        toolGroup.addViewport(viewportId, 'myRenderingEngineForPrint');
+        toolGroup.addViewport(viewportId, engineId);
 
         console.log(`[DcmCell] 工具组已创建并配置: ${toolGroupId}`);
       }
@@ -120,18 +147,63 @@ const ViewportContainer = ({ imageId, className, currentFilm, indexOfCell }: Vie
       const toolGroupId = `PRINT_TOOL_GROUP_${viewportId}`;
       const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId);
       if (toolGroup) {
-        // 先从工具组中移除 viewport
-        toolGroup.removeViewports(engine.id, viewportId);
-        // 然后销毁工具组
-        cornerstoneTools.ToolGroupManager.destroyToolGroup(toolGroupId);
-        console.log(`[DcmCell] 工具组已销毁: ${toolGroupId}`);
+        try {
+          // 先从工具组中移除 viewport
+          toolGroup.removeViewports(`renderingEngine-${currentFilm.id}`, viewportId);
+          // 然后销毁工具组
+          cornerstoneTools.ToolGroupManager.destroyToolGroup(toolGroupId);
+          console.log(`[DcmCell] 工具组已销毁: ${toolGroupId}`);
+        } catch (error) {
+          console.warn(`[DcmCell] 清理工具组时出错: ${error}`);
+        }
       }
 
-      // 销毁渲染引擎
-      renderingEngine?.destroy();
+      // 清理 viewport
+      if (engine) {
+        try {
+          engine.disableElement(viewportId);
+          console.log(`[DcmCell] viewport 已禁用: ${viewportId}`);
+        } catch (error) {
+          console.warn(`[DcmCell] 禁用 viewport 时出错: ${error}`);
+        }
+      }
     };
   }, []);
 
+  // 监听 imageId 变化,自动加载图像
+  useEffect(() => {
+    const loadImageFromProps = async () => {
+      if (!stackViewport) return;
+      
+      // 避免重复加载相同图像
+      if (imageId === currentImageId) return;
+      
+      if (imageId && imageId.trim() !== '') {
+        console.log(`[DcmCell] 开始从 props 加载图像: ${imageId}`);
+        const success = await loadImage(imageId, 'props');
+        if (success) {
+          setCurrentImageId(imageId);
+        }
+      } else {
+        // imageId 为空时清空显示
+        if (stackViewport) {
+          try {
+            // 清空 viewport 中的图像堆栈
+            await stackViewport.setStack([], 0);
+            stackViewport.render();
+          } catch (error) {
+            console.warn(`[DcmCell] 清空 viewport 时出错: ${error}`);
+          }
+        }
+        setHasImage(false);
+        setCurrentImageId(null);
+        console.log(`[DcmCell] imageId 为空,清空显示`);
+      }
+    };
+
+    loadImageFromProps();
+  }, [imageId, stackViewport]);
+
   // 处理拖放事件(核心逻辑)
   const handleDrop = async (e) => {
     e.preventDefault();
@@ -139,22 +211,23 @@ const ViewportContainer = ({ imageId, className, currentFilm, indexOfCell }: Vie
 
     // 1. 获取拖拽传递的序列标识
     const seriesInstanceUID = e.dataTransfer.getData('seriesInstanceUID');
-    if (!seriesInstanceUID || !stackViewport) return;
+    if (!seriesInstanceUID) return;
 
     try {
       // 2. 获取该序列的所有图像 ID(需替换为实际接口)
       const imageIds = getDcmImageUrl(seriesInstanceUID);
       console.log(`拖拽后要加载图像 是 ${imageIds}`);
-      // 3. 加载图像并设置到 Viewport
-      await stackViewport.setStack([imageIds], 0);
-      // 4. 渲染图像
-      stackViewport.render();
-      // 5. 成功加载后隐藏提示
-      setHasImage(true);
-      // 6. 通知到slice
-      dispatch(addImageToCell({ index: indexOfCell, imageId: imageIds[0] }));
+      
+      // 3. 使用统一的加载函数
+      const success = await loadImage(imageIds, 'drag');
+      
+      if (success) {
+        setCurrentImageId(imageIds);
+        // 4. 通知到slice
+        dispatch(addImageToCell({ index: indexOfCell, imageId: imageIds }));
+      }
     } catch (error) {
-      console.error('加载图像失败:', error);
+      console.error('[DcmCell] 拖拽加载图像失败:', error);
     }
   };
 

+ 21 - 12
src/pages/output/print/Film.tsx

@@ -8,7 +8,7 @@ const Film: React.FC = () => {
   const activeFilmId = useAppSelector((state) => state.print.activeFilmId);
 
   const currentFilm = films.find((film) => film.id === activeFilmId);
-
+  console.log(`当前胶片ID:${activeFilmId} ; 包含的images : ${currentFilm?.images}`);
   if (!currentFilm) {
     return <div className="film p-4">未找到胶片</div>;
   }
@@ -33,36 +33,45 @@ const Film: React.FC = () => {
     return 'grid-cols-1 grid-rows-1';
   };
 
-  const generateCell = (imageId,indexOfCell) => {
-    return (<ViewportContainer imageId={imageId} currentFilm={currentFilm} indexOfCell={indexOfCell} />);
+  const generateCell = (imageId, indexOfCell) => {
+    // 🎯 关键修复:添加唯一key确保胶片切换时重新创建组件
+    const uniqueKey = `${currentFilm.id}-${indexOfCell}`;
+    return (
+      <ViewportContainer
+        key={uniqueKey}
+        imageId={imageId}
+        currentFilm={currentFilm}
+        indexOfCell={indexOfCell}
+      />
+    );
   };
 
   const getCells = () => {
-    const { layout } = currentFilm;
+    const { layout, images } = currentFilm;
     const cells: any[] = [];
     if (layout === '1x1') {
-      cells.push(generateCell(null,0));
+      cells.push(generateCell(images[0], 0));
       return cells;
     } else if (layout === '1x2') {
-      cells.push(generateCell(null,0));
-      cells.push(generateCell(null,1));
+      cells.push(generateCell(images[0], 0));
+      cells.push(generateCell(images[1], 1));
       return cells;
     } else if (layout === '2x1') {
-      cells.push(generateCell(null,0));
-      cells.push(generateCell(null,1));
+      cells.push(generateCell(images[0], 0));
+      cells.push(generateCell(images[1], 1));
       return cells;
     } else if (layout === '2x2') {
       for (let i = 0; i < 4; i++) {
-        cells.push(generateCell(null,i));
+        cells.push(generateCell(images[i], i));
       }
       return cells;
     }
     console.warn(`没有得到布局信息`);
-    return generateCell(null,0);//不知道什么布局,认为只有一个格子
+    return generateCell(null, 0);//不知道什么布局,认为只有一个格子
   }
 
   return (
-    <div 
+    <div
       id="film-print-area"
       className="film h-full w-full p-4"
     >

+ 1 - 0
src/pages/output/print/FilmTabBar.tsx

@@ -10,6 +10,7 @@ const FilmTabBar: React.FC = () => {
   const activeFilmId = useAppSelector((state) => state.print.activeFilmId);
 
   const handleTabChange = (key: string) => {
+    console.log(`准备激活胶片:${key}`)
     dispatch(setActiveFilm(key));
   };