ERP-node/frontend/lib/api/data.ts

273 lines
9.1 KiB
TypeScript

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<string, any>;
},
): Promise<{
data: any[];
total: number;
page: number;
size: number;
totalPages: number;
}> => {
// filters를 평탄화하여 쿼리 파라미터로 전달 (백엔드 ...filters 형식에 맞춤)
const { filters, ...restParams } = params || {};
const flattenedParams = {
...restParams,
...(filters || {}), // filters 객체를 평탄화
};
const response = await apiClient.get(`/data/${tableName}`, { params: flattenedParams });
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<any[]> => {
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<string, any>): Promise<any> => {
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<string, any>): Promise<any> => {
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<string, any>): Promise<any> => {
// 복합키 객체인 경우 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<string, any>
): 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<string, any>,
records: Array<Record<string, any>>
): 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 || "데이터 저장 실패",
};
}
},
};