테스트 전 저장

This commit is contained in:
leeheejin
2025-12-17 11:59:03 +09:00
parent b910545f22
commit 3b33b0c133
5 changed files with 713 additions and 98 deletions

View File

@@ -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>
<!-- 반제품검사 행 잠금 (IS_LOCKED = 'Y') -->
<update id="lockSemiProductInspection" parameterType="map">
UPDATE PMS_QUALITY_SEMI_PRODUCT_INSPECTION
SET IS_LOCKED = 'Y'
WHERE OBJID = #{OBJID}
</update>
<!-- 반제품검사 데이터 삭제 (OBJID로 단건 삭제) -->
<delete id="deleteSemiProductInspectionByObjId" parameterType="map">
DELETE FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION
WHERE OBJID = #{OBJID}
</delete>
<!-- 반제품검사 데이터 삭제 (특정 OBJID 제외) -->
<delete id="deleteSemiProductInspectionExcludeObjIds" parameterType="map">
DELETE FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION
@@ -1734,6 +1748,19 @@
</if>
</delete>
<!-- 반제품검사 데이터 삭제 (타입별, 특정 OBJID 제외) -->
<delete id="deleteSemiProductInspectionByType" parameterType="map">
DELETE FROM PMS_QUALITY_SEMI_PRODUCT_INSPECTION
WHERE INSPECTION_GROUP_ID = #{INSPECTION_GROUP_ID}
AND DATA_TYPE = #{DATA_TYPE}
<if test="EXCLUDE_OBJIDS != null and EXCLUDE_OBJIDS.size() > 0">
AND OBJID NOT IN
<foreach collection="EXCLUDE_OBJIDS" item="objId" open="(" separator="," close=")">
#{objId}
</foreach>
</if>
</delete>
<!-- =====================================================
고객 CS 관리
===================================================== -->

View File

@@ -232,6 +232,7 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
<div class="btn_group">
<button type="button" class="btn_add" id="btnAddLeft">+ 행 추가</button>
<button type="button" class="btn_del" id="btnDelLeft">- 행 삭제</button>
<button type="button" class="btn_save" id="btnSaveLeft" style="margin-left:10px;">저장</button>
</div>
</div>
<div class="panel_body">
@@ -246,6 +247,7 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
<div class="btn_group">
<button type="button" class="btn_add" id="btnAddRight">+ 행 추가</button>
<button type="button" class="btn_del" id="btnDelRight">- 행 삭제</button>
<button type="button" class="btn_save" id="btnSaveRight" style="margin-left:10px;">저장</button>
</div>
</div>
<div class="panel_body" id="rightPanelBody">
@@ -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);
}
}
</script>
</body>
</html>