Merge pull request '외부 업체 전용 뷰어 모드 구현' (#303) from reportMng into main

Reviewed-on: http://39.117.244.52:3000/kjs/ERP-node/pulls/303
This commit is contained in:
hyeonsu 2025-12-19 09:42:11 +09:00
commit 9902b65598
1 changed files with 43 additions and 30 deletions

View File

@ -50,6 +50,7 @@ export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps)
// 외부 업체 모드
const [isExternalMode, setIsExternalMode] = useState(false);
const [isFullscreen, setIsFullscreen] = useState(false);
const [layoutKey, setLayoutKey] = useState(0); // 레이아웃 강제 리렌더링용
const canvasContainerRef = useRef<HTMLDivElement>(null);
// 외부 업체 역할 체크
@ -98,7 +99,16 @@ export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps)
// 전체 화면 변경 감지
useEffect(() => {
const handleFullscreenChange = () => {
setIsFullscreen(!!document.fullscreenElement);
const isNowFullscreen = !!document.fullscreenElement;
setIsFullscreen(isNowFullscreen);
// 전체화면 종료 시 레이아웃 강제 리렌더링
if (!isNowFullscreen) {
setTimeout(() => {
setLayoutKey(prev => prev + 1);
window.dispatchEvent(new Event('resize'));
}, 50);
}
};
document.addEventListener("fullscreenchange", handleFullscreenChange);
@ -262,7 +272,8 @@ export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps)
});
if (response.success && response.data) {
const layerColumn = hierarchyConfig.material.layerColumn || "LOLAYER";
const sortedMaterials = response.data.sort((a: any, b: any) => (a[layerColumn] || 0) - (b[layerColumn] || 0));
// 층 내림차순 정렬 (높은 층이 위로)
const sortedMaterials = response.data.sort((a: any, b: any) => (b[layerColumn] || 0) - (a[layerColumn] || 0));
setMaterials(sortedMaterials);
} else {
setMaterials([]);
@ -660,37 +671,26 @@ export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps)
</div>
)}
{/* 중앙: 3D 캔버스 */}
{/* 중앙 + 우측 컨테이너 (전체화면 시 함께 표시) */}
<div
ref={canvasContainerRef}
className={`relative flex-1 ${isFullscreen ? "bg-background" : ""}`}
className={`relative flex flex-1 overflow-hidden ${isFullscreen ? "bg-background" : ""}`}
>
{!isLoading && (
<Yard3DCanvas
placements={canvasPlacements}
selectedPlacementId={selectedObject?.id || null}
onPlacementClick={(placement) => handleObjectClick(placement?.id || null)}
focusOnPlacementId={null}
onCollisionDetected={() => {}}
/>
)}
{/* 풀스크린 모드일 때 종료 버튼 */}
{isFullscreen && (
<Button
variant="outline"
size="sm"
onClick={toggleFullscreen}
className="absolute top-4 right-4 z-50 bg-background/80 backdrop-blur-sm"
>
<Minimize className="mr-2 h-4 w-4" />
</Button>
)}
</div>
{/* 중앙: 3D 캔버스 */}
<div className="relative min-w-0 flex-1">
{!isLoading && (
<Yard3DCanvas
placements={canvasPlacements}
selectedPlacementId={selectedObject?.id || null}
onPlacementClick={(placement) => handleObjectClick(placement?.id || null)}
focusOnPlacementId={null}
onCollisionDetected={() => {}}
/>
)}
</div>
{/* 우측: 정보 패널 - 외부 모드에서는 숨김 */}
{!isExternalMode && (
<div className="h-full w-[480px] flex-shrink-0 overflow-y-auto border-l">
{/* 우측: 정보 패널 */}
<div className="h-full w-[480px] min-w-[480px] flex-shrink-0 overflow-y-auto border-l">
{selectedObject ? (
<div className="p-4">
<div className="mb-4">
@ -792,8 +792,21 @@ export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps)
<p className="text-muted-foreground text-sm"> </p>
</div>
)}
</div>
{/* 풀스크린 모드일 때 종료 버튼 */}
{isFullscreen && (
<Button
variant="outline"
size="sm"
onClick={toggleFullscreen}
className="absolute top-4 right-4 z-50 bg-background/80 backdrop-blur-sm"
>
<Minimize className="mr-2 h-4 w-4" />
</Button>
)}
</div>
)}
</div>
</div>
);