diff --git a/0_dev_comment.php b/0_dev_comment.php deleted file mode 100644 index aedbf520..00000000 --- a/0_dev_comment.php +++ /dev/null @@ -1,2897 +0,0 @@ -(경동기업, 주일기업) - -난 한국사람이고, 한국어를 제일 잘한다. 위의 두개의 회사의 업무를 처리하는 프로그램을 개발하고 있다. -이제부터 코드를 만들거나 수정하는 일을 할 것이다. - 웹사이트를 개발하고 관리하고 있다. -mysql, php, javascript로 대부분을 만들었다. - -오류에 대한 언급을 하면, 그 해당오류에 대한 코드만 보여주면 좋겠다. -이제부터 코드에 관련된 내용을 물어볼 것이니, 최선을 다해 답변해줘. -모든 script에 대한 선언은 이미 되어 있는 상태다. - -예를 들어 부트스트랩, 제이쿼리 등 전체 코드에 필요한 CDN 선언은 load_header.php 파일에 선언되어있다. -발주부터 출하, 재고관리, 인사관리 등등 전산시스템을 구축하고 있다. -회계부분도 매출, 출고통계, 로트번호관리 등 여러가지 종합적인 프로그램을 진행중에 있다. -지난 6개월간의 GPT와 협업해서 많은 코드를 만들었다. 하지만, 추가적인 요구사항들이 있어서 계속 수정할 것이다. -이제부터 이 개발과 관련된 코드에 대해 물어볼 것이다. -난 GPT의 모든 정보를 신뢰한다. 고마워. GPT 선생님! 추가적인 질문을 시작한다. -오류에 대한 언급을 하면, 그 해당오류에 대한 코드만 보여주면 좋겠다. -이제부터 코드에 관련된 내용을 물어볼 것이니, 최선을 다해 답변해줘. - -이제부터 내가 질문하는 것에는 전체코드 생성이라는 말이 없으면 부분적으로 내가 요청한 부분만 대답해줘. 알겠지? - -08/01 질문내용 -위의 파일은 statistics.php이다. 이 코드에는 스크린, 스라트의 제조통계를 화면에 보여주는 것인데, -내가 만들고 싶은 것은 두개의 합산된 것도 유지하면서, -col-sm-4을 활용해서 첫번째 col-sm-6에는 스크린의 차트가 보이고 -옆의 col-sm-4에는 스라트 -그리고 마지막 col-sm-4에는 두개의 합친 지금의 코드를 보여주는 코드로 수정하고자 한다. -가독성을 높이고, 경영자에게 더 좋은 정보를 제공하기 위해서이다. -아래의 코드로 충분히 이렇게 수정가능한 것 같다. 코드를 만들고 오류가 없지는 체크까지 부탁한다. - -chandj의 DB 내용중 output 테이블은 아래의 형태를 갖고 있다. - -num: 고유 번호 -con_num: 공사 번호 -is_deleted: 삭제 여부 -outdate: 출고일 -indate: 접수일 -outworkplace: 출고 작업장 -orderman: 발주자 -outputplace: 수신처 주소 -receiver: 수신자 -phone: 연락처 -comment: 비고 -file_name_0 ~ file_name_4: 파일명 -file_copied_0 ~ file_copied_4: 파일 경로 -root: 회사 구분 -steel: 절곡 발주 여부 -motor: 모터 발주 여부 -delivery: 배송 방식 -regist_state: 등록 상태 -bend_state: 절곡 상태 -motor_state: 모터 상태 -searchtag: 검색 태그 -update_log: 업데이트 로그 -screen: 스크린 정보 -screen_state: 스크린 상태 -screen_su: 스크린 수량 -screen_m2: 스크린 면적 (m²) -screenlist: 스크린 목록 -slatlist: 슬랫 목록 -slat: 슬랫 정보 -slat_state: 슬랫 상태 -slat_su: 슬랫 수량 -slat_m2: 슬랫 면적 (m²) -updatecomment: 수정 사항 기록 - -이 테이블의 구조를 이해할 수 있겠니? 각 컬럼의 역할도 마찬가지로 기억해줘. -이 모든 내용을 output 테이블이라고 칭하고 싶다. - -fetch_deadlineDate.php 내용은 아래와 같다. - -query("SELECT pjname, deadlineDate, secondord, deliverymethod, num, outputDate, status, hallDoorList, carDoorList, carWallList, etcList - FROM " . $DB . ".order - WHERE is_deleted IS NULL - AND MONTH(deadlineDate) = $month - AND YEAR(deadlineDate) = $year"); - - while($row = $stmh->fetch(PDO::FETCH_ASSOC)) { - array_push($data_order, $row); - } - - $data_order = array( - "data_order" => $data_order, - ); - - echo(json_encode($data_order, JSON_UNESCAPED_UNICODE)); - -} catch (PDOException $Exception) { - print "오류: ".$Exception->getMessage(); -} -?> - -fetch_outputDate.php 내용은 아래와 같다. - -query("SELECT pjname, deadlineDate, secondord, deliverymethod, num, outputDate, status, hallDoorList, carDoorList, carWallList, etcList - FROM " . $DB . ".order - WHERE is_deleted IS NULL - AND MONTH(deadlineDate) = $month - AND YEAR(deadlineDate) = $year"); - - while($row = $stmh->fetch(PDO::FETCH_ASSOC)) { - array_push($data_order, $row); - } - - $data_order = array( - "data_order" => $data_order, - ); - - echo(json_encode($data_order, JSON_UNESCAPED_UNICODE)); - -} catch (PDOException $Exception) { - print "오류: ".$Exception->getMessage(); -} -?> - -위의 코드에는 공통사항이 많다. 내가 언급한 output 테이블의 요소들로 바꾸고 두개의 파일을 하나의 파일로 만들고 전달하는 인자에 따라 처리하면 될 것 같다. -fetch_date.php 파일로 통합하고 output테이블의 컬럼요소에 맞게 수정해줘. - -아래의 파일은 month_schedule.php 파일인데, 한산엘테크 웹사이트에서 가져온 코드이다. -output 테이블에 맞게 모든 것을 수정해야 하는데, -방금 만든 fetch_date는 여기서 두개의 파일호출에 적용하면 된다. - -스크린의 면적을 누적하고, 스라트의 면적을 누적하는 코드가 있어야 한다. 이미 정의는 되어있다. - -################################## 주일기업 -(주일기업) -난 한국사람이고, 한국어를 제일 잘한다. 위의 두개의 회사의 업무를 처리하는 프로그램을 개발하고 있다. -이제부터 코드를 만들거나 수정하는 일을 할 것이다. - 웹사이트를 개발하고 관리하고 있다. -mysql, php, javascript로 대부분을 만들었다. - -오류에 대한 언급을 하면, 그 해당오류에 대한 코드만 보여주면 좋겠다. -이제부터 코드에 관련된 내용을 물어볼 것이니, 최선을 다해 답변해줘. -모든 script에 대한 선언은 이미 되어 있는 상태다. - -예를 들어 부트스트랩, 제이쿼리 등 전체 코드에 필요한 CDN 선언은 load_header.php 파일에 선언되어있다. -발주부터 출하, 재고관리, 인사관리 등등 전산시스템을 구축하고 있다. -회계부분도 매출, 출고통계, 로트번호관리 등 여러가지 종합적인 프로그램을 진행중에 있다. -지난 6개월간의 GPT와 협업해서 많은 코드를 만들었다. 하지만, 추가적인 요구사항들이 있어서 계속 수정할 것이다. -이제부터 이 개발과 관련된 코드에 대해 물어볼 것이다. -난 GPT의 모든 정보를 신뢰한다. 고마워. GPT 선생님! 추가적인 질문을 시작한다. -오류에 대한 언급을 하면, 그 해당오류에 대한 코드만 보여주면 좋겠다. -이제부터 코드에 관련된 내용을 물어볼 것이니, 최선을 다해 답변해줘. - -이제부터 내가 질문하는 것에는 전체코드 생성이라는 말이 없으면 부분적으로 내가 요청한 부분만 대답해줘. 알겠지? - -공사수주 리스트의 자료를 수정하려고 한다. - -work 테이블의 컬럼은 아래와 같이 구성되어있다. - -기본 정보: - -num: 기본 키로, 자동 증가하는 정수값입니다. -is_deleted: 삭제 여부를 나타내는 플래그입니다. -work_state: 작업의 상태를 나타내는 문자열입니다. -프로젝트 및 고객 정보: - -id, name, nick: 고객 또는 담당자에 대한 식별자 및 이름 정보입니다. -subject: 프로젝트나 작업의 제목입니다. -content, condate1, condate2: 프로젝트나 작업의 상세 내용 및 날짜 정보입니다. -regist_day: 등록 날짜를 기록합니다. -파일 및 문서 관련 정보: - -file_name_0 ~ file_name_4: 관련된 파일의 이름을 저장합니다. -file_copied_0 ~ file_copied_4: 파일 복사본의 이름을 저장합니다. -금전 및 청구 관련 정보: - -estimate1 ~ estimate4: 견적 관련 정보입니다. -bill1 ~ bill6: 청구서 관련 정보입니다. -deposit1 ~ deposit6: 입금 관련 정보입니다. -receivable: 미수금 관련 정보입니다. -claimamount1 ~ claimamount7, claimbalance1 ~ claimbalance7: 청구금액 및 잔액 정보입니다. -작업 진행 관련 정보: - -worklist: 작업 리스트를 저장합니다. -workday, endworkday: 작업 시작일과 종료일을 나타냅니다. -worker, cablestaff, asman: 작업자, 케이블 스태프, A/S 담당자 정보를 포함합니다. -A/S 관련 정보: - -asday, asendday, asproday: A/S 관련 날짜 정보입니다. -aslist, asresult, ashistory: A/S 관련 작업 리스트, 결과, 이력 정보를 저장합니다. -청구 및 클레임 정보: - -claimperson, claimtel: 클레임을 제기한 사람과 그 연락처입니다. -claimdate1 ~ claimdate6: 클레임 발생일을 기록합니다. -claimfix1 ~ claimfix7: 클레임 수정 관련 정보입니다. -기타 정보: - -comment, searchtag, update_log: 코멘트, 검색 태그, 업데이트 로그와 같은 부가 정보를 기록합니다. - - -## 공급가액,세액 자동만들기 프롬프트 -위의 코드에서 4개의 estimate 관련 내용을 한행에 td요소를 8개로 나눠서 날짜부터 금액을 표현하는 것까지 표현하고, -파일첨부는 colspan="1", colspan="7"로 구분해서 사용하자. - -그리고 위의 요소는 페이지를 오픈할때, 콤마를 제거하고, 숫자 3자리마다 콤마를 찍어주는 로직을 넣어준다. - -그리고, input이 발생할때 위의 요소는 세액은 readonly로 놓고, 공급가액을 넣으면 세액과 금액을 자동으로 계산하고, 반대로 금액을 넣으면 역으로 공급가액과 세액을 계산하는 동적 페이지로 구조를 자바스크립트로 만든다. - -$bill6_vat = isset($row['bill6_vat']) ? $row['bill6_vat'] : ''; -위의 형식으로 만들어줘. - -$bill6_vat = isset($_REQUEST['bill6_vat']) ? $_REQUEST['bill6_vat'] : ''; -위의 형식으로 만들어줘. - -1. 위의 코드를 $bill_issueDate1, $bill_issueDate2 ... 이런식으로 표현 -2. 위의 코드를 bill_issueDate1, bill_issueDate2 ... 이런식으로 표현 -3. 위의 코드를 bill_issueDate1=?, bill_issueDate2=? ... 이런식으로 표현 - -위의 3개를 만족하는 모양 형성해줘. - - -#컬럼제작 -만든 컬럼을 적용해서 하는데, 혹시 등록일자는 기본으로 있어야 할 것 같아. 등록일자(registedate) , is_deleted, updatelog, searchtag는 항상 기본으로 들어가야 한다. 모든 table에 있어야 한다. - -이에 따라 테이블에 4개의 컬럼을 추가하는 slq문장도 필요한다. - -위의 코드에서 tbody의 tr요소를 4개 만들건데, -name은 위의 tr요소 행 숫자만큼 col1부터 col13까지 [] 형식으로 만들어줘. - -아니다. 현재 php와 mysql의 버전이 json 타입으로 저장할수 없기에 text로 저장하는 대신 json으로 encode, decode해서 사용한다. - - -위의 코드는 수정되어야 한다. 일단 col18개까지 늘어야 한다. -엑셀은 D열부터 col1에 해당된다. 엑셀수식을 d5는 col1과 같은 것이다. 이렇게 해줘. -1) col7은 col3 * col4 으로 계산한다. -2) col8은 col5*col6*col7 로 계산한다. -3) col10 = col9* 1.2 -4) col11 = col8 * col10 -5) col12 는 엑셀수식 =ROUND(N5,-3) 이것을 이용한다. N5는 col11이다. -6) col14 는 엑셀수식 =ROUND(J5*P5,-3) -7) col15 , 엑셀수식 =O5+Q5 -8) col16 = 엑셀수식 =R5/J5 -9) col17 = 엑셀수식 =ROUND(S5,-3) -10) col18 = 엑셀수식 =R5/K5 - -이렇게 수식을 적용해줘. - -위의 코드는 수정되어야 한다. 일단 col20개까지 늘어야 한다. -엑셀은 D열부터 col1에 해당된다. 엑셀수식을 d5는 col1과 같은 것이다. 이렇게 해줘. -1) col6은 =(col7*col8*col9*col9)/1000 -2) col9은 col5/2 -3) col12 = col6 * col11 -4) col11 = col8 * col10 -5) col13는 col2 * col3 * col12 -6) col15는 col13 * col14 -7) col15은 엑셀수식 =O5+Q5 -8) col18은 =(col15/col2/col3)+col7 -9) col19= 엑셀수식 math.round(col18*1.2*1000)/1000 -10) col20= 엑셀수식 math.round(col18/3*1000)/1000 - -이렇게 수식을 적용해줘. - - - - - + - Copy - 품목 - 두께(T) - 폭 - 길이(M) - 가공비 - 입고가 - 원가합계 - 판매가 15% - - -위의 price_screenplate의 테이블을 아래의 th요소에 맞게 만들어야 한다. - - -function addRow(tableBody, rowData) { - var newRow = $(''); - - // + / - 버튼 추가 - newRow.append('' + - '
' + - '' + - '' + - '' + - '
'); - - // col1부터 col8까지 채우기 - for (let i = 1; i <= 8; i++) { - let colValue = rowData['col' + i] || ''; // 값이 없으면 빈 문자열 사용 - - // 첫 번째 열 제외, 모든 열에 텍스트 박스를 추가 - newRow.append(''); - } - - // 새 행을 테이블에 추가 - tableBody.append(newRow); - - // 숫자 필드에 3자리마다 콤마 추가 (소수점 입력 가능) - newRow.find('.number-format').on('input change', function() { - let value = $(this).val().replace(/,/g, ''); // 기존의 콤마를 제거 - - // 소수점 포함 숫자 검사 - if (!isNaN(value) && value !== '') { - // 정수와 소수 부분 분리 - let parts = value.split('.'); - parts[0] = Number(parts[0]).toLocaleString('en'); // 3자리마다 콤마 추가 - - // 소수점이 있는 경우 - let formattedValue = parts.join('.'); - - $(this).val(formattedValue); - } - - // 행 계산 함수 호출 - calculateRow(newRow); - }); - - // 처음 로드될 때도 자동 계산 적용 - calculateRow(newRow); -} - -function calculateRow(row) { - // 소수점 자릿수와 콤마를 포함한 숫자 형식 변환 함수 - function formatNumber(value, decimalPlaces) { - // value를 소수점 자릿수에 맞게 고정 - let fixedValue = parseFloat(value).toFixed(decimalPlaces); - - // 정수 부분과 소수 부분으로 분리 - let [integerPart, decimalPart] = fixedValue.split('.'); - - // 정수 부분에만 콤마 추가 - integerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ','); - - // 소수점 이하가 존재하고 0보다 큰 경우, 정수 부분과 결합하여 반환 - if (decimalPart && parseInt(decimalPart) > 0) { - return `${integerPart}.${decimalPart}`; - } else { - return integerPart; // 소수점 이하가 없거나 0인 경우 정수만 반환 - } - } - - // col1부터 col8까지의 값을 가져오기 - const col6 = parseFloat(row.find('.col6').val().replace(/,/g, '')) || 0; - const col7 = parseFloat(row.find('.col7').val().replace(/,/g, '')) || 0; - const col8 = parseFloat(row.find('.col8').val().replace(/,/g, '')) || 0; - - // 판매가 15% (col9) 계산: col8에 1.15를 곱한 값 - const col9 = col8 * 1.15; - if (!isNaN(col9)) { - row.find('.col9').val(formatNumber(col9, 0)); - } - - // 콤마 및 소수점 표시 설정 - if (!isNaN(col6)) { - row.find('.col6').val(formatNumber(col6, 2)); - } - if (!isNaN(col7)) { - row.find('.col7').val(formatNumber(col7, 2)); - } - if (!isNaN(col8)) { - row.find('.col8').val(formatNumber(col8, 0)); - } -} - - -위의 코드를 col1부터 col8까지 만들어야하는데, - -숫자 3자리마다 콤마 형태로 나오게 해줘. - -자동계산은 원가합계에 해당되는 col7과, col8이 해당되고 이 col7,col8은 수식이 적용되어야 한다. -col7은 = col5 + col6 -col8은 =ROUND(col7*1.2,-3) - - - - -#연기차단재 관련 생성 프롬프트 - -+ - Copy -품목 -용도 -단위(롤) -길이(mm) -폭(mm) -용차 -가공비 -입고가 -원가합계 -판매가 15% -1롤/50M - - -위의 price_smokeban의 테이블을 아래의 th요소에 맞게 만들어야 한다. -(위의 코드는 참고용이다. 11개의 컬럼을 만들어야 하니까.) -위의 코드를 col1부터 col11까지 만들어야하는데, -숫자 3자리마다 콤마 형태로 나오게 해줘. -자동계산은 원가합계에 해당되는 col9과, col10, col11이 해당되고 이는 수식이 적용되어야 한다. -col9은 = col6/(10*50) + col7+ col8 -col10은 =ROUND(col9 * 1.15,-3) -col11은 ==ROUND((col10*50)/(1200/50),-4) - - -function addRow(tableBody, rowData) { - var newRow = $(''); - - // + / - 버튼 추가 - newRow.append('' + - '
' + - '' + - '' + - '' + - '
'); - - // col1부터 col8까지 채우기 - for (let i = 1; i <= 8; i++) { - let colValue = rowData['col' + i] || ''; // 값이 없으면 빈 문자열 사용 - - // 첫 번째 열 제외, 모든 열에 텍스트 박스를 추가 - newRow.append(''); - } - - // 새 행을 테이블에 추가 - tableBody.append(newRow); - - // 숫자 필드에 3자리마다 콤마 추가 (소수점 입력 가능) - newRow.find('.number-format').on('input change', function() { - let value = $(this).val().replace(/,/g, ''); // 기존의 콤마를 제거 - - // 소수점 포함 숫자 검사 - if (!isNaN(value) && value !== '') { - // 정수와 소수 부분 분리 - let parts = value.split('.'); - parts[0] = Number(parts[0]).toLocaleString('en'); // 3자리마다 콤마 추가 - - // 소수점이 있는 경우 - let formattedValue = parts.join('.'); - - $(this).val(formattedValue); - } - - // 행 계산 함수 호출 - calculateRow(newRow); - }); - - // 처음 로드될 때도 자동 계산 적용 - calculateRow(newRow); -} - -function calculateRow(row) { - // 소수점 자릿수와 콤마를 포함한 숫자 형식 변환 함수 - function formatNumber(value, decimalPlaces) { - // value를 소수점 자릿수에 맞게 고정 - let fixedValue = parseFloat(value).toFixed(decimalPlaces); - - // 정수 부분과 소수 부분으로 분리 - let [integerPart, decimalPart] = fixedValue.split('.'); - - // 정수 부분에만 콤마 추가 - integerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ','); - - // 소수점 이하가 존재하고 0보다 큰 경우, 정수 부분과 결합하여 반환 - if (decimalPart && parseInt(decimalPart) > 0) { - return `${integerPart}.${decimalPart}`; - } else { - return integerPart; // 소수점 이하가 없거나 0인 경우 정수만 반환 - } - } - - // col1부터 col8까지의 값을 가져오기 - const col6 = parseFloat(row.find('.col6').val().replace(/,/g, '')) || 0; - const col7 = parseFloat(row.find('.col7').val().replace(/,/g, '')) || 0; - const col8 = parseFloat(row.find('.col8').val().replace(/,/g, '')) || 0; - - // 판매가 15% (col9) 계산: col8에 1.15를 곱한 값 - const col9 = col8 * 1.15; - if (!isNaN(col9)) { - row.find('.col9').val(formatNumber(col9, 0)); - } - - // 콤마 및 소수점 표시 설정 - if (!isNaN(col6)) { - row.find('.col6').val(formatNumber(col6, 2)); - } - if (!isNaN(col7)) { - row.find('.col7').val(formatNumber(col7, 2)); - } - if (!isNaN(col8)) { - row.find('.col8').val(formatNumber(col8, 0)); - } -} - - - -######## #개발자 컬럼보기 ######## -위의 코드에서 $user_id=='pro'인 경우는 th행을 하나 더 만들건데, -일련번호를 부여해서 개발할때 보려고 한다. -th 2번째 열부터 1로 시작해서 66열까지 1,2,.... 66번까지 col과 비교하면서 개발을 하려고 개발자 아이디인 'pro'만 보이도록 코드를 수정해줘. - -######단가 가져오기 fetch_price ##### 제작 프롬프트 -단가를 가져오는 코드들을 fetch_price.php를 호출해서 가져오는 방식이면 좋겠다. -이를 호출할때 테이블명과 값을 전달하면 결과를 리턴하는 방식이면 좋겠다. -그러면 위의 9가지 단가들에 대해서 하나의 모듈을 사용하면 효과적일 것 같다. - -물론 조건은 파라미터는 하나에서 여러개가 될 수 있다. - - -## json 저장 안됨 ## -$sql = "SELECT itemList FROM {$DB}.$tablename WHERE JSON_UNQUOTE(JSON_EXTRACT(itemList, '$.code')) IN ($placeholders) AND (is_deleted IS NULL OR is_deleted = 0)"; - -위의 코드는 잘못되었다. -php버전과 mysql에서 json을 지원하지 않는 버전을 사용한다. -text로 저장하고, encode, decode로 작업한다. - - -// 모터 부분 -if(True) { -$data = []; -$counter = 0; - foreach ($decodedEstimateList as $item) { - if (isset($item['col5']) && !empty($item['col5'])) { - $counter++; - // 각 col 값을 배열에 추가합니다. - $row = []; - $row['col1'] = '2.2
모터'; - $row['col2'] = $item['col3'] ?? ''; // 부호 - $row['col3'] = $item['col5'] ?? ''; // 실리카 - $row['col4'] = $item['col7'] ?? ''; // SUS - $row['col5'] = $item['col6'] ; // 벽마감표시 - $row['col6'] = $item['col8']; // 오픈 가로 - $row['col7'] = $item['col9']; // 오픈 세로 - $row['col8'] = $item['col10']; // 제작 가로 - $row['col9'] = $item['col11']; // 제작 세로 - - $row['col10'] = $item['col31']; // 케이스 500*380 - - // $data 배열에 행을 추가합니다. - $data[] = $row; - } - } - -모터부분의 내용의 누계를 내려고 한다. - - -## 모터 150 부터 1000까지 개수 파악하는 프롬프트 ## - -전체 col1~col12까지 배열은 필요없고 sum의 개념만 있으면 된다. -$item['col13']은 중량을 나타내는데 -이 값에 따라 col1~col7까지 누적해야 한다. -col1의 값은 아래의 엑셀공식이다. -E8은 $item['col4']의 문자열앞에 두문자'KS'이면 '스크린'으로 인식 -m8은 중량을 의미하는 $item['col13']; -엑셀공식 -=IF(AND(E8="스크린",BK8=4,M8<=150),1,IF(AND(E8="스크린",BK8=5,M8<=123),1,IF(AND(E8="스크린",BK8=6,M8<=104),1,0))) - -col2의 값은 아래의 엑셀공식이다. -E8은 $item['col4']의 문자열앞에 두문자'KS'이면 '스크린'으로 인식 -m8은 중량을 의미하는 $item['col13']; -bk8은 $item['col53']; -엑셀공식 -=IF(AND(E8="스크린",BK8=4,M8>150,M8<=300),1,IF(AND(E8="스크린",BK8=5,M8>123,M8<=246),1,IF(AND(E8="스크린",BK8=6,M8>104,M8<=208),1,IF(AND(E8="철재",BK8=4,M8<=300),1,IF(AND(E8="철재",BK8=5,M8<=246),1,IF(AND(E8="철재",BK8=6,M8<=208),1,0)))))) - -col3의 값은 아래의 엑셀공식이다. -E8은 $item['col4']의 문자열앞에 두문자'KS'이면 '스크린'으로 인식 -m8은 중량을 의미하는 $item['col13']; -bk8은 $item['col53']; -엑셀공식 -=IF(AND(E8="스크린",BK8=4,M8>300,M8<=400),1,IF(AND(E8="스크린",BK8=5,M8>246,M8<=327),1,IF(AND(E8="스크린",BK8=6,M8>208,M8<=300),1,IF(AND(E8="철재",BK8=4,M8>300,M8<=400),1,IF(AND(E8="철재",BK8=5,M8>246,M8<=327),1,IF(AND(E8="철재",BK8=6,M8>208,M8<=277),1,0)))))) - - - -col4의 값은 아래의 엑셀공식이다. -E8은 $item['col4']의 문자열앞에 두문자'KS'이면 '스크린'으로 인식 -m8은 중량을 의미하는 $item['col13']; -bk8은 $item['col53']; -엑셀공식 -=IF(AND(E8="스크린",BK8=5,M8>327,M8<=500),1,IF(AND(E8="스크린",BK8=6,M8>300,M8<=424),1,IF(AND(E8="철재",BK8=5,M8>400,M8<=500),1,IF(AND(E8="철재",BK8=5,M8>327,M8<=500),1,IF(AND(E8="철재",BK8=6,M8>277,M8<=424),1,IF(AND(E8="철재",BK8=8,M8<=324),1,0)))))) - -col5의 값은 아래의 엑셀공식이다. -E8은 $item['col4']의 문자열앞에 두문자'KS'이면 '스크린'으로 인식 -m8은 중량을 의미하는 $item['col13']; -bk8은 $item['col53']; -엑셀공식 -=IF(AND(BK8=5,M8>500,M8<=600),1,IF(AND(BK8=6,M8>424,M8<=508),1,IF(AND(BK8=8,M8>324,M8<=388),1,0))) - - -col6의 값은 아래의 엑셀공식이다. -E8은 $item['col4']의 문자열앞에 두문자'KS'이면 '스크린'으로 인식 -m8은 중량을 의미하는 $item['col13']; -bk8은 $item['col53']; -엑셀공식 -=IF(AND(E8="철재",BK8=6,M8>600,M8<=800),1,IF(AND(E8="철재",BK8=6,M8>508,M8<=800),1,IF(AND(E8="철재",BK8=8,M8>388,M8<=611),1,0))) - -col7의 값은 아래의 엑셀공식이다. -E8은 $item['col4']의 문자열앞에 두문자'KS'이면 '스크린'으로 인식 -m8은 중량을 의미하는 $item['col13']; -bk8은 $item['col53']; -엑셀공식 -=IF(AND(E8="철재",BK8=6,M8>800,M8<=1000),1,IF(AND(E8="철재",BK8=8,M8>611,M8<=1000),1,0)) - - - -col8의 값은 아래이다. -$item['col15']의 합 -col9의 값은 값은 아래이다. -$item['col16']의 합 -col10의 값은 값은 아래이다. -$item['col17']의 합 -col11의 값은 값은 아래이다. -$item['col14']의 합 -col12의 값은 값은 아래이다. -col11 * 4 - - -## 스크린 발주서 절곡 부분 ## - -// 절곡 부분 -if(True) { -$data = []; - -foreach ($decodedEstimateList as $item) { - -} - - echo '
'; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo '
2.3
절곡
(1) 가이드레일
(EGI 1.6T/ SUS 1.2T)
(2) 케이스
(EGI 1.6T)
(3) 하단마감재
(SUS 1.2T)
(4) 연기차단재
사이즈수량사이즈수량분류30004000종류수량
' . $col1_sum . '' . $col2_sum . '' . $col3_sum . '' . $col4_sum . '' . $col5_sum . '' . $col6_sum . '' . $col7_sum . '' . $col8_sum . '' . $col9_sum . '
'; - echo '
'; -} - - -아래의 5개는 배열은 필요없고 sum의 개념만 있으면 된다. -AC8은 $item['col23']은 셔터의 유효 길이를 의미한다. -이 값에 따라 row3_1 ~ row3_5는 행의 누계를 3_1은 3열, 1행을 의미한다. 총 5개를 만들어야 한다. -row3_1의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AC8<=2438,2,IF(AND(AC8>4300,AC8<=5438),2,0)) - -row3_2의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AC8>2438, AC8<=3000),2,IF(AND(AC8>4300,AC8<=5438),2,IF(AND(AC8>5438,AC8<=6000),4,IF(AND(AC8>6000,AC8<=7300),2,0)))) - -row3_3의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AC8>3000, AC8<=3500),2,IF(AND(AC8>6000,AC8<=6500),2,0)) - -row3_4의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AC8>3500, AC8<=4000),2,IF(AND(AC8>6500,AC8<=7000),2,0)) - -row3_5의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AC8>4000, AC8<=4300),2,IF(AND(AC8>7000,AC8<=7300),2,0)) - - - -아래의 8개는 배열은 필요없고 sum의 개념만 있으면 된다. -AQ8은 $item['col32']은 셔터의 유효 길이를 의미한다. -이 값에 따라 row5_1 ~ row5_6는 행의 누계를 5_1은 5열, 1행을 의미한다. -row5_1의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AQ8<=1219,1,IF(AND(AQ8>4150,AQ8<=4219),1,IF(AND(AQ8>4219,AQ8<=4719),1,IF(AND(AQ8>4876,AQ8<=5219),1,IF(AND(AQ8>5219,AQ8<=5369),1,IF(AND(AQ8>9026,AQ8<=9219),1,0)))))) - -row5_2의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AQ8>1219,AQ8<=2438),1,IF(AND(AQ8>4719,AQ8<=4876),2,IF(AND(AQ8>5369,AQ8<=5938),1,IF(AND(AQ8>6000,AQ8<=6438),1,IF(AND(AQ8>6500,AQ8<=6588),1,IF(AND(AQ8>8300,AQ8<=8376),2,IF(AND(AQ8>8376,AQ8<=8438),1,IF(AND(AQ8>8438,AQ8<=8876),2,IF(AND(AQ8>9000,AQ8<=9026),2,IF(AND(AQ8>9219,AQ8<=9438),1,IF(AND(AQ8>10150,AQ8<=10738),1,0))))))))))) - -row5_3의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AQ8>2438,AQ8<=3000),1,IF(AND(AQ8>4150,AQ8<=4219),1,IF(AND(AQ8>5369,AQ8<=5438),1,IF(AND(AQ8>5938,AQ8<=6000),2,IF(AND(AQ8>6438,AQ8<=6500),1,IF(AND(AQ8>7000,AQ8<=7150),1,IF(AND(AQ8>8376,AQ8<=8438),2,IF(AND(AQ8>8876,AQ8<=9000),3,IF(AND(AQ8>9438,AQ8<=10150),2,IF(AND(AQ8>10738,AQ8<=11000),1,0)))))))))) - -row5_4의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AQ8>3000,AQ8<=3500),1,IF(AND(AQ8>4219,AQ8<=4719),1,IF(AND(AQ8>5438,AQ8<=5938),1,IF(AND(AQ8>6438,AQ8<=6500),1,IF(AND(AQ8>6588,AQ8<=7000),2,IF(AND(AQ8>7150,AQ8<=7650),1,IF(AND(AQ8>8300,AQ8<=8376),1,IF(AND(AQ8>9219,AQ8<=9438),2,IF(AND(AQ8>9438,AQ8<=9500),1,0))))))))) - -row5_5의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AQ8>3500,AQ8<=4000),1,IF(AND(AQ8>4876,AQ8<=5219),1,IF(AND(AQ8>6000,AQ8<=6438),1,IF(AND(AQ8>7150,AQ8<=7500),1,IF(AND(AQ8>7650,AQ8<=8000),2,IF(AND(AQ8>8000,AQ8<=8150),1,IF(AND(AQ8>8438,AQ8<=8876),1,IF(AND(AQ8>9026,AQ8<=9219),2,IF(AND(AQ8>9500,AQ8<=10000),1,IF(AND(AQ8>10150,AQ8<=10438),2,IF(AND(AQ8>10738,AQ8<=11000),2,0))))))))))) - -row5_6의 값은 아래의 엑셀공식이다. -엑셀공식 -=IF(AND(AQ8>4000,AQ8<=4150),1,IF(AND(AQ8>5219,AQ8<=5369),1,IF(AND(AQ8>6500,AQ8<=6588),1,IF(AND(AQ8>7000,AQ8<=7150),1,IF(AND(AQ8>7500,AQ8<=7650),1,IF(AND(AQ8>8000,AQ8<=8150),1,IF(AND(AQ8>8150,AQ8<=8300),2,IF(AND(AQ8>9000,AQ8<=9026),1,IF(AND(AQ8>10000,AQ8<=10150),1,IF(AND(AQ8>10438,AQ8<=10738),2,0)))))))))) - -row5_7의 값은 $item['col39'] 의 합 -row5_8의 값은 $item['col41'] 의 합 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -work 테이블의 아래의 컬럼이 있다. - - - 1차 - - - - - - - - - 2차 - - - - - - - - - 3차 - - - - - - - - - 4차 - - - - - - - - - 5차 - - - - - - - - - 6차 - - - - - - - - - -6행의 컬럼이름들이 많다. 이 컬럼을 accountList 컬럼으로 넣으려고 하는데, -json형태로 만든 후 encode, decode를 통해 테이블에는 text형태로 저장할 것이다. -php와 mysql이 json 저장을 지원하지 않는 버전이라서 그렇다. - -그러면 아래의 코드에서 json의 encode, decode 코드형태를 엿볼 수 있다. - -위의 컬럼의 값들을 읽어서 1행부터 col1,col2,col3,col4,col5,col6까지 생성되는 것이다. -예를 들면, - 1차 - - - - - - - - -위의 코드는 col1은 bill_issueDate1이 되는 것이다. -위의 데이터는 6행을 반복하면 col1의 데이터는 -[{"col1":"2024-09-01"}.......{"col1":""}] - -이렇게 되는 것이겠지? - -아래의 코드를 참조하자. -setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); - -// 이 스크립트의 메모리 제한 증가 -ini_set('memory_limit', '256M'); - -$sql = "SELECT * FROM " . $DB . "." . $tablename . " "; - -try { - $stmh = $pdo->prepare($sql); - $stmh->execute(); - $rows = $stmh->fetchAll(PDO::FETCH_ASSOC); - - $dataByNum = []; - - // 데이터를 num별로 그룹화 - foreach ($rows as $row) { - $num = $row['num']; - if (!isset($dataByNum[$num])) { - $dataByNum[$num] = [ - 'accountList' => [] - ]; - } - $dataByNum[$num]['accountList'] = json_decode($row['accountList'], true); - } - - $updateData = []; - - // num별로 데이터 처리 - foreach ($dataByNum as $num => $lists) { - $newOrderlist = []; - - foreach ($lists['accountList'] as $item) { - $newItem = $item; - $tempCol14 = isset($item['col14']) ? $item['col14'] : ''; - $tempCol15 = isset($item['col15']) ? $item['col15'] : ''; - - $newItem['col15'] = $tempCol14; - $newItem['col16'] = $tempCol15; - - $newOrderlist[] = $newItem; - } - - $updateData[$num] = [ - 'accountList' => json_encode($newOrderlist, JSON_UNESCAPED_UNICODE) - ]; - } - - // 데이터베이스 업데이트 - $pdo->beginTransaction(); - - $sql = "UPDATE " . $DB . ".{$tablename} SET accountList = ? WHERE num = ?"; - $stmh = $pdo->prepare($sql); - - foreach ($updateData as $num => $data) { - $stmh->execute([$data['accountList'], $num]); - } - - $pdo->commit(); -} catch (PDOException $Exception) { - $pdo->rollBack(); - print "오류: " . $Exception->getMessage(); -} -?> - - -work 테이블의 위의 컬럼들을 accountList에 저장하는 코드로 만들어줘. 컬럼을 정리하려고 한다. - - -## json으로 올바르게 나오지 않는경우##### -## 아래의 코드로 하면 된다. - - // JSON이 배열인지 아닌지 여부를 확인하는 방법 - if (typeof accountList === 'string') { - try { - accountList = JSON.parse(accountList); - } catch (e) { - console.error('JSON 파싱 오류:', e); - accountList = []; - } - } - - if (Array.isArray(accountList)) { - console.log('accountList is an array:', accountList); - } else { - console.log('accountList is not an array, resetting to empty array'); - accountList = []; - } - - accountList.forEach(function(rowData, index) { - addBillRow($('#accountListBody'), rowData); - }); - - -##공급가액 아이콘으로 계산하기 ### - -function addRow_Bill(tableBody, rowData = {}) { - var newRow = $(''); - - // 첫 번째 열: 일련번호 (자동 생성) - newRow.append('' + - '
' + - '' + - '' + - '
'); - - // col1 (발행일자) - "0000-00-00"을 빈 문자열로 처리 - var col1Value = (rowData.col1 === "0000-00-00") ? '' : rowData.col1; - newRow.append(''); - - // col2 (공급가액) - newRow.append(''); - - // col3 (부가세) - newRow.append(''); - - // col4 (발행금액) - newRow.append(''); - - // col5 (입금일자) - "0000-00-00"을 빈 문자열로 처리 - var col5Value = (rowData.col5 === "0000-00-00") ? '' : rowData.col5; - newRow.append(''); - - // col6 (입금액) - newRow.append(''); - - tableBody.append(newRow); - - // 일련번호를 업데이트 - updateSerialNumbers(tableBody); - - // 숫자 필드에 3자리마다 콤마 추가 (소수점 입력 가능) - newRow.find('.number-format').on('input change', function() { - let value = $(this).val().replace(/,/g, ''); // 기존의 콤마를 제거 - - // 소수점 포함 숫자 검사 - if (!isNaN(value) && value !== '') { - // 정수와 소수 부분 분리 - let parts = value.split('.'); - parts[0] = Number(parts[0]).toLocaleString('en'); // 3자리마다 콤마 추가 - - // 소수점이 있는 경우 - let formattedValue = parts.join('.'); - - $(this).val(formattedValue); - } - - //계산 함수 호출 - calculateTotals(); - }); - - // 처음 로드될 때도 자동 계산 적용 - calculateTotals(); -} - - -위의 코드에 3번째 요소와 5번째 td요소인 발행합계의 열에 input요소 옆에 계산 아이콘은 배치해서 누르면 공급가액/부가세/발행합계를 그 행에 대해서 자동계산을 하려고 한다. -공급가액 옆의 아이콘을 누르면 공급가액을 기준으로 부가세와 발행금액이 계산되고, 발행금액을 누르면 역으로 공급가액과 부가세를 계산하는 원리다. - - 이 아이콘을 사용할거야. - -1행은 col1은 condate, col2는 estimate1_supply, col3는 estimate1_vat, col4는 estimate1, -col5는 file_name_0, , col6은 file_copied_0 -다소 매치가 안될것 같지만, 내가 제공한 코드를 보면 규칙이있으니 참고바랍니다. -2행은 col1은 condate1, col2는 estimate2_supply, col3는 estimate2_vat, col4는 estimate2, -col5는 file_name_1, col6은 file_copied_1 -2행은 col1은 condate2, col2는 estimate3_supply, col3는 estimate3_vat, col4는 estimate3, -col5는 file_name_2, col6은 file_copied_2 - -이렇게 나와야 한다. - - -#2. 파일 업로드 시 식별자 전송 -saveData 함수에서 파일을 전송할 때, 해당 파일의 row_id도 함께 전송하여 파일이 어느 행에 속하는지 알 수 있도록 합니다. - -실제 위와 같이 행을 동적으로 추가하고 그 마지막에 첨부파일을 넣는 방식인데, 여러가지 동적으로 행을 만들고 지우고 추가하고 하는 과정에서 내 마음대로 되지 않는구나. - -화면의 동적추가 및 기타 동작은 되지만, 서버에서 처리하는 insert.php 에서 제대로 되지 않는다. 이유는 알것 같지만, 막상 코드로 잘 안된다. - -문제는 이것이다. - -estimateList에서 col5, col6을 json형태로 가져와서 웹에서 front end에서는 잘 되는데 이것이 file을 서버로 전달하면, insert.php에서 파일의 첨부가 있을때, 이것이 1행에서 추가된 것이면 기존의 col5, col6의 1행에 해당되는 값만 수정이 되어야 하는데, -지금은 만약 4행이 있다면 4행 전부가 그 파일이름으로 수정이 되고, 1행은 서버저장 파일이름도 잘못되서 나온다. - -결국은 estimateList의 각 행과 upfile로 전달된 file의 첨부가 몇행에서 이뤄졌는지 정보가 전달되어야 정확할 것 같은데 방법이 있을까? - -ChatGPT의 말: - -ChatGPT -네, 상황을 이해했습니다. estimateList의 각 행과 파일 업로드가 정확히 매칭되지 않아서 문제가 발생하고 있습니다. 이를 해결하기 위해서는 다음과 같은 전략을 사용해야 합니다: - -해결책: -행의 고유 식별자 추가: 각 행이 고유한 식별자를 가지도록 하여 파일 업로드와 정확히 매칭할 수 있도록 합니다. 이 식별자는 행이 생성될 때마다 할당되며, insert.php에서 파일 업로드 처리 시 이 식별자를 사용해 해당 행과 파일을 매칭합니다. - -파일 업로드 시 식별자 전송: 파일 업로드가 일어날 때 해당 파일이 어느 행에 속하는지 식별자를 함께 전송합니다. 이를 통해 insert.php에서 해당 행만 파일 정보를 업데이트할 수 있습니다. - -1. 행의 고유 식별자 추가 -각 행에 고유한 data-id 속성을 추가합니다. 이 속성은 자바스크립트에서 행을 생성할 때 무작위 또는 순차적으로 생성됩니다. - - -#컬럼등 추가했을때 만들어주는 코드 -cableworkStatus, certifiedInspector, certifiedLabelAttachedDate - -위의 3개의 컬럼을 추가했다. - -_row.php 파일은 아래의 형태이다. 추가해줘. -8250,H8<=10200),1,0) -$col61은 =IF(AND(E8="스크린",BK8=6,H8>8250,H8<=10200),1,0) - - - var fileDiv = $('
').attr('id', 'file' + i).css({ - display: 'inline-block', - width: 'calc(20% - 10px)', // 5개를 한 줄에 맞추기 위해 20%의 너비 할당 (5개의 이미지가 한 줄에 배치됨) - margin: '5px', - textAlign: 'center' // 이미지와 버튼을 중앙 정렬 - }); - - -위의 코드는 5개 있을때는 좋은데, 1개, 2개 이미지가 있을때는 서로 겹처보인다. 1개, 2개~ 5개까지 여백이 확보되게 수정해줘. - -## 같은 이름의 첨부파일 등록하지 않기 - -코드 수정: -다음은 파일을 FormData에 추가하기 전에 중복 여부를 검사하는 코드입니다. - -javascript -코드 복사 -function uploadFiles(files) { - console.log('업로드 파일 리스트:', files); - - isUploading = true; // 업로드 중 상태 설정 - - var formData = new FormData($('#board_form')[0]); - - // 현재 폼 데이터에 추가된 파일 이름 목록 추적 - var existingFiles = new Set(); - for (var pair of formData.entries()) { - if (pair[0] === 'upfile[]') { - existingFiles.add(pair[1].name); - } - } - - // 중복되지 않은 파일만 추가 - for (var i = 0; i < files.length; i++) { - if (!existingFiles.has(files[i].name)) { - formData.append('upfile[]', files[i]); - existingFiles.add(files[i].name); // 추가된 파일 이름을 목록에 저장 - console.log('파일 추가:', files[i].name); // 디버그 - } else { - console.log('중복 파일 무시:', files[i].name); // 디버그 - } - } - -#토글버튼 추가로직 # -위의 코드에서 table을 보이게 안보이게 하는 토글 버튼을 만들건데, 아래의 코드를 참조해서 html 코드와 자바스크립트를 추가해줘. -쿠키에도 저장하고 다시 불러오는 과정도 포함된다. - -
-
-
-
-
-
절곡판
- - - -
- - - - - - - - - - - - - -
품목규격두께(T)비중㎡ / 단가
-
-
-
- -$(document).ready(function() { - initializePage(); - - // Toggle button for bendTable - $("#bendTableToggle").on("click", function() { - var showBendTable = getCookie("showBendTable"); - var bendTable = $("#item_bendTable"); - if (showBendTable === "show") { - bendTable.css("display", "none"); - setCookie("showBendTable", "hide", 10); - } else { - bendTable.css("display", "block"); - setCookie("showBendTable", "show", 10); - } - }); - - // Check the cookie value on page load and set the table visibility - var showBendTable = getCookie("showBendTable"); - var bendTable = $("#item_bendTable"); - if (showBendTable === "show") { - bendTable.css("display", "block"); - } else { - bendTable.css("display", "none"); - } -}); - - -##발주서 테이블 생성원리 설명자료 ## - -이제부터 생성원리에 대한 설명을 시작한다. -tr 1행은 아래와 같이 구성된다. 12개로 나뉜다. -구성품 길이 (mm) 수량 구성품 길이 수량 구성품 길이 수량 구성품 길이 수량 - -td 1열은 '하단마감재
-(60*40)' -td 2열은 길이 3000 또는 4000으로 구성된 자료를 읽어와서 해당수량을 다음열인 3열에 나타내는 것이다. -길이 3000에 대한 수량 col44 -길이 4000에 대한 수량 col45 - - -td 4열은 '하단
보강엘바
-(60*17)' -td 5열은 길이 3000 또는 4000으로 구성된 자료를 읽어와서 해당수량을 다음열인 6열에 나타내는 것이다. -길이 3000에 대한 수량 col47 -길이 4000에 대한 수량 col48 - - -td 7열은 '하단
-보강평철' -td 8열은 길이 3000 또는 4000으로 구성된 자료를 읽어와서 해당수량을 다음열인 9열에 나타내는 것이다. -길이 3000에 대한 수량 col50 -길이 4000에 대한 수량 col51 - - -td 10열은 '하단
무게평철
-[50*12T]' -td 11열은 길이 2000으로 구성된 자료를 읽어와서 해당수량을 다음열인 12열에 나타내는 것이다. -길이 2000에 대한 수량 col52 - -위의 내용을 코드로 만들어줘. - - - - - - -
- 2438, 'sum' => 0], - ['length' => 3000, 'sum' => 0], - ['length' => 3500, 'sum' => 0], - ['length' => 4000, 'sum' => 0], - ['length' => 4300, 'sum' => 0] - ]; - - foreach ($eList as $item) { - $AC8 = floatval($item['col23']); // 셔터의 유효 길이 - $railType = trim($item['col6']); // 벽부형, 측면형, 혼합형 여부 판단 - - // 혼합형일 경우 1개씩 계산, 나머지는 2개씩 계산 - for ($i = 0; $i < count($row3_data); $i++) { - $length = $row3_data[$i]['length']; - if ($AC8 <= $length) { - $row3_data[$i]['sum'] += ($railType == '혼합형') ? 1 : 2; - break; - } - } - } - - // 벽면형과 측면형을 혼합형일 때는 두 개씩, 나머지는 하나씩 출력 - $wall_rows = []; - $side_rows = []; - - foreach ($row3_data as $row) { - if ($row['sum'] > 0) { - if ($railType == '혼합형') { - $wall_rows[] = [ - 'length' => $row['length'], - 'sum' => $row['sum'] - ]; - $side_rows[] = [ - 'length' => $row['length'], - 'sum' => $row['sum'] - ]; - } elseif ($railType == '벽면형(120*70)') { - $wall_rows[] = [ - 'length' => $row['length'], - 'sum' => $row['sum'] - ]; - } elseif ($railType == '측면형(120*120)') { - $side_rows[] = [ - 'length' => $row['length'], - 'sum' => $row['sum'] - ]; - } - } - } - - // 벽면형 테이블 출력 (혼합형일 경우에만) - if ($railType == '혼합형' || $railType == '벽면형(120*70)') { - echo '
'; - echo '
'; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - echo ''; - echo '
1.1 벽면형[120*70]입고 LOT NO.
벽면형세부품명재질
①마감재' . $GuidrailFinish . '
②가이드레일' . $GuidrailFinish . '
③C형
④D형
⑤별도마감재' . $GuidrailExtraFinish . ' 없음
하부BASEEGI 1.55T
'; - echo '
'; - echo '
'; - - // 작업량 테이블 추가 (벽면형) - echo '
'; - echo '
'; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - $wall_sum = 0; - foreach ($wall_rows as $row) { - echo ''; - echo ''; - echo ''; - echo ''; - $wall_sum += $row['sum']; - } - - echo ''; - echo ''; - echo ''; - echo ''; - - echo ''; - echo '
작업량
길이/규격수량
' . $row['length'] . '' . $row['sum'] . '
하부BASE
(130*80)
' . $wall_sum . '
'; - echo '
'; - echo '
'; - } - - // 측면형 테이블 출력 (혼합형일 경우에만) - if ($railType == '혼합형' || $railType == '측면형(120*120)') { - echo '
'; - echo '
'; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - echo ''; - echo '
1.2 측면형[120*120]입고 LOT NO.
측면형세부품명재질
①②마감재' . $GuidrailFinish . '
③가이드레일' . $GuidrailFinish . '
④가이드레일
⑤C형
⑥D형
⑦⑧별도마감재' . $GuidrailExtraFinish . ' 없음
하부BASEEGI 1.55T
'; - echo '
'; - echo '
'; - - // 작업량 테이블 추가 (측면형) - echo '
'; - echo '
'; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - $side_sum = 0; - foreach ($side_rows as $row) { - echo ''; - echo ''; - echo ''; - echo ''; - $side_sum += $row['sum']; - } - - echo ''; - echo ''; - echo ''; - echo ''; - - echo ''; - echo '
작업량
길이/규격수량
' . $row['length'] . '' . $row['sum'] . '
하부BASE
(130*130)
' . $side_sum . '
'; - echo '
'; - echo '
'; - } -} -?> -
- -위의 코드를 하단마감재의 내용으로 전부 수정해줘. - -하단마감재 계산방법은 아래와 같다. 즉, 혼합형,벽면형, 측면형 표시는 필요가 없다. - -이미지는 ../img/bottombar/bottombar_KSS01.jpg -../img/bottombar/bottombar_KSE01.jpg - -이런식으로 이름과 관련이미지가 저장되어있다. -KWE01는 KSE01과 같은 형태다. - -하단마감재 산출공식은 아래를 참조한다. - - -
-3-2. 하단마감재
-' ; -?> - - - [ - 'size' => '(60*40)', - 'length_3000' => 0, - 'length_4000' => 0 - ], - '하단 보강엘바' => [ - 'size' => '(60*17)', - 'length_3000' => 0, - 'length_4000' => 0 - ], - '하단 보강평철' => [ - 'size' => '', - 'length_3000' => 0, - 'length_4000' => 0 - ], - '하단 무게평철' => [ - 'size' => '[50*12T]', - 'length_2000' => 0 - ] - ]; - - // 데이터를 누적하여 합산 - foreach ($eList as $item) { - $item_data['하단마감재']['length_3000'] += intval($item['col44']); - $item_data['하단마감재']['length_4000'] += intval($item['col45']); - $item_data['하단 보강엘바']['length_3000'] += intval($item['col47']); - $item_data['하단 보강엘바']['length_4000'] += intval($item['col48']); - $item_data['하단 보강평철']['length_3000'] += intval($item['col50']); - $item_data['하단 보강평철']['length_4000'] += intval($item['col51']); - $item_data['하단 무게평철']['length_2000'] += intval($item['col52']); - } - - // 테이블 출력 시작 - echo '
'; - echo ''; - - // 첫 번째 행: 자재 구성품명, 길이, 수량 표시 - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - // 두 번째 행: 3000mm 길이에 대한 수량 표시 - echo ''; - // 하단 마감재 - echo ''; - echo ''; - echo ''; - - // 하단 보강엘바 - echo ''; - echo ''; - echo ''; - - // 하단 보강평철 - echo ''; - echo ''; - echo ''; - - // 하단 무게평철 - echo ''; - echo ''; - echo ''; - echo ''; - - // 세 번째 행: 4000mm 길이에 대한 수량 표시 - echo ''; - // 하단 마감재 (길이 4000) - echo ''; - echo ''; - - // 하단 보강엘바 (길이 4000) - echo ''; - echo ''; - - // 하단 보강평철 (길이 4000) - echo ''; - echo ''; - - // 하단 무게평철은 2000mm만 존재하므로 공백 처리 - echo ''; - - echo ''; - echo '
구성품길이 (mm)수량구성품길이 (mm)수량구성품길이 (mm)수량구성품길이 (mm)수량
하단마감재
' . $item_data['하단마감재']['size'] . '
L : 3,000' . ($item_data['하단마감재']['length_3000'] ?: '-') . '하단
보강엘바
' . $item_data['하단 보강엘바']['size'] . '
L : 3,000' . ($item_data['하단 보강엘바']['length_3000'] ?: '-') . '하단
보강평철
L : 3,000' . ($item_data['하단 보강평철']['length_3000'] ?: '-') . '하단
무게평철
' . $item_data['하단 무게평철']['size'] . '
L : 2,000' . ($item_data['하단 무게평철']['length_2000'] ?: '-') . '
L : 4,000' . ($item_data['하단마감재']['length_4000'] ?: '-') . 'L : 4,000' . ($item_data['하단 보강엘바']['length_4000'] ?: '-') . 'L : 4,000' . ($item_data['하단 보강평철']['length_4000'] ?: '-') . '
'; - echo '
'; -} -?> - - - -이미지 정보를 하나 갖고 있는 컬럼(imgdata과 절곡의 전개치수를 저장하는 변수 plateList, -연신율을 저장하는 변수 bendingrateList, 음영정보를 기록하는 colorList, A각 정보를 담고 있는 AList - -위의 컬럼은 전부 'text' 형태이고, 아래의 추가적인 정보를 포함해서 bending 테이블을 생성하는 sql 코드 만들어줘. - - -php 7.3이전의 버전이라서 json 형태의 mysql 저장이 안되서 text로 저장하고 JSON형태의 파일을 encode, decode해서 사용할 예정입니다. - - - - -위의 코드는 write.php 전체의 코드인데, -mysql 버전이 낮아서 json형태로 저장하는 것이 직접되지 않아서, -text형태로 json 디코드, 인코드하는 과정을 거쳐서 서버에 저장한다. -bending 테이블의 컬럼은 text로 선언된 상태이다. - - - -사진관련 동작이 잘되니 좋다. - - 5) { - sleep(1); - header("Location:" . $WebSite . "login/login_form.php"); - exit; -} - -include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php'; - -// 첫 화면 표시 문구 -$title_message = '절곡바라시 기초자료'; -?> - - <?=$title_message?> - - - - - - 0) { - - try { - $sql = "SELECT * FROM " . $DB . "." . $tablename . " WHERE num=?"; - $stmh = $pdo->prepare($sql); - $stmh->bindValue(1, $num, PDO::PARAM_STR); - $stmh->execute(); - - $row = $stmh->fetch(PDO::FETCH_ASSOC); - include '_row.php'; - - } catch (PDOException $Exception) { - print "오류: " . $Exception->getMessage(); - } - - $mode = 'update'; - - $memo = ''; - $imgdata = ''; - $itemName = ''; - $inputList = '{}'; // JSON 초기값 - $plateList = '{}'; // JSON 초기값 - $bendingrateList = '{}'; // JSON 초기값 - $colorList = '{}'; // JSON 초기값 - $AList = '{}'; // JSON 초기값 - $sumList = '{}'; // JSON 초기값 - $title_message = '절곡바라시 기초자료 수정'; - -} else { - include '_request.php'; - - $mode = 'insert'; - $memo = ''; - $imgdata = ''; - $itemName = ''; - $inputList = '{}'; // JSON 초기값 - $plateList = '{}'; // JSON 초기값 - $bendingrateList = '{}'; // JSON 초기값 - $colorList = '{}'; // JSON 초기값 - $AList = '{}'; // JSON 초기값 - $sumList = '{}'; // JSON 초기값 - $registdate = date('Y-m-d'); // 현재일자 기록 -} -?> - -
- - - > - > - > - - - - - - - - - -
-
-
- -
-
-
-
-
-
- -
-
-
-
- L bar -
-
-
- - - - -
- -
- 여기로 사진을 drop 하세요! -
-
- -
-
-
-
- - - - -
-
-
-
- 등록일 - - 품명 - - 재질 - -
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
항목   값
번호 -
- 1 -
-
입력 -
- -
-
연신율 (-) -
- -
-
-
- -
-
음영 -
- -
-
A각 표시 -
- -
-
-
-
- - - -
-
-
-
-
-
-
-
-
-
- - - - - - - - - - -
- - - - - - - - -위의 코드는 write.php 전체의 코드인데, -mysql 버전이 낮아서 json형태로 저장하는 것이 직접되지 않아서, -text형태로 json 디코드, 인코드하는 과정을 거쳐서 서버에 저장한다. -bending 테이블의 컬럼은 text로 선언된 상태이다. - -위의 코드에서 서버로 보낼때 코드에 문제가 없는가? -예전의 사이트에서는 json으로 저장된 것을 아래와 같은 방식으로 form에 저장한 후 서버에 저장한다. -save를 저장하면 -예시) - - const formData = new FormData(document.getElementById('board_form')); - formData.set('mode', Number($("#num").val()) < 1 ? 'insert' : 'modify'); - - let itemList = []; - $('#itemListTable tbody tr').each(function() { - let rowData = {}; - $(this).find('input, select').each(function() { - let name = $(this).attr('name').replace('[]', ''); - rowData[name] = $(this).val(); - }); - itemList.push(rowData); - }); - - formData.set('itemList', JSON.stringify(itemList)); - -서버에서 받을때는 아래와 같은처리함. - -// 테이블 데이터 JSON 파싱 -if (isset($_POST['itemList'])) { - $itemList_jsondata = json_decode($_POST['itemList'], true); -} else { - $itemList_jsondata = null; -} - -if ($mode == "modify") { - $updatelog = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] . " " . $updatelog . " "; - - try { - $pdo->beginTransaction(); - $sql = "UPDATE " . $DB . ".{$tablename} SET - is_deleted=?, orderDate=?, secondord=?, secondordman=?, secondordmantel=?, pjnum=?, pjname=?, jobNo=?, spec=?, daesu=?, - unit=?, deadlineDate=?, drawDate=?, requestmaDate=?, stackmaDate=?, shearingDate=?, nctDate=?, bendingDate=?, assemblyDate=?, - outputDate=?, comment=?, memo=?, unitprice=?, amount=?, invoiceAmount=?, invoiceDate=?, itemList=?, - updatelog=?, status=? , searchtag=? , deliverymethod=?, address=? , makeDate=? - WHERE num=? LIMIT 1"; - - $stmh = $pdo->prepare($sql); - - $params = [ - $is_deleted, $orderDate, $secondord, $secondordman, $secondordmantel, $pjnum, $pjname, $jobNo, $spec, $daesu, - $unit, $deadlineDate, $drawDate, $requestmaDate, $stackmaDate, $shearingDate, $nctDate, $bendingDate, $assemblyDate, - $outputDate, $comment, $memo, $unitprice, $amount, $invoiceAmount, $invoiceDate, json_encode($itemList_jsondata), - $updatelog, $status, $searchtag, $deliverymethod, $address , $makeDate , $num - ]; - - -위의 자바스크립 코드를 제이쿼리 형식으로 전부 수정해주고, -null에 의한 오류가 안나도록 검사하고 실행하는 코드를 다 넣어주세요. - - -CREATE TABLE `instock` ( - `num` int NOT NULL AUTO_INCREMENT, - `is_deleted` tinyint DEFAULT NULL, - `lot_no` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `inspection_date` date NOT NULL, - `supplier` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `item_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `specification` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `unit` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `received_qty` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `material_no` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `manufacturer` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `remarks` text CHARACTER SET utf8 COLLATE utf8_general_ci, - `purchase_price_excl_vat` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, - `weight_kg` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - `searchtag` text CHARACTER SET utf8 COLLATE utf8_general_ci, - `update_log` text CHARACTER SET utf8 COLLATE utf8_general_ci, - PRIMARY KEY (`num`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 - - --- dbchandj.material_reg definition - -CREATE TABLE material_reg ( - num int NOT NULL AUTO_INCREMENT, - is_deleted tinyint DEFAULT NULL, - registedate date NOT NULL, - inoutdate date NOT NULL, - secondord varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - inout_item_code varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - item_name varchar(50) NOT NULL, - surang varchar(10) NOT NULL, - lotnum varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, - comment text, - unitprice varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, - searchtag text, - update_log text, - secondordnum varchar(10) DEFAULT NULL, - PRIMARY KEY (num) -) ENGINE=InnoDB AUTO_INCREMENT=248 DEFAULT CHARSET=utf8; - -위의 형식을 기반으로, 위의 컬럼명은 무시하고, - -table 'lot_sales'를 생성하려고 합니다. -컬럼은 아래와 같은데요. 한글을 영문화를 해주세요. -num, 등록일, LOT번호, 작성자, 비고, updatelog, searchtag, is_deleted -num은 고유번호로 autoincrement 적용입니다. - -CREATE TABLE `lot_sales` ( - `num` int NOT NULL AUTO_INCREMENT, -- 고유번호 - `reg_date` date NOT NULL, -- 등록일 - `lot_number` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, -- LOT번호 - `author` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, -- 작성자 - `remark` text, -- 비고 - `update_log` text, -- 업데이트 로그 - `search_tag` text, -- 검색 태그 - `is_deleted` tinyint DEFAULT NULL, -- 삭제 여부 - PRIMARY KEY (`num`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -fetch_modal.php 파일의 내용도 수정하려고 합니다. 위의 컬럼 내용으로 -기존의 list.php에서 이 부분이 빠졌는데, 아래의 코드를 완성하고, list.php에서 모달창을 불러오는 과정도 들어가야 합니다. - - -// 테이블 데이터 JSON 파싱 -if (isset($_POST['itemList'])) { - $itemList_jsondata = json_decode($_POST['itemList'], true); -} else { - $itemList_jsondata = null; -} -if ($mode == "modify") { - $updatelog = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] . " " . $updatelog . " "; - - try { - $pdo->beginTransaction(); - $sql = "UPDATE " . $DB . ".{$tablename} SET itemList=? WHERE num=? LIMIT 1"; - - $stmh = $pdo->prepare($sql); - - $params = [ - json_encode($itemList_jsondata) , $num - ]; - - -// 셔터박스 자동생성 로직 개발 -prepare($sql); - $stmh->bindValue(1, $num, PDO::PARAM_INT); - $stmh->execute(); - $row = $stmh->fetch(PDO::FETCH_ASSOC); - - include '_row.php'; - } catch (PDOException $Exception) { - echo "오류: ".$Exception->getMessage(); - exit; -} - -$title_message = '셔터박스 절곡 전개'; - -// echo '
';
-// print_r($row);
-// echo '
'; - -// 기존에 저장된 값이 있는 경우 해당 값을 설정 -$selected_check_typeFlat = isset($row['check_type']) ? $row['check_type'] : '양쪽 점검구'; - -?> - - - -
-
-
-
- -
-
-
-
- - - -
-
-
-
- Image - - - -
-
-
-
- - - - - - -
-
- 셔터박스 - 가로(폭) - - x - 세로(높이) - -
-
-
-
-
- -
-
-
-
-
- -위의 코드는 fetch_flat.php 코드이다. - -위의 코드에 새로운 내용을 추가할 것이다. -셔터박스의 각 부위에 대한 연산방법을 표현할때 절곡물의 형태에 따라 계산법이 있다. -위의 3가지 유형의 셔터박스의 계산법은 일부는 같고, 일부는 다르다. -그 계산하는 과정을 표현하는 코드는 아래를 참조한다. - -
- - - - -
-
- -해당 테이블의 CSS 코드 - - - -새로운 테이블은 총 6개의 행으로 구성되며, 각 열의 형성과정은 아래의 코드로 알 수 있다. - - -function addInitialColumn() { - - const tableBody = $('#tableBody'); - - if (!tableBody.length) return; - - const rowsData = [ - { label: '번호', type: 'span', className: 'form-control text-center', style: 'width: 40px;' }, - { label: '입력', type: 'input', className: 'form-control yellowBold text-center', style: 'width: 40px;', name: 'inputList[]', event: 'calculateSum()' }, - { label: '연신율 (-)', type: 'input', className: 'form-control text-center', style: 'width: 40px;', name: 'bendingrateList[]', event: 'calculateSum()' }, - { label: '합계', type: 'input', className: 'form-control orangeBlackBold text-center', style: 'width: 40px;', name: 'sumList[]' }, - { label: '음영', type: 'checkbox', className: 'form-check-input form-control ', style: 'width: 20px; height: 20px; margin-left: 20px; margin-right: 20px;', name: 'colorList[]' }, - { label: 'A각 표시', type: 'checkbox', className: 'form-check-input form-control ', style: 'width: 20px; height: 20px; margin-left: 20px; margin-right: 20px;', name: 'AList[]' } - ]; - - rowsData.forEach(function(rowData) { - const row = $(''); - - const labelCell = $('').addClass('lightgray').text(rowData.label); - row.append(labelCell); - - const inputCell = $('').addClass('input-container'); - - if (rowData.type === 'span') { - const span = $('').addClass(rowData.className).css('width', '40px').text('1'); - inputCell.append(span); - } else { - const input = $('') - .attr('type', rowData.type) - .addClass(rowData.className) - .css('width', ( rowData.type === 'checkbox' || rowData.type === 'checkbox') ? '20px' : '40px') - .css('margin-left', ( rowData.type === 'checkbox' || rowData.type === 'checkbox') ? '10px' : '') - .css('margin-right', ( rowData.type === 'checkbox' || rowData.type === 'checkbox') ? '20px' : '') - .attr('autocomplete', 'off'); // 올바른 autocomplete 설정 - - if (rowData.name) input.attr('name', rowData.name); - if (rowData.event) { - input.on('input change', calculateSum); - } - - inputCell.append(input); - } - - row.append(inputCell); - tableBody.append(row); - }); -} - - -내가 구현하는 것은 셔터박스 형태 3가지 종류에 대한 절곡품 1번부터 7번까지 정보를 위의 코드에서 참조해서 테이블 형태로 화면에 보여주고 싶다. -그 생성원리는 아래와 같다. - -1번 전면부 : 7개의 숫자로 이뤄지는데 입력값이 20, 15, 55, 4번째요소는 연산을 해야 한다. $box_height값이 된다. , 5번째 요소는 $front_bottom_width 값이다. ,55,17 이것이 자료가 된다. -2번 린텔부는 고정치수이다. 입력값은 5개의 배열이다. 30,55,50,15,20 - -일단 2개까지만 만들어줘. 추가로 3번부터 7번까지는 코드의 완성도를 보고 제공하겠다. - - - -#로그기록 함수. common.js 저장됨 - -function saveMenuLog(title) { - - var formData = new FormData(); - formData.append('menu', title); - - $.ajax({ - enctype: 'multipart/form-data', // file을 서버에 전송하려면 이렇게 해야 함 주의 - processData: false, - contentType: false, - cache: false, - timeout: 600000, - url: "/insert_logmenu.php", - type: "post", - data: formData, - dataType: "json", - success: function(data){ - console.log(data); - }, - error: function(jqxhr, status, error) { - console.log(jqxhr, status, error); - alert("An error occurred: " + error); // Display error message - } - }); -} - -$(document).ready(function(){ - // 방문기록 남김 - var title = ''; - saveMenuLog(title); -}); - -## 테이블 기본 생성칼럼 - -bendingmap 테이블을 생성할 것이다. - - -위의 컬럼은 기본적으로 생성한다. 레코드번호, 비고, 업데이트정보, 삭제여부, 작성자, 검색어 정보 등 기본적으로 테이블생성할때 필요한 요소이다. - - - - -echo '' . htmlspecialchars($row['col1']) . ''; - data-bs-toggle="tooltip" data-bs-placement="bottom" title="화물회사에서 대한의 요청에 대한 다른 사항이 발생하면 기록합니다." - - - - - - - 원자재 LOT - - - - - -위의 코드에서 input요소에 data-searchRaw= 형태로 제이쿼리 data 값을 읽는 형태로 만들고 싶다. 위의 값에 들어갈 것은 -해당 품목의 재질을 전달하고자 한다. -품목과 종류의 조합에 따라 재질이 결정된다. -아래의 정보를 참고해 주세요. -품목 : 연기차단재, 종류 : 화이바원단 => '화이바원단' -품목 : 하단마감재(스크린), 종류 : SUS => 'SUS 1.2T' -품목 : 하단마감재(스크린), 종류 : EGI => 'EGI 1.55T' -품목 : L - Bar, 종류 : 스크린용 => 'EGI 1.15T' -품목 : 가이드레일, 종류 : SUS => 'SUS 1.2T' -품목 : 가이드레일, 종류 : D형 => 'EGI 1.55T' -품목 : 가이드레일, 종류 : C형 => 'EGI 1.55T' -품목 : 가이드레일, 종류 : 본체 => 'EGI 1.55T' -품목 : 가이드레일, 종류 : EGI => 'EGI 1.55T' -품목 : 케이스, 종류 : 후면커버 => 'EGI 1.55T' -품목 : 케이스, 종류 : 린텔부 => 'EGI 1.55T' -품목 : 케이스, 종류 : 점검구 => 'EGI 1.55T' -품목 : 케이스, 종류 : 전면부 => 'EGI 1.55T' - -위의 내용이 전달되고, 이를 찾는 과정을 코드로 만들어줘. - -관련코드를 공유한다. - - - - // 품목명을 매핑하는 배열 - $prodNames = [ - 'R' => '가이드레일(벽면형)', - 'S' => '가이드레일(측면형)', - 'G' => '연기차단재', - 'B' => '하단마감재(스크린)', - 'T' => '하단마감재(철재)', - 'L' => 'L - Bar', - 'C' => '케이스' - ]; - - // 종류명을 매핑하는 배열 - $specNames = [ - 'I' => '화이바원단', - 'S' => 'SUS(마감)', - 'U' => 'SUS마감2', - 'E' => 'EGI(마감)', - 'A' => '스크린용', - 'D' => 'D형', - 'C' => 'C형', - 'M' => '본체', - 'T' => '본체(철재)', - 'B' => '후면커버', - 'L' => '린텔부', - 'P' => '점검구', - 'F' => '전면부' - ]; - - // 모양&길이를 매핑하는 배열 - $slengthNames = [ - '53' => 'W50 × 3000', - '54' => 'W50 × 4000', - '83' => 'W80 × 3000', - '84' => 'W80 × 4000', - '12' => '1219', - '24' => '2438', - '30' => '3000', - '35' => '3500', - '40' => '4000', - '41' => '4150', - '42' => '4200', - '43' => '4300' - ]; - -위의 코드로 일부 코드가 변경되었다. 아래의 코드에 이 코드를 적용해 주세요. - - - // 품목별 선택 가능한 종류 목록 설정 - const options = { - 'G': ['I'], // 연기차단재 - 화이바원단 - 'B': ['S', 'E'], // 하단마감재(스크린) - SUS, EGI - 'T': ['S', 'E'], // 하단마감재(철재) - SUS, EGI - 'L': ['A'], // L - Bar - 스크린용 - 'R': ['S', 'D', 'C', 'M', 'E'], // 가이드레일 - SUS, D형, C형, 본체, EGI - 'C': ['B', 'L', 'P', 'F'] // 케이스 - 후면커버, 린텔부, 점검구, 전면부 - }; - - const prodSelect = document.getElementById('prod'); - const specSelect = document.getElementById('spec'); - const slengthSelect = document.getElementById('slength'); - const lotNumberInput = document.getElementById('lot_number'); - - // 품목 변경 시 - $(document).on('change', '#prod', function() { - const selectedProd = this.value; - const specOptions = options[selectedProd] || []; - - // 종류 select의 옵션 초기화 - specSelect.innerHTML = ''; - - // 종류 select에 해당하는 품목의 옵션 추가 - specOptions.forEach(spec => { - let optionText = ''; - switch (spec) { - case 'I': optionText = '화이바원단'; break; - case 'S': optionText = 'SUS'; break; - case 'E': optionText = 'EGI'; break; - case 'A': optionText = '스크린용'; break; - case 'D': optionText = 'D형'; break; - case 'C': optionText = 'C형'; break; - case 'M': optionText = '본체'; break; - case 'B': optionText = '후면커버'; break; - case 'L': optionText = '린텔부'; break; - case 'P': optionText = '점검구'; break; - case 'F': optionText = '전면부'; break; - } - - - -위의 코드에서 이런 것을 만들고 싶다. -세부 산출내역서는 각 일련번호에 대한 세부산출서를 나타낸다. -위의 수량, 면적(㎡) 길이(㎜), 면적(㎡) 길이(㎜) 단가, 단가, 즉 4개의 각 행의 요소를 input으로 입력받는다. 이때 class에 noborder-input을 지정해서 입력창의 테두리가 안나오게 할것이다. -4개의 요소의 값을 수동으로 입력해서 저장하고 싶은것이 목적이다. -각 행의 합계는 자동으로 계산되는 로직을 구현하고, 이는 소계, 합계에 영향을 미쳐야 한다. - -저장하는 방식은 json형태로 각행을 col1~col4까지 저장하고 이를 json형태로 저장하고, 서버에는 text로 저장하면 된다. php7.3버전은 mysql json 저장방식을 사용할 수 없어서, encode, decode해서 사용한다. - -버튼 '수정된 산출내역 저장'을 누르면 위의 수정된 자료가 서버에 전송되고, 저장된다. -최초 로딩될때 서버에 저장된 수정파일이 존재하면, 이 저장된 자료가 최초 로드되어야 한다. - -// 일련번호, 검사비 -$subtotal += $inspectionFee * $su; -if($option !== 'option') -{ - echo ''; - echo '' . $column['col1'] . ''; - echo ' 검사비 '; - - // 수량 입력 필드 - echo ''; - - // 단위 및 기타 필드 - echo ' SET '; - - // 산출식 입력 필드 (예: 수량 * 단가 등으로 계산하는 필드) - echo ''; - - // 면적(㎡) 길이(㎜) 입력 필드 - echo ''; - - // 면적(㎡) 길이(㎜) 단가 입력 필드 - echo ''; - - // 단가 입력 필드 - echo ''; - - // 합계 필드 (자동 계산, 입력 불가) - echo '' . number_format($inspectionFee * $su) . ''; - - echo ''; - $rowCount++; -} - -위의 코드에서 자바스크립트 코드로 이제 행의 합계, 일련번호의 소계, 전체 합계를 자동으로 계산되는 로직을 만들어야 한다. - -계산공식은 아래와 같다. 조건에 따라 약간 다른 연산을 해야 한다. - -마지막 td의 합계 금액은 연산을 할 셀의 값이 없으면 거기는 곱하기를 하지 않고, -면적(㎡) -길이(㎜) 요소의 값이 있다면, 수량 * 이 값 -(면적(㎡) 길이(㎜) 단가) 이 값이 있으면 곱하기 - -기본적으로 수량 * 단가인데, 단가를 수동으로 입력하면, 수동입력된 단가에 수량을 곱해서 금액에 표시되어야 한다. - -소계는 이런 금액들의 합이고, 전체합계는 소계의 합이 되도록 자바스크립트 코드 만들어줘. - -## 혼합형 문구를 파싱해서 변수에 넣는 방법 - -$railtype의 값이 아래와 같이 '혼합형'이란 단어가 들어있으면 아래의 같은 형태가 된다. -예시) 혼합형(120*70)(120*120) - -이 경우는 4개의 숫자를 -$rail_length1 = 120; -$rail_width1 = 70; -$rail_length2 = 120; -$rail_width2 = 120; - -저장하는 코드를 만들어줘. - - // 감기샤프트 데이터에 품목 번호와 수량을 함께 저장 - $shaft_data = [ - '2인치_300' => ['item_code' => 'SHAFT2', 'quantity' => intval(0)], - '4인치_3000' => ['item_code' => 'SHAFT4', 'quantity' => intval(0)], - '4인치_4500' => ['item_code' => 'SHAFT4', 'quantity' => intval(0)], - '4인치_6000' => ['item_code' => 'SHAFT4', 'quantity' => intval(0)], - '5인치_6000' => ['item_code' => 'SHAFT5', 'quantity' => intval(0)], - '5인치_7000' => ['item_code' => 'SHAFT5', 'quantity' => intval(0)], - '5인치_8200' => ['item_code' => 'SHAFT5', 'quantity' => intval(0)], - ]; - - // 부속자재 데이터에 품목 번호와 수량을 함께 저장 - $subs_data = [ - '각파이프_3000' => ['item_code' => 'RPIPE3000', 'quantity' => intval(0)], - '각파이프_6000' => ['item_code' => 'RPIPE6000', 'quantity' => intval(0)], - '앵글_2500' => ['item_code' => 'ANGLE2500', 'quantity' => intval(0)], - '마환봉_3000' => ['item_code' => 'POLE3000', 'quantity' => intval(0)], - '받침용앵글_380' => ['item_code' => 'BBR380', 'quantity' => intval(0)], - '하단무게평철_12T' => ['item_code' => 'WEIGHT12T', 'quantity' => intval(0)], - ]; - - - - -위의 3개의 테이블을 생성했다. 이제 모델을 CRUD하는 과정을 코드로 작성하려고 한다. -실제 다른 테이블의 CRUD 작업을 하는 코드를 공유할테니 이를 참조해서 만들어주세요. - -루트/models라는 폴더를 만든 후 아래의 파일을 만들것이다. -list.php 모델을 조회하는 기능 -write_form.php 모델의 상세조회,입력,수정,삭제 기능 -insert.php 서버에서 입력,수정,삭제 기능 수행 -_row.php write_form.php에서 저장된 컬럼을 표현한 코드 -_request.php insert.php에서 저장할 컬럼을 가져오는 코드 - -위의 5개의 파일을 만드는 것이다. -다른 곳에서 사용하는 형태를 제공할것이니 이를 수정보완하면 좋겠다. - -• list.php – 모델 목록 및 검색/신규등록 -• write_form.php – 모델의 상세보기 및 입력/수정/삭제 폼 -• insert.php – 서버측에서 실제 DB INSERT/UPDATE/DELETE 수행 -• _request.php – 입력값을 변수로 할당 -• _row.php – 조회된 데이터를 폼에 채워 넣기 -의 구조로 CRUD 기능을 구현할 수 있습니다. - -추후 프론트엔드에서는 모델 선택 시 해당 모델의 부품 및 부품서브를 트리형태(플러스/마이너스 토글)로 확장하여 보여줄 수 있도록 추가하면 BOM 형성 과정을 직관적으로 확인할 수 있습니다. - diff --git a/A8E07106DC1E67319483B4836A5CF8EF.txt b/A8E07106DC1E67319483B4836A5CF8EF.txt deleted file mode 100644 index 2b211be4..00000000 --- a/A8E07106DC1E67319483B4836A5CF8EF.txt +++ /dev/null @@ -1,2 +0,0 @@ -586EADF5015F45A49E3546B8271FE76B.37BE05FC9B5422D984E1830C210E1976 -comodoca.com \ No newline at end of file diff --git a/config/google_speech_api.php.example b/config/google_speech_api.php.example new file mode 100644 index 00000000..80e50371 --- /dev/null +++ b/config/google_speech_api.php.example @@ -0,0 +1,22 @@ + "라이브러리"에서 "Cloud Speech-to-Text API" 검색 및 활성화 + * 4. "API 및 서비스" > "사용자 인증 정보"에서 API 키 생성 + * 5. 생성된 API 키를 아래에 입력 + */ + +// Google Cloud Speech-to-Text API 키 +$GOOGLE_SPEECH_API_KEY = 'YOUR_API_KEY_HERE'; + +// 또는 서비스 계정 키 파일 경로 사용 (더 안전) +// $GOOGLE_SPEECH_SERVICE_ACCOUNT_KEY = '/path/to/service-account-key.json'; + diff --git a/geoattendance/fix_geo_db.php b/geoattendance/fix_geo_db.php index 97f5c1cf..262d31d6 100644 --- a/geoattendance/fix_geo_db.php +++ b/geoattendance/fix_geo_db.php @@ -5,10 +5,26 @@ ini_set('display_errors', 1); echo "Starting Geo Attendance DB Fix...\n"; try { - // Connect directly +// Define DOCUMENT_ROOT if not set (for CLI execution) +if (!isset($_SERVER['DOCUMENT_ROOT']) || empty($_SERVER['DOCUMENT_ROOT'])) { + $_SERVER['DOCUMENT_ROOT'] = dirname(__DIR__); // Assumes script is in /geoattendance/ +} + +// Include mydb.php +require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php"); + +try { + // Try connecting using the standard application logic (loads .env) + $pdo = db_connect(); + echo "Connected via db_connect() (standard).\n"; +} catch (Exception $e) { + echo "Standard connection failed. Trying local fallback...\n"; + // Fallback for Local Development (CLI) where .env might have internal Docker hostnames $dsn = "mysql:host=127.0.0.1;dbname=chandj;charset=utf8"; $pdo = new PDO($dsn, 'root', 'root'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + echo "Connected via Local Fallback (127.0.0.1).\n"; +} // 1. Check for ID 0 and move it if exists // We use a subquery to find a safe new ID diff --git a/geoattendance/index.php b/geoattendance/index.php index 8d9bc59c..0eef4bcf 100644 --- a/geoattendance/index.php +++ b/geoattendance/index.php @@ -158,15 +158,19 @@ const [office, setOffice] = useState(DEFAULT_OFFICE); const [isLoading, setIsLoading] = useState(false); const [errorMsg, setErrorMsg] = useState(null); + const [noticeMsg, setNoticeMsg] = useState(null); const [distance, setDistance] = useState(null); const [activeTab, setActiveTab] = useState('home'); const [permissionStatus, setPermissionStatus] = useState('unknown'); const [isSecure, setIsSecure] = useState(window.isSecureContext); + const [geoMode, setGeoMode] = useState('알 수 없음'); + const [geoRetryCount, setGeoRetryCount] = useState(0); + const [lastLocationAt, setLastLocationAt] = useState(null); useEffect(() => { lucide.createIcons(); - }, [activeTab, records]); + }, [activeTab, records, errorMsg, noticeMsg]); // Load records on mount useEffect(() => { @@ -191,59 +195,130 @@ // Start watching location with fallback logic useEffect(() => { - let watchId = null; + const watchIdRef = { current: null }; + const retryTimerRef = { current: null }; + const profileIdxRef = { current: 0 }; + const retryCountRef = { current: 0 }; - const startWatch = (highAccuracy = true) => { - if (watchId) navigator.geolocation.clearWatch(watchId); + const profiles = [ + { + label: '고정밀(High Accuracy)', + options: { enableHighAccuracy: true, maximumAge: 0, timeout: 20000 } + }, + { + label: '저전력(Low Accuracy)', + // Cached/network location can be very helpful on desktop/indoors + options: { enableHighAccuracy: false, maximumAge: 600000, timeout: 30000 } + } + ]; - if ('geolocation' in navigator) { - watchId = navigator.geolocation.watchPosition( - (position) => { - const newLoc = { - latitude: position.coords.latitude, - longitude: position.coords.longitude, - accuracy: position.coords.accuracy - }; - setCurrentLocation(newLoc); - setErrorMsg(null); - }, - (err) => { - console.error(err); - - // On Timeout (code 3) and currently using High Accuracy, try fallback - if (err.code === 3 && highAccuracy) { - console.warn("High accuracy timed out. Falling back to low accuracy."); - startWatch(false); - return; - } - - let msg = "위치를 가져올 수 없습니다."; - switch(err.code) { - case 1: msg = "위치 정보 권한이 거부되었습니다. 브라우저 설정에서 권한을 허용해주세요."; break; - case 2: msg = "위치 정보를 사용할 수 없습니다. GPS 신호를 확인해주세요."; break; - case 3: msg = "위치 정보 요청 시간이 초과되었습니다. (Low Accuracy 시도 실패)"; break; - default: msg = "알 수 없는 오류가 발생했습니다. (" + err.message + ")"; break; - } - if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost' && window.location.hostname !== '127.0.0.1') { - msg += " (주의: 보안 연결(HTTPS)이 아니면 위치 정보가 차단될 수 있습니다)"; - } - setErrorMsg(msg); - }, - { - enableHighAccuracy: highAccuracy, - maximumAge: 10000, - timeout: 15000 // 15 seconds timeout - } - ); - } else { - setErrorMsg("Geolocation is not supported by your browser."); + const clearWatch = () => { + if (watchIdRef.current) { + try { navigator.geolocation.clearWatch(watchIdRef.current); } catch (e) {} + watchIdRef.current = null; } }; - startWatch(true); // Start with High Accuracy + const clearRetryTimer = () => { + if (retryTimerRef.current) { + clearTimeout(retryTimerRef.current); + retryTimerRef.current = null; + } + }; + + const scheduleRetry = (baseDelayMs) => { + clearRetryTimer(); + const attempt = retryCountRef.current; + const delay = Math.min(baseDelayMs * Math.max(1, attempt), 30000); + retryTimerRef.current = setTimeout(() => { + startWatch(0); + }, delay); + }; + + const startWatch = (profileIdx = 0) => { + clearRetryTimer(); + profileIdxRef.current = profileIdx; + setGeoMode(profiles[profileIdx]?.label || '알 수 없음'); + + if (!('geolocation' in navigator)) { + setErrorMsg("Geolocation is not supported by your browser."); + return; + } + + clearWatch(); + + watchIdRef.current = navigator.geolocation.watchPosition( + (position) => { + retryCountRef.current = 0; + setGeoRetryCount(0); + + const newLoc = { + latitude: position.coords.latitude, + longitude: position.coords.longitude, + accuracy: position.coords.accuracy + }; + setCurrentLocation(newLoc); + setLastLocationAt(Date.now()); + setErrorMsg(null); + setNoticeMsg(null); + }, + (err) => { + console.error(err); + + // Permission denied -> hard error (no auto retry) + if (err.code === 1) { + setNoticeMsg(null); + setErrorMsg("위치 정보 권한이 거부되었습니다. 브라우저 설정에서 권한을 허용해주세요."); + return; + } + + // Timeout -> try fallback profile first, then soft retry + if (err.code === 3) { + if (profileIdxRef.current < profiles.length - 1) { + setErrorMsg(null); + setNoticeMsg("정확한 위치가 지연되어 저전력(Low Accuracy) 모드로 전환합니다..."); + startWatch(profileIdxRef.current + 1); + return; + } + + retryCountRef.current += 1; + setGeoRetryCount(retryCountRef.current); + setErrorMsg(null); + setNoticeMsg(`위치 응답이 지연되고 있습니다. 자동 재시도 중... (${retryCountRef.current}회)`); + scheduleRetry(5000); + return; + } + + // Position unavailable -> soft retry (indoors/desktop common) + if (err.code === 2) { + retryCountRef.current += 1; + setGeoRetryCount(retryCountRef.current); + setErrorMsg(null); + setNoticeMsg(`위치 정보를 사용할 수 없습니다. GPS/네트워크 상태를 확인 중... (${retryCountRef.current}회 재시도)`); + scheduleRetry(8000); + return; + } + + // Unknown error -> show message, but still retry once in a while + retryCountRef.current += 1; + setGeoRetryCount(retryCountRef.current); + + let msg = "알 수 없는 오류가 발생했습니다. (" + (err.message || "unknown") + ")"; + if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost' && window.location.hostname !== '127.0.0.1') { + msg += " (주의: 보안 연결(HTTPS)이 아니면 위치 정보가 차단될 수 있습니다)"; + } + setErrorMsg(msg); + scheduleRetry(10000); + }, + profiles[profileIdx]?.options || { enableHighAccuracy: true, maximumAge: 0, timeout: 20000 } + ); + }; + + startWatch(0); // Start with High Accuracy profile return () => { - if (watchId) navigator.geolocation.clearWatch(watchId); + clearRetryTimer(); + clearWatch(); }; }, []); @@ -362,6 +437,14 @@ {/* Main Content Area */}
+ {/* Notice Banner (soft errors / retry status) */} + {noticeMsg && ( +
+ +

{noticeMsg}

+
+ )} + {/* Error Banner */} {errorMsg && (
@@ -507,6 +590,9 @@ 주의: HTTPS가 아니면 최신 브라우저에서 GPS가 차단됩니다.

)} +

위치 모드: {geoMode}

+

재시도 횟수: {geoRetryCount}

+

마지막 수신: {lastLocationAt ? new Date(lastLocationAt).toLocaleTimeString([], {hour: '2-digit', minute: '2-digit', second: '2-digit'}) : '없음'}

거리: {distance ? distance.toFixed(1) : '알 수 없음'} 미터

반경 제한: {office.allowedRadiusMeters} 미터

GPS 정확도: {currentLocation?.accuracy ? currentLocation.accuracy.toFixed(1) + 'm' : '알 수 없음'}

diff --git a/myheader.php b/myheader.php index 040aa507..6c998d5a 100644 --- a/myheader.php +++ b/myheader.php @@ -187,7 +187,7 @@ require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");