엔티티 즉시저장기능 추가
This commit is contained in:
@@ -584,6 +584,219 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
|
||||
}
|
||||
};
|
||||
|
||||
// 🆕 즉시 저장(quickInsert) 액션 핸들러
|
||||
const handleQuickInsertAction = async () => {
|
||||
// componentConfig에서 quickInsertConfig 가져오기
|
||||
const quickInsertConfig = (comp as any).componentConfig?.action?.quickInsertConfig;
|
||||
|
||||
if (!quickInsertConfig?.targetTable) {
|
||||
toast.error("대상 테이블이 설정되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 대상 테이블의 컬럼 목록 조회 (자동 매핑용)
|
||||
let targetTableColumns: string[] = [];
|
||||
try {
|
||||
const { default: apiClient } = await import("@/lib/api/client");
|
||||
const columnsResponse = await apiClient.get(
|
||||
`/table-management/tables/${quickInsertConfig.targetTable}/columns`
|
||||
);
|
||||
if (columnsResponse.data?.success && columnsResponse.data?.data) {
|
||||
const columnsData = columnsResponse.data.data.columns || columnsResponse.data.data;
|
||||
targetTableColumns = columnsData.map((col: any) => col.columnName || col.column_name || col.name);
|
||||
console.log("📍 대상 테이블 컬럼 목록:", targetTableColumns);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("대상 테이블 컬럼 조회 실패:", error);
|
||||
}
|
||||
|
||||
// 2. 컬럼 매핑에서 값 수집
|
||||
const insertData: Record<string, any> = {};
|
||||
const columnMappings = quickInsertConfig.columnMappings || [];
|
||||
|
||||
for (const mapping of columnMappings) {
|
||||
let value: any;
|
||||
|
||||
switch (mapping.sourceType) {
|
||||
case "component":
|
||||
// 같은 화면의 컴포넌트에서 값 가져오기
|
||||
// 방법1: sourceColumnName 사용
|
||||
if (mapping.sourceColumnName && formData[mapping.sourceColumnName] !== undefined) {
|
||||
value = formData[mapping.sourceColumnName];
|
||||
console.log(`📍 컴포넌트 값 (sourceColumnName): ${mapping.sourceColumnName} = ${value}`);
|
||||
}
|
||||
// 방법2: sourceComponentId로 컴포넌트 찾아서 columnName 사용
|
||||
else if (mapping.sourceComponentId) {
|
||||
const sourceComp = allComponents.find((c: any) => c.id === mapping.sourceComponentId);
|
||||
if (sourceComp) {
|
||||
const fieldName = (sourceComp as any).columnName || sourceComp.id;
|
||||
value = formData[fieldName];
|
||||
console.log(`📍 컴포넌트 값 (컴포넌트 조회): ${fieldName} = ${value}`);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "leftPanel":
|
||||
// 분할 패널 좌측 선택 데이터에서 값 가져오기
|
||||
if (mapping.sourceColumn && splitPanelContext?.selectedLeftData) {
|
||||
value = splitPanelContext.selectedLeftData[mapping.sourceColumn];
|
||||
}
|
||||
break;
|
||||
|
||||
case "fixed":
|
||||
value = mapping.fixedValue;
|
||||
break;
|
||||
|
||||
case "currentUser":
|
||||
if (mapping.userField) {
|
||||
switch (mapping.userField) {
|
||||
case "userId":
|
||||
value = user?.userId;
|
||||
break;
|
||||
case "userName":
|
||||
value = userName;
|
||||
break;
|
||||
case "companyCode":
|
||||
value = user?.companyCode;
|
||||
break;
|
||||
case "deptCode":
|
||||
value = authUser?.deptCode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (value !== undefined && value !== null && value !== "") {
|
||||
insertData[mapping.targetColumn] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 좌측 패널 선택 데이터에서 자동 매핑 (컬럼명이 같고 대상 테이블에 있는 경우)
|
||||
if (splitPanelContext?.selectedLeftData && targetTableColumns.length > 0) {
|
||||
const leftData = splitPanelContext.selectedLeftData;
|
||||
console.log("📍 좌측 패널 자동 매핑 시작:", leftData);
|
||||
|
||||
for (const [key, val] of Object.entries(leftData)) {
|
||||
// 이미 매핑된 컬럼은 스킵
|
||||
if (insertData[key] !== undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 대상 테이블에 해당 컬럼이 없으면 스킵
|
||||
if (!targetTableColumns.includes(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 시스템 컬럼 제외
|
||||
const systemColumns = ['id', 'created_date', 'updated_date', 'writer', 'writer_name'];
|
||||
if (systemColumns.includes(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// _label, _name 으로 끝나는 표시용 컬럼 제외
|
||||
if (key.endsWith('_label') || key.endsWith('_name')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 값이 있으면 자동 추가
|
||||
if (val !== undefined && val !== null && val !== '') {
|
||||
insertData[key] = val;
|
||||
console.log(`📍 자동 매핑 추가: ${key} = ${val}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("🚀 quickInsert 최종 데이터:", insertData);
|
||||
|
||||
// 4. 필수값 검증
|
||||
if (Object.keys(insertData).length === 0) {
|
||||
toast.error("저장할 데이터가 없습니다. 값을 선택해주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 중복 체크 (설정된 경우)
|
||||
if (quickInsertConfig.duplicateCheck?.enabled && quickInsertConfig.duplicateCheck?.columns?.length > 0) {
|
||||
try {
|
||||
const { default: apiClient } = await import("@/lib/api/client");
|
||||
|
||||
// 중복 체크를 위한 검색 조건 구성
|
||||
const searchConditions: Record<string, any> = {};
|
||||
for (const col of quickInsertConfig.duplicateCheck.columns) {
|
||||
if (insertData[col] !== undefined) {
|
||||
searchConditions[col] = { value: insertData[col], operator: "equals" };
|
||||
}
|
||||
}
|
||||
|
||||
console.log("📍 중복 체크 조건:", searchConditions);
|
||||
|
||||
// 기존 데이터 조회
|
||||
const checkResponse = await apiClient.post(
|
||||
`/table-management/tables/${quickInsertConfig.targetTable}/data`,
|
||||
{
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
search: searchConditions,
|
||||
}
|
||||
);
|
||||
|
||||
console.log("📍 중복 체크 응답:", checkResponse.data);
|
||||
|
||||
// data 배열이 있고 길이가 0보다 크면 중복
|
||||
const existingData = checkResponse.data?.data?.data || checkResponse.data?.data || [];
|
||||
if (Array.isArray(existingData) && existingData.length > 0) {
|
||||
toast.error(quickInsertConfig.duplicateCheck.errorMessage || "이미 존재하는 데이터입니다.");
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("중복 체크 오류:", error);
|
||||
// 중복 체크 실패 시 계속 진행
|
||||
}
|
||||
}
|
||||
|
||||
// 6. API 호출
|
||||
try {
|
||||
const { default: apiClient } = await import("@/lib/api/client");
|
||||
|
||||
const response = await apiClient.post(
|
||||
`/table-management/tables/${quickInsertConfig.targetTable}/add`,
|
||||
insertData
|
||||
);
|
||||
|
||||
if (response.data?.success) {
|
||||
// 7. 성공 후 동작
|
||||
if (quickInsertConfig.afterInsert?.showSuccessMessage !== false) {
|
||||
toast.success(quickInsertConfig.afterInsert?.successMessage || "저장되었습니다.");
|
||||
}
|
||||
|
||||
// 데이터 새로고침 (테이블리스트, 카드 디스플레이)
|
||||
if (quickInsertConfig.afterInsert?.refreshData !== false) {
|
||||
console.log("📍 데이터 새로고침 이벤트 발송");
|
||||
if (typeof window !== "undefined") {
|
||||
window.dispatchEvent(new CustomEvent("refreshTable"));
|
||||
window.dispatchEvent(new CustomEvent("refreshCardDisplay"));
|
||||
}
|
||||
}
|
||||
|
||||
// 지정된 컴포넌트 초기화
|
||||
if (quickInsertConfig.afterInsert?.clearComponents?.length > 0) {
|
||||
for (const componentId of quickInsertConfig.afterInsert.clearComponents) {
|
||||
const targetComp = allComponents.find((c: any) => c.id === componentId);
|
||||
if (targetComp) {
|
||||
const fieldName = (targetComp as any).columnName || targetComp.id;
|
||||
onFormDataChange?.(fieldName, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
toast.error(response.data?.message || "저장에 실패했습니다.");
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("quickInsert 오류:", error);
|
||||
toast.error(error.response?.data?.message || error.message || "저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = async () => {
|
||||
try {
|
||||
const actionType = config?.actionType || "save";
|
||||
@@ -604,6 +817,9 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
|
||||
case "custom":
|
||||
await handleCustomAction();
|
||||
break;
|
||||
case "quickInsert":
|
||||
await handleQuickInsertAction();
|
||||
break;
|
||||
default:
|
||||
// console.log("🔘 기본 버튼 클릭");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user