배치 정보 조절 에러 해결
This commit is contained in:
parent
6603ff81fe
commit
8b28107147
|
|
@ -49,9 +49,6 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (placement) {
|
if (placement) {
|
||||||
setEditData({
|
setEditData({
|
||||||
position_x: placement.position_x,
|
|
||||||
position_y: placement.position_y,
|
|
||||||
position_z: placement.position_z,
|
|
||||||
size_x: placement.size_x,
|
size_x: placement.size_x,
|
||||||
size_y: placement.size_y,
|
size_y: placement.size_y,
|
||||||
size_z: placement.size_z,
|
size_z: placement.size_z,
|
||||||
|
|
@ -107,52 +104,6 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="text-xs font-medium text-gray-500">배치 정보 (편집 가능)</div>
|
<div className="text-xs font-medium text-gray-500">배치 정보 (편집 가능)</div>
|
||||||
|
|
||||||
{/* 3D 위치 */}
|
|
||||||
<div>
|
|
||||||
<Label className="text-xs">위치</Label>
|
|
||||||
<div className="grid grid-cols-3 gap-2">
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="edit-posX" className="text-xs text-gray-600">
|
|
||||||
X
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
id="edit-posX"
|
|
||||||
type="number"
|
|
||||||
value={editData.position_x ?? placement.position_x}
|
|
||||||
onChange={(e) => setEditData({ ...editData, position_x: parseFloat(e.target.value) || 0 })}
|
|
||||||
step="0.5"
|
|
||||||
className="h-8 text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="edit-posY" className="text-xs text-gray-600">
|
|
||||||
Y
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
id="edit-posY"
|
|
||||||
type="number"
|
|
||||||
value={editData.position_y ?? placement.position_y}
|
|
||||||
onChange={(e) => setEditData({ ...editData, position_y: parseFloat(e.target.value) || 0 })}
|
|
||||||
step="0.5"
|
|
||||||
className="h-8 text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="edit-posZ" className="text-xs text-gray-600">
|
|
||||||
Z
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
id="edit-posZ"
|
|
||||||
type="number"
|
|
||||||
value={editData.position_z ?? placement.position_z}
|
|
||||||
onChange={(e) => setEditData({ ...editData, position_z: parseFloat(e.target.value) || 0 })}
|
|
||||||
step="0.5"
|
|
||||||
className="h-8 text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 3D 크기 */}
|
{/* 3D 크기 */}
|
||||||
<div>
|
<div>
|
||||||
<Label className="text-xs">크기</Label>
|
<Label className="text-xs">크기</Label>
|
||||||
|
|
@ -167,7 +118,7 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo
|
||||||
value={editData.size_x ?? placement.size_x}
|
value={editData.size_x ?? placement.size_x}
|
||||||
onChange={(e) => setEditData({ ...editData, size_x: parseFloat(e.target.value) || 1 })}
|
onChange={(e) => setEditData({ ...editData, size_x: parseFloat(e.target.value) || 1 })}
|
||||||
min="1"
|
min="1"
|
||||||
step="0.5"
|
step="1"
|
||||||
className="h-8 text-xs"
|
className="h-8 text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -181,7 +132,7 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo
|
||||||
value={editData.size_y ?? placement.size_y}
|
value={editData.size_y ?? placement.size_y}
|
||||||
onChange={(e) => setEditData({ ...editData, size_y: parseFloat(e.target.value) || 1 })}
|
onChange={(e) => setEditData({ ...editData, size_y: parseFloat(e.target.value) || 1 })}
|
||||||
min="1"
|
min="1"
|
||||||
step="0.5"
|
step="1"
|
||||||
className="h-8 text-xs"
|
className="h-8 text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -195,7 +146,7 @@ export default function MaterialEditPanel({ placement, onClose, onUpdate, onRemo
|
||||||
value={editData.size_z ?? placement.size_z}
|
value={editData.size_z ?? placement.size_z}
|
||||||
onChange={(e) => setEditData({ ...editData, size_z: parseFloat(e.target.value) || 1 })}
|
onChange={(e) => setEditData({ ...editData, size_z: parseFloat(e.target.value) || 1 })}
|
||||||
min="1"
|
min="1"
|
||||||
step="0.5"
|
step="1"
|
||||||
className="h-8 text-xs"
|
className="h-8 text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -62,10 +62,15 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
const [placements, setPlacements] = useState<YardPlacement[]>([]);
|
const [placements, setPlacements] = useState<YardPlacement[]>([]);
|
||||||
const [materials, setMaterials] = useState<TempMaterial[]>([]);
|
const [materials, setMaterials] = useState<TempMaterial[]>([]);
|
||||||
const [selectedPlacement, setSelectedPlacement] = useState<YardPlacement | null>(null);
|
const [selectedPlacement, setSelectedPlacement] = useState<YardPlacement | null>(null);
|
||||||
const [selectedMaterial, setSelectedMaterial] = useState<TempMaterial | null>(null);
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
const [editValues, setEditValues] = useState({
|
||||||
|
size_x: 5,
|
||||||
|
size_y: 5,
|
||||||
|
size_z: 5,
|
||||||
|
color: "#3b82f6",
|
||||||
|
});
|
||||||
|
|
||||||
// 배치 목록 & 자재 목록 로드
|
// 배치 목록 & 자재 목록 로드
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -78,10 +83,10 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (placementsRes.success) {
|
if (placementsRes.success) {
|
||||||
setPlacements(placementsRes.data);
|
setPlacements(placementsRes.data as YardPlacement[]);
|
||||||
}
|
}
|
||||||
if (materialsRes.success) {
|
if (materialsRes.success) {
|
||||||
setMaterials(materialsRes.data);
|
setMaterials(materialsRes.data as TempMaterial[]);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("데이터 로드 실패:", error);
|
console.error("데이터 로드 실패:", error);
|
||||||
|
|
@ -93,6 +98,18 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
loadData();
|
loadData();
|
||||||
}, [layout.id]);
|
}, [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) => {
|
const handleMaterialClick = async (material: TempMaterial) => {
|
||||||
// 이미 배치되었는지 확인
|
// 이미 배치되었는지 확인
|
||||||
|
|
@ -102,8 +119,6 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedMaterial(material);
|
|
||||||
|
|
||||||
// 기본 위치에 배치
|
// 기본 위치에 배치
|
||||||
const placementData = {
|
const placementData = {
|
||||||
external_material_id: `TEMP-${material.id}`,
|
external_material_id: `TEMP-${material.id}`,
|
||||||
|
|
@ -123,11 +138,10 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
try {
|
try {
|
||||||
const response = await yardLayoutApi.addMaterialPlacement(layout.id, placementData);
|
const response = await yardLayoutApi.addMaterialPlacement(layout.id, placementData);
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
setPlacements((prev) => [...prev, response.data]);
|
setPlacements((prev) => [...prev, response.data as YardPlacement]);
|
||||||
setSelectedPlacement(response.data);
|
setSelectedPlacement(response.data as YardPlacement);
|
||||||
setSelectedMaterial(null);
|
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error("자재 배치 실패:", error);
|
console.error("자재 배치 실패:", error);
|
||||||
alert("자재 배치에 실패했습니다.");
|
alert("자재 배치에 실패했습니다.");
|
||||||
}
|
}
|
||||||
|
|
@ -262,7 +276,7 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
<Yard3DCanvas
|
<Yard3DCanvas
|
||||||
placements={placements}
|
placements={placements}
|
||||||
selectedPlacementId={selectedPlacement?.id || null}
|
selectedPlacementId={selectedPlacement?.id || null}
|
||||||
onPlacementClick={setSelectedPlacement}
|
onPlacementClick={(placement) => setSelectedPlacement(placement as YardPlacement)}
|
||||||
onPlacementDrag={handlePlacementDrag}
|
onPlacementDrag={handlePlacementDrag}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
@ -304,60 +318,18 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
<div className="space-y-3 border-t pt-4">
|
<div className="space-y-3 border-t pt-4">
|
||||||
<Label className="text-sm font-semibold">배치 정보</Label>
|
<Label className="text-sm font-semibold">배치 정보</Label>
|
||||||
|
|
||||||
<div className="grid grid-cols-3 gap-2">
|
|
||||||
<div>
|
|
||||||
<Label className="text-xs">X</Label>
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
step="0.5"
|
|
||||||
value={selectedPlacement.position_x}
|
|
||||||
onChange={(e) =>
|
|
||||||
handlePlacementUpdate(selectedPlacement.id, {
|
|
||||||
position_x: parseFloat(e.target.value),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label className="text-xs">Y</Label>
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
step="0.5"
|
|
||||||
value={selectedPlacement.position_y}
|
|
||||||
onChange={(e) =>
|
|
||||||
handlePlacementUpdate(selectedPlacement.id, {
|
|
||||||
position_y: parseFloat(e.target.value),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label className="text-xs">Z</Label>
|
|
||||||
<Input
|
|
||||||
type="number"
|
|
||||||
step="0.5"
|
|
||||||
value={selectedPlacement.position_z}
|
|
||||||
onChange={(e) =>
|
|
||||||
handlePlacementUpdate(selectedPlacement.id, {
|
|
||||||
position_z: parseFloat(e.target.value),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 gap-2">
|
||||||
<div>
|
<div>
|
||||||
<Label className="text-xs">너비</Label>
|
<Label className="text-xs">너비</Label>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
step="1"
|
step="1"
|
||||||
value={selectedPlacement.size_x}
|
value={editValues.size_x}
|
||||||
onChange={(e) =>
|
onChange={(e) => {
|
||||||
handlePlacementUpdate(selectedPlacement.id, {
|
const newValue = parseFloat(e.target.value) || 1;
|
||||||
size_x: parseFloat(e.target.value),
|
setEditValues((prev) => ({ ...prev, size_x: newValue }));
|
||||||
})
|
handlePlacementUpdate(selectedPlacement.id, { size_x: newValue });
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -365,12 +337,12 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
step="1"
|
step="1"
|
||||||
value={selectedPlacement.size_y}
|
value={editValues.size_y}
|
||||||
onChange={(e) =>
|
onChange={(e) => {
|
||||||
handlePlacementUpdate(selectedPlacement.id, {
|
const newValue = parseFloat(e.target.value) || 1;
|
||||||
size_y: parseFloat(e.target.value),
|
setEditValues((prev) => ({ ...prev, size_y: newValue }));
|
||||||
})
|
handlePlacementUpdate(selectedPlacement.id, { size_y: newValue });
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -378,12 +350,12 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
step="1"
|
step="1"
|
||||||
value={selectedPlacement.size_z}
|
value={editValues.size_z}
|
||||||
onChange={(e) =>
|
onChange={(e) => {
|
||||||
handlePlacementUpdate(selectedPlacement.id, {
|
const newValue = parseFloat(e.target.value) || 1;
|
||||||
size_z: parseFloat(e.target.value),
|
setEditValues((prev) => ({ ...prev, size_z: newValue }));
|
||||||
})
|
handlePlacementUpdate(selectedPlacement.id, { size_z: newValue });
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -392,8 +364,11 @@ export default function YardEditor({ layout, onBack }: YardEditorProps) {
|
||||||
<Label className="text-xs">색상</Label>
|
<Label className="text-xs">색상</Label>
|
||||||
<Input
|
<Input
|
||||||
type="color"
|
type="color"
|
||||||
value={selectedPlacement.color}
|
value={editValues.color}
|
||||||
onChange={(e) => handlePlacementUpdate(selectedPlacement.id, { color: e.target.value })}
|
onChange={(e) => {
|
||||||
|
setEditValues((prev) => ({ ...prev, color: e.target.value }));
|
||||||
|
handlePlacementUpdate(selectedPlacement.id, { color: e.target.value });
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue