엑셀 업로드,다운로드 기능 개선

This commit is contained in:
kjs
2026-01-09 15:32:02 +09:00
parent ee3a648917
commit aa0698556e
9 changed files with 1619 additions and 387 deletions

View File

@@ -655,6 +655,52 @@ export class DynamicFormApi {
};
}
}
/**
* 마스터-디테일 간단 모드 엑셀 업로드
* - 마스터 정보는 UI에서 선택
* - 디테일 정보만 엑셀에서 업로드
* - 채번 규칙을 통해 마스터 키 자동 생성
* @param screenId 화면 ID
* @param detailData 디테일 데이터 배열
* @param masterFieldValues UI에서 선택한 마스터 필드 값
* @param numberingRuleId 채번 규칙 ID (optional)
* @returns 업로드 결과
*/
static async uploadMasterDetailSimple(
screenId: number,
detailData: Record<string, any>[],
masterFieldValues: Record<string, any>,
numberingRuleId?: string
): Promise<ApiResponse<MasterDetailSimpleUploadResult>> {
try {
console.log("📤 마스터-디테일 간단 모드 업로드:", {
screenId,
detailRowCount: detailData.length,
masterFieldValues,
numberingRuleId,
});
const response = await apiClient.post(`/data/master-detail/upload-simple`, {
screenId,
detailData,
masterFieldValues,
numberingRuleId,
});
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,
};
}
}
}
// 마스터-디테일 관계 타입
@@ -687,5 +733,14 @@ export interface MasterDetailUploadResult {
errors: string[];
}
// 🆕 마스터-디테일 간단 모드 업로드 결과 타입
export interface MasterDetailSimpleUploadResult {
success: boolean;
masterInserted: number;
detailInserted: number;
generatedKey: string; // 생성된 마스터 키
errors?: string[];
}
// 편의를 위한 기본 export
export const dynamicFormApi = DynamicFormApi;

View File

@@ -135,6 +135,13 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
if (item[underscoreKey] !== undefined) {
return item[underscoreKey];
}
// 6⃣ 🆕 모든 키에서 _fieldName으로 끝나는 키 찾기
// 예: partner_id_customer_name (프론트엔드가 customer_id로 추론했지만 실제는 partner_id인 경우)
const matchingKey = Object.keys(item).find((key) => key.endsWith(`_${fieldName}`));
if (matchingKey && item[matchingKey] !== undefined) {
return item[matchingKey];
}
}
return undefined;

View File

@@ -2886,3 +2886,4 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
</div>
);
};

View File

@@ -4840,10 +4840,12 @@ export class ButtonActionExecutor {
screenId: context.screenId,
});
// 🆕 마스터-디테일 구조 확인
// 🆕 마스터-디테일 구조 확인 (화면에 분할 패널이 있으면 자동 감지)
let isMasterDetail = false;
let masterDetailRelation: any = null;
let masterDetailExcelConfig: any = undefined;
// 화면 레이아웃에서 분할 패널 자동 감지
if (context.screenId) {
const { DynamicFormApi } = await import("@/lib/api/dynamicForm");
const relationResponse = await DynamicFormApi.getMasterDetailRelation(context.screenId);
@@ -4851,7 +4853,34 @@ export class ButtonActionExecutor {
if (relationResponse.success && relationResponse.data) {
isMasterDetail = true;
masterDetailRelation = relationResponse.data;
console.log("📊 마스터-디테일 구조 감지:", masterDetailRelation);
// 버튼 설정에서 채번 규칙 등 추가 설정 가져오기
if (config.masterDetailExcel) {
masterDetailExcelConfig = {
...config.masterDetailExcel,
// 분할 패널에서 감지한 테이블 정보로 덮어쓰기
masterTable: relationResponse.data.masterTable,
detailTable: relationResponse.data.detailTable,
masterKeyColumn: relationResponse.data.masterKeyColumn,
detailFkColumn: relationResponse.data.detailFkColumn,
};
} else {
// 버튼 설정이 없으면 분할 패널 정보만 사용
masterDetailExcelConfig = {
masterTable: relationResponse.data.masterTable,
detailTable: relationResponse.data.detailTable,
masterKeyColumn: relationResponse.data.masterKeyColumn,
detailFkColumn: relationResponse.data.detailFkColumn,
simpleMode: true, // 기본값으로 간단 모드 사용
};
}
console.log("📊 마스터-디테일 구조 자동 감지:", {
masterTable: relationResponse.data.masterTable,
detailTable: relationResponse.data.detailTable,
masterKeyColumn: relationResponse.data.masterKeyColumn,
numberingRuleId: masterDetailExcelConfig?.numberingRuleId,
});
}
}
@@ -4901,6 +4930,7 @@ export class ButtonActionExecutor {
screenId: context.screenId,
isMasterDetail,
masterDetailRelation,
masterDetailExcelConfig,
onSuccess: () => {
// 성공 메시지는 ExcelUploadModal 내부에서 이미 표시됨
context.onRefresh?.();