feat(UniversalFormModal): 수정 모드 INSERT/UPDATE/DELETE 지원
_groupedData를 테이블 섹션에 초기화하여 기존 품목 표시 originalGroupedData로 원본 데이터 보관하여 변경 추적 handleUniversalFormModalTableSectionSave()에 INSERT/UPDATE/DELETE 분기 로직 구현 EditModal, ConditionalSectionViewer에서 UniversalFormModal 감지 시 onSave 미전달 저장 완료 후 closeEditModal 이벤트 발생
This commit is contained in:
@@ -150,46 +150,54 @@ export function ConditionalSectionViewer({
|
||||
/* 실행 모드: 실제 화면 렌더링 */
|
||||
<div className="w-full">
|
||||
{/* 화면 크기만큼의 절대 위치 캔버스 */}
|
||||
<div
|
||||
className="relative mx-auto"
|
||||
style={{
|
||||
width: screenResolution?.width ? `${screenResolution.width}px` : "100%",
|
||||
height: screenResolution?.height ? `${screenResolution.height}px` : "auto",
|
||||
minHeight: "200px",
|
||||
}}
|
||||
>
|
||||
{components.map((component) => {
|
||||
const { position = { x: 0, y: 0, z: 1 }, size = { width: 200, height: 40 } } = component;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={component.id}
|
||||
className="absolute"
|
||||
style={{
|
||||
left: position.x || 0,
|
||||
top: position.y || 0,
|
||||
width: size.width || 200,
|
||||
height: size.height || 40,
|
||||
zIndex: position.z || 1,
|
||||
}}
|
||||
>
|
||||
<DynamicComponentRenderer
|
||||
component={component}
|
||||
isInteractive={true}
|
||||
screenId={screenInfo?.id}
|
||||
tableName={screenInfo?.tableName}
|
||||
userId={userId}
|
||||
userName={userName}
|
||||
companyCode={user?.companyCode}
|
||||
formData={enhancedFormData}
|
||||
onFormDataChange={onFormDataChange}
|
||||
groupedData={groupedData}
|
||||
onSave={onSave}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{/* UniversalFormModal이 있으면 onSave 전달하지 않음 (자체 저장 로직 사용) */}
|
||||
{(() => {
|
||||
const hasUniversalFormModal = components.some(
|
||||
(c) => c.componentType === "universal-form-modal"
|
||||
);
|
||||
return (
|
||||
<div
|
||||
className="relative mx-auto"
|
||||
style={{
|
||||
width: screenResolution?.width ? `${screenResolution.width}px` : "100%",
|
||||
height: screenResolution?.height ? `${screenResolution.height}px` : "auto",
|
||||
minHeight: "200px",
|
||||
}}
|
||||
>
|
||||
{components.map((component) => {
|
||||
const { position = { x: 0, y: 0, z: 1 }, size = { width: 200, height: 40 } } = component;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={component.id}
|
||||
className="absolute"
|
||||
style={{
|
||||
left: position.x || 0,
|
||||
top: position.y || 0,
|
||||
width: size.width || 200,
|
||||
height: size.height || 40,
|
||||
zIndex: position.z || 1,
|
||||
}}
|
||||
>
|
||||
<DynamicComponentRenderer
|
||||
component={component}
|
||||
isInteractive={true}
|
||||
screenId={screenInfo?.id}
|
||||
tableName={screenInfo?.tableName}
|
||||
userId={userId}
|
||||
userName={userName}
|
||||
companyCode={user?.companyCode}
|
||||
formData={enhancedFormData}
|
||||
onFormDataChange={onFormDataChange}
|
||||
groupedData={groupedData}
|
||||
onSave={hasUniversalFormModal ? undefined : onSave}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -339,6 +339,27 @@ export function TableSectionRenderer({
|
||||
// 날짜 일괄 적용 완료 플래그 (컬럼별로 한 번만 적용)
|
||||
const [batchAppliedFields, setBatchAppliedFields] = useState<Set<string>>(new Set());
|
||||
|
||||
// 초기 데이터 로드 완료 플래그 (무한 루프 방지)
|
||||
const initialDataLoadedRef = React.useRef(false);
|
||||
|
||||
// formData에서 초기 테이블 데이터 로드 (수정 모드에서 _groupedData 표시)
|
||||
useEffect(() => {
|
||||
// 이미 초기화되었으면 스킵
|
||||
if (initialDataLoadedRef.current) return;
|
||||
|
||||
const tableSectionKey = `_tableSection_${sectionId}`;
|
||||
const initialData = formData[tableSectionKey];
|
||||
|
||||
if (Array.isArray(initialData) && initialData.length > 0) {
|
||||
console.log("[TableSectionRenderer] 초기 데이터 로드:", {
|
||||
sectionId,
|
||||
itemCount: initialData.length,
|
||||
});
|
||||
setTableData(initialData);
|
||||
initialDataLoadedRef.current = true;
|
||||
}
|
||||
}, [sectionId, formData]);
|
||||
|
||||
// RepeaterColumnConfig로 변환
|
||||
const columns: RepeaterColumnConfig[] = (tableConfig.columns || []).map(convertToRepeaterColumn);
|
||||
|
||||
|
||||
@@ -195,6 +195,10 @@ export function UniversalFormModalComponent({
|
||||
// 로딩 상태
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
// 🆕 수정 모드: 원본 그룹 데이터 (INSERT/UPDATE/DELETE 추적용)
|
||||
const [originalGroupedData, setOriginalGroupedData] = useState<any[]>([]);
|
||||
const groupedDataInitializedRef = useRef(false);
|
||||
|
||||
// 삭제 확인 다이얼로그
|
||||
const [deleteDialog, setDeleteDialog] = useState<{
|
||||
open: boolean;
|
||||
@@ -304,6 +308,12 @@ export function UniversalFormModalComponent({
|
||||
console.log(`[UniversalFormModal] 반복 섹션 병합: ${sectionKey}`, items);
|
||||
}
|
||||
}
|
||||
|
||||
// 🆕 수정 모드: 원본 그룹 데이터 전달 (UPDATE/DELETE 추적용)
|
||||
if (originalGroupedData.length > 0) {
|
||||
event.detail.formData._originalGroupedData = originalGroupedData;
|
||||
console.log(`[UniversalFormModal] 원본 그룹 데이터 병합: ${originalGroupedData.length}개`);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("beforeFormSave", handleBeforeFormSave as EventListener);
|
||||
@@ -311,7 +321,37 @@ export function UniversalFormModalComponent({
|
||||
return () => {
|
||||
window.removeEventListener("beforeFormSave", handleBeforeFormSave as EventListener);
|
||||
};
|
||||
}, [formData, repeatSections, config.sections]);
|
||||
}, [formData, repeatSections, config.sections, originalGroupedData]);
|
||||
|
||||
// 🆕 수정 모드: _groupedData가 있으면 테이블 섹션 초기화
|
||||
useEffect(() => {
|
||||
if (!_groupedData || _groupedData.length === 0) return;
|
||||
if (groupedDataInitializedRef.current) return; // 이미 초기화됨
|
||||
|
||||
// 테이블 타입 섹션 찾기
|
||||
const tableSection = config.sections.find((s) => s.type === "table");
|
||||
if (!tableSection) {
|
||||
console.log("[UniversalFormModal] 테이블 섹션 없음 - _groupedData 무시");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("[UniversalFormModal] 수정 모드 - 테이블 섹션 초기화:", {
|
||||
sectionId: tableSection.id,
|
||||
itemCount: _groupedData.length,
|
||||
});
|
||||
|
||||
// 원본 데이터 저장 (수정/삭제 추적용)
|
||||
setOriginalGroupedData(JSON.parse(JSON.stringify(_groupedData)));
|
||||
|
||||
// 테이블 섹션 데이터 설정
|
||||
const tableSectionKey = `_tableSection_${tableSection.id}`;
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
[tableSectionKey]: _groupedData,
|
||||
}));
|
||||
|
||||
groupedDataInitializedRef.current = true;
|
||||
}, [_groupedData, config.sections]);
|
||||
|
||||
// 필드 레벨 linkedFieldGroup 데이터 로드
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user