diff --git a/backend-node/src/routes/cascadingAutoFillRoutes.ts b/backend-node/src/routes/cascadingAutoFillRoutes.ts index 7aa1d825..92cd1bbc 100644 --- a/backend-node/src/routes/cascadingAutoFillRoutes.ts +++ b/backend-node/src/routes/cascadingAutoFillRoutes.ts @@ -52,3 +52,4 @@ export default router; + diff --git a/backend-node/src/routes/cascadingConditionRoutes.ts b/backend-node/src/routes/cascadingConditionRoutes.ts index 5f57c6ca..5745511b 100644 --- a/backend-node/src/routes/cascadingConditionRoutes.ts +++ b/backend-node/src/routes/cascadingConditionRoutes.ts @@ -48,3 +48,4 @@ export default router; + diff --git a/backend-node/src/routes/cascadingHierarchyRoutes.ts b/backend-node/src/routes/cascadingHierarchyRoutes.ts index b0e3c79a..92da4019 100644 --- a/backend-node/src/routes/cascadingHierarchyRoutes.ts +++ b/backend-node/src/routes/cascadingHierarchyRoutes.ts @@ -64,3 +64,4 @@ export default router; + diff --git a/backend-node/src/routes/cascadingMutualExclusionRoutes.ts b/backend-node/src/routes/cascadingMutualExclusionRoutes.ts index 0cec35d2..451fe973 100644 --- a/backend-node/src/routes/cascadingMutualExclusionRoutes.ts +++ b/backend-node/src/routes/cascadingMutualExclusionRoutes.ts @@ -52,3 +52,4 @@ export default router; + diff --git a/backend-node/src/services/entityJoinService.ts b/backend-node/src/services/entityJoinService.ts index 5557d8b5..25d96927 100644 --- a/backend-node/src/services/entityJoinService.ts +++ b/backend-node/src/services/entityJoinService.ts @@ -186,8 +186,13 @@ export class EntityJoinService { } } - // 별칭 컬럼명 생성 (writer -> writer_name) - const aliasColumn = `${column.column_name}_name`; + // 🎯 별칭 컬럼명 생성 - 사용자가 선택한 displayColumns 기반으로 동적 생성 + // 단일 컬럼: manager + user_name → manager_user_name + // 여러 컬럼: 첫 번째 컬럼 기준 (나머지는 개별 alias로 처리됨) + const firstDisplayColumn = displayColumns[0] || "name"; + const aliasColumn = `${column.column_name}_${firstDisplayColumn}`; + + logger.info(`🔧 별칭 컬럼명 생성: ${column.column_name} + ${firstDisplayColumn} → ${aliasColumn}`); const joinConfig: EntityJoinConfig = { sourceTable: tableName, diff --git a/docs/노드플로우_개선사항.md b/docs/노드플로우_개선사항.md index a181ac21..b19c7092 100644 --- a/docs/노드플로우_개선사항.md +++ b/docs/노드플로우_개선사항.md @@ -584,3 +584,4 @@ const result = await executeNodeFlow(flowId, { + diff --git a/docs/메일발송_기능_사용_가이드.md b/docs/메일발송_기능_사용_가이드.md index 916fbc54..f0805640 100644 --- a/docs/메일발송_기능_사용_가이드.md +++ b/docs/메일발송_기능_사용_가이드.md @@ -357,3 +357,4 @@ + diff --git a/docs/즉시저장_버튼_액션_구현_계획서.md b/docs/즉시저장_버튼_액션_구현_계획서.md index 6ce86286..69e34f5a 100644 --- a/docs/즉시저장_버튼_액션_구현_계획서.md +++ b/docs/즉시저장_버튼_액션_구현_계획서.md @@ -343,3 +343,4 @@ const getComponentValue = (componentId: string) => { 3. **조건부 저장**: 특정 조건 만족 시에만 저장 4. **연쇄 저장**: 한 번의 클릭으로 여러 테이블에 저장 + diff --git a/frontend/app/(main)/admin/tableMng/page.tsx b/frontend/app/(main)/admin/tableMng/page.tsx index cd0c462d..b554dff1 100644 --- a/frontend/app/(main)/admin/tableMng/page.tsx +++ b/frontend/app/(main)/admin/tableMng/page.tsx @@ -93,7 +93,7 @@ export default function TableManagementPage() { const [createTableModalOpen, setCreateTableModalOpen] = useState(false); const [addColumnModalOpen, setAddColumnModalOpen] = useState(false); const [ddlLogViewerOpen, setDdlLogViewerOpen] = useState(false); - + // 테이블 복제 관련 상태 const [duplicateModalMode, setDuplicateModalMode] = useState<"create" | "duplicate">("create"); const [duplicateSourceTable, setDuplicateSourceTable] = useState(null); @@ -109,7 +109,7 @@ export default function TableManagementPage() { const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [tableToDelete, setTableToDelete] = useState(""); const [isDeleting, setIsDeleting] = useState(false); - + // 선택된 테이블 목록 (체크박스) const [selectedTableIds, setSelectedTableIds] = useState>(new Set()); @@ -459,11 +459,39 @@ export default function TableManagementPage() { if (!selectedTable) return; try { + // 🎯 Entity 타입인 경우 detailSettings에 엔티티 설정을 JSON으로 포함 + let finalDetailSettings = column.detailSettings || ""; + + if (column.inputType === "entity" && column.referenceTable) { + // 기존 detailSettings를 파싱하거나 새로 생성 + let existingSettings: Record = {}; + if (typeof column.detailSettings === "string" && column.detailSettings.trim().startsWith("{")) { + try { + existingSettings = JSON.parse(column.detailSettings); + } catch { + existingSettings = {}; + } + } + + // 엔티티 설정 추가 + const entitySettings = { + ...existingSettings, + entityTable: column.referenceTable, + entityCodeColumn: column.referenceColumn || "id", + entityLabelColumn: column.displayColumn || "name", + placeholder: (existingSettings.placeholder as string) || "항목을 선택하세요", + searchable: existingSettings.searchable ?? true, + }; + + finalDetailSettings = JSON.stringify(entitySettings); + console.log("🔧 Entity 설정 JSON 생성:", entitySettings); + } + const columnSetting = { columnName: column.columnName, // 실제 DB 컬럼명 (변경 불가) columnLabel: column.displayName, // 사용자가 입력한 표시명 inputType: column.inputType || "text", - detailSettings: column.detailSettings || "", + detailSettings: finalDetailSettings, codeCategory: column.codeCategory || "", codeValue: column.codeValue || "", referenceTable: column.referenceTable || "", @@ -487,7 +515,7 @@ export default function TableManagementPage() { if (response.data.success) { console.log("✅ 컬럼 설정 저장 성공"); - + // 🆕 Category 타입인 경우 컬럼 매핑 처리 console.log("🔍 카테고리 조건 체크:", { isCategory: column.inputType === "category", @@ -547,7 +575,7 @@ export default function TableManagementPage() { } else if (successCount > 0 && failCount > 0) { toast.warning(`컬럼 설정 저장 성공. ${successCount}개 메뉴 매핑 성공, ${failCount}개 실패.`); } else if (failCount > 0) { - toast.error(`컬럼 설정 저장 성공. 메뉴 매핑 생성 실패.`); + toast.error("컬럼 설정 저장 성공. 메뉴 매핑 생성 실패."); } } else { toast.success("컬럼 설정이 저장되었습니다. (메뉴 매핑 없음)"); @@ -680,9 +708,7 @@ export default function TableManagementPage() { console.log("📊 전체 매핑 결과:", { totalSuccessCount, totalFailCount }); if (totalSuccessCount > 0) { - toast.success( - `테이블 설정 및 ${totalSuccessCount}개 카테고리 메뉴 매핑이 저장되었습니다.` - ); + toast.success(`테이블 설정 및 ${totalSuccessCount}개 카테고리 메뉴 매핑이 저장되었습니다.`); } else if (totalFailCount > 0) { toast.warning(`테이블 설정은 저장되었으나 ${totalFailCount}개 메뉴 매핑 생성 실패.`); } else { @@ -1000,14 +1026,15 @@ export default function TableManagementPage() { .filter( (table) => table.tableName.toLowerCase().includes(searchTerm.toLowerCase()) || - (table.displayName && table.displayName.toLowerCase().includes(searchTerm.toLowerCase())), + (table.displayName && + table.displayName.toLowerCase().includes(searchTerm.toLowerCase())), ) .every((table) => selectedTableIds.has(table.tableName)) } onCheckedChange={handleSelectAll} aria-label="전체 선택" /> - + {selectedTableIds.size > 0 && `${selectedTableIds.size}개 선택됨`} @@ -1047,9 +1074,9 @@ export default function TableManagementPage() {
e.stopPropagation()} /> )} -
handleTableSelect(table.tableName)} - > +
handleTableSelect(table.tableName)}>

{table.displayName || table.tableName}

{table.description || getTextFromUI(TABLE_MANAGEMENT_KEYS.TABLE_DESCRIPTION, "설명 없음")} @@ -1147,7 +1171,10 @@ export default function TableManagementPage() { ) : (

{/* 컬럼 헤더 (고정) */} -
+
컬럼명
라벨
입력 타입
@@ -1171,7 +1198,7 @@ export default function TableManagementPage() { className="bg-background hover:bg-muted/50 grid min-h-16 items-start border-b px-6 py-3 transition-colors" style={{ gridTemplateColumns: "160px 200px 250px 1fr" }} > -
+
{column.columnName}
@@ -1226,9 +1253,9 @@ export default function TableManagementPage() { -
+
{secondLevelMenus.length === 0 ? ( -

+

2레벨 메뉴가 없습니다. 메뉴를 선택하지 않으면 모든 메뉴에서 사용 가능합니다.

) : ( @@ -1236,7 +1263,7 @@ export default function TableManagementPage() { // menuObjid를 숫자로 변환하여 비교 const menuObjidNum = Number(menu.menuObjid); const isChecked = (column.categoryMenus || []).includes(menuObjidNum); - + return (
col.columnName === column.columnName ? { ...col, categoryMenus: newMenus } - : col - ) + : col, + ), ); }} - className="h-4 w-4 rounded border-gray-300 text-primary focus:ring-2 focus:ring-ring" + className="text-primary focus:ring-ring h-4 w-4 rounded border-gray-300 focus:ring-2" /> @@ -1282,9 +1309,7 @@ export default function TableManagementPage() { <> {/* 참조 테이블 */}
- + @@ -1361,9 +1379,7 @@ export default function TableManagementPage() { column.referenceColumn && column.referenceColumn !== "none" && (
- +