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

556 lines
17 KiB
TypeScript
Raw Normal View History

import { apiClient, ApiResponse } from "./client";
// 동적 폼 데이터 타입
export interface DynamicFormData {
screenId: number;
tableName: string;
data: Record<string, any>;
}
// 폼 데이터 저장 응답 타입
export interface SaveFormDataResponse {
id: number;
success: boolean;
message: string;
data?: Record<string, any>;
}
// 폼 데이터 조회 응답 타입
export interface FormDataResponse {
id: number;
screenId: number;
tableName: string;
data: Record<string, any>;
createdAt: string;
updatedAt: string;
}
// 동적 폼 API 클래스
export class DynamicFormApi {
/**
* ( - )
* @param formData
* @returns
*/
static async saveFormData(formData: DynamicFormData): Promise<ApiResponse<SaveFormDataResponse>> {
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<ApiResponse<SaveFormDataResponse>> {
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<DynamicFormData>,
): Promise<ApiResponse<SaveFormDataResponse>> {
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,
};
}
}
2025-09-18 18:49:30 +09:00
/**
* ( )
* @param id ID
* @param originalData
* @param newData
* @param tableName
* @returns
*/
static async updateFormDataPartial(
id: string | number, // 🔧 UUID 문자열도 지원
2025-09-18 18:49:30 +09:00
originalData: Record<string, any>,
newData: Record<string, any>,
tableName: string,
): Promise<ApiResponse<SaveFormDataResponse>> {
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<ApiResponse<void>> {
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<ApiResponse<void>> {
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<ApiResponse<FormDataResponse>> {
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<string, any>,
): 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,
};
}
}
2025-09-18 18:49:30 +09:00
/**
*
* @param tableName
* @returns
*/
static async getTablePrimaryKeys(tableName: string): Promise<ApiResponse<string[]>> {
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<string, any>;
autoFilter?: {
enabled: boolean;
filterColumn?: string;
userField?: string;
};
},
): Promise<ApiResponse<any[]>> {
try {
console.log("📊 테이블 데이터 조회 요청:", { tableName, params });
// autoFilter가 없으면 기본값으로 멀티테넌시 필터 적용
// pageSize를 size로 변환 (백엔드 파라미터명 호환)
const requestParams = {
...params,
size: params?.pageSize || params?.size || 100, // 기본값 100
autoFilter: params?.autoFilter ?? {
enabled: true,
filterColumn: "company_code",
userField: "companyCode",
},
};
const response = await apiClient.post(`/table-management/tables/${tableName}/data`, requestParams);
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<ApiResponse<any>> {
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;