diff --git a/WebContent/WEB-INF/classes/com/pms/mapper/quality.xml b/WebContent/WEB-INF/classes/com/pms/mapper/quality.xml
index 5179bf6..1028007 100644
--- a/WebContent/WEB-INF/classes/com/pms/mapper/quality.xml
+++ b/WebContent/WEB-INF/classes/com/pms/mapper/quality.xml
@@ -1582,6 +1582,7 @@
, COALESCE(SPI.REMARK, '') AS "REMARK"
, SPI.DATA_TYPE AS "DATA_TYPE"
, COALESCE(SPI.INSPECTION_GROUP_ID, '') AS "INSPECTION_GROUP_ID"
+ , COALESCE(SPI.IS_LOCKED, 'N') AS "IS_LOCKED"
, (SELECT COUNT(*) FROM ATTACH_FILE_INFO AFI WHERE AFI.TARGET_OBJID = SPI.OBJID AND AFI.DOC_TYPE = 'SEMI_INSPECTION_IMAGE' AND AFI.STATUS = 'Active') AS "IMAGE_FILE_CNT"
, (SELECT COUNT(*) FROM ATTACH_FILE_INFO AFI WHERE AFI.TARGET_OBJID = SPI.OBJID AND AFI.DOC_TYPE = 'SEMI_INSPECTION_NCR' AND AFI.STATUS = 'Active') AS "NCR_FILE_CNT"
@@ -1722,6 +1723,19 @@
WHERE OBJID = #{OBJID}
+
+
+ UPDATE PMS_QUALITY_SEMI_PRODUCT_INSPECTION
+ SET IS_LOCKED = 'Y'
+ WHERE OBJID = #{OBJID}
+
+
+
+
+ DELETE FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION
+ WHERE OBJID = #{OBJID}
+
+
DELETE FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION
@@ -1734,6 +1748,19 @@
+
+
+ DELETE FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION
+ WHERE INSPECTION_GROUP_ID = #{INSPECTION_GROUP_ID}
+ AND DATA_TYPE = #{DATA_TYPE}
+
+ AND OBJID NOT IN
+
+ #{objId}
+
+
+
+
diff --git a/WebContent/WEB-INF/view/quality/semiProductInspectionFormPopUp.jsp b/WebContent/WEB-INF/view/quality/semiProductInspectionFormPopUp.jsp
index ca3445d..4aac99e 100644
--- a/WebContent/WEB-INF/view/quality/semiProductInspectionFormPopUp.jsp
+++ b/WebContent/WEB-INF/view/quality/semiProductInspectionFormPopUp.jsp
@@ -232,6 +232,7 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
+
@@ -246,6 +247,7 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
+
@@ -311,7 +313,9 @@ $(document).ready(function(){
}
// 버튼 이벤트
- $("#btnSave").click(fn_save);
+ $("#btnSave").click(fn_save); // 하단 저장: 전체 DB 저장
+ $("#btnSaveLeft").click(fn_saveSelectedLeft); // 좌측 저장: UI 잠금만 (DB 저장 X)
+ $("#btnSaveRight").click(fn_saveSelectedRight); // 우측 저장: UI 잠금만 (DB 저장 X)
$("#btnClose").click(function(){ window.close(); });
$("#btnAddLeft").click(fn_addLeftRow);
$("#btnDelLeft").click(fn_delLeftRow);
@@ -393,6 +397,11 @@ function createSelect2Editor(options, allowClear) {
};
}
+// 저장된 행인지 확인하는 함수 (편집 가능 여부 결정)
+function isEditable(cell){
+ return !cell.getRow().getData().IS_SAVED;
+}
+
// =====================================================
// 좌측 그리드 (양품 정보) 초기화
// =====================================================
@@ -400,14 +409,19 @@ function fn_initLeftGrid(){
var columns = [
{formatter:"rowSelection", titleFormatter:"rowSelection", hozAlign:"center", headerSort:false, width:30},
{title:"품명(모델명)", field:"MODEL_NAME", minWidth:120, headerSort:false,
- editor: createSelect2Editor(modelNameList)
+ editor: createSelect2Editor(modelNameList),
+ editable: isEditable
},
{title:"제품구분", field:"PRODUCT_TYPE", minWidth:80, headerSort:false,
- editor: createSelect2Editor(productTypeList)
+ editor: createSelect2Editor(productTypeList),
+ editable: isEditable
+ },
+ {title:"작업지시번호", field:"WORK_ORDER_NO", editor:"input", minWidth:100, headerSort:false,
+ editable: isEditable
},
- {title:"작업지시번호", field:"WORK_ORDER_NO", editor:"input", minWidth:100, headerSort:false},
{title:"부품품번", field:"PART_NO", minWidth:100, headerSort:false,
editor: createSelect2Editor(partNoList),
+ editable: isEditable,
cellEdited: function(cell){
var partNo = cell.getValue();
if(partNo){
@@ -423,6 +437,7 @@ function fn_initLeftGrid(){
},
{title:"부품명", field:"PART_NAME", minWidth:120, headerSort:false,
editor: createSelect2Editor(partNameList),
+ editable: isEditable,
cellEdited: function(cell){
var partName = cell.getValue();
if(partName){
@@ -438,6 +453,7 @@ function fn_initLeftGrid(){
},
{title:"입고수량", field:"RECEIPT_QTY", editor:"number", hozAlign:"right", minWidth:70, headerSort:false,
editorParams:{min:0, step:1},
+ editable: isEditable,
formatter: function(cell){
var val = cell.getValue();
return (val !== null && val !== undefined && val !== "") ? Number(val).toLocaleString() : "0";
@@ -445,6 +461,7 @@ function fn_initLeftGrid(){
},
{title:"양품수량", field:"GOOD_QTY", editor:"number", hozAlign:"right", minWidth:70, headerSort:false,
editorParams:{min:0, step:1},
+ editable: isEditable,
formatter: function(cell){
var val = cell.getValue();
return (val !== null && val !== undefined && val !== "") ? Number(val).toLocaleString() : "0";
@@ -458,7 +475,14 @@ function fn_initLeftGrid(){
columns: columns,
data: [],
placeholder: "행을 추가해주세요.",
- selectable: 1 // 단일 선택
+ selectable: 1, // 단일 선택
+ // 저장된 행 시각적 표시
+ rowFormatter: function(row){
+ if(row.getData().IS_SAVED){
+ row.getElement().style.backgroundColor = "#e8f5e9"; // 연한 초록색
+ row.getElement().style.color = "#555";
+ }
+ }
});
// 행 선택 이벤트 - 해당 행의 불량 정보를 우측에 표시
@@ -493,65 +517,72 @@ function fn_initRightGrid(){
{formatter:"rowSelection", titleFormatter:"rowSelection", hozAlign:"center", headerSort:false, width:30},
{title:"불량수량", field:"DEFECT_QTY", editor:"number", hozAlign:"right", minWidth:70, headerSort:false,
editorParams:{min:0, step:1},
+ editable: isEditable,
formatter: function(cell){
var val = cell.getValue();
return (val !== null && val !== undefined && val !== "") ? Number(val).toLocaleString() : "0";
}
},
{title:"불량유형", field:"DEFECT_TYPE", minWidth:85, headerSort:false,
- editor: createSelect2Editor(defectTypeList)
+ editor: createSelect2Editor(defectTypeList),
+ editable: isEditable
},
{title:"불량원인", field:"DEFECT_CAUSE", minWidth:90, headerSort:false,
- editor: createSelect2Editor(defectCauseList)
+ editor: createSelect2Editor(defectCauseList),
+ editable: isEditable
},
{title:"귀책부서", field:"RESPONSIBLE_DEPT", minWidth:80, headerSort:false,
- editor: createSelect2Editor(responsibleDeptList)
+ editor: createSelect2Editor(responsibleDeptList),
+ editable: isEditable
},
{title:"부적합보고서", field:"NCR_FILE_CNT", minWidth:75, headerSort:false, hozAlign:"center",
formatter: fnc_subInfoValueFormatter,
cellClick: function(e, cell){
var objId = fnc_checkNull(cell.getData().OBJID);
- if(objId && !objId.startsWith("DEFECT_")){
+ if(objId){
fn_openNCRFilePopUp(objId);
} else {
- Swal.fire({icon:'info', title:'알림', text:'먼저 저장 후 파일을 등록할 수 있습니다.'});
+ Swal.fire({icon:'info', title:'알림', text:'행을 추가한 후 파일을 등록할 수 있습니다.'});
}
}
},
{title:"처리현황", field:"PROCESS_STATUS", minWidth:75, headerSort:false,
- editor: createSelect2Editor(processStatusList)
+ editor: createSelect2Editor(processStatusList),
+ editable: isEditable
},
{title:"이미지", field:"IMAGE_FILE_CNT", minWidth:60, headerSort:false, hozAlign:"center",
formatter: fnc_subInfoValueFormatter,
cellClick: function(e, cell){
var objId = fnc_checkNull(cell.getData().OBJID);
- if(objId && !objId.startsWith("DEFECT_")){
+ if(objId){
fn_openImageFilePopUp(objId);
} else {
- Swal.fire({icon:'info', title:'알림', text:'먼저 저장 후 이미지를 등록할 수 있습니다.'});
+ Swal.fire({icon:'info', title:'알림', text:'행을 추가한 후 이미지를 등록할 수 있습니다.'});
}
}
},
{title:"검사일", field:"INSPECTION_DATE", minWidth:100, headerSort:false,
editor: "input",
- editorParams: { elementAttributes: { type: "date" } }
+ editorParams: { elementAttributes: { type: "date" } },
+ editable: isEditable
},
- {title:"검사자", field:"INSPECTOR", editor:"input", minWidth:70, headerSort:false},
+ {title:"검사자", field:"INSPECTOR", editor:"input", minWidth:70, headerSort:false, editable: isEditable},
{title:"처리결과", field:"DISPOSITION_TYPE", minWidth:75, headerSort:false,
- editor: createSelect2Editor(dispositionTypeList)
+ editor: createSelect2Editor(dispositionTypeList),
+ editable: isEditable
},
{title:"검사성적서", field:"REPORT_FILE_CNT", minWidth:70, headerSort:false, hozAlign:"center",
formatter: fnc_subInfoValueFormatter,
cellClick: function(e, cell){
var objId = fnc_checkNull(cell.getData().OBJID);
- if(objId && !objId.startsWith("DEFECT_")){
+ if(objId){
fn_openReportFilePopUp(objId);
} else {
- Swal.fire({icon:'info', title:'알림', text:'먼저 저장 후 파일을 등록할 수 있습니다.'});
+ Swal.fire({icon:'info', title:'알림', text:'행을 추가한 후 파일을 등록할 수 있습니다.'});
}
}
},
- {title:"비고", field:"REMARK", editor:"input", minWidth:100, headerSort:false}
+ {title:"비고", field:"REMARK", editor:"input", minWidth:100, headerSort:false, editable: isEditable}
];
rightGrid = new Tabulator("#rightGrid", {
@@ -560,7 +591,14 @@ function fn_initRightGrid(){
columns: columns,
data: [],
placeholder: "좌측에서 양품 정보를 선택하세요.",
- selectable: true
+ selectable: true,
+ // 저장된 행 시각적 표시
+ rowFormatter: function(row){
+ if(row.getData().IS_SAVED){
+ row.getElement().style.backgroundColor = "#e8f5e9"; // 연한 초록색
+ row.getElement().style.color = "#555";
+ }
+ }
});
}
@@ -608,22 +646,38 @@ function fn_clearRightGrid(){
// 좌측 그리드 행 추가
// =====================================================
function fn_addLeftRow(){
- rowSeq++;
- var newRowId = "NEW_" + rowSeq;
-
- leftGrid.addRow({
- ROW_ID: newRowId,
- MODEL_NAME: "",
- PRODUCT_TYPE: "",
- WORK_ORDER_NO: "",
- PART_NO: "",
- PART_NAME: "",
- RECEIPT_QTY: 0,
- GOOD_QTY: 0
+ // 서버에서 OBJID 미리 생성
+ $.ajax({
+ url: "/quality/generateObjId.do",
+ type: "POST",
+ async: false,
+ dataType: "json",
+ success: function(result){
+ if(result.result){
+ rowSeq++;
+ var newObjId = result.OBJID;
+
+ leftGrid.addRow({
+ ROW_ID: newObjId, // OBJID를 ROW_ID로 사용
+ OBJID: newObjId, // 서버에서 생성한 실제 OBJID
+ MODEL_NAME: "",
+ PRODUCT_TYPE: "",
+ WORK_ORDER_NO: "",
+ PART_NO: "",
+ PART_NAME: "",
+ RECEIPT_QTY: 0,
+ GOOD_QTY: 0
+ });
+
+ // 새 행에 대한 불량 데이터 배열 초기화
+ allDefectData[newObjId] = [];
+ }
+ },
+ error: function(xhr, status, error){
+ console.error("OBJID 생성 실패:", error);
+ Swal.fire({ icon: 'error', title: '오류', text: 'OBJID 생성에 실패했습니다.' });
+ }
});
-
- // 새 행에 대한 불량 데이터 배열 초기화
- allDefectData[newRowId] = [];
}
// 좌측 그리드 행 삭제
@@ -645,13 +699,54 @@ function fn_delLeftRow(){
cancelButtonText: '취소'
}).then(function(result){
if(result.isConfirmed){
+ var objIdsToDelete = [];
+
selectedRows.forEach(function(row){
- var rowId = row.getData().ROW_ID;
- // 해당 행의 불량 데이터도 삭제
- delete allDefectData[rowId];
+ var rowData = row.getData();
+ var rowId = rowData.ROW_ID;
+ var objId = rowData.OBJID;
+
+ // DB에 저장된 데이터면 삭제 목록에 추가
+ if(objId && !String(objId).startsWith("NEW_")){
+ objIdsToDelete.push(objId);
+ }
+
+ // 해당 행의 불량 데이터도 삭제 목록에 추가
+ if(allDefectData[rowId]){
+ allDefectData[rowId].forEach(function(defect){
+ if(defect.OBJID && !String(defect.OBJID).startsWith("DEFECT_")){
+ objIdsToDelete.push(defect.OBJID);
+ }
+ });
+ delete allDefectData[rowId];
+ }
+
row.delete();
});
+ // DB에서 삭제
+ if(objIdsToDelete.length > 0){
+ $.ajax({
+ url: "/quality/deleteSemiProductInspection.do",
+ type: "POST",
+ data: { objIds: JSON.stringify(objIdsToDelete) },
+ dataType: "json",
+ success: function(result){
+ if(result.result){
+ console.log("DB 삭제 완료:", objIdsToDelete.length + "건");
+ if(window.opener && window.opener.fn_search){
+ window.opener.fn_search();
+ }
+ } else {
+ console.error("DB 삭제 실패:", result.msg);
+ }
+ },
+ error: function(xhr, status, error){
+ console.error("삭제 오류:", error);
+ }
+ });
+ }
+
// 우측 그리드 초기화
selectedLeftRowId = null;
selectedLeftRowData = null;
@@ -669,22 +764,39 @@ function fn_addRightRow(){
return;
}
- rowSeq++;
- rightGrid.addRow({
- ROW_ID: "DEFECT_" + rowSeq,
- PARENT_ROW_ID: selectedLeftRowId, // 부모(좌측) 행 ID 연결
- DEFECT_QTY: 0,
- DEFECT_TYPE: "",
- DEFECT_CAUSE: "",
- RESPONSIBLE_DEPT: "",
- NCR_FILE_CNT: 0,
- PROCESS_STATUS: "",
- IMAGE_FILE_CNT: 0,
- INSPECTION_DATE: today,
- INSPECTOR: loginUserName,
- DISPOSITION_TYPE: "",
- REPORT_FILE_CNT: 0,
- REMARK: ""
+ // 서버에서 OBJID 미리 생성 (첨부파일 등록을 위해)
+ $.ajax({
+ url: "/quality/generateObjId.do",
+ type: "POST",
+ async: false,
+ dataType: "json",
+ success: function(result){
+ if(result.result){
+ rowSeq++;
+ rightGrid.addRow({
+ OBJID: result.OBJID, // 서버에서 생성한 실제 OBJID
+ ROW_ID: result.OBJID, // ROW_ID도 동일하게
+ PARENT_ROW_ID: selectedLeftRowId,
+ DEFECT_QTY: 0,
+ DEFECT_TYPE: "",
+ DEFECT_CAUSE: "",
+ RESPONSIBLE_DEPT: "",
+ NCR_FILE_CNT: 0,
+ PROCESS_STATUS: "",
+ IMAGE_FILE_CNT: 0,
+ INSPECTION_DATE: today,
+ INSPECTOR: loginUserName,
+ DISPOSITION_TYPE: "",
+ REPORT_FILE_CNT: 0,
+ REMARK: ""
+ });
+ } else {
+ Swal.fire({icon:'error', title:'오류', text:'행 추가 중 오류가 발생했습니다.'});
+ }
+ },
+ error: function(){
+ Swal.fire({icon:'error', title:'오류', text:'서버 통신 오류가 발생했습니다.'});
+ }
});
}
@@ -695,8 +807,52 @@ function fn_delRightRow(){
Swal.fire("삭제할 행을 선택해주세요.");
return;
}
- selectedRows.forEach(function(row){
- row.delete();
+
+ Swal.fire({
+ title: '삭제 확인',
+ text: '선택한 불량 정보를 삭제하시겠습니까?',
+ icon: 'warning',
+ showCancelButton: true,
+ confirmButtonColor: '#d33',
+ cancelButtonColor: '#3085d6',
+ confirmButtonText: '삭제',
+ cancelButtonText: '취소'
+ }).then(function(result){
+ if(result.isConfirmed){
+ var objIdsToDelete = [];
+
+ selectedRows.forEach(function(row){
+ var objId = row.getData().OBJID;
+ // DB에 저장된 데이터면 삭제 목록에 추가
+ if(objId && !String(objId).startsWith("DEFECT_")){
+ objIdsToDelete.push(objId);
+ }
+ row.delete();
+ });
+
+ // DB에서 삭제
+ if(objIdsToDelete.length > 0){
+ $.ajax({
+ url: "/quality/deleteSemiProductInspection.do",
+ type: "POST",
+ data: { objIds: JSON.stringify(objIdsToDelete) },
+ dataType: "json",
+ success: function(result){
+ if(result.result){
+ console.log("DB 삭제 완료:", objIdsToDelete.length + "건");
+ if(window.opener && window.opener.fn_search){
+ window.opener.fn_search();
+ }
+ } else {
+ console.error("DB 삭제 실패:", result.msg);
+ }
+ },
+ error: function(xhr, status, error){
+ console.error("삭제 오류:", error);
+ }
+ });
+ }
+ }
});
}
@@ -730,6 +886,7 @@ function fn_openReportFilePopUp(objId) {
fn_watchPopupClose(popup, objId, 'REPORT_FILE_CNT', 'SEMI_INSPECTION_REPORT');
}
+
// 팝업 닫힘 감지 및 파일 카운트 업데이트
function fn_watchPopupClose(popup, objId, fieldName, docType) {
var checkPopup = setInterval(function() {
@@ -801,9 +958,11 @@ function fn_loadData(objid, inspectionGroupId){
console.log("수정 모드 - INSPECTION_GROUP_ID:", currentInspectionGroupId);
}
- // 좌측 데이터에 ROW_ID 부여
+ // 좌측 데이터에 ROW_ID 부여 + IS_LOCKED='Y'인 행만 수정 불가
result.leftData.forEach(function(item, idx){
if(!item.ROW_ID) item.ROW_ID = item.OBJID || ("EXIST_" + (idx + 1));
+ // IS_LOCKED='Y'인 행만 수정 불가 (IS_SAVED=true)
+ item.IS_SAVED = (item.IS_LOCKED == 'Y');
rowSeq = Math.max(rowSeq, idx + 1);
});
leftGrid.setData(result.leftData);
@@ -824,6 +983,8 @@ function fn_loadData(objid, inspectionGroupId){
if(!allDefectData[parentId]) allDefectData[parentId] = [];
defect.PARENT_ROW_ID = parentId;
+ // IS_LOCKED='Y'인 행만 수정 불가 (IS_SAVED=true)
+ defect.IS_SAVED = (defect.IS_LOCKED == 'Y');
allDefectData[parentId].push(defect);
});
}
@@ -838,34 +999,124 @@ function fn_loadData(objid, inspectionGroupId){
}
// =====================================================
-// 저장
+// 좌측 행 잠금: 선택된 양품 행을 수정 불가로 변경 (DB에 잠금 상태 저장)
// =====================================================
-function fn_save(){
- // 현재 우측 데이터 저장
- fn_saveRightGridData();
-
- var leftData = leftGrid.getData();
-
- if(leftData.length == 0){
- Swal.fire({ icon: 'warning', title: '알림', text: '저장할 양품 정보가 없습니다.' });
+function fn_saveSelectedLeft(){
+ if(!selectedLeftRowId){
+ Swal.fire({ icon: 'warning', title: '알림', text: '잠금할 양품 정보를 선택해주세요.' });
return;
}
- // 모든 불량 데이터 수집
- var rightData = [];
- Object.keys(allDefectData).forEach(function(leftRowId){
- var defects = allDefectData[leftRowId] || [];
- defects.forEach(function(defect){
- defect.PARENT_ROW_ID = leftRowId;
- rightData.push(defect);
- });
+ // 선택된 좌측 행
+ var selectedRow = leftGrid.getSelectedRows()[0];
+ if(!selectedRow){
+ Swal.fire({ icon: 'warning', title: '알림', text: '잠금할 양품 정보를 선택해주세요.' });
+ return;
+ }
+
+ var rowData = selectedRow.getData();
+ var objId = rowData.OBJID;
+
+ // 아직 DB에 저장되지 않은 행은 잠금 불가
+ if(!objId || String(objId).startsWith("NEW_")){
+ Swal.fire({ icon: 'warning', title: '알림', text: '먼저 하단 저장 버튼을 눌러 DB에 저장한 후 잠금할 수 있습니다.' });
+ return;
+ }
+
+ // DB에 잠금 요청
+ $.ajax({
+ url: "/quality/lockSemiProductInspection.do",
+ type: "POST",
+ data: { objIds: JSON.stringify([objId]) },
+ dataType: "json",
+ success: function(result){
+ if(result.result){
+ // UI에서도 수정 불가 처리
+ selectedRow.update({ IS_SAVED: true, IS_LOCKED: 'Y' });
+ Swal.fire({ icon: 'success', title: '완료', text: '양품 정보가 잠금 처리되었습니다.' });
+ } else {
+ Swal.fire({ icon: 'error', title: '오류', text: result.msg || '잠금 처리에 실패했습니다.' });
+ }
+ },
+ error: function(xhr, status, error){
+ Swal.fire({ icon: 'error', title: '오류', text: '잠금 처리 중 오류가 발생했습니다.' });
+ }
+ });
+}
+
+// =====================================================
+// 우측 행 잠금: 선택된 불량 행을 수정 불가로 변경 (DB에 잠금 상태 저장)
+// =====================================================
+function fn_saveSelectedRight(){
+ if(!selectedLeftRowId){
+ Swal.fire({ icon: 'warning', title: '알림', text: '좌측에서 양품 정보를 먼저 선택해주세요.' });
+ return;
+ }
+
+ // 선택된 우측 행만 가져오기
+ var selectedRightRows = rightGrid.getSelectedRows();
+
+ if(selectedRightRows.length == 0){
+ Swal.fire({ icon: 'warning', title: '알림', text: '잠금할 불량 정보를 선택해주세요.' });
+ return;
+ }
+
+ // DB에 저장된 행만 잠금 가능
+ var objIdsToLock = [];
+ var unsavedCount = 0;
+ selectedRightRows.forEach(function(row){
+ var objId = row.getData().OBJID;
+ if(objId && !String(objId).startsWith("DEFECT_") && !String(objId).startsWith("NEW_")){
+ objIdsToLock.push(objId);
+ } else {
+ unsavedCount++;
+ }
});
- // 저장 확인
+ if(unsavedCount > 0){
+ Swal.fire({ icon: 'warning', title: '알림', text: '아직 DB에 저장되지 않은 행이 ' + unsavedCount + '건 있습니다. 먼저 하단 저장 버튼을 눌러 저장해주세요.' });
+ return;
+ }
+
+ if(objIdsToLock.length == 0){
+ Swal.fire({ icon: 'warning', title: '알림', text: '잠금할 행이 없습니다.' });
+ return;
+ }
+
+ // DB에 잠금 요청
+ $.ajax({
+ url: "/quality/lockSemiProductInspection.do",
+ type: "POST",
+ data: { objIds: JSON.stringify(objIdsToLock) },
+ dataType: "json",
+ success: function(result){
+ if(result.result){
+ // UI에서도 수정 불가 처리
+ selectedRightRows.forEach(function(row){
+ row.update({ IS_SAVED: true, IS_LOCKED: 'Y' });
+ });
+ Swal.fire({ icon: 'success', title: '완료', text: '불량 정보 ' + objIdsToLock.length + '건이 잠금 처리되었습니다.' });
+ } else {
+ Swal.fire({ icon: 'error', title: '오류', text: result.msg || '잠금 처리에 실패했습니다.' });
+ }
+ },
+ error: function(xhr, status, error){
+ Swal.fire({ icon: 'error', title: '오류', text: '잠금 처리 중 오류가 발생했습니다.' });
+ }
+ });
+}
+
+// =====================================================
+// 실제 저장 실행 함수
+// saveType: 'left' (좌측만), 'right' (우측만), 'all' (전체)
+// =====================================================
+function fn_doSave(leftData, rightData, confirmMsg, saveType){
+ saveType = saveType || 'all'; // 기본값은 전체 저장
+
Swal.fire({
icon: 'question',
title: '저장 확인',
- text: '양품 ' + leftData.length + '건, 불량 ' + rightData.length + '건을 저장하시겠습니까?',
+ text: confirmMsg,
showCancelButton: true,
confirmButtonText: '저장',
cancelButtonText: '취소'
@@ -874,7 +1125,8 @@ function fn_save(){
var paramData = {
leftData: JSON.stringify(leftData),
rightData: JSON.stringify(rightData),
- INSPECTION_GROUP_ID: currentInspectionGroupId || "" // 수정 모드일 때 기존 그룹 ID 전달
+ INSPECTION_GROUP_ID: currentInspectionGroupId || "",
+ saveType: saveType // 저장 타입 추가
};
$.ajax({
@@ -884,15 +1136,23 @@ function fn_save(){
dataType: "json",
success: function(result){
if(result.result == true || result.result == "true"){
+ // 저장된 INSPECTION_GROUP_ID 유지 (다음 저장 시 같은 그룹으로 저장)
+ if(result.inspectionGroupId){
+ currentInspectionGroupId = result.inspectionGroupId;
+ console.log("INSPECTION_GROUP_ID 설정:", currentInspectionGroupId);
+ }
+
Swal.fire({
icon: 'success',
title: '저장 완료',
text: '저장되었습니다.'
}).then(function(){
+ // 부모 창 새로고침
if(window.opener && window.opener.fn_search){
window.opener.fn_search();
}
- window.close();
+ // 데이터 다시 로드 (OBJID 동기화를 위해)
+ fn_loadData('', currentInspectionGroupId);
});
} else {
Swal.fire({
@@ -913,6 +1173,149 @@ function fn_save(){
}
});
}
+
+// 저장된 행을 읽기 전용으로 마킹하는 함수
+function fn_markAsSaved(savedLeftData, savedRightData){
+ // 좌측 그리드 행 업데이트
+ if(savedLeftData && savedLeftData.length > 0){
+ savedLeftData.forEach(function(leftItem){
+ var rowId = leftItem.ROW_ID;
+ var rows = leftGrid.getRows();
+ rows.forEach(function(row){
+ if(row.getData().ROW_ID === rowId){
+ row.update({ IS_SAVED: true });
+ }
+ });
+ });
+ }
+
+ // 우측 그리드 행 업데이트 (현재 표시된 데이터)
+ if(savedRightData && savedRightData.length > 0){
+ savedRightData.forEach(function(rightItem){
+ var objId = rightItem.OBJID;
+ var rows = rightGrid.getRows();
+ rows.forEach(function(row){
+ if(row.getData().OBJID === objId || row.getData().ROW_ID === rightItem.ROW_ID){
+ row.update({ IS_SAVED: true });
+ }
+ });
+
+ // allDefectData에도 IS_SAVED 설정
+ var parentId = rightItem.PARENT_ROW_ID;
+ if(parentId && allDefectData[parentId]){
+ allDefectData[parentId].forEach(function(defect){
+ if(defect.OBJID === objId || defect.ROW_ID === rightItem.ROW_ID){
+ defect.IS_SAVED = true;
+ }
+ });
+ }
+ });
+ }
+}
+
+// =====================================================
+// 전체 저장
+// =====================================================
+function fn_save(){
+ try {
+ console.log("fn_save 시작");
+
+ // 현재 선택된 좌측 행이 있으면 우측 데이터를 allDefectData에 저장
+ if(selectedLeftRowId){
+ var currentRightData = rightGrid.getData();
+ allDefectData[selectedLeftRowId] = currentRightData;
+ console.log("현재 우측 그리드 데이터 저장:", selectedLeftRowId, currentRightData.length + "건");
+ }
+
+ var leftData = leftGrid.getData();
+ console.log("좌측 데이터 수:", leftData.length);
+
+ if(leftData.length == 0){
+ Swal.fire({ icon: 'warning', title: '알림', text: '저장할 양품 정보가 없습니다.' });
+ return;
+ }
+
+ // 모든 불량 데이터 수집 (allDefectData에서)
+ var rightData = [];
+ Object.keys(allDefectData).forEach(function(leftRowId){
+ var defects = allDefectData[leftRowId] || [];
+ defects.forEach(function(defect){
+ defect.PARENT_ROW_ID = leftRowId;
+ // 좌측 데이터에서 부모 정보 찾아서 복사
+ var parentLeft = leftData.find(function(l){ return l.ROW_ID == leftRowId; });
+ if(parentLeft){
+ defect.MODEL_NAME = parentLeft.MODEL_NAME || '';
+ defect.PRODUCT_TYPE = parentLeft.PRODUCT_TYPE || '';
+ defect.WORK_ORDER_NO = parentLeft.WORK_ORDER_NO || '';
+ defect.PART_NO = parentLeft.PART_NO || '';
+ defect.PART_NAME = parentLeft.PART_NAME || '';
+ }
+ rightData.push(defect);
+ });
+ });
+ console.log("우측 데이터 수:", rightData.length);
+
+ // 바로 저장 실행 (확인 팝업 생략)
+ console.log("저장 시작 - currentInspectionGroupId:", currentInspectionGroupId);
+ console.log("좌측 데이터:", leftData);
+ console.log("우측 데이터:", rightData);
+
+ var paramData = {
+ leftData: JSON.stringify(leftData),
+ rightData: JSON.stringify(rightData),
+ INSPECTION_GROUP_ID: currentInspectionGroupId || "",
+ saveType: "all"
+ };
+
+ $.ajax({
+ url: "/quality/saveSemiProductInspection.do",
+ type: "POST",
+ data: paramData,
+ dataType: "json",
+ success: function(result){
+ console.log("저장 결과:", result);
+ if(result.result == true || result.result == "true"){
+ // 저장된 INSPECTION_GROUP_ID 유지
+ if(result.inspectionGroupId){
+ currentInspectionGroupId = result.inspectionGroupId;
+ console.log("INSPECTION_GROUP_ID 설정:", currentInspectionGroupId);
+ }
+
+ // 저장된 행에 IS_SAVED 플래그 설정
+ fn_markAsSaved(leftData, rightData);
+
+ Swal.fire({
+ icon: 'success',
+ title: '저장 완료',
+ text: '저장되었습니다.'
+ }).then(function(){
+ if(window.opener && window.opener.fn_search){
+ window.opener.fn_search();
+ }
+ window.close();
+ });
+ } else {
+ Swal.fire({
+ icon: 'error',
+ title: '저장 실패',
+ text: result.msg || '저장에 실패했습니다.'
+ });
+ }
+ },
+ error: function(xhr, status, error){
+ console.error("AJAX 오류:", error);
+ Swal.fire({
+ icon: 'error',
+ title: '오류 발생',
+ text: '저장 중 오류가 발생했습니다: ' + error
+ });
+ }
+ });
+ } catch(e) {
+ console.error("fn_save 오류:", e);
+ alert("저장 중 오류 발생: " + e.message);
+ }
+}