1226 lines
39 KiB
Plaintext
1226 lines
39 KiB
Plaintext
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
|
<%@ page import="com.pms.common.utils.*"%>
|
|
<%@ page import="java.util.*" %>
|
|
<%@include file= "/init.jsp" %>
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
<title><%=Constants.SYSTEM_NAME%></title>
|
|
<style>
|
|
body, html {
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
height: auto;
|
|
}
|
|
#plmSearchZon td.label,
|
|
#plmSearchZon td:first-child {
|
|
text-align: right;
|
|
padding-right: 5px;
|
|
}
|
|
</style>
|
|
<script>
|
|
// confirm/alert 헬퍼 함수
|
|
function showConfirm(options) {
|
|
if(typeof options === 'string') {
|
|
alert(options);
|
|
return Promise.resolve({isConfirmed: true});
|
|
}
|
|
|
|
var message = '';
|
|
if(options.title) message += options.title + '\n\n';
|
|
if(options.html) {
|
|
// HTML 태그 제거
|
|
message += options.html.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]+>/g, '');
|
|
} else if(options.text) {
|
|
message += options.text;
|
|
}
|
|
|
|
if(options.showCancelButton !== false && (options.icon === 'warning' || options.icon === 'question')) {
|
|
var result = confirm(message);
|
|
return Promise.resolve({isConfirmed: result});
|
|
} else {
|
|
alert(message);
|
|
return Promise.resolve({isConfirmed: true});
|
|
}
|
|
}
|
|
|
|
$(function(){
|
|
|
|
$('.select2').select2();
|
|
|
|
// 페이지 로드 시 프로젝트 정보로 검색 필드 자동 입력
|
|
<c:if test="${not empty info}">
|
|
$("#search_part_no").val("${info.PART_NO}");
|
|
$("#search_part_name").val("${info.PART_NAME}");
|
|
$("#search_quantity").val("${info.QUANTITY}"); // 프로젝트 수주수량
|
|
|
|
// 저장된 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);
|
|
|
|
// 날짜 형식 변환 (타임스탬프 또는 문자열 -> YYYY-MM-DD)
|
|
var regDate = response.REGDATE;
|
|
if(regDate) {
|
|
var dateStr = "";
|
|
|
|
// 타임스탬프(숫자)인 경우
|
|
if(typeof regDate === 'number') {
|
|
var date = new Date(regDate);
|
|
var year = date.getFullYear();
|
|
var month = String(date.getMonth() + 1).padStart(2, '0');
|
|
var day = String(date.getDate()).padStart(2, '0');
|
|
dateStr = year + '-' + month + '-' + day;
|
|
}
|
|
// 문자열인 경우 (YYYY-MM-DD HH:mm:ss 형식)
|
|
else if(typeof regDate === 'string') {
|
|
dateStr = regDate.split(' ')[0];
|
|
}
|
|
|
|
$("#search_save_date").val(dateStr);
|
|
} else {
|
|
$("#search_save_date").val("");
|
|
}
|
|
} 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}";
|
|
var productCode = "${info.PRODUCT_CODE}";
|
|
|
|
console.log("할당된 BOM 정보:", {
|
|
sourceBomType: sourceBomType,
|
|
sourceEbomObjId: sourceEbomObjId,
|
|
sourceMbomObjId: sourceMbomObjId,
|
|
productCode: productCode
|
|
});
|
|
|
|
// Machine 이외 제품: M-BOM 템플릿 자동 로드
|
|
<c:if test="${not empty mbomTemplateDetails}">
|
|
console.log("M-BOM 템플릿 발견 - 자동 로드 시작");
|
|
setTimeout(function() {
|
|
fn_loadMbomTemplate();
|
|
}, 500);
|
|
</c:if>
|
|
|
|
// Controller에서 이미 데이터를 로드하여 JSP에 전달하므로 자동 조회 불필요
|
|
// setTimeout(function() {
|
|
// fn_searchMbom();
|
|
// }, 500);
|
|
</c:if>
|
|
|
|
//Part 연결 (M-BOM용)
|
|
$("#moveLeft").click(function(){
|
|
fn_mbomAddPart();
|
|
});
|
|
|
|
//연결된 part 삭제 (M-BOM용)
|
|
$("#moveRight").click(function(){
|
|
fn_mbomDeletePart();
|
|
});
|
|
|
|
//연결된 part 변경 (M-BOM용)
|
|
$("#moveChange").click(function(){
|
|
fn_mbomChangePart();
|
|
});
|
|
|
|
|
|
|
|
// 이력보기 버튼 클릭
|
|
$("#btnHistory").click(function(){
|
|
fn_showHistory();
|
|
});
|
|
|
|
// 저장 버튼 클릭
|
|
$("#btnSave").click(function(){
|
|
fn_saveMbom();
|
|
});
|
|
|
|
// 닫기 버튼 클릭
|
|
$("#btnClose").click(function(){
|
|
fn_closeWindow();
|
|
});
|
|
|
|
/* 주석처리: 가공납기/연삭납기 일괄 적용 버튼 이벤트
|
|
// 일괄 적용 버튼 클릭
|
|
$("#btnApplyBulkDeadline").click(function(){
|
|
fn_applyBulkDeadline();
|
|
});
|
|
*/
|
|
|
|
});
|
|
|
|
/* 주석처리: 가공납기/연삭납기 일괄 적용 함수
|
|
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 템플릿 로드 (Machine 이외 제품)
|
|
function fn_loadMbomTemplate() {
|
|
console.log("fn_loadMbomTemplate 호출됨");
|
|
|
|
// 템플릿 데이터를 JSP에서 받아옴
|
|
var templateDetails = [];
|
|
<c:if test="${not empty mbomTemplateDetails}">
|
|
<c:forEach items="${mbomTemplateDetails}" var="item">
|
|
templateDetails.push({
|
|
OBJID: '', // 새로 생성될 ID
|
|
CHILD_OBJID: '${item.CHILD_OBJID}', // 템플릿의 CHILD_OBJID 유지 (트리 구조용)
|
|
PARENT_OBJID: '${item.PARENT_OBJID}',
|
|
SEQ: ${item.SEQ},
|
|
LEVEL: ${item.LEVEL},
|
|
PART_OBJID: '${item.PART_OBJID}',
|
|
PART_NO: '${item.PART_NO}',
|
|
PART_NAME: '${item.PART_NAME}',
|
|
QTY: ${item.QTY},
|
|
ITEM_QTY: ${item.QTY}, // 항목수량
|
|
QTY_TEMP: ${item.QTY},
|
|
UNIT: '${item.UNIT}',
|
|
SUPPLY_TYPE: '${item.SUPPLY_TYPE}',
|
|
MAKE_OR_BUY: '${item.MAKE_OR_BUY}',
|
|
RAW_MATERIAL: '${item.RAW_MATERIAL}',
|
|
RAW_MATERIAL_SPEC: '${item.RAW_MATERIAL_SPEC}',
|
|
SIZE: '${item.RAW_MATERIAL_SIZE}',
|
|
RAW_MATERIAL_NO: '${item.RAW_MATERIAL_PART_NO}',
|
|
PROCESSING_VENDOR: '${item.PROCESSING_VENDOR}',
|
|
PROCESSING_DEADLINE: '${item.PROCESSING_DEADLINE}',
|
|
GRINDING_DEADLINE: '${item.GRINDING_DEADLINE}',
|
|
REQUIRED_QTY: ${item.REQUIRED_QTY != null ? item.REQUIRED_QTY : 0},
|
|
// ORDER_QTY, PRODUCTION_QTY는 명시적으로 설정하지 않음 (undefined)
|
|
// 이렇게 하면 formatter에서 자동 계산됨
|
|
REMARK: '${item.REMARK}',
|
|
STATUS: 'ACTIVE'
|
|
});
|
|
</c:forEach>
|
|
</c:if>
|
|
|
|
console.log("템플릿 데이터 개수:", templateDetails.length);
|
|
|
|
// 왼쪽 프레임에 데이터 로드
|
|
var bottomFrame = parent.frames[1];
|
|
var leftFrame = bottomFrame ? bottomFrame.frames['leftFrame'] : null;
|
|
|
|
if(leftFrame && leftFrame._tabulGrid) {
|
|
leftFrame._tabulGrid.setData(templateDetails);
|
|
console.log("템플릿 데이터 로드 완료");
|
|
} else {
|
|
console.error("왼쪽 프레임 또는 그리드를 찾을 수 없습니다.");
|
|
}
|
|
}
|
|
|
|
// 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();
|
|
|
|
// 할당된 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,
|
|
mbomPartNo: mbomPartNo,
|
|
saveDate: saveDate
|
|
});
|
|
|
|
// 왼쪽 프레임의 조회 함수 호출
|
|
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 함수를 찾을 수 없습니다.");
|
|
}
|
|
}
|
|
|
|
// M-BOM 저장
|
|
function fn_saveMbom() {
|
|
console.log("fn_saveMbom 호출됨");
|
|
|
|
// 프레임 구조: 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) {
|
|
alert("M-BOM 데이터를 가져올 수 없습니다.");
|
|
return;
|
|
}
|
|
|
|
// 트리 데이터 수집
|
|
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 데이터가 없습니다.");
|
|
return;
|
|
}
|
|
|
|
// 저장 확인
|
|
if(!confirm("M-BOM을 저장하시겠습니까?")) {
|
|
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: existingMbom ? existingMbom.MBOM_NO : "", // 기존 M-BOM 품번 사용
|
|
isUpdate: existingMbom !== null // 기존 M-BOM이 있으면 업데이트
|
|
};
|
|
|
|
console.log("저장할 데이터:", saveData);
|
|
console.log("isUpdate:", saveData.isUpdate);
|
|
|
|
// 저장 API 호출
|
|
$.ajax({
|
|
url: "/productionplanning/saveMbom.do",
|
|
method: 'post',
|
|
data: JSON.stringify(saveData),
|
|
contentType: 'application/json',
|
|
dataType: 'json',
|
|
success: function(data) {
|
|
console.log("저장 응답:", data);
|
|
if(data && data.result === "success") {
|
|
alert("M-BOM이 저장되었습니다.");
|
|
|
|
// 부모 창(M-BOM 목록) 새로고침
|
|
try {
|
|
// window.opener가 있으면 (팝업으로 열린 경우)
|
|
if(window.opener && !window.opener.closed) {
|
|
console.log("window.opener 찾음");
|
|
if(window.opener.fn_search) {
|
|
console.log("window.opener.fn_search 호출");
|
|
window.opener.fn_search();
|
|
} else if(window.opener.location) {
|
|
console.log("window.opener.location.reload 호출");
|
|
window.opener.location.reload();
|
|
}
|
|
}
|
|
// window.top이 현재 창이 아니면 (iframe인 경우)
|
|
else if(window.top !== window.self && window.top.opener && !window.top.opener.closed) {
|
|
console.log("window.top.opener 찾음");
|
|
if(window.top.opener.fn_search) {
|
|
console.log("window.top.opener.fn_search 호출");
|
|
window.top.opener.fn_search();
|
|
} else if(window.top.opener.location) {
|
|
console.log("window.top.opener.location.reload 호출");
|
|
window.top.opener.location.reload();
|
|
}
|
|
}
|
|
} catch(e) {
|
|
console.error("부모 창 새로고침 실패:", e);
|
|
}
|
|
|
|
// 현재 창 닫기
|
|
fn_closeWindow();
|
|
} else {
|
|
alert("M-BOM 저장에 실패했습니다: " + (data.message || ""));
|
|
}
|
|
},
|
|
error: function(jqxhr, status, error){
|
|
console.error("M-BOM 저장 오류:", error);
|
|
console.error("응답:", jqxhr.responseText);
|
|
alert("M-BOM 저장 중 오류가 발생했습니다.");
|
|
}
|
|
});
|
|
}
|
|
|
|
// M-BOM 이력보기
|
|
function fn_showHistory() {
|
|
var projectObjId = "${info.OBJID}";
|
|
|
|
if(!projectObjId) {
|
|
alert("프로젝트 정보가 없습니다.");
|
|
return;
|
|
}
|
|
|
|
// M-BOM 이력 조회 (프로젝트 기준)
|
|
$.ajax({
|
|
url: "/productionplanning/getMbomHistory.do",
|
|
method: 'post',
|
|
data: {
|
|
projectObjId: projectObjId
|
|
},
|
|
dataType: 'json',
|
|
success: function(data) {
|
|
if(data && data.historyList && data.historyList.length > 0) {
|
|
// 이력 상세 분석 및 HTML 생성
|
|
var historyHtml = generateHistoryHtml(data.historyList);
|
|
|
|
// 새 창으로 이력 표시
|
|
var historyWindow = window.open("", "mbomHistory", "width=1400,height=800,scrollbars=yes,resizable=yes");
|
|
historyWindow.document.write("<html><head><title>M-BOM 변경 이력</title>");
|
|
historyWindow.document.write("<style>");
|
|
historyWindow.document.write("body { font-family: Arial, sans-serif; margin: 20px; }");
|
|
historyWindow.document.write("h2 { text-align: center; color: #333; }");
|
|
historyWindow.document.write("table { width: 100%; border-collapse: collapse; margin-bottom: 30px; }");
|
|
historyWindow.document.write("th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }");
|
|
historyWindow.document.write("th { background-color: #4CAF50; color: white; font-weight: bold; }");
|
|
historyWindow.document.write(".history-header { background-color: #f0f0f0; font-weight: bold; }");
|
|
historyWindow.document.write(".change-add { background-color: #e7f4e7; }");
|
|
historyWindow.document.write(".change-delete { background-color: #ffe7e7; }");
|
|
historyWindow.document.write(".change-modify { background-color: #fff4e6; }");
|
|
historyWindow.document.write(".change-bom { background-color: #e6f3ff; }");
|
|
historyWindow.document.write(".field-changed { color: #d9534f; font-weight: bold; }");
|
|
historyWindow.document.write(".section-title { background-color: #5bc0de; color: white; font-weight: bold; text-align: center; }");
|
|
historyWindow.document.write("</style>");
|
|
historyWindow.document.write("</head><body>");
|
|
historyWindow.document.write("<h2>M-BOM 변경 이력</h2>");
|
|
historyWindow.document.write(historyHtml);
|
|
historyWindow.document.write("</body></html>");
|
|
historyWindow.document.close();
|
|
} else {
|
|
alert("이력이 없습니다.");
|
|
}
|
|
},
|
|
error: function(jqxhr, status, error){
|
|
console.error("M-BOM 이력 조회 오류:", error);
|
|
alert("M-BOM 이력 조회 중 오류가 발생했습니다.");
|
|
}
|
|
});
|
|
}
|
|
|
|
// 이력 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 += "<div style='margin-bottom: 40px;'>";
|
|
html += "<h3 style='background-color: #333; color: white; padding: 10px;'>";
|
|
html += "이력 #" + (i + 1) + " - " + changeType + " (" + changeDate + " / " + changeUser + ")";
|
|
html += "</h3>";
|
|
|
|
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 += "<p style='color: red;'>데이터 파싱 오류</p>";
|
|
}
|
|
|
|
html += "</div>";
|
|
}
|
|
|
|
return html;
|
|
}
|
|
|
|
// 생성 이력 테이블 생성
|
|
function generateCreateHistoryTable(afterData) {
|
|
var html = "<table>";
|
|
html += "<tr class='section-title'><td colspan='4'>생성된 M-BOM 정보</td></tr>";
|
|
html += "<tr><th>항목</th><th>값</th><th>항목</th><th>값</th></tr>";
|
|
|
|
// 헤더 정보
|
|
html += "<tr>";
|
|
html += "<td>M-BOM 품번</td><td>" + (afterData.mbomNo || afterData.MBOM_NO || "") + "</td>";
|
|
html += "<td>품번</td><td>" + (afterData.partNo || afterData.PART_NO || "") + "</td>";
|
|
html += "</tr>";
|
|
html += "<tr>";
|
|
html += "<td>품명</td><td>" + (afterData.partName || afterData.PART_NAME || "") + "</td>";
|
|
html += "<td>기준 BOM 유형</td><td>" + (afterData.sourceBomType || afterData.SOURCE_BOM_TYPE || "") + "</td>";
|
|
html += "</tr>";
|
|
|
|
// BOM 상세 항목
|
|
var mbomData = afterData.mbomData || [];
|
|
if(mbomData.length > 0) {
|
|
html += "<tr class='section-title'><td colspan='4'>생성된 BOM 항목 (" + mbomData.length + "개)</td></tr>";
|
|
html += "<tr class='change-add'><th>품번</th><th>품명</th><th>수량</th><th>레벨</th></tr>";
|
|
|
|
for(var i = 0; i < mbomData.length; i++) {
|
|
var item = mbomData[i];
|
|
html += "<tr class='change-add'>";
|
|
html += "<td>" + (item.partNo || "") + "</td>";
|
|
html += "<td>" + (item.partName || "") + "</td>";
|
|
html += "<td>" + (item.qty || "") + "</td>";
|
|
html += "<td>" + (item.level || "") + "</td>";
|
|
html += "</tr>";
|
|
}
|
|
}
|
|
|
|
html += "</table>";
|
|
return html;
|
|
}
|
|
|
|
// 수정 이력 테이블 생성 (새 형식)
|
|
function generateUpdateHistoryTable(beforeData, afterData) {
|
|
var html = "";
|
|
|
|
// beforeData는 이제 변경된 항목 배열
|
|
var changedItems = beforeData;
|
|
|
|
if(!Array.isArray(changedItems) || changedItems.length === 0) {
|
|
return "<p>변경 사항이 없습니다.</p>";
|
|
}
|
|
|
|
html += "<table>";
|
|
html += "<tr class='section-title'><td colspan='4'>변경된 항목 (" + changedItems.length + "개)</td></tr>";
|
|
html += "<tr><th>변경유형</th><th>품번</th><th>품명</th><th>변경 내용</th></tr>";
|
|
|
|
for(var i = 0; i < changedItems.length; i++) {
|
|
var item = changedItems[i];
|
|
var changeType = item.changeType;
|
|
|
|
if(changeType === "ADD") {
|
|
// 추가된 항목
|
|
var afterData = item.afterData || {};
|
|
html += "<tr class='change-add'>";
|
|
html += "<td>추가</td>";
|
|
html += "<td>" + (afterData.partNo || "") + "</td>";
|
|
html += "<td>" + (afterData.partName || "") + "</td>";
|
|
html += "<td>새 항목 추가</td>";
|
|
html += "</tr>";
|
|
} else if(changeType === "DELETE") {
|
|
// 삭제된 항목
|
|
var beforeDataItem = item.beforeData || {};
|
|
html += "<tr class='change-delete'>";
|
|
html += "<td>삭제</td>";
|
|
html += "<td>" + (beforeDataItem.PART_NO || "") + "</td>";
|
|
html += "<td>" + (beforeDataItem.PART_NAME || "") + "</td>";
|
|
html += "<td>항목 삭제</td>";
|
|
html += "</tr>";
|
|
} else if(changeType === "MODIFY") {
|
|
// 수정된 항목
|
|
html += "<tr class='change-modify'>";
|
|
html += "<td>수정</td>";
|
|
html += "<td>" + (item.partNo || "") + "</td>";
|
|
html += "<td>" + (item.partName || "") + "</td>";
|
|
html += "<td>";
|
|
|
|
var fieldChanges = item.fieldChanges || [];
|
|
for(var j = 0; j < fieldChanges.length; j++) {
|
|
var fc = fieldChanges[j];
|
|
var fieldNameKr = getFieldNameKorean(fc.field);
|
|
html += "<strong>" + fieldNameKr + ":</strong> ";
|
|
html += "<span class='before-value'>" + (fc.before || "(없음)") + "</span> → ";
|
|
html += "<span class='after-value'>" + (fc.after || "(없음)") + "</span>";
|
|
if(j < fieldChanges.length - 1) html += "<br>";
|
|
}
|
|
|
|
html += "</td>";
|
|
html += "</tr>";
|
|
}
|
|
}
|
|
|
|
html += "</table>";
|
|
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 += "<table>";
|
|
html += "<tr class='section-title'><td colspan='3'>헤더 정보 변경</td></tr>";
|
|
html += "<tr class='change-bom'><th>항목</th><th>변경 전</th><th>변경 후</th></tr>";
|
|
|
|
for(var i = 0; i < headerChanges.length; i++) {
|
|
var change = headerChanges[i];
|
|
html += "<tr class='change-bom'>";
|
|
html += "<td>" + change.field + "</td>";
|
|
html += "<td>" + change.before + "</td>";
|
|
html += "<td class='field-changed'>" + change.after + "</td>";
|
|
html += "</tr>";
|
|
}
|
|
html += "</table><br>";
|
|
}
|
|
|
|
// 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 += "<table style='font-size: 11px;'>";
|
|
html += "<tr class='section-title'>";
|
|
html += "<th>구분</th>";
|
|
html += "<th>품번</th>";
|
|
html += "<th>품명</th>";
|
|
html += "<th>수량</th>";
|
|
html += "<th>자급/사급</th>";
|
|
html += "<th>소재</th>";
|
|
html += "<th>사이즈</th>";
|
|
html += "<th>소재품번</th>";
|
|
html += "<th>소재소요량</th>";
|
|
html += "<th>가공업체</th>";
|
|
html += "<th>가공납기</th>";
|
|
html += "<th>연삭납기</th>";
|
|
html += "<th>소재발주수량</th>";
|
|
html += "<th>제작수량</th>";
|
|
html += "<th>비고</th>";
|
|
html += "</tr>";
|
|
|
|
// 추가된 항목
|
|
for(var i = 0; i < changes.added.length; i++) {
|
|
var item = changes.added[i];
|
|
html += "<tr class='change-add'>";
|
|
html += "<td>추가</td>";
|
|
html += "<td>" + (item.partNo || "") + "</td>";
|
|
html += "<td>" + (item.partName || "") + "</td>";
|
|
html += "<td>" + (item.qty || "") + "</td>";
|
|
html += "<td>" + (item.supplyType || "") + "</td>";
|
|
html += "<td>" + (item.rawMaterial || "") + "</td>";
|
|
html += "<td>" + (item.rawMaterialSize || "") + "</td>";
|
|
html += "<td>" + (item.rawMaterialPartNo || "") + "</td>";
|
|
html += "<td>" + (item.requiredQty || "") + "</td>";
|
|
html += "<td>" + (item.processingVendor || "") + "</td>";
|
|
html += "<td>" + (item.processingDeadline || "") + "</td>";
|
|
html += "<td>" + (item.grindingDeadline || "") + "</td>";
|
|
html += "<td>" + (item.orderQty || "") + "</td>";
|
|
html += "<td>" + (item.productionQty || "") + "</td>";
|
|
html += "<td>" + (item.remark || "") + "</td>";
|
|
html += "</tr>";
|
|
}
|
|
|
|
// 삭제된 항목
|
|
for(var i = 0; i < changes.deleted.length; i++) {
|
|
var item = changes.deleted[i];
|
|
html += "<tr class='change-delete'>";
|
|
html += "<td>삭제</td>";
|
|
html += "<td>" + (item.partNo || "") + "</td>";
|
|
html += "<td>" + (item.partName || "") + "</td>";
|
|
html += "<td>" + (item.qty || "") + "</td>";
|
|
html += "<td>" + (item.supplyType || "") + "</td>";
|
|
html += "<td>" + (item.rawMaterial || "") + "</td>";
|
|
html += "<td>" + (item.rawMaterialSize || "") + "</td>";
|
|
html += "<td>" + (item.rawMaterialPartNo || "") + "</td>";
|
|
html += "<td>" + (item.requiredQty || "") + "</td>";
|
|
html += "<td>" + (item.processingVendor || "") + "</td>";
|
|
html += "<td>" + (item.processingDeadline || "") + "</td>";
|
|
html += "<td>" + (item.grindingDeadline || "") + "</td>";
|
|
html += "<td>" + (item.orderQty || "") + "</td>";
|
|
html += "<td>" + (item.productionQty || "") + "</td>";
|
|
html += "<td>" + (item.remark || "") + "</td>";
|
|
html += "</tr>";
|
|
}
|
|
|
|
// 수정된 항목 (변경된 필드만 강조)
|
|
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 += "<tr class='change-modify'>";
|
|
html += "<td>수정</td>";
|
|
html += "<td>" + (mod.partNo || "") + "</td>";
|
|
html += "<td>" + (mod.partName || "") + "</td>";
|
|
html += "<td" + (changedFields['qty'] ? " class='field-changed'" : "") + ">" + (mod.after.qty || "") + "</td>";
|
|
html += "<td" + (changedFields['supplyType'] ? " class='field-changed'" : "") + ">" + (mod.after.supplyType || "") + "</td>";
|
|
html += "<td" + (changedFields['rawMaterial'] ? " class='field-changed'" : "") + ">" + (mod.after.rawMaterial || "") + "</td>";
|
|
html += "<td" + (changedFields['rawMaterialSize'] ? " class='field-changed'" : "") + ">" + (mod.after.rawMaterialSize || "") + "</td>";
|
|
html += "<td" + (changedFields['rawMaterialPartNo'] ? " class='field-changed'" : "") + ">" + (mod.after.rawMaterialPartNo || "") + "</td>";
|
|
html += "<td" + (changedFields['requiredQty'] ? " class='field-changed'" : "") + ">" + (mod.after.requiredQty || "") + "</td>";
|
|
html += "<td" + (changedFields['processingVendor'] ? " class='field-changed'" : "") + ">" + (mod.after.processingVendor || "") + "</td>";
|
|
html += "<td" + (changedFields['processingDeadline'] ? " class='field-changed'" : "") + ">" + (mod.after.processingDeadline || "") + "</td>";
|
|
html += "<td" + (changedFields['grindingDeadline'] ? " class='field-changed'" : "") + ">" + (mod.after.grindingDeadline || "") + "</td>";
|
|
html += "<td" + (changedFields['orderQty'] ? " class='field-changed'" : "") + ">" + (mod.after.orderQty || "") + "</td>";
|
|
html += "<td" + (changedFields['productionQty'] ? " class='field-changed'" : "") + ">" + (mod.after.productionQty || "") + "</td>";
|
|
html += "<td" + (changedFields['remark'] ? " class='field-changed'" : "") + ">" + (mod.after.remark || "") + "</td>";
|
|
html += "</tr>";
|
|
}
|
|
|
|
html += "</table>";
|
|
}
|
|
|
|
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;
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<form name="form1" id="form1" action="" method="post">
|
|
<input type="hidden" name="objId" id="objId" value="${param.objId}" />
|
|
<input type="hidden" name="search_quantity" id="search_quantity" value="" />
|
|
|
|
<div id="plmSearchZon">
|
|
<table>
|
|
<tr>
|
|
<td><label for="search_part_no">품번</label></td>
|
|
<td>
|
|
<input type="text" name="search_part_no" id="search_part_no" style="width: 300px;" value="" readonly>
|
|
</td>
|
|
|
|
<td class="label"><label for="search_part_name">품명</label></td>
|
|
<td>
|
|
<input type="text" name="search_part_name" id="search_part_name" style="width: 300px;" value="" readonly>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="search_mbom_part_no">M-BOM 품번</label></td>
|
|
<td>
|
|
<input type="text" name="search_mbom_part_no" id="search_mbom_part_no" style="width: 300px;" value="" readonly>
|
|
</td>
|
|
|
|
<td class="label"><label for="search_save_date">저장일</label></td>
|
|
<td>
|
|
<input type="text" name="search_save_date" id="search_save_date" style="width: 300px;" value="" readonly>
|
|
</td>
|
|
<td style="width: 40px;"></td>
|
|
<td >
|
|
<input type="button" value="이력보기" class="plm_btns" id="btnHistory">
|
|
<input type="button" value="저장" class="plm_btns" id="btnSave">
|
|
<input type="button" value="닫기" class="plm_btns" id="btnClose">
|
|
</td>
|
|
</tr>
|
|
<!-- <tr>
|
|
<td><label for="bulk_processing_deadline">가공납기 일괄</label></td>
|
|
<td>
|
|
<input type="date" name="bulk_processing_deadline" id="bulk_processing_deadline" value="">
|
|
</td>
|
|
|
|
<td class="label"><label for="bulk_grinding_deadline">연삭납기 일괄</label></td>
|
|
<td>
|
|
<input type="date" name="bulk_grinding_deadline" id="bulk_grinding_deadline" value="">
|
|
</td>
|
|
<td style="width: 40px;"></td>
|
|
<td>
|
|
<input type="button" value="일괄 적용" class="plm_btns" id="btnApplyBulkDeadline">
|
|
</td>
|
|
</tr> -->
|
|
</table>
|
|
</div>
|
|
</form>
|
|
|
|
<script>
|
|
|
|
// ==================== M-BOM 전용 파트 추가/삭제/변경 함수 ====================
|
|
|
|
// M-BOM 파트 추가 (그리드에만 반영)
|
|
function fn_mbomAddPart() {
|
|
var rightFrame = parent.frames[1].frames['rightFrame'];
|
|
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
|
|
|
if(rightSelectedRows.length === 0) {
|
|
showConfirm("선택된 파트가 없습니다.");
|
|
return false;
|
|
}
|
|
|
|
var leftFrame = parent.frames[1].frames['leftFrame'];
|
|
var leftPartNoObj = $("input[name=checkedPartNo]:checked", leftFrame.document);
|
|
|
|
var parentObjid = "";
|
|
var parentLevel = 0;
|
|
|
|
if(leftPartNoObj.length > 0) {
|
|
parentObjid = leftPartNoObj.attr("data-CHILD_OBJID");
|
|
parentLevel = parseInt(leftPartNoObj.attr("data-LEVEL") || 0);
|
|
console.log("부모 선택됨:", {
|
|
parentObjid: parentObjid,
|
|
parentLevel: parentLevel,
|
|
partNo: leftPartNoObj.attr("data-PART_NO")
|
|
});
|
|
} else {
|
|
console.log("부모 선택 안됨 - 최상위 레벨에 추가");
|
|
}
|
|
|
|
// 추가할 파트 데이터 준비
|
|
var newParts = [];
|
|
for(var i = 0; i < rightSelectedRows.length; i++){
|
|
var rowData = rightSelectedRows[i].getData();
|
|
|
|
var newPart = {
|
|
OBJID: generateTempId(),
|
|
CHILD_OBJID: generateTempId(),
|
|
PARENT_OBJID: parentObjid,
|
|
LEVEL: parentLevel + 1,
|
|
PART_OBJID: rowData.OBJID,
|
|
PART_NO: rowData.PART_NO,
|
|
PART_NAME: rowData.PART_NAME,
|
|
QTY: 1,
|
|
ITEM_QTY: 1,
|
|
QTY_TEMP: 1,
|
|
UNIT: rowData.UNIT,
|
|
SPEC: rowData.SPEC,
|
|
REVISION: rowData.REVISION,
|
|
SUPPLY_TYPE: '사급',
|
|
STATUS: 'ACTIVE'
|
|
};
|
|
|
|
console.log("추가할 파트:", {
|
|
partNo: newPart.PART_NO,
|
|
parentObjid: newPart.PARENT_OBJID,
|
|
level: newPart.LEVEL
|
|
});
|
|
|
|
newParts.push(newPart);
|
|
}
|
|
|
|
// 왼쪽 프레임의 Tabulator에 추가
|
|
if(leftFrame && leftFrame._tabulGrid) {
|
|
if(parentObjid) {
|
|
// 부모가 선택된 경우: 데이터 배열에 직접 삽입
|
|
var allData = leftFrame._tabulGrid.getData();
|
|
var insertPosition = -1;
|
|
|
|
// 부모 행 찾기
|
|
for(var i = 0; i < allData.length; i++) {
|
|
if(allData[i].CHILD_OBJID == parentObjid) {
|
|
insertPosition = i + 1;
|
|
|
|
// 부모의 모든 하위 항목(자식, 손자, 증손자 등)을 건너뛰기
|
|
for(var j = i + 1; j < allData.length; j++) {
|
|
var rowLevel = allData[j].LEVEL || 1;
|
|
|
|
if(rowLevel > parentLevel) {
|
|
// 부모보다 하위 레벨이면 계속 건너뛰기
|
|
insertPosition = j + 1;
|
|
} else {
|
|
// 같은 레벨이거나 상위 레벨이 나오면 중단
|
|
break;
|
|
}
|
|
}
|
|
|
|
console.log("부모 레벨:", parentLevel, "/ 삽입 위치:", insertPosition);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 삽입 위치에 추가
|
|
if(insertPosition >= 0) {
|
|
console.log("부모 찾음! 삽입 위치:", insertPosition);
|
|
|
|
// 배열에 직접 삽입
|
|
for(var i = newParts.length - 1; i >= 0; i--) {
|
|
allData.splice(insertPosition, 0, newParts[i]);
|
|
}
|
|
|
|
// 전체 데이터 다시 설정
|
|
leftFrame._tabulGrid.setData(allData);
|
|
} else {
|
|
console.log("부모를 못 찾음 - 맨 밑에 추가");
|
|
// 부모를 못 찾으면 맨 밑에 추가
|
|
for(var i = 0; i < newParts.length; i++) {
|
|
leftFrame._tabulGrid.addData([newParts[i]], false);
|
|
}
|
|
}
|
|
} else {
|
|
// 부모가 선택되지 않은 경우: 최상위 레벨 맨 밑에 추가
|
|
for(var i = 0; i < newParts.length; i++) {
|
|
leftFrame._tabulGrid.addData([newParts[i]], false);
|
|
}
|
|
}
|
|
|
|
showConfirm({
|
|
title: '파트 추가',
|
|
text: newParts.length + '개 파트가 추가되었습니다.\n저장 버튼을 눌러 확정하세요.',
|
|
icon: 'success'
|
|
});
|
|
}
|
|
}
|
|
|
|
// M-BOM 파트 삭제 (그리드에서만 제거)
|
|
function fn_mbomDeletePart() {
|
|
var leftFrame = parent.frames[1].frames['leftFrame'];
|
|
var leftPartNoObj = $("input[name=checkedPartNo]:checked", leftFrame.document);
|
|
|
|
if(leftPartNoObj.length === 0) {
|
|
showConfirm("삭제할 파트를 선택해주세요.");
|
|
return;
|
|
}
|
|
|
|
var childObjid = leftPartNoObj.val();
|
|
|
|
showConfirm({
|
|
title: 'Part 삭제',
|
|
text: '선택한 Part를 삭제하시겠습니까?\n(저장 버튼을 눌러야 확정됩니다)',
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#3085d6',
|
|
cancelButtonColor: '#d33',
|
|
confirmButtonText: '삭제',
|
|
cancelButtonText: '취소',
|
|
reverseButtons: false
|
|
}).then(result => {
|
|
if (result.isConfirmed) {
|
|
// Tabulator에서 해당 행 찾아서 삭제
|
|
if(leftFrame && leftFrame._tabulGrid) {
|
|
var rows = leftFrame._tabulGrid.getRows();
|
|
for(var i = 0; i < rows.length; i++) {
|
|
var rowData = rows[i].getData();
|
|
if(rowData.CHILD_OBJID == childObjid) {
|
|
rows[i].delete();
|
|
showConfirm({
|
|
title: '파트 삭제',
|
|
text: '파트가 삭제되었습니다.\n저장 버튼을 눌러 확정하세요.',
|
|
icon: 'success'
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// M-BOM 파트 변경 (그리드에서만 변경)
|
|
function fn_mbomChangePart() {
|
|
var leftFrame = parent.frames[1].frames['leftFrame'];
|
|
var leftPartNoList = $("input[name=checkedPartNo]:checked", leftFrame.document);
|
|
|
|
if(leftPartNoList.length === 0){
|
|
showConfirm("변경할 파트를 선택해주세요.");
|
|
return false;
|
|
}
|
|
|
|
if(leftPartNoList.length > 1){
|
|
showConfirm("한번에 1개의 파트만 변경가능합니다.");
|
|
return false;
|
|
}
|
|
|
|
var rightFrame = parent.frames[1].frames['rightFrame'];
|
|
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
|
|
|
if(rightSelectedRows.length === 0){
|
|
showConfirm("변경할 새 파트를 선택해주세요.");
|
|
return false;
|
|
}
|
|
|
|
if(rightSelectedRows.length > 1){
|
|
showConfirm("한번에 1개의 파트만 변경가능합니다.");
|
|
return false;
|
|
}
|
|
|
|
var leftPartNo = leftPartNoList.attr("data-PART_NO");
|
|
var leftChildObjid = leftPartNoList.val();
|
|
|
|
var rightRowData = rightSelectedRows[0].getData();
|
|
var rightPartNo = rightRowData.PART_NO;
|
|
var rightPartName = rightRowData.PART_NAME;
|
|
var rightObjId = rightRowData.OBJID;
|
|
var rightRevision = rightRowData.REVISION || "";
|
|
|
|
showConfirm({
|
|
title: 'Part 변경',
|
|
html: '선택한 Part를 변경하시겠습니까?<br><br>' +
|
|
'<strong>기존:</strong> ' + leftPartNo + '<br>' +
|
|
'<strong>변경:</strong> ' + rightPartNo,
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#3085d6',
|
|
cancelButtonColor: '#d33',
|
|
confirmButtonText: '변경',
|
|
cancelButtonText: '취소',
|
|
reverseButtons: false
|
|
}).then(result => {
|
|
if (result.isConfirmed) {
|
|
// Tabulator에서 해당 행 찾아서 업데이트
|
|
if(leftFrame && leftFrame._tabulGrid) {
|
|
var rows = leftFrame._tabulGrid.getRows();
|
|
for(var i = 0; i < rows.length; i++) {
|
|
var rowData = rows[i].getData();
|
|
if(rowData.CHILD_OBJID == leftChildObjid) {
|
|
rows[i].update({
|
|
PART_OBJID: rightObjId,
|
|
PART_NO: rightPartNo,
|
|
PART_NAME: rightPartName,
|
|
REVISION: rightRevision
|
|
});
|
|
showConfirm({
|
|
title: '파트 변경',
|
|
text: '파트가 변경되었습니다.\n저장 버튼을 눌러 확정하세요.',
|
|
icon: 'success'
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// 임시 ID 생성 (음수 사용)
|
|
function generateTempId() {
|
|
return -Math.floor(Math.random() * 1000000000);
|
|
}
|
|
|
|
// 창 닫기 함수 (프레임 구조 고려)
|
|
function fn_closeWindow() {
|
|
try {
|
|
// 최상위 창(frameset)을 닫기
|
|
if(window.top && window.top.opener) {
|
|
// 팝업으로 열린 경우
|
|
window.top.close();
|
|
} else if(window.parent && window.parent !== window) {
|
|
// 프레임 내부인 경우 최상위 창 닫기 시도
|
|
window.top.close();
|
|
} else {
|
|
// 일반 창인 경우
|
|
window.close();
|
|
}
|
|
} catch(e) {
|
|
console.error("창 닫기 오류:", e);
|
|
// 오류 발생 시 강제로 닫기 시도
|
|
window.top.close();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
</body>
|
|
</html> |