From 51099ba858e308835043e863c263c548e6402174 Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Fri, 12 Dec 2025 14:12:33 +0900 Subject: [PATCH] =?UTF-8?q?fix(modal-repeater-table):=20=EC=99=B8=EB=B6=80?= =?UTF-8?q?=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=A1=B0=EC=9D=B8=20=EC=8B=9C?= =?UTF-8?q?=20ID=20=ED=83=80=EC=9E=85=20=EB=B3=80=ED=99=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 문제: - 외부 테이블 조인 시 ID 값이 문자열로 전달되어 백엔드에서 ILIKE 검색 수행 - 문자열 '189'로 검색하면 '189', '1890', '18900' 등 모두 매칭되는 문제 - 발주 등록 화면에서 품목 참조 데이터 조회 실패 해결: - fetchReferenceValue 함수: 조인 조건 값 타입 변환 추가 - resolveDynamicValue 함수 (단순 테이블 조회): 조인 조건 값 타입 변환 추가 - resolveDynamicValue 함수 (복합 조인): 조인 조건 값 타입 변환 추가 변환 로직: - targetField가 '_id'로 끝나거나 'id'인 경우 Number()로 변환 - NaN 체크로 변환 불가능한 값은 원본 유지 - 백엔드에서 숫자는 = 비교, 문자열은 ILIKE 검색 수행하므로 정확한 매칭 필요 영향 범위: - modal-repeater-table 컴포넌트를 사용하는 모든 화면 - 발주 등록, 수주 등록 등 품목 참조 테이블 조회 --- .../ModalRepeaterTableComponent.tsx | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx b/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx index 64c9e95f..e16c5d72 100644 --- a/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx +++ b/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx @@ -78,7 +78,18 @@ async function fetchReferenceValue( // 연산자가 "=" 인 경우만 지원 (확장 가능) if (operator === "=") { - whereConditions[targetField] = value; + // 숫자형 ID인 경우 숫자로 변환 (문자열 '189' → 숫자 189) + // 백엔드에서 entity 타입 컬럼 검색 시 문자열이면 ILIKE 검색을 수행하므로 + // 정확한 ID 매칭을 위해 숫자로 변환해야 함 + let convertedValue = value; + if (targetField.endsWith('_id') || targetField === 'id') { + const numValue = Number(value); + if (!isNaN(numValue)) { + convertedValue = numValue; + console.log(` 🔢 ID 타입 변환: ${targetField} = "${value}" → ${numValue}`); + } + } + whereConditions[targetField] = convertedValue; } else { console.warn(`⚠️ 연산자 "${operator}"는 아직 지원되지 않습니다.`); } @@ -504,11 +515,18 @@ export function ModalRepeaterTableComponent({ const whereConditions: Record = {}; for (const cond of joinConditions) { - const value = rowData[cond.sourceField]; + let value = rowData[cond.sourceField]; if (value === undefined || value === null) { console.warn(`⚠️ 조인 조건의 소스 필드 "${cond.sourceField}" 값이 없음`); return undefined; } + // 숫자형 ID인 경우 숫자로 변환 + if (cond.targetField.endsWith('_id') || cond.targetField === 'id') { + const numValue = Number(value); + if (!isNaN(numValue)) { + value = numValue; + } + } whereConditions[cond.targetField] = value; } @@ -561,8 +579,16 @@ export function ModalRepeaterTableComponent({ } // 테이블 조회 + // 숫자형 ID인 경우 숫자로 변환 + let convertedFromValue = fromValue; + if (joinCondition.toField.endsWith('_id') || joinCondition.toField === 'id') { + const numValue = Number(fromValue); + if (!isNaN(numValue)) { + convertedFromValue = numValue; + } + } const whereConditions: Record = { - [joinCondition.toField]: fromValue + [joinCondition.toField]: convertedFromValue }; console.log(` 🔍 단계 ${i + 1}: ${tableName} 조회`, whereConditions);