From 8b2810714727a9d9e6ac29dd41087b7e70920961 Mon Sep 17 00:00:00 2001 From: dohyeons Date: Fri, 17 Oct 2025 17:43:58 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=EB=B0=B0=EC=B9=98=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=A1=B0=EC=A0=88=20=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../widgets/yard-3d/MaterialEditPanel.tsx | 55 +------- .../dashboard/widgets/yard-3d/YardEditor.tsx | 119 +++++++----------- 2 files changed, 50 insertions(+), 124 deletions(-) diff --git a/frontend/components/admin/dashboard/widgets/yard-3d/MaterialEditPanel.tsx b/frontend/components/admin/dashboard/widgets/yard-3d/MaterialEditPanel.tsx index d2388711..a909a195 100644 --- a/frontend/components/admin/dashboard/widgets/yard-3d/MaterialEditPanel.tsx +++ b/frontend/components/admin/dashboard/widgets/yard-3d/MaterialEditPanel.tsx @@ -49,9 +49,6 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo useEffect(() => { if (placement) { setEditData({ - position_x: placement.position_x, - position_y: placement.position_y, - position_z: placement.position_z, size_x: placement.size_x, size_y: placement.size_y, size_z: placement.size_z, @@ -107,52 +104,6 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo
배치 정보 (편집 가능)
- {/* 3D 위치 */} -
- -
-
- - setEditData({ ...editData, position_x: parseFloat(e.target.value) || 0 })} - step="0.5" - className="h-8 text-xs" - /> -
-
- - setEditData({ ...editData, position_y: parseFloat(e.target.value) || 0 })} - step="0.5" - className="h-8 text-xs" - /> -
-
- - setEditData({ ...editData, position_z: parseFloat(e.target.value) || 0 })} - step="0.5" - className="h-8 text-xs" - /> -
-
-
- {/* 3D 크기 */}
@@ -167,7 +118,7 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo value={editData.size_x ?? placement.size_x} onChange={(e) => setEditData({ ...editData, size_x: parseFloat(e.target.value) || 1 })} min="1" - step="0.5" + step="1" className="h-8 text-xs" />
@@ -181,7 +132,7 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo value={editData.size_y ?? placement.size_y} onChange={(e) => setEditData({ ...editData, size_y: parseFloat(e.target.value) || 1 })} min="1" - step="0.5" + step="1" className="h-8 text-xs" />
@@ -195,7 +146,7 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo value={editData.size_z ?? placement.size_z} onChange={(e) => setEditData({ ...editData, size_z: parseFloat(e.target.value) || 1 })} min="1" - step="0.5" + step="1" className="h-8 text-xs" /> diff --git a/frontend/components/admin/dashboard/widgets/yard-3d/YardEditor.tsx b/frontend/components/admin/dashboard/widgets/yard-3d/YardEditor.tsx index 1d93f6a9..9c85799e 100644 --- a/frontend/components/admin/dashboard/widgets/yard-3d/YardEditor.tsx +++ b/frontend/components/admin/dashboard/widgets/yard-3d/YardEditor.tsx @@ -62,10 +62,15 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { const [placements, setPlacements] = useState([]); const [materials, setMaterials] = useState([]); const [selectedPlacement, setSelectedPlacement] = useState(null); - const [selectedMaterial, setSelectedMaterial] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); const [searchTerm, setSearchTerm] = useState(""); + const [editValues, setEditValues] = useState({ + size_x: 5, + size_y: 5, + size_z: 5, + color: "#3b82f6", + }); // 배치 목록 & 자재 목록 로드 useEffect(() => { @@ -78,10 +83,10 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { ]); if (placementsRes.success) { - setPlacements(placementsRes.data); + setPlacements(placementsRes.data as YardPlacement[]); } if (materialsRes.success) { - setMaterials(materialsRes.data); + setMaterials(materialsRes.data as TempMaterial[]); } } catch (error) { console.error("데이터 로드 실패:", error); @@ -93,6 +98,18 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { loadData(); }, [layout.id]); + // selectedPlacement 변경 시 editValues 업데이트 + useEffect(() => { + if (selectedPlacement) { + setEditValues({ + size_x: selectedPlacement.size_x, + size_y: selectedPlacement.size_y, + size_z: selectedPlacement.size_z, + color: selectedPlacement.color, + }); + } + }, [selectedPlacement]); + // 자재 클릭 → 배치 추가 const handleMaterialClick = async (material: TempMaterial) => { // 이미 배치되었는지 확인 @@ -102,8 +119,6 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { return; } - setSelectedMaterial(material); - // 기본 위치에 배치 const placementData = { external_material_id: `TEMP-${material.id}`, @@ -123,11 +138,10 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { try { const response = await yardLayoutApi.addMaterialPlacement(layout.id, placementData); if (response.success) { - setPlacements((prev) => [...prev, response.data]); - setSelectedPlacement(response.data); - setSelectedMaterial(null); + setPlacements((prev) => [...prev, response.data as YardPlacement]); + setSelectedPlacement(response.data as YardPlacement); } - } catch (error: any) { + } catch (error) { console.error("자재 배치 실패:", error); alert("자재 배치에 실패했습니다."); } @@ -262,7 +276,7 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { setSelectedPlacement(placement as YardPlacement)} onPlacementDrag={handlePlacementDrag} /> )} @@ -304,60 +318,18 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
-
-
- - - handlePlacementUpdate(selectedPlacement.id, { - position_x: parseFloat(e.target.value), - }) - } - /> -
-
- - - handlePlacementUpdate(selectedPlacement.id, { - position_y: parseFloat(e.target.value), - }) - } - /> -
-
- - - handlePlacementUpdate(selectedPlacement.id, { - position_z: parseFloat(e.target.value), - }) - } - /> -
-
-
- handlePlacementUpdate(selectedPlacement.id, { - size_x: parseFloat(e.target.value), - }) - } + value={editValues.size_x} + onChange={(e) => { + const newValue = parseFloat(e.target.value) || 1; + setEditValues((prev) => ({ ...prev, size_x: newValue })); + handlePlacementUpdate(selectedPlacement.id, { size_x: newValue }); + }} />
@@ -365,12 +337,12 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { - handlePlacementUpdate(selectedPlacement.id, { - size_y: parseFloat(e.target.value), - }) - } + value={editValues.size_y} + onChange={(e) => { + const newValue = parseFloat(e.target.value) || 1; + setEditValues((prev) => ({ ...prev, size_y: newValue })); + handlePlacementUpdate(selectedPlacement.id, { size_y: newValue }); + }} />
@@ -378,12 +350,12 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { - handlePlacementUpdate(selectedPlacement.id, { - size_z: parseFloat(e.target.value), - }) - } + value={editValues.size_z} + onChange={(e) => { + const newValue = parseFloat(e.target.value) || 1; + setEditValues((prev) => ({ ...prev, size_z: newValue })); + handlePlacementUpdate(selectedPlacement.id, { size_z: newValue }); + }} />
@@ -392,8 +364,11 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) { handlePlacementUpdate(selectedPlacement.id, { color: e.target.value })} + value={editValues.color} + onChange={(e) => { + setEditValues((prev) => ({ ...prev, color: e.target.value })); + handlePlacementUpdate(selectedPlacement.id, { color: e.target.value }); + }} />
From 809ded37464ffbb385131cd0662fbcfb14b80736 Mon Sep 17 00:00:00 2001 From: dohyeons Date: Fri, 17 Oct 2025 18:00:27 +0900 Subject: [PATCH 02/11] =?UTF-8?q?=EB=AA=A8=EB=8B=AC=20=EC=97=B4=EB=A0=B8?= =?UTF-8?q?=EC=9D=84=20=EB=96=84=20=EC=9C=84=EC=A0=AF=EC=9D=B4=20=EB=81=8C?= =?UTF-8?q?=EB=A6=AC=EB=8A=94=20=ED=98=84=EC=83=81=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/dashboard/CanvasElement.tsx | 29 ++++++++++----- .../widgets/YardManagement3DWidget.tsx | 6 +-- .../widgets/yard-3d/YardLayoutCreateModal.tsx | 37 ++++++------------- 3 files changed, 34 insertions(+), 38 deletions(-) diff --git a/frontend/components/admin/dashboard/CanvasElement.tsx b/frontend/components/admin/dashboard/CanvasElement.tsx index e294a797..6b54daae 100644 --- a/frontend/components/admin/dashboard/CanvasElement.tsx +++ b/frontend/components/admin/dashboard/CanvasElement.tsx @@ -162,6 +162,11 @@ export function CanvasElement({ // 요소 선택 처리 const handleMouseDown = useCallback( (e: React.MouseEvent) => { + // 모달이나 다이얼로그가 열려있으면 드래그 무시 + if (document.querySelector('[role="dialog"]')) { + return; + } + // 닫기 버튼이나 리사이즈 핸들 클릭 시 무시 if ((e.target as HTMLElement).closest(".element-close, .resize-handle")) { return; @@ -192,6 +197,11 @@ export function CanvasElement({ // 리사이즈 핸들 마우스다운 const handleResizeMouseDown = useCallback( (e: React.MouseEvent, handle: string) => { + // 모달이나 다이얼로그가 열려있으면 리사이즈 무시 + if (document.querySelector('[role="dialog"]')) { + return; + } + e.stopPropagation(); setIsResizing(true); setResizeStart({ @@ -522,16 +532,15 @@ export function CanvasElement({ {element.customTitle || element.title}
{/* 설정 버튼 (기사관리 위젯만 자체 설정 UI 사용) */} - {onConfigure && - !(element.type === "widget" && element.subtype === "driver-management") && ( - - )} + {onConfigure && !(element.type === "widget" && element.subtype === "driver-management") && ( + + )} {/* 삭제 버튼 */}