From baa5d0249a5fd908bf3907433c788cca82780604 Mon Sep 17 00:00:00 2001 From: leeheejin Date: Mon, 17 Nov 2025 18:20:46 +0900 Subject: [PATCH 1/3] =?UTF-8?q?Fix:=20Java=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=ED=98=B8=ED=99=98=EC=84=B1=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20-=20Dockerfile.dev=20jre8->jre7=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile.dev | 2 +- .../WEB-INF/view/partMng/structurePopupCenter.jsp | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Dockerfile.dev b/Dockerfile.dev index 4a02db3..03e8b29 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM dockerhub.wace.me/tomcat:7.0.94-jre8-alpine.arm64 AS Development +FROM dockerhub.wace.me/tomcat:7.0.94-jre7-alpine.arm64 AS Development # Remove default webapps RUN rm -rf /usr/local/tomcat/webapps/* diff --git a/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp b/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp index f9a1c99..4c5934f 100644 --- a/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp +++ b/WebContent/WEB-INF/view/partMng/structurePopupCenter.jsp @@ -422,14 +422,16 @@ function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPa } - +
-
+
- - +
+ +
+
From af02560097e9a5ff3dbd7cff2bed7e8a29123ada Mon Sep 17 00:00:00 2001 From: leeheejin Date: Mon, 17 Nov 2025 18:44:44 +0900 Subject: [PATCH 2/3] =?UTF-8?q?m-bom=20=EC=A7=84=ED=96=89=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../partMng/structureBomCopyFormPopup.jsp | 27 +++++++-- .../productionplanning/mBomHeaderPopup.jsp | 8 +++ .../view/productionplanning/mBomMgmtList.jsp | 55 +++++++++++++------ src/com/pms/controller/PartMngController.java | 5 ++ 4 files changed, 75 insertions(+), 20 deletions(-) diff --git a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp index 7438365..6fb8dc7 100644 --- a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp +++ b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp @@ -134,12 +134,21 @@ var selectedBomType = null; // 'EBOM' 또는 'MBOM' var bomGridData = []; // BOM 그리드 데이터 $(function(){ - // 페이지 로드 시 프로젝트 정보가 있으면 품번/품명 자동 입력 + // 페이지 로드 시 URL 파라미터 또는 프로젝트 정보에서 품번/품명 자동 입력 + var urlPartNo = "${param.partNo}"; + var urlPartName = "${param.partName}"; + + if(urlPartNo && urlPartNo !== "") { + console.log("URL 파라미터에서 품번/품명 설정 중..."); + $("#COPY_PART_NO").val(decodeURIComponent(urlPartNo)); + $("#COPY_PART_NAME").val(decodeURIComponent(urlPartName)); + } + else { console.log("projectInfo가 있습니다. 품번/품명 설정 중..."); $("#COPY_PART_NO").val("${projectInfo.PART_NO}"); $("#COPY_PART_NAME").val("${projectInfo.PART_NAME}"); - // E-BOM 품번은 사용자가 직접 입력하도록 비워둠 (M-BOM 품번과 다를 수 있음) + } // 담기 버튼 - 선택한 BOM을 복사 대상으로 설정 @@ -526,9 +535,19 @@ function fn_saveBomCopy() { text: 'M-BOM이 성공적으로 생성되었습니다.', icon: 'success' }).then(() => { - // 부모 창(M-BOM 관리) 새로고침하여 아이콘 업데이트 + // 부모 창(M-BOM 관리)의 검색 함수만 호출하여 그리드 업데이트 if(window.opener && !window.opener.closed) { - window.opener.location.reload(); + // 부모 창의 검색 조건 유지하면서 그리드만 새로고침 + if(typeof window.opener.fn_search === 'function') { + window.opener.fn_search(); + } + // M-BOM 품번과 저장일을 부모 창 검색 조건에 설정 + if(response.mbomPartNo) { + window.opener.$("#search_mbom_part_no").val(response.mbomPartNo); + } + if(response.saveDate) { + window.opener.$("#search_save_date").val(response.saveDate); + } } window.close(); }); diff --git a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp index 2f60269..ad23c1d 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp @@ -50,6 +50,14 @@ $(function(){ $('.select2').select2(); + // 페이지 로드 시 프로젝트 정보로 검색 필드 자동 입력 + + $("#search_part_no").val("${info.PART_NO}"); + $("#search_part_name").val("${info.PART_NAME}"); + $("#search_mbom_part_no").val("${info.PART_NO}"); // M-BOM 품번은 품번과 동일 + $("#search_save_date").val("${info.MBOM_REGDATE}"); + + //Part 연결 $("#moveLeft").click(function(){ // Tabulator에서 선택된 오른쪽 행 데이터 가져오기 diff --git a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp index a043b69..14e4f64 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp @@ -211,6 +211,12 @@ var columns = [ // 파란색(저장된 M-BOM)일 때만 팝업 열기 if(mbomStatus !== '' && mbomStatus !== '0') { + // 검색 조건에 해당 행의 데이터 자동 입력 + $("#search_part_no").val(fnc_checkNull(rowData.PART_NO)); + $("#search_part_name").val(fnc_checkNull(rowData.PART_NAME)); + $("#search_mbom_part_no").val(fnc_checkNull(rowData.PART_NO)); // M-BOM 품번은 품번과 동일 + $("#search_save_date").val(fnc_checkNull(rowData.MBOM_REGDATE)); + fn_openMBomFormPopup(objid); } else { Swal.fire({ @@ -355,10 +361,20 @@ function fn_openBomCopyPopup() { // BOM 복사 팝업 창 열기 function fn_openBomCopyPopupWindow(objId) { - var popup_width = 1800; - var popup_height = 900; - var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId; - fn_centerPopup(popup_width, popup_height, url, 'bomCopyPopup'); + // 선택된 행의 데이터 가져오기 + var selectedRow = _tabulGrid.searchRows("OBJID", "=", objId); + if(selectedRow.length > 0) { + var rowData = selectedRow[0].getData(); + var partNo = encodeURIComponent(fnc_checkNull(rowData.PART_NO)); + var partName = encodeURIComponent(fnc_checkNull(rowData.PART_NAME)); + + var popup_width = 1800; + var popup_height = 900; + var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId + "&partNo=" + partNo + "&partName=" + partName; + fn_centerPopup(popup_width, popup_height, url, 'bomCopyPopup'); + } else { + Swal.fire('선택된 데이터를 찾을 수 없습니다.'); + } } @@ -376,18 +392,25 @@ function fn_openBomCopyPopupWindow(objId) {
- -
- - - - - - - - -
-
+ +
+ + + + + + + + + + + + + + + +
+
<%@include file= "/WEB-INF/view/common/common_gridArea.jsp" %> diff --git a/src/com/pms/controller/PartMngController.java b/src/com/pms/controller/PartMngController.java index cfb469b..6fdd43c 100644 --- a/src/com/pms/controller/PartMngController.java +++ b/src/com/pms/controller/PartMngController.java @@ -982,6 +982,11 @@ public class PartMngController { resultMap.put("result", "success"); resultMap.put("message", "M-BOM이 성공적으로 생성되었습니다."); + // M-BOM 품번과 저장일 추가 (부모 창 검색 조건에 사용) + resultMap.put("mbomPartNo", targetPartNo); + // 현재 날짜를 YYYY-MM-DD 형식으로 반환 + java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd"); + resultMap.put("saveDate", sdf.format(new java.util.Date())); } finally { if(sqlSession != null) { sqlSession.close(); From 81a0ac5c627391fb945c192b0abd8643f5e88087 Mon Sep 17 00:00:00 2001 From: leeheejin Date: Tue, 18 Nov 2025 14:37:36 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EC=83=9D=EC=82=B0=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/pms/mapper/productionplanning.xml | 287 ++++++++++--- .../partMng/structureBomCopyFormPopup.jsp | 159 ++++--- .../productionplanning/mBomHeaderPopup.jsp | 135 ++++-- .../view/productionplanning/mBomMgmtList.jsp | 50 +-- .../productionplanning/mBomPopupCenter.jsp | 338 ++++++++++++--- .../view/productionplanning/mBomPopupFs.jsp | 2 +- .../view/productionplanning/mBomPopupLeft.jsp | 392 +++++++++++++++++- .../productionplanning/mBomPopupRight.jsp | 73 +++- src/com/pms/controller/PartMngController.java | 71 +++- .../ProductionPlanningController.java | 182 ++++++-- src/com/pms/mapper/productionplanning.xml | 287 ++++++++++--- .../service/ProductionPlanningService.java | 239 ++++++++++- 12 files changed, 1864 insertions(+), 351 deletions(-) diff --git a/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml b/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml index ade66d9..5555df3 100644 --- a/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml +++ b/WebContent/WEB-INF/classes/com/pms/mapper/productionplanning.xml @@ -2945,8 +2945,23 @@ '' ) AS EBOM_REGDATE, COALESCE(PM.MBOM_STATUS, '') AS MBOM_STATUS, + COALESCE( + (SELECT PBR.PART_NO + FROM PART_BOM_REPORT PBR + WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID + AND PM.MBOM_STATUS = 'Y' + LIMIT 1), + '' + ) AS MBOM_PART_NO, '1.0' AS MBOM_VERSION, - TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS MBOM_REGDATE + COALESCE( + (SELECT TO_CHAR(PBR.REGDATE, 'YYYY-MM-DD') + FROM PART_BOM_REPORT PBR + WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID + AND PM.MBOM_STATUS = 'Y' + LIMIT 1), + TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') + ) AS MBOM_REGDATE FROM PROJECT_MGMT PM LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID @@ -3009,6 +3024,14 @@ PM.BOM_REPORT_OBJID, PM.PART_NO, PM.PART_NAME, + COALESCE( + (SELECT PBR.PART_NO + FROM PART_BOM_REPORT PBR + WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID + AND PM.MBOM_STATUS = 'Y' + LIMIT 1), + '' + ) AS MBOM_PART_NO, CM.CATEGORY_CD, COALESCE( (SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1), @@ -3032,7 +3055,14 @@ CM.PAID_TYPE, CM.REQ_DEL_DATE, TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS RECEIPT_DATE, - TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS MBOM_REGDATE + COALESCE( + (SELECT TO_CHAR(PBR.REGDATE, 'YYYY-MM-DD') + FROM PART_BOM_REPORT PBR + WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID + AND PM.MBOM_STATUS = 'Y' + LIMIT 1), + TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') + ) AS MBOM_REGDATE FROM PROJECT_MGMT PM INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID @@ -3092,71 +3122,209 @@ + + + + + + + + + @@ -3229,6 +3397,7 @@ /* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */ /* 1. 새로운 PART_BOM_REPORT 생성 (M-BOM용) */ + /* M-BOM 품번을 PART_NO에 저장 (규칙: M-{품번}-YYMMDD-01) */ WITH new_bom_report AS ( INSERT INTO PART_BOM_REPORT ( OBJID, @@ -3239,7 +3408,7 @@ STATUS ) VALUES ( (SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000)::INTEGER), - #{PART_NO}, + #{MBOM_PART_NO}, #{PART_NAME}, #{USER_ID}, NOW(), diff --git a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp index 6fb8dc7..9958000 100644 --- a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp +++ b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp @@ -137,6 +137,7 @@ $(function(){ // 페이지 로드 시 URL 파라미터 또는 프로젝트 정보에서 품번/품명 자동 입력 var urlPartNo = "${param.partNo}"; var urlPartName = "${param.partName}"; + var productCode = "${projectInfo.PRODUCT}"; if(urlPartNo && urlPartNo !== "") { console.log("URL 파라미터에서 품번/품명 설정 중..."); @@ -149,6 +150,13 @@ $(function(){ $("#COPY_PART_NO").val("${projectInfo.PART_NO}"); $("#COPY_PART_NAME").val("${projectInfo.PART_NAME}"); } + + // Machine이 아닌 경우, 동일 품번의 기존 M-BOM 확인 및 자동 로드 + var isMachine = productCode && (productCode === '0001807' || productCode.toUpperCase().indexOf('MACHINE') >= 0); + if(!isMachine && "${projectInfo.PART_NO}" !== "") { + console.log("Machine이 아닌 제품입니다. 기존 M-BOM 확인 중..."); + fn_checkExistingMbom("${projectInfo.PART_NO}"); + } // 담기 버튼 - 선택한 BOM을 복사 대상으로 설정 @@ -184,9 +192,9 @@ $(function(){ var ebomPartNo = $("#EBOM_PART_NO").val().trim(); if(!ebomPartNo) { Swal.fire('E-BOM 품번을 입력해주세요.'); - return; - } - + return; + } + // E-BOM 조회 후 미리보기 로드 fn_loadBomPreview(ebomPartNo, 'EBOM'); }); @@ -196,9 +204,9 @@ $(function(){ var mbomPartNo = $("#MBOM_PART_NO").val().trim(); if(!mbomPartNo) { Swal.fire('M-BOM 품번을 입력해주세요.'); - return; - } - + return; + } + // M-BOM 조회 후 미리보기 로드 fn_loadBomPreview(mbomPartNo, 'MBOM'); }); @@ -222,6 +230,45 @@ $(function(){ fn_initGrid([], 3); }); +// 기존 M-BOM 확인 (Machine 이외 제품용) +function fn_checkExistingMbom(partNo) { + $.ajax({ + url: "/productionplanning/getLatestMbomByPartNo.do", + type: "POST", + data: { partNo: partNo }, + dataType: "json", + success: function(response) { + console.log("getLatestMbomByPartNo 응답:", response); + + if(response && response.MBOM_PART_NO) { + // 기존 M-BOM이 있는 경우 사용자에게 알림 + Swal.fire({ + title: '기존 M-BOM 발견', + html: '동일 품번(' + partNo + ')의 M-BOM이 이미 존재합니다.
' + + 'M-BOM 품번: ' + response.MBOM_PART_NO + '
' + + '저장일: ' + response.SAVE_DATE + '

' + + '기존 M-BOM을 자동으로 불러오시겠습니까?', + icon: 'question', + showCancelButton: true, + confirmButtonText: '자동 불러오기', + cancelButtonText: '새로 생성' + }).then((result) => { + if(result.isConfirmed) { + // M-BOM 자동 로드 + $("#MBOM_PART_NO").val(response.MBOM_PART_NO); + fn_loadBomPreview(response.MBOM_PART_NO, 'MBOM'); + } + }); + } else { + console.log("기존 M-BOM이 없습니다."); + } + }, + error: function(xhr, status, error) { + console.error("getLatestMbomByPartNo 에러:", xhr, status, error); + } + }); +} + // BOM 미리보기 로드 function fn_loadBomPreview(partNo, bomType) { console.log("fn_loadBomPreview 호출:", partNo, bomType); @@ -257,8 +304,8 @@ function fn_loadBomPreview(partNo, bomType) { // BOM 트리 데이터 로드 function fn_loadBomTree(bomObjId) { console.log("fn_loadBomTree 호출:", bomObjId); - - $.ajax({ + + $.ajax({ url: "/partMng/getStructureTreeJson.do", type: "POST", data: { @@ -514,6 +561,15 @@ function fn_saveBomCopy() { } }); + // 제품구분 가져오기 + var productCode = "${projectInfo.PRODUCT}"; + + // 기존 M-BOM 품번 가져오기 (M-BOM 선택 시 사용) + var existingMbomPartNo = ""; + if(selectedBomType === 'MBOM') { + existingMbomPartNo = $("#MBOM_PART_NO").val().trim(); + } + $.ajax({ url: "/partMng/saveBomCopy.do", type: "POST", @@ -523,6 +579,8 @@ function fn_saveBomCopy() { sourceBomType: selectedBomType, targetPartNo: copyPartNo, targetPartName: copyPartName, + productCode: productCode, // 제품구분 추가 + existingMbomPartNo: existingMbomPartNo, // 기존 M-BOM 품번 추가 bomData: bomGridData }), contentType: "application/json", @@ -542,12 +600,12 @@ function fn_saveBomCopy() { window.opener.fn_search(); } // M-BOM 품번과 저장일을 부모 창 검색 조건에 설정 - if(response.mbomPartNo) { - window.opener.$("#search_mbom_part_no").val(response.mbomPartNo); - } - if(response.saveDate) { - window.opener.$("#search_save_date").val(response.saveDate); - } + // if(response.mbomPartNo) { + // window.opener.$("#search_mbom_part_no").val(response.mbomPartNo); + // } + // if(response.saveDate) { + // window.opener.$("#search_save_date").val(response.saveDate); + // } } window.close(); }); @@ -587,13 +645,37 @@ function fn_excel() { -
+
+ + + + + + + + + + + + + + +
+ + + + + + +
+ + @@ -601,42 +683,25 @@ function fn_excel() { - - - - - - - -
- - - - - - -
- - - - - - - + - + + - + - -
- + + + -
- + + + -
+ + +
@@ -646,9 +711,9 @@ function fn_excel() { - +
- +
diff --git a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp index ad23c1d..1d84dbd 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp @@ -54,8 +54,13 @@ $(function(){ $("#search_part_no").val("${info.PART_NO}"); $("#search_part_name").val("${info.PART_NAME}"); - $("#search_mbom_part_no").val("${info.PART_NO}"); // M-BOM 품번은 품번과 동일 + $("#search_mbom_part_no").val("${info.MBOM_PART_NO}"); // M-BOM 품번 (자동 생성된 값) $("#search_save_date").val("${info.MBOM_REGDATE}"); + + // 자동으로 M-BOM 조회 + setTimeout(function() { + fn_searchMbom(); + }, 500); //Part 연결 @@ -246,11 +251,11 @@ $(function(){ fn_changeRelatePartInfo(leftPartBomQtyObjId, rightObjId, leftPartChildObjId, leftParentPartObjid, leftPartChildObjId, leftPartObjid, rightPartNo, rightPartRev); } }); -}); + }); - // 조회 버튼 클릭 - $("#btnSearch").click(function(){ - fn_searchMbom(); + // 이력보기 버튼 클릭 + $("#btnHistory").click(function(){ + fn_showHistory(); }); // 저장 버튼 클릭 @@ -258,9 +263,9 @@ $(function(){ fn_saveMbom(); }); - // BOM 복사 버튼 클릭 - $("#btnBomCopy").click(function(){ - fn_openBomCopyPopup(); + // 닫기 버튼 클릭 + $("#btnClose").click(function(){ + window.close(); }); }); @@ -462,11 +467,21 @@ function fn_searchMbom() { var partName = $("#search_part_name").val().trim(); var mbomPartNo = $("#search_mbom_part_no").val().trim(); var saveDate = $("#search_save_date").val().trim(); + var bomReportObjId = "${info.BOM_REPORT_OBJID}"; // M-BOM의 BOM_REPORT_OBJID + + console.log("fn_searchMbom 호출:", { + bomReportObjId: bomReportObjId, + partNo: partNo, + partName: partName, + mbomPartNo: mbomPartNo, + saveDate: saveDate + }); // 왼쪽 프레임의 조회 함수 호출 var leftFrame = parent.frames['leftFrame']; if(leftFrame && leftFrame.fn_searchMbom) { leftFrame.fn_searchMbom({ + bomReportObjId: bomReportObjId, partNo: partNo, partName: partName, mbomPartNo: mbomPartNo, @@ -477,15 +492,21 @@ function fn_searchMbom() { // M-BOM 저장 function fn_saveMbom() { + console.log("fn_saveMbom 호출됨"); + // 왼쪽 프레임에서 M-BOM 트리 데이터 가져오기 var leftFrame = parent.frames['leftFrame']; + console.log("leftFrame:", leftFrame); + if(!leftFrame) { alert("M-BOM 데이터를 가져올 수 없습니다."); return; } - // 트리 데이터 수집 (leftFrame에서 구현 필요) + // 트리 데이터 수집 var mbomData = leftFrame.getMbomTreeData ? leftFrame.getMbomTreeData() : null; + console.log("mbomData:", mbomData); + console.log("mbomData length:", mbomData ? mbomData.length : 0); if(!mbomData || mbomData.length === 0) { alert("저장할 M-BOM 데이터가 없습니다."); @@ -497,18 +518,25 @@ function fn_saveMbom() { return; } + var saveData = { + mbomData: mbomData, + partNo: $("#search_part_no").val().trim(), + partName: $("#search_part_name").val().trim(), + mbomPartNo: $("#search_mbom_part_no").val().trim(), + isUpdate: $("#search_mbom_part_no").val().trim() !== "" + }; + + console.log("저장할 데이터:", saveData); + // 저장 API 호출 $.ajax({ url: "/productionplanning/saveMbom.do", method: 'post', - data: JSON.stringify({ - mbomData: mbomData, - partNo: $("#search_part_no").val().trim(), - partName: $("#search_part_name").val().trim() - }), + data: JSON.stringify(saveData), contentType: 'application/json', dataType: 'json', success: function(data) { + console.log("저장 응답:", data); if(data && data.result === "success") { alert("M-BOM이 저장되었습니다."); @@ -520,34 +548,75 @@ function fn_saveMbom() { window.opener.fn_search(); } } else { - alert("M-BOM 저장에 실패했습니다."); + alert("M-BOM 저장에 실패했습니다: " + (data.message || "")); } }, error: function(jqxhr, status, error){ console.error("M-BOM 저장 오류:", error); - alert("M-BOM 저장 중 오류가 발생했습니다."); - } + console.error("응답:", jqxhr.responseText); + alert("M-BOM 저장 중 오류가 발생했습니다."); + } }); } -// BOM 복사 팝업 열기 -function fn_openBomCopyPopup() { - var objId = $("#objId").val(); +// M-BOM 이력보기 +function fn_showHistory() { + var mbomPartNo = $("#search_mbom_part_no").val().trim(); - if(!objId || objId === "-1") { - alert("프로젝트 정보를 찾을 수 없습니다."); + if(!mbomPartNo) { + alert("M-BOM 품번이 없습니다. 먼저 M-BOM을 저장해주세요."); return; } - // BOM 복사 팝업 열기 (저번에 만든 화면) - var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId; - var popupName = "bomCopyPopup"; - var popupWidth = 1400; - var popupHeight = 800; - var left = (screen.width - popupWidth) / 2; - var top = (screen.height - popupHeight) / 2; - - window.open(url, popupName, "width=" + popupWidth + ",height=" + popupHeight + ",left=" + left + ",top=" + top + ",scrollbars=yes,resizable=yes"); + // M-BOM 이력 조회 + $.ajax({ + url: "/productionplanning/getMbomHistory.do", + method: 'post', + data: { + mbomPartNo: mbomPartNo + }, + dataType: 'json', + success: function(data) { + if(data && data.historyList && data.historyList.length > 0) { + // 이력 팝업 표시 + var historyHtml = ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + + for(var i = 0; i < data.historyList.length; i++) { + var item = data.historyList[i]; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + historyHtml += ""; + } + + historyHtml += "
순번M-BOM 품번저장일수정자비고
" + (i + 1) + "" + (item.MBOM_PART_NO || "") + "" + (item.REGDATE || "") + "" + (item.REGUSER || "") + "" + (item.REMARK || "") + "
"; + + // 새 창으로 이력 표시 + var historyWindow = window.open("", "mbomHistory", "width=800,height=600,scrollbars=yes,resizable=yes"); + historyWindow.document.write("M-BOM 이력"); + historyWindow.document.write("

M-BOM 수정 이력

"); + historyWindow.document.write(historyHtml); + historyWindow.document.write(""); + historyWindow.document.close(); + } else { + alert("이력이 없습니다."); + } + }, + error: function(jqxhr, status, error){ + console.error("M-BOM 이력 조회 오류:", error); + alert("M-BOM 이력 조회 중 오류가 발생했습니다."); + } + }); } @@ -580,9 +649,9 @@ function fn_openBomCopyPopup() { - + - + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp index 14e4f64..3aeffca 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp @@ -70,7 +70,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 50, + width: 40, title: '', field: 'CHK', formatter: function(cell, formatterParams, onRendered) { @@ -83,7 +83,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'left', - width: 120, + width: 100, title: '프로젝트번호', field: 'PROJECT_NO' }, @@ -92,7 +92,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 100, + width: 80, title: '주문유형', field: 'CATEGORY_NAME' }, @@ -101,7 +101,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 100, + width: 80, title: '제품구분', field: 'PRODUCT_NAME' }, @@ -110,7 +110,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 80, + width: 70, title: '국내/해외', field: 'AREA_NAME' }, @@ -119,7 +119,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 100, + width: 90, title: '접수일', field: 'RECEIPT_DATE' }, @@ -128,7 +128,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'left', - width: 150, + width: 120, title: '고객사', field: 'CUSTOMER_NAME' }, @@ -137,7 +137,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 80, + width: 70, title: '유/무상', field: 'PAID_TYPE_NAME' }, @@ -146,7 +146,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'left', - width: 150, + width: 120, title: '품번', field: 'PART_NO' }, @@ -155,7 +155,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'left', - width: 200, + width: 150, title: '품명', field: 'PART_NAME' }, @@ -164,7 +164,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 120, + width: 100, title: 'S/N', field: 'SERIAL_NO' }, @@ -173,7 +173,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'right', - width: 80, + width: 70, title: '수주수량', field: 'QUANTITY' }, @@ -182,7 +182,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 100, + width: 90, title: '요청납기', field: 'REQ_DEL_DATE' }, @@ -191,7 +191,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'left', - width: 200, + width: 150, title: '고객사요청사항', field: 'CUSTOMER_REQUEST' }, @@ -200,7 +200,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 100, + width: 70, title: 'M-BOM', field: 'MBOM_STATUS', formatter: fnc_subInfoValueFormatter, @@ -211,11 +211,11 @@ var columns = [ // 파란색(저장된 M-BOM)일 때만 팝업 열기 if(mbomStatus !== '' && mbomStatus !== '0') { - // 검색 조건에 해당 행의 데이터 자동 입력 - $("#search_part_no").val(fnc_checkNull(rowData.PART_NO)); - $("#search_part_name").val(fnc_checkNull(rowData.PART_NAME)); - $("#search_mbom_part_no").val(fnc_checkNull(rowData.PART_NO)); // M-BOM 품번은 품번과 동일 - $("#search_save_date").val(fnc_checkNull(rowData.MBOM_REGDATE)); + // 검색 조건에 해당 행의 데이터 자동 입력 (주석처리) + // $("#search_part_no").val(fnc_checkNull(rowData.PART_NO)); + // $("#search_part_name").val(fnc_checkNull(rowData.PART_NAME)); + // $("#search_mbom_part_no").val(fnc_checkNull(rowData.MBOM_PART_NO)); // M-BOM 품번 (자동 생성된 값) + // $("#search_save_date").val(fnc_checkNull(rowData.MBOM_REGDATE)); fn_openMBomFormPopup(objid); } else { @@ -232,7 +232,7 @@ var columns = [ { headerHozAlign: 'center', hozAlign: 'center', - width: 120, + width: 100, title: '최종저장일', field: 'MBOM_REGDATE' } @@ -241,7 +241,7 @@ var columns = [ // 검색 함수 function fn_search(){ // showCheck를 false로 설정하여 자동 체크박스 제거 (columns에 이미 체크박스 정의되어 있음) - _tabulGrid = fnc_tabul_search(_tabul_layout_fitColumns, _tabulGrid, "/productionplanning/mBomMgmtGridList.do", columns, false); + _tabulGrid = fnc_tabul_search(_tabul_layout_fitData, _tabulGrid, "/productionplanning/mBomMgmtGridList.do", columns, false); // 그리드 로드 완료 후 행 클릭 이벤트 추가 if(_tabulGrid) { @@ -397,11 +397,12 @@ function fn_openBomCopyPopupWindow(objId) { - + - + + <%-- @@ -409,6 +410,7 @@ function fn_openBomCopyPopupWindow(objId) { + --%>
diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp index 06fd456..03abffe 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp @@ -38,98 +38,317 @@ $(function(){ $('.select2').select2(); - // E-BOM 할당 버튼 (변경) - $("#moveChange").click(function(){ + //Part 연결 (<< 버튼) + $("#moveLeft").click(function(){ + // Tabulator에서 선택된 오른쪽 행 데이터 가져오기 + var rightFrame = parent.frames['rightFrame']; + var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : []; + + if(rightSelectedRows.length === 0) { + showConfirm("선택된 파트가 없습니다."); + return false; + } + + // 왼쪽 프레임에서 선택된 행 데이터 가져오기 + var leftPartNoObj = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document); + + var leftPartChildObjId = null; + var leftPartNo = null; + var leftPartNoQty = null; + var leftParentObjId = null; + var leftPartLastObjId = null; + var leftQtyParObjId = null; + var leftParentParts = ""; + + if(leftPartNoObj.length > 0) { + leftPartChildObjId = leftPartNoObj.val(); + leftPartNo = leftPartNoObj.attr("data-PART_NO"); + leftPartNoQty = leftPartNoObj.attr("data-PART_NO_QTY"); + leftParentObjId = leftPartNoObj.attr("data-OBJID"); + leftPartLastObjId = leftPartNoObj.attr("data-LAST_PART_OBJID"); + leftQtyParObjId = leftPartNoObj.attr("data-PART_OBJID"); + leftParentParts = leftPartNoObj.attr("data-PARENT_PARTS") || ""; + } + + // 같은 Part를 연결한건지 체크 + var isSamePart = false; + for(var i = 0; i < rightSelectedRows.length; i++){ + var rowData = rightSelectedRows[i].getData(); + var rightPartNo = rowData.PART_NO; + if(rightPartNo == leftPartNo){ + showConfirm({ + title: '연결 불가', + html: '오류 Part No : ['+rightPartNo+']
같은 Part No끼리 연결할 수 없습니다.', + icon: 'error' + }); + isSamePart = true; + break; + } + } + + if(isSamePart) return false; + + // 선택된 파트의 OBJID 배열 생성 + var rightCheckedArr = []; + for(var i = 0; i < rightSelectedRows.length; i++){ + var rowData = rightSelectedRows[i].getData(); + rightCheckedArr.push(rowData.OBJID); + } + + // Part 연결 확인 + if(fnc_checkNull(leftPartNo) == ""){ + showConfirm({ + title: '1레벨 등록 확인', + html: '좌측에 선택된 Part정보가 없습니다.
이대로 연결하면 1레벨로 등록됩니다.

진행하시겠습니까?', + icon: 'warning', + showCancelButton: true, + confirmButtonText: '진행', + cancelButtonText: '취소' + }).then(result => { + if (result.isConfirmed) { + fn_relatePartInfo(leftPartChildObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId); + } + }); + return; + } + showConfirm({ - title: 'E-BOM 할당', - text: 'E-BOM을 선택하여 이 프로젝트에 할당하시겠습니까?', + title: 'Part 연결', + text: '선택한 Part를 연결하시겠습니까?', icon: 'question', showCancelButton: true, - confirmButtonColor: '#3085d6', - cancelButtonColor: '#d33', - confirmButtonText: '할당', + confirmButtonText: '연결', cancelButtonText: '취소' }).then(result => { if (result.isConfirmed) { - fn_assignEbom(); + fn_relatePartInfo(leftPartChildObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId); + } + }); + }); + //end of Part 연결 + + //연결된 part 삭제 (>> 버튼) + $("#moveRight").click(function(){ + var leftPartNoObj = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document); + var leftPartChildObjId = leftPartNoObj.val(); + var leftPartNo = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PART_NO"); + var leftParentPartNo = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PARENT_PART_NO"); + var leftParentObjId = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PARENT_OBJID"); + var leftPartLastObjId = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-LAST_PART_OBJID"); + + fn_deletePartRelateInfo(leftPartNoObj.val(), leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId); + }); + //end of 연결된 part 삭제 + + //연결된 part 변경 (변경 버튼) + $("#moveChange").click(function(){ + var leftPartNoList = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document); + + if(leftPartNoList.length === 0){ + showConfirm("선택된 파트가 없습니다."); + return false; + } + + if(leftPartNoList.length > 1){ + showConfirm("한번에 1개의 파트만 변경가능합니다."); + return false; + } + + var leftPartNo = leftPartNoList.attr("data-PART_NO"); + var leftPartObjid = leftPartNoList.attr("data-BOM_LAST_PART_OBJID"); + var leftParentPartObjid = leftPartNoList.attr("data-PARENT_PART_NO"); + var leftPartChildObjId = leftPartNoList.val(); + var leftPartBomQtyObjId = leftPartNoList.attr("data-OBJID"); + + // Tabulator에서 선택된 오른쪽 행 데이터 가져오기 + var rightFrame = parent.frames['rightFrame']; + var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : []; + + if(rightSelectedRows.length === 0){ + showConfirm("선택된 파트가 없습니다."); + return false; + } + + if(rightSelectedRows.length > 1){ + showConfirm("한번에 1개의 파트만 변경가능합니다."); + return false; + } + + var rightRowData = rightSelectedRows[0].getData(); + var rightPartNo = rightRowData.PART_NO; + var rightPartRev = rightRowData.REVISION || ""; + var rightObjId = rightRowData.OBJID; + + // Part 변경 확인 + showConfirm({ + title: 'Part 변경', + html: '선택한 Part를 변경하시겠습니까?

' + + '기존: ' + leftPartNo + '
' + + '변경: ' + rightPartNo, + icon: 'warning', + showCancelButton: true, + confirmButtonText: '변경', + cancelButtonText: '취소' + }).then(result => { + if (result.isConfirmed) { + fn_changeRelatePartInfo(leftPartBomQtyObjId, rightObjId, leftPartChildObjId, leftParentPartObjid, leftPartChildObjId, leftPartObjid, rightPartNo, rightPartRev); } }); }); - // << 버튼 (현재는 사용 안 함) - $("#moveLeft").click(function(){ - showConfirm("이 기능은 현재 사용할 수 없습니다."); - }); - - // >> 버튼 (현재는 사용 안 함) - $("#moveRight").click(function(){ - showConfirm("이 기능은 현재 사용할 수 없습니다."); - }); - }); -// E-BOM 할당 함수 -function fn_assignEbom(){ - // 오른쪽 프레임에서 선택된 E-BOM 가져오기 - var rightFrame = parent.frames['rightFrame']; - var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : []; - - if(rightSelectedRows.length === 0){ - showConfirm("할당할 E-BOM을 선택해주세요."); - return false; +//구조 연결 +function fn_relatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId){ + if(typeof rightCheckedArr != "undefined" && rightCheckedArr.length == 0){ + showConfirm("선택된 Part가 없습니다."); + return; } - if(rightSelectedRows.length > 1){ - showConfirm("한 번에 1개의 E-BOM만 할당할 수 있습니다."); - return false; - } - - var rowData = rightSelectedRows[0].getData(); - var bomReportObjid = rowData.OBJID; + // M-BOM API 호출 + console.log("API 호출 시작: /productionplanning/relateMbomPartInfo.do"); + console.log("전송 데이터:", { + "leftObjId": leftObjId, + "leftPartNoQty": leftPartNoQty, + "OBJID": $("#objId").val(), + "rightCheckedArr[]": rightCheckedArr, + "partObjId": leftPartLastObjId, + "BOM_REPORT_OBJID": $("#objId").val(), + "leftPartChildObjId": leftPartChildObjId, + "leftQtyParObjId": leftQtyParObjId + }); $.ajax({ - url: "/productionplanning/assignEbomToMbom.do", + url: "/productionplanning/relateMbomPartInfo.do", method: 'post', + traditional: true, data: { - "projectMgmtObjid": $("#objId").val(), - "bomReportObjid": bomReportObjid + "leftObjId": leftObjId, + "leftPartNoQty": leftPartNoQty, + "OBJID": $("#objId").val(), + "rightCheckedArr[]": rightCheckedArr, + "partObjId": leftPartLastObjId, + "BOM_REPORT_OBJID": $("#objId").val(), + "leftPartChildObjId": leftPartChildObjId, + "leftQtyParObjId": leftQtyParObjId }, dataType: 'json', + async:false, success: function(data) { + console.log("API 응답:", data); if(data.result){ - showConfirm({ - title: '할당 완료', - text: 'E-BOM이 성공적으로 할당되었습니다.', - icon: 'success' - }); + // 왼쪽 프레임 새로고침 (캐시 방지) + var leftFrame = parent.frames['leftFrame']; + leftFrame.location.href = leftFrame.location.href.split('?')[0] + '?t=' + new Date().getTime(); - // 왼쪽 프레임 새로고침 - parent.frames['leftFrame'].location.reload(); - - // 부모 창(M-BOM 목록) 새로고침 - if(window.opener && window.opener.fn_search) { - window.opener.fn_search(); + // 오른쪽 프레임 선택 해제 + var rightFrame = parent.frames['rightFrame']; + if(rightFrame.clearSelection) { + rightFrame.clearSelection(); } } else { - showConfirm({ - title: '할당 실패', - text: 'E-BOM 할당 중 오류가 발생했습니다.', - icon: 'error' - }); + console.error("API 결과 실패"); } }, error: function(jqxhr, status, error){ - showConfirm({ - title: '오류', - text: 'E-BOM 할당 중 오류가 발생했습니다.', - icon: 'error' - }); + console.error("API 호출 실패:", error); + console.error("상태 코드:", jqxhr.status); + console.error("응답 텍스트:", jqxhr.responseText); + } + }); +} +//end of 구조 연결 + +//구조 연결 해제 +function fn_deletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId){ + if(leftObjId == null){ + showConfirm("연결 해제할 Part를 선택해 주시기 바랍니다."); + return; + } + + showConfirm({ + title: 'Part 연결 해제', + text: '선택한 Part의 연결을 해제하시겠습니까?', + icon: 'warning', + showCancelButton: true, + confirmButtonText: '연결 해제', + cancelButtonText: '취소' + }).then(result => { + if (!result.isConfirmed) return; + + // M-BOM API 호출 + $.ajax({ + url: "/productionplanning/deleteMbomPartRelateInfo.do", + method: 'post', + data: { + "OBJID": $("#objId").val(), + "leftObjId": leftObjId, + "partObjId": leftPartLastObjId, + "BOM_REPORT_OBJID": $("#objId").val(), + "leftPartChildObjId": leftPartChildObjId, + "leftParentPartNo": leftParentPartNo, + "leftParentObjId": leftParentObjId + }, + dataType: 'json', + success: function(data) { + if(data.result){ + // 왼쪽 프레임 새로고침 (캐시 방지) + var leftFrame = parent.frames['leftFrame']; + leftFrame.location.href = leftFrame.location.href.split('?')[0] + '?t=' + new Date().getTime(); + } else { + console.error("API 결과 실패"); + } + }, + error: function(jqxhr, status, error){ + console.error("API 호출 실패:", error); + } + }); + }); +} +//end of 구조 연결 해제 + +//구조 연결 변경 +function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPartChildObjId,leftPartObjid,rightPartNo,rightPartRev){ + // M-BOM API 호출 + $.ajax({ + url: "/productionplanning/changeMbomPartInfo.do", + method: 'post', + data: { + "rightObjId": rightObjId, + "OBJID": objId, + "BOM_REPORT_OBJID": $("#objId").val(), + "leftObjId": leftObjId, + "leftPartNoQty": leftPartNoQty, + "leftPartChildObjId": leftPartChildObjId, + "leftPartObjid": leftPartObjid, + "rightPartNo": rightPartNo, + "rightPartRev": rightPartRev + }, + dataType: 'json', + async:false, + success: function(data) { + if(data.result){ + // 왼쪽 프레임 새로고침 (캐시 방지) + var leftFrame = parent.frames['leftFrame']; + leftFrame.location.href = leftFrame.location.href.split('?')[0] + '?t=' + new Date().getTime(); + + // 오른쪽 프레임 선택 해제 + var rightFrame = parent.frames['rightFrame']; + if(rightFrame.clearSelection) { + rightFrame.clearSelection(); + } + } else { + console.error("API 결과 실패"); + } + }, + error: function(jqxhr, status, error){ + console.error("API 호출 실패:", error); } }); } - +
@@ -143,4 +362,3 @@ function fn_assignEbom(){
- diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupFs.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupFs.jsp index b1d7136..b15b1f6 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupFs.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupFs.jsp @@ -1,5 +1,5 @@ <%String objId = com.pms.common.utils.CommonUtils.checkNull(request.getParameter("objId"));%> - + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp index f8e27b2..d633e1d 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp @@ -17,12 +17,17 @@ #mBomTableWrap { width: 99%; margin: 10px auto; + overflow-x: auto; + overflow-y: hidden; } #mBomName { margin-bottom: 10px; font-weight: bold; font-size: 16px; } +body { + overflow: hidden; +} /* Tabulator 커스텀 스타일 */ .tabulator-row.level-1 { background-color: #fde9d9 !important; } .tabulator-row.level-2 { background-color: #daeef3 !important; } @@ -50,13 +55,37 @@ function fn_initGrid() { // 컬럼 정의 var columns = []; + // 라디오 버튼 컬럼 (E-BOM과 동일) + columns.push({ + headerHozAlign: 'center', + hozAlign: 'center', + width: 60, + title: '선택', + field: 'RADIO', + headerSort: false, + formatter: function(cell) { + var rowData = cell.getData(); + return ''; + } + }); + // 수준 컬럼 그룹 var levelColumns = []; for(var i = 1; i <= maxLevel; i++) { levelColumns.push({ headerHozAlign: 'center', hozAlign: 'center', - width: 30, + width: 25, title: i, field: 'LEVEL_' + i, formatter: function(cell) { @@ -71,36 +100,39 @@ function fn_initGrid() { columns: levelColumns }); - // 나머지 컬럼 추가 + // 기본 정보 컬럼들 (E-BOM 정보) columns.push( { headerHozAlign: 'center', hozAlign: 'left', - width: 150, + widthGrow: 2, title: '품번', field: 'PART_NO' }, { headerHozAlign: 'center', hozAlign: 'left', - width: 250, + widthGrow: 3, title: '품명', field: 'PART_NAME' }, { headerHozAlign: 'center', hozAlign: 'center', - width: 80, + width: 60, title: '수량', - field: 'QTY_TEMP' + field: 'QTY_TEMP', + visible: false }, { headerHozAlign: 'center', hozAlign: 'center', - width: 100, + width: 80, title: '항목 수량', - field: 'ITEM_QTY' + field: 'ITEM_QTY', + visible: false }, + /* 주석처리: Rev, 규격, 제품구분, 상태 컬럼 { headerHozAlign: 'center', hozAlign: 'center', @@ -128,21 +160,351 @@ function fn_initGrid() { width: 100, title: '상태', field: 'STATUS_NAME' + }, + */ + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 60, + title: '3D', + field: 'CU01_CNT', + visible: false, + formatter: function(cell) { + var value = cell.getValue(); + return value && value > 0 ? '' : ''; + } + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 60, + title: '2D', + field: 'CU02_CNT', + visible: false, + formatter: function(cell) { + var value = cell.getValue(); + return value && value > 0 ? '' : ''; + } + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 60, + title: 'PDF', + field: 'CU03_CNT', + visible: false, + formatter: function(cell) { + var value = cell.getValue(); + return value && value > 0 ? '' : ''; + } + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 100, + title: '재료', + field: 'MATERIAL', + visible: false + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 120, + title: '열처리경도', + field: 'HEAT_TREATMENT_HARDNESS', + visible: false + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 120, + title: '열처리방법', + field: 'HEAT_TREATMENT_METHOD', + visible: false + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 100, + title: '표면처리', + field: 'SURFACE_TREATMENT', + visible: false + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 150, + title: '공급업체', + field: 'SUPPLIER', + visible: false + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 100, + title: '범주이름', + field: 'CATEGORY_NAME', + visible: false } ); + // 생산관리 컬럼 그룹 + columns.push({ + title: '생산관리', + headerHozAlign: 'center', + columns: [ + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 100, + title: '지급/사급', + field: 'SUPPLY_TYPE', + editor: 'list', + editorParams: { + values: ['지급', '사급', '자급'] + } + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 100, + title: '소재', + field: 'RAW_MATERIAL', + editor: 'input', + editable: function(cell) { + // 자급인 경우 입력 불가 + return cell.getRow().getData().SUPPLY_TYPE !== '자급'; + } + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 100, + title: '사이즈', + field: 'SIZE', + editor: false, + formatter: function(cell) { + // 항목수량 × 수주수량 (수정 불가) + var data = cell.getRow().getData(); + var itemQty = data.ITEM_QTY || 0; + var orderQty = data.ORDER_QTY || 0; + return itemQty * orderQty; + } + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 100, + title: '소요량', + field: 'REQUIRED_QTY', + editor: false + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 100, + title: '발주수량', + field: 'ORDER_QTY', + editor: false, + formatter: function(cell) { + // 항목수량 (수정 불가) + return cell.getRow().getData().ITEM_QTY || 0; + } + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 80, + title: "Q'ty", + field: 'QTY', + editor: 'number', + editorParams: { + min: 0, + step: 1 + } + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 100, + title: '제작수량', + field: 'PRODUCTION_QTY', + editor: 'number', + editorParams: { + min: 0, + step: 1 + } + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 150, + title: '가공업체', + field: 'PROCESSING_VENDOR', + editor: 'input' + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 100, + title: '가공납기', + field: 'PROCESSING_DEADLINE', + editor: 'date' + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 100, + title: '연삭납기', + field: 'GRINDING_DEADLINE', + editor: 'date' + } + ] + }); + + // 구매 컬럼 그룹 (제작수량 기준) + columns.push({ + title: '구매', + headerHozAlign: 'center', + columns: [ + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 150, + title: '소재품번', + field: 'MATERIAL_PART_NO', + editor: 'input' + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 100, + title: '정미수량', + field: 'NET_QTY', + editor: false, + formatter: function(cell) { + // 소요량 × 제작수량 (소수점 무조건 올림) + var data = cell.getRow().getData(); + var requiredQty = parseFloat(data.REQUIRED_QTY) || 0; + var productionQty = parseFloat(data.PRODUCTION_QTY) || 0; + var netQty = requiredQty * productionQty; + return Math.ceil(netQty); // 무조건 올림 + } + }, + { + headerHozAlign: 'center', + hozAlign: 'center', + width: 100, + title: '발주수량', + field: 'PO_QTY', + editor: 'number', + editorParams: { + min: 0, + step: 1 + } + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + width: 150, + title: '공급업체', + field: 'VENDOR', + editor: 'input' + }, + { + headerHozAlign: 'center', + hozAlign: 'right', + width: 100, + title: '단가', + field: 'UNIT_PRICE', + editor: 'number', + editorParams: { + min: 0, + step: 0.01 + }, + formatter: function(cell) { + var value = cell.getValue(); + return value ? Number(value).toLocaleString() : '0'; + } + }, + { + headerHozAlign: 'center', + hozAlign: 'right', + width: 100, + title: '총단가', + field: 'TOTAL_PRICE', + editor: false, + formatter: function(cell) { + // 발주수량 × 단가 + var data = cell.getRow().getData(); + var poQty = parseFloat(data.PO_QTY) || 0; + var unitPrice = parseFloat(data.UNIT_PRICE) || 0; + var totalPrice = poQty * unitPrice; + return totalPrice.toLocaleString(); + } + } + ] + }); + + // 서버에서 전달받은 데이터 확인 + var bomTreeData = ${bomTreeListJson}; + console.log("bomTreeData:", bomTreeData); + console.log("bomTreeData length:", bomTreeData ? bomTreeData.length : 0); + // Tabulator 생성 _tabulGrid = new Tabulator("#mBomTableWrap", { - layout: "fitColumns", + layout: "fitData", height: "calc(100vh - 150px)", columns: columns, - data: ${bomTreeListJson}, + data: bomTreeData, rowFormatter: function(row) { var data = row.getData(); var level = data.LEVEL || 1; row.getElement().classList.add('level-' + level); } }); + + // 셀 편집 이벤트 등록 + _tabulGrid.on("cellEdited", function(cell) { + var field = cell.getField(); + var row = cell.getRow(); + var data = row.getData(); + + // 지급/사급 변경 시 소재, 사이즈, 소요량 필드 재계산 + if(field === 'SUPPLY_TYPE') { + if(data.SUPPLY_TYPE === '자급') { + // 자급인 경우 소재, 사이즈, 소요량 초기화 + row.update({ + RAW_MATERIAL: '', + SIZE: 0, + REQUIRED_QTY: 0 + }); + } + // 행 전체 재렌더링 + row.reformat(); + } + + // 제작수량 변경 시 정미수량 자동 계산 + if(field === 'PRODUCTION_QTY' || field === 'REQUIRED_QTY') { + var requiredQty = parseFloat(data.REQUIRED_QTY) || 0; + var productionQty = parseFloat(data.PRODUCTION_QTY) || 0; + var netQty = Math.ceil(requiredQty * productionQty); + row.update({NET_QTY: netQty}); + } + + // 발주수량 또는 단가 변경 시 총단가 자동 계산 + if(field === 'PO_QTY' || field === 'UNIT_PRICE') { + var poQty = parseFloat(data.PO_QTY) || 0; + var unitPrice = parseFloat(data.UNIT_PRICE) || 0; + var totalPrice = poQty * unitPrice; + row.update({TOTAL_PRICE: totalPrice}); + } + + // Q'ty 초기값 설정 (발주수량에서 가져오기) + if(field === 'ORDER_QTY' && !data.QTY) { + row.update({QTY: data.ORDER_QTY}); + } + }); } // 필터 적용 함수 @@ -172,20 +534,26 @@ function fn_resetFilter() { // M-BOM 조회 (헤더 프레임에서 호출) function fn_searchMbom(searchParams) { + console.log("fn_searchMbom (left) 호출됨:", searchParams); + $.ajax({ url: "/productionplanning/getMbomList.do", method: 'post', data: searchParams, dataType: 'json', success: function(data) { + console.log("M-BOM 조회 결과:", data); if(data && data.list) { + console.log("데이터 개수:", data.list.length); _tabulGrid.setData(data.list); } else { + console.log("데이터 없음"); _tabulGrid.setData([]); } }, error: function(jqxhr, status, error){ console.error("M-BOM 조회 오류:", error); + console.error("응답:", jqxhr.responseText); _tabulGrid.setData([]); } }); @@ -215,7 +583,7 @@ function getMbomTreeData() { -
+
diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp index 1e6b297..37b97f9 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp @@ -29,7 +29,7 @@ body, html { padding-right: 5px; } #ebomTable { - height: calc(100% - 80px); + height: 540px; } @@ -70,10 +70,32 @@ body, html {
+ +
+
+
+ +
+ 0 건 +
+
+