const tb_custom_editor = { // 기초 코드용 에디터: 새로추가한(STATUS = I) ROW의 기초코드만 수정가능 pkCode: function (cell, onRendered, success, cancel, editorParams) { const input = document.createElement("input"); const format = editorParams.format ? editorParams.format : "text"; if (cell.getData()._STATUS_ == "I") { input.setAttribute("type", format); input.style.width = "100%"; input.value = cell.getValue() ? cell.getValue() : ""; if (editorParams.type === "upper") { // 입력값이 변경될 때 대문자로 변환 input.addEventListener("input", function () { this.value = this.value.toUpperCase(); }); } onRendered(function () { input.focus(); input.style.height = "100%"; }); function successFunc() { success(input.value); } input.addEventListener("change", successFunc); input.addEventListener("blur", successFunc); return input; } else { return false; } }, // 팝업이 열리는 셀의 에디터: 수정되지 않는다(READONLY) pop: function(cell,onRendered,success,cancel,editorParams){ const input = document.createElement("input"); const format = editorParams.format ? editorParams.format : "text"; input.setAttribute("type", format); input.setAttribute("readonly", true); input.style.width = "100%"; input.value = cell.getValue() ? cell.getValue() : ""; onRendered(function () { input.focus(); input.style.height = "100%"; }); function successFunc() { success(input.value); } input.addEventListener("change", successFunc); input.addEventListener("blur", successFunc); return input; }, // item 에서 없애고 pop으로 대체하기 clickShow: function(cell,onRendered,success,cancel,editorParams){ const input = document.createElement("input"); const format = editorParams.format ? editorParams.format : "text"; input.setAttribute("type", format); input.setAttribute("readonly", true); input.style.width = "100%"; input.value = cell.getValue() ? cell.getValue() : ""; onRendered(function () { input.focus(); input.style.height = "100%"; }); function successFunc() { success(input.value); } input.addEventListener("change", successFunc); input.addEventListener("blur", successFunc); return input; }, // select 박스 에디터 editorSelect: function(cell, onRendered, success, cancel, editorParams){ let edSelect = document.createElement("select"); let params = editorParams.values; params = params || {}; Object.keys(params).forEach(key => { let edOption = document.createElement("option"); edOption.value = key; edOption.text = params[key]; edSelect.append(edOption); }); edSelect.className = 'form-select form-select-sm'; edSelect.value = cell._cell.value; onRendered(function() { edSelect.focus(); }); let cback = function(){ success( edSelect.value); } edSelect.addEventListener("change", cback); edSelect.addEventListener("blur", cback); return edSelect; }, // 다른 셀의 체크 상태에 따라 input / select 에디터 inputOrSelect: function (cell, onRendered, success, cancel, editorParams) { const rowData = cell.getData(); const checkPoint = rowData[editorParams.checkPoint]; const cellValue = cell.getValue() ? cell.getValue() : ""; // 현재 셀의 값을 가져옵니다. let input; // 조건에 따라 생성될 입력 요소 if (checkPoint === "Y") { let options = [{ idx:1, val: "OK" }, { idx:0, val: "NG" }, { idx: "", val: "없음" } ]; input = document.createElement("select"); input.style.width = "100%"; options.forEach((temp)=>{ var optionElement = document.createElement("option"); optionElement.value = temp.idx; optionElement.text = temp.val; input.appendChild(optionElement); }) } else { input = document.createElement("input"); input.setAttribute("type", "text"); input.value = cellValue; input.style.width = "100%"; // input.className = 'form-control form-control-sm'; // 부트스트랩 클래스 적용 } onRendered(function () { input.focus(); input.style.height = "100%"; }); function successFunc() { success(input.value); // 성공 콜백에 값을 전달하여 셀을 업데이트합니다. } input?.addEventListener("change", successFunc); input?.addEventListener("blur", successFunc); return input; }, // inputOrSelect: function (cell, onRendered, success, cancel, editorParams) { // const rowData = cell.getData(); // const checkPoint = rowData[editorParams.checkPoint]; // const cellValue = cell.getValue() ? cell.getValue() : ""; // 현재 셀의 값을 가져옵니다. // let input; // 조건에 따라 생성될 입력 요소 // if (checkPoint === "Y") { // input = document.createElement("select"); // const options = ["OK", "NG"]; // options.forEach(function (option, idx) { // const optionElement = document.createElement("option"); // optionElement.value = idx; // optionElement.textContent = option; // if (option === cellValue) { // optionElement.selected = true; // input.value = idx; // console.log(input.value) // } // input.append(optionElement); // }); // console.log(cell._cell.value) // input.value = cell._cell.value; // input.style.width = "100%"; // } else { // input = document.createElement("input"); // input.setAttribute("type", "text"); // input.value = cellValue; // input.style.width = "100%"; // } // onRendered(function () { // input.focus(); // input.style.height = "100%"; // }); // function successFunc() { // if (checkPoint === "Y") { // success(input.value); // } else { // success(input.value); // } // } // input.addEventListener("change", successFunc); // input.addEventListener("blur", successFunc); // return input; // }, // 생산계획: 다른 셀의 값에 따라 input[type=num] / select regPlan: function (cell, onRendered, success, cancel, editorParams) { const rowData = cell.getData(); const checkPoint = rowData[editorParams.checkPoint]; let cellValue = cell.getValue() ? cell.getValue() : ""; // 현재 셀의 값을 가져옵니다. let input; // 조건에 따라 생성될 입력 요소 if (checkPoint === "그룹") { // div // let options = editorParams.values // input = document.createElement("select"); // input.style.width = "100%"; let options = editorParams.values; input = document.createElement("input"); input.style.width = "100%"; input.style.height = "100%"; // Autocomplete 기능 추가 $(input).autocomplete({ source: Object.values(options), select: function(event, ui) { success(ui.item.value); // 선택된 값을 성공 콜백에 전달 }, }); input.value = cellValue; for(let temp in options){ var optionElement = document.createElement("option"); optionElement.value = temp; optionElement.text = options[temp]; if(temp === cellValue){ optionElement.selected = true; } input.appendChild(optionElement); } input.addEventListener("keydown", function(e) { if (['ArrowUp', 'ArrowDown'].includes(e.key)) { e.stopPropagation(); } }); // let options = editorParams.values // input = document.createElement("select"); // input.style.width = "100%"; // for(let temp in options){ // var optionElement = document.createElement("option"); // optionElement.value = temp; // optionElement.text = options[temp]; // if(temp === cellValue){ // optionElement.selected = true; // } // input.appendChild(optionElement); // } }else{ input = document.createElement("input"); input.setAttribute("type", "number"); input.setAttribute("min", 0); input.value = cellValue; input.style.width = "100%"; input.addEventListener("input", function () { this.value = this.value < 0 ? 0 : this.value; }); } onRendered(function () { input.focus(); input.style.height = "100%"; }); function successFunc() { success(input.value); // if (checkPoint === "Y") { // } else { // success(input.value); // } } input.addEventListener("change", successFunc); input.addEventListener("blur", successFunc); return input; }, // 현장작업자 팝업: 이전양품수량 초과 안되게 리미트 limitQty: function (cell, onRendered, success, cancel, editorParams) { const input = document.createElement("input"); const curSum = cell.getTable().getCalcResults().bottom[editorParams.qty]; const vsNum = editorParams.vsNum.formData[editorParams.formQty]; input.setAttribute("type", "number"); input.setAttribute("min", 0); input.style.width = "100%"; input.value = cell.getValue() ? parseInt(cell.getValue()) : ""; onRendered(function () { input.focus(); input.style.height = "100%"; }); function successFunc() { if (parseInt(vsNum) < parseInt(curSum) + parseInt(input.value)) { input.value = parseInt(vsNum) - parseInt(curSum); kuls_alert("이전양품수량을 초과할 수 없습니다."); } success(input.value); } input.addEventListener("change", successFunc); input.addEventListener("input", function () { this.value = this.value < 0 ? 0 : this.value; }); // input.addEventListener("blur", successFunc); return input; }, // 양수만 입력가능한 number 에디터 minNumber: function (cell, onRendered, success, cancel, editorParams) { const input = document.createElement("input"); const minVal = editorParams.min; input.setAttribute("type", "number"); input.setAttribute("min", 0); input.style.width = "100%"; input.value = cell.getValue() ? parseInt(cell.getValue()) : ""; onRendered(function () { input.focus(); input.style.height = "100%"; }); input.addEventListener("input", function () { this.value = this.value < minVal ? minVal : this.value; }); // 값 변경 완료 시 function onChange() { if (input.value != cell.getValue()) { success(input.value); } else { cancel(); } } // 이벤트 리스너 등록 input.addEventListener("blur", onChange); input.addEventListener("keydown", function (e) { if (e.keyCode == 13) { onChange(); // 엔터 키를 누를 때 } if (e.keyCode == 27) { cancel(); // ESC 키를 누를 때 } }); return input; }, // 대문자로 변경되는 에디터 upper: function (cell, onRendered, success, cancel) { // input 요소 생성 const input = document.createElement("input"); input.setAttribute("type", "text"); input.style.width = "100%"; input.value = cell.getValue() ? cell.getValue() : ""; // 입력값이 변경될 때 대문자로 변환 input.addEventListener("input", function () { this.value = this.value.toUpperCase(); }); // 에디터가 렌더링된 후 실행될 콜백 onRendered(function () { input.focus(); input.style.height = "100%"; input.select(); }); // 값 변경 완료 시 function onChange() { if (input.value != cell.getValue()) { success(input.value); } else { cancel(); } } // 이벤트 리스너 등록 input.addEventListener("blur", onChange); input.addEventListener("keydown", function (e) { if (e.keyCode == 13) { onChange(); // 엔터 키를 누를 때 } if (e.keyCode == 27) { cancel(); // ESC 키를 누를 때 } }); return input; }, // 숫자만 입력 가능한 에디터 onlyNumber: function (cell, onRendered, success, cancel) { // 입력 요소 생성 const input = document.createElement("input"); input.setAttribute("type", "text"); input.style.width = "100%"; input.value = cell.getValue() ? cell.getValue() : ""; onRendered(function () { input.focus(); input.style.height = "100%"; }); function onChange() { if (input.value.match(/^\d*$/)) { // 숫자만 허용 success(input.value); } else { input.value = input.value.replace(/[^0-9]/g, ""); } } input.addEventListener("blur", onChange); input.addEventListener("keydown", function (e) { if (e.keyCode == 13) { onChange(); } if (e.keyCode == 27) { cancel(); } }); return input; }, // 숫자 최대 4자리(문자x) -> 00:00 time: function (cell, onRendered, success, cancel) { // 입력 요소 생성 const input = document.createElement("input"); input.setAttribute("type", "text"); input.style.width = "100%"; input.value = cell.getValue() ? cell.getValue() : ""; onRendered(function () { input.focus(); input.select(); input.style.height = "100%"; }); // 변경사항이 완료되면 호출될 함수 function onChange() { if (input.value.length === 5) { // 'HH:mm' 형식 확인 success(input.value); console.log(cell.getValue()); } else { cancel(); } } // 입력 이벤트 처리 input.addEventListener("input", function () { var value = input.value.replace(/[^0-9]/g, ""); // 숫자만 입력 받음 if (value.length > 2) { value = value.substring(0, 4); // 최대 4자리 input.value = value.replace(/(\d{2})(\d{1})/, "$1:$2"); } }); input.addEventListener("blur", onChange); input.addEventListener("keydown", function (e) { if (e.keyCode == 13) { onChange(); } if (e.keyCode == 27) { cancel(); } }); return input; }, }; // 키-값 저장 클래스 const rowClickeventMap = new WeakMap(); const tb_custom_formatter = { // 기초코드 셀에 조건에 따라 클래스 추가 pkCode: function (tgt, params) { if (tgt.getData()._STATUS_ == "I") { tgt.getElement().classList.add("editable-cell"); } else { tgt.getElement().classList.remove("tabulator-editable"); let rowClickevent = rowClickeventMap.get(tgt.getElement()); if (!rowClickevent) { rowClickevent = function (e) { params.tableClass.rowClick(e, tgt.getRow()); }; rowClickeventMap.set(tgt.getElement(), rowClickevent); tgt.getElement().addEventListener("click", rowClickevent); } } return tgt.getValue(); }, // 재사용x 생산계획 구분선 rowspan_3: function (tgt, params) { if (tgt.getData().SEPER === "계획") { return tgt.getValue(); } else if(tgt.getData().SEPER === "실적"){ tgt.getElement().classList.add("border-bottom") return ""; }else{ return ""; } }, // 값에 따라 배경색 바꾸기(클래스 추가) status: function (cell, formatterParams, onRendered) { const cellStats = cell.getValue()?.split(" / ")[1]; const cellVar = cell.getValue()?.split(" / ")[0]; if ( formatterParams["selectValue"] === cellVar && formatterParams["selectValue"] ) { cell.getElement().classList.add("red-font"); } switch (cellStats) { case "R": cell.getElement().classList.add("yellow-back"); break; case "F": cell.getElement().classList.add("blue-back"); break; case "D": cell.getElement().classList.add("orange-back"); break; case "P": cell.getElement().classList.add("gray-back"); cell.getElement().classList.add("white-font"); break; case "S": cell.getElement().classList.add("red-back"); break; } return cellVar; }, // 값에 따라 붉은 글씨 stopStatus: function (tgt, formatterParams) { var cell = tgt._cell; let div = document.createElement("div"); // const cellStats = tgt.getValue()?.split(" / ")[1]; const cellVar = tgt.getValue(); if(formatterParams.class) div.className = formatterParams.class; let nval = cell.value || formatterParams.default; div.innerHTML = formatterParams.values[nval] || (formatterParams.defaultValue || ''); if (cellVar === 'S') { tgt.getElement().classList.add("red-font"); } return div; }, //토글버튼 출력 red formatterToggleboxRedIcon: function (tgt, params) { let cell = tgt._cell; let span = document.createElement("span"); if(tgt.getData()[params.field] !== params.value){ tgt.getElement().classList.add('tabulator-editable'); } if ( params.checkval && cell.value == params.checkval || !params.checkval && cell.value == true) { span.className = "bi bi-toggle-on tb_toggle red"; } else { span.className = "bi bi-toggle-off tb_toggle red"; } return span; }, selectOrNum: function (cell, formatterParams) { const rowData = cell.getData(); const checkPoint = rowData[formatterParams.checkPoint]; const value = cell.getValue() || ""; const field = cell.getField(); if (checkPoint === "그룹") { return value; } else if(checkPoint === "계획"){ const nextRow = cell.getRow().getNextRow(); const nextRowData = nextRow.getData(); const nextValue = nextRowData[field] || 0 const valueFormat = value === "" ? 0 : value; if(parseInt(valueFormat)>parseInt(nextValue)){ const rsltCell = nextRow.getCell(field); rsltCell.getElement().classList.add("red-back"); }else{ const rsltCell = nextRow.getCell(field); rsltCell.getElement().classList.remove("red-back") } return value; } else if(checkPoint === "실적"){ const prevRow = cell.getRow().getPrevRow(); const prevRowData = prevRow.getData(); const prevValue = prevRowData[field] || 0 const valueFormat = value === "" ? 0 : value; if(parseInt(prevValue)>parseInt(valueFormat)){ cell.getElement().classList.add("red-back"); }else{ cell.getElement().classList.remove("red-back") } return value; } }, // 0000 -> 00:00 time: function (cell, formatterParams, onRendered) { return cell .getValue() .padStart(4, "0") .replace(/(\d{2})(\d{2})/, "$1:$2"); }, datetime: function (cell, formatterParams) { const datetime = cell.getValue(); return ( (datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours()) + ":" + (datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes()) + ":" + (datetime.getSeconds() < 10 ? "0" + datetime.getSeconds() : datetime.getSeconds()) ); }, // 시간 차 계산 diffTitme: function (cell, formatterParams, onRendered) { let startTime = cell.getRow().getCell("OPER_ST_TM").getValue(); let endTime = cell.getRow().getCell("OPER_ED_TM").getValue(); if (startTime && endTime) { let start = luxon.DateTime.fromFormat(startTime, "HH:mm"); let end = luxon.DateTime.fromFormat(endTime, "HH:mm"); // 날짜가 반전되는 경우를 처리 (예: 밤샘) if (end < start) { end = end.plus({ days: 1 }); } // 시간 차이 계산 let duration = end.diff(start, "minutes"); return duration.minutes; // 분 단위로 반환 } else { return ""; // Return empty string if either time is missing } }, deleteIcon: function (cell, formatterParams) { const tgt = cell.getElement(); const isExit = cell.getData()["_STATUS_"]; if(!formatterParams['icon']){ if (isExit !== "I") { let span = document.createElement("span"); span.className = "bi bi-x-square"; tgt.addEventListener("mouseenter", () => { span.className = "bi bi-x-square-fill"; }); tgt.addEventListener("mouseleave", () => { span.className = "bi bi-x-square"; }); return span; } return ""; }else{ let span = document.createElement("span"); span.className = "bi bi-x-square"; tgt.addEventListener("mouseenter", () => { span.className = "bi bi-x-square-fill"; }); tgt.addEventListener("mouseleave", () => { span.className = "bi bi-x-square"; }); return span; } }, checkInspValue: function (cell, formatterParams) { const rowData = cell.getData(); const checkPoint = formatterParams["checkPoint"]; const upValue = parseFloat(rowData.TOL_UPPER); const lowValue = parseFloat(rowData.TOL_LOWER); const value = cell.getValue(); // 셀 DOM 요소 가져오기 // let cell = tgt._cell; // if ( params.checkval && cell.value == params.checkval || !params.checkval && cell.value == true) { // } else { // } const cellElement = cell.getElement(); // 클래스 추가/제거 if (rowData[checkPoint] === "Y") { // let span = document.createElement("span"); switch (parseInt(value)) { case 1: cellElement.classList.add("green-back"); cellElement.classList.remove("red-back"); return "OK"; case 0: cellElement.classList.add("red-back"); cellElement.classList.remove("green-back"); return "NG"; default: cellElement.classList.remove("green-back"); cellElement.classList.remove("red-back"); return ""; } } else { if (value) { const valueNum = parseFloat(value) ? parseFloat(value) : ""; if (valueNum > upValue || valueNum < lowValue) { cellElement.classList.add("red-back"); cellElement.classList.remove("green-back"); } else { cellElement.classList.add("green-back"); cellElement.classList.remove("red-back"); } // 소수점 3자리까지 표시 return valueNum ? valueNum.toFixed(0) : 0; } else { return value; } } }, limitValue: function (cell, formatterParams) { const rowData = cell.getData(); const checkPoint = formatterParams["checkPoint"]; const decimal = formatterParams["decimal"] ? formatterParams["decimal"] : 0; const value = cell.getValue() ? cell.getValue() : 0; // 클래스 추가/제거 if (rowData[checkPoint] === "Y") { if (value !== "") { // cell.setValue(""); // 셀 값을 빈 문자열로 설정 } return ""; } else { if(value !== "" ){ return parseFloat(value).toFixed(decimal); } // if(decimal){ // const valuesFormat = parseFloat(value).toFixed(decimal); // console.log(cell) // // cell.setValue(`${valuesFormat}`); // }else{ // return value; // } } }, }; const tb_custom_validator = { onlyString: function (cell, value, parameters) { const regex = /^[가-힣A-Za-z\s]+$/; return regex.test(value); }, onlyEnglish: function (cell, value, parameters) { const regex = /^[A-Za-z\s]+$/; return regex.test(value); }, stringNumeric: function (cell, value, parameters) { const regex = /^[가-힣ㄱ-ㅎㅏ-ㅣA-Za-z0-9\/\-\_\s]+$/; return regex.test(value); }, }; const tb_custom_edited = { // checkInspValue: function(cell){ // // 셀 값 가져오기 // const rowData = cell.getData(); // const upValue = parseFloat(rowData.SPEC_VAL) + parseFloat(rowData.TOL_UPPER) * 0.001; // const lowValue = parseFloat(rowData.SPEC_VAL) - parseFloat(rowData.TOL_LOWER) * 0.001; // const value = parseFloat(cell.getValue()); // // 셀 DOM 요소 가져오기 // const cellElement = cell.getElement(); // // 클래스 추가/제거 // if(value > upValue || value < lowValue){ // cellElement.classList.add("red-back"); // cellElement.classList.remove("green-back"); // } else { // cellElement.classList.remove("red-back"); // cellElement.classList.add("green-back"); // } // } }; const formFormat = { telInput: function (input) { let formattedNumber = input.value.replace(/[^0-9]/g, ""); // 숫자만 추출 // 자동 포맷팅 로직 구현 예시: "123-456-7890" 형식 if (formattedNumber.length > 10) { formattedNumber = formattedNumber.slice(0, 3) + "-" + formattedNumber.slice(3, 7) + "-" + formattedNumber.slice(7); } else { formattedNumber = formattedNumber.slice(0, 3) + "-" + formattedNumber.slice(3, 6) + "-" + formattedNumber.slice(6); } input.value = formattedNumber; // 포맷팅된 번호를 입력 필드에 다시 설정 }, inNumInput: function (input) { let formattedNumber = input.value.replace(/[^0-9]/g, ""); // 숫자만 추출 // 자동 포맷팅 로직 구현 예시: "123-456-7890" 형식 formattedNumber = formattedNumber.slice(0, 6) + "-" + formattedNumber.slice(6, 13); input.value = formattedNumber; // 포맷팅된 번호를 입력 필드에 다시 설정 }, alphanumeric: function (input) { input.value = input.value.toUpperCase().replace(/[^A-Z0-9]/g, ""); }, submitValidate: function () { let isValid = true; return isValid; }, };