diff --git a/INDEX.md b/INDEX.md index 23f0ba9..02e9e3a 100644 --- a/INDEX.md +++ b/INDEX.md @@ -289,6 +289,7 @@ DB 도메인별: | [barobill-react-improvement-request.md](plans/barobill-react-improvement-request.md) | 바로빌 React 개선 요청서 (동기화 버튼, 인증서/잔액 표시, 계좌/카드 목록, Server Action 6개) | | [receiving-lot-auto-generate-request.md](plans/receiving-lot-auto-generate-request.md) | 입고등록 원자재로트번호 자동채번 적용 요청 (읽기전용 변경, API 자동생성) | | [stock-detail-inventory-adjustment-request.md](plans/stock-detail-inventory-adjustment-request.md) | 재고 조정 위치 이동 요청 (입고관리 → 재고 상세 화면) | +| [bom-tree-visualization-request.md](plans/bom-tree-visualization-request.md) | BOM Tree 시각화 React 구현 요청 (API 완료, 재귀 트리 UI) | ### frontend/integration/ — 프론트엔드 개발 가이드 diff --git a/plans/bom-tree-visualization-request.md b/plans/bom-tree-visualization-request.md new file mode 100644 index 0000000..ed30cf6 --- /dev/null +++ b/plans/bom-tree-visualization-request.md @@ -0,0 +1,292 @@ +# BOM Tree 시각화 React 구현 요청 + +**날짜:** 2026-03-18 +**요청자:** R&D실 (백엔드) +**대상:** React 프론트엔드 +**API 상태:** 구현 완료 (tree 엔드포인트 존재) + +--- + +## 변경 요약 + +품목관리 또는 품목기준관리에서 **BOM(Bill of Materials) 트리를 시각적으로 표시**하는 UI를 추가한다. + +--- + +## 1. 배경 + +### 현재 상태 + +| 시스템 | BOM Tree UI | 비고 | +|--------|:----------:|------| +| MNG (Laravel) | ✅ 구현됨 | 3-panel: 검색 + 트리 + 상세 | +| 서비스 (React) | ❌ 미구현 | API는 있으나 UI 없음 | + +### MNG 참고 화면 + +``` +MNG 품목관리 (item-management) +┌──────────┬──────────────────────────┬──────────────┐ +│ 품목 검색 │ BOM 트리 시각화 │ 품목 상세 │ +│ │ │ │ +│ 🔍 검색 │ ▼ [FG] 제품A │ 코드: P-001 │ +│ │ ├─ [PT] 부품B (x2) │ 이름: 제품A │ +│ · P-001 │ │ └─ [RM] SUS 철판 (x5)│ 유형: 완제품 │ +│ · P-002 │ ├─ [SM] 볼트 M8 (x10) │ │ +│ │ └─ [RM] EGI 판재 (x3) │ │ +└──────────┴──────────────────────────┴──────────────┘ +``` + +--- + +## 2. 구현 위치 + +### 안 1: 품목 상세 화면에 BOM 탭 추가 (권장) + +``` +품목관리 > 품목 상세 (/master-data/item-management/{id}) + ├─ 기본정보 (기존) + ├─ BOM Tree 탭 ← 신규 + └─ 기타 탭 +``` + +### 안 2: 독립 BOM 뷰어 페이지 + +``` +기준정보 관리 > BOM 뷰어 (/master-data/bom-viewer) + ├─ 품목 검색 (좌측) + └─ BOM Tree 시각화 (우측) +``` + +> 구현 위치는 프론트엔드 개발자 판단에 맡김. 기존 화면 구조에 맞는 위치 선택. + +--- + +## 3. BOM Tree UI 명세 + +### 3.1 트리 노드 구조 + +``` +▼ [FG] P-001 | 제품A x1 + ├─ ▼ [PT] PT-001 | 가이드레일 조립품 x2 + │ ├─ [RM] 20000 | SUS1.2*1219*2438 x5 + │ ├─ [SM] 80067 | 가스켓쫄대(삼각) x10 + │ └─ [SM] 80061 | 8인치후렌지 x2 + ├─ [RM] 30000 | EGI1.2*1219*2438 x3 + └─ [SM] 00043 | 불연지퍼 x20 +``` + +### 3.2 노드 요소 + +| 요소 | 설명 | +|------|------| +| ▼/▶ | 펼침/접힘 토글 (자식 있을 때만) | +| 유형 뱃지 | `[FG]` `[PT]` `[RM]` `[SM]` `[CS]` — 색상 구분 | +| 코드 | 품목코드 (monospace) | +| 품목명 | 품목 이름 | +| 수량 | `x2`, `x5` — 부모 대비 필요 수량 | + +### 3.3 유형별 뱃지 색상 + +| 유형 | 코드 | 색상 | 설명 | +|------|------|------|------| +| 완제품 | FG | 🔵 blue | 최상위 제품 | +| 부품 | PT | 🟢 green | 조립 부품 (자식 가질 수 있음) | +| 원자재 | RM | 🟠 orange | 미가공 원자재 (leaf) | +| 부자재 | SM | 🟣 purple | 부자재 (leaf) | +| 소모품 | CS | ⚪ gray | 소모품 (leaf) | + +### 3.4 인터랙션 + +| 동작 | 설명 | +|------|------| +| 노드 펼침/접힘 | 화살표 클릭 시 자식 노드 토글 | +| 전체 펼침 | 버튼 클릭 시 모든 노드 펼침 | +| 전체 접힘 | 버튼 클릭 시 루트만 표시 | +| 노드 클릭 | (선택) 해당 품목 상세 정보 표시 또는 품목 상세 페이지 이동 | + +--- + +## 4. API 스펙 (구현 완료) + +### 4.1 Items BOM Tree + +``` +GET /api/v1/items/{id}/bom/tree +``` + +**응답:** + +```json +{ + "success": true, + "data": { + "id": 100, + "code": "P-001", + "name": "제품A", + "item_type": "FG", + "specification": "...", + "unit": "EA", + "quantity": 1, + "depth": 0, + "children": [ + { + "id": 200, + "code": "PT-001", + "name": "가이드레일 조립품", + "item_type": "PT", + "quantity": 2, + "depth": 1, + "children": [ + { + "id": 300, + "code": "20000", + "name": "SUS1.2*1219*2438", + "item_type": "RM", + "quantity": 5, + "depth": 2, + "children": [] + } + ] + }, + { + "id": 400, + "code": "00043", + "name": "불연지퍼", + "item_type": "SM", + "quantity": 20, + "depth": 1, + "children": [] + } + ] + } +} +``` + +### 4.2 Products BOM Tree (제품 기반) + +``` +GET /api/v1/products/{id}/bom +``` + +**응답 구조 동일** — `type` 필드가 `PRODUCT` 또는 `MATERIAL`로 구분. + +### 4.3 BOM Flat List (참고) + +``` +GET /api/v1/items/{id}/bom → 1단계 자식만 (flat) +GET /api/v1/items/{id}/bom/tree → 전체 계층 (recursive) +``` + +--- + +## 5. TypeScript 타입 + +```typescript +interface BomTreeNode { + id: number; + code: string; + name: string; + item_type: 'FG' | 'PT' | 'RM' | 'SM' | 'CS'; + specification?: string; + unit?: string; + quantity: number; + depth: number; + children: BomTreeNode[]; +} + +// 유형별 뱃지 색상 매핑 +const ITEM_TYPE_COLORS: Record = { + FG: 'bg-blue-100 text-blue-800', + PT: 'bg-green-100 text-green-800', + RM: 'bg-orange-100 text-orange-800', + SM: 'bg-purple-100 text-purple-800', + CS: 'bg-gray-100 text-gray-800', +}; + +const ITEM_TYPE_LABELS: Record = { + FG: '완제품', PT: '부품', RM: '원자재', SM: '부자재', CS: '소모품', +}; +``` + +--- + +## 6. 컴포넌트 구조 제안 + +``` +BomTreeViewer/ +├─ BomTreeViewer.tsx # 메인 컨테이너 (API 호출 + 상태 관리) +├─ BomTreeNode.tsx # 개별 노드 (재귀 렌더링) +├─ BomTreeToolbar.tsx # 전체 펼침/접힘 버튼 +└─ types.ts # BomTreeNode 타입 +``` + +### 재귀 렌더링 핵심 + +```tsx +function BomTreeNode({ node, level = 0 }: { node: BomTreeNode; level?: number }) { + const [isOpen, setIsOpen] = useState(level < 2); // 2단계까지 기본 펼침 + const hasChildren = node.children.length > 0; + + return ( +
+
+ {/* 펼침/접힘 */} + {hasChildren ? ( + + ) : } + + {/* 유형 뱃지 */} + + {node.item_type} + + + {/* 코드 + 이름 */} + {node.code} + {node.name} + + {/* 수량 */} + x{node.quantity} +
+ + {/* 재귀: 자식 노드 */} + {isOpen && hasChildren && node.children.map(child => ( + + ))} +
+ ); +} +``` + +--- + +## 7. Server Action 예시 + +```typescript +// actions.ts +export async function getBomTree(itemId: number) { + return fetchApi(`/items/${itemId}/bom/tree`); +} +``` + +--- + +## 작업 체크리스트 + +- [ ] `BomTreeViewer` 컴포넌트 생성 (재귀 트리 렌더링) +- [ ] 유형별 뱃지 색상 적용 (FG/PT/RM/SM/CS) +- [ ] 펼침/접힘 토글 구현 +- [ ] 전체 펼침/접힘 버튼 +- [ ] `GET /api/v1/items/{id}/bom/tree` 연동 +- [ ] 품목 상세 또는 독립 페이지에 배치 +- [ ] (선택) 노드 클릭 시 품목 상세 이동 + +--- + +## 참고 + +- MNG BOM Tree 구현: `mng/resources/views/item-management/index.blade.php` (라인 248-316) +- API Tree 빌더: `api/app/Services/Products/ProductComponentResolver.php` +- Items BOM API: `api/app/Http/Controllers/Api/V1/ItemsBomController.php`