Files
sam-docs/plans/bom-tree-3level-react.md

8.4 KiB

BOM 트리 3단계 구조 — React 구현 요청

작성일: 2026-03-18 요청자: API/MNG 개발팀 대상: React 프론트엔드 상태: API 구현 완료, React 구현 대기


1. 개요

품목관리 > 제품상세 화면의 BOM 표시를 플랫 테이블에서 3단계 트리(FG → 카테고리 → PT)로 개선한다. API가 이미 3단계 구조를 반환하므로, React는 렌더링만 변경하면 된다.

1.1 현재 상태

항목 상태
API BOM 트리 3단계 완료 (GET /api/v1/items/{id}/bom/tree)
API BOM 목록 category 필드 완료 (GET /api/v1/items/{id}/bom)
MNG BOM 트리 3단계 완료 (참고용)
React BOM 표시 플랫 테이블 (개선 필요)

1.2 대상 페이지

/production/screen-production/{code}?mode=view&type=FG&id={id}

1.3 대상 컴포넌트

src/components/items/ItemDetailClient.tsx — 557~611줄 "부품 구성 (BOM)" 섹션


2. 현재 vs 목표 UI

현재 (플랫 테이블)

부품 구성 (BOM)                    총 17개 품목
┌────┬──────────────────────┬──────────────────┬────────┬──────┐
│ 번호 │ 품목코드              │ 품목명           │  수량  │ 단위 │
├────┼──────────────────────┼──────────────────┼────────┼──────┤
│  1 │ EST-RAW-슬랫-방화     │ 스크린 실리카     │ +10.65 │ m²   │
│  2 │ EST-MOTOR-220V-150K  │ 모터 150K(S)     │     x1 │ EA   │
│ .. │ ...17건 나열...       │                  │        │      │
└────┴──────────────────────┴──────────────────┴────────┴──────┘

목표 (3단계 트리 — 카테고리 접힘/펼침)

부품 구성 (BOM)                    총 17개 품목 (6개 그룹)

▼ 주자재 (1건)
  │ EST-RAW-슬랫-방화      스크린 실리카        x10.65  m²
▼ 모터 (1건)
  │ EST-MOTOR-220V-150K   모터 150K(S) (220V)  x1     EA
▼ 제어기 (1건)
  │ EST-CTRL-노출형        제어기 노출형         x1     EA
▼ 절곡품 (9건)
  │ BD-케이스-500*380      케이스 500*380       x3.22   m
  │ BD-케이스용 연기차단... 케이스용 연기차단재   x3.22   m
  │ ...
▶ 부자재 (4건)                               ← 접힌 상태
▼ 검사비 (1건)
  │ EST-INSPECTION         검사비              x1     EA

3. API 응답 구조 (구현 완료)

3.1 BOM 트리 엔드포인트

GET /api/v1/items/{id}/bom/tree

응답 예시 (GET /api/v1/items/15531/bom/tree):

{
  "success": true,
  "message": "...",
  "data": {
    "id": 15531,
    "code": "FG-KSS02-측면형-SUS",
    "name": "KSS02 스크린 SUS마감 측면형",
    "item_type": "FG",
    "unit": "EA",
    "depth": 1,
    "children": [
      {
        "id": 0,
        "code": "",
        "name": "주자재",
        "item_type": "CAT",
        "unit": "",
        "depth": 2,
        "count": 1,
        "children": [
          {
            "id": 15657,
            "code": "EST-RAW-슬랫-방화",
            "name": "스크린 실리카",
            "item_type": "PT",
            "unit": "EA",
            "depth": 3,
            "quantity": 10.65,
            "children": []
          }
        ]
      },
      {
        "id": 0,
        "code": "",
        "name": "모터",
        "item_type": "CAT",
        "unit": "",
        "depth": 2,
        "count": 1,
        "children": [
          {
            "id": 15627,
            "code": "EST-MOTOR-220V-150K",
            "name": "모터 150K(S) (220V)",
            "item_type": "PT",
            "unit": "EA",
            "depth": 3,
            "quantity": 1,
            "children": []
          }
        ]
      },
      {
        "id": 0,
        "name": "절곡품",
        "item_type": "CAT",
        "count": 9,
        "children": [ "...9개 PT 품목..." ]
      },
      {
        "id": 0,
        "name": "부자재",
        "item_type": "CAT",
        "count": 4,
        "children": [ "...4개 PT 품목..." ]
      },
      {
        "id": 0,
        "name": "검사비",
        "item_type": "CAT",
        "count": 1,
        "children": [ "...1개 PT 품목..." ]
      }
    ]
  }
}

3.2 핵심 구조

필드 설명
item_type: "CAT" 카테고리 그룹 노드 (가상 노드, id=0)
item_type: "FG"/"PT" 실제 품목 노드
count CAT 노드에만 존재 — 하위 품목 건수
quantity 품목 노드에만 존재 — 소요 수량
children 하위 노드 배열 (재귀)

3.3 BOM 목록 엔드포인트 (category 필드 포함)

GET /api/v1/items/{id}/bom

각 항목에 category 필드가 추가되었다:

[
  {
    "child_item_id": 15657,
    "child_item_code": "EST-RAW-슬랫-방화",
    "child_item_name": "스크린 실리카",
    "child_item_type": "PT",
    "unit": "m²",
    "quantity": 10.65,
    "category": "주자재"
  }
]

4. React 구현 가이드

4.1 방법 A: BOM 트리 API 활용 (권장)

/api/v1/items/{id}/bom/tree를 호출하여 3단계 구조를 그대로 렌더링한다.

// 1. BOM 트리 데이터 로드
const [bomTree, setBomTree] = useState(null);

useEffect(() => {
  if (item?.id) {
    fetch(`/api/proxy/items/${item.id}/bom/tree`)
      .then(res => res.json())
      .then(data => setBomTree(data.data));
  }
}, [item?.id]);

// 2. 재귀 렌더링
function BomTreeNode({ node }) {
  const [isOpen, setIsOpen] = useState(true);
  const isCategory = node.item_type === 'CAT';

  return (
    <div className={isCategory ? '' : 'ml-4'}>
      <div
        className={`flex items-center gap-2 py-1.5 px-2 rounded ${isCategory ? 'bg-gray-50 cursor-pointer hover:bg-gray-100' : 'hover:bg-gray-50'}`}
        onClick={() => isCategory && setIsOpen(!isOpen)}
      >
        {node.children?.length > 0 && (
          isOpen ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />
        )}
        {isCategory ? (
          <>
            <span className="text-sm font-semibold">{node.name}</span>
            <Badge variant="outline">{node.count}</Badge>
          </>
        ) : (
          <>
            <Badge>{node.item_type}</Badge>
            <span className="text-sm">{node.name}</span>
            <code className="text-xs text-gray-400">{node.code}</code>
            {node.quantity && <span className="ml-auto text-blue-600">x{node.quantity}</span>}
          </>
        )}
      </div>
      {isOpen && node.children?.map((child, i) => (
        <BomTreeNode key={child.id || i} node={child} />
      ))}
    </div>
  );
}

4.2 방법 B: 기존 item.bom의 category로 그룹화

API 추가 호출 없이 기존 item.bom 데이터의 category 필드로 프론트에서 그룹화한다.

const groupedBom = useMemo(() => {
  if (!item.bom) return {};
  const groups: Record<string, typeof item.bom> = {};
  for (const line of item.bom) {
    const cat = line.category || '기타';
    if (!groups[cat]) groups[cat] = [];
    groups[cat].push(line);
  }
  return groups;
}, [item.bom]);

방법 A가 권장 — API가 구조를 보장하므로 프론트 로직이 단순해진다.


5. 수정 대상

파일 수정 내용
src/components/items/ItemDetailClient.tsx 557~611줄 BOM Card 섹션을 트리 UI로 교체
src/types/item.ts (선택) BOMLine 타입에 category?: string 추가

6. 체크리스트

  • BOM 트리 API 호출 (/api/v1/items/{id}/bom/tree) 또는 기존 item.bom의 category 그룹화
  • item_type === 'CAT' 노드는 카테고리 헤더로 렌더링 (접힘/펼침)
  • 카테고리 헤더에 건수(count) Badge 표시
  • 품목 노드에 코드, 품목명, 수량, 단위 표시
  • 기존 BOM 조건 유지 (FG 또는 PT 비절곡품만 표시)
  • MNG 화면(admin.codebridge-x.com > 품목관리)에서 동작 확인 가능

관련 문서

  • changes/20260318_item-management-bom-tree.md — MNG BOM 트리 3단계 구현 완료
  • rules/item-policy.md — 품목 정책

최종 업데이트: 2026-03-18