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

102 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React from "react";
import { Handle, Position, NodeResizer } 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;
onScrollAreaEnter?: () => void;
onScrollAreaLeave?: () => void;
selected?: boolean;
selectedFields?: string[]; // 선택된 필드 목록
}
export const ScreenNode: React.FC<{ data: ScreenNodeData; selected?: boolean }> = ({ data, selected }) => {
const { screen, onFieldClick, onScrollAreaEnter, onScrollAreaLeave, selectedFields = [] } = data;
// 필드 타입에 따른 색상 반환
const getFieldTypeColor = (type: string) => {
if (!type || typeof type !== "string") return "text-gray-600 bg-gray-50";
const upperType = type.toUpperCase();
if (upperType.includes("INTEGER") || upperType.includes("NUMERIC")) return "text-blue-600 bg-blue-50";
if (upperType.includes("VARCHAR") || upperType.includes("TEXT")) return "text-green-600 bg-green-50";
if (upperType.includes("TIMESTAMP") || upperType.includes("DATE")) return "text-purple-600 bg-purple-50";
if (upperType.includes("BOOLEAN")) return "text-orange-600 bg-orange-50";
return "text-gray-600 bg-gray-50";
};
return (
<div className="flex h-full min-h-52 w-full min-w-80 flex-col rounded-lg border-2 border-gray-300 bg-white shadow-lg transition-shadow hover:shadow-xl">
{/* NodeResizer - 선택된 경우에만 표시 */}
{selected && <NodeResizer color="#3B82F6" isVisible={selected} minWidth={320} minHeight={200} />}
{/* 노드 헤더 */}
<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="flex flex-1 flex-col overflow-hidden 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="flex-1 space-y-2 overflow-y-auto"
onMouseEnter={onScrollAreaEnter}
onMouseLeave={onScrollAreaLeave}
>
{screen.fields.map((field, index) => {
const isSelected = selectedFields.includes(field.name);
return (
<div
key={field.name}
className={`relative flex cursor-pointer items-center justify-between rounded-lg border p-3 transition-colors ${
isSelected
? "border-blue-500 bg-blue-50 hover:bg-blue-100"
: "border-transparent 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>
</div>
);
};