From a9135165d9941a4390c690822d2b2e643a3d507b Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Fri, 12 Dec 2025 10:55:09 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20UniversalFormModal=20=EC=B1=84=EB=B2=88?= =?UTF-8?q?=20=EA=B7=9C=EC=B9=99=20=EC=9E=90=EB=8F=99=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모달 재오픈 시 동일 번호 유지 (previewCode 사용) - 저장 시 정상적인 순번 증가 (allocateCode에서 nextSequence 사용) - refreshKey를 React key로 전달하여 컴포넌트 강제 리마운트 - ruleId를 부모 컴포넌트까지 전달하여 buttonActions에서 감지 - 미리보기와 저장 번호 일치 (currentSequence + 1 통일) --- .../src/services/numberingRuleService.ts | 5 ++- .../lib/registry/DynamicComponentRenderer.tsx | 3 +- .../UniversalFormModalComponent.tsx | 42 +++++++++++++------ 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/backend-node/src/services/numberingRuleService.ts b/backend-node/src/services/numberingRuleService.ts index 4a9b53a4..8208ecc5 100644 --- a/backend-node/src/services/numberingRuleService.ts +++ b/backend-node/src/services/numberingRuleService.ts @@ -959,9 +959,10 @@ class NumberingRuleService { switch (part.partType) { case "sequence": { - // 순번 (자동 증가 숫자) + // 순번 (자동 증가 숫자 - 다음 번호 사용) const length = autoConfig.sequenceLength || 3; - return String(rule.currentSequence || 1).padStart(length, "0"); + const nextSequence = (rule.currentSequence || 0) + 1; + return String(nextSequence).padStart(length, "0"); } case "number": { diff --git a/frontend/lib/registry/DynamicComponentRenderer.tsx b/frontend/lib/registry/DynamicComponentRenderer.tsx index 4d12309b..dc92c38a 100644 --- a/frontend/lib/registry/DynamicComponentRenderer.tsx +++ b/frontend/lib/registry/DynamicComponentRenderer.tsx @@ -468,7 +468,8 @@ export const DynamicComponentRenderer: React.FC = return rendererInstance.render(); } else { // 함수형 컴포넌트 - return ; + // refreshKey를 React key로 전달하여 컴포넌트 리마운트 강제 + return ; } } } catch (error) { diff --git a/frontend/lib/registry/components/universal-form-modal/UniversalFormModalComponent.tsx b/frontend/lib/registry/components/universal-form-modal/UniversalFormModalComponent.tsx index a78d2e95..14f84858 100644 --- a/frontend/lib/registry/components/universal-form-modal/UniversalFormModalComponent.tsx +++ b/frontend/lib/registry/components/universal-form-modal/UniversalFormModalComponent.tsx @@ -23,7 +23,7 @@ import { ChevronDown, ChevronUp, Plus, Trash2, RefreshCw, Loader2 } from "lucide import { toast } from "sonner"; import { cn } from "@/lib/utils"; import { apiClient } from "@/lib/api/client"; -import { generateNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule"; +import { generateNumberingCode, allocateNumberingCode, previewNumberingCode } from "@/lib/api/numberingRule"; import { useCascadingDropdown } from "@/hooks/useCascadingDropdown"; import { CascadingDropdownConfig } from "@/types/screen-management"; @@ -257,8 +257,11 @@ export function UniversalFormModalComponent({ // 외부 formData에 이미 값이 있어도 UniversalFormModal 값으로 덮어씀 // (UniversalFormModal이 해당 필드의 주인이므로) for (const [key, value] of Object.entries(formData)) { - // 설정에 정의된 필드만 병합 - if (configuredFields.has(key)) { + // 설정에 정의된 필드 또는 채번 규칙 ID 필드만 병합 + const isConfiguredField = configuredFields.has(key); + const isNumberingRuleId = key.endsWith("_numberingRuleId"); + + if (isConfiguredField || isNumberingRuleId) { if (value !== undefined && value !== null && value !== "") { event.detail.formData[key] = value; console.log(`[UniversalFormModal] 필드 병합: ${key} =`, value); @@ -401,7 +404,7 @@ export function UniversalFormModalComponent({ } isGeneratingRef.current = true; // 진행 중 표시 - console.log('[채번] 생성 시작'); + console.log('[채번] 미리보기 생성 시작'); const updatedData = { ...currentFormData }; let hasChanges = false; @@ -417,17 +420,32 @@ export function UniversalFormModalComponent({ !updatedData[field.columnName] ) { try { - console.log(`[채번 API 호출] ${field.columnName}, ruleId: ${field.numberingRule.ruleId}`); - // generateOnOpen: 모달 열 때 실제 순번 할당 (DB 시퀀스 즉시 증가) - const response = await allocateNumberingCode(field.numberingRule.ruleId); + console.log(`[채번 미리보기 API 호출] ${field.columnName}, ruleId: ${field.numberingRule.ruleId}`); + // generateOnOpen: 미리보기만 표시 (DB 시퀀스 증가 안 함) + const response = await previewNumberingCode(field.numberingRule.ruleId); if (response.success && response.data?.generatedCode) { updatedData[field.columnName] = response.data.generatedCode; + + // 저장 시 실제 할당을 위해 ruleId 저장 (TextInput과 동일한 키 형식) + const ruleIdKey = `${field.columnName}_numberingRuleId`; + updatedData[ruleIdKey] = field.numberingRule.ruleId; + hasChanges = true; numberingGeneratedRef.current = true; // 생성 완료 표시 - console.log(`[채번 완료] ${field.columnName} = ${response.data.generatedCode}`); + console.log(`[채번 미리보기 완료] ${field.columnName} = ${response.data.generatedCode} (저장 시 실제 할당)`); + console.log(`[채번 규칙 ID 저장] ${ruleIdKey} = ${field.numberingRule.ruleId}`); + + // 부모 컴포넌트에도 ruleId 전달 (ModalRepeaterTable → ScreenModal) + if (onChange) { + onChange({ + ...updatedData, + [ruleIdKey]: field.numberingRule.ruleId + }); + console.log(`[채번] 부모에게 ruleId 전달: ${ruleIdKey}`); + } } } catch (error) { - console.error(`채번규칙 생성 실패 (${field.columnName}):`, error); + console.error(`채번규칙 미리보기 실패 (${field.columnName}):`, error); } } } @@ -439,7 +457,7 @@ export function UniversalFormModalComponent({ setFormData(updatedData); } }, - [config], + [config, onChange], ); // 필드 값 변경 핸들러 @@ -659,9 +677,9 @@ export function UniversalFormModalComponent({ const saveSingleRow = useCallback(async () => { const dataToSave = { ...formData }; - // 메타데이터 필드 제거 + // 메타데이터 필드 제거 (채번 규칙 ID는 유지 - buttonActions.ts에서 사용) Object.keys(dataToSave).forEach((key) => { - if (key.startsWith("_")) { + if (key.startsWith("_") && !key.includes("_numberingRuleId")) { delete dataToSave[key]; } });