From e8bdcbb95cbe35a2a1e2fd6558f4eded2e2c18cc Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Thu, 15 Jan 2026 14:36:00 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=B0=9C=EC=A3=BC/=EC=9E=85=EA=B3=A0?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EA=B7=B8=EB=A3=B9=20=ED=8E=B8=EC=A7=91=20?= =?UTF-8?q?=EC=8B=9C=20=EB=8B=A8=EA=B1=B4=EB=A7=8C=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EB=90=98=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?EditModal.tsx:=20conditional-container=20=EC=A1=B4=EC=9E=AC=20?= =?UTF-8?q?=EC=8B=9C=20onSave=20=EB=AF=B8=EC=A0=84=EB=8B=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95=20ModalRepeaterTableComponent.ts?= =?UTF-8?q?x:=20groupedData=20prop=20=EC=9A=B0=EC=84=A0=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/components/screen/EditModal.tsx | 36 ++++++------------- .../ModalRepeaterTableComponent.tsx | 16 +++++++-- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/frontend/components/screen/EditModal.tsx b/frontend/components/screen/EditModal.tsx index b3c94ade..7c722ad6 100644 --- a/frontend/components/screen/EditModal.tsx +++ b/frontend/components/screen/EditModal.tsx @@ -309,17 +309,10 @@ export const EditModal: React.FC = ({ className }) => { // 🆕 그룹 데이터 조회 함수 const loadGroupData = async () => { if (!modalState.tableName || !modalState.groupByColumns || modalState.groupByColumns.length === 0) { - // console.warn("테이블명 또는 그룹핑 컬럼이 없습니다."); return; } try { - // console.log("🔍 그룹 데이터 조회 시작:", { - // tableName: modalState.tableName, - // groupByColumns: modalState.groupByColumns, - // editData: modalState.editData, - // }); - // 그룹핑 컬럼 값 추출 (예: order_no = "ORD-20251124-001") const groupValues: Record = {}; modalState.groupByColumns.forEach((column) => { @@ -329,15 +322,9 @@ export const EditModal: React.FC = ({ className }) => { }); if (Object.keys(groupValues).length === 0) { - // console.warn("그룹핑 컬럼 값이 없습니다:", modalState.groupByColumns); return; } - // console.log("🔍 그룹 조회 요청:", { - // tableName: modalState.tableName, - // groupValues, - // }); - // 같은 그룹의 모든 레코드 조회 (entityJoinApi 사용) const { entityJoinApi } = await import("@/lib/api/entityJoin"); const response = await entityJoinApi.getTableDataWithJoins(modalState.tableName, { @@ -347,23 +334,19 @@ export const EditModal: React.FC = ({ className }) => { enableEntityJoin: true, }); - // console.log("🔍 그룹 조회 응답:", response); - // entityJoinApi는 배열 또는 { data: [] } 형식으로 반환 const dataArray = Array.isArray(response) ? response : response?.data || []; if (dataArray.length > 0) { - // console.log("✅ 그룹 데이터 조회 성공:", dataArray.length, "건"); setGroupData(dataArray); setOriginalGroupData(JSON.parse(JSON.stringify(dataArray))); // Deep copy toast.info(`${dataArray.length}개의 관련 품목을 불러왔습니다.`); } else { - console.warn("그룹 데이터가 없습니다:", response); setGroupData([modalState.editData]); // 기본값: 선택된 행만 setOriginalGroupData([JSON.parse(JSON.stringify(modalState.editData))]); } } catch (error: any) { - console.error("❌ 그룹 데이터 조회 오류:", error); + console.error("그룹 데이터 조회 오류:", error); toast.error("관련 데이터를 불러오는 중 오류가 발생했습니다."); setGroupData([modalState.editData]); // 기본값: 선택된 행만 setOriginalGroupData([JSON.parse(JSON.stringify(modalState.editData))]); @@ -1043,17 +1026,18 @@ export const EditModal: React.FC = ({ className }) => { const groupedDataProp = groupData.length > 0 ? groupData : undefined; // 🆕 UniversalFormModal이 있는지 확인 (자체 저장 로직 사용) - // 최상위 컴포넌트 또는 조건부 컨테이너 내부 화면에 universal-form-modal이 있는지 확인 + // 최상위 컴포넌트에 universal-form-modal이 있는지 확인 + // ⚠️ 수정: conditional-container는 제외 (groupData가 있으면 EditModal.handleSave 사용) const hasUniversalFormModal = screenData.components.some( (c) => { - // 최상위에 universal-form-modal이 있는 경우 + // 최상위에 universal-form-modal이 있는 경우만 자체 저장 로직 사용 if (c.componentType === "universal-form-modal") return true; - // 조건부 컨테이너 내부에 universal-form-modal이 있는 경우 - // (조건부 컨테이너가 있으면 내부 화면에서 universal-form-modal을 사용하는 것으로 가정) - if (c.componentType === "conditional-container") return true; return false; } ); + + // 🆕 그룹 데이터가 있으면 EditModal.handleSave 사용 (일괄 저장) + const shouldUseEditModalSave = groupData.length > 0 || !hasUniversalFormModal; // 🔑 첨부파일 컴포넌트가 행(레코드) 단위로 파일을 저장할 수 있도록 tableName 추가 const enrichedFormData = { @@ -1095,9 +1079,9 @@ export const EditModal: React.FC = ({ className }) => { id: modalState.screenId!, tableName: screenData.screenInfo?.tableName, }} - // 🆕 UniversalFormModal이 있으면 onSave 전달 안 함 (자체 저장 로직 사용) - // ModalRepeaterTable만 있으면 기존대로 onSave 전달 (호환성 유지) - onSave={hasUniversalFormModal ? undefined : handleSave} + // 🆕 그룹 데이터가 있거나 UniversalFormModal이 없으면 EditModal.handleSave 사용 + // groupData가 있으면 일괄 저장을 위해 반드시 EditModal.handleSave 사용 + onSave={shouldUseEditModalSave ? handleSave : undefined} isInModal={true} // 🆕 그룹 데이터를 ModalRepeaterTable에 전달 groupedData={groupedDataProp} diff --git a/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx b/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx index 2caf1332..153cebdf 100644 --- a/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx +++ b/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx @@ -180,8 +180,11 @@ export function ModalRepeaterTableComponent({ filterCondition: propFilterCondition, companyCode: propCompanyCode, + // 🆕 그룹 데이터 (EditModal에서 전달, 같은 그룹의 여러 품목) + groupedData, + ...props -}: ModalRepeaterTableComponentProps) { +}: ModalRepeaterTableComponentProps & { groupedData?: Record[] }) { // ✅ config 또는 component.config 또는 개별 prop 우선순위로 병합 const componentConfig = { ...config, @@ -208,9 +211,16 @@ export function ModalRepeaterTableComponent({ // 모달 필터 설정 const modalFilters = componentConfig?.modalFilters || []; - // ✅ value는 formData[columnName] 우선, 없으면 prop 사용 + // ✅ value는 groupedData 우선, 없으면 formData[columnName], 없으면 prop 사용 const columnName = component?.columnName; - const externalValue = (columnName && formData?.[columnName]) || componentConfig?.value || propValue || []; + + // 🆕 groupedData가 전달되면 (EditModal에서 그룹 조회 결과) 우선 사용 + const externalValue = (() => { + if (groupedData && groupedData.length > 0) { + return groupedData; + } + return (columnName && formData?.[columnName]) || componentConfig?.value || propValue || []; + })(); // 빈 객체 판단 함수 (수정 모달의 실제 데이터는 유지) const isEmptyRow = (item: any): boolean => {