대규모 코드 구조 개선: - useFieldDetection: 필드 감지 로직 분리 - useFileHandling: 파일 업로드 로직 분리 - useItemCodeGeneration: 품목코드 자동생성 로직 분리 - usePartTypeHandling: 파트타입 처리 로직 분리 - FormHeader, ValidationAlert, FileUploadFields 컴포넌트 분리 - DuplicateCodeDialog 컴포넌트 분리 - index.tsx 1300줄+ 감소로 가독성 및 유지보수성 향상 - BOM 검색 최적화 (검색어 입력 시에만 API 호출) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
175 lines
6.0 KiB
TypeScript
175 lines
6.0 KiB
TypeScript
'use client';
|
|
|
|
import { useMemo } from 'react';
|
|
import { DynamicFormData, ItemType, StructuredFieldConfig } from '../types';
|
|
import { ItemFieldResponse } from '@/types/item';
|
|
|
|
/**
|
|
* 부품 유형 탐지 결과
|
|
*/
|
|
export interface PartTypeDetectionResult {
|
|
/** 부품 유형 필드 키 (예: 'part_type') */
|
|
partTypeFieldKey: string;
|
|
/** 현재 선택된 부품 유형 값 (예: '절곡 부품') */
|
|
selectedPartType: string;
|
|
/** 절곡 부품 여부 */
|
|
isBendingPart: boolean;
|
|
/** 조립 부품 여부 */
|
|
isAssemblyPart: boolean;
|
|
/** 구매 부품 여부 */
|
|
isPurchasedPart: boolean;
|
|
}
|
|
|
|
/**
|
|
* useFieldDetection 훅 입력 파라미터
|
|
*/
|
|
export interface UseFieldDetectionParams {
|
|
/** 폼 구조 정보 */
|
|
structure: StructuredFieldConfig | null;
|
|
/** 현재 선택된 품목 유형 (FG, PT, SM, RM, CS) */
|
|
selectedItemType: ItemType;
|
|
/** 현재 폼 데이터 */
|
|
formData: DynamicFormData;
|
|
}
|
|
|
|
/**
|
|
* useFieldDetection 훅 반환 타입
|
|
*/
|
|
export interface FieldDetectionResult extends PartTypeDetectionResult {
|
|
/** BOM 필요 체크박스 필드 키 */
|
|
bomRequiredFieldKey: string;
|
|
}
|
|
|
|
/**
|
|
* 필드 탐지 커스텀 훅
|
|
*
|
|
* 폼 구조에서 특정 필드들을 탐지합니다:
|
|
* 1. PT 품목의 부품 유형 필드 (절곡/조립/구매 부품 판별)
|
|
* 2. BOM 필요 체크박스 필드
|
|
*
|
|
* @param params - 훅 입력 파라미터
|
|
* @returns 필드 탐지 결과
|
|
*/
|
|
export function useFieldDetection({
|
|
structure,
|
|
selectedItemType,
|
|
formData,
|
|
}: UseFieldDetectionParams): FieldDetectionResult {
|
|
// 부품 유형 필드 탐지 (PT 품목에서 절곡/조립/구매 부품 판별용)
|
|
const { partTypeFieldKey, selectedPartType, isBendingPart, isAssemblyPart, isPurchasedPart } = useMemo(() => {
|
|
if (!structure || selectedItemType !== 'PT') {
|
|
return {
|
|
partTypeFieldKey: '',
|
|
selectedPartType: '',
|
|
isBendingPart: false,
|
|
isAssemblyPart: false,
|
|
isPurchasedPart: false,
|
|
};
|
|
}
|
|
|
|
let foundPartTypeKey = '';
|
|
|
|
// 모든 필드에서 부품 유형 필드 찾기
|
|
const checkField = (fieldKey: string, field: ItemFieldResponse) => {
|
|
const fieldName = field.field_name || '';
|
|
// part_type, 부품유형, 부품 유형 등 탐지
|
|
const isPartType =
|
|
fieldKey.includes('part_type') ||
|
|
fieldName.includes('부품유형') ||
|
|
fieldName.includes('부품 유형');
|
|
if (isPartType && !foundPartTypeKey) {
|
|
foundPartTypeKey = fieldKey;
|
|
}
|
|
};
|
|
|
|
structure.sections.forEach((section) => {
|
|
section.fields.forEach((f) => {
|
|
const key = f.field.field_key || `field_${f.field.id}`;
|
|
checkField(key, f.field);
|
|
});
|
|
});
|
|
|
|
structure.directFields.forEach((f) => {
|
|
const key = f.field.field_key || `field_${f.field.id}`;
|
|
checkField(key, f.field);
|
|
});
|
|
|
|
const currentPartType = (formData[foundPartTypeKey] as string) || '';
|
|
// "절곡 부품", "BENDING", "절곡부품" 등 다양한 형태 지원
|
|
const isBending = currentPartType.includes('절곡') || currentPartType.toUpperCase() === 'BENDING';
|
|
// "조립 부품", "ASSEMBLY", "조립부품" 등 다양한 형태 지원
|
|
const isAssembly = currentPartType.includes('조립') || currentPartType.toUpperCase() === 'ASSEMBLY';
|
|
// "구매 부품", "PURCHASED", "구매부품" 등 다양한 형태 지원
|
|
const isPurchased = currentPartType.includes('구매') || currentPartType.toUpperCase() === 'PURCHASED';
|
|
|
|
// console.log('[useFieldDetection] 부품 유형 감지:', { partTypeFieldKey: foundPartTypeKey, currentPartType, isBending, isAssembly, isPurchased });
|
|
|
|
return {
|
|
partTypeFieldKey: foundPartTypeKey,
|
|
selectedPartType: currentPartType,
|
|
isBendingPart: isBending,
|
|
isAssemblyPart: isAssembly,
|
|
isPurchasedPart: isPurchased,
|
|
};
|
|
}, [structure, selectedItemType, formData]);
|
|
|
|
// BOM 필요 체크박스 필드 키 탐지 (structure에서 직접 검색)
|
|
const bomRequiredFieldKey = useMemo(() => {
|
|
if (!structure) return '';
|
|
|
|
// 모든 섹션의 필드에서 BOM 관련 체크박스 필드 찾기
|
|
for (const section of structure.sections) {
|
|
for (const f of section.fields) {
|
|
const field = f.field;
|
|
const fieldKey = field.field_key || '';
|
|
const fieldName = field.field_name || '';
|
|
const fieldType = field.field_type || '';
|
|
|
|
// 체크박스 타입이고 BOM 관련 필드인지 확인
|
|
const isCheckbox = fieldType.toLowerCase() === 'checkbox' || fieldType.toLowerCase() === 'boolean';
|
|
const isBomRelated =
|
|
fieldKey.toLowerCase().includes('bom') ||
|
|
fieldName.toLowerCase().includes('bom') ||
|
|
fieldName.includes('부품구성') ||
|
|
fieldKey.includes('부품구성');
|
|
|
|
if (isCheckbox && isBomRelated) {
|
|
// console.log('[useFieldDetection] BOM 체크박스 필드 발견:', { fieldKey, fieldName });
|
|
return field.field_key || `field_${field.id}`;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 직접 필드에서도 찾기
|
|
for (const f of structure.directFields) {
|
|
const field = f.field;
|
|
const fieldKey = field.field_key || '';
|
|
const fieldName = field.field_name || '';
|
|
const fieldType = field.field_type || '';
|
|
|
|
const isCheckbox = fieldType.toLowerCase() === 'checkbox' || fieldType.toLowerCase() === 'boolean';
|
|
const isBomRelated =
|
|
fieldKey.toLowerCase().includes('bom') ||
|
|
fieldName.toLowerCase().includes('bom') ||
|
|
fieldName.includes('부품구성') ||
|
|
fieldKey.includes('부품구성');
|
|
|
|
if (isCheckbox && isBomRelated) {
|
|
// console.log('[useFieldDetection] BOM 체크박스 필드 발견 (직접필드):', { fieldKey, fieldName });
|
|
return field.field_key || `field_${field.id}`;
|
|
}
|
|
}
|
|
|
|
// console.log('[useFieldDetection] BOM 체크박스 필드를 찾지 못함');
|
|
return '';
|
|
}, [structure]);
|
|
|
|
return {
|
|
partTypeFieldKey,
|
|
selectedPartType,
|
|
isBendingPart,
|
|
isAssemblyPart,
|
|
isPurchasedPart,
|
|
bomRequiredFieldKey,
|
|
};
|
|
} |