diff --git a/dev/dev_plans/bending-management/README.md b/dev/dev_plans/bending-management/README.md index cab0be7..7ce7173 100644 --- a/dev/dev_plans/bending-management/README.md +++ b/dev/dev_plans/bending-management/README.md @@ -42,22 +42,42 @@ SAM은 절곡품의 "계산과 조합"(BendingInfoBuilder/PrefixResolver)은 잘 --- -## 작업 순서 +## 작업 순서 및 진행 상태 ``` Step 1 (DB분석) → Step 2 (API) → Step 3 (MNG 화면) → Step 4 (React 연동) -레거시 매핑 options 확장 Blade + HTMX 견적 이미지 -+ 데이터 정리 + 엔드포인트 + 메뉴 등록 +✅ 완료 ✅ 완료 ✅ 완료 (샘플용) ⬜ 미착수 ``` -상세 계획: 아래 문서 참조 +| 문서 | 내용 | 상태 | +|------|------|:---:| +| `step1-데이터분석.md` | 레거시 매핑 + options 확장 | ✅ 완료 | +| `step2-API.md` | API 엔드포인트 + 컨트롤러 설계 | ✅ 완료 | +| `step3-MNG화면.md` | Blade 뷰 + HTMX + 메뉴 등록 | ✅ 완료 | +| `step4-React연동.md` | React 운영 화면 구현 | ⬜ 미착수 | -| 문서 | 내용 | -|------|------| -| `step1-데이터분석.md` | 레거시 매핑 + options 확장 | -| `step2-API.md` | API 엔드포인트 + 컨트롤러 설계 | -| `step3-MNG화면.md` | Blade 뷰 + HTMX + 메뉴 등록 | -| `step4-React연동.md` | 견적 페이지 이미지 컴포넌트 | +### 완료된 작업 (2026-03-16~17) + +**Step 1 완료:** +- `bending:fill-options` — BD-* prefix/분류 속성 자동 보강 (170건) +- `bending:import-legacy` — chandj 전개도(bendingData) 임포트 (139/170건) +- `guiderail:import-legacy` — chandj guiderail 20건 임포트 +- `bending-product:import-legacy` — chandj shutterbox 30건 + bottombar 10건 임포트 + +**Step 2 완료:** +- `BendingItemController` — CRUD + filters + pagination (6 엔드포인트) +- `GuiderailModelController` — CRUD + filters (6 엔드포인트, 3개 카테고리 통합) +- `BendingItemResource` / `GuiderailModelResource` — API 응답 포맷 +- `FormRequest` — Index/Store/Update 유효성 검증 +- `ApiKeyMiddleware` — bending/guiderail/files 화이트리스트 + +**Step 3 완료 (MNG 샘플용):** +- 기초관리: 목록(13컬럼) + 폼(기본정보12필드 + 케이스전용5필드 + 절곡테이블 + 이미지업로드) +- 절곡품: 가이드레일/케이스/하단마감재 별도 메뉴 + 타입별 헤더 분기 +- 절곡품 폼: 부품 추가(기초관리 검색 모달) + 삭제 + 수량/품명/재질 편집 + 절곡테이블 inline 편집 +- 작업지시서: 레거시 포맷 인쇄 페이지 (`/print`) +- 파일: FileViewController (API R2 프록시) + 이미지 업로드/표시 +- DB 메뉴: 기초관리 + 절곡품 + 케이스 + 하단마감재 (4개) --- @@ -271,7 +291,7 @@ AList: [false,false,false...] sum:21, color:false, aAngle:false }, ``` ┌──────────────────────────────────────────────────────────────┐ -│ MNG 사이드바 │ +│ MNG │ │ │ │ 생산 관리 │ │ ├─ 품목기준 필드 관리 │ diff --git a/dev/dev_plans/bending-management/step1-데이터분석.md b/dev/dev_plans/bending-management/step1-데이터분석.md index ae1104b..94499f5 100644 --- a/dev/dev_plans/bending-management/step1-데이터분석.md +++ b/dev/dev_plans/bending-management/step1-데이터분석.md @@ -103,14 +103,58 @@ | `search_keyword` | varchar(50) | 검색어 | | `material_summary` | text | 재질별 폭합 | -### 1-1b. 추가 파악 필요 +### 1-1b. 추가 분석 결과 (완료) -| 작업 | 대상 | 비고 | -|------|------|------| -| BendingInfoBuilder.php 지원 모델 추출 | 코드 분석 | 기존 로직 파악 | -| PrefixResolver.php PREFIX 규칙 추출 | 코드 분석 | 기존 로직 파악 | -| bendingfee 82건 구조 | 절곡 단가 — SAM 연동 필요 여부 | | -| bendingmap 9건 구조 | 매핑 용도 확인 | | +#### BendingInfoBuilder 지원 모델 + +`getMaterialMapping()` (line 924~960)에서 정의: + +| 그룹 | 모델 | 마감재 재질 | 본체 재질 | +|------|------|-----------|----------| +| Group 1 (SUS 전용) | KQTS01, KSS01, KSS02 | SUS 1.2T | EGI 1.55T | +| Group 2 (철재) | KTE01 | EGI 1.55T (SUS마감 시 +SUS 1.2T) | EGI 1.55T | +| Group 3 (기타) | KSE01, KWE01 등 | EGI 1.55T (SUS마감 시 +SUS 1.2T) | EGI 1.55T | + +**미지원 모델**: KDSS01, 스크린비인정 (guiderail 테이블에는 있지만 Builder에 미등록) + +#### 🔴 CRITICAL: BOM 카테고리 분류가 한글 BD 코드 의존 + +`BendingInfoBuilder.categorizeBomItem()` (line 401~434): + +```php +str_starts_with($code, 'BD-가이드레일') → guideRail +str_starts_with($code, 'BD-케이스') → shutterBox_case +str_starts_with($code, 'BD-마구리') → shutterBox_finCover +str_starts_with($code, 'BD-L-BAR') → detail_lbar +str_starts_with($code, 'BD-보강평철') → detail_reinforce +``` + +**→ BD-한글 패턴(58건)을 PREFIX로 변환하면 BOM 분류 로직이 깨짐!** +**→ 결정: 한글 코드는 유지하고, `options`에 속성만 추가하는 방식으로 진행** + +#### PrefixResolver PREFIX 규칙 + +| 카테고리 | partType → prefix | 비고 | +|----------|-------------------|------| +| **가이드레일(벽면)** | finish→RS/RE, body→RM, c_type→RC, d_type→RD, extra→YY, base→XX | KTE body→RT | +| **가이드레일(측면)** | finish→SS/SE, body→SM, c_type→SC, d_type→SD, extra→YY, base→XX | KTE body→ST | +| **하단마감재** | main→BE/BS/TS, lbar→LA, reinforce→HH, extra→YY | 재질 기반 분기 | +| **셔터박스** | front→CF, lintel→CL, inspection→CP, rear_corner→CB, top/fin→XX | 고정 | +| **연기차단재** | smoke→GI | 전용 길이코드(53/54/83/84) | + +#### bendingfee (82건) — `price_bend` 테이블 + +- **용도**: 절곡 BOM 단가 (모델별 단가 JSON) +- **구조**: `itemList` (JSON), `registedate`, `is_deleted` +- **사용법**: 최신 1건만 사용 (`ORDER BY num DESC LIMIT 1`) +- **관련 테이블**: `BDmodels` (모델별 조회) +- **SAM 연동**: 1차 제외 (단가 관리는 별도 Phase) + +#### bendingmap (9건) + +- **용도**: 절곡품 그룹화/매핑 (생산 현장용) +- **컬럼**: prodcode, railtype, boxsize, boxexit, frontbottom, railwidth, search_tag +- **SAM 연동**: 1차 제외 (그룹화는 options.item_bending으로 대체) ### 1-2. SAM BD 품목 현황 (170건) @@ -173,9 +217,64 @@ num:101 본체 EGI 120*70 ↔ BD-RM-30 (PREFIX-LEN — 길이 기준) ``` **핵심 결정사항**: -- BD-한글 패턴(58건)을 BD-PREFIX-LEN으로 통일할지 -- 레거시 265건 중 SAM에 없는 항목 → 신규 생성 범위 -- 매핑 애매한 항목 → 사업부 확인 목록 +- ~~BD-한글 패턴(58건)을 BD-PREFIX 으로 통일~~ **취소** — BendingInfoBuilder.categorizeBomItem()이 한글 코드 의존 +- **BD-한글 패턴(58건)은 코드 유지, `options`에 속성만 추가** +- BD-PREFIX-LEN(112건)도 options 속성 보강 (item_sep, item_bending 등) +- 레거시 265건 중 SAM에 없는 항목 → 신규 생성 범위 확인 필요 + +### 🔴 chandj 265건 vs SAM 170건 차이 설명 + +**구조가 다르지만 데이터는 동일**: + +``` +chandj 265건 = 절곡 "형상" (규격별 1건) + 예: 마감재 SUS 120*70 → 전개도 [10,11,110,30,15,15,15] ← 1건 + +SAM 170건 = 절곡 "제품" (길이별 확장) + 예: BD-RS-24 (2438mm) ┐ + BD-RS-30 (3000mm) │ 모두 같은 전개도 + BD-RS-35 (3500mm) │ (chandj 1건의 형상을 공유) + BD-RS-40 (4000mm) │ + BD-RS-43 (4300mm) ┘ ← 5건 +``` + +| 항목 | chandj | SAM | 관계 | +|------|:---:|:---:|------| +| 가이드레일 부품 | 71건 (규격별) | 74건 (길이별) | 1:N (형상 1 → 길이 여러 개) | +| 케이스 부품 | 160건 (규격×크기별) | 34건 (PREFIX-LEN) | N:1 (여러 규격 → 모델 components로 통합) | +| 하단마감재 부품 | 11건 | 21건 | 1:N | +| 마구리/기타 | 23건 | 41건 | 1:N | + +**누락 없는 이유**: +- chandj 265건의 **전개도 데이터**는 SAM 170건의 `options.bendingData`에 포함 (139건 매핑) +- chandj에서 SAM에 직접 없는 부품들은 **모델(GR/SB/BB)의 components**에서 `legacy_bending_num`으로 참조 +- 추가 임포트 **불필요** + +--- + +### 🔴 코드 체계 변경 불가 사유 + +**BD 코드(절곡 부품)는 변경 금지:** + +`BendingInfoBuilder.categorizeBomItem()` (line 401~434)에서 코드 접두사 기반으로 BOM 카테고리 분류: +```php +str_starts_with($code, 'BD-가이드레일') → guideRail +str_starts_with($code, 'BD-케이스') → shutterBox_case +str_starts_with($code, 'BD-마구리') → shutterBox_finCover +str_starts_with($code, 'BD-L-BAR') → detail_lbar +str_starts_with($code, 'BD-보강평철') → detail_reinforce +``` +BD-PREFIX-LEN 코드(BD-RS-30 등)도 `PrefixResolver` + LOT 재고에서 참조. +→ **견적→BOM→작업지시 전체 흐름이 깨지므로 코드 변경 불가** + +**모델 코드(GR/SB/BB)는 변경 가능** — 신규 생성이라 참조 없음: + +| 코드 | 카테고리 | 변경 가능 | 이유 | +|------|---------|:---:|------| +| `BD-*` (170건) | BENDING | ❌ | BendingInfoBuilder + PrefixResolver + LOT 의존 | +| `GR-*` (20건) | GUIDERAIL_MODEL | ✅ | 신규, 참조 없음 | +| `SB-*` (30건) | SHUTTERBOX_MODEL | ✅ | 신규, 참조 없음 | +| `BB-*` (10건) | BOTTOMBAR_MODEL | ✅ | 신규, 참조 없음 | --- @@ -247,36 +346,45 @@ num:101 본체 EGI 120*70 ↔ BD-RM-30 (PREFIX-LEN — 길이 기준) → 레거시 inputList/bendingrateList/sumList/colorList ``` -### 2-3. artisan command +### 2-3. artisan command (✅ 전체 실행 완료) ```bash -# 1단계 -php artisan bending:fill-options --dry-run # 미리보기 -php artisan bending:fill-options # 실행 +# 1단계: prefix/분류 속성 보강 (170건) +php artisan bending:fill-options # ✅ 완료 -# 2단계 -php artisan bending:import-legacy --dry-run -php artisan bending:import-legacy +# 2단계+3단계: 전개도(bendingData) + 속성 임포트 (139/170건) +php artisan bending:import-legacy # ✅ 완료 (31건 chandj 원본 없음) -# 3단계 (2단계에 포함 가능) +# 가이드레일 모델 임포트 (20건) +php artisan guiderail:import-legacy # ✅ 완료 + +# 케이스+하단마감재 모델 임포트 (30+10건) +php artisan bending-product:import-legacy # ✅ 완료 + +# 이미지 마이그레이션 +php artisan bending:import-images # ✅ 기초관리 부품 이미지 138건 +php artisan bending-model:import-images # ✅ 모델 부품별 이미지 275건 +php artisan bending-model:import-assembly-images # ✅ 결합형태 이미지 60건 ``` --- -## 3. 회귀 테스트 (필수) +## 3. 회귀 테스트 -| 테스트 | 확인 내용 | 판정 기준 | -|--------|----------|----------| -| BendingInfoBuilder | 견적 BOM 계산 결과 | 변경 전/후 동일 | -| PrefixResolver | BD 코드 자동 결정 | 변경 전/후 동일 | -| 작업지시서 절곡 섹션 | GuideRailSection 렌더링 | 정상 표시 | -| 절곡 검사 | inspection-config API | 정상 응답 | -| 견적→수주→작업지시 | 전체 흐름 1건 | 오류 없음 | +| 테스트 | 확인 내용 | 판정 기준 | 상태 | +|--------|----------|----------|:---:| +| BendingInfoBuilder | 견적 BOM 계산 결과 | 변경 전/후 동일 | ⚠️ BD 코드 무변경이므로 영향 없음 | +| PrefixResolver | BD 코드 자동 결정 | 변경 전/후 동일 | ⚠️ 무변경 | +| 작업지시서 절곡 섹션 | GuideRailSection 렌더링 | 정상 표시 | ⚠️ 무변경 | +| CRUD 테스트 | 기초관리/모델 전체 | 생성/조회/수정/삭제 | ✅ 검증 완료 | +| 테넌트 격리 | 287 vs 1 데이터 분리 | 각 테넌트 독립 조회 | ✅ 검증 완료 | +| 이미지 표시 | R2→API→MNG 프록시 | 정상 표시 | ✅ 검증 완료 | --- ## 4. 산출물 -- [ ] 매핑 테이블 (레거시 num ↔ SAM item_id) -- [ ] artisan command (bending:fill-options, bending:import-legacy) - - [ ] 회귀 테스트 결과 +- [x] 매핑 테이블 (legacy_bending_num으로 chandj↔SAM 연결) +- [x] artisan command 7개 (위 목록 참조) +- [x] CRUD 검증 완료 +- [x] 이미지 마이그레이션 완료 (총 473건 R2 업로드) diff --git a/dev/dev_plans/bending-management/step2-API.md b/dev/dev_plans/bending-management/step2-API.md index 30a6cbe..b4ea16d 100644 --- a/dev/dev_plans/bending-management/step2-API.md +++ b/dev/dev_plans/bending-management/step2-API.md @@ -1,7 +1,8 @@ -# Step 2: API 엔드포인트 +# Step 2: API 엔드포인트 ✅ 완료 > **프로젝트**: API (`sam/api`) > **선행 조건**: Step 1 완료 +> **상태**: ✅ 구현 완료 (2026-03-16~17) > **참조**: `standards/api-rules.md`, `standards/options-column-policy.md`, `rules/item-policy.md` --- @@ -58,21 +59,41 @@ ?item_sep=스크린 # 대분류 &item_bending=가이드레일 # 중분류 &material=SUS # 재질 (부분 매칭) -&model_UA=인정 # 인정여부 +&model_UA=인정 # 인정여부 &search=KSS01 # 통합 검색 (이름/검색어/규격) &page=1&size=50 # 페이지네이션 (size — api-rules 기준) ``` -### 2-2. 절곡품 모델 관리 (조합) +### 2-2. 절곡품 모델 관리 (가이드레일/케이스/하단마감재 통합) | Method | Path | 설명 | 비고 | |--------|------|------|------| -| GET | `/api/v1/guiderail-models` | 모델 목록 (타입별) | ?type=가이드레일 | +| GET | `/api/v1/guiderail-models` | 모델 목록 | `?item_category=` 필수 | +| GET | `/api/v1/guiderail-models/filters` | 필터 옵션 | | | GET | `/api/v1/guiderail-models/{id}` | 모델 상세 (부품 조합 + 재질별 폭합) | | | POST | `/api/v1/guiderail-models` | 모델 등록 | | | PUT | `/api/v1/guiderail-models/{id}` | 모델 수정 | | | DELETE | `/api/v1/guiderail-models/{id}` | 모델 삭제 (soft delete) | | +**카테고리 구분** (필수 파라미터): + +| item_category | 메뉴 | 건수 | 코드 패턴 | +|--------------|------|:---:|---------| +| `GUIDERAIL_MODEL` | 가이드레일 | 20 | `GR-KSS01-벽면형-SUS` | +| `SHUTTERBOX_MODEL` | 케이스 | 30 | `SB-500*350-밑면` | +| `BOTTOMBAR_MODEL` | 하단마감재 | 10 | `BB-KSS01-SUS` | + +**필터 파라미터** (GET /api/v1/guiderail-models): +``` +?item_category=GUIDERAIL_MODEL # 필수: 카테고리 구분 +&item_sep=스크린 # 대분류 +&model_UA=인정 # 인정여부 +&check_type=벽면형 # 형상 (가이드레일만) +&model_name=KSS01 # 모델명 +&search=KSS01 # 통합 검색 +&page=1&size=50 +``` + --- ## 3. 구현 파일 구조 diff --git a/dev/dev_plans/bending-management/step3-MNG화면.md b/dev/dev_plans/bending-management/step3-MNG화면.md index 0be37b7..09aee56 100644 --- a/dev/dev_plans/bending-management/step3-MNG화면.md +++ b/dev/dev_plans/bending-management/step3-MNG화면.md @@ -1,7 +1,8 @@ -# Step 3: MNG 관리 화면 (Blade + HTMX) +# Step 3: MNG 관리 화면 (Blade + HTMX) ✅ 완료 > **프로젝트**: MNG (`sam/mng`) > **선행 조건**: Step 2 (API 엔드포인트) 완료 +> **상태**: ✅ 샘플 구현 완료 (2026-03-16~17) > **참조**: 프로토타입 `SAM/work/절곡/`, MNG 기존 Blade 패턴 --- @@ -293,7 +294,7 @@ class FileViewController extends Controller ┌───────────────────────────────────┬──────────────────┐ │ [기본 정보] │ [형상 이미지] │ │ 등록일 | 작성자 │ 이미지 업로드 │ -├───────────────────────────────────┤ │ +├───────────────────────────────────┤**** │ │ [케이스 정보] │ 품목검색어 │ │ 가로(폭) × 세로(높이) │ 비고 │ │ 전면밑: [50] | 레일폭: [75] │ │ diff --git a/dev/dev_plans/bending-management/step4-React연동.md b/dev/dev_plans/bending-management/step4-React연동.md index 61d0b53..a9b0d13 100644 --- a/dev/dev_plans/bending-management/step4-React연동.md +++ b/dev/dev_plans/bending-management/step4-React연동.md @@ -1,43 +1,272 @@ -# Step 4: React 견적 화면 이미지 연동 +# Step 4: React 절곡품 관리 화면 + 견적 이미지 연동 ⬜ 미착수 > **프로젝트**: React (`sam/react`) -> **선행 조건**: Step 2 (API), Step 3 (MNG에서 데이터 등록 후) -> **참조**: 기존 GuideRailSection 컴포넌트 +> **선행 조건**: Step 2 (API ✅), Step 3 (MNG 샘플 ✅) +> **상태**: ⬜ 미착수 +> **참조**: MNG 샘플 화면, 기존 GuideRailSection 컴포넌트 --- -## 1. 목적 +## 1. 개요 -견적 페이지(`/sales/quote-management/new`)에서 가이드레일 모델 선택 시 -전개도 이미지 + 부품 조합 테이블을 표시한다. +MNG에서 샘플로 구현/검증한 절곡품 관리 기능을 React 운영 화면으로 이관한다. +모든 API 엔드포인트는 Step 2에서 완료되어 있으므로, **프론트엔드 구현만** 필요. --- -## 2. 현재 흐름 +## 2. API 엔드포인트 (Step 2 완료 — 그대로 사용) +### 2-1. 기초관리 (절곡 부품) ``` -제품 선택 → BOM 계산 (BendingInfoBuilder) - → product_code, finish_material 확정 - → 가이드레일 모델 결정 - → 텍스트만 표시 ❌ 이미지 없음 +GET /api/v1/bending-items ← 목록 (필터/검색/페이지네이션) +GET /api/v1/bending-items/filters ← 필터 옵션 (분류/재질/모델 distinct) +GET /api/v1/bending-items/{id} ← 상세 (options 전체) +POST /api/v1/bending-items ← 등록 +PUT /api/v1/bending-items/{id} ← 수정 +DELETE /api/v1/bending-items/{id} ← 삭제 (soft delete) ``` -## 3. 목표 흐름 - +**응답 구조** (목록): +```json +{ + "success": true, + "data": { + "data": [ + { + "id": 15862, "code": "BD-BE-30", + "name": "하단마감재(스크린) EGI 3000mm", + "item_type": "PT", "item_category": "BENDING", + "item_name": "하단마감재", "item_sep": "스크린", + "item_bending": "하단마감재", "item_spec": "60*40", + "material": "EGI 1.55T", "model_name": null, + "model_UA": "인정", "search_keyword": null, + "rail_width": null, "registration_date": "2025-07-21", + "author": "개발자", "memo": null, + "exit_direction": null, "front_bottom_width": null, + "box_width": null, "box_height": null, + "bendingData": [ + {"no":1,"input":15,"rate":"","sum":15,"color":false,"aAngle":false}, + {"no":2,"input":14,"rate":"-1","sum":28,"color":false,"aAngle":false} + ], + "prefix": "BE", "length_code": "30", "length_mm": 3000, + "legacy_bending_num": 288, + "width_sum": 193, "bend_count": 5, + "created_at": "2026-02-21 19:47:01" + } + ], + "current_page": 1, "total": 170, "last_page": 6, "per_page": 30 + } +} ``` -제품 선택 → BOM 계산 (기존 그대로) - → 모델 확정 - → GET /api/guiderail-models/{id} 호출 🆕 - → GuiderailPreview 컴포넌트 렌더링 🆕 - ├─ 전개도 이미지 - └─ 부품 조합 테이블 (부품명/재질/수량/전개폭) + +### 2-2. 절곡품 모델 (가이드레일/케이스/하단마감재 통합) +``` +GET /api/v1/guiderail-models ← 모델 목록 +GET /api/v1/guiderail-models/filters ← 필터 옵션 +GET /api/v1/guiderail-models/{id} ← 모델 상세 (부품 조합) +POST /api/v1/guiderail-models ← 모델 등록 +PUT /api/v1/guiderail-models/{id} ← 모델 수정 +DELETE /api/v1/guiderail-models/{id} ← 모델 삭제 +``` + +**카테고리 필터**: `?item_category=GUIDERAIL_MODEL|SHUTTERBOX_MODEL|BOTTOMBAR_MODEL` + +**응답 구조** (상세): +```json +{ + "success": true, + "data": { + "id": 15914, "code": "GR-KDSS01-벽면형-SUS", + "name": "KDSS01 벽면형 SUS마감", + "item_category": "GUIDERAIL_MODEL", + "model_name": "KDSS01", "check_type": "벽면형", + "rail_width": 150, "rail_length": 150, + "finishing_type": "SUS마감", + "item_sep": "스크린", "model_UA": "인정", + "components": [ + { + "orderNumber": 1, + "itemName": "1번(마감제)", "material": "SUS 1.2T", + "quantity": 2, "width_sum": 227, + "bendingData": [ + {"no":1,"input":15,"rate":"0","sum":15,"color":true,"aAngle":false}, + {"no":2,"input":13,"rate":"0","sum":28,"color":false,"aAngle":false} + ], + "legacy_bending_num": "170" + } + ], + "material_summary": {"SUS 1.2T": 599, "EGI 1.55T": 894}, + "component_count": 4 + } +} +``` + +### 2-3. 이미지 (기존 API 재사용) +``` +POST /api/v1/items/{id}/files ← 업로드 (field_key: 'bending_diagram') +GET /api/v1/items/{id}/files ← 목록 조회 +GET /api/v1/files/{id}/view ← 인라인 표시 +DELETE /api/v1/items/{id}/files/{fileId} ← 삭제 ``` --- -## 4. 구현 사항 +## 3. React 화면 구성 -### 4-1. GuiderailPreview 컴포넌트 +### 3-1. 메뉴 구조 (사이드바) + +``` +생산 관리 +├─ ... (기존) +└─ 절곡품 관리 + ├─ 기초관리 /bending/base + ├─ 절곡품 (가이드레일) /bending/products + ├─ 케이스 /bending/cases + └─ 하단마감재 /bending/bottombars +``` + +### 3-2. 기초관리 화면 + +**목록 (`/bending/base`)**: +| 컬럼 | API 필드 | +|------|---------| +| NO | id | +| 코드 | code | +| 대분류 | item_sep (스크린=파란배지, 철재=주황배지) | +| 인정 | model_UA | +| 분류 | item_bending | +| 품명 | item_name | +| 규격 | item_spec | +| 재질 | material | +| 모델 | model_name | +| 폭합 | width_sum | +| 절곡수 | bend_count | +| 등록일 | created_at | + +**필터**: item_sep, item_bending, material, search (HTMX 실시간 검색) + +**폼 (`/bending/base/{id}/edit`)**: + +기본 정보 (4열 그리드): +- 코드*, 이름*, 품명*, 대분류*(select) +- 분류*(datalist), 재질*(datalist), 규격, 모델(datalist) +- 인정여부(select), 등록일(date), 작성자, 검색어 + +케이스 전용 (분류=케이스 시 표시): +- 점검구 방향(select), 전면밑(mm), 레일폭(mm), 케이스 너비(mm), 케이스 높이(mm) + +절곡 입력 테이블: +- 동적 열 추가/삭제 +- 행: 입력(number) → 연신율(text) → 연신율후(자동) → 합계(자동) → 음영(checkbox) → A각(checkbox) +- 연신율 규칙: `-1` → input-1mm, `1` → input+1mm, 빈값 → 그대로 +- 폭합계 + 절곡횟수 자동 표시 +- `bendingData` JSON으로 직렬화하여 API 전송 + +이미지: 파일 업로드 + Ctrl+V 클립보드 + 미리보기 + +### 3-3. 절곡품 화면 (3가지 타입) + +**목록** (공통 테이블): +| 컬럼 | API 필드 | +|------|---------| +| NO | id | +| 모델명 | model_name | +| 대분류 | item_sep | +| 인정 | model_UA | +| 형상 | check_type | +| 레일폭×높이 | rail_width × rail_length | +| 마감 | finishing_type | +| 부품수 | component_count | +| 소요자재량 | material_summary | + +**필터**: `item_category`(필수!), item_sep, model_UA, check_type, model_name, search + +> ⚠️ `item_category` 없이 호출하면 3개 카테고리 60건이 섞여서 나옴 + +**폼 — 타입별 헤더 차이**: + +| 필드 | 가이드레일 | 케이스 | 하단마감재 | +|------|:---:|:---:|:---:| +| 등록일/작성자/비고 | ✅ | ✅ | ✅ | +| 외형치수 (가로×세로) | ✅ 너비×폭 | ✅ 폭×높이+전면밑+레일폭 | ✅ 폭×높이 | +| 대분류 라디오 | ✅ | ❌ | ✅ | +| 인정/비인정 라디오 | ✅ | ❌ | ✅ | +| 형태 라디오 (벽면/측면) | ✅ | ❌ | ❌ | +| 점검구 방향 라디오 | ❌ | ✅ | ❌ | +| 모델 select | ✅ | ❌ | ✅ | +| 마감 select | ✅ | ❌ | ✅ | +| 품목검색어 | ✅ | ✅ | ✅ | + +**절곡 부품 조립 섹션**: +- 부품별 절곡 테이블 (inline 편집) +- 부품 추가: 기초관리 검색 모달 (필터+체크박스+선택적용) +- 부품 삭제: DOM 즉시 제거 +- 품명/재질/수량 inline 편집 +- 순서 변경 (위로/아래로) +- `components` JSON으로 직렬화하여 API 전송 + +**재질별 폭합**: components에서 자동 계산 (`material_summary`) + +**작업지시서 PDF**: 별도 인쇄 페이지 (`/{type}/{id}/print`) +- 레거시 포맷: 번호 | 재질 | 절곡치수(합계+음영) | 폭합 | 수량 +- A각 표시 행 +- A4 가로 인쇄 최적화 + +--- + +## 4. React 컴포넌트 구조 (설계안) + +``` +src/pages/bending/ +├─ base/ +│ ├─ BendingBaseList.tsx ← 기초관리 목록 +│ └─ BendingBaseForm.tsx ← 등록/수정/조회 (mode 분기) +├─ products/ +│ ├─ BendingProductList.tsx ← 절곡품 목록 (category prop으로 3타입 공용) +│ ├─ BendingProductForm.tsx ← 등록/수정/조회 (타입별 헤더 분기) +│ └─ BendingProductPrint.tsx ← 작업지시서 인쇄 +├─ components/ +│ ├─ BendingTable.tsx ← 절곡 입력 테이블 (공용 컴포넌트) +│ ├─ BendingSearchModal.tsx ← 기초관리 부품 검색 모달 +│ ├─ PartListEditor.tsx ← 부품 조립 편집기 +│ ├─ MaterialSummary.tsx ← 재질별 폭합 표시 +│ └─ GuiderailPreview.tsx ← 견적 페이지용 미리보기 +└─ hooks/ + ├─ useBendingItems.ts ← API 호출 훅 + └─ useGuiderailModels.ts ← API 호출 훅 +``` + +### 4-1. BendingTable 컴포넌트 (핵심) + +```tsx +interface BendingData { + no: number; + input: number; + rate: string; // '' | '-1' | '1' + sum: number; // 자동 계산 + color: boolean; // 음영 마킹 + aAngle: boolean; // A각 표시 +} + +interface BendingTableProps { + data: BendingData[]; + onChange: (data: BendingData[]) => void; + readOnly?: boolean; +} +``` + +### 4-2. BendingSearchModal 컴포넌트 + +```tsx +interface BendingSearchModalProps { + open: boolean; + onClose: () => void; + onSelect: (items: BendingItem[]) => void; + filters?: { item_sep?: string; item_bending?: string; }; +} +``` + +### 4-3. GuiderailPreview 컴포넌트 (견적 페이지 연동) ``` ┌─────────────────────────────────────────────────────┐ @@ -46,44 +275,138 @@ │ 전개도 이미지 │ 부품 조합 │ │ ┌────────────────┐ │ # │ 부품 │ 재질 │ 수량 │ │ │ │ │ 1 │ 마감재 │ SUS │ 2 │ -│ │ (이미지) │ │ 2 │ 본체 │ EGI │ 1 │ +│ │ (R2 이미지) │ │ 2 │ 본체 │ EGI │ 1 │ │ │ │ │ 3 │ C형 │ EGI │ 1 │ │ └────────────────┘ │ 4 │ D형 │ EGI │ 1 │ +│ │ 재질별 폭합 │ +│ │ SUS: 406 | EGI: 398 │ └──────────────────────┴──────────────────────────────┘ ``` -### 4-2. 삽입 위치 +--- -견적 페이지에서 BOM 결과 표시 영역 하단 (기존 레이아웃 무변경) +## 5. 데이터 현황 (Step 1~3 완료 시점) -### 4-3. 데이터 흐름 - -``` -BOM 계산 결과 → product_code + finish_material - → API 호출: GET /api/guiderail-models?model={code}&check_type={형상} - → 응답: image_url + components + material_summary - → GuiderailPreview 렌더링 -``` +| 항목 | 건수 | 상태 | +|------|:---:|:---:| +| 기초관리 (BENDING) | 170건 | ✅ | +| ├ 전개도 임포트 | 139/170건 | ✅ (31건 chandj 원본 없음) | +| 가이드레일 모델 (GUIDERAIL_MODEL) | 20건 | ✅ | +| 케이스 모델 (SHUTTERBOX_MODEL) | 30건 | ✅ | +| 하단마감재 모델 (BOTTOMBAR_MODEL) | 10건 | ✅ | +| DB 메뉴 | 4개 | ✅ | --- -## 5. 주의사항 +## 6. 주의사항 -- 기존 견적 계산 로직 무변경 -- 기존 GuideRailSection (작업지시서용) 무변경 — 별도 컴포넌트 -- 이미지 없는 모델: 텍스트만 표시 (graceful degradation) -- 모바일 반응형 처리 +- ✅ 기존 GuideRailSection (작업지시서용) 무변경 — 별도 컴포넌트 +- ✅ 기존 BendingInfoBuilder / PrefixResolver 무변경 +- ✅ 이미지 없는 모델: 텍스트만 표시 (graceful degradation) +- ✅ MNG는 **샘플 확인용** — React가 **운영용** +- ✅ MNG/React 모두 동일한 API 엔드포인트 호출 +- ⚠️ tenant_id 287 하드코딩 → React에서는 Sanctum Bearer 토큰으로 자동 해결 +- ⚠️ **인증 전환**: React 작업 시 `ApiKeyMiddleware.php`의 `allowWithoutAuth`에서 bending 관련 4줄 제거 → 다른 API와 동일한 2중 인증 (API Key + Bearer) 적용 +- ⚠️ 재고 데이터 (stocks 153건) 이미 존재 — React에서 재고 연동 시 기존 Stock API 사용 +- ⚠️ **운영 배포 전 정리 필요** (options 불필요 키 삭제): + - `source` (5130_migration 등) — 마이그레이션 추적용, 운영 불필요 + - `legacy_prod`, `legacy_spec`, `legacy_slength` — PREFIX 생성 완료, 삭제 가능 + - `legacy_bending_num`, `legacy_num`, `legacy_guiderail_num` — 이미지 매핑 완료, 삭제 가능 + - `lot_managed`, `consumption_method`, `production_source`, `input_tracking` — 재고 시스템 별도 관리 + - `author = '개발자'` — 실제 담당자로 변경 필요 + - ⚠️ 레거시 키 삭제 후 `bending:import-*` 커맨드 재실행 불가 — 운영 확정 후 정리 +- ⚠️ **운영 안정화 후 마이그레이션 커맨드 삭제 가능** (1회성 도구): + - `BendingFillOptions.php`, `BendingImportLegacy.php`, `BendingImportImages.php` + - `GuiderailImportLegacy.php`, `BendingProductImportLegacy.php` + - `BendingModelImportImages.php`, `BendingModelImportAssemblyImages.php` + - ⚠️ R2 이미지 + files 레코드는 운영 데이터 — 삭제 불가 --- -## 6. 범위 (추후 확정) +## 7. MNG 샘플에서 발견된 실무 구현 노트 -| 영역 | 설명 | 시점 | +> React 구현 시 참고할 MNG 작업 중 발견된 이슈 및 해결 방법 + +### 7-1. API 호출 주의사항 + +| 이슈 | 원인 | 해결 | |------|------|------| -| 견적 이미지 연동 | GuiderailPreview 컴포넌트 | Step 1~3 완료 후 | -| 절곡품 관리 화면 | React 버전 CRUD (MNG 대체) | MNG 샘플 검증 후 | +| PUT/POST JSON body 파싱 안 됨 | Laravel API가 form-data만 파싱 | React axios는 JSON 자동 처리되므로 문제 없음 | +| `bendingData` 전송 | MNG form은 hidden input JSON 문자열 | React는 객체 배열 그대로 전송 가능 | +| pagination 메타 누락 | `ResourceCollection` 감싸면 메타 사라짐 | `paginator.transform()` 방식으로 수정 완료 | +| `unique:items,code` | Store 시 코드 중복 체크 | React form에서 에러 메시지 표시 필요 | -- MNG는 **샘플 확인용** — API 연동 검증이 목적 -- **실제 운영 화면은 React**에서 구현 (MNG와 동일한 API 호출) -- React 화면 상세 설계는 MNG 검증 후 별도 문서로 작성 예정 -- 현재 문서는 견적 이미지 연동 범위만 정의 +### 7-2. 절곡 테이블 구현 핵심 로직 + +``` +연신율 보정 규칙: + rate = "" → 보정 없음 (input 그대로) + rate = "-1" → input - 1mm (절곡 시 1mm 줄어듦) + rate = "1" → input + 1mm + +합계 = 보정 후 값의 누적합 +폭합계 = 마지막 합계값 + +절곡횟수 = rate가 빈 문자열이 아닌 열의 수 +``` + +### 7-3. 부품 추가 모달 동작 + +``` +1. [+ 부품 추가] 클릭 → 모달 열기 +2. GET /api/v1/bending-items?item_sep=&item_bending=&material=&search=&size=100 +3. 체크박스로 복수 선택 +4. [선택 적용] → 선택된 아이템의 bendingData를 components에 push +5. components JSON 직렬화 → hidden input → form submit +``` + +### 7-4. 타입별 라우트 매핑 + +| React 라우트 | API 파라미터 | MNG 참고 | +|-------------|------------|---------| +| `/bending/base/*` | `/api/v1/bending-items` | `BendingBaseController` | +| `/bending/products/*` | `/api/v1/guiderail-models?item_category=GUIDERAIL_MODEL` (20건) | `BendingProductController` | +| `/bending/cases/*` | `/api/v1/guiderail-models?item_category=SHUTTERBOX_MODEL` (30건) | 동일 컨트롤러 | +| `/bending/bottombars/*` | `/api/v1/guiderail-models?item_category=BOTTOMBAR_MODEL` (10건) | 동일 컨트롤러 | + +> ⚠️ `item_category` 파라미터 누락 시 60건 전부 반환됨 — React에서 반드시 포함할 것 + +### 7-5. 작업지시서 PDF + +MNG에서는 `window.print()` 기반 별도 인쇄 페이지(`/print`)로 구현. +React에서는 동일 방식 또는 html2pdf.js / react-to-print 라이브러리 사용 가능. + +**인쇄 포맷 (레거시 동일):** +- 헤더: 모델명, 형태, 규격, 마감 +- 테이블: 번호 | 재질 | 절곡치수(합계+음영) | A각 | 폭합 | 수량 +- 재질별 폭합 요약 +- A4 가로 + +### 7-6. 이미지 업로드 흐름 + +``` +React: +1. 또는 Ctrl+V 클립보드 +2. POST /api/v1/items/{itemId}/files (FormData: file + field_key=bending_diagram) +3. 응답: { file_id, file_url } +4. 표시: GET /api/v1/files/{fileId}/view (inline 이미지) +``` + +### 7-7. 메뉴 구조 (사이드바) + +``` +절곡품 관리 +├─ 기초관리 /bending/base (170건) +├─ 가이드레일 /bending/products (20건, GUIDERAIL_MODEL) +├─ 케이스 /bending/cases (30건, SHUTTERBOX_MODEL) +└─ 하단마감재 /bending/bottombars (10건, BOTTOMBAR_MODEL) +``` + +React 사이드바 메뉴는 DB `menus` 테이블 기반 동적 렌더링 — 이미 등록 완료. + +### 7-8. 재고 연동 (향후) + +절곡 부품 재고는 SAM 기존 재고 시스템에 통합: +- `stocks` 테이블: `item_type = 'bent_part'` (153건) +- `stock_lots` 테이블: LOT 기반 FIFO 재고 +- 기존 Stock API 사용 가능 — 별도 재고 API 불필요