feat: modal-repeater-table 배열 데이터 저장 기능 구현
- 백엔드: 배열 객체 형식 Repeater 데이터 처리 로직 추가 - 백엔드: Repeater 저장 시 company_code 자동 주입 - 백엔드: 부모 테이블 데이터 자동 병합 (targetTable = tableName) - 프론트엔드: beforeFormSave 이벤트로 formData 주입 - 프론트엔드: _targetTable 메타데이터 전달 - 프론트엔드: ComponentRendererProps 상속 및 Renderer 단순화 멀티테넌시 및 부모-자식 관계 자동 처리로 복잡한 배열 데이터 저장 안정성 확보
This commit is contained in:
@@ -320,43 +320,60 @@ export class DynamicFormService {
|
||||
Object.keys(dataToInsert).forEach((key) => {
|
||||
const value = dataToInsert[key];
|
||||
|
||||
// RepeaterInput 데이터인지 확인 (JSON 배열 문자열)
|
||||
if (
|
||||
// 🔥 RepeaterInput 데이터인지 확인 (배열 객체 또는 JSON 문자열)
|
||||
let parsedArray: any[] | null = null;
|
||||
|
||||
// 1️⃣ 이미 배열 객체인 경우 (ModalRepeaterTable, SelectedItemsDetailInput 등)
|
||||
if (Array.isArray(value) && value.length > 0) {
|
||||
parsedArray = value;
|
||||
console.log(
|
||||
`🔄 배열 객체 Repeater 데이터 감지: ${key}, ${parsedArray.length}개 항목`
|
||||
);
|
||||
}
|
||||
// 2️⃣ JSON 문자열인 경우 (레거시 RepeaterInput)
|
||||
else if (
|
||||
typeof value === "string" &&
|
||||
value.trim().startsWith("[") &&
|
||||
value.trim().endsWith("]")
|
||||
) {
|
||||
try {
|
||||
const parsedArray = JSON.parse(value);
|
||||
if (Array.isArray(parsedArray) && parsedArray.length > 0) {
|
||||
console.log(
|
||||
`🔄 RepeaterInput 데이터 감지: ${key}, ${parsedArray.length}개 항목`
|
||||
);
|
||||
|
||||
// 컴포넌트 설정에서 targetTable 추출 (컴포넌트 ID를 통해)
|
||||
// 프론트엔드에서 { data: [...], targetTable: "..." } 형식으로 전달될 수 있음
|
||||
let targetTable: string | undefined;
|
||||
let actualData = parsedArray;
|
||||
|
||||
// 첫 번째 항목에 _targetTable이 있는지 확인 (프론트엔드에서 메타데이터 전달)
|
||||
if (parsedArray[0] && parsedArray[0]._targetTable) {
|
||||
targetTable = parsedArray[0]._targetTable;
|
||||
actualData = parsedArray.map(
|
||||
({ _targetTable, ...item }) => item
|
||||
);
|
||||
}
|
||||
|
||||
repeaterData.push({
|
||||
data: actualData,
|
||||
targetTable,
|
||||
componentId: key,
|
||||
});
|
||||
delete dataToInsert[key]; // 원본 배열 데이터는 제거
|
||||
}
|
||||
parsedArray = JSON.parse(value);
|
||||
console.log(
|
||||
`🔄 JSON 문자열 Repeater 데이터 감지: ${key}, ${parsedArray?.length || 0}개 항목`
|
||||
);
|
||||
} catch (parseError) {
|
||||
console.log(`⚠️ JSON 파싱 실패: ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 파싱된 배열이 있으면 처리
|
||||
if (parsedArray && Array.isArray(parsedArray) && parsedArray.length > 0) {
|
||||
// 컴포넌트 설정에서 targetTable 추출 (컴포넌트 ID를 통해)
|
||||
// 프론트엔드에서 { data: [...], targetTable: "..." } 형식으로 전달될 수 있음
|
||||
let targetTable: string | undefined;
|
||||
let actualData = parsedArray;
|
||||
|
||||
// 첫 번째 항목에 _targetTable이 있는지 확인 (프론트엔드에서 메타데이터 전달)
|
||||
if (parsedArray[0] && parsedArray[0]._targetTable) {
|
||||
targetTable = parsedArray[0]._targetTable;
|
||||
actualData = parsedArray.map(
|
||||
({ _targetTable, ...item }) => item
|
||||
);
|
||||
}
|
||||
|
||||
repeaterData.push({
|
||||
data: actualData,
|
||||
targetTable,
|
||||
componentId: key,
|
||||
});
|
||||
delete dataToInsert[key]; // 원본 배열 데이터는 제거
|
||||
|
||||
console.log(`✅ Repeater 데이터 추가: ${key}`, {
|
||||
targetTable: targetTable || "없음 (화면 설계에서 설정 필요)",
|
||||
itemCount: actualData.length,
|
||||
firstItem: actualData[0],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 존재하지 않는 컬럼 제거
|
||||
@@ -497,8 +514,29 @@ export class DynamicFormService {
|
||||
created_by,
|
||||
updated_by,
|
||||
regdate: new Date(),
|
||||
// 🔥 멀티테넌시: company_code 필수 추가
|
||||
company_code: data.company_code || company_code,
|
||||
};
|
||||
|
||||
// 🔥 부모 테이블의 데이터를 자동 복사 (외래키 관계)
|
||||
// targetTable이 메인 테이블과 같으면 부모 데이터 추가
|
||||
if (targetTableName === tableName) {
|
||||
console.log(
|
||||
`⚠️ [Repeater] targetTable이 메인 테이블과 같음 (${tableName}). 부모 데이터 추가 중...`
|
||||
);
|
||||
// 메인 테이블의 모든 데이터를 Repeater 항목에 복사
|
||||
Object.keys(dataToInsert).forEach((key) => {
|
||||
// 중복되지 않는 필드만 추가
|
||||
if (itemData[key] === undefined) {
|
||||
itemData[key] = dataToInsert[key];
|
||||
}
|
||||
});
|
||||
console.log(
|
||||
`✅ [Repeater] 부모 데이터 병합 완료:`,
|
||||
Object.keys(itemData)
|
||||
);
|
||||
}
|
||||
|
||||
// 대상 테이블에 존재하는 컬럼만 필터링
|
||||
Object.keys(itemData).forEach((key) => {
|
||||
if (!targetColumnNames.includes(key)) {
|
||||
|
||||
Reference in New Issue
Block a user