feat(UniversalFormModal): 섹션별 저장 방식 설정 기능 추가

SectionSaveMode 타입 추가 (공통 저장/개별 저장)
SaveSettingsModal에 섹션별/필드별 저장 방식 설정 UI 추가
saveSingleRow()에 공통 필드 + 품목 병합 저장 로직 구현
buttonActions.ts에 외부 저장 버튼용 병합 저장 처리 추가
This commit is contained in:
SeongHyun Kim
2025-12-19 14:53:16 +09:00
parent 9684a83f37
commit 9fb94da493
4 changed files with 485 additions and 5 deletions

View File

@@ -675,6 +675,14 @@ export class ButtonActionExecutor {
console.log("⚠️ [handleSave] formData 전체 내용:", context.formData);
}
// 🆕 Universal Form Modal 테이블 섹션 병합 저장 처리
// 범용_폼_모달 내부에 _tableSection_ 데이터가 있는 경우 공통 필드 + 개별 품목 병합 저장
const universalFormModalResult = await this.handleUniversalFormModalTableSectionSave(config, context, formData);
if (universalFormModalResult.handled) {
console.log("✅ [handleSave] Universal Form Modal 테이블 섹션 저장 완료");
return universalFormModalResult.success;
}
// 폼 유효성 검사
if (config.validateForm) {
const validation = this.validateFormData(formData);
@@ -1479,6 +1487,122 @@ export class ButtonActionExecutor {
}
}
/**
* 🆕 Universal Form Modal 테이블 섹션 병합 저장 처리
* 범용_폼_모달 내부의 공통 필드 + _tableSection_ 데이터를 병합하여 품목별로 저장
*/
private static async handleUniversalFormModalTableSectionSave(
config: ButtonActionConfig,
context: ButtonActionContext,
formData: Record<string, any>,
): Promise<{ handled: boolean; success: boolean }> {
const { tableName, screenId } = context;
// 범용_폼_모달 키 찾기 (컬럼명에 따라 다를 수 있음)
const universalFormModalKey = Object.keys(formData).find((key) => {
const value = formData[key];
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
// _tableSection_ 키가 있는지 확인
return Object.keys(value).some((k) => k.startsWith("_tableSection_"));
});
if (!universalFormModalKey) {
return { handled: false, success: false };
}
console.log("🎯 [handleUniversalFormModalTableSectionSave] Universal Form Modal 감지:", universalFormModalKey);
const modalData = formData[universalFormModalKey];
// _tableSection_ 데이터 추출
const tableSectionData: Record<string, any[]> = {};
const commonFieldsData: Record<string, any> = {};
for (const [key, value] of Object.entries(modalData)) {
if (key.startsWith("_tableSection_")) {
const sectionId = key.replace("_tableSection_", "");
tableSectionData[sectionId] = value as any[];
} else if (!key.startsWith("_")) {
// _로 시작하지 않는 필드는 공통 필드로 처리
commonFieldsData[key] = value;
}
}
console.log("🎯 [handleUniversalFormModalTableSectionSave] 데이터 분리:", {
commonFields: Object.keys(commonFieldsData),
tableSections: Object.keys(tableSectionData),
tableSectionCounts: Object.entries(tableSectionData).map(([k, v]) => ({ [k]: v.length })),
});
// 테이블 섹션 데이터가 없으면 처리하지 않음
const hasTableSectionData = Object.values(tableSectionData).some((arr) => arr.length > 0);
if (!hasTableSectionData) {
console.log("⚠️ [handleUniversalFormModalTableSectionSave] 테이블 섹션 데이터 없음 - 일반 저장으로 전환");
return { handled: false, success: false };
}
try {
// 사용자 정보 추가
if (!context.userId) {
throw new Error("사용자 정보를 불러올 수 없습니다. 다시 로그인해주세요.");
}
const userInfo = {
writer: context.userId,
created_by: context.userId,
updated_by: context.userId,
company_code: context.companyCode || "",
};
let totalSaved = 0;
// 각 테이블 섹션의 품목별로 저장
for (const [sectionId, items] of Object.entries(tableSectionData)) {
console.log(`🔄 [handleUniversalFormModalTableSectionSave] 섹션 ${sectionId} 저장 시작: ${items.length}개 품목`);
for (const item of items) {
// 공통 필드 + 품목 데이터 병합
const rowToSave = { ...commonFieldsData, ...item, ...userInfo };
// 내부 메타데이터 제거
Object.keys(rowToSave).forEach((key) => {
if (key.startsWith("_")) {
delete rowToSave[key];
}
});
console.log("📝 [handleUniversalFormModalTableSectionSave] 저장할 행:", rowToSave);
// INSERT 실행
const saveResult = await DynamicFormApi.saveFormData({
screenId: screenId!,
tableName: tableName!,
data: rowToSave,
});
if (!saveResult.success) {
throw new Error(saveResult.message || "품목 저장 실패");
}
totalSaved++;
}
}
console.log(`✅ [handleUniversalFormModalTableSectionSave] 총 ${totalSaved}개 행 저장 완료`);
toast.success(`${totalSaved}개 항목이 저장되었습니다.`);
// 저장 성공 이벤트 발생
window.dispatchEvent(new CustomEvent("saveSuccess"));
window.dispatchEvent(new CustomEvent("refreshTable"));
return { handled: true, success: true };
} catch (error: any) {
console.error("❌ [handleUniversalFormModalTableSectionSave] 저장 오류:", error);
toast.error(error.message || "저장 중 오류가 발생했습니다.");
return { handled: true, success: false };
}
}
/**
* 🆕 배치 저장 액션 처리 (SelectedItemsDetailInput용 - 새로운 데이터 구조)
* ItemData[] → 각 품목의 details 배열을 개별 레코드로 저장