# common_addrowJS.php 개발자 가이드 ## 📋 개요 `common_addrowJS.php`는 방화셔터 견적 시스템의 핵심 JavaScript 컴포넌트로, 견적 테이블에 새로운 행을 동적으로 추가하고 관리하는 기능을 제공합니다. 이 파일은 PHP와 JavaScript가 혼합된 형태로 구성되어 있으며, 견적 항목의 복잡한 입력 폼을 자동으로 생성합니다. ## 🏗️ 파일 구조 ### 📁 파일 위치 ``` /estimate/common/common_addrowJS.php ``` ### 📊 파일 정보 - **파일 크기**: 113KB (2536 lines) - **주요 언어**: PHP + JavaScript + jQuery - **의존성**: jQuery, Bootstrap, models.json ## 🔧 핵심 기능 ### 1. 모델 데이터 로드 ```php // models.json에서 스크린/철재 모델 정보 로드 $jsonFile = $_SERVER['DOCUMENT_ROOT'] . '/models/models.json'; $models = json_decode(file_get_contents($jsonFile), true); // 스크린과 철재 모델 분리 $screenModels = array_filter($models, function ($m) { return $m['slatitem'] === '스크린'; }); $steelModels = array_filter($models, function ($m) { return $m['slatitem'] === '철재'; }); ``` ### 2. 메인 함수: `addRow()` ```javascript function addRow(tableBody, rowData, typebutton, afterRow = null, autoData = {}) ``` #### 매개변수 - `tableBody`: 대상 테이블의 tbody 요소 - `rowData`: 행에 설정할 초기 데이터 객체 - `typebutton`: 버튼 타입 (사용되지 않음) - `afterRow`: 삽입할 기준 행 (선택사항) - `autoData`: 자동 계산 데이터 (선택사항) ## 📊 컬럼 구조 (71개 컬럼) ### 🎯 컬럼별 특성 #### **기본 컬럼 (1-3)** - **col1**: 행 번호 (자동 생성, readonly) - **col2**: 기본 입력 필드 - **col3**: 기본 입력 필드 #### **모델 관련 컬럼 (4-7)** - **col4**: 스크린 모델 선택 (드롭다운) - `screenModelOptions`에서 동적 로드 - 변경 시 `modelChange_screen()` 함수 호출 - **col5**: readonly 필드 (자동 계산) - **col6**: 셔터박스 타입 선택 - 벽면형(120*70) - 측면형(120*120) - 혼합형(120*70)(120*120) - **col7**: 마감 타입 선택 - SUS마감 - EGI마감 #### **제작 사이즈 컬럼 (10-11)** - **col10**: 제작 사이즈 (가로) - **col11**: 제작 사이즈 (세로) - **특별 처리**: col10은 3개의 필드로 분할 - `col10_SW`: 가로 사이즈 - `col11_SH`: 세로 사이즈 - `col10`: 통합 사이즈 #### **수량 컬럼 (14)** - **col14**: 수량 입력 + 자동산출 버튼 ```javascript '' ``` #### **모터 관련 컬럼 (18-19)** - **col18**: 모터 브랜드 + 전압 + 유선/무선 - 브랜드: 경동(견적가포함), 대한, 기타 - 전압: 220V, 380V - 연결: 유선, 무선 - **col19**: 모터 용량 선택 - 브라켓 사이즈별 용량 매핑 - 380*180: 150K, 300K, 400K - 530*320: 300K, 400K - 600*350: 500K, 600K - 690*390: 800K, 1000K #### **셔터박스 컬럼 (36)** - **col36**: 복합 입력 필드 - 기본 옵션: 500*380, 500*350 - 직접 입력 옵션 - 전면밑, 레일폭, 박스 방향 설정 ```javascript let selectHtml = ''; let inputHtml = ''; let inputHtmlfrontbottom = ''; let inputHtmlrailwidth = ''; let selectHtmlboxdirection = ''; ``` #### **마구리 윙 컬럼 (45)** - **col45**: 기본 입력 필드 - **col45_wing**: 마구리 윙 길이 - 기본값: `$('#maguriWing').val()` 또는 빈 값 #### **샤프트 관련 컬럼 (59)** - **col59**: 복합 입력 필드 - 인치 선택: 2인치, 3인치 - 길이 입력 - 수량 입력 #### **Readonly 컬럼들** - **col5, 12, 13, 23, 37, 48, 51, 54, 58, 67**: 자동 계산 필드 ## 🎨 UI/UX 특징 ### 📱 반응형 디자인 - Bootstrap 클래스 활용 - 모바일 최적화 - 테이블 반응형 처리 ### 🎯 컬럼 너비 최적화 ```javascript let width = [2, 3, 4, 5, 7, 20, 22, 23, 29, 30, 36, 45].includes(i) ? '85px' : '50px'; width = [6].includes(i) ? '170px' : width; width = [18].includes(i) ? '60px' : width; width = [23,32,43,46,49,53,62].includes(i) ? '50px' : width; ``` ### 🔘 버튼 시스템 - **추가 버튼**: `+` (새 행 추가) - **삭제 버튼**: `-` (행 삭제) - **복사 버튼**: 📋 (행 복사) - **계산 버튼**: 🧮 (자동 산출) ## ⚡ 이벤트 핸들링 ### 🔄 모델 변경 이벤트 ```javascript newRow.find('.col4-select').on('input change', function() { var row = $(this).closest('tr'); modelChange_screen(row); }); ``` ### 🔌 모터 브랜드 변경 이벤트 ```javascript newRow.find('.col18_brand').on('change', function() { var row = $(this).closest('tr'); const qty = row.find('.col14-input').val(); const col18_brandValue = row.find('.col18_brand').val(); // 모터 브랜드별 처리 로직 }); ``` ### 🎛️ 셔터박스 커스텀 입력 이벤트 ```javascript newRow.find('.col36-select').on('change', function() { var selectedValue = $(this).val(); var customInput = $(this).closest('td').find('.col36-custom-input'); if (selectedValue === 'custom') { customInput.show(); customInput.focus(); } else { customInput.hide(); customInput.val(''); } }); ``` ## 🧮 자동 계산 시스템 ### 📏 철재 스라트 계산 함수들 #### **Slat_updateCol59()**: 샤프트 수량 계산 ```javascript function Slat_updateCol59(row) { var col10Value = parseFloat(row.find('.col10-input').val()) || 0; // 셔터 길이 var col13Value = parseFloat(row.find('.col13-input').val()) || 0; // 중량 var col59Input = row.find('.col59-input'); // 길이와 중량에 따른 샤프트 수량 결정 if (col10Value <= 4500) { if (col13Value <= 400) { col59Input.val(4); } else if (col13Value > 400) { col59Input.val(5); } } // ... 추가 조건들 } ``` #### **Slat_updateCol60to71()**: 샤프트 길이별 수량 계산 ```javascript function Slat_updateCol60to71(row) { var col15Value = parseFloat(row.find('.col15-input').val()) || 0; // 셔터수량 var col59Value = parseFloat(row.find('.col22-select').val()) || 0; // 브라켓인치 var col10Value = parseFloat(row.find('.col10-input').val()) || 0; // 제작사이즈 가로 // 브라켓 인치별 샤프트 길이 분류 row.find('.col61-input').val((col59Value === 4 && col10Value <= 3050) ? col15Value : 0); row.find('.col62-input').val((col59Value === 4 && col10Value > 3050 && col10Value <= 4550) ? col15Value : 0); // ... 추가 조건들 } ``` #### **Slat_updateCol72()**: 셔터박스 수량 계산 ```javascript function Slat_updateCol72(row) { var col38Value = parseFloat(row.find('.col38-input').val()) || 0; // 셔터박스 사이즈 var col72Input = row.find('.col72-input'); // 사이즈별 박스 수량 결정 col72Input.val((col38Value <= 1600) ? 3 : (col38Value <= 2800) ? 4 : (col38Value <= 4000) ? 5 : // ... 추가 조건들 0); } ``` #### **Slat_updateCol73()**: 셔터박스 길이 계산 ```javascript function Slat_updateCol73(row) { var col38Value = parseFloat(row.find('.col38-input').val()) || 0; // 셔터박스 사이즈 var col72Value = parseFloat(row.find('.col72-input').val()) || 0; row.find('.col73-input').val(col38Value + 3000 * col72Value); } ``` #### **Slat_updateCol74to75()**: 앵글 수량 계산 ```javascript function Slat_updateCol74to75(row) { var col15Value = parseFloat(row.find('.col15-input').val()) || 0; // 셔터수량 var col73Value = parseFloat(row.find('.col73-input').val()) || 0; // 길이별 앵글 수량 계산 var col74Input = row.find('.col74-input'); col74Input.val((col73Value <= 9000) ? 3 * col15Value: (col73Value > 9000 && col73Value <= 12000) ? 4 * col15Value: // ... 추가 조건들 0); } ``` #### **Slat_updateCo76()**: 조인트바 수량 계산 ```javascript function Slat_updateCo76(row) { var col15Value = parseFloat(row.find('.col15-input').val()) || 0; // 셔터수량 var col10Value = parseFloat(row.find('.col10-input').val()) || 0; // 제작사이즈 (가로) var col76Input = row.find('.col76-input'); var calculatedValue = 2 + Math.floor((col10Value - 500) / 1000); col76Input.val(calculatedValue * col15Value); } ``` #### **Slat_updateTotals()**: 전체 합계 계산 ```javascript function Slat_updateTotals() { var sumColumns = [16, 17, 18, 19, 20, 21, 22, 31, 32, 33, 34, 35, 38, 39, 40, 41, 42, 45, 46, 47, 48, 49, 50, 51, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 81, 82, 83, 84]; sumColumns.forEach(function (colIndex) { var total = 0; $('#estimateSlatTable tbody tr').each(function () { var $cell = $(this).find('td').eq(colIndex - 1); var val = ''; if ($cell.find('input').length > 0) { val = $cell.find('input').val() || ''; } else if ($cell.find('select').length > 0) { val = $cell.find('select').val() || ''; } var numericValue = parseFloat(val.toString().replace(/,/g, '')) || 0; total += numericValue; }); var formattedTotal = total === 0 ? '' : total.toLocaleString(); $('#estimateSlattotalCol' + colIndex).text(formattedTotal); }); } ``` ## 🔧 개발자 사용법 ### 📝 기본 사용법 ```javascript // 새로운 행 추가 addRow($('#estimateTable tbody'), {}, 'add'); // 특정 데이터로 행 추가 addRow($('#estimateTable tbody'), { col4: '스크린모델명', col14: '10', col10: '3000' }, 'add'); // 특정 행 다음에 삽입 addRow($('#estimateTable tbody'), {}, 'add', $('#someRow')); ``` ### 🎯 커스텀 데이터 처리 ```javascript // 자동 계산 데이터 포함 addRow($('#estimateTable tbody'), rowData, 'add', null, { calculated: true, timestamp: new Date().getTime() }); ``` ### 🔄 이벤트 바인딩 ```javascript // 새로 추가된 행에 이벤트 바인딩 $('#estimateTable').on('change', '.col4-select', function() { var row = $(this).closest('tr'); modelChange_screen(row); }); ``` ## 🚨 주의사항 ### ⚠️ 필수 의존성 - jQuery 3.x 이상 - Bootstrap 5.x - models.json 파일 존재 필요 ### 🔒 보안 고려사항 - XSS 방지를 위한 입력값 검증 필요 - SQL 인젝션 방지를 위한 서버 사이드 검증 필요 ### 📱 성능 최적화 - 대량의 행 추가 시 성능 저하 가능 - 이벤트 위임 사용 권장 - 메모리 누수 방지를 위한 이벤트 정리 필요 ## 🐛 디버깅 가이드 ### 🔍 콘솔 로그 확인 ```javascript // 조인트바 계산 디버깅 console.log('조인트바 계산 col10Value : ', col10Value); console.log('조인트바 계산 col15Value : ', col15Value); console.log('조인트바 계산 col76 : ', col76Input.val()); ``` ### 🛠️ 일반적인 문제 해결 #### 1. 모델 옵션이 로드되지 않는 경우 ```javascript // models.json 파일 경로 확인 console.log('Models loaded:', screenModelOptions, steelModelOptions); ``` #### 2. 이벤트가 작동하지 않는 경우 ```javascript // 이벤트 바인딩 확인 $(document).on('change', '.col4-select', function() { console.log('Model changed:', $(this).val()); }); ``` #### 3. 계산이 올바르지 않은 경우 ```javascript // 입력값 확인 console.log('Input values:', { col10: $('.col10-input').val(), col13: $('.col13-input').val(), col15: $('.col15-input').val() }); ``` ## 📚 관련 파일 ### 🔗 의존성 파일 - `/models/models.json`: 모델 데이터 - `jQuery`: DOM 조작 - `Bootstrap`: UI 프레임워크 ### 🔗 연관 함수 - `modelChange_screen()`: 모델 변경 처리 - `calculateAmount()`: 금액 계산 - `updateTotals()`: 합계 업데이트 ## 🎯 향후 개선 방향 ### 🔄 코드 리팩토링 - 함수 분리 및 모듈화 - TypeScript 도입 고려 - ES6+ 문법 활용 ### 🎨 UI/UX 개선 - 드래그 앤 드롭 행 재정렬 - 키보드 단축키 지원 - 실시간 검증 메시지 ### ⚡ 성능 최적화 - 가상 스크롤링 도입 - 지연 로딩 구현 - 메모리 사용량 최적화 --- **📅 문서 버전**: 1.0 **👨‍💻 작성자**: 전산실장 김보곤