diff --git a/frontend/components/screen/EditModal.tsx b/frontend/components/screen/EditModal.tsx index ec36096d..0127af40 100644 --- a/frontend/components/screen/EditModal.tsx +++ b/frontend/components/screen/EditModal.tsx @@ -18,7 +18,7 @@ import { useAuth } from "@/hooks/useAuth"; import { ConditionalZone, LayerDefinition } from "@/types/screen-management"; import { convertV2ToLegacy, isValidV2Layout } from "@/lib/utils/layoutV2Converter"; import { ScreenContextProvider } from "@/contexts/ScreenContext"; - +import { entityJoinApi } from "@/lib/api/entityJoin"; interface EditModalState { isOpen: boolean; screenId: number | null; @@ -244,6 +244,92 @@ export const EditModal: React.FC = ({ className }) => { } }; + /** + * 디테일 행의 FK를 통해 마스터 테이블 데이터를 자동 조회 + * - entity join 설정에서 FK 관계 탐지 + * - FK 값으로 마스터 테이블 전체 row 조회 + * - editData에 없는 필드만 병합 (디테일 데이터를 덮어쓰지 않음) + */ + const loadMasterDataForDetailRow = async ( + editData: Record, + targetScreenId: number, + eventTableName?: string, + ): Promise> => { + try { + let detailTableName = eventTableName; + if (!detailTableName) { + const screenInfo = await screenApi.getScreen(targetScreenId); + detailTableName = screenInfo?.tableName; + } + + if (!detailTableName) { + console.log("[EditModal:MasterLoad] 테이블명을 알 수 없음 - 스킵"); + return {}; + } + + console.log("[EditModal:MasterLoad] 시작:", { detailTableName, editDataKeys: Object.keys(editData) }); + + const entityJoinRes = await entityJoinApi.getEntityJoinConfigs(detailTableName); + const joinConfigs = entityJoinRes?.joinConfigs || []; + + if (joinConfigs.length === 0) { + console.log("[EditModal:MasterLoad] entity join 없음 - 스킵"); + return {}; + } + + console.log("[EditModal:MasterLoad] entity join:", joinConfigs.map((c) => `${c.sourceColumn} → ${c.referenceTable}`)); + + const masterDataResult: Record = {}; + const processedTables = new Set(); + const { apiClient } = await import("@/lib/api/client"); + + for (const joinConfig of joinConfigs) { + const { sourceColumn, referenceTable, referenceColumn } = joinConfig; + if (processedTables.has(referenceTable)) continue; + + const fkValue = editData[sourceColumn]; + if (!fkValue) continue; + + try { + const response = await apiClient.post( + `/table-management/tables/${referenceTable}/data`, + { + search: { [referenceColumn || "id"]: fkValue }, + size: 1, + page: 1, + autoFilter: true, + }, + ); + + const rows = response.data?.data?.data || response.data?.data?.rows || []; + if (rows.length > 0) { + const masterRow = rows[0]; + for (const [col, val] of Object.entries(masterRow)) { + if (val !== undefined && val !== null && editData[col] === undefined) { + masterDataResult[col] = val; + } + } + console.log("[EditModal:MasterLoad] 조회 성공:", { + table: referenceTable, + fk: `${sourceColumn}=${fkValue}`, + loadedFields: Object.keys(masterDataResult), + }); + } + } catch (queryError) { + console.warn("[EditModal:MasterLoad] 조회 실패:", referenceTable, queryError); + } + + processedTables.add(referenceTable); + } + + console.log("[EditModal:MasterLoad] 최종 결과:", Object.keys(masterDataResult)); + return masterDataResult; + } catch (error) { + console.warn("[EditModal:MasterLoad] 전체 오류:", error); + return {}; + } + }; + // 전역 모달 이벤트 리스너 useEffect(() => { const handleOpenEditModal = async (event: CustomEvent) => { @@ -294,6 +380,8 @@ export const EditModal: React.FC = ({ className }) => { } }); } + + // editData로 formData를 즉시 세팅 (채번 컴포넌트가 빈 formData로 마운트되어 새 번호 생성하는 것 방지) setFormData(enriched); // originalData: changedData 계산(PATCH)에만 사용 // INSERT/UPDATE 판단에는 사용하지 않음 @@ -302,6 +390,21 @@ export const EditModal: React.FC = ({ className }) => { // isCreateMode=true(복사/등록) → INSERT, false/undefined(수정) → UPDATE setIsCreateModeFlag(!!isCreateMode); + // 마스터 데이터 자동 조회 (수정 모드일 때, formData 세팅 이후 비동기로 병합) + // 디테일 행 선택 시 마스터 테이블의 컬럼 데이터를 자동으로 가져와서 추가 + if (!isCreateMode && editData && screenId) { + loadMasterDataForDetailRow(editData, screenId, tableName) + .then((masterData) => { + if (Object.keys(masterData).length > 0) { + setFormData((prev) => ({ ...prev, ...masterData })); + console.log("[EditModal] 마스터 데이터 비동기 병합 완료:", Object.keys(masterData)); + } + }) + .catch((masterError) => { + console.warn("[EditModal] 마스터 데이터 자동 조회 중 오류 (무시):", masterError); + }); + } + console.log("[EditModal] 모달 열림:", { mode: isCreateMode ? "INSERT (생성/복사)" : "UPDATE (수정)", hasEditData: !!editData, @@ -1529,7 +1632,10 @@ export const EditModal: React.FC = ({ className }) => { const shouldUseEditModalSave = !hasTableSectionData && (groupData.length > 0 || !hasUniversalFormModal); const enrichedFormData = { - ...(groupData.length > 0 ? groupData[0] : formData), + // 마스터 데이터(formData)를 기본으로 깔고, groupData[0]으로 덮어쓰기 + // → 디테일 행 수정 시에도 마스터 폼 필드가 표시됨 + ...formData, + ...(groupData.length > 0 ? groupData[0] : {}), tableName: screenData.screenInfo?.tableName, screenId: modalState.screenId, }; @@ -1589,7 +1695,8 @@ export const EditModal: React.FC = ({ className }) => { }; const enrichedFormData = { - ...(groupData.length > 0 ? groupData[0] : formData), + ...formData, + ...(groupData.length > 0 ? groupData[0] : {}), tableName: screenData.screenInfo?.tableName, screenId: modalState.screenId, };