계층 구조 유효성 검사 및 그룹 이동 기능 구현

This commit is contained in:
dohyeons 2025-11-24 15:57:28 +09:00
parent 68e8e7b36b
commit 7994b2a72a
2 changed files with 114 additions and 16 deletions

View File

@ -657,13 +657,13 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi
};
// 캔버스에 드롭
const handleCanvasDrop = (x: number, z: number) => {
const handleCanvasDrop = async (x: number, z: number) => {
if (!draggedTool) return;
const defaults = getToolDefaults(draggedTool);
// Area는 바닥(y=0.05)에, 다른 객체는 중앙 정렬
const yPosition = draggedTool === "area" ? 0.05 : (defaults.size?.y || 1) / 2;
let yPosition = draggedTool === "area" ? 0.05 : (defaults.size?.y || 1) / 2;
// 외부 DB 데이터에서 드래그한 경우 해당 정보 사용
let objectName = defaults.name || "새 객체";
@ -697,12 +697,51 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi
externalKey = draggedLocationData.LOCAKEY;
}
// 기본 크기 설정
let objectSize = defaults.size || { x: 5, y: 5, z: 5 };
// Location 배치 시 자재 개수에 따라 높이 자동 설정
if (
(draggedTool === "location-bed" ||
draggedTool === "location-stp" ||
draggedTool === "location-temp" ||
draggedTool === "location-dest") &&
locaKey &&
selectedDbConnection &&
hierarchyConfig?.material
) {
try {
// 해당 Location의 자재 개수 조회
const countsResponse = await getMaterialCounts(selectedDbConnection, hierarchyConfig.material.tableName, [
locaKey,
]);
if (countsResponse.success && countsResponse.data && countsResponse.data.length > 0) {
const materialCount = countsResponse.data[0].count;
// 자재 개수에 비례해서 높이(Y축) 설정 (최소 5, 최대 30)
// 자재 1개 = 높이 5, 자재 10개 = 높이 15, 자재 50개 = 높이 30
const calculatedHeight = Math.min(30, Math.max(5, 5 + materialCount * 0.5));
objectSize = {
...objectSize,
y: calculatedHeight, // Y축이 높이!
};
// 높이가 높아진 만큼 Y 위치도 올려서 바닥을 뚫지 않게 조정
yPosition = calculatedHeight / 2;
}
} catch (error) {
console.error("자재 개수 조회 실패, 기본 높이 사용:", error);
}
}
const newObject: PlacedObject = {
id: nextObjectId,
type: draggedTool,
name: objectName,
position: { x, y: yPosition, z },
size: defaults.size || { x: 5, y: 5, z: 5 },
size: objectSize,
color: OBJECT_COLORS[draggedTool] || DEFAULT_COLOR, // 타입별 기본 색상
areaKey,
locaKey,

View File

@ -442,20 +442,79 @@ function MaterialBox({
</>
)}
{/* Area 이름 텍스트 */}
{/* Area 이름 텍스트 - 위쪽 (바닥) */}
{placement.name && (
<Text
position={[0, 0.15, 0]}
rotation={[-Math.PI / 2, 0, 0]}
fontSize={Math.min(boxWidth, boxDepth) * 0.2}
color={placement.color}
anchorX="center"
anchorY="middle"
outlineWidth={0.05}
outlineColor="#000000"
>
{placement.name}
</Text>
<>
<Text
position={[0, 0.15, 0]}
rotation={[-Math.PI / 2, 0, 0]}
fontSize={Math.min(boxWidth, boxDepth) * 0.2}
color={placement.color}
anchorX="center"
anchorY="middle"
outlineWidth={0.05}
outlineColor="#000000"
>
{placement.name}
</Text>
{/* 4면에 텍스트 표시 */}
{/* 앞면 (+Z) */}
<Text
position={[0, boxHeight / 2, boxDepth / 2 + 0.01]}
rotation={[0, 0, 0]}
fontSize={Math.min(boxWidth, boxHeight) * 0.3}
color="#ffffff"
anchorX="center"
anchorY="middle"
outlineWidth={0.08}
outlineColor="#000000"
>
{placement.name}
</Text>
{/* 뒷면 (-Z) */}
<Text
position={[0, boxHeight / 2, -boxDepth / 2 - 0.01]}
rotation={[0, Math.PI, 0]}
fontSize={Math.min(boxWidth, boxHeight) * 0.3}
color="#ffffff"
anchorX="center"
anchorY="middle"
outlineWidth={0.08}
outlineColor="#000000"
>
{placement.name}
</Text>
{/* 왼쪽면 (-X) */}
<Text
position={[-boxWidth / 2 - 0.01, boxHeight / 2, 0]}
rotation={[0, -Math.PI / 2, 0]}
fontSize={Math.min(boxDepth, boxHeight) * 0.3}
color="#ffffff"
anchorX="center"
anchorY="middle"
outlineWidth={0.08}
outlineColor="#000000"
>
{placement.name}
</Text>
{/* 오른쪽면 (+X) */}
<Text
position={[boxWidth / 2 + 0.01, boxHeight / 2, 0]}
rotation={[0, Math.PI / 2, 0]}
fontSize={Math.min(boxDepth, boxHeight) * 0.3}
color="#ffffff"
anchorX="center"
anchorY="middle"
outlineWidth={0.08}
outlineColor="#000000"
>
{placement.name}
</Text>
</>
)}
</>
);