feat: EditModal에서 채번 규칙 할당 로직 병렬 처리 최적화

- allocateCode 호출 시 Promise.all을 사용하여 여러 채번 필드를 병렬로 처리하도록 개선하였습니다.
- 채번 규칙 할당 실패 시 사용자에게 명확한 오류 메시지를 제공하도록 로깅을 강화하였습니다.
- 코드 할당 결과를 보다 효율적으로 처리하여 성능을 향상시켰습니다.
This commit is contained in:
kjs 2026-02-05 15:55:32 +09:00
parent 77fcf1a35a
commit d28e703cd2
3 changed files with 64 additions and 28 deletions

View File

@ -767,46 +767,51 @@ export const EditModal: React.FC<EditModalProps> = ({ 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}`);

View File

@ -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<string, unknown>) => void;
updateRepeaterRow: (fieldName: string, index: number, row: Record<string, unknown>) => void;
deleteRepeaterRow: (fieldName: string, index: number) => void;
// 조건부 레이어 시스템
layers: LayerConfig[];
setLayers: (layers: LayerConfig[]) => void;
evaluateLayer: (layer: LayerConfig) => boolean;
isComponentVisible: (componentId: string) => boolean;
}
// ===== Context 생성 =====

View File

@ -544,3 +544,28 @@ export const LEGACY_TO_V2_MAP: Record<string, V2ComponentType> = {
// 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; // 항상 표시 (조건 무시)
}