ERP-node/frontend/components/dataflow/ScreenNode.tsx

110 lines
4.0 KiB
TypeScript
Raw Normal View History

2025-09-05 11:30:27 +09:00
"use client";
import React from "react";
import { Handle, Position } from "@xyflow/react";
interface ScreenField {
name: string;
type: string;
description: string;
}
interface Screen {
screenId: string;
screenName: string;
screenCode: string;
tableName: string;
fields: ScreenField[];
}
interface ScreenNodeData {
screen: Screen;
onFieldClick: (screenId: string, fieldName: string) => void;
}
export const ScreenNode: React.FC<{ data: ScreenNodeData }> = ({ data }) => {
const { screen, onFieldClick } = data;
// 필드 타입에 따른 색상 반환
const getFieldTypeColor = (type: string) => {
if (type.includes("INTEGER") || type.includes("NUMERIC")) return "text-blue-600 bg-blue-50";
if (type.includes("VARCHAR") || type.includes("TEXT")) return "text-green-600 bg-green-50";
if (type.includes("TIMESTAMP") || type.includes("DATE")) return "text-purple-600 bg-purple-50";
if (type.includes("BOOLEAN")) return "text-orange-600 bg-orange-50";
return "text-gray-600 bg-gray-50";
};
return (
<div className="max-w-96 min-w-80 rounded-lg border-2 border-gray-300 bg-white shadow-lg transition-shadow hover:shadow-xl">
{/* 노드 헤더 */}
<div className="rounded-t-lg bg-gradient-to-r from-blue-500 to-blue-600 p-4 text-white">
<div className="mb-1 text-base font-bold">{screen.screenName}</div>
<div className="mb-1 text-sm opacity-90">ID: {screen.screenCode}</div>
<div className="flex items-center text-xs opacity-75">
<span className="mr-1">🗃</span>
: {screen.tableName}
</div>
</div>
{/* 필드 목록 */}
<div className="p-4">
<div className="mb-3 flex items-center justify-between">
<div className="text-sm font-semibold text-gray-700"> </div>
<div className="rounded-full bg-gray-100 px-2 py-1 text-xs text-gray-500">{screen.fields.length}</div>
</div>
<div className="max-h-64 space-y-2 overflow-y-auto">
{screen.fields.map((field, index) => (
<div
key={field.name}
className="flex cursor-pointer items-center justify-between rounded-lg border border-transparent p-3 transition-colors hover:border-gray-200 hover:bg-gray-50"
onClick={() => onFieldClick(screen.screenId, field.name)}
>
<div className="min-w-0 flex-1">
<div className="mb-1 flex items-center">
<div className="truncate text-sm font-medium text-gray-900">{field.name}</div>
{index === 0 && (
<span className="ml-2 rounded bg-yellow-100 px-1.5 py-0.5 text-xs text-yellow-800">PK</span>
)}
</div>
<div className="truncate text-xs text-gray-500">{field.description}</div>
</div>
<div className={`ml-2 rounded px-2 py-1 font-mono text-xs ${getFieldTypeColor(field.type)}`}>
{field.type}
</div>
</div>
))}
</div>
</div>
{/* React Flow 핸들 */}
<Handle
type="source"
position={Position.Right}
className="h-4 w-4 border-2 border-white bg-blue-500 shadow-md transition-colors hover:bg-blue-600"
title="연결 시작점"
/>
<Handle
type="target"
position={Position.Left}
className="h-4 w-4 border-2 border-white bg-green-500 shadow-md transition-colors hover:bg-green-600"
title="연결 도착점"
/>
{/* 추가 핸들들 (상하) */}
<Handle
type="source"
position={Position.Bottom}
className="h-4 w-4 border-2 border-white bg-blue-500 shadow-md transition-colors hover:bg-blue-600"
id="bottom-source"
/>
<Handle
type="target"
position={Position.Top}
className="h-4 w-4 border-2 border-white bg-green-500 shadow-md transition-colors hover:bg-green-600"
id="top-target"
/>
</div>
);
};