3d필드로 텍스트 변경

This commit is contained in:
dohyeons
2025-11-25 15:06:55 +09:00
parent 60832e88ff
commit f59218aa43
9 changed files with 43 additions and 46 deletions

View File

@@ -57,7 +57,7 @@ import riskAlertRoutes from "./routes/riskAlertRoutes"; // 리스크/알림 관
import todoRoutes from "./routes/todoRoutes"; // To-Do 관리
import bookingRoutes from "./routes/bookingRoutes"; // 예약 요청 관리
import mapDataRoutes from "./routes/mapDataRoutes"; // 지도 데이터 관리
import yardLayoutRoutes from "./routes/yardLayoutRoutes"; // 야드 관리 3D
import yardLayoutRoutes from "./routes/yardLayoutRoutes"; // 3D 필드
//import materialRoutes from "./routes/materialRoutes"; // 자재 관리
import digitalTwinRoutes from "./routes/digitalTwinRoutes"; // 디지털 트윈 (야드 관제)
import flowRoutes from "./routes/flowRoutes"; // 플로우 관리
@@ -222,7 +222,7 @@ app.use("/api/risk-alerts", riskAlertRoutes); // 리스크/알림 관리
app.use("/api/todos", todoRoutes); // To-Do 관리
app.use("/api/bookings", bookingRoutes); // 예약 요청 관리
app.use("/api/map-data", mapDataRoutes); // 지도 데이터 조회
app.use("/api/yard-layouts", yardLayoutRoutes); // 야드 관리 3D
app.use("/api/yard-layouts", yardLayoutRoutes); // 3D 필드
// app.use("/api/materials", materialRoutes); // 자재 관리 (임시 주석)
app.use("/api/digital-twin", digitalTwinRoutes); // 디지털 트윈 (야드 관제)
app.use("/api/flow-external-db", flowExternalDbConnectionRoutes); // 플로우 전용 외부 DB 연결

View File

@@ -193,7 +193,7 @@ import { ListWidget } from "./widgets/ListWidget";
import { X } from "lucide-react";
import { Button } from "@/components/ui/button";
// 야드 관리 3D 위젯
// 3D 필드 위젯
const YardManagement3DWidget = dynamic(() => import("./widgets/YardManagement3DWidget"), {
ssr: false,
loading: () => (
@@ -1085,7 +1085,7 @@ export function CanvasElement({
<ListWidget element={element} />
</div>
) : element.type === "widget" && element.subtype === "yard-management-3d" ? (
// 야드 관리 3D 위젯 렌더링
// 3D 필드 위젯 렌더링
<div className="widget-interactive-area h-full w-full">
<YardManagement3DWidget
isEditMode={true}

View File

@@ -749,7 +749,7 @@ function getElementTitle(type: ElementType, subtype: ElementSubtype): string {
case "document":
return "문서 위젯";
case "yard-management-3d":
return "야드 관리 3D";
return "3D 필드";
case "work-history":
return "작업 이력";
case "transport-stats":

View File

@@ -362,7 +362,7 @@ export function DashboardTopMenu({
<SelectItem value="list-v2"></SelectItem>
<SelectItem value="custom-metric-v2"> </SelectItem>
<SelectItem value="risk-alert-v2">/</SelectItem>
<SelectItem value="yard-management-3d"> 3D</SelectItem>
<SelectItem value="yard-management-3d">3D </SelectItem>
{/* <SelectItem value="transport-stats">커스텀 통계 카드</SelectItem> */}
{/* <SelectItem value="status-summary">커스텀 상태 카드</SelectItem> */}
</SelectGroup>

View File

@@ -93,7 +93,7 @@ const getWidgetTitle = (subtype: ElementSubtype): string => {
chart: "차트",
"map-summary-v2": "지도",
"risk-alert-v2": "리스크 알림",
"yard-management-3d": "야드 관리 3D",
"yard-management-3d": "3D 필드",
weather: "날씨 위젯",
exchange: "환율 위젯",
calculator: "계산기",
@@ -449,7 +449,7 @@ export function WidgetConfigSidebar({ element, isOpen, onClose, onApply }: Widge
</div>
</div>
{/* 레이아웃 선택 (야드 관리 3D 위젯 전용) */}
{/* 레이아웃 선택 (3D 필드 위젯 전용) */}
{element.subtype === "yard-management-3d" && (
<div className="bg-background rounded-lg p-3 shadow-sm">
<Label htmlFor="layout-id" className="mb-2 block text-xs font-semibold">

View File

@@ -49,7 +49,7 @@ export type ElementSubtype =
| "maintenance"
| "document"
// | "list" // (구버전 - 주석 처리: 2025-10-28, list-v2로 대체)
| "yard-management-3d" // 야드 관리 3D 위젯
| "yard-management-3d" // 3D 필드 위젯
| "work-history" // 작업 이력 위젯
| "transport-stats"; // 커스텀 통계 카드 위젯
// | "custom-metric"; // (구버전 - 주석 처리: 2025-10-28, custom-metric-v2로 대체)
@@ -116,7 +116,7 @@ export interface DashboardElement {
calendarConfig?: CalendarConfig; // 달력 설정
driverManagementConfig?: DriverManagementConfig; // 기사 관리 설정
listConfig?: ListWidgetConfig; // 리스트 위젯 설정
yardConfig?: YardManagementConfig; // 야드 관리 3D 설정
yardConfig?: YardManagementConfig; // 3D 필드 설정
customMetricConfig?: CustomMetricConfig; // 사용자 커스텀 카드 설정
}
@@ -385,7 +385,7 @@ export interface ListColumn {
visible?: boolean; // 표시 여부 (기본: true)
}
// 야드 관리 3D 설정
// 3D 필드 설정
export interface YardManagementConfig {
layoutId: number; // 선택된 야드 레이아웃 ID
layoutName?: string; // 레이아웃 이름 (표시용)

View File

@@ -42,14 +42,16 @@ export default function YardManagement3DWidget({
setIsLoading(true);
const response = await getLayouts();
if (response.success && response.data) {
setLayouts(response.data.map((layout: any) => ({
id: layout.id,
name: layout.layout_name,
description: layout.description || "",
placement_count: layout.object_count || 0,
created_at: layout.created_at,
updated_at: layout.updated_at,
})));
setLayouts(
response.data.map((layout: any) => ({
id: layout.id,
name: layout.layout_name,
description: layout.description || "",
placement_count: layout.object_count || 0,
created_at: layout.created_at,
updated_at: layout.updated_at,
})),
);
}
} catch (error) {
console.error("야드 레이아웃 목록 조회 실패:", error);
@@ -152,11 +154,7 @@ export default function YardManagement3DWidget({
onMouseDown={(e) => e.stopPropagation()}
onClick={(e) => e.stopPropagation()}
>
<DigitalTwinEditor
layoutId={editingLayout.id}
layoutName={editingLayout.name}
onBack={handleEditComplete}
/>
<DigitalTwinEditor layoutId={editingLayout.id} layoutName={editingLayout.name} onBack={handleEditComplete} />
</div>
);
}
@@ -164,30 +162,31 @@ export default function YardManagement3DWidget({
// 편집 모드: 레이아웃 선택 UI
if (isEditMode) {
return (
<div className="widget-interactive-area flex h-full w-full flex-col bg-background">
<div className="widget-interactive-area bg-background flex h-full w-full flex-col">
<div className="flex items-center justify-between border-b p-4">
<div>
<h3 className="text-sm font-semibold text-foreground"> </h3>
<p className="mt-1 text-xs text-muted-foreground">
{config?.layoutName ? `선택됨: ${config.layoutName}` : "표시할 야드 레이아웃을 선택하세요"}
<h3 className="text-foreground text-sm font-semibold">3D </h3>
<p className="text-muted-foreground mt-1 text-xs">
{config?.layoutName ? `선택됨: ${config.layoutName}` : "표시할 3D필드를 선택하세요"}
</p>
</div>
<Button onClick={() => setIsCreateModalOpen(true)} size="sm">
<Plus className="mr-1 h-4 w-4" /> 3d필드
<Plus className="mr-1 h-4 w-4" />
3D필드
</Button>
</div>
<div className="flex-1 overflow-auto p-4">
{isLoading ? (
<div className="flex h-full items-center justify-center">
<div className="text-sm text-muted-foreground"> ...</div>
<div className="text-muted-foreground text-sm"> ...</div>
</div>
) : layouts.length === 0 ? (
<div className="flex h-full items-center justify-center">
<div className="text-center">
<div className="mb-2 text-4xl">🏗</div>
<div className="text-sm text-foreground"> </div>
<div className="mt-1 text-xs text-muted-foreground"> </div>
<div className="text-foreground text-sm"> 3D필드가 </div>
<div className="text-muted-foreground mt-1 text-xs"> 3D필드가 </div>
</div>
</div>
) : (
@@ -202,11 +201,11 @@ export default function YardManagement3DWidget({
<div className="flex items-start justify-between gap-3">
<button onClick={() => handleSelectLayout(layout)} className="flex-1 text-left hover:opacity-80">
<div className="flex items-center gap-2">
<span className="font-medium text-foreground">{layout.name}</span>
{config?.layoutId === layout.id && <Check className="h-4 w-4 text-primary" />}
<span className="text-foreground font-medium">{layout.name}</span>
{config?.layoutId === layout.id && <Check className="text-primary h-4 w-4" />}
</div>
{layout.description && <p className="mt-1 text-xs text-muted-foreground">{layout.description}</p>}
<div className="mt-2 text-xs text-muted-foreground"> : {layout.placement_count}</div>
{layout.description && <p className="text-muted-foreground mt-1 text-xs">{layout.description}</p>}
<div className="text-muted-foreground mt-2 text-xs"> : {layout.placement_count}</div>
</button>
<div className="flex gap-1">
<Button
@@ -257,12 +256,12 @@ export default function YardManagement3DWidget({
<DialogTitle> </DialogTitle>
</DialogHeader>
<div className="space-y-4">
<p className="text-sm text-foreground">
<p className="text-foreground text-sm">
?
<br />
.
<br />
<span className="font-semibold text-destructive"> .</span>
<span className="text-destructive font-semibold"> .</span>
</p>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => setDeleteLayoutId(null)}>
@@ -283,14 +282,12 @@ export default function YardManagement3DWidget({
if (!config?.layoutId) {
console.warn("⚠️ 야드관리 위젯: layoutId가 설정되지 않음", { config, isEditMode });
return (
<div className="flex h-full w-full items-center justify-center bg-muted">
<div className="bg-muted flex h-full w-full items-center justify-center">
<div className="text-center">
<div className="mb-2 text-4xl">🏗</div>
<div className="text-sm font-medium text-foreground"> </div>
<div className="mt-1 text-xs text-muted-foreground"> </div>
<div className="mt-2 text-xs text-destructive">
디버그: config={JSON.stringify(config)}
</div>
<div className="text-foreground text-sm font-medium">3D필드가 </div>
<div className="text-muted-foreground mt-1 text-xs"> 3D필드를 </div>
<div className="text-destructive mt-2 text-xs">디버그: config={JSON.stringify(config)}</div>
</div>
</div>
);

View File

@@ -68,7 +68,7 @@ export default function YardLayoutCreateModal({ isOpen, onClose, onCreate }: Yar
<ResizableDialogContent className="sm:max-w-[500px]" onPointerDown={(e) => e.stopPropagation()}>
<ResizableDialogHeader>
<div className="flex items-center gap-2">
<ResizableDialogTitle> 3d필드 </ResizableDialogTitle>
<ResizableDialogTitle> 3D필드 </ResizableDialogTitle>
<ResizableDialogDescription> </ResizableDialogDescription>
</div>
</ResizableDialogHeader>

View File

@@ -1,4 +1,4 @@
// 야드 관리 3D - 타입 정의
// 3D 필드 - 타입 정의
import { ChartDataSource } from "../../types";