fix: update file handling and improve query logging
- Added mes-architecture-guide.md to .gitignore to prevent unnecessary tracking. - Enhanced NodeFlowExecutionService to merge context data for WHERE clause, improving query accuracy. - Updated logging to include values in SQL query logs for better debugging. - Removed redundant event dispatches in V2Repeater to streamline save operations. - Adjusted DynamicComponentRenderer to conditionally refresh keys based on component type. - Improved FileUploadComponent to clear localStorage only for modal components, preventing unintended resets in non-modal contexts. These changes aim to enhance the overall functionality and maintainability of the application, ensuring better data handling and user experience.
This commit is contained in:
@@ -542,15 +542,6 @@ export class ButtonActionExecutor {
|
||||
this.saveCallCount++;
|
||||
const callId = this.saveCallCount;
|
||||
|
||||
// 🔧 디버그: context.formData 확인 (handleSave 진입 시점)
|
||||
console.log("🔍 [handleSave] 진입 시 context.formData:", {
|
||||
keys: Object.keys(context.formData || {}),
|
||||
hasCompanyImage: "company_image" in (context.formData || {}),
|
||||
hasCompanyLogo: "company_logo" in (context.formData || {}),
|
||||
companyImageValue: context.formData?.company_image,
|
||||
companyLogoValue: context.formData?.company_logo,
|
||||
});
|
||||
|
||||
const { formData, originalData, tableName, screenId, onSave } = context;
|
||||
|
||||
// 🆕 중복 호출 방지: 같은 screenId + tableName + formData 조합으로 2초 내 재호출 시 무시
|
||||
@@ -621,6 +612,18 @@ export class ButtonActionExecutor {
|
||||
if (onSave) {
|
||||
try {
|
||||
await onSave();
|
||||
|
||||
// 모달 저장 후에도 제어관리 실행 (onSave 경로에서도 dataflow 지원)
|
||||
if (config.enableDataflowControl && config.dataflowConfig) {
|
||||
console.log("📦 [handleSave] onSave 콜백 후 제어관리 실행 시작");
|
||||
const contextWithSavedData = {
|
||||
...context,
|
||||
savedData: context.formData,
|
||||
selectedRowsData: context.selectedRowsData || [],
|
||||
};
|
||||
await this.executeAfterSaveControl(config, contextWithSavedData);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
console.error("❌ [handleSave] onSave 콜백 실행 오류:", error);
|
||||
@@ -636,13 +639,6 @@ export class ButtonActionExecutor {
|
||||
|
||||
console.log("⚠️ [handleSave] onSave 콜백 없음 - 기본 저장 로직 실행");
|
||||
|
||||
// 🔧 디버그: beforeFormSave 이벤트 후 formData 확인
|
||||
console.log("🔍 [handleSave] beforeFormSave 이벤트 후:", {
|
||||
keys: Object.keys(context.formData || {}),
|
||||
hasCompanyImage: "company_image" in (context.formData || {}),
|
||||
companyImageValue: context.formData?.company_image,
|
||||
});
|
||||
|
||||
// skipDefaultSave 플래그 확인
|
||||
if (beforeSaveEventDetail.skipDefaultSave) {
|
||||
return true;
|
||||
@@ -749,11 +745,6 @@ export class ButtonActionExecutor {
|
||||
return await this.handleBatchSave(config, context, selectedItemsKeys);
|
||||
} else {
|
||||
console.log("⚠️ [handleSave] SelectedItemsDetailInput 데이터 감지 실패 - 일반 저장 진행");
|
||||
// 🔧 디버그: formData 상세 확인
|
||||
console.log("🔍 [handleSave] formData 키 목록:", Object.keys(context.formData || {}));
|
||||
console.log("🔍 [handleSave] formData.company_image:", context.formData?.company_image);
|
||||
console.log("🔍 [handleSave] formData.company_logo:", context.formData?.company_logo);
|
||||
console.log("⚠️ [handleSave] formData 전체 내용:", context.formData);
|
||||
}
|
||||
|
||||
// 🆕 RepeaterFieldGroup JSON 문자열 파싱 및 저장 처리
|
||||
@@ -1011,6 +1002,9 @@ export class ButtonActionExecutor {
|
||||
// saveResult를 상위 스코프에서 정의 (repeaterSave 이벤트에서 사용)
|
||||
let saveResult: { success: boolean; data?: any; message?: string } | undefined;
|
||||
|
||||
// 제어 실행 데이터를 상위 스코프에서 정의 (리피터 저장 완료 후 실행 위해)
|
||||
let pendingDataflowControl: { config: ButtonActionConfig; context: ButtonActionContext } | null = null;
|
||||
|
||||
if (tableName && screenId) {
|
||||
// DB에서 실제 기본키 조회하여 INSERT/UPDATE 자동 판단
|
||||
const primaryKeyResult = await DynamicFormApi.getTablePrimaryKeys(tableName);
|
||||
@@ -1758,25 +1752,20 @@ export class ButtonActionExecutor {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 🔥 저장 성공 후 연결된 제어 실행 (dataflowTiming이 'after'인 경우)
|
||||
// 제어 실행 준비 (실제 실행은 리피터 저장 완료 후로 지연)
|
||||
console.log("🔍 [handleSave] 제어관리 설정 체크:", {
|
||||
enableDataflowControl: config.enableDataflowControl,
|
||||
hasDataflowConfig: !!config.dataflowConfig,
|
||||
flowControls: config.dataflowConfig?.flowControls?.length || 0,
|
||||
});
|
||||
if (config.enableDataflowControl && config.dataflowConfig) {
|
||||
// 테이블 섹션 데이터 파싱 (comp_로 시작하는 필드에 JSON 배열이 있는 경우)
|
||||
// 입고 화면 등에서 품목 목록이 comp_xxx 필드에 JSON 문자열로 저장됨
|
||||
// 🔧 수정: saveResult.data가 3단계로 중첩된 경우 실제 폼 데이터 추출
|
||||
// saveResult.data = API 응답 { success, data, message }
|
||||
// saveResult.data.data = 저장된 레코드 { id, screenId, tableName, data, createdAt... }
|
||||
// saveResult.data.data.data = 실제 폼 데이터 { sabun, user_name... }
|
||||
const savedRecord = saveResult?.data?.data || saveResult?.data || {};
|
||||
const actualFormData = savedRecord?.data || savedRecord;
|
||||
const formData: Record<string, any> = (
|
||||
Object.keys(actualFormData).length > 0 ? actualFormData : context.formData || {}
|
||||
) as Record<string, any>;
|
||||
console.log("📦 [executeAfterSaveControl] savedRecord 구조:", Object.keys(savedRecord));
|
||||
console.log("📦 [executeAfterSaveControl] actualFormData 추출:", Object.keys(formData));
|
||||
console.log("📦 [executeAfterSaveControl] formData.sabun:", formData.sabun);
|
||||
let parsedSectionData: any[] = [];
|
||||
|
||||
// comp_로 시작하는 필드에서 테이블 섹션 데이터 찾기
|
||||
const compFieldKey = Object.keys(formData).find(
|
||||
(key) => key.startsWith("comp_") && typeof formData[key] === "string",
|
||||
);
|
||||
@@ -1785,11 +1774,8 @@ export class ButtonActionExecutor {
|
||||
try {
|
||||
const sectionData = JSON.parse(formData[compFieldKey]);
|
||||
if (Array.isArray(sectionData) && sectionData.length > 0) {
|
||||
// 공통 필드와 섹션 데이터 병합
|
||||
parsedSectionData = sectionData.map((item: any) => {
|
||||
// 섹션 데이터에서 불필요한 내부 필드 제거
|
||||
const { _isNewItem, _targetTable, _existingRecord, ...cleanItem } = item;
|
||||
// 공통 필드(comp_ 필드 제외) + 섹션 아이템 병합
|
||||
const commonFields: Record<string, any> = {};
|
||||
Object.keys(formData).forEach((key) => {
|
||||
if (!key.startsWith("comp_") && !key.endsWith("_numberingRuleId")) {
|
||||
@@ -1804,14 +1790,14 @@ export class ButtonActionExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
// 저장된 데이터를 context에 추가하여 플로우에 전달
|
||||
const contextWithSavedData = {
|
||||
...context,
|
||||
savedData: formData,
|
||||
// 파싱된 섹션 데이터가 있으면 selectedRowsData로 전달
|
||||
selectedRowsData: parsedSectionData.length > 0 ? parsedSectionData : context.selectedRowsData,
|
||||
pendingDataflowControl = {
|
||||
config,
|
||||
context: {
|
||||
...context,
|
||||
savedData: formData,
|
||||
selectedRowsData: parsedSectionData.length > 0 ? parsedSectionData : context.selectedRowsData,
|
||||
},
|
||||
};
|
||||
await this.executeAfterSaveControl(config, contextWithSavedData);
|
||||
}
|
||||
} else {
|
||||
throw new Error("저장에 필요한 정보가 부족합니다. (테이블명 또는 화면ID 누락)");
|
||||
@@ -1935,13 +1921,26 @@ export class ButtonActionExecutor {
|
||||
await repeaterSavePromise;
|
||||
}
|
||||
|
||||
// 리피터 저장 완료 후 제어관리 실행 (디테일 레코드가 DB에 있는 상태에서 실행)
|
||||
console.log("🔍 [handleSave] 리피터 저장 완료, pendingDataflowControl:", !!pendingDataflowControl);
|
||||
if (pendingDataflowControl) {
|
||||
console.log("📦 [handleSave] 리피터 저장 완료 후 제어관리 실행 시작");
|
||||
await this.executeAfterSaveControl(
|
||||
pendingDataflowControl.config,
|
||||
pendingDataflowControl.context,
|
||||
);
|
||||
}
|
||||
|
||||
// 테이블과 플로우 새로고침 (모달 닫기 전에 실행)
|
||||
context.onRefresh?.();
|
||||
context.onFlowRefresh?.();
|
||||
|
||||
// 저장 성공 후 모달 닫기 이벤트 발생
|
||||
window.dispatchEvent(new CustomEvent("closeEditModal"));
|
||||
window.dispatchEvent(new CustomEvent("saveSuccessInModal"));
|
||||
// 저장 성공 후 모달 닫기 이벤트 발생 (모달 내부에서만)
|
||||
// 비모달 화면에서 이 이벤트를 발행하면 ScreenModal이 반응하여 컴포넌트 트리 재마운트 발생
|
||||
if (context.onClose) {
|
||||
window.dispatchEvent(new CustomEvent("closeEditModal"));
|
||||
window.dispatchEvent(new CustomEvent("saveSuccessInModal"));
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
|
||||
Reference in New Issue
Block a user