리피터 데이터 저장 로직 개선 및 이벤트 처리 추가

- EditModal, InteractiveScreenViewer, SaveModal 컴포넌트에서 리피터 데이터(배열)를 마스터 저장에서 제외하고, 별도로 저장하는 로직을 추가하였습니다.
- 리피터 데이터 저장 이벤트를 발생시켜 UnifiedRepeater 컴포넌트가 이를 리스닝하도록 개선하였습니다.
- 각 컴포넌트에서 최종 저장 데이터 로그를 업데이트하여, 저장 과정에서의 데이터 흐름을 명확히 하였습니다.

이로 인해 데이터 저장의 효율성과 리피터 관리의 일관성이 향상되었습니다.
This commit is contained in:
kjs
2026-01-22 14:23:38 +09:00
parent d429e237ee
commit 1d068e0a20
15 changed files with 441 additions and 957 deletions
+68 -38
View File
@@ -85,21 +85,25 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
const isModalMode = config.renderMode === "modal";
// 전역 리피터 등록
// 🆕 useCustomTable이 설정된 경우 mainTableName 사용 (실제 저장될 테이블)
useEffect(() => {
const tableName = config.dataSource?.tableName;
if (tableName) {
const targetTableName = config.useCustomTable && config.mainTableName
? config.mainTableName
: config.dataSource?.tableName;
if (targetTableName) {
if (!window.__unifiedRepeaterInstances) {
window.__unifiedRepeaterInstances = new Set();
}
window.__unifiedRepeaterInstances.add(tableName);
window.__unifiedRepeaterInstances.add(targetTableName);
}
return () => {
if (tableName && window.__unifiedRepeaterInstances) {
window.__unifiedRepeaterInstances.delete(tableName);
if (targetTableName && window.__unifiedRepeaterInstances) {
window.__unifiedRepeaterInstances.delete(targetTableName);
}
};
}, [config.dataSource?.tableName]);
}, [config.useCustomTable, config.mainTableName, config.dataSource?.tableName]);
// 저장 이벤트 리스너
useEffect(() => {
@@ -115,11 +119,11 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
const masterRecordId = event.detail?.masterRecordId || mainFormData?.id;
if (!tableName || data.length === 0) {
console.log("📋 UnifiedRepeater 저장 스킵:", { tableName, dataLength: data.length });
return;
}
console.log("📋 UnifiedRepeater 저장 시작:", {
// UnifiedRepeater 저장 시작
const saveInfo = {
tableName,
useCustomTable: config.useCustomTable,
mainTableName: config.mainTableName,
@@ -152,10 +156,24 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
// 커스텀 테이블: 리피터 데이터만 저장
mergedData = { ...cleanRow };
// 🆕 FK 자동 연결
if (config.foreignKeyColumn && masterRecordId) {
mergedData[config.foreignKeyColumn] = masterRecordId;
console.log(`📎 FK 자동 연결: ${config.foreignKeyColumn} = ${masterRecordId}`);
// 🆕 FK 자동 연결 - foreignKeySourceColumn이 설정된 경우 해당 컬럼 값 사용
if (config.foreignKeyColumn) {
// foreignKeySourceColumn이 있으면 mainFormData에서 해당 컬럼 값 사용
// 없으면 마스터 레코드 ID 사용 (기존 동작)
const sourceColumn = config.foreignKeySourceColumn;
let fkValue: any;
if (sourceColumn && mainFormData && mainFormData[sourceColumn] !== undefined) {
// mainFormData에서 참조 컬럼 값 가져오기
fkValue = mainFormData[sourceColumn];
} else {
// 기본: 마스터 레코드 ID 사용
fkValue = masterRecordId;
}
if (fkValue !== undefined && fkValue !== null) {
mergedData[config.foreignKeyColumn] = fkValue;
}
}
} else {
// 기존 방식: 메인 폼 데이터 병합
@@ -177,7 +195,6 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
await apiClient.post(`/table-management/tables/${tableName}/add`, filteredData);
}
console.log("✅ UnifiedRepeater 저장 완료:", data.length, "건 →", tableName);
} catch (error) {
console.error("❌ UnifiedRepeater 저장 실패:", error);
throw error;
@@ -252,13 +269,6 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
config.dataSource?.referenceKey ||
"id";
console.log("🔄 [UnifiedRepeater] 엔티티 참조 정보 조회:", {
foreignKey,
resolvedSourceTable: refTable,
resolvedReferenceKey: refKey,
configSourceTable: config.dataSource?.sourceTable,
});
setResolvedSourceTable(refTable);
setResolvedReferenceKey(refKey);
} else {
@@ -424,11 +434,29 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
const handleDataChange = useCallback(
(newData: any[]) => {
setData(newData);
onDataChange?.(newData);
// 🆕 _targetTable 메타데이터 포함하여 전달 (백엔드에서 테이블 분리용)
if (onDataChange) {
const targetTable = config.useCustomTable && config.mainTableName
? config.mainTableName
: config.dataSource?.tableName;
if (targetTable) {
// 각 행에 _targetTable 추가
const dataWithTarget = newData.map(row => ({
...row,
_targetTable: targetTable,
}));
onDataChange(dataWithTarget);
} else {
onDataChange(newData);
}
}
// 🆕 데이터 변경 시 자동으로 컬럼 너비 조정
setAutoWidthTrigger((prev) => prev + 1);
},
[onDataChange],
[onDataChange, config.useCustomTable, config.mainTableName, config.dataSource?.tableName],
);
// 행 변경 핸들러
@@ -436,11 +464,26 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
(index: number, newRow: any) => {
const newData = [...data];
newData[index] = newRow;
// 🆕 handleDataChange 대신 직접 호출 (행 변경마다 너비 조정은 불필요)
setData(newData);
onDataChange?.(newData);
// 🆕 _targetTable 메타데이터 포함
if (onDataChange) {
const targetTable = config.useCustomTable && config.mainTableName
? config.mainTableName
: config.dataSource?.tableName;
if (targetTable) {
const dataWithTarget = newData.map(row => ({
...row,
_targetTable: targetTable,
}));
onDataChange(dataWithTarget);
} else {
onDataChange(newData);
}
}
},
[data, onDataChange],
[data, onDataChange, config.useCustomTable, config.mainTableName, config.dataSource?.tableName],
);
// 행 삭제 핸들러
@@ -672,13 +715,6 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
return;
}
console.log("📥 [UnifiedRepeater] componentDataTransfer 수신:", {
targetComponentId,
dataCount: transferData?.length,
mode,
myId: parentId,
});
if (!transferData || transferData.length === 0) {
return;
}
@@ -719,12 +755,6 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
const customEvent = event as CustomEvent;
const { data: transferData, mappingRules, mode, sourcePosition } = customEvent.detail || {};
console.log("📥 [UnifiedRepeater] splitPanelDataTransfer 수신:", {
dataCount: transferData?.length,
mode,
sourcePosition,
});
if (!transferData || transferData.length === 0) {
return;
}