Compare commits

...

2 Commits

2 changed files with 284 additions and 107 deletions

View File

@ -963,6 +963,13 @@ export function UniversalFormModalComponent({
} }
} }
// 별도 테이블에 저장해야 하는 테이블 섹션 목록
const tableSectionsForSeparateTable = config.sections.filter(
(s) => s.type === "table" &&
s.tableConfig?.saveConfig?.targetTable &&
s.tableConfig.saveConfig.targetTable !== config.saveConfig.tableName
);
// 테이블 섹션이 있고 메인 테이블에 품목별로 저장하는 경우 (공통 + 개별 병합 저장) // 테이블 섹션이 있고 메인 테이블에 품목별로 저장하는 경우 (공통 + 개별 병합 저장)
// targetTable이 없거나 메인 테이블과 같은 경우 // targetTable이 없거나 메인 테이블과 같은 경우
const tableSectionsForMainTable = config.sections.filter( const tableSectionsForMainTable = config.sections.filter(
@ -971,6 +978,12 @@ export function UniversalFormModalComponent({
s.tableConfig.saveConfig.targetTable === config.saveConfig.tableName) s.tableConfig.saveConfig.targetTable === config.saveConfig.tableName)
); );
console.log("[saveSingleRow] 메인 테이블:", config.saveConfig.tableName);
console.log("[saveSingleRow] 메인 테이블에 저장할 테이블 섹션:", tableSectionsForMainTable.map(s => s.id));
console.log("[saveSingleRow] 별도 테이블에 저장할 테이블 섹션:", tableSectionsForSeparateTable.map(s => s.id));
console.log("[saveSingleRow] 테이블 섹션 데이터 키:", Object.keys(tableSectionData));
console.log("[saveSingleRow] dataToSave 키:", Object.keys(dataToSave));
if (tableSectionsForMainTable.length > 0) { if (tableSectionsForMainTable.length > 0) {
// 공통 저장 필드 수집 (sectionSaveModes 설정에 따라) // 공통 저장 필드 수집 (sectionSaveModes 설정에 따라)
const commonFieldsData: Record<string, any> = {}; const commonFieldsData: Record<string, any> = {};
@ -1050,35 +1063,51 @@ export function UniversalFormModalComponent({
// 메인 레코드 ID가 필요한 경우 (response.data에서 가져오기) // 메인 레코드 ID가 필요한 경우 (response.data에서 가져오기)
const mainRecordId = response.data?.data?.id; const mainRecordId = response.data?.data?.id;
// 공통 저장 필드 수집 (sectionSaveModes 설정에 따라) // 공통 저장 필드 수집: 다른 섹션(필드 타입)에서 공통 저장으로 설정된 필드 값
// 기본값: 필드 타입 섹션은 'common', 테이블 타입 섹션은 'individual'
const commonFieldsData: Record<string, any> = {}; const commonFieldsData: Record<string, any> = {};
const { sectionSaveModes } = config.saveConfig; const { sectionSaveModes } = config.saveConfig;
if (sectionSaveModes && sectionSaveModes.length > 0) { // 다른 섹션에서 공통 저장으로 설정된 필드 값 수집
// 다른 섹션에서 공통 저장으로 설정된 필드 값 수집 for (const otherSection of config.sections) {
for (const otherSection of config.sections) { if (otherSection.id === section.id) continue; // 현재 테이블 섹션은 건너뛰기
if (otherSection.id === section.id) continue; // 현재 테이블 섹션은 건너뛰기
const sectionMode = sectionSaveModes.find((s) => s.sectionId === otherSection.id); const sectionMode = sectionSaveModes?.find((s) => s.sectionId === otherSection.id);
const defaultMode = otherSection.type === "table" ? "individual" : "common"; // 기본값: 필드 타입 섹션은 'common', 테이블 타입 섹션은 'individual'
const sectionSaveMode = sectionMode?.saveMode || defaultMode; const defaultMode = otherSection.type === "table" ? "individual" : "common";
const sectionSaveMode = sectionMode?.saveMode || defaultMode;
// 필드 타입 섹션의 필드들 처리 // 필드 타입 섹션의 필드들 처리
if (otherSection.type !== "table" && otherSection.fields) { if (otherSection.type !== "table" && otherSection.fields) {
for (const field of otherSection.fields) { for (const field of otherSection.fields) {
// 필드별 오버라이드 확인 // 필드별 오버라이드 확인
const fieldOverride = sectionMode?.fieldOverrides?.find((f) => f.fieldName === field.columnName); const fieldOverride = sectionMode?.fieldOverrides?.find((f) => f.fieldName === field.columnName);
const fieldSaveMode = fieldOverride?.saveMode || sectionSaveMode; const fieldSaveMode = fieldOverride?.saveMode || sectionSaveMode;
// 공통 저장이면 formData에서 값을 가져와 모든 품목에 적용 // 공통 저장이면 formData에서 값을 가져와 모든 품목에 적용
if (fieldSaveMode === "common" && formData[field.columnName] !== undefined) { if (fieldSaveMode === "common" && formData[field.columnName] !== undefined) {
commonFieldsData[field.columnName] = formData[field.columnName]; commonFieldsData[field.columnName] = formData[field.columnName];
}
}
}
// 🆕 선택적 필드 그룹 (optionalFieldGroups)도 처리
if (otherSection.optionalFieldGroups && otherSection.optionalFieldGroups.length > 0) {
for (const optGroup of otherSection.optionalFieldGroups) {
if (optGroup.fields) {
for (const field of optGroup.fields) {
// 선택적 필드 그룹은 기본적으로 common 저장
if (formData[field.columnName] !== undefined) {
commonFieldsData[field.columnName] = formData[field.columnName];
}
} }
} }
} }
} }
} }
console.log("[saveSingleRow] 별도 테이블 저장 - 공통 필드:", Object.keys(commonFieldsData));
for (const item of sectionData) { for (const item of sectionData) {
// 공통 필드 병합 + 개별 품목 데이터 // 공통 필드 병합 + 개별 품목 데이터
const itemToSave = { ...commonFieldsData, ...item }; const itemToSave = { ...commonFieldsData, ...item };
@ -1091,15 +1120,26 @@ export function UniversalFormModalComponent({
} }
} }
// _sourceData 등 내부 메타데이터 제거
Object.keys(itemToSave).forEach((key) => {
if (key.startsWith("_")) {
delete itemToSave[key];
}
});
// 메인 레코드와 연결이 필요한 경우 // 메인 레코드와 연결이 필요한 경우
if (mainRecordId && config.saveConfig.primaryKeyColumn) { if (mainRecordId && config.saveConfig.primaryKeyColumn) {
itemToSave[config.saveConfig.primaryKeyColumn] = mainRecordId; itemToSave[config.saveConfig.primaryKeyColumn] = mainRecordId;
} }
await apiClient.post( const saveResponse = await apiClient.post(
`/table-management/tables/${section.tableConfig.saveConfig.targetTable}/add`, `/table-management/tables/${section.tableConfig.saveConfig.targetTable}/add`,
itemToSave itemToSave
); );
if (!saveResponse.data?.success) {
throw new Error(saveResponse.data?.message || `${section.title || "테이블 섹션"} 저장 실패`);
}
} }
} }
} }

View File

@ -1491,6 +1491,7 @@ export class ButtonActionExecutor {
* 🆕 Universal Form Modal * 🆕 Universal Form Modal
* _폼_모달 + _tableSection_ * _폼_모달 + _tableSection_
* 모드: INSERT/UPDATE/DELETE * 모드: INSERT/UPDATE/DELETE
* 🆕 (targetTable)
*/ */
private static async handleUniversalFormModalTableSectionSave( private static async handleUniversalFormModalTableSectionSave(
config: ButtonActionConfig, config: ButtonActionConfig,
@ -1515,6 +1516,65 @@ export class ButtonActionExecutor {
const modalData = formData[universalFormModalKey]; const modalData = formData[universalFormModalKey];
// 🆕 universal-form-modal 컴포넌트 설정 가져오기
// 1. componentConfigs에서 컴포넌트 ID로 찾기
// 2. allComponents에서 columnName으로 찾기
// 3. 화면 레이아웃 API에서 가져오기
let modalComponentConfig = context.componentConfigs?.[universalFormModalKey];
// componentConfigs에서 직접 찾지 못한 경우, allComponents에서 columnName으로 찾기
if (!modalComponentConfig && context.allComponents) {
const modalComponent = context.allComponents.find(
(comp: any) =>
comp.columnName === universalFormModalKey || comp.properties?.columnName === universalFormModalKey,
);
if (modalComponent) {
modalComponentConfig = modalComponent.componentConfig || modalComponent.properties?.componentConfig;
console.log("🎯 [handleUniversalFormModalTableSectionSave] allComponents에서 설정 찾음:", modalComponent.id);
}
}
// 🆕 아직도 설정을 찾지 못했으면 화면 레이아웃 API에서 가져오기
if (!modalComponentConfig && screenId) {
try {
console.log("🔍 [handleUniversalFormModalTableSectionSave] 화면 레이아웃 API에서 설정 조회:", screenId);
const { screenApi } = await import("@/lib/api/screen");
const layoutData = await screenApi.getLayout(screenId);
if (layoutData && layoutData.components) {
// 레이아웃에서 universal-form-modal 컴포넌트 찾기
const modalLayout = (layoutData.components as any[]).find(
(comp) =>
comp.properties?.columnName === universalFormModalKey || comp.columnName === universalFormModalKey,
);
if (modalLayout) {
modalComponentConfig = modalLayout.properties?.componentConfig || modalLayout.componentConfig;
console.log(
"🎯 [handleUniversalFormModalTableSectionSave] 화면 레이아웃에서 설정 찾음:",
modalLayout.componentId,
);
}
}
} catch (error) {
console.warn("⚠️ [handleUniversalFormModalTableSectionSave] 화면 레이아웃 조회 실패:", error);
}
}
const sections: any[] = modalComponentConfig?.sections || [];
const saveConfig = modalComponentConfig?.saveConfig || {};
console.log("🎯 [handleUniversalFormModalTableSectionSave] 컴포넌트 설정:", {
hasComponentConfig: !!modalComponentConfig,
sectionsCount: sections.length,
mainTableName: saveConfig.tableName || tableName,
sectionSaveModes: saveConfig.sectionSaveModes,
sectionDetails: sections.map((s: any) => ({
id: s.id,
type: s.type,
targetTable: s.tableConfig?.saveConfig?.targetTable,
})),
});
// _tableSection_ 데이터 추출 // _tableSection_ 데이터 추출
const tableSectionData: Record<string, any[]> = {}; const tableSectionData: Record<string, any[]> = {};
const commonFieldsData: Record<string, any> = {}; const commonFieldsData: Record<string, any> = {};
@ -1564,10 +1624,64 @@ export class ButtonActionExecutor {
let insertedCount = 0; let insertedCount = 0;
let updatedCount = 0; let updatedCount = 0;
let deletedCount = 0; let deletedCount = 0;
let mainRecordId: number | null = null;
// 🆕 먼저 메인 테이블에 공통 데이터 저장 (별도 테이블이 있는 경우에만)
const hasSeparateTargetTable = sections.some(
(s) =>
s.type === "table" &&
s.tableConfig?.saveConfig?.targetTable &&
s.tableConfig.saveConfig.targetTable !== tableName,
);
if (hasSeparateTargetTable && Object.keys(commonFieldsData).length > 0) {
console.log("📦 [handleUniversalFormModalTableSectionSave] 메인 테이블에 공통 데이터 저장:", tableName);
const mainRowToSave = { ...commonFieldsData, ...userInfo };
// 메타데이터 제거
Object.keys(mainRowToSave).forEach((key) => {
if (key.startsWith("_")) {
delete mainRowToSave[key];
}
});
console.log("📦 [handleUniversalFormModalTableSectionSave] 메인 테이블 저장 데이터:", mainRowToSave);
const mainSaveResult = await DynamicFormApi.saveFormData({
screenId: screenId!,
tableName: tableName!,
data: mainRowToSave,
});
if (!mainSaveResult.success) {
throw new Error(mainSaveResult.message || "메인 데이터 저장 실패");
}
mainRecordId = mainSaveResult.data?.id || null;
console.log("✅ [handleUniversalFormModalTableSectionSave] 메인 테이블 저장 완료, ID:", mainRecordId);
}
// 각 테이블 섹션 처리 // 각 테이블 섹션 처리
for (const [sectionId, currentItems] of Object.entries(tableSectionData)) { for (const [sectionId, currentItems] of Object.entries(tableSectionData)) {
console.log(`🔄 [handleUniversalFormModalTableSectionSave] 섹션 ${sectionId} 처리 시작: ${currentItems.length}개 품목`); console.log(
`🔄 [handleUniversalFormModalTableSectionSave] 섹션 ${sectionId} 처리 시작: ${currentItems.length}개 품목`,
);
// 🆕 해당 섹션의 설정 찾기
const sectionConfig = sections.find((s) => s.id === sectionId);
const targetTableName = sectionConfig?.tableConfig?.saveConfig?.targetTable;
// 🆕 실제 저장할 테이블 결정
// - targetTable이 있으면 해당 테이블에 저장
// - targetTable이 없으면 메인 테이블에 저장
const saveTableName = targetTableName || tableName!;
console.log(`📊 [handleUniversalFormModalTableSectionSave] 섹션 ${sectionId} 저장 테이블:`, {
targetTableName,
saveTableName,
isMainTable: saveTableName === tableName,
});
// 1⃣ 신규 품목 INSERT (id가 없는 항목) // 1⃣ 신규 품목 INSERT (id가 없는 항목)
const newItems = currentItems.filter((item) => !item.id); const newItems = currentItems.filter((item) => !item.id);
@ -1581,11 +1695,16 @@ export class ButtonActionExecutor {
} }
}); });
console.log(" [INSERT] 신규 품목:", rowToSave); // 🆕 메인 레코드 ID 연결 (별도 테이블에 저장하는 경우)
if (targetTableName && mainRecordId && saveConfig.primaryKeyColumn) {
rowToSave[saveConfig.primaryKeyColumn] = mainRecordId;
}
console.log(" [INSERT] 신규 품목:", { tableName: saveTableName, data: rowToSave });
const saveResult = await DynamicFormApi.saveFormData({ const saveResult = await DynamicFormApi.saveFormData({
screenId: screenId!, screenId: screenId!,
tableName: tableName!, tableName: saveTableName,
data: rowToSave, data: rowToSave,
}); });
@ -1612,9 +1731,14 @@ export class ButtonActionExecutor {
}); });
delete rowToSave.id; // id 제거하여 INSERT delete rowToSave.id; // id 제거하여 INSERT
// 🆕 메인 레코드 ID 연결 (별도 테이블에 저장하는 경우)
if (targetTableName && mainRecordId && saveConfig.primaryKeyColumn) {
rowToSave[saveConfig.primaryKeyColumn] = mainRecordId;
}
const saveResult = await DynamicFormApi.saveFormData({ const saveResult = await DynamicFormApi.saveFormData({
screenId: screenId!, screenId: screenId!,
tableName: tableName!, tableName: saveTableName,
data: rowToSave, data: rowToSave,
}); });
@ -1631,14 +1755,14 @@ export class ButtonActionExecutor {
const hasChanges = this.checkForChanges(originalItem, currentDataWithCommon); const hasChanges = this.checkForChanges(originalItem, currentDataWithCommon);
if (hasChanges) { if (hasChanges) {
console.log(`🔄 [UPDATE] 품목 수정: id=${item.id}`); console.log(`🔄 [UPDATE] 품목 수정: id=${item.id}, tableName=${saveTableName}`);
// 변경된 필드만 추출하여 부분 업데이트 // 변경된 필드만 추출하여 부분 업데이트
const updateResult = await DynamicFormApi.updateFormDataPartial( const updateResult = await DynamicFormApi.updateFormDataPartial(
item.id, item.id,
originalItem, originalItem,
currentDataWithCommon, currentDataWithCommon,
tableName!, saveTableName,
); );
if (!updateResult.success) { if (!updateResult.success) {
@ -1656,9 +1780,9 @@ export class ButtonActionExecutor {
const deletedItems = originalGroupedData.filter((orig) => orig.id && !currentIds.has(orig.id)); const deletedItems = originalGroupedData.filter((orig) => orig.id && !currentIds.has(orig.id));
for (const deletedItem of deletedItems) { for (const deletedItem of deletedItems) {
console.log(`🗑️ [DELETE] 품목 삭제: id=${deletedItem.id}`); console.log(`🗑️ [DELETE] 품목 삭제: id=${deletedItem.id}, tableName=${saveTableName}`);
const deleteResult = await DynamicFormApi.deleteFormDataFromTable(tableName!, deletedItem.id); const deleteResult = await DynamicFormApi.deleteFormDataFromTable(saveTableName, deletedItem.id);
if (!deleteResult.success) { if (!deleteResult.success) {
throw new Error(deleteResult.message || "품목 삭제 실패"); throw new Error(deleteResult.message || "품목 삭제 실패");
@ -1670,6 +1794,7 @@ export class ButtonActionExecutor {
// 결과 메시지 생성 // 결과 메시지 생성
const resultParts: string[] = []; const resultParts: string[] = [];
if (mainRecordId) resultParts.push("메인 데이터 저장");
if (insertedCount > 0) resultParts.push(`${insertedCount}개 추가`); if (insertedCount > 0) resultParts.push(`${insertedCount}개 추가`);
if (updatedCount > 0) resultParts.push(`${updatedCount}개 수정`); if (updatedCount > 0) resultParts.push(`${updatedCount}개 수정`);
if (deletedCount > 0) resultParts.push(`${deletedCount}개 삭제`); if (deletedCount > 0) resultParts.push(`${deletedCount}개 삭제`);
@ -2145,7 +2270,10 @@ export class ButtonActionExecutor {
* *
* RelatedDataButtons * RelatedDataButtons
*/ */
private static async handleOpenRelatedModal(config: ButtonActionConfig, context: ButtonActionContext): Promise<boolean> { private static async handleOpenRelatedModal(
config: ButtonActionConfig,
context: ButtonActionContext,
): Promise<boolean> {
// 버튼 설정에서 targetScreenId 가져오기 (여러 위치에서 확인) // 버튼 설정에서 targetScreenId 가져오기 (여러 위치에서 확인)
const targetScreenId = config.relatedModalConfig?.targetScreenId || config.targetScreenId; const targetScreenId = config.relatedModalConfig?.targetScreenId || config.targetScreenId;
@ -2188,7 +2316,7 @@ export class ButtonActionExecutor {
}); });
if (relatedConfig?.modalLink?.dataMapping && relatedConfig.modalLink.dataMapping.length > 0) { if (relatedConfig?.modalLink?.dataMapping && relatedConfig.modalLink.dataMapping.length > 0) {
relatedConfig.modalLink.dataMapping.forEach(mapping => { relatedConfig.modalLink.dataMapping.forEach((mapping) => {
console.log("🔍 [openRelatedModal] 매핑 처리:", { console.log("🔍 [openRelatedModal] 매핑 처리:", {
mapping, mapping,
sourceField: mapping.sourceField, sourceField: mapping.sourceField,
@ -2219,18 +2347,20 @@ export class ButtonActionExecutor {
}); });
// 모달 열기 이벤트 발생 (ScreenModal은 editData를 사용) // 모달 열기 이벤트 발생 (ScreenModal은 editData를 사용)
window.dispatchEvent(new CustomEvent("openScreenModal", { window.dispatchEvent(
detail: { new CustomEvent("openScreenModal", {
screenId: targetScreenId, detail: {
title: config.modalTitle, screenId: targetScreenId,
description: config.modalDescription, title: config.modalTitle,
editData: initialData, // ScreenModal은 editData로 폼 데이터를 받음 description: config.modalDescription,
onSuccess: () => { editData: initialData, // ScreenModal은 editData로 폼 데이터를 받음
// 성공 후 데이터 새로고침 onSuccess: () => {
window.dispatchEvent(new CustomEvent("refreshTableData")); // 성공 후 데이터 새로고침
window.dispatchEvent(new CustomEvent("refreshTableData"));
},
}, },
}, }),
})); );
return true; return true;
} }
@ -3296,10 +3426,7 @@ export class ButtonActionExecutor {
* EditModal public으로 * EditModal public으로
* *
*/ */
public static async executeAfterSaveControl( public static async executeAfterSaveControl(config: ButtonActionConfig, context: ButtonActionContext): Promise<void> {
config: ButtonActionConfig,
context: ButtonActionContext,
): Promise<void> {
console.log("🎯 저장 후 제어 실행:", { console.log("🎯 저장 후 제어 실행:", {
enableDataflowControl: config.enableDataflowControl, enableDataflowControl: config.enableDataflowControl,
dataflowConfig: config.dataflowConfig, dataflowConfig: config.dataflowConfig,
@ -4763,19 +4890,20 @@ export class ButtonActionExecutor {
if (userId) { if (userId) {
try { try {
const { apiClient } = await import("@/lib/api/client"); const { apiClient } = await import("@/lib/api/client");
const statusTableName = config.trackingStatusTableName || this.trackingConfig?.trackingStatusTableName || context.tableName || "vehicles"; const statusTableName =
config.trackingStatusTableName ||
this.trackingConfig?.trackingStatusTableName ||
context.tableName ||
"vehicles";
const keyField = config.trackingStatusKeyField || this.trackingConfig?.trackingStatusKeyField || "user_id"; const keyField = config.trackingStatusKeyField || this.trackingConfig?.trackingStatusKeyField || "user_id";
// DB에서 현재 차량 정보 조회 // DB에서 현재 차량 정보 조회
const vehicleResponse = await apiClient.post( const vehicleResponse = await apiClient.post(`/table-management/tables/${statusTableName}/data`, {
`/table-management/tables/${statusTableName}/data`, page: 1,
{ size: 1,
page: 1, search: { [keyField]: userId },
size: 1, autoFilter: true,
search: { [keyField]: userId }, });
autoFilter: true,
},
);
const vehicleData = vehicleResponse.data?.data?.data?.[0] || vehicleResponse.data?.data?.rows?.[0]; const vehicleData = vehicleResponse.data?.data?.data?.[0] || vehicleResponse.data?.data?.rows?.[0];
if (vehicleData) { if (vehicleData) {
@ -4792,14 +4920,18 @@ export class ButtonActionExecutor {
// 마지막 위치 저장 (추적 중이었던 경우에만) // 마지막 위치 저장 (추적 중이었던 경우에만)
if (isTrackingActive) { if (isTrackingActive) {
// DB 값 우선, 없으면 formData 사용 // DB 값 우선, 없으면 formData 사용
const departure = dbDeparture || const departure =
this.trackingContext?.formData?.[this.trackingConfig?.trackingDepartureField || "departure"] || null; dbDeparture ||
const arrival = dbArrival || this.trackingContext?.formData?.[this.trackingConfig?.trackingDepartureField || "departure"] ||
this.trackingContext?.formData?.[this.trackingConfig?.trackingArrivalField || "arrival"] || null; null;
const arrival =
dbArrival || this.trackingContext?.formData?.[this.trackingConfig?.trackingArrivalField || "arrival"] || null;
const departureName = this.trackingContext?.formData?.["departure_name"] || null; const departureName = this.trackingContext?.formData?.["departure_name"] || null;
const destinationName = this.trackingContext?.formData?.["destination_name"] || null; const destinationName = this.trackingContext?.formData?.["destination_name"] || null;
const vehicleId = dbVehicleId || const vehicleId =
this.trackingContext?.formData?.[this.trackingConfig?.trackingVehicleIdField || "vehicle_id"] || null; dbVehicleId ||
this.trackingContext?.formData?.[this.trackingConfig?.trackingVehicleIdField || "vehicle_id"] ||
null;
await this.saveLocationToHistory( await this.saveLocationToHistory(
tripId, tripId,
@ -5681,10 +5813,10 @@ export class ButtonActionExecutor {
const columnMappings = quickInsertConfig.columnMappings || []; const columnMappings = quickInsertConfig.columnMappings || [];
for (const mapping of columnMappings) { for (const mapping of columnMappings) {
console.log(`📍 매핑 처리 시작:`, mapping); console.log("📍 매핑 처리 시작:", mapping);
if (!mapping.targetColumn) { if (!mapping.targetColumn) {
console.log(`📍 targetColumn 없음, 스킵`); console.log("📍 targetColumn 없음, 스킵");
continue; continue;
} }
@ -5692,7 +5824,7 @@ export class ButtonActionExecutor {
switch (mapping.sourceType) { switch (mapping.sourceType) {
case "component": case "component":
console.log(`📍 component 타입 처리:`, { console.log("📍 component 타입 처리:", {
sourceComponentId: mapping.sourceComponentId, sourceComponentId: mapping.sourceComponentId,
sourceColumnName: mapping.sourceColumnName, sourceColumnName: mapping.sourceColumnName,
targetColumn: mapping.targetColumn, targetColumn: mapping.targetColumn,
@ -5715,7 +5847,7 @@ export class ButtonActionExecutor {
// 3. 없으면 allComponents에서 컴포넌트를 찾아 columnName으로 시도 // 3. 없으면 allComponents에서 컴포넌트를 찾아 columnName으로 시도
if (value === undefined && context.allComponents) { if (value === undefined && context.allComponents) {
const comp = context.allComponents.find((c: any) => c.id === mapping.sourceComponentId); const comp = context.allComponents.find((c: any) => c.id === mapping.sourceComponentId);
console.log(`📍 방법3 찾은 컴포넌트:`, comp); console.log("📍 방법3 찾은 컴포넌트:", comp);
if (comp?.columnName) { if (comp?.columnName) {
value = formData?.[comp.columnName]; value = formData?.[comp.columnName];
console.log(`📍 방법3 (allComponents): ${mapping.sourceComponentId}${comp.columnName} = ${value}`); console.log(`📍 방법3 (allComponents): ${mapping.sourceComponentId}${comp.columnName} = ${value}`);
@ -5742,7 +5874,7 @@ export class ButtonActionExecutor {
break; break;
case "leftPanel": case "leftPanel":
console.log(`📍 leftPanel 타입 처리:`, { console.log("📍 leftPanel 타입 처리:", {
sourceColumn: mapping.sourceColumn, sourceColumn: mapping.sourceColumn,
selectedLeftData: splitPanelContext?.selectedLeftData, selectedLeftData: splitPanelContext?.selectedLeftData,
}); });
@ -5786,7 +5918,7 @@ export class ButtonActionExecutor {
insertData[mapping.targetColumn] = value; insertData[mapping.targetColumn] = value;
console.log(`📍 insertData에 추가됨: ${mapping.targetColumn} = ${value}`); console.log(`📍 insertData에 추가됨: ${mapping.targetColumn} = ${value}`);
} else { } else {
console.log(`📍 값이 비어있어서 insertData에 추가 안됨`); console.log("📍 값이 비어있어서 insertData에 추가 안됨");
} }
} }
@ -5799,7 +5931,7 @@ export class ButtonActionExecutor {
let targetTableColumns: string[] = []; let targetTableColumns: string[] = [];
try { try {
const columnsResponse = await apiClient.get( const columnsResponse = await apiClient.get(
`/table-management/tables/${quickInsertConfig.targetTable}/columns` `/table-management/tables/${quickInsertConfig.targetTable}/columns`,
); );
if (columnsResponse.data?.success && columnsResponse.data?.data) { if (columnsResponse.data?.success && columnsResponse.data?.data) {
const columnsData = columnsResponse.data.data.columns || columnsResponse.data.data; const columnsData = columnsResponse.data.data.columns || columnsResponse.data.data;
@ -5824,20 +5956,20 @@ export class ButtonActionExecutor {
} }
// 시스템 컬럼 제외 (id, created_date, updated_date, writer 등) // 시스템 컬럼 제외 (id, created_date, updated_date, writer 등)
const systemColumns = ['id', 'created_date', 'updated_date', 'writer', 'writer_name']; const systemColumns = ["id", "created_date", "updated_date", "writer", "writer_name"];
if (systemColumns.includes(key)) { if (systemColumns.includes(key)) {
console.log(`📍 자동 매핑 스킵 (시스템 컬럼): ${key}`); console.log(`📍 자동 매핑 스킵 (시스템 컬럼): ${key}`);
continue; continue;
} }
// _label, _name 으로 끝나는 표시용 컬럼 제외 // _label, _name 으로 끝나는 표시용 컬럼 제외
if (key.endsWith('_label') || key.endsWith('_name')) { if (key.endsWith("_label") || key.endsWith("_name")) {
console.log(`📍 자동 매핑 스킵 (표시용 컬럼): ${key}`); console.log(`📍 자동 매핑 스킵 (표시용 컬럼): ${key}`);
continue; continue;
} }
// 값이 있으면 자동 추가 // 값이 있으면 자동 추가
if (val !== undefined && val !== null && val !== '') { if (val !== undefined && val !== null && val !== "") {
insertData[key] = val; insertData[key] = val;
console.log(`📍 자동 매핑 추가: ${key} = ${val}`); console.log(`📍 자동 매핑 추가: ${key} = ${val}`);
} }
@ -5877,14 +6009,19 @@ export class ButtonActionExecutor {
page: 1, page: 1,
pageSize: 1, pageSize: 1,
search: duplicateCheckData, search: duplicateCheckData,
} },
); );
console.log("📍 중복 체크 응답:", checkResponse.data); console.log("📍 중복 체크 응답:", checkResponse.data);
// 응답 구조: { success: true, data: { data: [...], total: N } } 또는 { success: true, data: [...] } // 응답 구조: { success: true, data: { data: [...], total: N } } 또는 { success: true, data: [...] }
const existingData = checkResponse.data?.data?.data || checkResponse.data?.data || []; const existingData = checkResponse.data?.data?.data || checkResponse.data?.data || [];
console.log("📍 기존 데이터:", existingData, "길이:", Array.isArray(existingData) ? existingData.length : 0); console.log(
"📍 기존 데이터:",
existingData,
"길이:",
Array.isArray(existingData) ? existingData.length : 0,
);
if (Array.isArray(existingData) && existingData.length > 0) { if (Array.isArray(existingData) && existingData.length > 0) {
toast.error(quickInsertConfig.duplicateCheck.errorMessage || "이미 존재하는 데이터입니다."); toast.error(quickInsertConfig.duplicateCheck.errorMessage || "이미 존재하는 데이터입니다.");
@ -5902,7 +6039,7 @@ export class ButtonActionExecutor {
// 데이터 저장 // 데이터 저장
const response = await apiClient.post( const response = await apiClient.post(
`/table-management/tables/${quickInsertConfig.targetTable}/add`, `/table-management/tables/${quickInsertConfig.targetTable}/add`,
insertData insertData,
); );
if (response.data?.success) { if (response.data?.success) {