# Phase 5.3: 작업일지 폼 구현 계획 > **작성일**: 2026-02-10 > **마스터 문서**: [`document-system-master.md`](./document-system-master.md) > **상태**: 🔄 진행 중 (3/4+α, mng 상세보기 ✅) > **선행 조건**: Phase 5.0과 독립 (검사기준서 없음). 병렬 진행 가능 --- ## 1. 개요 ### 1.1 목적 mng에서 작업일지 양식 템플릿을 정의하고, React 작업자 화면(`/production/worker-screen`)의 작업일지 모달에서 해당 양식을 기반으로 작업 내역을 기록/조회할 수 있도록 한다. ### 1.2 하이브리드 방식 - **양식 정의**: mng 템플릿 시스템 (DocumentTemplate) 활용 - **전용 UI/로직**: React에서 작업일지 전용 컴포넌트로 구현 (검사 성적서와 다른 구조) - **이유**: 작업일지는 검사 항목표가 아닌, 품목 목록 + 작업 통계 + 특이사항 구조 ### 1.3 현재 상태 | 항목 | 상태 | 비고 | |------|:----:|------| | React WorkLogContent.tsx | ✅ | 정적 문서, DocumentHeader + 기본정보 + 품목테이블 + 작업내역 + 특이사항 | | mng 양식 템플릿 | ✅ | WorkLogTemplateSeeder 3종 (스크린:62, 슬랫:63, 절곡:64) | | WorkLogModal 양식 연동 | ✅ | 공정관리 workLogTemplateId 기반 콘텐츠 분기, processType 폴백 | | ScreenWorkLogContent 자재 LOT | ✅ | materialLots item_name별 동적 그룹핑 (하드코딩 "내화실" 제거) | | API 자재 투입 LOT 조회 | ✅ | materialInputLots 엔드포인트 (stock_transactions 기반) | | API 작업일지 전용 | ✅ | getWorkLogTemplate, getWorkLog, createWorkLog (3개 라우트) | | 작업 통계 계산 | ✅ | calculateWorkStats() 함수 존재 (완료/진행중/대기 수량) | | **mng 문서 상세보기** | ✅ | **show.blade.php 작업일지 전용 섹션 (템플릿 컬럼 기반 동적 렌더링)** | | **mng bf_ backfill 분기** | ✅ | **resolveAndBackfillBasicFields: 작업일지=label 기반, 검사=field_key 기반** | | **mng 재단 알고리즘 (PHP)** | ✅ | **React calculateCutSize 동일 구현. 실리카/와이어/화이바 원단별 설정** | | **mng 개소별 투입자재 LOT** | ✅ | **work_order_material_inputs → stock_lots JOIN, 개소별 lot_no 매핑** | | **mng 취소 트랜잭션 상쇄** | ✅ | **work_order_input + work_order_input_cancel 합산 → 순수 투입량** | ### 1.4 성공 기준 1. mng에서 작업일지 양식 정의 가능 (기본필드, 결재라인) 2. React에서 WorkOrder 선택 시 작업일지 자동생성 또는 수동생성 3. 품목 목록(WorkOrderItem[])이 자동으로 테이블에 매핑 4. 작업 통계(지시수량/완료수량/진행률) 자동 계산 5. 특이사항 입력/저장 가능 --- ## 2. 데이터 흐름 ``` WorkOrder (작업지시) ├─ work_order_no: "KD-WO-260210-01" ├─ process_id → Process (공정: 스크린/슬랫/절곡) ├─ sales_order_id → Order (수주) │ ├─ client_name: "발주처명" │ └─ site_name: "현장명" └─ items: WorkOrderItem[] ├─ [0] item_name="와이어 스크린", quantity=2, status="completed" ├─ [1] item_name="메쉬 스크린", quantity=4, status="in_progress" └─ [N] ... 작업일지 생성: ↓ Document (작업일지 1건 / 작업지시 1건) ├─ template_id → 작업일지 양식 ├─ linkable_type = 'WorkOrder' ├─ linkable_id = work_order.id ├─ status: DRAFT → PENDING → APPROVED └─ document_data (EAV) ├─ 기본필드: 발주처, 현장명, 작업일자, LOT NO, 납기일, 작업지시번호 ├─ 품목데이터: 행(row) = WorkOrderItem별 │ ├─ r{행}_item_name = "와이어 스크린" │ ├─ r{행}_floor_code = "1F-A" │ ├─ r{행}_specification = "W7400×H2950" │ ├─ r{행}_quantity = "2" │ └─ r{행}_status = "completed" ├─ 작업통계: order_qty, completed_qty, in_progress_qty, waiting_qty, progress └─ 특이사항: remarks ``` ### 2.1 mng 상세보기 데이터 흐름 (구현 완료) ``` DocumentController::show($id) ├─ Document + relations 로드 ├─ linkable_type === 'work_order' ? │ ├─ workOrderItems (work_order_items, options JSON decode) │ ├─ workOrder (work_orders) │ ├─ salesOrder (orders, via work_order.sales_order_id) │ ├─ materialInputLots (stock_transactions: work_order_input + cancel 상쇄) │ │ └─ 순수 투입량 = SUM(qty) where qty < 0 → abs() │ └─ itemLotMap (work_order_material_inputs → stock_lots JOIN) │ └─ groupBy(work_order_item_id) → lot_no 문자열 ├─ resolveAndBackfillBasicFields($document) │ ├─ isWorkLog = sections 없음? │ ├─ 작업일지 → buildWorkLogResolveMap (label 기반: 발주처, 현장명, 수주일 등) │ └─ 검사 문서 → buildInspectionResolveMap (field_key 기반: product_name 등) └─ view('documents.show', [...]) show.blade.php (작업일지 전용 섹션) ├─ 템플릿 컬럼 기반 동적 테이블 │ ├─ 헤더: simple 컬럼 = 1행, complex 컬럼 = colspan + sub_labels 2행 │ ├─ 데이터: $getCellValue (label 기반 매핑), $getSubCellValue (sub_label 매핑) │ └─ PHP $calculateCutSize (재단 알고리즘: FABRIC_CONFIG 원단별) ├─ 작업 통계 (지시수량/완료/진행중/대기/진행률) ├─ 투입 자재 LOT 테이블 (materialInputLots) └─ 비고 (remarks) ``` ### 2.2 중간검사 문서와의 차이 | 항목 | 중간검사 | 작업일지 | |------|---------|---------| | 단위 | 작업지시 (내부 개소별 행) | 작업지시 (1:1) | | 테이블 내용 | 검사항목 + 측정값 + 판정 | 품목 목록 + 상태 | | 통계 | 적합/부적합 비율 | 완료/진행중/대기 수량 | | Footer | 부적합 내용 + 종합판정 | 특이사항 | | 결재 | 작성→검토→승인 (3단계) | 작성→확인 (2단계) | --- ## 3. 작업 항목 | # | 작업 | 상태 | 완료 기준 | 비고 | |---|------|:----:|----------|------| | 5.3.1 | mng 작업일지 양식 시더 생성 | ✅ | WorkLogTemplateSeeder 3종. 스크린(62)/슬랫(63)/절곡(64). 공정별 결재+기본필드+컬럼 | 검사 기준서 섹션 없음, 판정 없음 | | 5.3.2 | mng 양식 편집 검증 | ✅ | 작업일지 양식 edit → 미리보기 정상 동작 확인 (코드 레벨 검증) | 빈 sections/judgement 안전 처리 | | 5.3.3 | API 작업일지 생성/저장 | ✅ | getWorkLogTemplate, getWorkLog, createWorkLog 구현. 3개 라우트 추가 | EAV 저장, 기본필드 자동매핑, 작업통계 자동계산 | | 5.3.4 | React WorkLogContent 양식 기반 전환 | ⏳ | 양식의 기본필드/결재라인을 API에서 받아 렌더링. 품목테이블/통계는 전용 로직 유지 | 하이브리드 | ### mng 작업일지 상세보기 (추가 작업, ✅ 완료) | # | 작업 | 상태 | 설명 | |---|------|:----:|------| | α.1 | resolveAndBackfillBasicFields 작업일지/검사 분기 | ✅ | 섹션 유무로 판별. 작업일지=label 기반(발주처, 현장명 등), 검사=field_key 기반(product_name 등) | | α.2 | show() 메서드 데이터 로딩 확장 | ✅ | workOrder, salesOrder, materialInputLots, itemLotMap 변수 추가 | | α.3 | 템플릿 컬럼 기반 동적 테이블 렌더링 | ✅ | template.columns 구조대로 헤더/데이터 렌더링. complex 컬럼(제작사이즈, 규격매수) sub_labels 지원 | | α.4 | PHP 재단 알고리즘 (calculateCutSize) | ✅ | React 동일 구현. FABRIC_CONFIG(실리카1220/와이어1100/화이바1100), 나머지높이+규격(매수) 자동계산 | | α.5 | 개소별 투입자재 LOT 매핑 | ✅ | work_order_material_inputs → stock_lots JOIN. 입고 LOT NO 컬럼에 개소별 lot_no 표시 | | α.6 | 투입자재 취소 트랜잭션 상쇄 | ✅ | stock_transactions에서 work_order_input(OUT,음수) + work_order_input_cancel(IN,양수) 합산 | | α.7 | 작업통계/자재LOT/비고 섹션 | ✅ | 지시수량/완료/진행중/대기 통계, 투입 자재 LOT 테이블, 비고 표시 | --- ## 4. 작업일지 구조 (React 현재 기준) ### 4.1 WorkLogContent.tsx 구조 ``` 작업일지 문서 ├─ DocumentHeader │ ├─ 로고 (케이디산업) │ ├─ 제목: "작업일지" │ └─ 결재라인: 작성 / 확인 │ ├─ 기본 정보 테이블 │ ├─ 발주처 / 현장명 │ ├─ 작업일자 / LOT NO │ └─ 납기일 / 작업지시번호 │ ├─ 품목 테이블 │ ├─ No | 품목명 | 층-부호 | 규격 | 수량 | 상태 │ ├─ [1] 와이어 스크린 | 1F-A | W7400×H2950 | 2 | 완료 │ ├─ [2] 메쉬 스크린 | 2F-B | W5200×H3100 | 4 | 작업중 │ └─ [N] ... │ ├─ 작업내역 (공정별) │ ├─ 지시수량: 50 │ ├─ 완료수량: 30 │ ├─ 진행률: 60% │ └─ 대기: 10 / 작업중: 10 / 완료: 30 │ └─ 특이사항 └─ (자유 텍스트 입력) ``` ### 4.2 작업 통계 계산 (기존 로직) ```typescript function calculateWorkStats(items: WorkOrderItem[]): WorkStats { return { orderQty: items.length, // 전체 개소 수 completedQty: items.filter(i => i.status === 'completed').length, inProgressQty: items.filter(i => i.status === 'in_progress').length, waitingQty: items.filter(i => i.status === 'waiting').length, progress: (completedQty / orderQty) * 100 } } ``` --- ## 5. 양식 시더 구조 (구현 완료 - 3종) ```php // WorkLogTemplateSeeder - 공정별 3종 // 스크린(ID:62): 결재 3단계(작성/검토/승인), 규격매수 컬럼(기준폭/900/800/600/400/300) // 슬랫(ID:63): 결재 4단계(작성/승인×3), 방화유리/조인트바/코일 컬럼 // 절곡(ID:64): 결재 4단계(작성/승인×3), 유형명/세부품명/재질/길이규격 컬럼 // // 공통: 기본필드 9개(신청업체4+신청내용5), 판정 없음, 비고만 [ 'name' => '스크린 작업일지', // or 슬랫/절곡 'category' => '생산/작업일지', 'title' => '작업일지 (스크린)', 'company_name' => '케이디산업', 'footer_remark_label' => '비고', 'footer_judgement_label' => '', // NOT NULL 컬럼 → 빈문자열 'footer_judgement_options' => [], // 작업일지는 종합판정 없음 'approval_lines' => [ ['name' => '작성', 'dept' => '생산', 'role' => '담당자', 'sort_order' => 1], ['name' => '확인', 'dept' => '생산', 'role' => '관리자', 'sort_order' => 2], ], 'basic_fields' => [ ['label' => '발주처', 'field_type' => 'text'], ['label' => '현장명', 'field_type' => 'text'], ['label' => '작업일자', 'field_type' => 'date'], ['label' => 'LOT NO', 'field_type' => 'text'], ['label' => '납기일', 'field_type' => 'date'], ['label' => '작업지시번호', 'field_type' => 'text'], ], // 섹션 없음 (작업일지는 검사 기준서가 필요 없음) 'sections' => [], // 컬럼: 품목 테이블용 (React에서 직접 렌더링하므로 참조용) 'columns' => [ ['label' => 'No', 'column_type' => 'text', 'width' => '40px'], ['label' => '품목명', 'column_type' => 'text', 'width' => '150px'], ['label' => '층-부호', 'column_type' => 'text', 'width' => '80px'], ['label' => '규격', 'column_type' => 'text', 'width' => '150px'], ['label' => '수량', 'column_type' => 'text', 'width' => '60px'], ['label' => '상태', 'column_type' => 'select', 'width' => '80px'], ], ] ``` --- ## 6. 하이브리드 구현 전략 ### mng 템플릿에서 관리하는 것 - 결재라인 (작성/확인 or 커스텀) - 기본필드 (발주처, 현장명, 작업일자 등) - 회사명, 문서 제목 ### React 전용 로직으로 유지하는 것 - 품목 테이블 (WorkOrderItem[] 기반 동적 생성) - 작업 통계 계산 (calculateWorkStats) - 상태 배지 (완료/작업중/대기 → 색상 표시) - 특이사항 입력 UI ### API 요청 흐름 ``` 1. 작업일지 생성 요청 POST /api/v1/work-orders/{id}/create-work-log → Document 생성 (template_id, linkable → WorkOrder) → 기본필드 자동매핑 (발주처, 현장명, LOT NO 등) 2. 작업일지 데이터 저장 PUT /api/v1/documents/{id} Body: { basic_data: { ... }, // 기본필드 (양식 기반) table_data: [ ... ], // 품목 테이블 (전용 로직) stats: { ... }, // 작업 통계 (자동 계산) remarks: "특이사항" // 자유 텍스트 } 3. 작업일지 조회 GET /api/v1/documents/{id} → 양식 JSON + 저장된 데이터 반환 ``` --- ## 7. 핵심 파일 경로 ### mng | 파일 | 용도 | |------|------| | `mng/database/seeders/WorkLogTemplateSeeder.php` | ✅ 3종 생성 (62/63/64) | | `mng/app/Http/Controllers/DocumentController.php` | ✅ show() 작업일지 데이터 로딩, resolveAndBackfillBasicFields 분기, buildWorkLogResolveMap | | `mng/resources/views/documents/show.blade.php` | ✅ 작업일지 전용 섹션 (템플릿 컬럼 동적 렌더링, PHP 재단 알고리즘, 통계, 자재LOT, 비고) | ### react | 파일 | 용도 | |------|------| | `react/src/components/production/WorkerScreen/WorkLogModal.tsx` | ✅ 작업일지 모달 (공정관리 양식 연동) | | `react/src/components/production/WorkerScreen/WorkLogContent.tsx` | 작업일지 범용 (~280행) | | `react/src/components/production/WorkOrders/documents/ScreenWorkLogContent.tsx` | ✅ 스크린 작업일지 (자재 LOT 동적화) | | `react/src/components/production/WorkOrders/documents/SlatWorkLogContent.tsx` | 슬랫 작업일지 | | `react/src/components/production/WorkOrders/documents/BendingWorkLogContent.tsx` | 절곡 작업일지 | | `react/src/components/production/WorkerScreen/actions.ts` | API 호출 | | `react/src/components/document-system/viewer/DocumentViewer.tsx` | 문서 뷰어 | ### api | 파일 | 용도 | |------|------| | `api/app/Services/WorkOrderService.php` | ✅ getWorkLogTemplate, getWorkLog, createWorkLog | | `api/app/Http/Controllers/Api/V1/WorkOrderController.php` | ✅ 작업일지 3개 엔드포인트 | | `api/routes/api/v1/production.php` | ✅ work-log-template, work-log 라우트 | | `api/app/Models/Production/WorkOrder.php` | ✅ documents() MorphMany 관계 | --- ## 8. 변경 이력 | 날짜 | 내용 | |------|------| | 2026-02-10 | Phase 5.3 계획 문서 신규 생성 | | 2026-02-11 | 5.3.1 완료: WorkLogTemplateSeeder 3종 생성 (스크린62/슬랫63/절곡64). 범용(61) 삭제. React 공정별 코드 분석 기반 구조 반영. 판정 없음 확정 | | 2026-02-11 | WorkLogModal 공정관리 양식 연동: workLogTemplateId/Name prop 추가, resolveProcessTypeFromTemplate() | | 2026-02-11 | ScreenWorkLogContent 자재 LOT 동적화: "내화실 입고 LOT NO" → materialLots item_name별 그룹핑 | | 2026-02-11 | 결정: 자재 LOT 역할 분리 — 개소별 품목=작업내역 테이블, 공용 자재=자재 투입 시스템 (예외 필드 없음) | | 2026-02-12 | 5.3.2 완료: mng 양식 편집/미리보기 코드 레벨 검증 (빈 sections/judgement 안전 처리 확인) | | 2026-02-12 | 5.3.3 완료: API 작업일지 3개 엔드포인트 구현 (getWorkLogTemplate, getWorkLog, createWorkLog). 기본필드 자동매핑, 작업통계 자동계산, EAV 저장 | | 2026-02-12 | MNG α.1~7 완료: 작업일지 상세보기 전면 구현 | | 2026-02-12 | DocumentController: resolveAndBackfillBasicFields 작업일지(label)/검사(field_key) 분기. buildWorkLogResolveMap, buildInspectionResolveMap 추가 | | 2026-02-12 | show.blade.php: 템플릿 컬럼 기반 동적 테이블 (complex 컬럼 sub_labels 지원), PHP 재단 알고리즘 (React calculateCutSize 동일) | | 2026-02-12 | show(): workOrder, salesOrder, materialInputLots(취소 상쇄), itemLotMap(개소별 LOT) 변수 추가 | | 2026-02-12 | 자재 투입 방식 변경 요청 기록 (수량 입력 → LOT 선택 방식, 미착수) | --- *이 문서는 /plan 스킬로 생성되었습니다.*