테이블 리스트 오류수정

This commit is contained in:
kjs 2025-10-01 17:18:48 +09:00
parent 767c031629
commit b84f35d514
1 changed files with 50 additions and 45 deletions

View File

@ -250,13 +250,13 @@ export class ImprovedButtonActionExecutor {
throw new Error(`관계 정보를 찾을 수 없습니다: ${config.relationshipId}`); throw new Error(`관계 정보를 찾을 수 없습니다: ${config.relationshipId}`);
} }
console.log(`📋 관계 데이터 로드 완료:`, relationshipData); console.log("📋 관계 데이터 로드 완료:", relationshipData);
// 2. 관계 타입에 따른 실행 // 2. 관계 타입에 따른 실행
const relationships = relationshipData.relationships; const relationships = relationshipData.relationships;
const connectionType = relationships.connectionType; const connectionType = relationships.connectionType;
console.log(`🔍 관계 상세 정보:`, { console.log("🔍 관계 상세 정보:", {
connectionType, connectionType,
hasExternalCallConfig: !!relationships.externalCallConfig, hasExternalCallConfig: !!relationships.externalCallConfig,
externalCallConfig: relationships.externalCallConfig, externalCallConfig: relationships.externalCallConfig,
@ -308,7 +308,7 @@ export class ImprovedButtonActionExecutor {
const response = await apiClient.get(`/dataflow-diagrams/${relationshipId}`); const response = await apiClient.get(`/dataflow-diagrams/${relationshipId}`);
console.log(`✅ 관계 데이터 조회 성공:`, response.data); console.log("✅ 관계 데이터 조회 성공:", response.data);
if (!response.data.success) { if (!response.data.success) {
throw new Error(response.data.message || "관계 데이터 조회 실패"); throw new Error(response.data.message || "관계 데이터 조회 실패");
@ -330,10 +330,10 @@ export class ImprovedButtonActionExecutor {
context: ButtonExecutionContext, context: ButtonExecutionContext,
): Promise<ExecutionResult> { ): Promise<ExecutionResult> {
try { try {
console.log(`🔍 외부 호출 실행 시작 - relationships 구조:`, relationships); console.log("🔍 외부 호출 실행 시작 - relationships 구조:", relationships);
const externalCallConfig = relationships.externalCallConfig; const externalCallConfig = relationships.externalCallConfig;
console.log(`🔍 externalCallConfig:`, externalCallConfig); console.log("🔍 externalCallConfig:", externalCallConfig);
if (!externalCallConfig) { if (!externalCallConfig) {
console.error("❌ 외부 호출 설정이 없습니다. relationships 구조:", relationships); console.error("❌ 외부 호출 설정이 없습니다. relationships 구조:", relationships);
@ -368,7 +368,7 @@ export class ImprovedButtonActionExecutor {
} }
// 백엔드 프록시를 통한 외부 API 호출 (CORS 문제 해결) // 백엔드 프록시를 통한 외부 API 호출 (CORS 문제 해결)
console.log(`🌐 백엔드 프록시를 통한 외부 API 호출 준비:`, { console.log("🌐 백엔드 프록시를 통한 외부 API 호출 준비:", {
originalUrl: restApiSettings.apiUrl, originalUrl: restApiSettings.apiUrl,
method: restApiSettings.httpMethod || "GET", method: restApiSettings.httpMethod || "GET",
headers, headers,
@ -393,24 +393,24 @@ export class ImprovedButtonActionExecutor {
templateData: restApiSettings.httpMethod !== "GET" && requestBody ? JSON.parse(requestBody) : formData, templateData: restApiSettings.httpMethod !== "GET" && requestBody ? JSON.parse(requestBody) : formData,
}; };
console.log(`📤 백엔드로 전송할 데이터:`, requestPayload); console.log("📤 백엔드로 전송할 데이터:", requestPayload);
const proxyResponse = await apiClient.post(`/external-calls/execute`, requestPayload); const proxyResponse = await apiClient.post("/external-calls/execute", requestPayload);
console.log(`📡 백엔드 프록시 응답:`, proxyResponse.data); console.log("📡 백엔드 프록시 응답:", proxyResponse.data);
if (!proxyResponse.data.success) { if (!proxyResponse.data.success) {
throw new Error(`프록시 API 호출 실패: ${proxyResponse.data.error || proxyResponse.data.message}`); throw new Error(`프록시 API 호출 실패: ${proxyResponse.data.error || proxyResponse.data.message}`);
} }
const responseData = proxyResponse.data.result; const responseData = proxyResponse.data.result;
console.log(`✅ 외부 API 호출 성공 (프록시):`, responseData); console.log("✅ 외부 API 호출 성공 (프록시):", responseData);
// 데이터 매핑 처리 (inbound mapping) // 데이터 매핑 처리 (inbound mapping)
if (externalCallConfig.dataMappingConfig?.inboundMapping) { if (externalCallConfig.dataMappingConfig?.inboundMapping) {
console.log(`📥 데이터 매핑 설정 발견 - HTTP 메서드: ${restApiSettings.httpMethod}`); console.log(`📥 데이터 매핑 설정 발견 - HTTP 메서드: ${restApiSettings.httpMethod}`);
console.log(`📥 매핑 설정:`, externalCallConfig.dataMappingConfig.inboundMapping); console.log("📥 매핑 설정:", externalCallConfig.dataMappingConfig.inboundMapping);
console.log(`📥 응답 데이터:`, responseData); console.log("📥 응답 데이터:", responseData);
await this.processInboundMapping(externalCallConfig.dataMappingConfig.inboundMapping, responseData, context); await this.processInboundMapping(externalCallConfig.dataMappingConfig.inboundMapping, responseData, context);
} else { } else {
@ -443,7 +443,7 @@ export class ImprovedButtonActionExecutor {
context: ButtonExecutionContext, context: ButtonExecutionContext,
): Promise<ExecutionResult> { ): Promise<ExecutionResult> {
try { try {
console.log(`💾 데이터 저장 실행 시작`); console.log("💾 데이터 저장 실행 시작");
// 제어 조건 확인 // 제어 조건 확인
const controlConditions = relationships.controlConditions || []; const controlConditions = relationships.controlConditions || [];
@ -520,11 +520,13 @@ export class ImprovedButtonActionExecutor {
): Promise<ExecutionResult> { ): Promise<ExecutionResult> {
try { try {
console.log(`🔧 데이터 액션 실행: ${action.name} (${action.actionType})`); console.log(`🔧 데이터 액션 실행: ${action.name} (${action.actionType})`);
console.log(`📥 받은 formData:`, formData); console.log("📥 받은 formData:", formData);
console.log("📥 formData 키들:", Object.keys(formData));
// 🔥 UPDATE 액션의 경우 formData를 기본으로 시작 // 🔥 UPDATE 액션의 경우 formData를 기본으로 시작 (기본키 포함)
const mappedData: Record<string, any> = action.actionType === "update" ? { ...formData } : {}; const mappedData: Record<string, any> = action.actionType === "update" ? { ...formData } : {};
// 필드 매핑 처리 (기존 데이터에 덮어쓰기)
for (const mapping of action.fieldMappings) { for (const mapping of action.fieldMappings) {
if (mapping.valueType === "static") { if (mapping.valueType === "static") {
// 정적 값 처리 // 정적 값 처리
@ -533,19 +535,22 @@ export class ImprovedButtonActionExecutor {
value = new Date().toISOString(); value = new Date().toISOString();
} }
mappedData[mapping.targetField] = value; mappedData[mapping.targetField] = value;
console.log(`🔧 정적 값 매핑: ${mapping.targetField} = ${value}`);
} else { } else {
// 필드 매핑 처리 // 필드 매핑 처리
const sourceField = mapping.fromField?.columnName; const sourceField = mapping.fromField?.columnName;
if (sourceField && formData[sourceField] !== undefined) { if (sourceField && formData[sourceField] !== undefined) {
mappedData[mapping.toField.columnName] = formData[sourceField]; mappedData[mapping.toField.columnName] = formData[sourceField];
console.log(`🔧 필드 매핑: ${sourceField}${mapping.toField.columnName} = ${formData[sourceField]}`);
} }
} }
} }
console.log(`📋 매핑된 데이터:`, mappedData); console.log("📋 최종 매핑된 데이터:", mappedData);
console.log(`🔑 기본키 포함 여부 체크:`, { console.log("🔑 기본키 포함 여부 체크:", {
hasId: "id" in mappedData, hasId: "id" in mappedData,
keys: Object.keys(mappedData), keys: Object.keys(mappedData),
values: Object.values(mappedData),
}); });
// 대상 연결 정보 // 대상 연결 정보
@ -616,7 +621,7 @@ export class ImprovedButtonActionExecutor {
formData: Record<string, any>, formData: Record<string, any>,
context: ButtonExecutionContext, context: ButtonExecutionContext,
): boolean { ): boolean {
console.log(`🔍 조건 평가 시작:`, { console.log("🔍 조건 평가 시작:", {
conditions, conditions,
formDataKeys: Object.keys(formData), formDataKeys: Object.keys(formData),
formData, formData,
@ -628,7 +633,7 @@ export class ImprovedButtonActionExecutor {
const conditionValue = condition.value; const conditionValue = condition.value;
const operator = condition.operator; const operator = condition.operator;
console.log(`🔍 개별 조건 검증:`, { console.log("🔍 개별 조건 검증:", {
field: condition.field, field: condition.field,
operator, operator,
expectedValue: conditionValue, expectedValue: conditionValue,
@ -664,13 +669,13 @@ export class ImprovedButtonActionExecutor {
if (!conditionMet) { if (!conditionMet) {
console.log(`❌ 조건 불만족: ${condition.field} ${operator} ${conditionValue} (실제값: ${fieldValue})`); console.log(`❌ 조건 불만족: ${condition.field} ${operator} ${conditionValue} (실제값: ${fieldValue})`);
console.log(`❌ 사용 가능한 필드들:`, Object.keys(formData)); console.log("❌ 사용 가능한 필드들:", Object.keys(formData));
console.log(`❌ 전체 formData:`, formData); console.log("❌ 전체 formData:", formData);
return false; return false;
} }
} }
console.log(`✅ 모든 조건 만족`); console.log("✅ 모든 조건 만족");
return true; return true;
} }
@ -682,25 +687,25 @@ export class ImprovedButtonActionExecutor {
// null이나 undefined인 경우 // null이나 undefined인 경우
if (!responseData) { if (!responseData) {
console.log(`⚠️ 응답 데이터가 null 또는 undefined`); console.log("⚠️ 응답 데이터가 null 또는 undefined");
return []; return [];
} }
// 이미 배열인 경우 (직접 배열 응답) // 이미 배열인 경우 (직접 배열 응답)
if (Array.isArray(responseData)) { if (Array.isArray(responseData)) {
console.log(`✅ 직접 배열 응답 감지`); console.log("✅ 직접 배열 응답 감지");
return responseData; return responseData;
} }
// 문자열인 경우 JSON 파싱 시도 // 문자열인 경우 JSON 파싱 시도
if (typeof responseData === "string") { if (typeof responseData === "string") {
console.log(`🔄 JSON 문자열 파싱 시도`); console.log("🔄 JSON 문자열 파싱 시도");
try { try {
const parsed = JSON.parse(responseData); const parsed = JSON.parse(responseData);
console.log(`✅ JSON 파싱 성공, 재귀 호출`); console.log("✅ JSON 파싱 성공, 재귀 호출");
return this.extractActualData(parsed); return this.extractActualData(parsed);
} catch (error) { } catch (error) {
console.log(`⚠️ JSON 파싱 실패, 원본 문자열 반환:`, error); console.log("⚠️ JSON 파싱 실패, 원본 문자열 반환:", error);
return [responseData]; return [responseData];
} }
} }
@ -733,20 +738,20 @@ export class ImprovedButtonActionExecutor {
// 추출된 데이터가 문자열인 경우 JSON 파싱 시도 // 추출된 데이터가 문자열인 경우 JSON 파싱 시도
if (typeof extractedData === "string") { if (typeof extractedData === "string") {
console.log(`🔄 추출된 데이터가 JSON 문자열, 파싱 시도`); console.log("🔄 추출된 데이터가 JSON 문자열, 파싱 시도");
try { try {
const parsed = JSON.parse(extractedData); const parsed = JSON.parse(extractedData);
console.log(`✅ JSON 파싱 성공, 재귀 호출`); console.log("✅ JSON 파싱 성공, 재귀 호출");
return this.extractActualData(parsed); return this.extractActualData(parsed);
} catch (error) { } catch (error) {
console.log(`⚠️ JSON 파싱 실패, 원본 문자열 반환:`, error); console.log("⚠️ JSON 파싱 실패, 원본 문자열 반환:", error);
return [extractedData]; return [extractedData];
} }
} }
// 추출된 데이터가 객체이고 또 다른 중첩 구조일 수 있으므로 재귀 호출 // 추출된 데이터가 객체이고 또 다른 중첩 구조일 수 있으므로 재귀 호출
if (typeof extractedData === "object" && !Array.isArray(extractedData)) { if (typeof extractedData === "object" && !Array.isArray(extractedData)) {
console.log(`🔄 중첩된 객체 감지, 재귀 추출 시도`); console.log("🔄 중첩된 객체 감지, 재귀 추출 시도");
return this.extractActualData(extractedData); return this.extractActualData(extractedData);
} }
@ -759,14 +764,14 @@ export class ImprovedButtonActionExecutor {
const arrayValue = objectValues.find((value) => Array.isArray(value)); const arrayValue = objectValues.find((value) => Array.isArray(value));
if (arrayValue) { if (arrayValue) {
console.log(`✅ 객체 값 중 배열 발견`); console.log("✅ 객체 값 중 배열 발견");
return arrayValue; return arrayValue;
} }
// 객체의 값들 중에서 객체를 찾아서 재귀 탐색 // 객체의 값들 중에서 객체를 찾아서 재귀 탐색
for (const value of objectValues) { for (const value of objectValues) {
if (value && typeof value === "object" && !Array.isArray(value)) { if (value && typeof value === "object" && !Array.isArray(value)) {
console.log(`🔄 객체 값에서 재귀 탐색`); console.log("🔄 객체 값에서 재귀 탐색");
const nestedResult = this.extractActualData(value); const nestedResult = this.extractActualData(value);
if (Array.isArray(nestedResult) && nestedResult.length > 0) { if (Array.isArray(nestedResult) && nestedResult.length > 0) {
return nestedResult; return nestedResult;
@ -775,7 +780,7 @@ export class ImprovedButtonActionExecutor {
} }
// 모든 시도가 실패한 경우, 원본 객체를 단일 항목 배열로 반환 // 모든 시도가 실패한 경우, 원본 객체를 단일 항목 배열로 반환
console.log(`📦 원본 객체를 단일 항목으로 처리`); console.log("📦 원본 객체를 단일 항목으로 처리");
return [responseData]; return [responseData];
} }
@ -788,38 +793,38 @@ export class ImprovedButtonActionExecutor {
context: ButtonExecutionContext, context: ButtonExecutionContext,
): Promise<void> { ): Promise<void> {
try { try {
console.log(`📥 인바운드 데이터 매핑 처리 시작`); console.log("📥 인바운드 데이터 매핑 처리 시작");
console.log(`📥 원본 응답 데이터:`, responseData); console.log("📥 원본 응답 데이터:", responseData);
const targetTable = inboundMapping.targetTable; const targetTable = inboundMapping.targetTable;
const fieldMappings = inboundMapping.fieldMappings || []; const fieldMappings = inboundMapping.fieldMappings || [];
const insertMode = inboundMapping.insertMode || "insert"; const insertMode = inboundMapping.insertMode || "insert";
console.log(`📥 매핑 설정:`, { console.log("📥 매핑 설정:", {
targetTable, targetTable,
fieldMappings, fieldMappings,
insertMode, insertMode,
}); });
// 응답 데이터에서 실제 데이터 추출 (다양한 구조 지원) // 응답 데이터에서 실제 데이터 추출 (다양한 구조 지원)
let actualData = this.extractActualData(responseData); const actualData = this.extractActualData(responseData);
console.log(`📥 추출된 실제 데이터:`, actualData); console.log("📥 추출된 실제 데이터:", actualData);
// 배열이 아닌 경우 배열로 변환 // 배열이 아닌 경우 배열로 변환
const dataArray = Array.isArray(actualData) ? actualData : [actualData]; const dataArray = Array.isArray(actualData) ? actualData : [actualData];
console.log(`📥 처리할 데이터 배열:`, dataArray); console.log("📥 처리할 데이터 배열:", dataArray);
if (dataArray.length === 0) { if (dataArray.length === 0) {
console.log(`⚠️ 처리할 데이터가 없습니다`); console.log("⚠️ 처리할 데이터가 없습니다");
return; return;
} }
for (const item of dataArray) { for (const item of dataArray) {
const mappedData: Record<string, any> = {}; const mappedData: Record<string, any> = {};
console.log(`📥 개별 아이템 처리:`, item); console.log("📥 개별 아이템 처리:", item);
// 필드 매핑 적용 // 필드 매핑 적용
for (const mapping of fieldMappings) { for (const mapping of fieldMappings) {
@ -831,17 +836,17 @@ export class ImprovedButtonActionExecutor {
} }
} }
console.log(`📋 매핑된 데이터:`, mappedData); console.log("📋 매핑된 데이터:", mappedData);
// 매핑된 데이터가 비어있지 않은 경우에만 저장 // 매핑된 데이터가 비어있지 않은 경우에만 저장
if (Object.keys(mappedData).length > 0) { if (Object.keys(mappedData).length > 0) {
await this.saveDataToTable(targetTable, mappedData, insertMode); await this.saveDataToTable(targetTable, mappedData, insertMode);
} else { } else {
console.log(`⚠️ 매핑된 데이터가 비어있어 저장을 건너뜁니다`); console.log("⚠️ 매핑된 데이터가 비어있어 저장을 건너뜁니다");
} }
} }
console.log(`✅ 인바운드 데이터 매핑 완료`); console.log("✅ 인바운드 데이터 매핑 완료");
} catch (error) { } catch (error) {
console.error("인바운드 데이터 매핑 오류:", error); console.error("인바운드 데이터 매핑 오류:", error);
throw error; throw error;