From e934cc945bbe1c7a0f76171c2eaf9509e6eb89de Mon Sep 17 00:00:00 2001 From: kjs Date: Thu, 23 Oct 2025 10:07:55 +0900 Subject: [PATCH] =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=BB=AC?= =?UTF-8?q?=EB=9F=BC=20=EC=A4=91=EB=B3=B5=20=EC=82=BD=EC=9E=85=20=EC=95=88?= =?UTF-8?q?=EB=90=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/components/screen/ScreenDesigner.tsx | 28 +++++++++++++++++++ .../screen/panels/ComponentsPanel.tsx | 5 +++- .../components/screen/panels/TablesPanel.tsx | 27 ++++++++++++++---- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/frontend/components/screen/ScreenDesigner.tsx b/frontend/components/screen/ScreenDesigner.tsx index 046f955f..e57418a9 100644 --- a/frontend/components/screen/ScreenDesigner.tsx +++ b/frontend/components/screen/ScreenDesigner.tsx @@ -356,6 +356,33 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD ); }, [tables, searchTerm]); + // 이미 배치된 컬럼 목록 계산 + const placedColumns = useMemo(() => { + const placed = new Set(); + + const collectColumns = (components: ComponentData[]) => { + components.forEach((comp) => { + const anyComp = comp as any; + + // widget 타입 또는 component 타입 (새로운 시스템)에서 tableName과 columnName 확인 + if ((comp.type === "widget" || comp.type === "component") && anyComp.tableName && anyComp.columnName) { + const key = `${anyComp.tableName}.${anyComp.columnName}`; + placed.add(key); + console.log("🔍 배치된 컬럼 발견:", key, "타입:", comp.type); + } + + // 자식 컴포넌트도 확인 (재귀) + if (comp.children && comp.children.length > 0) { + collectColumns(comp.children); + } + }); + }; + + collectColumns(layout.components); + console.log("📋 배치된 컬럼 목록:", Array.from(placed)); + return placed; + }, [layout.components]); + // 히스토리에 저장 const saveToHistory = useCallback( (newLayout: LayoutData) => { @@ -3926,6 +3953,7 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD e.dataTransfer.setData("application/json", JSON.stringify(dragData)); }} selectedTableName={selectedScreen.tableName} + placedColumns={placedColumns} /> diff --git a/frontend/components/screen/panels/ComponentsPanel.tsx b/frontend/components/screen/panels/ComponentsPanel.tsx index 9d25536c..b341cfb2 100644 --- a/frontend/components/screen/panels/ComponentsPanel.tsx +++ b/frontend/components/screen/panels/ComponentsPanel.tsx @@ -18,6 +18,7 @@ interface ComponentsPanelProps { onSearchChange?: (value: string) => void; onTableDragStart?: (e: React.DragEvent, table: TableInfo, column?: ColumnInfo) => void; selectedTableName?: string; + placedColumns?: Set; // 이미 배치된 컬럼명 집합 } export function ComponentsPanel({ @@ -26,7 +27,8 @@ export function ComponentsPanel({ searchTerm = "", onSearchChange, onTableDragStart, - selectedTableName + selectedTableName, + placedColumns }: ComponentsPanelProps) { const [searchQuery, setSearchQuery] = useState(""); @@ -207,6 +209,7 @@ export function ComponentsPanel({ onSearchChange={onSearchChange || (() => {})} onDragStart={onTableDragStart} selectedTableName={selectedTableName} + placedColumns={placedColumns} /> ) : (
diff --git a/frontend/components/screen/panels/TablesPanel.tsx b/frontend/components/screen/panels/TablesPanel.tsx index 4b667599..9f42dfef 100644 --- a/frontend/components/screen/panels/TablesPanel.tsx +++ b/frontend/components/screen/panels/TablesPanel.tsx @@ -26,6 +26,7 @@ interface TablesPanelProps { onSearchChange: (term: string) => void; onDragStart: (e: React.DragEvent, table: TableInfo, column?: any) => void; selectedTableName?: string; + placedColumns?: Set; // 이미 배치된 컬럼명 집합 (tableName.columnName 형식) } // 위젯 타입별 아이콘 @@ -67,6 +68,7 @@ export const TablesPanel: React.FC = ({ onSearchChange, onDragStart, selectedTableName, + placedColumns = new Set(), }) => { const [expandedTables, setExpandedTables] = useState>(new Set()); @@ -80,11 +82,26 @@ export const TablesPanel: React.FC = ({ setExpandedTables(newExpanded); }; - const filteredTables = tables.filter( - (table) => - table.tableName.toLowerCase().includes(searchTerm.toLowerCase()) || - table.columns.some((col) => col.columnName.toLowerCase().includes(searchTerm.toLowerCase())), - ); + // 이미 배치된 컬럼을 제외한 테이블 정보 생성 + const tablesWithAvailableColumns = tables.map((table) => ({ + ...table, + columns: table.columns.filter((col) => { + const columnKey = `${table.tableName}.${col.columnName}`; + const isPlaced = placedColumns.has(columnKey); + if (isPlaced) { + console.log("🚫 필터링된 컬럼:", columnKey); + } + return !isPlaced; + }), + })); + + const filteredTables = tablesWithAvailableColumns + .filter((table) => table.columns.length > 0) // 사용 가능한 컬럼이 있는 테이블만 표시 + .filter( + (table) => + table.tableName.toLowerCase().includes(searchTerm.toLowerCase()) || + table.columns.some((col) => col.columnName.toLowerCase().includes(searchTerm.toLowerCase())), + ); return (