import { apiClient, ApiResponse } from "./client"; // 동적 폼 데이터 타입 export interface DynamicFormData { screenId: number; tableName: string; data: Record; } // 폼 데이터 저장 응답 타입 export interface SaveFormDataResponse { id: number; success: boolean; message: string; data?: Record; } // 폼 데이터 조회 응답 타입 export interface FormDataResponse { id: number; screenId: number; tableName: string; data: Record; createdAt: string; updatedAt: string; } // 동적 폼 API 클래스 export class DynamicFormApi { /** * 폼 데이터 저장 (기존 버전 - 레거시 지원) * @param formData 저장할 폼 데이터 * @returns 저장 결과 */ static async saveFormData(formData: DynamicFormData): Promise> { try { const response = await apiClient.post("/dynamic-form/save", formData); return { success: true, data: response.data, message: "데이터가 성공적으로 저장되었습니다.", }; } catch (error: any) { console.error("❌ 폼 데이터 저장 실패:", error); const errorMessage = error.response?.data?.message || error.message || "데이터 저장 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 폼 데이터 저장 (개선된 버전) * @param formData 저장할 폼 데이터 * @returns 저장 결과 (상세한 검증 정보 포함) */ static async saveData(formData: DynamicFormData): Promise> { try { const response = await apiClient.post("/dynamic-form/save-enhanced", formData); return response.data; } catch (error: any) { console.error("❌ 개선된 폼 데이터 저장 실패:", error); // 개선된 오류 처리 const errorResponse = error.response?.data; if (errorResponse && !errorResponse.success) { return errorResponse; // 서버에서 온 구조화된 오류 응답 그대로 반환 } const errorMessage = error.response?.data?.message || error.message || "데이터 저장 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 폼 데이터 업데이트 * @param id 레코드 ID * @param formData 업데이트할 폼 데이터 * @returns 업데이트 결과 */ static async updateFormData( id: string | number, formData: Partial, ): Promise> { try { console.log("🔄 폼 데이터 업데이트 요청:", { id, formData }); const response = await apiClient.put(`/dynamic-form/${id}`, formData); console.log("✅ 폼 데이터 업데이트 성공:", response.data); return { success: true, data: response.data, message: "데이터가 성공적으로 업데이트되었습니다.", }; } catch (error: any) { console.error("❌ 폼 데이터 업데이트 실패:", error); const errorMessage = error.response?.data?.message || error.message || "데이터 업데이트 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 폼 데이터 부분 업데이트 (변경된 필드만) * @param id 레코드 ID * @param originalData 원본 데이터 * @param newData 변경할 데이터 * @param tableName 테이블명 * @returns 업데이트 결과 */ static async updateFormDataPartial( id: number, originalData: Record, newData: Record, tableName: string, ): Promise> { try { console.log("🔄 폼 데이터 부분 업데이트 요청:", { id, originalData, newData, tableName, }); const response = await apiClient.patch(`/dynamic-form/${id}/partial`, { tableName, originalData, newData, }); console.log("✅ 폼 데이터 부분 업데이트 성공:", response.data); return { success: true, data: response.data, message: "데이터가 성공적으로 업데이트되었습니다.", }; } catch (error: any) { console.error("❌ 폼 데이터 부분 업데이트 실패:", error); const errorMessage = error.response?.data?.message || error.message || "부분 업데이트 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 폼 데이터 삭제 * @param id 레코드 ID * @returns 삭제 결과 */ static async deleteFormData(id: number): Promise> { try { console.log("🗑️ 폼 데이터 삭제 요청:", id); await apiClient.delete(`/dynamic-form/${id}`); console.log("✅ 폼 데이터 삭제 성공"); return { success: true, message: "데이터가 성공적으로 삭제되었습니다.", }; } catch (error: any) { console.error("❌ 폼 데이터 삭제 실패:", error); const errorMessage = error.response?.data?.message || error.message || "데이터 삭제 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 실제 테이블에서 폼 데이터 삭제 * @param id 레코드 ID * @param tableName 테이블명 * @returns 삭제 결과 */ static async deleteFormDataFromTable(id: string | number, tableName: string): Promise> { try { console.log("🗑️ 실제 테이블에서 폼 데이터 삭제 요청:", { id, tableName }); await apiClient.delete(`/dynamic-form/${id}`, { data: { tableName }, }); console.log("✅ 실제 테이블에서 폼 데이터 삭제 성공"); return { success: true, message: "데이터가 성공적으로 삭제되었습니다.", }; } catch (error: any) { console.error("❌ 실제 테이블에서 폼 데이터 삭제 실패:", error); const errorMessage = error.response?.data?.message || error.message || "데이터 삭제 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 폼 데이터 목록 조회 * @param screenId 화면 ID * @param params 검색 파라미터 * @returns 폼 데이터 목록 */ static async getFormDataList( screenId: number, params?: { page?: number; size?: number; search?: string; sortBy?: string; sortOrder?: "asc" | "desc"; }, ): Promise< ApiResponse<{ content: FormDataResponse[]; totalElements: number; totalPages: number; currentPage: number; size: number; }> > { try { console.log("📋 폼 데이터 목록 조회 요청:", { screenId, params }); const response = await apiClient.get(`/dynamic-form/screen/${screenId}`, { params }); console.log("✅ 폼 데이터 목록 조회 성공:", response.data); return { success: true, data: response.data, }; } catch (error: any) { console.error("❌ 폼 데이터 목록 조회 실패:", error); const errorMessage = error.response?.data?.message || error.message || "데이터 조회 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 특정 폼 데이터 조회 * @param id 레코드 ID * @returns 폼 데이터 */ static async getFormData(id: number): Promise> { try { console.log("📄 폼 데이터 단건 조회 요청:", id); const response = await apiClient.get(`/dynamic-form/${id}`); console.log("✅ 폼 데이터 단건 조회 성공:", response.data); return { success: true, data: response.data, }; } catch (error: any) { console.error("❌ 폼 데이터 단건 조회 실패:", error); const errorMessage = error.response?.data?.message || error.message || "데이터 조회 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 테이블의 컬럼 정보 조회 (폼 검증용) * @param tableName 테이블명 * @returns 컬럼 정보 */ static async getTableColumns(tableName: string): Promise< ApiResponse<{ tableName: string; columns: Array<{ columnName: string; dataType: string; nullable: boolean; primaryKey: boolean; maxLength?: number; defaultValue?: any; }>; }> > { try { console.log("📊 테이블 컬럼 정보 조회 요청:", tableName); const response = await apiClient.get(`/dynamic-form/table/${tableName}/columns`); console.log("✅ 테이블 컬럼 정보 조회 성공:", response.data); return { success: true, data: response.data, }; } catch (error: any) { console.error("❌ 테이블 컬럼 정보 조회 실패:", error); const errorMessage = error.response?.data?.message || error.message || "테이블 정보 조회 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 폼 데이터 검증 * @param tableName 테이블명 * @param data 검증할 데이터 * @returns 검증 결과 */ static async validateFormData( tableName: string, data: Record, ): Promise< ApiResponse<{ valid: boolean; errors: Array<{ field: string; message: string; code: string; }>; }> > { try { console.log("✅ 폼 데이터 검증 요청:", { tableName, data }); const response = await apiClient.post(`/dynamic-form/validate`, { tableName, data, }); console.log("✅ 폼 데이터 검증 성공:", response.data); return { success: true, data: response.data, }; } catch (error: any) { console.error("❌ 폼 데이터 검증 실패:", error); const errorMessage = error.response?.data?.message || error.message || "데이터 검증 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 테이블의 기본키 조회 * @param tableName 테이블명 * @returns 기본키 컬럼명 배열 */ static async getTablePrimaryKeys(tableName: string): Promise> { try { const response = await apiClient.get(`/dynamic-form/table/${tableName}/primary-keys`); return { success: true, data: response.data.data, message: "기본키 조회가 완료되었습니다.", }; } catch (error: any) { console.error("❌ 테이블 기본키 조회 실패:", error); const errorMessage = error.response?.data?.message || error.message || "기본키 조회 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 테이블 데이터 조회 (페이징 + 검색) * @param tableName 테이블명 * @param params 검색 파라미터 * @returns 테이블 데이터 */ static async getTableData( tableName: string, params?: { page?: number; pageSize?: number; search?: string; sortBy?: string; sortOrder?: "asc" | "desc"; filters?: Record; }, ): Promise> { try { console.log("📊 테이블 데이터 조회 요청:", { tableName, params }); const response = await apiClient.post(`/table-management/tables/${tableName}/data`, params || {}); console.log("✅ 테이블 데이터 조회 성공 (원본):", response.data); console.log("🔍 response.data 상세:", { type: typeof response.data, isArray: Array.isArray(response.data), keys: response.data ? Object.keys(response.data) : [], hasData: response.data?.data !== undefined, dataType: response.data?.data ? typeof response.data.data : "N/A", dataIsArray: response.data?.data ? Array.isArray(response.data.data) : false, dataLength: response.data?.data ? (Array.isArray(response.data.data) ? response.data.data.length : "not array") : "no data", // 중첩 구조 확인 dataDataExists: response.data?.data?.data !== undefined, dataDataIsArray: response.data?.data?.data ? Array.isArray(response.data.data.data) : false, dataDataLength: response.data?.data?.data ? (Array.isArray(response.data.data.data) ? response.data.data.data.length : "not array") : "no nested data", }); // API 응답 구조: { data: [...], total, page, size, totalPages } // 또는 중첩: { success: true, data: { data: [...], total, ... } } // data 배열만 추출 let tableData: any[] = []; if (Array.isArray(response.data)) { // 케이스 1: 응답이 배열이면 그대로 사용 console.log("✅ 케이스 1: 응답이 배열"); tableData = response.data; } else if (response.data && Array.isArray(response.data.data)) { // 케이스 2: 응답이 { data: [...] } 구조면 data 배열 추출 console.log("✅ 케이스 2: 응답이 { data: [...] } 구조"); tableData = response.data.data; } else if (response.data?.data?.data && Array.isArray(response.data.data.data)) { // 케이스 2-1: 중첩 구조 { success: true, data: { data: [...] } } console.log("✅ 케이스 2-1: 중첩 구조 { data: { data: [...] } }"); tableData = response.data.data.data; } else if (response.data && typeof response.data === "object") { // 케이스 3: 응답이 객체면 배열로 감싸기 (최후의 수단) console.log("⚠️ 케이스 3: 응답이 객체 (배열로 감싸기)"); tableData = [response.data]; } console.log("✅ 테이블 데이터 추출 완료:", { originalType: typeof response.data, isArray: Array.isArray(response.data), hasDataProperty: response.data?.data !== undefined, extractedCount: tableData.length, firstRow: tableData[0], allRows: tableData, }); return { success: true, data: tableData, message: "테이블 데이터 조회가 완료되었습니다.", }; } catch (error: any) { console.error("❌ 테이블 데이터 조회 실패:", error); const errorMessage = error.response?.data?.message || error.message || "테이블 데이터 조회 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } /** * 엑셀 업로드 (대량 데이터 삽입/업데이트) * @param payload 업로드 데이터 * @returns 업로드 결과 */ static async uploadExcelData(payload: { tableName: string; data: any[]; uploadMode: "insert" | "update" | "upsert"; keyColumn?: string; }): Promise> { try { console.log("📤 엑셀 업로드 요청:", payload); const response = await apiClient.post(`/dynamic-form/excel-upload`, payload); console.log("✅ 엑셀 업로드 성공:", response.data); return { success: true, data: response.data, message: "엑셀 파일이 성공적으로 업로드되었습니다.", }; } catch (error: any) { console.error("❌ 엑셀 업로드 실패:", error); const errorMessage = error.response?.data?.message || error.message || "엑셀 업로드 중 오류가 발생했습니다."; return { success: false, message: errorMessage, errorCode: error.response?.data?.errorCode, }; } } } // 편의를 위한 기본 export export const dynamicFormApi = DynamicFormApi;