From d28e703cd2da00e3e5948d9259fdb2647779e8c3 Mon Sep 17 00:00:00 2001 From: kjs Date: Thu, 5 Feb 2026 15:55:32 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20EditModal=EC=97=90=EC=84=9C=20=EC=B1=84?= =?UTF-8?q?=EB=B2=88=20=EA=B7=9C=EC=B9=99=20=ED=95=A0=EB=8B=B9=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B3=91=EB=A0=AC=20=EC=B2=98=EB=A6=AC=20=EC=B5=9C?= =?UTF-8?q?=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - allocateCode 호출 시 Promise.all을 사용하여 여러 채번 필드를 병렬로 처리하도록 개선하였습니다. - 채번 규칙 할당 실패 시 사용자에게 명확한 오류 메시지를 제공하도록 로깅을 강화하였습니다. - 코드 할당 결과를 보다 효율적으로 처리하여 성능을 향상시켰습니다. --- frontend/components/screen/EditModal.tsx | 59 +++++++++++++----------- frontend/components/v2/V2FormContext.tsx | 8 +++- frontend/types/v2-components.ts | 25 ++++++++++ 3 files changed, 64 insertions(+), 28 deletions(-) diff --git a/frontend/components/screen/EditModal.tsx b/frontend/components/screen/EditModal.tsx index 0e28e8ac..877a65c4 100644 --- a/frontend/components/screen/EditModal.tsx +++ b/frontend/components/screen/EditModal.tsx @@ -767,46 +767,51 @@ export const EditModal: React.FC = ({ className }) => { } } - // 채번 규칙이 있는 필드에 대해 allocateCode 호출 + // 채번 규칙이 있는 필드에 대해 allocateCode 호출 (🚀 병렬 처리로 최적화) if (Object.keys(fieldsWithNumbering).length > 0) { console.log("🎯 [EditModal] 채번 규칙 할당 시작, formData:", { - material: formData.material, // 재질 값 로깅 + material: formData.material, allKeys: Object.keys(formData), }); const { allocateNumberingCode } = await import("@/lib/api/numberingRule"); - let hasAllocationFailure = false; - const failedFields: string[] = []; - - for (const [fieldName, ruleId] of Object.entries(fieldsWithNumbering)) { - try { - // 🆕 사용자가 편집한 값을 전달 (수동 입력 부분 추출용) + // 🚀 Promise.all로 병렬 처리 (여러 채번 필드가 있을 경우 성능 향상) + const allocationPromises = Object.entries(fieldsWithNumbering).map( + async ([fieldName, ruleId]) => { const userInputCode = dataToSave[fieldName] as string; - console.log(`🔄 [EditModal] ${fieldName} 필드에 대해 allocateCode 호출: ${ruleId}, 사용자입력: ${userInputCode}`); - const allocateResult = await allocateNumberingCode(ruleId, userInputCode, formData); - - if (allocateResult.success && allocateResult.data?.generatedCode) { - const newCode = allocateResult.data.generatedCode; - console.log(`✅ [EditModal] ${fieldName} 새 코드 할당: ${userInputCode} → ${newCode}`); - dataToSave[fieldName] = newCode; - } else { - console.warn(`⚠️ [EditModal] ${fieldName} 코드 할당 실패:`, allocateResult.error); - if (!dataToSave[fieldName] || dataToSave[fieldName] === "") { - hasAllocationFailure = true; - failedFields.push(fieldName); + console.log(`🔄 [EditModal] ${fieldName} 필드에 대해 allocateCode 호출: ${ruleId}`); + + try { + const allocateResult = await allocateNumberingCode(ruleId, userInputCode, formData); + + if (allocateResult.success && allocateResult.data?.generatedCode) { + return { fieldName, success: true, code: allocateResult.data.generatedCode }; + } else { + console.warn(`⚠️ [EditModal] ${fieldName} 코드 할당 실패:`, allocateResult.error); + return { fieldName, success: false, hasExistingValue: !!(dataToSave[fieldName]) }; } + } catch (allocateError) { + console.error(`❌ [EditModal] ${fieldName} 코드 할당 오류:`, allocateError); + return { fieldName, success: false, hasExistingValue: !!(dataToSave[fieldName]) }; } - } catch (allocateError) { - console.error(`❌ [EditModal] ${fieldName} 코드 할당 오류:`, allocateError); - if (!dataToSave[fieldName] || dataToSave[fieldName] === "") { - hasAllocationFailure = true; - failedFields.push(fieldName); - } + } + ); + + const allocationResults = await Promise.all(allocationPromises); + + // 결과 처리 + const failedFields: string[] = []; + for (const result of allocationResults) { + if (result.success && result.code) { + console.log(`✅ [EditModal] ${result.fieldName} 새 코드 할당: ${result.code}`); + dataToSave[result.fieldName] = result.code; + } else if (!result.hasExistingValue) { + failedFields.push(result.fieldName); } } // 채번 규칙 할당 실패 시 저장 중단 - if (hasAllocationFailure) { + if (failedFields.length > 0) { const fieldNames = failedFields.join(", "); toast.error(`채번 규칙 할당에 실패했습니다 (${fieldNames}). 화면 설정에서 채번 규칙을 확인해주세요.`); console.error(`❌ [EditModal] 채번 규칙 할당 실패로 저장 중단. 실패 필드: ${fieldNames}`); diff --git a/frontend/components/v2/V2FormContext.tsx b/frontend/components/v2/V2FormContext.tsx index 4f2553ac..9473ef75 100644 --- a/frontend/components/v2/V2FormContext.tsx +++ b/frontend/components/v2/V2FormContext.tsx @@ -10,7 +10,7 @@ */ import React, { createContext, useContext, useState, useCallback, useMemo, useRef } from "react"; -import { ConditionalConfig, CascadingConfig } from "@/types/v2-components"; +import { ConditionalConfig, CascadingConfig, LayerConfig, LayerCondition } from "@/types/v2-components"; import { ValidationRule } from "@/types/v2-core"; import type { FormStatus, @@ -89,6 +89,12 @@ export interface V2FormContextValue { addRepeaterRow: (fieldName: string, row: Record) => void; updateRepeaterRow: (fieldName: string, index: number, row: Record) => void; deleteRepeaterRow: (fieldName: string, index: number) => void; + + // 조건부 레이어 시스템 + layers: LayerConfig[]; + setLayers: (layers: LayerConfig[]) => void; + evaluateLayer: (layer: LayerConfig) => boolean; + isComponentVisible: (componentId: string) => boolean; } // ===== Context 생성 ===== diff --git a/frontend/types/v2-components.ts b/frontend/types/v2-components.ts index c0d6ca53..68539c08 100644 --- a/frontend/types/v2-components.ts +++ b/frontend/types/v2-components.ts @@ -544,3 +544,28 @@ export const LEGACY_TO_V2_MAP: Record = { // Button (Input의 버튼 모드) "button-primary": "V2Input", }; + +// ===== 조건부 레이어 시스템 ===== + +/** + * 레이어 조건 설정 + * 특정 필드값에 따라 레이어 활성화 여부를 결정 + */ +export interface LayerCondition { + field: string; // 트리거 필드 (columnName 또는 탭ID) + operator: "=" | "!=" | "in" | "notIn" | "isEmpty" | "isNotEmpty"; + value: string | string[]; // 비교값 +} + +/** + * 레이어 설정 + * 특정 조건이 충족될 때 표시되는 컴포넌트들의 그룹 + */ +export interface LayerConfig { + layerId: string; // 고유 ID + layerName: string; // 표시명 (설정용) + conditions: LayerCondition[]; // 조건 목록 + conditionLogic?: "AND" | "OR"; // 조건 조합 방식 (기본: AND) + targetComponents: string[]; // 표시할 컴포넌트 ID 목록 + alwaysVisible?: boolean; // 항상 표시 (조건 무시) +}