From 77bb917248bb85edb79ee00efa7de66554e0ed4b Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Tue, 6 Jan 2026 15:03:22 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20RepeaterFieldGroup=20=EC=83=81=EC=9C=84?= =?UTF-8?q?=20=ED=8F=BC=20=ED=95=84=EB=93=9C=20=EC=A0=84=EB=8B=AC=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 하드코딩된 masterDetailFields 배열을 규칙 기반 필터링으로 변경 - 제외 규칙: comp_ 접두사, _numberingRuleId 접미사, 배열/객체 타입, 빈 값 등 - 새 필드 추가 시 코드 수정 불필요하도록 개선 - 에러 로깅 상세 정보 추가 (status, data, message, fullError) --- frontend/lib/utils/buttonActions.ts | 58 +++++++++++++---------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/frontend/lib/utils/buttonActions.ts b/frontend/lib/utils/buttonActions.ts index 681e9a3f..472de705 100644 --- a/frontend/lib/utils/buttonActions.ts +++ b/frontend/lib/utils/buttonActions.ts @@ -996,38 +996,27 @@ export class ButtonActionExecutor { } // 🆕 루트 레벨 formData에서 RepeaterFieldGroup에 전달할 공통 필드 추출 - // 주문번호, 발주번호 등 마스터-디테일 관계에서 필요한 필드만 명시적으로 지정 - const masterDetailFields = [ - // 번호 필드 - "order_no", // 발주번호 - "sales_order_no", // 수주번호 - "shipment_no", // 출하번호 - "receipt_no", // 입고번호 - "work_order_no", // 작업지시번호 - // 거래처 필드 - "supplier_code", // 공급처 코드 - "supplier_name", // 공급처 이름 - "customer_code", // 고객 코드 - "customer_name", // 고객 이름 - // 날짜 필드 - "order_date", // 발주일 - "sales_date", // 수주일 - "shipment_date", // 출하일 - "receipt_date", // 입고일 - "due_date", // 납기일 - // 담당자/메모 필드 - "manager", // 담당자 - "memo", // 메모 - "remark", // 비고 - ]; + // 규칙 기반 필터링: 하드코딩 대신 패턴으로 제외할 필드를 정의 + for (const [fieldName, value] of Object.entries(context.formData)) { + // 제외 규칙 1: comp_로 시작하는 필드 (하위 항목 배열) + if (fieldName.startsWith("comp_")) continue; + // 제외 규칙 2: _numberingRuleId로 끝나는 필드 (채번 규칙 메타 정보) + if (fieldName.endsWith("_numberingRuleId")) continue; + // 제외 규칙 3: _로 시작하는 필드 (내부 메타 필드) + if (fieldName.startsWith("_")) continue; + // 제외 규칙 4: 배열 타입 (하위 항목 데이터) + if (Array.isArray(value)) continue; + // 제외 규칙 5: 객체 타입 (복잡한 구조 데이터) - null 제외 + if (value !== null && typeof value === "object") continue; + // 제외 규칙 6: 빈 값 + if (value === undefined || value === "" || value === null) continue; + // 제외 규칙 7: 이미 commonFields에 있는 필드 (범용 폼 모달에서 가져온 필드) + if (fieldName in commonFields) continue; - for (const fieldName of masterDetailFields) { - const value = context.formData[fieldName]; - if (value !== undefined && value !== "" && value !== null && !(fieldName in commonFields)) { - commonFields[fieldName] = value; - } + // 위 규칙에 해당하지 않는 단순 값(문자열, 숫자, 날짜 등)은 공통 필드로 전달 + commonFields[fieldName] = value; } - console.log("📋 [handleSave] 최종 공통 필드 (마스터-디테일 필드 포함):", commonFields); + console.log("📋 [handleSave] 최종 공통 필드 (규칙 기반 자동 추출):", commonFields); for (const item of parsedData) { // 메타 필드 제거 (eslint 경고 무시 - 의도적으로 분리) @@ -1089,10 +1078,15 @@ export class ButtonActionExecutor { console.log("✅ [handleSave] RepeaterFieldGroup UPDATE 완료:", updateResult.data); } } catch (err) { - const error = err as { response?: { data?: unknown }; message?: string }; + const error = err as { response?: { data?: unknown; status?: number }; message?: string }; console.error( `❌ [handleSave] RepeaterFieldGroup 저장 실패 (${repeaterTargetTable}):`, - error.response?.data || error.message, + { + status: error.response?.status, + data: error.response?.data, + message: error.message, + fullError: JSON.stringify(error.response?.data, null, 2), + }, ); } }