diff --git a/frontend/components/admin/dashboard/widgets/yard-3d/DigitalTwinEditor.tsx b/frontend/components/admin/dashboard/widgets/yard-3d/DigitalTwinEditor.tsx index 88e844d3..ac9aac19 100644 --- a/frontend/components/admin/dashboard/widgets/yard-3d/DigitalTwinEditor.tsx +++ b/frontend/components/admin/dashboard/widgets/yard-3d/DigitalTwinEditor.tsx @@ -25,6 +25,7 @@ import { import type { MaterialData } from "@/types/digitalTwin"; import { ExternalDbConnectionAPI } from "@/lib/api/externalDbConnection"; import HierarchyConfigPanel, { HierarchyConfig } from "./HierarchyConfigPanel"; +import { OBJECT_COLORS, DEFAULT_COLOR } from "./constants"; import { validateSpatialContainment, updateChildrenPositions, getAllDescendants } from "./spatialContainment"; // 백엔드 DB 객체 타입 (snake_case) @@ -702,7 +703,7 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi name: objectName, position: { x, y: yPosition, z }, size: defaults.size || { x: 5, y: 5, z: 5 }, - color: defaults.color || "#9ca3af", + color: OBJECT_COLORS[draggedTool] || DEFAULT_COLOR, // 타입별 기본 색상 areaKey, locaKey, locType, @@ -1169,8 +1170,8 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi 도구: {[ { type: "area" as ToolType, label: "영역", icon: Grid3x3, color: "text-blue-500" }, - { type: "location-bed" as ToolType, label: "베드", icon: Package, color: "text-emerald-500" }, - { type: "location-stp" as ToolType, label: "정차", icon: Move, color: "text-orange-500" }, + { type: "location-bed" as ToolType, label: "베드", icon: Package, color: "text-blue-600" }, + { type: "location-stp" as ToolType, label: "정차", icon: Move, color: "text-gray-500" }, // { type: "crane-gantry" as ToolType, label: "겐트리", icon: Combine, color: "text-green-500" }, { type: "crane-mobile" as ToolType, label: "크레인", icon: Truck, color: "text-yellow-500" }, { type: "rack" as ToolType, label: "랙", icon: Box, color: "text-purple-500" }, @@ -1221,54 +1222,6 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi - {/* 창고 테이블 및 컬럼 매핑 */} - {selectedDbConnection && ( -
- - - {/* 이 레이아웃의 창고 선택 */} - {hierarchyConfig?.warehouse?.tableName && hierarchyConfig?.warehouse?.keyColumn && ( -
- - {loadingWarehouses ? ( -
- -
- ) : ( - - )} -
- )} -
- )} - {/* 계층 설정 패널 (신규) */} {selectedDbConnection && ( )} + {/* 창고 선택 (HierarchyConfigPanel 아래로 이동) */} + {selectedDbConnection && hierarchyConfig?.warehouse?.tableName && hierarchyConfig?.warehouse?.keyColumn && ( +
+ + +
+ + {loadingWarehouses ? ( +
+ +
+ ) : ( + + )} +
+
+ )} + {/* Area 목록 */} {selectedDbConnection && selectedWarehouse && (
@@ -1605,7 +1605,7 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi handleObjectUpdate({ name: e.target.value })} className="mt-1.5 h-9 text-sm" /> @@ -1622,7 +1622,7 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi handleObjectUpdate({ position: { @@ -1641,7 +1641,7 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi handleObjectUpdate({ position: { @@ -1669,7 +1669,7 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi type="number" step="5" min="5" - value={selectedObject.size.x} + value={selectedObject.size?.x || 5} onChange={(e) => handleObjectUpdate({ size: { @@ -1688,7 +1688,7 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi handleObjectUpdate({ size: { @@ -1709,7 +1709,7 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi type="number" step="5" min="5" - value={selectedObject.size.z} + value={selectedObject.size?.z || 5} onChange={(e) => handleObjectUpdate({ size: { @@ -1732,7 +1732,7 @@ export default function DigitalTwinEditor({ layoutId, layoutName, onBack }: Digi handleObjectUpdate({ color: e.target.value })} className="mt-1.5 h-9" /> diff --git a/frontend/components/admin/dashboard/widgets/yard-3d/DigitalTwinViewer.tsx b/frontend/components/admin/dashboard/widgets/yard-3d/DigitalTwinViewer.tsx index 3945a692..94ef98fb 100644 --- a/frontend/components/admin/dashboard/widgets/yard-3d/DigitalTwinViewer.tsx +++ b/frontend/components/admin/dashboard/widgets/yard-3d/DigitalTwinViewer.tsx @@ -10,6 +10,7 @@ import dynamic from "next/dynamic"; import { useToast } from "@/hooks/use-toast"; import type { PlacedObject, MaterialData } from "@/types/digitalTwin"; import { getLayoutById, getMaterials } from "@/lib/api/digitalTwin"; +import { OBJECT_COLORS, DEFAULT_COLOR } from "./constants"; const Yard3DCanvas = dynamic(() => import("./Yard3DCanvas"), { ssr: false, @@ -81,7 +82,7 @@ export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps) z: parseFloat(obj.size_z), }, rotation: obj.rotation ? parseFloat(obj.rotation) : 0, - color: getObjectColor(objectType), // 타입별 기본 색상 사용 + color: getObjectColor(objectType, obj.color), // 저장된 색상 우선, 없으면 타입별 기본 색상 areaKey: obj.area_key, locaKey: obj.loca_key, locType: obj.loc_type, @@ -225,17 +226,11 @@ export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps) // 객체 타입별 기본 색상 (useMemo로 최적화) const getObjectColor = useMemo(() => { - return (type: string): string => { - const colorMap: Record = { - area: "#3b82f6", // 파란색 - "location-bed": "#2563eb", // 진한 파란색 - "location-stp": "#6b7280", // 회색 - "location-temp": "#f59e0b", // 주황색 - "location-dest": "#10b981", // 초록색 - "crane-mobile": "#8b5cf6", // 보라색 - rack: "#ef4444", // 빨간색 - }; - return colorMap[type] || "#3b82f6"; + return (type: string, savedColor?: string): string => { + // 저장된 색상이 있으면 우선 사용 + if (savedColor) return savedColor; + // 없으면 타입별 기본 색상 사용 + return OBJECT_COLORS[type] || DEFAULT_COLOR; }; }, []); @@ -383,7 +378,7 @@ export default function DigitalTwinViewer({ layoutId }: DigitalTwinViewerProps)
{typeLabel}
diff --git a/frontend/components/admin/dashboard/widgets/yard-3d/HierarchyConfigPanel.tsx b/frontend/components/admin/dashboard/widgets/yard-3d/HierarchyConfigPanel.tsx index 8a6f4bfd..d309c92f 100644 --- a/frontend/components/admin/dashboard/widgets/yard-3d/HierarchyConfigPanel.tsx +++ b/frontend/components/admin/dashboard/widgets/yard-3d/HierarchyConfigPanel.tsx @@ -257,7 +257,7 @@ export default function HierarchyConfigPanel({
handleLevelChange(level.level, "name", e.target.value)} className="h-7 w-32 text-xs" placeholder="레벨명" @@ -276,7 +276,7 @@ export default function HierarchyConfigPanel({
handleLevelChange(level.level, "keyColumn", val)} > @@ -319,7 +319,7 @@ export default function HierarchyConfigPanel({
handleLevelChange(level.level, "parentKeyColumn", val)} > @@ -422,7 +422,7 @@ export default function HierarchyConfigPanel({
handleMaterialChange("locationKeyColumn", val)} > diff --git a/frontend/components/admin/dashboard/widgets/yard-3d/constants.ts b/frontend/components/admin/dashboard/widgets/yard-3d/constants.ts new file mode 100644 index 00000000..d4959a6c --- /dev/null +++ b/frontend/components/admin/dashboard/widgets/yard-3d/constants.ts @@ -0,0 +1,30 @@ +/** + * 디지털 트윈 3D 야드 - 공통 상수 + */ + +// 객체 타입별 색상 매핑 (HEX 코드) +export const OBJECT_COLORS: Record = { + area: "#3b82f6", // 파란색 + "location-bed": "#2563eb", // 진한 파란색 + "location-stp": "#6b7280", // 회색 + "location-temp": "#f59e0b", // 주황색 + "location-dest": "#10b981", // 초록색 + "crane-mobile": "#8b5cf6", // 보라색 + rack: "#ef4444", // 빨간색 +}; + +// Tailwind 색상 클래스 매핑 (아이콘용) +export const OBJECT_COLOR_CLASSES: Record = { + area: "text-blue-500", + "location-bed": "text-blue-600", + "location-stp": "text-gray-500", + "location-temp": "text-orange-500", + "location-dest": "text-emerald-500", + "crane-mobile": "text-purple-500", + rack: "text-red-500", +}; + +// 기본 색상 +export const DEFAULT_COLOR = "#3b82f6"; +export const DEFAULT_COLOR_CLASS = "text-blue-500"; +