diff --git a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp index 9958000..ce7101d 100644 --- a/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp +++ b/WebContent/WEB-INF/view/partMng/structureBomCopyFormPopup.jsp @@ -134,30 +134,30 @@ var selectedBomType = null; // 'EBOM' 또는 'MBOM' var bomGridData = []; // BOM 그리드 데이터 $(function(){ - // 페이지 로드 시 URL 파라미터 또는 프로젝트 정보에서 품번/품명 자동 입력 - var urlPartNo = "${param.partNo}"; - var urlPartName = "${param.partName}"; - var productCode = "${projectInfo.PRODUCT}"; + // Select2 초기화 + $('.select2').select2(); - 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}"); - } - - // 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}"); - } - + // 페이지 로드 시 품번/품명 자동 입력 + // 우선순위: urlParamInfo(POST 파라미터) > projectInfo(DB 조회) + + + // POST 파라미터로 전달된 품번/품명 사용 + $("#COPY_PART_NO").val("${urlParamInfo.PART_NO}"); + $("#COPY_PART_NAME").val("${urlParamInfo.PART_NAME}"); + + + // DB에서 조회한 프로젝트 정보 사용 + $("#COPY_PART_NO").val("${projectInfo.PART_NO}"); + $("#COPY_PART_NAME").val("${projectInfo.PART_NAME}"); + + // Machine이 아닌 경우, 동일 품번의 기존 M-BOM 확인 및 자동 로드 + var productCode = "${projectInfo.PRODUCT}"; + var isMachine = productCode && (productCode === '0001807' || productCode.toUpperCase().indexOf('MACHINE') >= 0); + if(!isMachine && "${projectInfo.PART_NO}" !== "") { + fn_checkExistingMbom("${projectInfo.PART_NO}"); + } + + // 담기 버튼 - 선택한 BOM을 복사 대상으로 설정 $("#btnAddItem").click(function(){ @@ -187,28 +187,40 @@ $(function(){ fn_saveBomCopy(); }); - // E-BOM 선택 버튼 - $("#btnSelectEbom").click(function(){ - var ebomPartNo = $("#EBOM_PART_NO").val().trim(); - if(!ebomPartNo) { - Swal.fire('E-BOM 품번을 입력해주세요.'); - return; - } - - // E-BOM 조회 후 미리보기 로드 - fn_loadBomPreview(ebomPartNo, 'EBOM'); + // E-BOM 셀렉트박스 변경 이벤트 + $("#EBOM_SELECT").change(function(){ + var selectedObjId = $(this).val(); + if(!selectedObjId) { + // 선택 해제 시 M-BOM 셀렉트박스 활성화 및 그리드 초기화 + $("#MBOM_SELECT").prop("disabled", false); + _tabulGrid.clearData(); + $("#bomPartName").text(""); + return; + } + + // E-BOM 선택 시 M-BOM 셀렉트박스 비활성화 + $("#MBOM_SELECT").val("").prop("disabled", true); + + // 선택된 E-BOM으로 미리보기 로드 + fn_loadBomPreviewByObjId(selectedObjId, 'EBOM'); }); - // M-BOM 선택 버튼 - $("#btnSelectMbom").click(function(){ - var mbomPartNo = $("#MBOM_PART_NO").val().trim(); - if(!mbomPartNo) { - Swal.fire('M-BOM 품번을 입력해주세요.'); - return; - } - - // M-BOM 조회 후 미리보기 로드 - fn_loadBomPreview(mbomPartNo, 'MBOM'); + // M-BOM 셀렉트박스 변경 이벤트 + $("#MBOM_SELECT").change(function(){ + var selectedObjId = $(this).val(); + if(!selectedObjId) { + // 선택 해제 시 E-BOM 셀렉트박스 활성화 및 그리드 초기화 + $("#EBOM_SELECT").prop("disabled", false); + _tabulGrid.clearData(); + $("#bomPartName").text(""); + return; + } + + // M-BOM 선택 시 E-BOM 셀렉트박스 비활성화 + $("#EBOM_SELECT").val("").prop("disabled", true); + + // 선택된 M-BOM으로 미리보기 로드 + fn_loadBomPreviewByObjId(selectedObjId, 'MBOM'); }); // Excel 다운로드 버튼 @@ -269,7 +281,7 @@ function fn_checkExistingMbom(partNo) { }); } -// BOM 미리보기 로드 +// BOM 미리보기 로드 (품번으로) function fn_loadBomPreview(partNo, bomType) { console.log("fn_loadBomPreview 호출:", partNo, bomType); @@ -301,6 +313,23 @@ function fn_loadBomPreview(partNo, bomType) { }); } +// BOM 미리보기 로드 (OBJID로 직접) +function fn_loadBomPreviewByObjId(objId, bomType) { + console.log("fn_loadBomPreviewByObjId 호출:", objId, bomType); + + // 전역 변수에 저장 + selectedBomObjId = objId; + selectedBomType = bomType; + + // 셀렉트박스에서 선택된 텍스트를 품명으로 표시 + var selectBox = bomType === 'EBOM' ? $("#EBOM_SELECT") : $("#MBOM_SELECT"); + var selectedText = selectBox.find("option:selected").text(); + $("#bomPartName").text(selectedText); + + // BOM 트리 데이터 로드 + fn_loadBomTree(objId); +} + // BOM 트리 데이터 로드 function fn_loadBomTree(bomObjId) { console.log("fn_loadBomTree 호출:", bomObjId); @@ -375,6 +404,7 @@ function fn_initGrid(data, maxLevel) { headerHozAlign: 'center', hozAlign: 'center', width: 60, + headerSort: false, title: '선택', field: 'RADIO', formatter: function(cell) { @@ -397,6 +427,7 @@ function fn_initGrid(data, maxLevel) { levelColumns.push({ headerHozAlign: 'center', hozAlign: 'center', + headerSort: false, width: 30, title: i, field: 'LEVEL_' + i, @@ -417,20 +448,23 @@ function fn_initGrid(data, maxLevel) { { headerHozAlign: 'center', hozAlign: 'left', - width: 150, + headerSort: false, + width: 220, title: '품번', field: 'PART_NO' }, { headerHozAlign: 'center', hozAlign: 'left', - width: 200, + headerSort: false, + // width: 200, title: '품명', field: 'PART_NAME' }, { headerHozAlign: 'center', hozAlign: 'center', + headerSort: false, width: 60, title: '수량', field: 'QTY_TEMP' @@ -438,13 +472,15 @@ function fn_initGrid(data, maxLevel) { { headerHozAlign: 'center', hozAlign: 'center', - width: 100, + headerSort: false, + width: 80, title: '항목 수량', field: 'ITEM_QTY' }, { headerHozAlign: 'center', hozAlign: 'center', + headerSort: false, width: 60, title: '3D', field: 'CU01_CNT', @@ -457,6 +493,7 @@ function fn_initGrid(data, maxLevel) { { headerHozAlign: 'center', hozAlign: 'center', + headerSort: false, width: 60, title: '2D', field: 'CU02_CNT', @@ -468,7 +505,8 @@ function fn_initGrid(data, maxLevel) { }, { headerHozAlign: 'center', - hozAlign: 'center', + hozAlign: 'center', + headerSort: false, width: 60, title: 'PDF', field: 'CU03_CNT', @@ -481,16 +519,50 @@ function fn_initGrid(data, maxLevel) { { headerHozAlign: 'center', hozAlign: 'left', - width: 100, + headerSort: false, + width: 130, title: '재료', field: 'MATERIAL' }, { headerHozAlign: 'center', - hozAlign: 'center', + hozAlign: 'left', + headerSort: false, width: 120, title: '열처리경도', field: 'HEAT_TREATMENT_HARDNESS' + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + headerSort: false, + width: 130, + title: '열처리방법', + field: 'HEAT_TREATMENT_METHOD' + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + headerSort: false, + width: 130, + title: '표면처리', + field: 'SURFACE_TREATMENT' + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + headerSort: false, + width: 120, + title: '메이커', + field: 'MAKER' + }, + { + headerHozAlign: 'center', + hozAlign: 'left', + headerSort: false, + width: 100, + title: '범주이름', + field: 'CATEGORY_NAME' } ); @@ -515,13 +587,18 @@ function fn_initGrid(data, maxLevel) { }); } -// BOM 복사 저장 +// BOM 복사 저장 - PROJECT_MGMT에 할당 정보만 저장 function fn_saveBomCopy() { var copyPartNo = $("#COPY_PART_NO").val().trim(); var copyPartName = $("#COPY_PART_NAME").val().trim(); var targetObjId = $("#TARGET_OBJID").val(); // 유효성 검사 + if(!targetObjId) { + Swal.fire('프로젝트가 선택되지 않았습니다.'); + return; + } + if(!copyPartNo || !copyPartName) { Swal.fire('품번과 품명을 입력해주세요.'); return; @@ -538,50 +615,35 @@ function fn_saveBomCopy() { } // 확인 메시지 - var confirmMessage = targetObjId - ? '선택한 ' + selectedBomType + '을(를) M-BOM으로 복사하시겠습니까?\n기존 M-BOM이 있다면 초기화됩니다.' - : '선택한 ' + selectedBomType + '을(를) 새로운 품번(' + copyPartNo + ')으로 복사하시겠습니까?'; + var confirmMessage = '선택한 ' + selectedBomType + '을(를) M-BOM 기준으로 할당하시겠습니까?\n' + + '실제 M-BOM 생성은 M-BOM 상세 팝업에서 저장 시 이루어집니다.'; Swal.fire({ - title: 'BOM 복사', + title: 'BOM 할당', text: confirmMessage, icon: 'question', showCancelButton: true, - confirmButtonText: '복사', + confirmButtonText: '할당', cancelButtonText: '취소' }).then((result) => { if(result.isConfirmed) { - // 저장 처리 + // 할당 처리 Swal.fire({ - title: '저장 중...', - text: 'BOM을 복사하고 있습니다.', + title: '할당 중...', + text: 'BOM 할당 정보를 저장하고 있습니다.', allowOutsideClick: false, didOpen: () => { Swal.showLoading(); } }); - // 제품구분 가져오기 - var productCode = "${projectInfo.PRODUCT}"; - - // 기존 M-BOM 품번 가져오기 (M-BOM 선택 시 사용) - var existingMbomPartNo = ""; - if(selectedBomType === 'MBOM') { - existingMbomPartNo = $("#MBOM_PART_NO").val().trim(); - } - $.ajax({ - url: "/partMng/saveBomCopy.do", + url: "/productionplanning/saveBomAssignment.do", type: "POST", data: JSON.stringify({ - targetObjId: targetObjId, // M-BOM 관리에서 선택한 프로젝트 OBJID - sourceBomObjId: selectedBomObjId, - sourceBomType: selectedBomType, - targetPartNo: copyPartNo, - targetPartName: copyPartName, - productCode: productCode, // 제품구분 추가 - existingMbomPartNo: existingMbomPartNo, // 기존 M-BOM 품번 추가 - bomData: bomGridData + projectObjId: targetObjId, + sourceBomType: selectedBomType, // 'EBOM' or 'MBOM' + sourceBomObjId: selectedBomObjId }), contentType: "application/json", dataType: "json", @@ -589,30 +651,22 @@ function fn_saveBomCopy() { Swal.close(); if(response && response.result === 'success') { Swal.fire({ - title: '저장 완료', - text: 'M-BOM이 성공적으로 생성되었습니다.', + title: '할당 완료', + text: 'BOM 할당 정보가 저장되었습니다.\nM-BOM 셀을 클릭하여 실제 M-BOM을 생성하세요.', icon: 'success' }).then(() => { - // 부모 창(M-BOM 관리)의 검색 함수만 호출하여 그리드 업데이트 + // 부모 창(M-BOM 관리)의 검색 함수 호출하여 그리드 업데이트 if(window.opener && !window.opener.closed) { - // 부모 창의 검색 조건 유지하면서 그리드만 새로고침 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(); }); } else { Swal.fire({ - title: '저장 실패', - text: response.message || 'BOM 복사 중 오류가 발생했습니다.', + title: '할당 실패', + text: response.message || 'BOM 할당 중 오류가 발생했습니다.', icon: 'error' }); } @@ -621,7 +675,7 @@ function fn_saveBomCopy() { Swal.close(); console.error('Save error:', error); Swal.fire({ - title: '저장 실패', + title: '할당 실패', text: '서버 오류가 발생했습니다: ' + error, icon: 'error' }); @@ -653,55 +707,55 @@ function fn_excel() {
- - - - - + + + + + + + + + - -
- - - + + -
+ + + - - - - + - - - - + + + - - - - -
- - - -
+ +
- - - -
+ + + + + +
diff --git a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp index 1d84dbd..951d68c 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp @@ -54,13 +54,47 @@ $(function(){ $("#search_part_no").val("${info.PART_NO}"); $("#search_part_name").val("${info.PART_NAME}"); - $("#search_mbom_part_no").val("${info.MBOM_PART_NO}"); // M-BOM 품번 (자동 생성된 값) - $("#search_save_date").val("${info.MBOM_REGDATE}"); + $("#search_quantity").val("${info.QUANTITY}"); // 프로젝트 수주수량 - // 자동으로 M-BOM 조회 - setTimeout(function() { - fn_searchMbom(); - }, 500); + // 저장된 M-BOM 품번 조회 및 표시 + var projectObjId = "${info.OBJID}"; + $.ajax({ + url: "/productionplanning/getLatestMbomByProjectId.do", + type: "POST", + data: { projectObjId: projectObjId }, + dataType: "json", + async: false, + success: function(response) { + if(response && response.MBOM_NO) { + console.log("저장된 M-BOM 발견:", response); + $("#search_mbom_part_no").val(response.MBOM_NO); + $("#search_save_date").val(response.REGDATE); + } else { + console.log("저장된 M-BOM 없음"); + $("#search_mbom_part_no").val(""); + $("#search_save_date").val(""); + } + }, + error: function(xhr, status, error) { + console.error("M-BOM 조회 오류:", error); + } + }); + + // 할당된 BOM 정보 확인 및 자동 로드 + var sourceBomType = "${info.SOURCE_BOM_TYPE}"; + var sourceEbomObjId = "${info.SOURCE_EBOM_OBJID}"; + var sourceMbomObjId = "${info.SOURCE_MBOM_OBJID}"; + + console.log("할당된 BOM 정보:", { + sourceBomType: sourceBomType, + sourceEbomObjId: sourceEbomObjId, + sourceMbomObjId: sourceMbomObjId + }); + + // Controller에서 이미 데이터를 로드하여 JSP에 전달하므로 자동 조회 불필요 + // setTimeout(function() { + // fn_searchMbom(); + // }, 500); //Part 연결 @@ -268,6 +302,11 @@ $(function(){ window.close(); }); + // 일괄 적용 버튼 클릭 + $("#btnApplyBulkDeadline").click(function(){ + fn_applyBulkDeadline(); + }); + }); //1레벨에 같은 Part No가 등록되어있는지 확인. @@ -461,15 +500,67 @@ function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPa }); } +// 가공납기/연삭납기 일괄 적용 +function fn_applyBulkDeadline() { + var processingDeadline = $("#bulk_processing_deadline").val(); + var grindingDeadline = $("#bulk_grinding_deadline").val(); + + if(!processingDeadline && !grindingDeadline) { + alert("가공납기 또는 연삭납기를 입력해주세요."); + return; + } + + // 확인 메시지 + var message = "선택한 날짜를 전체 항목에 일괄 적용하시겠습니까?\n\n"; + if(processingDeadline) message += "가공납기: " + processingDeadline + "\n"; + if(grindingDeadline) message += "연삭납기: " + grindingDeadline; + + if(!confirm(message)) { + return; + } + + // 왼쪽 프레임의 함수 호출 + var bottomFrame = parent.frames[1]; + var leftFrame = bottomFrame ? bottomFrame.frames['leftFrame'] : null; + + if(!leftFrame || !leftFrame.applyBulkDeadline) { + alert("M-BOM 화면을 찾을 수 없습니다."); + return; + } + + // 일괄 적용 실행 + var updatedCount = leftFrame.applyBulkDeadline(processingDeadline, grindingDeadline); + + if(updatedCount > 0) { + alert("일괄 적용이 완료되었습니다. (" + updatedCount + "개 항목)"); + } else { + alert("적용할 데이터가 없습니다."); + } +} + // M-BOM 조회 function fn_searchMbom() { var partNo = $("#search_part_no").val().trim(); 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 + + // 할당된 BOM 정보 사용 (우선순위: SOURCE_EBOM_OBJID > SOURCE_MBOM_OBJID > 기존 BOM_REPORT_OBJID) + var sourceBomType = "${info.SOURCE_BOM_TYPE}"; + var sourceEbomObjId = "${info.SOURCE_EBOM_OBJID}"; + var sourceMbomObjId = "${info.SOURCE_MBOM_OBJID}"; + var bomReportObjId = ""; + + if(sourceBomType === "EBOM" && sourceEbomObjId) { + bomReportObjId = sourceEbomObjId; + } else if(sourceBomType === "MBOM" && sourceMbomObjId) { + bomReportObjId = sourceMbomObjId; + } else { + bomReportObjId = "${info.BOM_REPORT_OBJID}"; // 기존 방식 (하위 호환) + } console.log("fn_searchMbom 호출:", { + sourceBomType: sourceBomType, bomReportObjId: bomReportObjId, partNo: partNo, partName: partName, @@ -478,15 +569,20 @@ function fn_searchMbom() { }); // 왼쪽 프레임의 조회 함수 호출 - var leftFrame = parent.frames['leftFrame']; + var bottomFrame = parent.frames[1]; // 하단 프레임셋 + var leftFrame = bottomFrame ? bottomFrame.frames['leftFrame'] : null; + if(leftFrame && leftFrame.fn_searchMbom) { leftFrame.fn_searchMbom({ bomReportObjId: bomReportObjId, + sourceBomType: sourceBomType, partNo: partNo, partName: partName, mbomPartNo: mbomPartNo, saveDate: saveDate }); + } else { + console.error("왼쪽 프레임 또는 fn_searchMbom 함수를 찾을 수 없습니다."); } } @@ -494,8 +590,16 @@ function fn_searchMbom() { function fn_saveMbom() { console.log("fn_saveMbom 호출됨"); - // 왼쪽 프레임에서 M-BOM 트리 데이터 가져오기 - var leftFrame = parent.frames['leftFrame']; + // 프레임 구조: parent(최상위) -> parent.frames[1](하단) -> parent.frames[1].frames['leftFrame'] + var bottomFrame = parent.frames[1]; // 하단 프레임 (mBomPopupFs.jsp) + console.log("bottomFrame:", bottomFrame); + + if(!bottomFrame) { + alert("하단 프레임을 찾을 수 없습니다."); + return; + } + + var leftFrame = bottomFrame.frames['leftFrame']; // 왼쪽 프레임 (mBomPopupLeft.jsp) console.log("leftFrame:", leftFrame); if(!leftFrame) { @@ -518,15 +622,35 @@ function fn_saveMbom() { return; } + var projectObjId = "${info.OBJID}"; + + // 기존 M-BOM 존재 여부 확인 (동기 처리) + var existingMbom = null; + $.ajax({ + url: "/productionplanning/getLatestMbomByProjectId.do", + type: "POST", + data: { projectObjId: projectObjId }, + dataType: "json", + async: false, + success: function(response) { + if(response && response.OBJID) { + existingMbom = response; + console.log("기존 M-BOM 발견:", existingMbom); + } + } + }); + var saveData = { + projectObjId: projectObjId, // PROJECT_MGMT의 OBJID 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() !== "" + mbomPartNo: existingMbom ? existingMbom.MBOM_NO : "", // 기존 M-BOM 품번 사용 + isUpdate: existingMbom !== null // 기존 M-BOM이 있으면 업데이트 }; console.log("저장할 데이터:", saveData); + console.log("isUpdate:", saveData.isUpdate); // 저장 API 호출 $.ajax({ @@ -540,13 +664,13 @@ function fn_saveMbom() { if(data && data.result === "success") { alert("M-BOM이 저장되었습니다."); - // 조회 새로고침 - fn_searchMbom(); - // 부모 창 새로고침 if(window.opener && window.opener.fn_search) { window.opener.fn_search(); } + + // 현재 창 닫기 + window.close(); } else { alert("M-BOM 저장에 실패했습니다: " + (data.message || "")); } @@ -561,50 +685,45 @@ function fn_saveMbom() { // M-BOM 이력보기 function fn_showHistory() { - var mbomPartNo = $("#search_mbom_part_no").val().trim(); + var projectObjId = "${info.OBJID}"; - if(!mbomPartNo) { - alert("M-BOM 품번이 없습니다. 먼저 M-BOM을 저장해주세요."); + if(!projectObjId) { + alert("프로젝트 정보가 없습니다."); return; } - // M-BOM 이력 조회 + // M-BOM 이력 조회 (프로젝트 기준) $.ajax({ url: "/productionplanning/getMbomHistory.do", method: 'post', data: { - mbomPartNo: mbomPartNo + projectObjId: projectObjId }, 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 || "") + "
"; + // 이력 상세 분석 및 HTML 생성 + var historyHtml = generateHistoryHtml(data.historyList); // 새 창으로 이력 표시 - var historyWindow = window.open("", "mbomHistory", "width=800,height=600,scrollbars=yes,resizable=yes"); - historyWindow.document.write("M-BOM 이력"); - historyWindow.document.write("

M-BOM 수정 이력

"); + var historyWindow = window.open("", "mbomHistory", "width=1400,height=800,scrollbars=yes,resizable=yes"); + historyWindow.document.write("M-BOM 변경 이력"); + historyWindow.document.write(""); + historyWindow.document.write(""); + historyWindow.document.write("

M-BOM 변경 이력

"); historyWindow.document.write(historyHtml); historyWindow.document.write(""); historyWindow.document.close(); @@ -618,11 +737,419 @@ function fn_showHistory() { } }); } + +// 이력 HTML 생성 함수 +function generateHistoryHtml(historyList) { + var html = ""; + + for(var i = 0; i < historyList.length; i++) { + var history = historyList[i]; + var changeType = history.CHANGE_TYPE || "UNKNOWN"; + var changeDate = history.CHANGE_DATE || history.REGDATE || ""; + var changeUser = history.CHANGE_USER || ""; + + // 이력 헤더 + html += "
"; + html += "

"; + html += "이력 #" + (i + 1) + " - " + changeType + " (" + changeDate + " / " + changeUser + ")"; + html += "

"; + + try { + var beforeData = history.BEFORE_DATA ? JSON.parse(history.BEFORE_DATA) : null; + var afterData = history.AFTER_DATA ? JSON.parse(history.AFTER_DATA) : null; + + if(changeType === "CREATE") { + // 생성: afterData만 표시 + html += generateCreateHistoryTable(afterData); + } else if(changeType === "UPDATE") { + // 수정: 변경 사항 비교 + html += generateUpdateHistoryTable(beforeData, afterData); + } + } catch(e) { + console.error("JSON 파싱 오류:", e); + html += "

데이터 파싱 오류

"; + } + + html += "
"; + } + + return html; +} + +// 생성 이력 테이블 생성 +function generateCreateHistoryTable(afterData) { + var html = ""; + html += ""; + html += ""; + + // 헤더 정보 + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + + // BOM 상세 항목 + var mbomData = afterData.mbomData || []; + if(mbomData.length > 0) { + html += ""; + html += ""; + + for(var i = 0; i < mbomData.length; i++) { + var item = mbomData[i]; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + } + } + + html += "
생성된 M-BOM 정보
항목항목
M-BOM 품번" + (afterData.mbomNo || afterData.MBOM_NO || "") + "품번" + (afterData.partNo || afterData.PART_NO || "") + "
품명" + (afterData.partName || afterData.PART_NAME || "") + "기준 BOM 유형" + (afterData.sourceBomType || afterData.SOURCE_BOM_TYPE || "") + "
생성된 BOM 항목 (" + mbomData.length + "개)
품번품명수량레벨
" + (item.partNo || "") + "" + (item.partName || "") + "" + (item.qty || "") + "" + (item.level || "") + "
"; + return html; +} + +// 수정 이력 테이블 생성 (새 형식) +function generateUpdateHistoryTable(beforeData, afterData) { + var html = ""; + + // beforeData는 이제 변경된 항목 배열 + var changedItems = beforeData; + + if(!Array.isArray(changedItems) || changedItems.length === 0) { + return "

변경 사항이 없습니다.

"; + } + + html += ""; + html += ""; + html += ""; + + for(var i = 0; i < changedItems.length; i++) { + var item = changedItems[i]; + var changeType = item.changeType; + + if(changeType === "ADD") { + // 추가된 항목 + var afterData = item.afterData || {}; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + } else if(changeType === "DELETE") { + // 삭제된 항목 + var beforeDataItem = item.beforeData || {}; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + } else if(changeType === "MODIFY") { + // 수정된 항목 + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + } + } + + html += "
변경된 항목 (" + changedItems.length + "개)
변경유형품번품명변경 내용
추가" + (afterData.partNo || "") + "" + (afterData.partName || "") + "새 항목 추가
삭제" + (beforeDataItem.PART_NO || "") + "" + (beforeDataItem.PART_NAME || "") + "항목 삭제
수정" + (item.partNo || "") + "" + (item.partName || "") + ""; + + var fieldChanges = item.fieldChanges || []; + for(var j = 0; j < fieldChanges.length; j++) { + var fc = fieldChanges[j]; + var fieldNameKr = getFieldNameKorean(fc.field); + html += "" + fieldNameKr + ": "; + html += "" + (fc.before || "(없음)") + " → "; + html += "" + (fc.after || "(없음)") + ""; + if(j < fieldChanges.length - 1) html += "
"; + } + + html += "
"; + return html; +} + +// 필드명 한글 변환 +function getFieldNameKorean(field) { + var fieldMap = { + "QTY": "수량", + "SUPPLY_TYPE": "자급/사급", + "RAW_MATERIAL": "소재", + "RAW_MATERIAL_SIZE": "사이즈", + "RAW_MATERIAL_PART_NO": "소재품번", + "PROCESSING_VENDOR": "가공업체", + "PROCESSING_DEADLINE": "가공납기", + "GRINDING_DEADLINE": "연삭납기", + "REQUIRED_QTY": "소재소요량", + "ORDER_QTY": "소재발주수량", + "PRODUCTION_QTY": "제작수량", + "REMARK": "비고" + }; + return fieldMap[field] || field; +} + +// 기존 함수들은 사용하지 않지만 남겨둠 +function oldGenerateUpdateHistoryTable(beforeData, afterData) { + var html = ""; + + // 1. 헤더 정보 변경 확인 + var headerChanges = compareHeaderData(beforeData, afterData); + if(headerChanges.length > 0) { + html += ""; + html += ""; + html += ""; + + for(var i = 0; i < headerChanges.length; i++) { + var change = headerChanges[i]; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + } + html += "
헤더 정보 변경
항목변경 전변경 후
" + change.field + "" + change.before + "" + change.after + "

"; + } + + // 2. BOM 항목 변경 분석 + var beforeItems = beforeData.mbomData || []; + var afterItems = afterData.mbomData || []; + + var changes = compareBomItems(beforeItems, afterItems); + + // Excel 스타일 통합 테이블 생성 + if(false && changes.added.length > 0 || changes.deleted.length > 0 || changes.modified.length > 0) { + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + + // 추가된 항목 + for(var i = 0; i < changes.added.length; i++) { + var item = changes.added[i]; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + } + + // 삭제된 항목 + for(var i = 0; i < changes.deleted.length; i++) { + var item = changes.deleted[i]; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + } + + // 수정된 항목 (변경된 필드만 강조) + for(var i = 0; i < changes.modified.length; i++) { + var mod = changes.modified[i]; + var changedFields = {}; + for(var j = 0; j < mod.changes.length; j++) { + changedFields[mod.changes[j].fieldKey] = true; + } + + html += ""; + html += ""; + html += ""; + html += ""; + html += "" + (mod.after.qty || "") + ""; + html += "" + (mod.after.supplyType || "") + ""; + html += "" + (mod.after.rawMaterial || "") + ""; + html += "" + (mod.after.rawMaterialSize || "") + ""; + html += "" + (mod.after.rawMaterialPartNo || "") + ""; + html += "" + (mod.after.requiredQty || "") + ""; + html += "" + (mod.after.processingVendor || "") + ""; + html += "" + (mod.after.processingDeadline || "") + ""; + html += "" + (mod.after.grindingDeadline || "") + ""; + html += "" + (mod.after.orderQty || "") + ""; + html += "" + (mod.after.productionQty || "") + ""; + html += "" + (mod.after.remark || "") + ""; + html += ""; + } + + html += "
구분품번품명수량자급/사급소재사이즈소재품번소재소요량가공업체가공납기연삭납기소재발주수량제작수량비고
추가" + (item.partNo || "") + "" + (item.partName || "") + "" + (item.qty || "") + "" + (item.supplyType || "") + "" + (item.rawMaterial || "") + "" + (item.rawMaterialSize || "") + "" + (item.rawMaterialPartNo || "") + "" + (item.requiredQty || "") + "" + (item.processingVendor || "") + "" + (item.processingDeadline || "") + "" + (item.grindingDeadline || "") + "" + (item.orderQty || "") + "" + (item.productionQty || "") + "" + (item.remark || "") + "
삭제" + (item.partNo || "") + "" + (item.partName || "") + "" + (item.qty || "") + "" + (item.supplyType || "") + "" + (item.rawMaterial || "") + "" + (item.rawMaterialSize || "") + "" + (item.rawMaterialPartNo || "") + "" + (item.requiredQty || "") + "" + (item.processingVendor || "") + "" + (item.processingDeadline || "") + "" + (item.grindingDeadline || "") + "" + (item.orderQty || "") + "" + (item.productionQty || "") + "" + (item.remark || "") + "
수정" + (mod.partNo || "") + "" + (mod.partName || "") + "
"; + } + + return html; +} + +// 헤더 데이터 비교 +function compareHeaderData(before, after) { + var changes = []; + var fieldsToCheck = { + 'SOURCE_BOM_TYPE': '기준 BOM 유형', + 'SOURCE_EBOM_OBJID': '기준 E-BOM', + 'SOURCE_MBOM_OBJID': '기준 M-BOM', + 'PART_NO': '품번', + 'PART_NAME': '품명', + 'MBOM_STATUS': 'M-BOM 상태' + }; + + for(var key in fieldsToCheck) { + var beforeVal = before[key] || before[key.toLowerCase()] || ""; + var afterVal = after[key] || after[key.toLowerCase()] || ""; + + if(beforeVal != afterVal) { + changes.push({ + field: fieldsToCheck[key], + before: beforeVal, + after: afterVal + }); + } + } + + return changes; +} + +// BOM 항목 비교 +function compareBomItems(beforeItems, afterItems) { + var added = []; + var deleted = []; + var modified = []; + + // childObjid를 키로 사용하여 매핑 + var beforeMap = {}; + var afterMap = {}; + + for(var i = 0; i < beforeItems.length; i++) { + var item = beforeItems[i]; + var key = item.childObjid || item.objid; + if(key) beforeMap[key] = item; + } + + for(var i = 0; i < afterItems.length; i++) { + var item = afterItems[i]; + var key = item.childObjid || item.objid; + if(key) afterMap[key] = item; + } + + // 추가된 항목 찾기 + for(var key in afterMap) { + if(!beforeMap[key]) { + added.push(afterMap[key]); + } + } + + // 삭제된 항목 찾기 + for(var key in beforeMap) { + if(!afterMap[key]) { + deleted.push(beforeMap[key]); + } + } + + // 수정된 항목 찾기 + for(var key in afterMap) { + if(beforeMap[key]) { + var itemChanges = compareItemFields(beforeMap[key], afterMap[key]); + if(itemChanges.length > 0) { + modified.push({ + partNo: afterMap[key].partNo, + partName: afterMap[key].partName, + before: beforeMap[key], + after: afterMap[key], + changes: itemChanges + }); + } + } + } + + return { + added: added, + deleted: deleted, + modified: modified + }; +} + +// 항목 필드 비교 +function compareItemFields(before, after) { + var changes = []; + var fieldsToCheck = { + 'qty': '수량', + 'supplyType': '자급/사급', + 'rawMaterial': '소재', + 'rawMaterialSize': '사이즈', + 'rawMaterialPartNo': '소재품번', + 'processingVendor': '가공업체', + 'processingDeadline': '가공납기', + 'grindingDeadline': '연삭납기', + 'requiredQty': '소재소요량', + 'orderQty': '소재발주수량', + 'productionQty': '제작수량', + 'remark': '비고' + }; + + for(var key in fieldsToCheck) { + var beforeVal = before[key] || ""; + var afterVal = after[key] || ""; + + // 값 비교 (타입 변환 고려) + if(String(beforeVal) != String(afterVal)) { + changes.push({ + field: fieldsToCheck[key], + fieldKey: key, // 필드 키 추가 (CSS 클래스 적용용) + before: beforeVal, + after: afterVal + }); + } + } + + return changes; +}
+
@@ -654,6 +1181,21 @@ function fn_showHistory() { + + + + + + + + +
+ + + + + +
diff --git a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp index 4c7ff8a..d79f771 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomMgmtList.jsp @@ -207,24 +207,9 @@ var columns = [ cellClick: function(e, cell) { var rowData = cell.getData(); var objid = fnc_checkNull(rowData.OBJID); - var mbomStatus = fnc_checkNull(rowData.MBOM_STATUS); - // 파란색(저장된 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.MBOM_PART_NO)); // M-BOM 품번 (자동 생성된 값) - // $("#search_save_date").val(fnc_checkNull(rowData.MBOM_REGDATE)); - - fn_openMBomFormPopup(objid); - } else { - Swal.fire({ - title: '알림', - text: 'M-BOM이 생성되지 않았습니다.\nBOM 복사 버튼을 통해 먼저 M-BOM을 생성해주세요.', - icon: 'info' - }); - } + // 할당 정보 확인 후 M-BOM 팝업 열기 + fn_checkAssignmentAndOpenMbom(objid); } }, @@ -365,19 +350,72 @@ function fn_openBomCopyPopupWindow(objId) { 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 partNo = fnc_checkNull(rowData.PART_NO); + var partName = fnc_checkNull(rowData.PART_NAME); + + // hiddenForm을 사용하여 POST 방식으로 팝업 열기 (한글 인코딩 문제 해결) + var hiddenForm = document.hiddenForm; + var url = "/partMng/structureBomCopyFormPopup.do"; + var target = "bomCopyPopup"; + + hiddenForm.objId.value = objId; + hiddenForm.partNo.value = partNo; + hiddenForm.partName.value = partName; 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'); + window.open('', target, 'width=' + popup_width + ', height=' + popup_height + ', resizable=yes'); + hiddenForm.action = url; + hiddenForm.target = target; + hiddenForm.submit(); } else { Swal.fire('선택된 데이터를 찾을 수 없습니다.'); } } + +// 할당 정보 확인 후 M-BOM 팝업 열기 +function fn_checkAssignmentAndOpenMbom(projectObjId) { + // PROJECT_MGMT의 BOM 할당 정보 조회 + $.ajax({ + url: "/productionplanning/getMbomAssignmentInfo.do", + type: "POST", + data: { projectObjId: projectObjId }, + dataType: "json", + success: function(response) { + console.log("BOM 할당 정보:", response); + + if(!response || !response.SOURCE_BOM_TYPE) { + // 할당 정보가 없는 경우 + Swal.fire({ + title: '알림', + text: 'BOM 할당 정보가 없습니다.\nBOM 복사 버튼을 통해 먼저 BOM을 할당해주세요.', + icon: 'info' + }); + return; + } + + // 할당된 BOM 정보가 있는 경우 기존 M-BOM 팝업 열기 + fn_openMBomFormPopup(projectObjId); + }, + error: function(xhr, status, error) { + console.error("BOM 할당 정보 조회 오류:", error); + Swal.fire({ + title: '오류', + text: 'BOM 할당 정보를 조회하는 중 오류가 발생했습니다.', + icon: 'error' + }); + } + }); +} + +
+ + + +
+
@@ -388,6 +426,7 @@ function fn_openBomCopyPopupWindow(objId) {
+
diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp index 21cfaee..ccb1d56 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupHeaderFs.jsp @@ -6,9 +6,18 @@ if(map == null || map.isEmpty()) { return; } String objId = com.pms.common.utils.CommonUtils.checkNull(map.get("OBJID")); +String quantity = com.pms.common.utils.CommonUtils.checkNull(map.get("QUANTITY")); %> + + + + + diff --git a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp index d633e1d..a5f3263 100644 --- a/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp +++ b/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp @@ -42,8 +42,22 @@ body {