import { apiClient } from "./client"; /** * 데이터 조회 API */ export const dataApi = { /** * 테이블 데이터 조회 * @param tableName 테이블명 * @param params 조회 파라미터 (검색, 페이징 등) */ getTableData: async ( tableName: string, params?: { page?: number; size?: number; searchTerm?: string; sortBy?: string; sortOrder?: "asc" | "desc"; filters?: Record; }, ): Promise<{ data: any[]; total: number; page: number; size: number; totalPages: number; }> => { const response = await apiClient.get(`/data/${tableName}`, { params }); const raw = response.data || {}; const items: any[] = (raw.data ?? raw.items ?? raw.rows ?? []) as any[]; const page = raw.page ?? params?.page ?? 1; const size = raw.size ?? params?.size ?? items.length; const total = raw.total ?? items.length; const totalPages = raw.totalPages ?? Math.max(1, Math.ceil(total / (size || 1))); return { data: items, total, page, size, totalPages }; }, /** * 특정 레코드 상세 조회 * @param tableName 테이블명 * @param id 레코드 ID * @param enableEntityJoin Entity 조인 활성화 여부 (기본값: false) * @param groupByColumns 그룹핑 기준 컬럼들 (배열) */ getRecordDetail: async ( tableName: string, id: string | number, enableEntityJoin: boolean = false, groupByColumns: string[] = [] ): Promise<{ success: boolean; data?: any; error?: string }> => { try { const params: any = {}; if (enableEntityJoin) { params.enableEntityJoin = true; } if (groupByColumns.length > 0) { params.groupByColumns = JSON.stringify(groupByColumns); } console.log("🌐 [dataApi.getRecordDetail] API 호출:", { tableName, id, enableEntityJoin, groupByColumns, params, url: `/data/${tableName}/${id}`, }); const response = await apiClient.get(`/data/${tableName}/${id}`, { params }); console.log("📥 [dataApi.getRecordDetail] API 응답:", { success: response.data?.success, dataType: Array.isArray(response.data?.data) ? "배열" : "객체", dataCount: Array.isArray(response.data?.data) ? response.data.data.length : 1, }); return response.data; // { success: true, data: ... } 형식 그대로 반환 } catch (error: any) { console.error("❌ [dataApi.getRecordDetail] API 오류:", error); return { success: false, error: error.response?.data?.message || error.message || "레코드 조회 실패", }; } }, /** * 조인된 데이터 조회 * @param leftTable 좌측 테이블명 * @param rightTable 우측 테이블명 * @param leftColumn 좌측 컬럼명 * @param rightColumn 우측 컬럼명 (외래키) * @param leftValue 좌측 값 (필터링) * @param dataFilter 데이터 필터 * @param enableEntityJoin Entity 조인 활성화 * @param displayColumns 표시할 컬럼 목록 (tableName.columnName 형식 포함) */ getJoinedData: async ( leftTable: string, rightTable: string, leftColumn: string, rightColumn: string, leftValue?: any, dataFilter?: any, enableEntityJoin?: boolean, displayColumns?: Array<{ name: string; label?: string }>, deduplication?: { // 🆕 중복 제거 설정 enabled: boolean; groupByColumn: string; keepStrategy: "latest" | "earliest" | "base_price" | "current_date"; sortColumn?: string; }, ): Promise => { const response = await apiClient.get(`/data/join`, { params: { leftTable, rightTable, leftColumn, rightColumn, leftValue, dataFilter: dataFilter ? JSON.stringify(dataFilter) : undefined, enableEntityJoin: enableEntityJoin ?? true, displayColumns: displayColumns ? JSON.stringify(displayColumns) : undefined, // 🆕 표시 컬럼 전달 deduplication: deduplication ? JSON.stringify(deduplication) : undefined, // 🆕 중복 제거 설정 전달 }, }); const raw = response.data || {}; return (raw.data ?? raw.items ?? raw.rows ?? []) as any[]; }, /** * 레코드 생성 * @param tableName 테이블명 * @param data 레코드 데이터 */ createRecord: async (tableName: string, data: Record): Promise => { const response = await apiClient.post(`/data/${tableName}`, data); return response.data; // success, data, message 포함된 전체 응답 반환 }, /** * 레코드 수정 * @param tableName 테이블명 * @param id 레코드 ID * @param data 수정할 데이터 */ updateRecord: async (tableName: string, id: string | number, data: Record): Promise => { const response = await apiClient.put(`/data/${tableName}/${id}`, data); return response.data; // success, data, message 포함된 전체 응답 반환 }, /** * 레코드 삭제 * @param tableName 테이블명 * @param id 레코드 ID 또는 복합키 객체 */ deleteRecord: async (tableName: string, id: string | number | Record): Promise => { // 복합키 객체인 경우 POST로 전달 if (typeof id === 'object' && !Array.isArray(id)) { const response = await apiClient.post(`/data/${tableName}/delete`, id); return response.data; } // 단일 ID인 경우 기존 방식 const response = await apiClient.delete(`/data/${tableName}/${id}`); return response.data; // success, message 포함된 전체 응답 반환 }, /** * 조건에 맞는 모든 레코드 삭제 (그룹 삭제) * @param tableName 테이블명 * @param filterConditions 삭제 조건 (예: { customer_id: "CUST-0002", item_id: "SLI-2025-0002" }) */ deleteGroupRecords: async ( tableName: string, filterConditions: Record ): Promise<{ success: boolean; deleted?: number; message?: string; error?: string }> => { try { console.log(`🗑️ [dataApi] 그룹 삭제 요청:`, { tableName, filterConditions }); const response = await apiClient.post(`/data/${tableName}/delete-group`, filterConditions); console.log(`✅ [dataApi] 그룹 삭제 성공:`, response.data); return response.data; } catch (error: any) { console.error(`❌ [dataApi] 그룹 삭제 실패:`, error); return { success: false, error: error.response?.data?.message || error.message || "그룹 삭제 실패", }; } }, /** * 특정 레코드 상세 조회 * @param tableName 테이블명 * @param id 레코드 ID * @param enableEntityJoin Entity 조인 활성화 여부 (기본값: false) */ getRecordDetail: async ( tableName: string, id: string | number, enableEntityJoin: boolean = false ): Promise<{ success: boolean; data?: any; error?: string }> => { try { const params: any = {}; if (enableEntityJoin) { params.enableEntityJoin = "true"; } const response = await apiClient.get(`/data/${tableName}/${id}`, { params }); return response.data; // { success: true, data: ... } 형식 그대로 반환 } catch (error: any) { return { success: false, error: error.response?.data?.message || error.message || "레코드 조회 실패", }; } }, /** * 그룹화된 데이터 UPSERT * @param tableName 테이블명 * @param parentKeys 부모 키 (예: { customer_id: "CUST-0002", item_id: "SLI-2025-0002" }) * @param records 레코드 배열 */ upsertGroupedRecords: async ( tableName: string, parentKeys: Record, records: Array> ): Promise<{ success: boolean; inserted?: number; updated?: number; deleted?: number; message?: string; error?: string }> => { try { console.log("📡 [dataApi.upsertGroupedRecords] 요청 데이터:", { tableName, tableNameType: typeof tableName, tableNameValue: JSON.stringify(tableName), parentKeys, recordsCount: records.length, }); const requestBody = { tableName, parentKeys, records, }; console.log("📦 [dataApi.upsertGroupedRecords] 요청 본문 (JSON):", JSON.stringify(requestBody, null, 2)); const response = await apiClient.post('/data/upsert-grouped', requestBody); return response.data; } catch (error: any) { console.error("❌ [dataApi.upsertGroupedRecords] 에러:", { status: error.response?.status, statusText: error.response?.statusText, data: error.response?.data, message: error.message, }); return { success: false, error: error.response?.data?.message || error.message || "데이터 저장 실패", }; } }, };