Compare commits

...

2 Commits

3 changed files with 56 additions and 33 deletions

View File

@ -93,10 +93,15 @@ export class DynamicFormApi {
): Promise<ApiResponse<SaveFormDataResponse>> {
try {
console.log("🔄 폼 데이터 업데이트 요청:", { id, formData });
console.log("🌐 API URL:", `/dynamic-form/${id}`);
console.log("📦 요청 본문:", JSON.stringify(formData, null, 2));
const response = await apiClient.put(`/dynamic-form/${id}`, formData);
console.log("✅ 폼 데이터 업데이트 성공:", response.data);
console.log("📊 응답 상태:", response.status);
console.log("📋 응답 헤더:", response.headers);
return {
success: true,
data: response.data,
@ -104,6 +109,8 @@ export class DynamicFormApi {
};
} catch (error: any) {
console.error("❌ 폼 데이터 업데이트 실패:", error);
console.error("📊 에러 응답:", error.response?.data);
console.error("📊 에러 상태:", error.response?.status);
const errorMessage = error.response?.data?.message || error.message || "데이터 업데이트 중 오류가 발생했습니다.";

View File

@ -333,6 +333,14 @@ export function UniversalFormModalComponent({
}
}
// 🆕 테이블 섹션 데이터 병합 (품목 리스트 등)
for (const [key, value] of Object.entries(formData)) {
if (key.startsWith("_tableSection_") && Array.isArray(value)) {
event.detail.formData[key] = value;
console.log(`[UniversalFormModal] 테이블 섹션 병합: ${key}, ${value.length}개 항목`);
}
}
// 🆕 수정 모드: 원본 그룹 데이터 전달 (UPDATE/DELETE 추적용)
if (originalGroupedData.length > 0) {
event.detail.formData._originalGroupedData = originalGroupedData;
@ -355,15 +363,9 @@ export function UniversalFormModalComponent({
// 테이블 타입 섹션 찾기
const tableSection = config.sections.find((s) => s.type === "table");
if (!tableSection) {
// console.log("[UniversalFormModal] 테이블 섹션 없음 - _groupedData 무시");
return;
}
// console.log("[UniversalFormModal] 수정 모드 - 테이블 섹션 초기화:", {
// sectionId: tableSection.id,
// itemCount: _groupedData.length,
// });
// 원본 데이터 저장 (수정/삭제 추적용)
setOriginalGroupedData(JSON.parse(JSON.stringify(_groupedData)));

View File

@ -724,11 +724,16 @@ export class ButtonActionExecutor {
// originalData는 수정 버튼 클릭 시 editData로 전달되어 context.originalData로 설정됨
// 빈 객체 {}도 truthy이므로 Object.keys로 실제 데이터 유무 확인
const hasRealOriginalData = originalData && Object.keys(originalData).length > 0;
const isUpdate = hasRealOriginalData && !!primaryKeyValue;
// 🆕 폴백 로직: originalData가 없어도 formData에 id가 있으면 UPDATE로 판단
// 조건부 컨테이너 등에서 originalData 전달이 누락되는 경우를 처리
const hasIdInFormData = formData.id !== undefined && formData.id !== null && formData.id !== "";
const isUpdate = (hasRealOriginalData || hasIdInFormData) && !!primaryKeyValue;
console.log("🔍 [handleSave] INSERT/UPDATE 판단:", {
hasOriginalData: !!originalData,
hasRealOriginalData,
hasIdInFormData,
originalDataKeys: originalData ? Object.keys(originalData) : [],
primaryKeyValue,
isUpdate,
@ -741,18 +746,18 @@ export class ButtonActionExecutor {
// UPDATE 처리 - 부분 업데이트 사용 (원본 데이터가 있는 경우)
console.log("🔄 UPDATE 모드로 저장:", {
primaryKeyValue,
formData,
originalData,
hasOriginalData: !!originalData,
hasIdInFormData,
updateReason: hasRealOriginalData ? "originalData 존재" : "formData.id 존재 (폴백)",
});
if (originalData) {
if (hasRealOriginalData) {
// 부분 업데이트: 변경된 필드만 업데이트
console.log("📝 부분 업데이트 실행 (변경된 필드만)");
saveResult = await DynamicFormApi.updateFormDataPartial(primaryKeyValue, originalData, formData, tableName);
} else {
// 전체 업데이트 (기존 방식)
console.log("📝 전체 업데이트 실행 (모든 필드)");
// 전체 업데이트 (originalData 없이 id로 UPDATE 판단된 경우)
console.log("📝 전체 업데이트 실행 (originalData 없음 - 폴백 모드)");
saveResult = await DynamicFormApi.updateFormData(primaryKeyValue, {
tableName,
data: formData,
@ -1862,37 +1867,45 @@ export class ButtonActionExecutor {
const originalItem = originalGroupedData.find((orig) => orig.id === item.id);
if (!originalItem) {
console.warn(`⚠️ [UPDATE] 원본 데이터 없음 - INSERT로 처리: id=${item.id}`);
// 원본이 없으면 신규로 처리
const rowToSave = { ...commonFieldsData, ...item, ...userInfo };
Object.keys(rowToSave).forEach((key) => {
// 🆕 폴백 로직: 원본 데이터가 없어도 id가 있으면 UPDATE 시도
// originalGroupedData 전달이 누락된 경우를 처리
console.warn(`⚠️ [UPDATE] 원본 데이터 없음 - id가 있으므로 UPDATE 시도 (폴백): id=${item.id}`);
// ⚠️ 중요: commonFieldsData가 item보다 우선순위가 높아야 함
// item에 있는 기존 값(예: manager_id=123)이 commonFieldsData의 새 값(manager_id=234)을 덮어쓰지 않도록
// 순서: item(기존) → commonFieldsData(새로 입력) → userInfo(메타데이터)
const rowToUpdate = { ...item, ...commonFieldsData, ...userInfo };
Object.keys(rowToUpdate).forEach((key) => {
if (key.startsWith("_")) {
delete rowToSave[key];
delete rowToUpdate[key];
}
});
delete rowToSave.id; // id 제거하여 INSERT
// 🆕 메인 레코드 ID 연결 (별도 테이블에 저장하는 경우)
if (targetTableName && mainRecordId && saveConfig.primaryKeyColumn) {
rowToSave[saveConfig.primaryKeyColumn] = mainRecordId;
}
const saveResult = await DynamicFormApi.saveFormData({
screenId: screenId!,
console.log("📝 [UPDATE 폴백] 저장할 데이터:", {
id: item.id,
tableName: saveTableName,
data: rowToSave,
commonFieldsData,
itemFields: Object.keys(item).filter(k => !k.startsWith("_")),
rowToUpdate,
});
if (!saveResult.success) {
throw new Error(saveResult.message || "품목 저장 실패");
// id를 유지하고 UPDATE 실행
const updateResult = await DynamicFormApi.updateFormData(item.id, {
tableName: saveTableName,
data: rowToUpdate,
});
if (!updateResult.success) {
throw new Error(updateResult.message || "품목 수정 실패");
}
insertedCount++;
updatedCount++;
continue;
}
// 변경 사항 확인 (공통 필드 포함)
const currentDataWithCommon = { ...commonFieldsData, ...item };
// ⚠️ 중요: commonFieldsData가 item보다 우선순위가 높아야 함 (새로 입력한 값이 기존 값을 덮어씀)
const currentDataWithCommon = { ...item, ...commonFieldsData };
const hasChanges = this.checkForChanges(originalItem, currentDataWithCommon);
if (hasChanges) {
@ -1917,13 +1930,14 @@ export class ButtonActionExecutor {
}
// 3⃣ 삭제된 품목 DELETE (원본에는 있지만 현재에는 없는 항목)
const currentIds = new Set(currentItems.map((item) => item.id).filter(Boolean));
const deletedItems = originalGroupedData.filter((orig) => orig.id && !currentIds.has(orig.id));
// ⚠️ id 타입 통일: 문자열로 변환하여 비교 (숫자 vs 문자열 불일치 방지)
const currentIds = new Set(currentItems.map((item) => String(item.id)).filter(Boolean));
const deletedItems = originalGroupedData.filter((orig) => orig.id && !currentIds.has(String(orig.id)));
for (const deletedItem of deletedItems) {
console.log(`🗑️ [DELETE] 품목 삭제: id=${deletedItem.id}, tableName=${saveTableName}`);
const deleteResult = await DynamicFormApi.deleteFormDataFromTable(saveTableName, deletedItem.id);
const deleteResult = await DynamicFormApi.deleteFormDataFromTable(deletedItem.id, saveTableName);
if (!deleteResult.success) {
throw new Error(deleteResult.message || "품목 삭제 실패");