diff --git a/frontend/components/screen/InteractiveScreenViewer.tsx b/frontend/components/screen/InteractiveScreenViewer.tsx index ff6e614d..b758a584 100644 --- a/frontend/components/screen/InteractiveScreenViewer.tsx +++ b/frontend/components/screen/InteractiveScreenViewer.tsx @@ -1762,7 +1762,7 @@ export const InteractiveScreenViewer: React.FC = ( writer: mappedData.writer || writerValue, // ✅ 입력값 우선, 없으면 userId created_by: writerValue, // created_by는 항상 로그인한 사람 updated_by: writerValue, // updated_by는 항상 로그인한 사람 - company_code: mappedData.company_code || companyCodeValue, // ✅ 입력값 우선, 없으면 user.companyCode + company_code: mappedData.company_code || companyCodeValue, // ✅ 입력값 우선, 없으면 user.company_code }; // 🆕 리피터 데이터(배열)를 마스터 저장에서 제외 (V2Repeater가 별도로 저장) @@ -2123,7 +2123,7 @@ export const InteractiveScreenViewer: React.FC = ( regdate: file.regdate, status: file.status, parent_target_objid: "", - company_code: file.companyCode + company_code: file.company_code })); // console.log("💾 attach_file_info 형태로 변환된 데이터:", fileInfoForDB); diff --git a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx index dc21975c..7d1107ed 100644 --- a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx +++ b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx @@ -775,7 +775,7 @@ export const InteractiveScreenViewerDynamic: React.FC c.id === mapping.sourceComponentId); if (sourceComp) { - const fieldName = (sourceComp as any).columnName || sourceComp.id; + const fieldName = (sourceComp as any).column_name || sourceComp.id; value = formData[fieldName]; console.log(`📍 컴포넌트 값 (컴포넌트 조회): ${fieldName} = ${value}`); } @@ -926,7 +926,7 @@ export const InteractiveScreenViewerDynamic: React.FC c.id === componentId); if (targetComp) { - const fieldName = (targetComp as any).columnName || targetComp.id; + const fieldName = (targetComp as any).column_name || targetComp.id; onFormDataChange?.(fieldName, ""); } } @@ -1312,7 +1312,7 @@ export const InteractiveScreenViewerDynamic: React.FC - {labelText}{((component as any).required || (component as any).componentConfig?.required || isColumnRequiredByMeta((component as any).tableName, (component as any).columnName)) && ( + {labelText}{((component as any).required || (component as any).componentConfig?.required || isColumnRequiredByMeta((component as any).tableName, (component as any).column_name)) && ( * )} @@ -1366,7 +1366,7 @@ export const InteractiveScreenViewerDynamic: React.FC - {labelText}{((component as any).required || (component as any).componentConfig?.required || isColumnRequiredByMeta((component as any).tableName, (component as any).columnName)) && ( + {labelText}{((component as any).required || (component as any).componentConfig?.required || isColumnRequiredByMeta((component as any).tableName, (component as any).column_name)) && ( * )} diff --git a/frontend/components/screen/MenuAssignmentModal.tsx b/frontend/components/screen/MenuAssignmentModal.tsx index 14eff49a..7111f259 100644 --- a/frontend/components/screen/MenuAssignmentModal.tsx +++ b/frontend/components/screen/MenuAssignmentModal.tsx @@ -166,7 +166,7 @@ export const MenuAssignmentModal: React.FC = ({ // 기존에 할당된 화면이 있는지 확인 if (existingScreens.length > 0) { // 이미 같은 화면이 할당되어 있는지 확인 - const alreadyAssigned = existingScreens.some((screen) => screen.screenId === screenInfo.screenId); + const alreadyAssigned = existingScreens.some((screen) => screen.screen_id === screenInfo.screen_id); if (alreadyAssigned) { toast.info("이미 해당 메뉴에 할당된 화면입니다."); return; @@ -199,20 +199,20 @@ export const MenuAssignmentModal: React.FC = ({ // console.log("기존 화면들 제거 중...", existingScreens); for (const existingScreen of existingScreens) { try { - await menuScreenApi.unassignScreenFromMenu(existingScreen.screenId, menuObjid); - // console.log(`기존 화면 "${existingScreen.screenName}" 제거 완료`); + await menuScreenApi.unassignScreenFromMenu(existingScreen.screen_id, menuObjid); + // console.log(`기존 화면 "${existingScreen.screen_name}" 제거 완료`); } catch (error) { - // console.error(`기존 화면 "${existingScreen.screenName}" 제거 실패:`, error); + // console.error(`기존 화면 "${existingScreen.screen_name}" 제거 실패:`, error); } } } // 새 화면 할당 - await menuScreenApi.assignScreenToMenu(screenInfo.screenId, menuObjid); + await menuScreenApi.assignScreenToMenu(screenInfo.screen_id, menuObjid); const successMessage = replaceExisting - ? `기존 화면을 제거하고 "${screenInfo.screenName}" 화면이 "${selectedMenu.menu_name_kor}" 메뉴에 할당되었습니다.` - : `"${screenInfo.screenName}" 화면이 "${selectedMenu.menu_name_kor}" 메뉴에 성공적으로 할당되었습니다.`; + ? `기존 화면을 제거하고 "${screenInfo.screen_name}" 화면이 "${selectedMenu.menu_name_kor}" 메뉴에 할당되었습니다.` + : `"${screenInfo.screen_name}" 화면이 "${selectedMenu.menu_name_kor}" 메뉴에 성공적으로 할당되었습니다.`; // 성공 상태 설정 setAssignmentSuccess(true); @@ -245,7 +245,7 @@ export const MenuAssignmentModal: React.FC = ({ // 성공 상태 설정 (나중에 할당 메시지) setAssignmentSuccess(true); - setAssignmentMessage(`"${screenInfo.screenName}" 화면이 저장되었습니다. 나중에 메뉴에 할당할 수 있습니다.`); + setAssignmentMessage(`"${screenInfo.screen_name}" 화면이 저장되었습니다. 나중에 메뉴에 할당할 수 있습니다.`); // 할당 완료 콜백 호출 (모달은 아직 열린 상태 유지) if (onAssignmentComplete) { @@ -425,9 +425,9 @@ export const MenuAssignmentModal: React.FC = ({
- {screenInfo.screenName} + {screenInfo.screen_name} - {screenInfo.screenCode} + {screenInfo.screen_code}
{screenInfo.description &&

{screenInfo.description}

} @@ -533,11 +533,11 @@ export const MenuAssignmentModal: React.FC = ({

{existingScreens.map((screen) => ( -
+
- {screen.screenName} + {screen.screen_name} - {screen.screenCode} + {screen.screen_code}
))} @@ -596,11 +596,11 @@ export const MenuAssignmentModal: React.FC = ({

제거될 화면 ({existingScreens.length}개):

{existingScreens.map((screen) => ( -
+
- {screen.screenName} + {screen.screen_name} - {screen.screenCode} + {screen.screen_code}
))} @@ -613,9 +613,9 @@ export const MenuAssignmentModal: React.FC = ({

새로 할당될 화면:

- {screenInfo.screenName} + {screenInfo.screen_name} - {screenInfo.screenCode} + {screenInfo.screen_code}
diff --git a/frontend/components/screen/SaveModal.tsx b/frontend/components/screen/SaveModal.tsx index 2f99d9db..64e8481a 100644 --- a/frontend/components/screen/SaveModal.tsx +++ b/frontend/components/screen/SaveModal.tsx @@ -72,7 +72,7 @@ export const SaveModal: React.FC = ({ setComponents(layout.components || []); // 테이블 컬럼 정보 로드 (NOT NULL 필수값 자동 인식용) - const tblName = screen?.table_name || layout.components?.find((c: any) => c.columnName)?.table_name; + const tblName = screen?.table_name || layout.components?.find((c: any) => c.column_name)?.table_name; if (tblName) { try { const colResult = await getTableColumns(tblName); @@ -134,7 +134,7 @@ export const SaveModal: React.FC = ({ const missingFields: string[] = []; components.forEach((component) => { - const columnName = component.columnName || component.style?.columnName; + const columnName = component.column_name || component.style?.column_name; const label = component.label || component.style?.label || columnName; // 기존 required 속성 (화면 디자이너에서 수동 설정한 것) @@ -237,7 +237,7 @@ export const SaveModal: React.FC = ({ }); // 테이블명 결정 - const tableName = screenData.table_name || components.find((c) => c.columnName)?.table_name || "dynamic_form_data"; + const tableName = screenData.table_name || components.find((c) => c.column_name)?.table_name || "dynamic_form_data"; const saveData: DynamicFormData = { screen_id: screenId, diff --git a/frontend/components/screen/ScreenRelationFlow.tsx b/frontend/components/screen/ScreenRelationFlow.tsx index 6f59740b..e918e3f8 100644 --- a/frontend/components/screen/ScreenRelationFlow.tsx +++ b/frontend/components/screen/ScreenRelationFlow.tsx @@ -509,13 +509,13 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId screenSubData.subTables.forEach((subTable) => { // mainTableSet에 있으면 서브 테이블에서 제외 (우선순위: 메인 > 서브) - if (mainTableSet.has(subTable.tableName)) { + if (mainTableSet.has(subTable.table_name)) { return; } // 조인으로만 연결된 테이블 → 서브 테이블 - subTableSet.add(subTable.tableName); - subTableNames.push(subTable.tableName); + subTableSet.add(subTable.table_name); + subTableNames.push(subTable.table_name); }); if (subTableNames.length > 0) { @@ -538,27 +538,27 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId // 1. lookup, reference 관계: 참조되는 테이블에 정보 추가 if (subTable.relationType === 'lookup' || subTable.relationType === 'reference') { - const existingRefs = tableReferencesMap.get(subTable.tableName) || []; + const existingRefs = tableReferencesMap.get(subTable.table_name) || []; existingRefs.push({ fromTable: mainTable, fromColumn: subTable.fieldMappings?.[0]?.sourceField || '', toColumn: subTable.fieldMappings?.[0]?.targetField || '', relationType: 'lookup', }); - tableReferencesMap.set(subTable.tableName, existingRefs); + tableReferencesMap.set(subTable.table_name, existingRefs); } // 2. rightPanelRelation (마스터-디테일 필터링): 디테일 테이블에 정보 추가 - // 마스터(mainTable) → 디테일(subTable.tableName) 필터링 관계 + // 마스터(mainTable) → 디테일(subTable.table_name) 필터링 관계 if (subTable.relationType === 'rightPanelRelation') { - const existingRefs = tableReferencesMap.get(subTable.tableName) || []; + const existingRefs = tableReferencesMap.get(subTable.table_name) || []; existingRefs.push({ fromTable: mainTable, fromColumn: subTable.leftColumn || '', // 마스터 테이블의 선택 기준 컬럼 toColumn: subTable.foreignKey || '', // 디테일 테이블의 FK 컬럼 relationType: 'filter', }); - tableReferencesMap.set(subTable.tableName, existingRefs); + tableReferencesMap.set(subTable.table_name, existingRefs); } }); }); @@ -667,7 +667,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId // 서브 테이블의 관계 타입 결정 let relationType = "참조"; Object.values(subTablesData).forEach((screenSubData) => { - const matchedSub = screenSubData.subTables.find((st) => st.tableName === tableName); + const matchedSub = screenSubData.subTables.find((st) => st.table_name === tableName); if (matchedSub) { if (matchedSub.relationType === "lookup") relationType = "조회"; else if (matchedSub.relationType === "source") relationType = "데이터 소스"; @@ -753,18 +753,18 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId // 메인 테이블이든 서브 테이블이든 상관없이 연결선 추가 if (subTable.relationType === 'rightPanelRelation') { // 테이블 노드 ID 결정: 메인 테이블 영역 또는 서브 테이블 영역 - const isFilterTargetMainTable = mainTableSet.has(subTable.tableName); - const isFilterTargetSubTable = subTableSet.has(subTable.tableName); + const isFilterTargetMainTable = mainTableSet.has(subTable.table_name); + const isFilterTargetSubTable = subTableSet.has(subTable.table_name); if (!isFilterTargetMainTable && !isFilterTargetSubTable) return; // 노드가 없으면 스킵 const targetNodeId = isFilterTargetMainTable - ? `table-${subTable.tableName}` - : `subtable-${subTable.tableName}`; + ? `table-${subTable.table_name}` + : `subtable-${subTable.table_name}`; // 화면 → 필터 대상 테이블 연결선 newEdges.push({ - id: `edge-screen-filter-${sourceScreenId}-${subTable.tableName}`, + id: `edge-screen-filter-${sourceScreenId}-${subTable.table_name}`, source: `screen-${sourceScreenId}`, target: targetNodeId, sourceHandle: "bottom", @@ -796,21 +796,21 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId if (!isRefMainTable && !isRefSubTable) return; // 중복 체크 (같은 화면에서 같은 조인 관계 중복 방지) - const joinKey = `${sourceScreenId}-${subTable.tableName}-${refTable}`; + const joinKey = `${sourceScreenId}-${subTable.table_name}-${refTable}`; if (filterJoinEdgeSet.has(joinKey)) return; filterJoinEdgeSet.add(joinKey); // 소스/타겟 노드 ID 결정 const sourceNodeId = isFilterTargetMainTable - ? `table-${subTable.tableName}` - : `subtable-${subTable.tableName}`; + ? `table-${subTable.table_name}` + : `subtable-${subTable.table_name}`; const refTargetNodeId = isRefMainTable ? `table-${refTable}` : `subtable-${refTable}`; // 조인선 추가 (초기 스타일 - styledEdges에서 포커싱에 따라 스타일 결정) newEdges.push({ - id: `edge-filter-join-${sourceScreenId}-${subTable.tableName}-${refTable}`, + id: `edge-filter-join-${sourceScreenId}-${subTable.table_name}-${refTable}`, source: sourceNodeId, target: refTargetNodeId, sourceHandle: "bottom", @@ -851,11 +851,11 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId if (!mainTable || !mainTableSet.has(mainTable)) return; screenSubData.subTables.forEach((subTable) => { - const isTargetSubTable = subTableSet.has(subTable.tableName); - const isTargetMainTable = mainTableSet.has(subTable.tableName); + const isTargetSubTable = subTableSet.has(subTable.table_name); + const isTargetMainTable = mainTableSet.has(subTable.table_name); // 자기 자신 연결 방지 - if (mainTable === subTable.tableName) return; + if (mainTable === subTable.table_name) return; // 메인 테이블 → 메인 테이블 연결 (서브테이블 구간을 통해 연결) // 규격: bottom → bottom_target (참조하는 테이블에서 참조당하는 테이블로) @@ -876,33 +876,33 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId // fieldMappings에서 sourceTable 확인 const hasSourceTable = subTable.fieldMappings?.some( - (fm: any) => fm.sourceTable && fm.sourceTable === subTable.tableName + (fm: any) => fm.sourceTable && fm.sourceTable === subTable.table_name ); if (subTable.relationType === 'parentMapping' || hasSourceTable) { - // parentMapping: mainTable이 sourceTable(=subTable.tableName)을 참조 - // 방향: mainTable → subTable.tableName + // parentMapping: mainTable이 sourceTable(=subTable.table_name)을 참조 + // 방향: mainTable → subTable.table_name referrerTable = mainTable; - referencedTable = subTable.tableName; + referencedTable = subTable.table_name; } else if (subTable.relationType === 'rightPanelRelation') { // rightPanelRelation: split-panel-layout의 마스터-디테일 관계 // mainTable(leftPanel, 마스터)이 subTable(rightPanel, 디테일)을 필터링 // 방향: mainTable(마스터) → subTable(디테일) referrerTable = mainTable; - referencedTable = subTable.tableName; + referencedTable = subTable.table_name; } else if (subTable.relationType === 'reference') { // reference (column_labels): mainTable이 subTable을 참조 - // 방향: mainTable → subTable.tableName + // 방향: mainTable → subTable.table_name referrerTable = mainTable; - referencedTable = subTable.tableName; + referencedTable = subTable.table_name; } else { // 기본: subTable이 mainTable을 참조한다고 가정 - referrerTable = subTable.tableName; + referrerTable = subTable.table_name; referencedTable = mainTable; } // 화면별로 고유한 키 생성 (같은 테이블 쌍이라도 다른 화면에서는 별도 엣지) - const pairKey = `${sourceScreenId}-${[mainTable, subTable.tableName].sort().join('-')}`; + const pairKey = `${sourceScreenId}-${[mainTable, subTable.table_name].sort().join('-')}`; if (!mainToMainEdgeSet.has(pairKey)) { mainToMainEdgeSet.add(pairKey); @@ -953,7 +953,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId if (!isTargetSubTable) return; // 화면별로 고유한 엣지 ID (같은 서브 테이블이라도 다른 화면에서 사용하면 별도 엣지) - const edgeId = `edge-main-sub-${sourceScreenId}-${mainTable}-${subTable.tableName}`; + const edgeId = `edge-main-sub-${sourceScreenId}-${mainTable}-${subTable.table_name}`; const exists = newEdges.some((e) => e.id === edgeId); if (exists) return; @@ -965,7 +965,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId newEdges.push({ id: edgeId, source: `table-${mainTable}`, - target: `subtable-${subTable.tableName}`, + target: `subtable-${subTable.table_name}`, sourceHandle: "bottom", targetHandle: "top", type: "animatedFlow", @@ -1135,7 +1135,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId for (const screenId in subTablesDataMap) { const screenSubTables = subTablesDataMap[parseInt(screenId)]; if (screenSubTables?.subTables) { - const subTable = screenSubTables.subTables.find(st => st.tableName === tableName); + const subTable = screenSubTables.subTables.find(st => st.table_name === tableName); if (subTable) { return { joinColumnRefs: subTable.joinColumnRefs, @@ -1184,7 +1184,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId const filterTables = allFilterTableNames.map(tableName => { // subTablesDataMap에서 해당 테이블 정보 찾기 const subTableData = subTablesDataMap[screenId]?.subTables?.find( - st => st.tableName === tableName + st => st.table_name === tableName ); // 또는 nodes에서 테이블 노드 정보 찾기 @@ -1245,7 +1245,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId allFieldMappings.push({ targetField: mapping.targetField, sourceField: mapping.sourceField, - sourceTable: mapping.sourceTable || subTable.tableName, + sourceTable: mapping.sourceTable || subTable.table_name, sourceDisplayName: mapping.sourceDisplayName, componentType: subTable.relationType, }); @@ -1406,7 +1406,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId && subTable.fieldMappings) { subTable.fieldMappings.forEach((mapping) => { // sourceTable이 명시되어 있으면 그 테이블에 sourceField 추가 - // sourceTable이 없으면 subTable.tableName을 sourceTable로 간주하지 않음 + // sourceTable이 없으면 subTable.table_name을 sourceTable로 간주하지 않음 // mapping에서 sourceTable 정보가 필요함 - 현재는 tableName에서 추론 // parentDataMapping의 경우: tableName이 targetTable이고, sourceTable은 별도 정보 필요 @@ -1427,10 +1427,10 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId if (focusedSubTablesData) { // 포커스된 화면의 subTables 순회 focusedSubTablesData.subTables.forEach((subTable) => { - // 1. subTable.tableName 자체가 다른 화면의 메인 테이블인 경우 - if (allMainTableSet.has(subTable.tableName) && subTable.tableName !== focusedSubTablesData.mainTable) { - if (!relatedMainTables[subTable.tableName]) { - relatedMainTables[subTable.tableName] = { columns: [], displayNames: [] }; + // 1. subTable.table_name 자체가 다른 화면의 메인 테이블인 경우 + if (allMainTableSet.has(subTable.table_name) && subTable.table_name !== focusedSubTablesData.mainTable) { + if (!relatedMainTables[subTable.table_name]) { + relatedMainTables[subTable.table_name] = { columns: [], displayNames: [] }; } // fieldMappings가 있으면 조인 컬럼 정보 추출 @@ -1445,9 +1445,9 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId ? (mapping.sourceDisplayName || mapping.sourceField) : (mapping.targetDisplayName || mapping.targetField); - if (relatedColumn && !relatedMainTables[subTable.tableName].columns.includes(relatedColumn)) { - relatedMainTables[subTable.tableName].columns.push(relatedColumn); - relatedMainTables[subTable.tableName].displayNames.push(displayName); + if (relatedColumn && !relatedMainTables[subTable.table_name].columns.includes(relatedColumn)) { + relatedMainTables[subTable.table_name].columns.push(relatedColumn); + relatedMainTables[subTable.table_name].displayNames.push(displayName); } }); } @@ -1656,8 +1656,8 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId let relatedTableFieldMappings: Array<{ sourceField: string; targetField: string; sourceDisplayName?: string; targetDisplayName?: string }> = []; if (isRelatedTable && focusedSubTablesData) { focusedSubTablesData.subTables.forEach((subTable) => { - // 1. subTable.tableName === tableName인 경우 (메인-메인 조인) - if (subTable.tableName === tableName && subTable.fieldMappings) { + // 1. subTable.table_name === tableName인 경우 (메인-메인 조인) + if (subTable.table_name === tableName && subTable.fieldMappings) { subTable.fieldMappings.forEach((mapping) => { // reference/source 타입: sourceField가 메인테이블, targetField가 이 연관테이블 // 연관 테이블 표시: targetField ← sourceDisplayName (메인테이블 컬럼 한글명) @@ -1720,7 +1720,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId if (focusedScreenId !== null && focusedSubTablesData) { // 포커스된 화면에서 이 테이블이 rightPanelRelation의 서브테이블인 경우 focusedSubTablesData.subTables.forEach((subTable) => { - if (subTable.tableName === tableName && subTable.relationType === 'rightPanelRelation') { + if (subTable.table_name === tableName && subTable.relationType === 'rightPanelRelation') { // FK 컬럼 추출 (필터링 기준) if (subTable.foreignKey) { focusedFilterColumns.push(subTable.foreignKey); @@ -1744,7 +1744,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId const fromColInfo = mainTableCols.find(c => c.column_name === (subTable.leftColumn || 'id')); const fromColumnLabel = fromColInfo?.display_name || subTable.leftColumn || 'id'; - const subTableCols = tableColumns[subTable.tableName] || []; + const subTableCols = tableColumns[subTable.table_name] || []; const toColInfo = subTableCols.find(c => c.column_name === subTable.foreignKey); const toColumnLabel = toColInfo?.display_name || subTable.foreignKey || ''; @@ -1770,7 +1770,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId const fromColumnLabel = fromColInfo?.display_name || subTable.leftColumn || 'id'; // 서브 테이블의 컬럼 한글명 조회 - const subTableCols = tableColumns[subTable.tableName] || []; + const subTableCols = tableColumns[subTable.table_name] || []; const toColInfo = subTableCols.find(c => c.column_name === subTable.foreignKey); const toColumnLabel = toColInfo?.display_name || subTable.foreignKey || ''; @@ -1791,12 +1791,12 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId // 포커싱된 화면 기준 저장 정보 추출 if (focusedSubTablesData.saveTables) { focusedSubTablesData.saveTables.forEach((st) => { - if (st.tableName === tableName) { + if (st.table_name === tableName) { focusedSaveInfos.push({ saveType: st.saveType, componentType: st.componentType, isMainTable: st.isMainTable, - sourceScreenId: focusedSubTablesData.screenId, + sourceScreenId: focusedSubTablesData.screen_id, }); } }); @@ -1833,7 +1833,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId // - lookup 등: sourceField가 서브테이블 컬럼 let subTableJoinColumns: string[] = []; if (isActiveSubTable && focusedSubTablesData) { - const subTableInfo = focusedSubTablesData.subTables.find(st => st.tableName === subTableName); + const subTableInfo = focusedSubTablesData.subTables.find(st => st.table_name === subTableName); if (subTableInfo?.fieldMappings) { subTableInfo.fieldMappings.forEach((mapping) => { // reference, source, parentMapping, rightPanelRelation 타입: targetField가 서브테이블의 컬럼 (조인 키) @@ -1867,7 +1867,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId let subTableSaveInfos: Array<{ saveType: string; componentType: string; isMainTable: boolean; sourceScreenId?: number }> = []; if (isActiveSubTable && focusedSubTablesData) { - const subTableInfo = focusedSubTablesData.subTables.find(st => st.tableName === subTableName); + const subTableInfo = focusedSubTablesData.subTables.find(st => st.table_name === subTableName); if (subTableInfo?.fieldMappings) { displayFieldMappings = subTableInfo.fieldMappings.map((mapping) => { if (subTableInfo.relationType === 'reference' || subTableInfo.relationType === 'source' || @@ -1898,12 +1898,12 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId // 서브 테이블에 대한 저장 정보 추출 if (focusedSubTablesData.saveTables) { focusedSubTablesData.saveTables.forEach((st) => { - if (st.tableName === subTableName) { + if (st.table_name === subTableName) { subTableSaveInfos.push({ saveType: st.saveType, componentType: st.componentType, isMainTable: st.isMainTable, - sourceScreenId: focusedSubTablesData.screenId, + sourceScreenId: focusedSubTablesData.screen_id, }); } }); @@ -1998,11 +1998,11 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId if (focusedSubTablesData) { focusedSubTablesData.subTables.forEach((subTable) => { - // 1. subTable.tableName이 다른 화면의 메인 테이블인 경우 (메인-메인 조인) - const isTargetMainTable = allMainTables.has(subTable.tableName) && subTable.tableName !== focusedMainTable; + // 1. subTable.table_name이 다른 화면의 메인 테이블인 경우 (메인-메인 조인) + const isTargetMainTable = allMainTables.has(subTable.table_name) && subTable.table_name !== focusedMainTable; if (isTargetMainTable) { - const pairKey = `${subTable.tableName}-${focusedMainTable}`; + const pairKey = `${subTable.table_name}-${focusedMainTable}`; if (addedPairs.has(pairKey)) return; addedPairs.add(pairKey); @@ -2528,7 +2528,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId = ({ const compConfig = (comp as any).component_config || {}; if (compType === "split-panel-layout" || compType === "screen-split-panel") { - sourceTableName = compConfig.leftPanel?.tableName || compConfig.tableName || null; + sourceTableName = compConfig.leftPanel?.table_name || compConfig.table_name || null; if (sourceTableName) break; } if (compType === "table-list") { - sourceTableName = compConfig.tableName || compConfig.selectedTable || null; + sourceTableName = compConfig.table_name || compConfig.selectedTable || null; if (sourceTableName) break; } if (compType === "v2-list") { - sourceTableName = compConfig.dataSource?.table || compConfig.tableName || null; + sourceTableName = compConfig.dataSource?.table || compConfig.table_name || null; if (sourceTableName) break; } } @@ -492,7 +492,7 @@ export const ActionTab: React.FC = ({ allComponents.forEach((comp, idx) => { const compType = comp.component_type || (comp as any).component_config?.type; console.log( - ` [${idx}] componentType: ${compType}, tableName: ${(comp as any).componentConfig?.tableName || (comp as any).componentConfig?.leftPanel?.tableName || "N/A"}`, + ` [${idx}] componentType: ${compType}, tableName: ${(comp as any).componentConfig?.table_name || (comp as any).componentConfig?.leftPanel?.table_name || "N/A"}`, ); }); @@ -502,7 +502,7 @@ export const ActionTab: React.FC = ({ // 분할 패널 타입들 (다양한 경로에서 테이블명 추출) if (compType === "split-panel-layout" || compType === "screen-split-panel") { - sourceTableName = compConfig?.leftPanel?.tableName || compConfig?.leftTableName || compConfig?.tableName; + sourceTableName = compConfig?.leftPanel?.table_name || compConfig?.leftTableName || compConfig?.table_name; if (sourceTableName) { console.log(`✅ [openModalWithData] split-panel-layout에서 소스 테이블 감지: ${sourceTableName}`); break; @@ -511,7 +511,7 @@ export const ActionTab: React.FC = ({ // split-panel-layout2 타입 (새로운 분할 패널) if (compType === "split-panel-layout2") { - sourceTableName = compConfig?.leftPanel?.tableName || compConfig?.tableName || compConfig?.leftTableName; + sourceTableName = compConfig?.leftPanel?.table_name || compConfig?.table_name || compConfig?.leftTableName; if (sourceTableName) { console.log(`✅ [openModalWithData] split-panel-layout2에서 소스 테이블 감지: ${sourceTableName}`); break; @@ -520,7 +520,7 @@ export const ActionTab: React.FC = ({ // 테이블 리스트 타입 if (compType === "table-list") { - sourceTableName = compConfig?.tableName; + sourceTableName = compConfig?.table_name; if (sourceTableName) { console.log(`✅ [openModalWithData] table-list에서 소스 테이블 감지: ${sourceTableName}`); break; @@ -528,8 +528,8 @@ export const ActionTab: React.FC = ({ } // 🆕 모든 컴포넌트에서 tableName 찾기 (폴백) - if (!sourceTableName && compConfig?.tableName) { - sourceTableName = compConfig.tableName; + if (!sourceTableName && compConfig?.table_name) { + sourceTableName = compConfig.table_name; console.log(`✅ [openModalWithData] ${compType}에서 소스 테이블 감지 (폴백): ${sourceTableName}`); break; } @@ -1236,8 +1236,8 @@ export const ActionTab: React.FC = ({ role="combobox" className="h-7 w-full justify-between text-xs" > - {block.tableName - ? availableTables.find((t) => t.name === block.tableName)?.label || block.tableName + {block.table_name + ? availableTables.find((t) => t.name === block.table_name)?.label || block.table_name : "테이블 선택"} @@ -1279,7 +1279,7 @@ export const ActionTab: React.FC = ({ {table.label} @@ -1294,7 +1294,7 @@ export const ActionTab: React.FC = ({ - {block.tableName && ( + {block.table_name && ( <> {/* 컬럼 선택 - Combobox (라벨명 표시) */} = ({ className="h-7 w-full justify-between text-xs" > {block.value - ? tableColumnsMap[block.tableName]?.find((c) => c.name === block.value) + ? tableColumnsMap[block.table_name]?.find((c) => c.name === block.value) ?.label || block.value : "컬럼 선택"} @@ -1329,7 +1329,7 @@ export const ActionTab: React.FC = ({ 컬럼을 찾을 수 없습니다. - {(tableColumnsMap[block.tableName] || []) + {(tableColumnsMap[block.table_name] || []) .filter((col) => { const search = (blockColumnSearches[block.id] || "").toLowerCase(); if (!search) return true; @@ -3915,8 +3915,8 @@ const MasterDetailExcelUploadConfig: React.FC<{ return findSplitPanel(allComponents as any[]); }, [allComponents]); - const masterTable = splitPanelInfo?.leftPanel?.tableName || ""; - const detailTable = splitPanelInfo?.rightPanel?.tableName || ""; + const masterTable = splitPanelInfo?.leftPanel?.table_name || ""; + const detailTable = splitPanelInfo?.rightPanel?.table_name || ""; // 마스터 테이블 컬럼 로드 useEffect(() => { @@ -4427,19 +4427,19 @@ const ExcelUploadConfigSection: React.FC<{ compId === "table-list" || compId === "simple-table" ) { - const tableName = compConfig?.tableName || compConfig?.table; + const tableName = compConfig?.table_name || compConfig?.table; if (tableName) return tableName; } // 폼 컴포넌트에서 테이블명 찾기 if (compId === "form-panel" || compId === "input-form" || compId === "form" || compId === "detail-form") { - const tableName = compConfig?.tableName || compConfig?.table; + const tableName = compConfig?.table_name || compConfig?.table; if (tableName) return tableName; } // 범용적으로 tableName 속성이 있는 컴포넌트 찾기 - if (compConfig?.tableName) { - return compConfig.tableName; + if (compConfig?.table_name) { + return compConfig.table_name; } if (comp.children && comp.children.length > 0) { diff --git a/frontend/lib/registry/components/screen-split-panel/ScreenSplitPanelConfigPanel.tsx b/frontend/lib/registry/components/screen-split-panel/ScreenSplitPanelConfigPanel.tsx index 7d92caee..6b7802bc 100644 --- a/frontend/lib/registry/components/screen-split-panel/ScreenSplitPanelConfigPanel.tsx +++ b/frontend/lib/registry/components/screen-split-panel/ScreenSplitPanelConfigPanel.tsx @@ -44,7 +44,7 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl const [isLoadingRightColumns, setIsLoadingRightColumns] = useState(false); const [localConfig, setLocalConfig] = useState({ - screenId: config.screenId || 0, + screenId: config.screen_id || 0, leftScreenId: config.leftScreenId || 0, rightScreenId: config.rightScreenId || 0, splitRatio: config.splitRatio || 50, @@ -61,7 +61,7 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl useEffect(() => { console.log("🔄 [ScreenSplitPanelConfigPanel] config prop 변경 감지:", config); setLocalConfig({ - screenId: config.screenId || 0, + screenId: config.screen_id || 0, leftScreenId: config.leftScreenId || 0, rightScreenId: config.rightScreenId || 0, splitRatio: config.splitRatio || 50, @@ -98,8 +98,8 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl const columnsResponse = await getTableColumns(screenData.table_name); if (columnsResponse.success && columnsResponse.data?.columns) { const columns = columnsResponse.data.columns.map((col: any) => ({ - columnName: col.column_name || col.columnName, - columnLabel: col.column_label || col.columnLabel || col.column_name || col.columnName, + columnName: col.column_name || col.column_name, + columnLabel: col.column_label || col.column_label || col.column_name || col.column_name, })); setLeftScreenColumns(columns); console.log("📋 좌측 화면 컬럼 로드 완료:", columns.length); @@ -138,8 +138,8 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl tableName: screenData.table_name, screenName: screenData.screen_name || "메인 화면", columns: columnsResponse.data.columns.map((col: any) => ({ - columnName: col.column_name || col.columnName, - columnLabel: col.column_label || col.columnLabel || col.column_name || col.columnName, + columnName: col.column_name || col.column_name, + columnLabel: col.column_label || col.column_label || col.column_name || col.column_name, })), }); } @@ -160,9 +160,9 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl // TabsWidget의 탭들 if (comp.componentType === "tabs-widget" && config.tabs) { for (const tab of config.tabs) { - if (tab.screenId) { - embeddedScreenIds.add(tab.screenId); - console.log("🔍 탭에서 화면 발견:", tab.screenId, tab.screenName); + if (tab.screen_id) { + embeddedScreenIds.add(tab.screen_id); + console.log("🔍 탭에서 화면 발견:", tab.screen_id, tab.screen_name); } } } @@ -174,8 +174,8 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl } // EmbeddedScreen - if (comp.componentType === "embedded-screen" && config.screenId) { - embeddedScreenIds.add(config.screenId); + if (comp.componentType === "embedded-screen" && config.screen_id) { + embeddedScreenIds.add(config.screen_id); } // 중첩된 컴포넌트 검색 @@ -194,15 +194,15 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl const embeddedScreen = await screenApi.getScreen(embeddedScreenId); if (embeddedScreen?.table_name) { // 이미 추가된 테이블인지 확인 - if (!tables.find(t => t.tableName === embeddedScreen.table_name)) { + if (!tables.find(t => t.table_name === embeddedScreen.table_name)) { const columnsResponse = await getTableColumns(embeddedScreen.table_name); if (columnsResponse.success && columnsResponse.data?.columns) { tables.push({ tableName: embeddedScreen.table_name, screenName: embeddedScreen.screen_name || `화면 ${embeddedScreenId}`, columns: columnsResponse.data.columns.map((col: any) => ({ - columnName: col.column_name || col.columnName, - columnLabel: col.column_label || col.columnLabel || col.column_name || col.columnName, + columnName: col.column_name || col.column_name, + columnLabel: col.column_label || col.column_label || col.column_name || col.column_name, })), }); console.log("✅ 테이블 추가:", embeddedScreen.table_name); @@ -216,7 +216,7 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl } setRightScreenTables(tables); - console.log("📋 우측 화면 테이블 로드 완료:", tables.map(t => t.tableName)); + console.log("📋 우측 화면 테이블 로드 완료:", tables.map(t => t.table_name)); } catch (error) { console.error("우측 화면 컬럼 로드 실패:", error); setRightScreenTables([]); @@ -440,7 +440,7 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl className="h-9 w-full justify-between text-xs" > {localConfig.leftScreenId - ? screens.find((s) => s.screenId === localConfig.leftScreenId)?.screenName || "화면 선택..." + ? screens.find((s) => s.screen_id === localConfig.leftScreenId)?.screen_name || "화면 선택..." : "화면 선택..."} @@ -457,10 +457,10 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl {screens.map((screen) => ( { - updateConfig("leftScreenId", screen.screenId); + updateConfig("leftScreenId", screen.screen_id); setLeftOpen(false); }} className="text-xs" @@ -468,12 +468,12 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl
- {screen.screenName} - {screen.screenCode} + {screen.screen_name} + {screen.screen_code}
))} @@ -500,7 +500,7 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl className="h-9 w-full justify-between text-xs" > {localConfig.rightScreenId - ? screens.find((s) => s.screenId === localConfig.rightScreenId)?.screenName || + ? screens.find((s) => s.screen_id === localConfig.rightScreenId)?.screen_name || "화면 선택..." : "화면 선택..."} @@ -518,10 +518,10 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl {screens.map((screen) => ( { - updateConfig("rightScreenId", screen.screenId); + updateConfig("rightScreenId", screen.screen_id); setRightOpen(false); }} className="text-xs" @@ -529,12 +529,12 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl
- {screen.screenName} - {screen.screenCode} + {screen.screen_name} + {screen.screen_code}
))} @@ -627,8 +627,8 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl {leftScreenColumns.map((col) => ( - - {col.columnLabel} ({col.columnName}) + + {col.column_label} ({col.column_name}) ))} @@ -648,17 +648,17 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl {rightScreenTables.map((table) => ( - +
- {table.screenName} ({table.tableName}) + {table.screen_name} ({table.table_name})
{table.columns.map((col) => ( - {col.columnLabel} ({col.columnName}) + {col.column_label} ({col.column_name}) ))}
@@ -732,7 +732,7 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl

    {rightScreenTables.map((table) => ( -
  • • {table.screenName}: {table.tableName}
  • +
  • • {table.screen_name}: {table.table_name}
  • ))}
@@ -764,8 +764,8 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl {leftScreenColumns.map((col) => ( - - {col.columnLabel} ({col.columnName}) + + {col.column_label} ({col.column_name}) ))} @@ -785,17 +785,17 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl {rightScreenTables.map((table) => ( - +
- {table.screenName} ({table.tableName}) + {table.screen_name} ({table.table_name})
{table.columns.map((col) => ( - {col.columnLabel} ({col.columnName}) + {col.column_label} ({col.column_name}) ))}
@@ -856,7 +856,7 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl 좌측 화면: {localConfig.leftScreenId - ? screens.find((s) => s.screenId === localConfig.leftScreenId)?.screenName || + ? screens.find((s) => s.screen_id === localConfig.leftScreenId)?.screen_name || `ID: ${localConfig.leftScreenId}` : "미설정"} @@ -865,7 +865,7 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl 우측 화면: {localConfig.rightScreenId - ? screens.find((s) => s.screenId === localConfig.rightScreenId)?.screenName || + ? screens.find((s) => s.screen_id === localConfig.rightScreenId)?.screen_name || `ID: ${localConfig.rightScreenId}` : "미설정"} diff --git a/frontend/lib/registry/pop-components/pop-card-list-v2/PopCardListV2Config.tsx b/frontend/lib/registry/pop-components/pop-card-list-v2/PopCardListV2Config.tsx index f691d388..f3c44151 100644 --- a/frontend/lib/registry/pop-components/pop-card-list-v2/PopCardListV2Config.tsx +++ b/frontend/lib/registry/pop-components/pop-card-list-v2/PopCardListV2Config.tsx @@ -2356,8 +2356,8 @@ function ActionButtonsEditor({
POP 화면 updateSelectModeBtn(bi, ai, si, { modalScreenId: e.target.value })} + value={smBtn.modal_screen_id || ""} + onChange={(e) => updateSelectModeBtn(bi, ai, si, { modal_screen_id: e.target.value })} placeholder="화면 ID (예: 4481)" className="h-6 flex-1 text-[10px]" /> @@ -2375,8 +2375,8 @@ function ActionButtonsEditor({
POP 화면 updateAction(bi, ai, { modalScreenId: e.target.value })} + value={action.modal_screen_id || ""} + onChange={(e) => updateAction(bi, ai, { modal_screen_id: e.target.value })} placeholder="화면 ID (예: 4481)" className="h-6 flex-1 text-[10px]" /> @@ -2944,7 +2944,7 @@ function TabActions({ const designerCtx = usePopDesignerContext(); const overflow = cfg.overflow || { mode: "loadMore" as const, visibleCount: 6 }; const clickAction = cfg.cardClickAction || "none"; - const modalConfig = cfg.cardClickModalConfig || { screenId: "" }; + const modalConfig = cfg.cardClickModalConfig || { screen_id: "" }; const [processColumns, setProcessColumns] = useState([]); const timelineCell = cfg.cardGrid?.cells?.find((c) => c.type === "timeline" && c.timelineSource?.processTable); @@ -3018,12 +3018,12 @@ function TabActions({ {/* 모달 캔버스 (디자이너 모드) */} {designerCtx && (
- {modalConfig.screenId?.startsWith("modal-") ? ( + {modalConfig.screen_id?.startsWith("modal-") ? ( @@ -3037,10 +3037,10 @@ function TabActions({ if (!selectedId) return; const modalId = designerCtx.createModalCanvas( selectedId, - modalConfig.modalTitle || "카드 상세" + modalConfig.modal_title || "카드 상세" ); onUpdate({ - cardClickModalConfig: { ...modalConfig, screenId: modalId }, + cardClickModalConfig: { ...modalConfig, screen_id: modalId }, }); }} > @@ -3054,8 +3054,8 @@ function TabActions({
모달 ID onUpdate({ cardClickModalConfig: { ...modalConfig, screenId: e.target.value } })} + value={modalConfig.screen_id || ""} + onChange={(e) => onUpdate({ cardClickModalConfig: { ...modalConfig, screen_id: e.target.value } })} placeholder="모달 ID" className="h-7 flex-1 text-[10px]" /> @@ -3064,8 +3064,8 @@ function TabActions({
모달 제목 onUpdate({ cardClickModalConfig: { ...modalConfig, modalTitle: e.target.value } })} + value={modalConfig.modal_title || ""} + onChange={(e) => onUpdate({ cardClickModalConfig: { ...modalConfig, modal_title: e.target.value } })} placeholder="비우면 '상세 작업' 표시" className="h-7 flex-1 text-[10px]" /> diff --git a/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx b/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx index 8ebacd8b..270310af 100644 --- a/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx +++ b/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx @@ -854,8 +854,8 @@ function CartListModeSection({ if (res?.data) { setScreens( res.data.map((s) => ({ - id: s.screenId, - name: s.screenName || `화면 ${s.screenId}`, + id: s.screen_id, + name: s.screen_name || `화면 ${s.screen_id}`, })) ); } @@ -865,13 +865,13 @@ function CartListModeSection({ // 원본 화면 선택 시 -> 해당 화면의 pop-card-list 컴포넌트 목록 로드 useEffect(() => { - if (!mode.sourceScreenId) { + if (!mode.source_screen_id) { setSourceCardLists([]); return; } setLoadingComponents(true); screenApi - .getLayoutPop(mode.sourceScreenId) + .getLayoutPop(mode.source_screen_id) .then((layoutJson: any) => { const componentsMap = layoutJson?.components || {}; const componentList = Object.values(componentsMap) as any[]; @@ -887,11 +887,11 @@ function CartListModeSection({ setSourceCardLists([]); }) .finally(() => setLoadingComponents(false)); - }, [mode.sourceScreenId]); + }, [mode.source_screen_id]); const handleScreenChange = (val: string) => { const screenId = val === "__none__" ? undefined : Number(val); - onUpdate({ ...mode, sourceScreenId: screenId }); + onUpdate({ ...mode, source_screen_id: screenId }); }; const handleComponentSelect = (val: string) => { @@ -927,7 +927,7 @@ function CartListModeSection({