디버그 로그 제거 및 버튼 구성 패널 개선
- ScreenDesigner 컴포넌트에서 불필요한 디버그 로그를 제거하여 코드 가독성을 향상시켰습니다. - ButtonConfigPanel에서 actionType을 로컬 상태로 관리하도록 개선하여, 버튼 액션 설정의 일관성을 높였습니다. - RepeatContainerComponent에서 섹션별 폼 데이터 관리 기능을 추가하여, 각 반복 아이템의 독립적인 폼 데이터 처리가 가능해졌습니다. 이로 인해 코드의 효율성과 유지보수성이 향상되었습니다.
This commit is contained in:
parent
8344486e56
commit
8c0572e0ac
|
|
@ -3329,14 +3329,6 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
|||
});
|
||||
}
|
||||
|
||||
if (newComponent.type === "group") {
|
||||
console.log("🔓 그룹 컴포넌트는 격자 스냅 제외:", {
|
||||
type: newComponent.type,
|
||||
position: newComponent.position,
|
||||
size: newComponent.size,
|
||||
});
|
||||
}
|
||||
|
||||
const newLayout = {
|
||||
...layout,
|
||||
components: [...layout.components, newComponent],
|
||||
|
|
@ -3508,27 +3500,6 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
|||
componentsToMove = [...componentsToMove, ...additionalComponents];
|
||||
}
|
||||
|
||||
// console.log("드래그 시작:", component.id, "이동할 컴포넌트 수:", componentsToMove.length);
|
||||
console.log("마우스 위치 (줌 보정):", {
|
||||
zoomLevel,
|
||||
clientX: event.clientX,
|
||||
clientY: event.clientY,
|
||||
rectLeft: rect.left,
|
||||
rectTop: rect.top,
|
||||
mouseRaw: { x: event.clientX - rect.left, y: event.clientY - rect.top },
|
||||
mouseZoomCorrected: { x: relativeMouseX, y: relativeMouseY },
|
||||
componentX: component.position.x,
|
||||
componentY: component.position.y,
|
||||
grabOffsetX: relativeMouseX - component.position.x,
|
||||
grabOffsetY: relativeMouseY - component.position.y,
|
||||
});
|
||||
|
||||
console.log("🚀 드래그 시작:", {
|
||||
componentId: component.id,
|
||||
componentType: component.type,
|
||||
initialPosition: { x: component.position.x, y: component.position.y },
|
||||
});
|
||||
|
||||
setDragState({
|
||||
isDragging: true,
|
||||
draggedComponent: component, // 주 드래그 컴포넌트 (마우스 위치 기준)
|
||||
|
|
@ -3581,27 +3552,11 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
|||
};
|
||||
|
||||
// 드래그 상태 업데이트
|
||||
console.log("🔥 ScreenDesigner updateDragPosition (줌 보정):", {
|
||||
zoomLevel,
|
||||
draggedComponentId: dragState.draggedComponent.id,
|
||||
mouseRaw: { x: event.clientX - rect.left, y: event.clientY - rect.top },
|
||||
mouseZoomCorrected: { x: relativeMouseX, y: relativeMouseY },
|
||||
oldPosition: dragState.currentPosition,
|
||||
newPosition: newPosition,
|
||||
});
|
||||
|
||||
setDragState((prev) => {
|
||||
const newState = {
|
||||
...prev,
|
||||
currentPosition: { ...newPosition }, // 새로운 객체 생성
|
||||
};
|
||||
console.log("🔄 ScreenDesigner dragState 업데이트:", {
|
||||
prevPosition: prev.currentPosition,
|
||||
newPosition: newState.currentPosition,
|
||||
stateChanged:
|
||||
prev.currentPosition.x !== newState.currentPosition.x ||
|
||||
prev.currentPosition.y !== newState.currentPosition.y,
|
||||
});
|
||||
return newState;
|
||||
});
|
||||
|
||||
|
|
@ -3646,13 +3601,6 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
|||
},
|
||||
);
|
||||
|
||||
console.log("🎯 격자 스냅 적용됨:", {
|
||||
componentType: draggedComponent?.type,
|
||||
resolution: `${screenResolution.width}x${screenResolution.height}`,
|
||||
originalPosition: dragState.currentPosition,
|
||||
snappedPosition: finalPosition,
|
||||
columnWidth: currentGridInfo.columnWidth,
|
||||
});
|
||||
}
|
||||
|
||||
// 스냅으로 인한 추가 이동 거리 계산
|
||||
|
|
@ -3717,28 +3665,6 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
|||
height: snappedHeight,
|
||||
};
|
||||
|
||||
console.log("🎯 드래그 종료 시 그룹 내부 컴포넌트 격자 스냅 (패딩 고려):", {
|
||||
componentId: comp.id,
|
||||
parentId: comp.parentId,
|
||||
beforeSnap: {
|
||||
x: originalComponent.position.x + totalDeltaX,
|
||||
y: originalComponent.position.y + totalDeltaY,
|
||||
},
|
||||
calculation: {
|
||||
effectiveX,
|
||||
effectiveY,
|
||||
columnIndex,
|
||||
rowIndex,
|
||||
columnWidth,
|
||||
fullColumnWidth,
|
||||
widthInColumns,
|
||||
gap: gap || 16,
|
||||
padding,
|
||||
},
|
||||
afterSnap: newPosition,
|
||||
afterSizeSnap: newSize,
|
||||
});
|
||||
|
||||
return {
|
||||
...comp,
|
||||
position: newPosition as Position,
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
// 로컬 상태 관리 (실시간 입력 반영)
|
||||
const [localInputs, setLocalInputs] = useState({
|
||||
text: config.text !== undefined ? config.text : "버튼",
|
||||
actionType: String(config.action?.type || "save"),
|
||||
modalTitle: String(config.action?.modalTitle || ""),
|
||||
modalDescription: String(config.action?.modalDescription || ""),
|
||||
editModalTitle: String(config.action?.editModalTitle || ""),
|
||||
|
|
@ -135,13 +136,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
|
||||
// "flow-widget" 체크
|
||||
const isFlow = compType === "flow-widget" || compType?.toLowerCase().includes("flow");
|
||||
|
||||
if (isFlow) {
|
||||
console.log("✅ 플로우 위젯 발견!", { id: comp.id, componentType: comp.componentType });
|
||||
}
|
||||
return isFlow;
|
||||
});
|
||||
console.log("🎯 플로우 위젯 존재 여부:", found);
|
||||
return found;
|
||||
}, [allComponents]);
|
||||
|
||||
|
|
@ -152,6 +148,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
|
||||
setLocalInputs({
|
||||
text: latestConfig.text !== undefined ? latestConfig.text : "버튼",
|
||||
actionType: String(latestAction.type || "save"),
|
||||
modalTitle: String(latestAction.modalTitle || ""),
|
||||
modalDescription: String(latestAction.modalDescription || ""),
|
||||
editModalTitle: String(latestAction.editModalTitle || ""),
|
||||
|
|
@ -168,7 +165,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
setTitleBlocks([]);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [component.id]);
|
||||
}, [component.id, component.componentConfig?.action?.type]);
|
||||
|
||||
// 🆕 제목 블록 핸들러
|
||||
const addTextBlock = () => {
|
||||
|
|
@ -251,7 +248,6 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
label: table.displayName || table.tableName,
|
||||
}));
|
||||
setAvailableTables(tables);
|
||||
console.log("✅ 전체 테이블 목록 로드 성공:", tables.length);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("테이블 목록 로드 실패:", error);
|
||||
|
|
@ -777,14 +773,6 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
// console.log("🔧 config-panels/ButtonConfigPanel 렌더링:", {
|
||||
// component,
|
||||
// config,
|
||||
// action: config.action,
|
||||
// actionType: config.action?.type,
|
||||
// screensCount: screens.length,
|
||||
// });
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
|
|
@ -804,9 +792,11 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
<div>
|
||||
<Label htmlFor="button-action">버튼 액션</Label>
|
||||
<Select
|
||||
key={`action-${component.id}-${component.componentConfig?.action?.type || "save"}`}
|
||||
value={component.componentConfig?.action?.type || "save"}
|
||||
key={`action-${component.id}`}
|
||||
value={localInputs.actionType}
|
||||
onValueChange={(value) => {
|
||||
// 🔥 로컬 상태 먼저 업데이트
|
||||
setLocalInputs((prev) => ({ ...prev, actionType: value }));
|
||||
// 🔥 action.type 업데이트
|
||||
onUpdateProperty("componentConfig.action.type", value);
|
||||
|
||||
|
|
@ -854,7 +844,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
</div>
|
||||
|
||||
{/* 모달 열기 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "modal" && (
|
||||
{localInputs.actionType === "modal" && (
|
||||
<div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">모달 설정</h4>
|
||||
|
||||
|
|
@ -1748,7 +1738,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 수정 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "edit" && (
|
||||
{localInputs.actionType === "edit" && (
|
||||
<div className="bg-success/10 mt-4 space-y-4 rounded-lg border p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">수정 설정</h4>
|
||||
|
||||
|
|
@ -2005,7 +1995,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 복사 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "copy" && (
|
||||
{localInputs.actionType === "copy" && (
|
||||
<div className="mt-4 space-y-4 rounded-lg border bg-blue-50 p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">복사 설정 (품목코드 자동 초기화)</h4>
|
||||
|
||||
|
|
@ -2160,7 +2150,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 테이블 이력 보기 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "view_table_history" && (
|
||||
{localInputs.actionType === "view_table_history" && (
|
||||
<div className="mt-4 space-y-4">
|
||||
<div>
|
||||
<Label>
|
||||
|
|
@ -2221,7 +2211,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 페이지 이동 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "navigate" && (
|
||||
{localInputs.actionType === "navigate" && (
|
||||
<div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">페이지 이동 설정</h4>
|
||||
|
||||
|
|
@ -2317,7 +2307,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 엑셀 다운로드 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "excel_download" && (
|
||||
{localInputs.actionType === "excel_download" && (
|
||||
<div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">엑셀 다운로드 설정</h4>
|
||||
|
||||
|
|
@ -2356,7 +2346,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 엑셀 업로드 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "excel_upload" && (
|
||||
{localInputs.actionType === "excel_upload" && (
|
||||
<ExcelUploadConfigSection
|
||||
config={config}
|
||||
onUpdateProperty={onUpdateProperty}
|
||||
|
|
@ -2366,7 +2356,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 바코드 스캔 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "barcode_scan" && (
|
||||
{localInputs.actionType === "barcode_scan" && (
|
||||
<div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">📷 바코드 스캔 설정</h4>
|
||||
|
||||
|
|
@ -2413,7 +2403,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 코드 병합 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "code_merge" && (
|
||||
{localInputs.actionType === "code_merge" && (
|
||||
<div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">🔀 코드 병합 설정</h4>
|
||||
|
||||
|
|
@ -2460,14 +2450,14 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 공차등록 설정 - 운행알림으로 통합되어 주석 처리 */}
|
||||
{/* {(component.componentConfig?.action?.type || "save") === "empty_vehicle" && (
|
||||
{/* {localInputs.actionType === "empty_vehicle" && (
|
||||
<div className="mt-4 space-y-4 rounded-lg border bg-muted/50 p-4">
|
||||
... 공차등록 설정 UI 생략 ...
|
||||
</div>
|
||||
)} */}
|
||||
|
||||
{/* 운행알림 및 종료 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "operation_control" && (
|
||||
{localInputs.actionType === "operation_control" && (
|
||||
<div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">🚗 운행알림 및 종료 설정</h4>
|
||||
|
||||
|
|
@ -2908,7 +2898,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
)}
|
||||
|
||||
{/* 데이터 전달 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "transferData" && (
|
||||
{localInputs.actionType === "transferData" && (
|
||||
<div className="bg-muted/50 mt-4 space-y-4 rounded-lg border p-4">
|
||||
<h4 className="text-foreground text-sm font-medium">📦 데이터 전달 설정</h4>
|
||||
|
||||
|
|
@ -3618,7 +3608,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
</div>
|
||||
|
||||
{/* 제어 기능 섹션 - 엑셀 업로드가 아닐 때만 표시 */}
|
||||
{(component.componentConfig?.action?.type || "save") !== "excel_upload" && (
|
||||
{localInputs.actionType !== "excel_upload" && (
|
||||
<div className="border-border mt-8 border-t pt-6">
|
||||
<ImprovedButtonControlConfigPanel component={component} onUpdateProperty={onUpdateProperty} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -307,14 +307,8 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
|
|||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
console.warn("⚠️ ComponentRegistry에서 ConfigPanel을 찾을 수 없음 - switch case로 이동:", {
|
||||
componentId,
|
||||
definitionName: definition?.name,
|
||||
hasDefinition: !!definition,
|
||||
});
|
||||
// ConfigPanel이 없으면 아래 switch case로 넘어감
|
||||
}
|
||||
// ConfigPanel이 없으면 아래 switch case로 넘어감
|
||||
}
|
||||
|
||||
// 기존 하드코딩된 설정 패널들 (레거시)
|
||||
|
|
@ -322,6 +316,7 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
|
|||
case "button":
|
||||
case "button-primary":
|
||||
case "button-secondary":
|
||||
case "v2-button-primary":
|
||||
// 🔧 component.id만 key로 사용 (unmount 방지)
|
||||
return (
|
||||
<ButtonConfigPanel
|
||||
|
|
@ -957,6 +952,7 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
|
|||
"button",
|
||||
"button-primary",
|
||||
"button-secondary",
|
||||
"v2-button-primary",
|
||||
"card",
|
||||
"dashboard",
|
||||
"stats",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import React, { useState, useEffect, useMemo, useCallback } from "react";
|
||||
import React, { useState, useEffect, useMemo, useCallback, useRef } from "react";
|
||||
import { ComponentRendererProps } from "@/types/component";
|
||||
import { RepeatContainerConfig, RepeatItemContext, SlotComponentConfig } from "./types";
|
||||
import { Repeat, Package, ChevronLeft, ChevronRight, Plus } from "lucide-react";
|
||||
|
|
@ -31,6 +31,14 @@ interface RepeatContainerComponentProps extends ComponentRendererProps {
|
|||
onUpdateComponent?: (updates: Partial<RepeatContainerConfig>) => void;
|
||||
}
|
||||
|
||||
// 섹션별 폼 데이터를 저장하는 타입
|
||||
interface SectionFormData {
|
||||
index: number;
|
||||
originalData: Record<string, any>;
|
||||
formData: Record<string, any>;
|
||||
isDirty: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 리피터 컨테이너 컴포넌트
|
||||
* 데이터 수만큼 내부 컨텐츠를 반복 렌더링하는 컨테이너
|
||||
|
|
@ -125,6 +133,9 @@ export function RepeatContainerComponent({
|
|||
const [selectedIndices, setSelectedIndices] = useState<number[]>([]);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
// 섹션별 폼 데이터 관리 (각 반복 아이템별로 독립적인 폼 데이터)
|
||||
const sectionFormDataRef = useRef<Map<number, SectionFormData>>(new Map());
|
||||
|
||||
// 실제 사용할 테이블명
|
||||
const effectiveTableName = useCustomTable ? customTableName : tableName;
|
||||
|
|
@ -133,9 +144,116 @@ export function RepeatContainerComponent({
|
|||
useEffect(() => {
|
||||
if (externalData && Array.isArray(externalData)) {
|
||||
setData(externalData);
|
||||
// 데이터가 변경되면 섹션별 폼 데이터 초기화
|
||||
sectionFormDataRef.current.clear();
|
||||
}
|
||||
}, [externalData]);
|
||||
|
||||
// 섹션별 폼 데이터 변경 핸들러
|
||||
const handleSectionFormDataChange = useCallback(
|
||||
(sectionIndex: number, key: string, value: any, originalData: Record<string, any>) => {
|
||||
const currentSection = sectionFormDataRef.current.get(sectionIndex) || {
|
||||
index: sectionIndex,
|
||||
originalData: originalData,
|
||||
formData: { ...originalData },
|
||||
isDirty: false,
|
||||
};
|
||||
|
||||
// 폼 데이터 업데이트
|
||||
currentSection.formData[key] = value;
|
||||
|
||||
// 변경 여부 확인 (원본 데이터와 비교)
|
||||
currentSection.isDirty = Object.keys(currentSection.formData).some(
|
||||
(k) => currentSection.formData[k] !== currentSection.originalData[k]
|
||||
);
|
||||
|
||||
sectionFormDataRef.current.set(sectionIndex, currentSection);
|
||||
|
||||
// 상위로 변경 알림 (기존 방식 호환)
|
||||
if (onFormDataChange) {
|
||||
onFormDataChange(`_repeat_${sectionIndex}_${key}`, value);
|
||||
}
|
||||
},
|
||||
[onFormDataChange]
|
||||
);
|
||||
|
||||
// beforeFormSave 이벤트 리스너 - 외부 저장 버튼 클릭 시 섹션별 데이터 수집
|
||||
useEffect(() => {
|
||||
if (isDesignMode) return;
|
||||
|
||||
const handleBeforeFormSave = (event: Event) => {
|
||||
if (!(event instanceof CustomEvent) || !event.detail) return;
|
||||
|
||||
const componentKey = component?.id || effectiveTableName || "repeat_container_data";
|
||||
|
||||
// 섹션별 데이터 수집
|
||||
const sectionsData: any[] = [];
|
||||
const dirtySectionsData: any[] = [];
|
||||
|
||||
// data 배열의 각 아이템에 대해 폼 데이터 수집
|
||||
data.forEach((originalRow, index) => {
|
||||
const sectionData = sectionFormDataRef.current.get(index);
|
||||
|
||||
if (sectionData) {
|
||||
// 섹션별 폼 데이터가 있는 경우
|
||||
const mergedData = {
|
||||
...originalRow,
|
||||
...sectionData.formData,
|
||||
_sectionIndex: index,
|
||||
_isDirty: sectionData.isDirty,
|
||||
_targetTable: effectiveTableName,
|
||||
};
|
||||
sectionsData.push(mergedData);
|
||||
|
||||
// 변경된 섹션만 별도로 수집
|
||||
if (sectionData.isDirty) {
|
||||
dirtySectionsData.push(mergedData);
|
||||
}
|
||||
} else {
|
||||
// 폼 데이터가 없으면 원본 데이터 사용
|
||||
sectionsData.push({
|
||||
...originalRow,
|
||||
_sectionIndex: index,
|
||||
_isDirty: false,
|
||||
_targetTable: effectiveTableName,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// event.detail.formData에 수집된 데이터 추가
|
||||
if (event.detail.formData) {
|
||||
// 전체 섹션 데이터 (배열)
|
||||
event.detail.formData[componentKey] = sectionsData;
|
||||
|
||||
// 변경된 섹션만 (저장 최적화용)
|
||||
event.detail.formData[`${componentKey}_dirty`] = dirtySectionsData;
|
||||
|
||||
// 테이블별 그룹화 (멀티테이블 저장용)
|
||||
if (effectiveTableName) {
|
||||
if (!event.detail.formData._repeatContainerTables) {
|
||||
event.detail.formData._repeatContainerTables = {};
|
||||
}
|
||||
event.detail.formData._repeatContainerTables[effectiveTableName] = dirtySectionsData.length > 0
|
||||
? dirtySectionsData
|
||||
: sectionsData;
|
||||
}
|
||||
|
||||
console.log("[RepeatContainer] beforeFormSave 데이터 수집 완료:", {
|
||||
componentKey,
|
||||
tableName: effectiveTableName,
|
||||
totalSections: sectionsData.length,
|
||||
dirtySections: dirtySectionsData.length,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("beforeFormSave", handleBeforeFormSave as EventListener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("beforeFormSave", handleBeforeFormSave as EventListener);
|
||||
};
|
||||
}, [isDesignMode, component?.id, effectiveTableName, data]);
|
||||
|
||||
// 컴포넌트 데이터 변경 이벤트 리스닝 (componentId 또는 tableName으로 매칭)
|
||||
useEffect(() => {
|
||||
if (isDesignMode) return;
|
||||
|
|
@ -167,6 +285,8 @@ export function RepeatContainerComponent({
|
|||
setData(eventData);
|
||||
setCurrentPage(1);
|
||||
setSelectedIndices([]);
|
||||
// 데이터 변경 시 섹션별 폼 데이터 초기화
|
||||
sectionFormDataRef.current.clear();
|
||||
} else {
|
||||
console.log("⚠️ 리피터: 컴포넌트 ID 불일치로 무시", { expected: dataSourceComponentId, received: componentId });
|
||||
}
|
||||
|
|
@ -179,6 +299,8 @@ export function RepeatContainerComponent({
|
|||
setData(eventData);
|
||||
setCurrentPage(1);
|
||||
setSelectedIndices([]);
|
||||
// 데이터 변경 시 섹션별 폼 데이터 초기화
|
||||
sectionFormDataRef.current.clear();
|
||||
} else if (effectiveTableName) {
|
||||
console.log("⚠️ 리피터: 테이블명 불일치로 무시", { expected: effectiveTableName, received: eventTableName });
|
||||
}
|
||||
|
|
@ -409,9 +531,8 @@ export function RepeatContainerComponent({
|
|||
companyCode={companyCode}
|
||||
formData={itemFormData}
|
||||
onFormDataChange={(key, value) => {
|
||||
if (onFormDataChange) {
|
||||
onFormDataChange(`_repeat_${context.index}_${key}`, value);
|
||||
}
|
||||
// 섹션별 폼 데이터 관리
|
||||
handleSectionFormDataChange(context.index, key, value, context.data);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -430,7 +551,7 @@ export function RepeatContainerComponent({
|
|||
userId,
|
||||
userName,
|
||||
companyCode,
|
||||
onFormDataChange,
|
||||
handleSectionFormDataChange,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue