754 lines
23 KiB
TypeScript
754 lines
23 KiB
TypeScript
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 });
|
||
console.log("🌐 API URL:", `/dynamic-form/${id}`);
|
||
console.log("📦 요청 본문:", JSON.stringify(formData, null, 2));
|
||
|
||
const response = await apiClient.put(`/dynamic-form/${id}`, formData);
|
||
|
||
console.log("✅ 폼 데이터 업데이트 성공:", response.data);
|
||
console.log("📊 응답 상태:", response.status);
|
||
console.log("📋 응답 헤더:", response.headers);
|
||
|
||
return {
|
||
success: true,
|
||
data: response.data,
|
||
message: "데이터가 성공적으로 업데이트되었습니다.",
|
||
};
|
||
} catch (error: any) {
|
||
console.error("❌ 폼 데이터 업데이트 실패:", error);
|
||
console.error("📊 에러 응답:", error.response?.data);
|
||
console.error("📊 에러 상태:", error.response?.status);
|
||
|
||
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: string | number, // 🔧 UUID 문자열도 지원
|
||
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 테이블명
|
||
* @param screenId 화면 ID (제어관리 실행용, 선택사항)
|
||
* @returns 삭제 결과
|
||
*/
|
||
static async deleteFormDataFromTable(
|
||
id: string | number,
|
||
tableName: string,
|
||
screenId?: number
|
||
): Promise<ApiResponse<void>> {
|
||
try {
|
||
console.log("🗑️ 실제 테이블에서 폼 데이터 삭제 요청:", { id, tableName, screenId });
|
||
|
||
await apiClient.delete(`/dynamic-form/${id}`, {
|
||
data: { tableName, screenId },
|
||
});
|
||
|
||
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,
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 테이블의 기본키 조회
|
||
* @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,
|
||
};
|
||
}
|
||
}
|
||
|
||
// ================================
|
||
// 마스터-디테일 엑셀 API
|
||
// ================================
|
||
|
||
/**
|
||
* 마스터-디테일 관계 정보 조회
|
||
* @param screenId 화면 ID
|
||
* @returns 마스터-디테일 관계 정보 (null이면 마스터-디테일 구조 아님)
|
||
*/
|
||
static async getMasterDetailRelation(screenId: number): Promise<ApiResponse<MasterDetailRelation | null>> {
|
||
try {
|
||
console.log("🔍 마스터-디테일 관계 조회:", screenId);
|
||
|
||
const response = await apiClient.get(`/data/master-detail/relation/${screenId}`);
|
||
|
||
return {
|
||
success: true,
|
||
data: response.data?.data || null,
|
||
message: response.data?.message || "조회 완료",
|
||
};
|
||
} catch (error: any) {
|
||
console.error("❌ 마스터-디테일 관계 조회 실패:", error);
|
||
return {
|
||
success: false,
|
||
data: null,
|
||
message: error.response?.data?.message || error.message,
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 마스터-디테일 엑셀 다운로드 데이터 조회
|
||
* @param screenId 화면 ID
|
||
* @param filters 필터 조건
|
||
* @returns JOIN된 플랫 데이터
|
||
*/
|
||
static async getMasterDetailDownloadData(
|
||
screenId: number,
|
||
filters?: Record<string, any>
|
||
): Promise<ApiResponse<MasterDetailDownloadData>> {
|
||
try {
|
||
console.log("📥 마스터-디테일 다운로드 데이터 조회:", { screenId, filters });
|
||
|
||
const response = await apiClient.post(`/data/master-detail/download`, {
|
||
screenId,
|
||
filters,
|
||
});
|
||
|
||
return {
|
||
success: true,
|
||
data: response.data?.data,
|
||
message: "데이터 조회 완료",
|
||
};
|
||
} catch (error: any) {
|
||
console.error("❌ 마스터-디테일 다운로드 실패:", error);
|
||
return {
|
||
success: false,
|
||
message: error.response?.data?.message || error.message,
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 마스터-디테일 엑셀 업로드
|
||
* @param screenId 화면 ID
|
||
* @param data 엑셀에서 읽은 플랫 데이터
|
||
* @returns 업로드 결과
|
||
*/
|
||
static async uploadMasterDetailData(
|
||
screenId: number,
|
||
data: Record<string, any>[]
|
||
): Promise<ApiResponse<MasterDetailUploadResult>> {
|
||
try {
|
||
console.log("📤 마스터-디테일 업로드:", { screenId, rowCount: data.length });
|
||
|
||
const response = await apiClient.post(`/data/master-detail/upload`, {
|
||
screenId,
|
||
data,
|
||
});
|
||
|
||
return {
|
||
success: response.data?.success,
|
||
data: response.data?.data,
|
||
message: response.data?.message,
|
||
};
|
||
} catch (error: any) {
|
||
console.error("❌ 마스터-디테일 업로드 실패:", error);
|
||
return {
|
||
success: false,
|
||
message: error.response?.data?.message || error.message,
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 마스터-디테일 간단 모드 엑셀 업로드
|
||
* - 마스터 정보는 UI에서 선택
|
||
* - 디테일 정보만 엑셀에서 업로드
|
||
* - 채번 규칙을 통해 마스터 키 자동 생성
|
||
* @param screenId 화면 ID
|
||
* @param detailData 디테일 데이터 배열
|
||
* @param masterFieldValues UI에서 선택한 마스터 필드 값
|
||
* @param numberingRuleId 채번 규칙 ID (optional)
|
||
* @param afterUploadFlowId 업로드 후 실행할 제어 ID (optional, 하위 호환성)
|
||
* @param afterUploadFlows 업로드 후 실행할 제어 목록 (optional)
|
||
* @returns 업로드 결과
|
||
*/
|
||
static async uploadMasterDetailSimple(
|
||
screenId: number,
|
||
detailData: Record<string, any>[],
|
||
masterFieldValues: Record<string, any>,
|
||
numberingRuleId?: string,
|
||
afterUploadFlowId?: string,
|
||
afterUploadFlows?: Array<{ flowId: string; order: number }>
|
||
): Promise<ApiResponse<MasterDetailSimpleUploadResult>> {
|
||
try {
|
||
console.log("📤 마스터-디테일 간단 모드 업로드:", {
|
||
screenId,
|
||
detailRowCount: detailData.length,
|
||
masterFieldValues,
|
||
numberingRuleId,
|
||
afterUploadFlows: afterUploadFlows?.length || 0,
|
||
});
|
||
|
||
const response = await apiClient.post(`/data/master-detail/upload-simple`, {
|
||
screenId,
|
||
detailData,
|
||
masterFieldValues,
|
||
numberingRuleId,
|
||
afterUploadFlowId,
|
||
afterUploadFlows,
|
||
});
|
||
|
||
return {
|
||
success: response.data?.success,
|
||
data: response.data?.data,
|
||
message: response.data?.message,
|
||
};
|
||
} catch (error: any) {
|
||
console.error("❌ 마스터-디테일 간단 모드 업로드 실패:", error);
|
||
return {
|
||
success: false,
|
||
message: error.response?.data?.message || error.message,
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
// 마스터-디테일 관계 타입
|
||
export interface MasterDetailRelation {
|
||
masterTable: string;
|
||
detailTable: string;
|
||
masterKeyColumn: string;
|
||
detailFkColumn: string;
|
||
masterColumns: Array<{ name: string; label: string; inputType: string; isFromMaster: boolean }>;
|
||
detailColumns: Array<{ name: string; label: string; inputType: string; isFromMaster: boolean }>;
|
||
}
|
||
|
||
// 마스터-디테일 다운로드 데이터 타입
|
||
export interface MasterDetailDownloadData {
|
||
headers: string[];
|
||
columns: string[];
|
||
data: Record<string, any>[];
|
||
masterColumns: string[];
|
||
detailColumns: string[];
|
||
joinKey: string;
|
||
}
|
||
|
||
// 마스터-디테일 업로드 결과 타입
|
||
export interface MasterDetailUploadResult {
|
||
success: boolean;
|
||
masterInserted: number;
|
||
masterUpdated: number;
|
||
detailInserted: number;
|
||
detailDeleted: number;
|
||
errors: string[];
|
||
}
|
||
|
||
// 🆕 마스터-디테일 간단 모드 업로드 결과 타입
|
||
export interface MasterDetailSimpleUploadResult {
|
||
success: boolean;
|
||
masterInserted: number;
|
||
detailInserted: number;
|
||
generatedKey: string; // 생성된 마스터 키
|
||
errors?: string[];
|
||
}
|
||
|
||
// 편의를 위한 기본 export
|
||
export const dynamicFormApi = DynamicFormApi;
|