diff --git a/backend-node/src/services/numberingRuleService.ts b/backend-node/src/services/numberingRuleService.ts index 0bdec037..4749bde5 100644 --- a/backend-node/src/services/numberingRuleService.ts +++ b/backend-node/src/services/numberingRuleService.ts @@ -1038,6 +1038,7 @@ class NumberingRuleService { if (manualParts.length > 0 && userInputCode) { // 프리뷰 코드를 생성해서 ____ 위치 파악 + // 🔧 category 파트도 처리하여 올바른 템플릿 생성 const previewParts = rule.parts .sort((a: any, b: any) => a.order - b.order) .map((part: any) => { @@ -1054,6 +1055,35 @@ class NumberingRuleService { return autoConfig.textValue || ""; case "date": return "DATEPART"; // 날짜 자리 표시 + case "category": { + // 카테고리 파트: formData에서 실제 값을 가져와서 매핑된 형식 사용 + const categoryKey = autoConfig.categoryKey; + const categoryMappings = autoConfig.categoryMappings || []; + + if (!categoryKey || !formData) { + return "CATEGORY"; // 폴백 + } + + const columnName = categoryKey.includes(".") + ? categoryKey.split(".")[1] + : categoryKey; + const selectedValue = formData[columnName]; + + if (!selectedValue) { + return "CATEGORY"; // 폴백 + } + + const selectedValueStr = String(selectedValue); + const mapping = categoryMappings.find( + (m: any) => { + if (m.categoryValueId?.toString() === selectedValueStr) return true; + if (m.categoryValueLabel === selectedValueStr) return true; + return false; + } + ); + + return mapping?.format || "CATEGORY"; + } default: return ""; } @@ -1165,6 +1195,68 @@ class NumberingRuleService { return autoConfig.textValue || "TEXT"; } + case "category": { + // 카테고리 기반 코드 생성 (allocateCode용) + const categoryKey = autoConfig.categoryKey; // 예: "item_info.material" + const categoryMappings = autoConfig.categoryMappings || []; + + if (!categoryKey || !formData) { + logger.warn("allocateCode: 카테고리 키 또는 폼 데이터 없음", { categoryKey, hasFormData: !!formData }); + return ""; + } + + // categoryKey에서 컬럼명 추출 (예: "item_info.material" -> "material") + const columnName = categoryKey.includes(".") + ? categoryKey.split(".")[1] + : categoryKey; + + // 폼 데이터에서 해당 컬럼의 값 가져오기 + const selectedValue = formData[columnName]; + + logger.info("allocateCode: 카테고리 파트 처리", { + categoryKey, + columnName, + selectedValue, + formDataKeys: Object.keys(formData), + mappingsCount: categoryMappings.length + }); + + if (!selectedValue) { + logger.warn("allocateCode: 카테고리 값이 선택되지 않음", { columnName, formDataKeys: Object.keys(formData) }); + return ""; + } + + // 카테고리 매핑에서 해당 값에 대한 형식 찾기 + const selectedValueStr = String(selectedValue); + const mapping = categoryMappings.find( + (m: any) => { + // ID로 매칭 + if (m.categoryValueId?.toString() === selectedValueStr) return true; + // 라벨로 매칭 + if (m.categoryValueLabel === selectedValueStr) return true; + return false; + } + ); + + if (mapping) { + logger.info("allocateCode: 카테고리 매핑 적용", { + selectedValue, + format: mapping.format, + categoryValueLabel: mapping.categoryValueLabel + }); + return mapping.format || ""; + } + + logger.warn("allocateCode: 카테고리 매핑을 찾을 수 없음", { + selectedValue, + availableMappings: categoryMappings.map((m: any) => ({ + id: m.categoryValueId, + label: m.categoryValueLabel + })) + }); + return ""; + } + default: logger.warn("알 수 없는 파트 타입", { partType: part.partType }); return ""; diff --git a/frontend/components/screen/EditModal.tsx b/frontend/components/screen/EditModal.tsx index 3dccd0db..0e28e8ac 100644 --- a/frontend/components/screen/EditModal.tsx +++ b/frontend/components/screen/EditModal.tsx @@ -769,7 +769,10 @@ export const EditModal: React.FC = ({ className }) => { // 채번 규칙이 있는 필드에 대해 allocateCode 호출 if (Object.keys(fieldsWithNumbering).length > 0) { - console.log("🎯 [EditModal] 채번 규칙 할당 시작"); + console.log("🎯 [EditModal] 채번 규칙 할당 시작, formData:", { + material: formData.material, // 재질 값 로깅 + allKeys: Object.keys(formData), + }); const { allocateNumberingCode } = await import("@/lib/api/numberingRule"); let hasAllocationFailure = false; diff --git a/frontend/components/v2/V2Input.tsx b/frontend/components/v2/V2Input.tsx index 08295ea7..8e27e38f 100644 --- a/frontend/components/v2/V2Input.tsx +++ b/frontend/components/v2/V2Input.tsx @@ -360,6 +360,10 @@ export const V2Input = forwardRef((props, ref) => // 채번 타입 자동생성 상태 const [isGeneratingNumbering, setIsGeneratingNumbering] = useState(false); const hasGeneratedNumberingRef = useRef(false); + + // formData를 ref로 관리하여 closure 문제 해결 (채번 코드 생성 시 최신 값 사용) + const formDataRef = useRef(formData); + formDataRef.current = formData; // tableName 추출 (여러 소스에서 확인) // 1. props에서 직접 전달받은 값 @@ -565,8 +569,14 @@ export const V2Input = forwardRef((props, ref) => return; } - // 채번 코드 생성 (formData 전달하여 카테고리 값 기반 생성) - const previewResponse = await previewNumberingCode(numberingRuleId, formData); + // 채번 코드 생성 (formDataRef.current 사용하여 최신 formData 전달) + const currentFormData = formDataRef.current; + console.log("🔍 [V2Input] 채번 미리보기 호출:", { + numberingRuleId, + formDataKeys: Object.keys(currentFormData), + materialValue: currentFormData.material // 재질 값 로깅 + }); + const previewResponse = await previewNumberingCode(numberingRuleId, currentFormData); if (previewResponse.success && previewResponse.data?.generatedCode) { const generatedCode = previewResponse.data.generatedCode; diff --git a/frontend/lib/registry/components/v2-category-manager/V2CategoryManagerComponent.tsx b/frontend/lib/registry/components/v2-category-manager/V2CategoryManagerComponent.tsx index aee1946d..615ea61d 100644 --- a/frontend/lib/registry/components/v2-category-manager/V2CategoryManagerComponent.tsx +++ b/frontend/lib/registry/components/v2-category-manager/V2CategoryManagerComponent.tsx @@ -115,31 +115,36 @@ export function V2CategoryManagerComponent({ }, []); return ( -
- {/* 좌측: 카테고리 컬럼 리스트 */} +
+ {/* 좌측: 카테고리 컬럼 리스트 - 스크롤 가능 */} {config.showColumnList && ( <> -
- +
+
+ +
{/* 리사이저 */}
)} - {/* 우측: 카테고리 값 관리 */} -
+ {/* 우측: 카테고리 값 관리 - 고정 */} +
{/* 뷰 모드 토글 */} {config.showViewModeToggle && (
@@ -167,8 +172,8 @@ export function V2CategoryManagerComponent({
)} - {/* 카테고리 값 관리 컴포넌트 */} -
+ {/* 카테고리 값 관리 컴포넌트 - 스크롤 가능 */} +
{selectedColumn ? ( viewMode === "tree" ? (