From 649ed5c6d71cfbce67c23364c52745a28df275af Mon Sep 17 00:00:00 2001 From: kjs Date: Wed, 24 Sep 2025 14:31:46 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A1=B0=EC=9D=B8=EC=BB=AC=EB=9F=BC=EC=88=98?= =?UTF-8?q?=EC=A0=95(=EC=A1=B0=EC=9D=B8=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EC=8B=9C=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=ED=91=9C=EC=8B=9C=20=EC=98=A4=EB=A5=98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/services/entityJoinService.ts | 110 +++++++++++--- .../src/services/tableManagementService.ts | 25 +++- .../table-list/SingleTableWithSticky.tsx | 22 ++- .../table-list/TableListComponent.tsx | 137 +++++++++++++----- 4 files changed, 238 insertions(+), 56 deletions(-) diff --git a/backend-node/src/services/entityJoinService.ts b/backend-node/src/services/entityJoinService.ts index d0b01846..56633952 100644 --- a/backend-node/src/services/entityJoinService.ts +++ b/backend-node/src/services/entityJoinService.ts @@ -42,9 +42,23 @@ export class EntityJoinService { }, }); + logger.info(`๐Ÿ” Entity ์ปฌ๋Ÿผ ์กฐํšŒ ๊ฒฐ๊ณผ: ${entityColumns.length}๊ฐœ ๋ฐœ๊ฒฌ`); + entityColumns.forEach((col, index) => { + logger.info( + ` ${index + 1}. ${col.column_name} -> ${col.reference_table}.${col.reference_column} (display: ${col.display_column})` + ); + }); + const joinConfigs: EntityJoinConfig[] = []; for (const column of entityColumns) { + logger.info(`๐Ÿ” Entity ์ปฌ๋Ÿผ ์ƒ์„ธ ์ •๋ณด:`, { + column_name: column.column_name, + reference_table: column.reference_table, + reference_column: column.reference_column, + display_column: column.display_column, + }); + if ( !column.column_name || !column.reference_table || @@ -58,6 +72,12 @@ export class EntityJoinService { let displayColumns: string[] = []; let separator = " - "; + logger.info(`๐Ÿ” ์กฐ๊ฑด ํ™•์ธ - ์ปฌ๋Ÿผ: ${column.column_name}`, { + hasScreenConfig: !!screenConfig, + hasDisplayColumns: screenConfig?.displayColumns, + displayColumn: column.display_column, + }); + if (screenConfig && screenConfig.displayColumns) { // ํ™”๋ฉด์—์„œ ์„ค์ •๋œ ํ‘œ์‹œ ์ปฌ๋Ÿผ๋“ค ์‚ฌ์šฉ (๊ธฐ๋ณธ ํ…Œ์ด๋ธ” + ์กฐ์ธ ํ…Œ์ด๋ธ” ์กฐํ•ฉ ์ง€์›) displayColumns = screenConfig.displayColumns; @@ -70,9 +90,12 @@ export class EntityJoinService { } else if (column.display_column && column.display_column !== "none") { // ๊ธฐ์กด ์„ค์ •๋œ ๋‹จ์ผ ํ‘œ์‹œ ์ปฌ๋Ÿผ ์‚ฌ์šฉ (none์ด ์•„๋‹Œ ๊ฒฝ์šฐ๋งŒ) displayColumns = [column.display_column]; + logger.info( + `๐Ÿ”ง ๊ธฐ์กด display_column ์‚ฌ์šฉ: ${column.column_name} โ†’ ${column.display_column}` + ); } else { - // ์กฐ์ธ ํƒญ์—์„œ ๋ณด์—ฌ์ค„ ๊ธฐ๋ณธ ํ‘œ์‹œ ์ปฌ๋Ÿผ ์„ค์ • - // dept_info ํ…Œ์ด๋ธ”์˜ ๊ฒฝ์šฐ dept_name์„ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉ + // display_column์ด "none"์ด๊ฑฐ๋‚˜ ์—†๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ ํ‘œ์‹œ ์ปฌ๋Ÿผ ์„ค์ • + // ๐Ÿšจ display_column์ด ํ•ญ์ƒ "none"์ด๋ฏ€๋กœ ์ด ๋กœ์ง์„ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉ let defaultDisplayColumn = column.reference_column; if (column.reference_table === "dept_info") { defaultDisplayColumn = "dept_name"; @@ -83,9 +106,10 @@ export class EntityJoinService { } displayColumns = [defaultDisplayColumn]; - console.log( - `๐Ÿ”ง ์กฐ์ธ ํƒญ์šฉ ๊ธฐ๋ณธ ํ‘œ์‹œ ์ปฌ๋Ÿผ ์„ค์ •: ${column.column_name} โ†’ ${defaultDisplayColumn} (${column.reference_table})` + logger.info( + `๐Ÿ”ง Entity ์กฐ์ธ ๊ธฐ๋ณธ ํ‘œ์‹œ ์ปฌ๋Ÿผ ์„ค์ •: ${column.column_name} โ†’ ${defaultDisplayColumn} (${column.reference_table})` ); + logger.info(`๐Ÿ” ์ƒ์„ฑ๋œ displayColumns ๋ฐฐ์—ด:`, displayColumns); } // ๋ณ„์นญ ์ปฌ๋Ÿผ๋ช… ์ƒ์„ฑ (writer -> writer_name) @@ -102,13 +126,32 @@ export class EntityJoinService { separator: separator, }; + logger.info(`๐Ÿ”ง ๊ธฐ๋ณธ ์กฐ์ธ ์„ค์ • ์ƒ์„ฑ:`, { + sourceTable: joinConfig.sourceTable, + sourceColumn: joinConfig.sourceColumn, + referenceTable: joinConfig.referenceTable, + aliasColumn: joinConfig.aliasColumn, + displayColumns: joinConfig.displayColumns, + }); + // ์กฐ์ธ ์„ค์ • ์œ ํšจ์„ฑ ๊ฒ€์ฆ + logger.info( + `๐Ÿ” ์กฐ์ธ ์„ค์ • ๊ฒ€์ฆ ์ค‘: ${joinConfig.sourceColumn} -> ${joinConfig.referenceTable}` + ); if (await this.validateJoinConfig(joinConfig)) { joinConfigs.push(joinConfig); + logger.info(`โœ… ์กฐ์ธ ์„ค์ • ์ถ”๊ฐ€๋จ: ${joinConfig.aliasColumn}`); + } else { + logger.warn(`โŒ ์กฐ์ธ ์„ค์ • ๊ฒ€์ฆ ์‹คํŒจ: ${joinConfig.sourceColumn}`); } } - logger.info(`Entity ์กฐ์ธ ์„ค์ • ์ƒ์„ฑ ์™„๋ฃŒ: ${joinConfigs.length}๊ฐœ`); + logger.info(`๐ŸŽฏ Entity ์กฐ์ธ ์„ค์ • ์ƒ์„ฑ ์™„๋ฃŒ: ${joinConfigs.length}๊ฐœ`); + joinConfigs.forEach((config, index) => { + logger.info( + ` ${index + 1}. ${config.sourceColumn} -> ${config.referenceTable}.${config.referenceColumn} AS ${config.aliasColumn}` + ); + }); return joinConfigs; } catch (error) { logger.error(`Entity ์กฐ์ธ ๊ฐ์ง€ ์‹คํŒจ: ${tableName}`, error); @@ -273,7 +316,7 @@ export class EntityJoinService { .filter(Boolean) .join("\n"); - logger.debug(`์ƒ์„ฑ๋œ Entity ์กฐ์ธ ์ฟผ๋ฆฌ:`, query); + logger.info(`๐Ÿ” ์ƒ์„ฑ๋œ Entity ์กฐ์ธ ์ฟผ๋ฆฌ:`, query); return { query: query, aliasMap: aliasMap, @@ -303,10 +346,18 @@ export class EntityJoinService { } // ์ฐธ์กฐ ํ…Œ์ด๋ธ”์˜ ์บ์‹œ ๊ฐ€๋Šฅ์„ฑ ํ™•์ธ + const displayCol = + config.displayColumn || + config.displayColumns?.[0] || + config.referenceColumn; + logger.info( + `๐Ÿ” ์บ์‹œ ํ™•์ธ์šฉ ํ‘œ์‹œ ์ปฌ๋Ÿผ: ${config.referenceTable} - ${displayCol}` + ); + const cachedData = await referenceCacheService.getCachedReference( config.referenceTable, config.referenceColumn, - config.displayColumn || config.displayColumns[0] + displayCol ); return cachedData ? "cache" : "join"; @@ -336,6 +387,14 @@ export class EntityJoinService { */ private async validateJoinConfig(config: EntityJoinConfig): Promise { try { + logger.info("๐Ÿ” ์กฐ์ธ ์„ค์ • ๊ฒ€์ฆ ์ƒ์„ธ:", { + sourceColumn: config.sourceColumn, + referenceTable: config.referenceTable, + displayColumns: config.displayColumns, + displayColumn: config.displayColumn, + aliasColumn: config.aliasColumn, + }); + // ์ฐธ์กฐ ํ…Œ์ด๋ธ” ์กด์žฌ ํ™•์ธ const tableExists = await prisma.$queryRaw` SELECT 1 FROM information_schema.tables @@ -350,23 +409,32 @@ export class EntityJoinService { // ์ฐธ์กฐ ์ปฌ๋Ÿผ ์กด์žฌ ํ™•์ธ (displayColumns[0] ์‚ฌ์šฉ) const displayColumn = config.displayColumns?.[0] || config.displayColumn; - if (!displayColumn) { - logger.warn(`ํ‘œ์‹œ ์ปฌ๋Ÿผ์ด ์„ค์ •๋˜์ง€ ์•Š์Œ: ${config.sourceColumn}`); - return false; - } + logger.info( + `๐Ÿ” ํ‘œ์‹œ ์ปฌ๋Ÿผ ํ™•์ธ: ${displayColumn} (from displayColumns: ${config.displayColumns}, displayColumn: ${config.displayColumn})` + ); - const columnExists = await prisma.$queryRaw` - SELECT 1 FROM information_schema.columns - WHERE table_name = ${config.referenceTable} - AND column_name = ${displayColumn} - LIMIT 1 - `; + // ๐Ÿšจ display_column์ด ํ•ญ์ƒ "none"์ด๋ฏ€๋กœ, ํ‘œ์‹œ ์ปฌ๋Ÿผ์ด ์—†์–ด๋„ ์กฐ์ธ ํ—ˆ์šฉ + if (displayColumn && displayColumn !== "none") { + const columnExists = await prisma.$queryRaw` + SELECT 1 FROM information_schema.columns + WHERE table_name = ${config.referenceTable} + AND column_name = ${displayColumn} + LIMIT 1 + `; - if (!Array.isArray(columnExists) || columnExists.length === 0) { - logger.warn( - `ํ‘œ์‹œ ์ปฌ๋Ÿผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Œ: ${config.referenceTable}.${displayColumn}` + if (!Array.isArray(columnExists) || columnExists.length === 0) { + logger.warn( + `ํ‘œ์‹œ ์ปฌ๋Ÿผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Œ: ${config.referenceTable}.${displayColumn}` + ); + return false; + } + logger.info( + `โœ… ํ‘œ์‹œ ์ปฌ๋Ÿผ ํ™•์ธ ์™„๋ฃŒ: ${config.referenceTable}.${displayColumn}` + ); + } else { + logger.info( + `๐Ÿ”ง ํ‘œ์‹œ ์ปฌ๋Ÿผ ๊ฒ€์ฆ ์ƒ๋žต: display_column์ด none์ด๊ฑฐ๋‚˜ ์„ค์ •๋˜์ง€ ์•Š์Œ` ); - return false; } return true; diff --git a/backend-node/src/services/tableManagementService.ts b/backend-node/src/services/tableManagementService.ts index 5cb2853d..1278c1c3 100644 --- a/backend-node/src/services/tableManagementService.ts +++ b/backend-node/src/services/tableManagementService.ts @@ -2049,6 +2049,17 @@ export class TableManagementService { options.screenEntityConfigs ); + logger.info( + `๐Ÿ” detectEntityJoins ๊ฒฐ๊ณผ: ${joinConfigs.length}๊ฐœ ์กฐ์ธ ์„ค์ •` + ); + if (joinConfigs.length > 0) { + joinConfigs.forEach((config, index) => { + logger.info( + ` ์กฐ์ธ ${index + 1}: ${config.sourceColumn} -> ${config.referenceTable} AS ${config.aliasColumn}` + ); + }); + } + // ์ถ”๊ฐ€ ์กฐ์ธ ์ปฌ๋Ÿผ ์ •๋ณด๊ฐ€ ์žˆ์œผ๋ฉด ์กฐ์ธ ์„ค์ •์— ์ถ”๊ฐ€ if ( options.additionalJoinColumns && @@ -2057,6 +2068,10 @@ export class TableManagementService { logger.info( `์ถ”๊ฐ€ ์กฐ์ธ ์ปฌ๋Ÿผ ์ฒ˜๋ฆฌ: ${options.additionalJoinColumns.length}๊ฐœ` ); + logger.info( + "๐Ÿ“‹ ์ „๋‹ฌ๋ฐ›์€ additionalJoinColumns:", + options.additionalJoinColumns + ); for (const additionalColumn of options.additionalJoinColumns) { // ๊ธฐ์กด ์กฐ์ธ ์„ค์ •์—์„œ ๊ฐ™์€ ์ฐธ์กฐ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜๋Š” ์„ค์ • ์ฐพ๊ธฐ @@ -2251,10 +2266,18 @@ export class TableManagementService { try { // ์บ์‹œ ๋ฐ์ดํ„ฐ ๋ฏธ๋ฆฌ ๋กœ๋“œ for (const config of joinConfigs) { + const displayCol = + config.displayColumn || + config.displayColumns?.[0] || + config.referenceColumn; + logger.info( + `๐Ÿ” ์บ์‹œ ๋กœ๋“œ - ${config.referenceTable}: keyCol=${config.referenceColumn}, displayCol=${displayCol}` + ); + await referenceCacheService.getCachedReference( config.referenceTable, config.referenceColumn, - config.displayColumn || config.displayColumns[0] + displayCol ); } diff --git a/frontend/lib/registry/components/table-list/SingleTableWithSticky.tsx b/frontend/lib/registry/components/table-list/SingleTableWithSticky.tsx index eeedfaaa..5687bdba 100644 --- a/frontend/lib/registry/components/table-list/SingleTableWithSticky.tsx +++ b/frontend/lib/registry/components/table-list/SingleTableWithSticky.tsx @@ -22,6 +22,7 @@ interface SingleTableWithStickyProps { renderCheckboxCell: (row: any, index: number) => React.ReactNode; formatCellValue: (value: any, format?: string, columnName?: string) => string; getColumnWidth: (column: ColumnConfig) => number; + joinColumnMapping: Record; // ์กฐ์ธ ์ปฌ๋Ÿผ ๋งคํ•‘ ์ถ”๊ฐ€ } export const SingleTableWithSticky: React.FC = ({ @@ -39,6 +40,7 @@ export const SingleTableWithSticky: React.FC = ({ renderCheckboxCell, formatCellValue, getColumnWidth, + joinColumnMapping, }) => { const checkboxConfig = tableConfig.checkbox || {}; @@ -174,7 +176,25 @@ export const SingleTableWithSticky: React.FC = ({ > {column.columnName === "__checkbox__" ? renderCheckboxCell(row, index) - : formatCellValue(row[column.columnName], column.format, column.columnName) || "\u00A0"} + : (() => { + // ๐ŸŽฏ ๋งคํ•‘๋œ ์ปฌ๋Ÿผ๋ช…์œผ๋กœ ๋ฐ์ดํ„ฐ ์ฐพ๊ธฐ (๊ธฐ๋ณธ ํ…Œ์ด๋ธ”๊ณผ ๋™์ผํ•œ ๋กœ์ง) + const mappedColumnName = joinColumnMapping[column.columnName] || column.columnName; + + // ์กฐ์ธ ์ปฌ๋Ÿผ ๋งคํ•‘ ์ •๋ณด ๋กœ๊น… + if (column.columnName !== mappedColumnName && index === 0) { + console.log(`๐Ÿ”— Sticky ์กฐ์ธ ์ปฌ๋Ÿผ ๋งคํ•‘: ${column.columnName} โ†’ ${mappedColumnName}`); + } + + const cellValue = row[mappedColumnName]; + if (index === 0) { + // ์ฒซ ๋ฒˆ์งธ ํ–‰๋งŒ ๋กœ๊ทธ ์ถœ๋ ฅ (๋””๋ฒ„๊น…์šฉ) + console.log( + `๐Ÿ” Sticky ์…€ ๋ฐ์ดํ„ฐ [${column.columnName} โ†’ ${mappedColumnName}]:`, + cellValue, + ); + } + return formatCellValue(cellValue, column.format, column.columnName) || "\u00A0"; + })()} ); })} diff --git a/frontend/lib/registry/components/table-list/TableListComponent.tsx b/frontend/lib/registry/components/table-list/TableListComponent.tsx index 2c5b1dd1..10416855 100644 --- a/frontend/lib/registry/components/table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/table-list/TableListComponent.tsx @@ -290,28 +290,39 @@ export const TableListComponent: React.FC = ({ // ๐ŸŽฏ ์กฐ์ธ ํƒญ์—์„œ ์ถ”๊ฐ€ํ•œ ์ปฌ๋Ÿผ๋“ค๋„ ์ถ”๊ฐ€ (์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š” ์ปฌ๋Ÿผ๋งŒ) ...joinTabColumns .filter((col) => { - // ์‹ค์ œ API ์‘๋‹ต์— ์กด์žฌํ•˜๋Š” ์ปฌ๋Ÿผ๋งŒ ํ•„ํ„ฐ๋ง - const validJoinColumns = ["dept_code_name", "dept_name"]; - const isValid = validJoinColumns.includes(col.columnName); - if (!isValid) { - console.log(`๐Ÿ” ์กฐ์ธ ํƒญ ์ปฌ๋Ÿผ ์ œ์™ธ: ${col.columnName} (์œ ํšจํ•˜์ง€ ์•Š์Œ)`); + // ์กฐ์ธ ์ปฌ๋Ÿผ์ธ์ง€ ํ™•์ธ (์–ธ๋”์Šค์ฝ”์–ด๊ฐ€ ํฌํ•จ๋œ ์ปฌ๋Ÿผ) + const isJoinColumn = col.columnName.includes("_") && col.columnName !== "__checkbox__"; + if (!isJoinColumn) { + console.log(`๐Ÿ” ์กฐ์ธ ํƒญ ์ปฌ๋Ÿผ ์ œ์™ธ: ${col.columnName} (์กฐ์ธ ์ปฌ๋Ÿผ์ด ์•„๋‹˜)`); } - return isValid; + return isJoinColumn; }) .map((col) => { - // ์‹ค์ œ ์กด์žฌํ•˜๋Š” ์กฐ์ธ ์ปฌ๋Ÿผ๋งŒ ์ฒ˜๋ฆฌ - let sourceTable = tableConfig.selectedTable; - let sourceColumn = col.columnName; + // ๋™์ ์œผ๋กœ ์กฐ์ธ ์ปฌ๋Ÿผ ์ •๋ณด ์ถ”์ถœ + console.log(`๐Ÿ” ์กฐ์ธ ์ปฌ๋Ÿผ ๋ถ„์„: ${col.columnName}`); - if (col.columnName === "dept_code_name" || col.columnName === "dept_name") { - sourceTable = "dept_info"; + // ์ปฌ๋Ÿผ๋ช…์—์„œ ๊ธฐ๋ณธ ์ปฌ๋Ÿผ๊ณผ ์ฐธ์กฐ ํ…Œ์ด๋ธ” ์ถ”์ถœ + // ์˜ˆ: dept_code_company_name -> dept_code (๊ธฐ๋ณธ), company_name (์ฐธ์กฐ) + const parts = col.columnName.split("_"); + let sourceColumn = ""; + let referenceTable = ""; + + // dept_code๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ์šฐ + if (col.columnName.startsWith("dept_code_")) { sourceColumn = "dept_code"; + referenceTable = "dept_info"; + } + // ๋‹ค๋ฅธ ํŒจํ„ด๋“ค๋„ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ + else { + // ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ถ„์„ ์†Œ์Šค ์ปฌ๋Ÿผ์œผ๋กœ ์‚ฌ์šฉ + sourceColumn = parts[0]; + referenceTable = tableConfig.selectedTable || "unknown"; } - console.log(`๐Ÿ” ์กฐ์ธ ํƒญ ์ปฌ๋Ÿผ ์ฒ˜๋ฆฌ: ${col.columnName} -> ${sourceTable}.${sourceColumn}`); + console.log(`๐Ÿ”— ์กฐ์ธ ์„ค์ •: ${col.columnName} -> ${sourceColumn} (${referenceTable})`); return { - sourceTable: sourceTable || tableConfig.selectedTable || "unknown", + sourceTable: referenceTable, sourceColumn: sourceColumn, joinAlias: col.columnName, }; @@ -410,6 +421,14 @@ export const TableListComponent: React.FC = ({ console.log("๐ŸŽฏ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜:", result.data?.length || 0); console.log("๐ŸŽฏ ์ „์ฒด ํŽ˜์ด์ง€:", result.totalPages); console.log("๐ŸŽฏ ์ด ์•„์ดํ…œ:", result.total); + + // ๐Ÿšจ ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ ํ™•์ธ (์ฒซ ๋ฒˆ์งธ ํ–‰์˜ ๋ชจ๋“  ์ปฌ๋Ÿผ๊ณผ ๊ฐ’) + if (result.data && result.data.length > 0) { + console.log("๐Ÿ” ์ฒซ ๋ฒˆ์งธ ํ–‰ ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ:", result.data[0]); + Object.entries(result.data[0]).forEach(([key, value]) => { + console.log(` ๐Ÿ“Š ${key}: "${value}" (ํƒ€์ž…: ${typeof value})`); + }); + } setData(result.data || []); setTotalPages(result.totalPages || 1); setTotalItems(result.total || 0); @@ -507,24 +526,62 @@ export const TableListComponent: React.FC = ({ } } - // 3. ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ๋งค์นญ (์ปฌ๋Ÿผ๋ช…์— ์ผ๋ถ€๊ฐ€ ํฌํ•จ๋œ ๊ฒฝ์šฐ) + // 3. ์กฐ์ธ ์ปฌ๋Ÿผ ๊ฒ€์ฆ ๋ฐ ์ฒ˜๋ฆฌ if (!foundMatch) { - const partialMatches = actualApiColumns.filter( - (apiCol) => apiCol.includes(userColumn.columnName) || userColumn.columnName.includes(apiCol), - ); + // ๐Ÿšจ ์กฐ์ธ ์ปฌ๋Ÿผ์ธ์ง€ ํ™•์ธ (๋” ์ •ํ™•ํ•œ ๊ฐ์ง€ ๋กœ์ง) + const hasUnderscore = userColumn.columnName.includes("_"); + let isJoinColumn = false; + let baseColumnName = ""; - if (partialMatches.length > 0) { - // ๊ฐ€์žฅ ๊ธธ์ด๊ฐ€ ๋น„์Šทํ•œ ๊ฒƒ ์„ ํƒ - const bestMatch = partialMatches.reduce((best, current) => - Math.abs(current.length - userColumn.columnName.length) < - Math.abs(best.length - userColumn.columnName.length) - ? current - : best, + if (hasUnderscore) { + // ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๊ธฐ๋ณธ ์ปฌ๋Ÿผ๋ช…์„ ํ™•์ธ (dept_code_company_name -> dept_code, dept ์ˆœ์œผ๋กœ) + const parts = userColumn.columnName.split("_"); + for (let i = parts.length - 1; i >= 1; i--) { + const possibleBase = parts.slice(0, i).join("_"); + if (actualApiColumns.includes(possibleBase)) { + baseColumnName = possibleBase; + isJoinColumn = true; + break; + } + } + } + + console.log(`๐Ÿ” ์กฐ์ธ ์ปฌ๋Ÿผ ๊ฒ€์‚ฌ: "${userColumn.columnName}"`, { + hasUnderscore, + baseColumnName, + isJoinColumn, + }); + + if (isJoinColumn) { + console.log(`๐Ÿ” ์กฐ์ธ ์ปฌ๋Ÿผ ๊ธฐ๋ณธ ์ปฌ๋Ÿผ ํ™•์ธ: "${baseColumnName}"`, { + existsInApi: actualApiColumns.includes(baseColumnName), + actualApiColumns: actualApiColumns.slice(0, 10), // ์ฒ˜์Œ 10๊ฐœ๋งŒ ํ‘œ์‹œ + }); + + console.warn( + `โš ๏ธ ์กฐ์ธ ์‹คํŒจ: "${userColumn.columnName}" - ๋ฐฑ์—”๋“œ์—์„œ Entity ์กฐ์ธ์ด ์‹คํ–‰๋˜์ง€ ์•Š์Œ. ๊ธฐ๋ณธ ์ปฌ๋Ÿผ๊ฐ’ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.`, + ); + // ์กฐ์ธ ์‹คํŒจ ์‹œ ๊ธฐ๋ณธ ์ปฌ๋Ÿผ๊ฐ’์„ ํ‘œ์‹œํ•˜๋„๋ก ๋งคํ•‘ + newJoinColumnMapping[userColumn.columnName] = baseColumnName; + foundMatch = true; + } else { + // ์ผ๋ฐ˜ ์ปฌ๋Ÿผ์ธ ๊ฒฝ์šฐ ๋ถ€๋ถ„ ๋งค์นญ ์‹œ๋„ + const partialMatches = actualApiColumns.filter( + (apiCol) => apiCol.includes(userColumn.columnName) || userColumn.columnName.includes(apiCol), ); - newJoinColumnMapping[userColumn.columnName] = bestMatch; - console.log(`๐Ÿ” ๋ถ€๋ถ„ ๋งคํ•‘: ${userColumn.columnName} โ†’ ${bestMatch}`); - foundMatch = true; + if (partialMatches.length > 0) { + const bestMatch = partialMatches.reduce((best, current) => + Math.abs(current.length - userColumn.columnName.length) < + Math.abs(best.length - userColumn.columnName.length) + ? current + : best, + ); + + newJoinColumnMapping[userColumn.columnName] = bestMatch; + console.log(`๐Ÿ” ๋ถ€๋ถ„ ๋งคํ•‘: ${userColumn.columnName} โ†’ ${bestMatch}`); + foundMatch = true; + } } } @@ -1245,6 +1302,7 @@ export const TableListComponent: React.FC = ({ renderCheckboxCell={renderCheckboxCell} formatCellValue={formatCellValue} getColumnWidth={getColumnWidth} + joinColumnMapping={joinColumnMapping} /> ) : ( // ๊ธฐ์กด ํ…Œ์ด๋ธ” (๊ฐ€๋กœ ์Šคํฌ๋กค์ด ํ•„์š” ์—†๋Š” ๊ฒฝ์šฐ) @@ -1325,15 +1383,28 @@ export const TableListComponent: React.FC = ({ : (() => { // ๐ŸŽฏ ๋งคํ•‘๋œ ์ปฌ๋Ÿผ๋ช…์œผ๋กœ ๋ฐ์ดํ„ฐ ์ฐพ๊ธฐ const mappedColumnName = joinColumnMapping[column.columnName] || column.columnName; + + // ์กฐ์ธ ์ปฌ๋Ÿผ ๋งคํ•‘ ์ •๋ณด ๋กœ๊น… + if (column.columnName !== mappedColumnName && index === 0) { + console.log(`๐Ÿ”— ์กฐ์ธ ์ปฌ๋Ÿผ ๋งคํ•‘: ${column.columnName} โ†’ ${mappedColumnName}`); + } + const cellValue = row[mappedColumnName]; if (index === 0) { // ์ฒซ ๋ฒˆ์งธ ํ–‰๋งŒ ๋กœ๊ทธ ์ถœ๋ ฅ - console.log( - `๐Ÿ” ์…€ ๋ฐ์ดํ„ฐ [${column.columnName} โ†’ ${mappedColumnName}]:`, - cellValue, - "์ „์ฒด row:", - row, - ); + console.log(`๐Ÿ” ์…€ ๋ฐ์ดํ„ฐ [${column.columnName} โ†’ ${mappedColumnName}]:`, cellValue); + + // ๐Ÿšจ ์กฐ์ธ๋œ ์ปฌ๋Ÿผ์ธ ๊ฒฝ์šฐ ์ถ”๊ฐ€ ๋””๋ฒ„๊น… + if (column.columnName !== mappedColumnName) { + console.log(" ๐Ÿ”— ์กฐ์ธ ์ปฌ๋Ÿผ ๋ถ„์„:"); + console.log(` ๐Ÿ‘ค ์‚ฌ์šฉ์ž ์„ค์ • ์ปฌ๋Ÿผ: "${column.columnName}"`); + console.log(` ๐Ÿ“ก ๋งคํ•‘๋œ API ์ปฌ๋Ÿผ: "${mappedColumnName}"`); + console.log(` ๐Ÿ“‹ ์ปฌ๋Ÿผ ๋ผ๋ฒจ: "${column.displayName}"`); + console.log(` ๐Ÿ’พ ์‹ค์ œ ๋ฐ์ดํ„ฐ: "${cellValue}"`); + console.log( + ` ๐Ÿ”„ ์›๋ณธ ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ (${column.columnName}): "${row[column.columnName]}"`, + ); + } } return formatCellValue(cellValue, column.format, column.columnName) || "\u00A0"; })()}