품질관리_공정검사관리

This commit is contained in:
2025-12-08 12:02:03 +09:00
parent c2e48f4cbb
commit d3e2ffa662
6 changed files with 832 additions and 166 deletions

View File

@@ -1,13 +1,16 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ page import="com.pms.common.utils.*"%>
<%@ page import="java.util.*" %>
<%@include file= "/init.jsp" %>
<script type="text/javascript" src="/js/tabulator/tabulator_custom.js"></script>
<%
String menuObjId = request.getParameter("menuObjId");
String menuName = CommonUtils.getMenuName(menuObjId, "공정검사 등록");
PersonBean person = (PersonBean) session.getAttribute(Constants.PERSON_BEAN);
String connector = person.getUserId();
%>
<c:set var="now" value="<%=new java.util.Date()%>" />
<c:set var="today"><fmt:formatDate value="${now}" pattern="yyyy-MM-dd" /></c:set>
<!DOCTYPE html>
<html>
<head>
@@ -15,88 +18,471 @@ String menuName = CommonUtils.getMenuName(menuObjId, "공정검사 등록");
<title><%=Constants.SYSTEM_NAME%></title>
</head>
<style>
.form-header {
display: flex;
align-items: center;
gap: 20px;
padding: 10px 15px;
background: #f8f9fa;
border-bottom: 1px solid #ddd;
}
.form-header label {
font-weight: bold;
margin-right: 5px;
}
.form-header .required {
color: red;
}
.form-header input, .form-header select {
padding: 5px 10px;
border: 1px solid #ccc;
border-radius: 3px;
}
/* 검사결과 스타일 */
.inspection-ng { color: #dc3545; font-weight: bold; }
.inspection-ok { color: #28a745; font-weight: bold; }
</style>
<script type="text/javascript">
var _editable = true;
var grid;
var rowIndex = 0;
// 진행공정 목록
var _PROCESS_LIST = [];
// 프로젝트 목록
var _PROJECT_LIST = [];
// 작업환경상태 목록
var _WORK_ENV_STATUS_LIST = [
{"CODE": "", "NAME": "선택"},
{"CODE": "양호", "NAME": "양호"},
{"CODE": "불량", "NAME": "불량"}
];
// 측정기 목록 (양호/불량)
var _MEASURING_DEVICE_LIST = [
{"CODE": "", "NAME": "선택"},
{"CODE": "양호", "NAME": "양호"},
{"CODE": "불량", "NAME": "불량"}
];
// 담당팀 목록
var _DEPT_LIST = [];
// 담당자 목록
var _USER_LIST = [];
// 검사결과 목록
var _INSPECTION_RESULT_LIST = [
{"CODE": "", "NAME": "선택"},
{"CODE": "OK", "NAME": "OK"},
{"CODE": "NG", "NAME": "NG"}
];
$(document).ready(function(){
fnc_datepick();
$('.select2').select2();
// 저장
// 진행공정 목록 조회 (더존 기준정보>내부공정)
_PROCESS_LIST = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getCodeselect", "code": "0001870"})
);
// 프로젝트 목록 조회
_PROJECT_LIST = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getProjectNameList"})
);
// 담당팀 목록 조회
_DEPT_LIST = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getDeptselect"})
);
// 담당자 목록 조회
_USER_LIST = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getUserselect"})
);
// 검사일 기본 설정 (저장된 값 없으면 오늘 날짜)
var savedInspectionDate = "${info.inspection_date}";
if(savedInspectionDate != '' && savedInspectionDate != 'null'){
$("#INSPECTION_DATE").val(savedInspectionDate);
} else if($("#INSPECTION_DATE").val() == ''){
$("#INSPECTION_DATE").val("${today}");
}
// 행추가 버튼
$("#btnAddRow").click(function(){
fn_addRow();
});
// 행삭제 버튼
$("#btnDelRow").click(function(){
fn_deleteRow();
});
// 저장 버튼
$("#btnSave").click(function(){
fn_save();
});
// 닫기
// 닫기 버튼
$("#btnClose").click(function(){
window.close();
self.close();
});
// 그리드 초기화 및 조회
fn_search();
});
function fn_save(){
// TODO: 저장 로직 구현
Swal.fire("저장 기능 준비중입니다.");
// 프로젝트별 파트 목록 캐시
var _PART_LIST_CACHE = {};
// 프로젝트번호로 MBOM 파트 목록 조회
function fn_getPartListByProject(projectNo) {
if (!projectNo) return [{"CODE": "", "NAME": "선택"}];
// 캐시에 있으면 캐시에서 반환
if (_PART_LIST_CACHE[projectNo]) {
return _PART_LIST_CACHE[projectNo];
}
// 서버에서 조회
var partList = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getMbomPartListByProjectNo", "PROJECT_NO": projectNo})
);
// 캐시에 저장
_PART_LIST_CACHE[projectNo] = partList;
return partList;
}
// 그리드 초기화 및 조회
function fn_search(){
var columns = [
{formatter:"rowSelection", titleFormatter:"rowSelection", hozAlign:"center", headerSort:false, width:30},
{title:'진행공정', field:'PROCESS_CD', headerHozAlign:'center', hozAlign:'center', width:130,
editor: fnc_customSelectEditor,
formatter: function(cell) {
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values:_PROCESS_LIST});
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_PROCESS_LIST}
},
{title:'프로젝트번호', field:'PROJECT_OBJID', headerHozAlign:'center', hozAlign:'center', width:130,
editor: fnc_customSelectEditor,
formatter: function(cell) {
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values:_PROJECT_LIST});
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_PROJECT_LIST}
},
{title:'품번', field:'PART_OBJID', headerHozAlign:'center', hozAlign:'left', width:250,
editor: fnc_customSelectEditor,
formatter: function(cell) {
var projectObjid = cell.getData().PROJECT_OBJID;
var partList = fn_getPartListByProject(projectObjid);
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values: partList});
},
editorParams: function(cell) {
var projectObjid = cell.getData().PROJECT_OBJID;
var partList = fn_getPartListByProject(projectObjid);
return {valueId:"CODE", labelId:"NAME", values: partList};
}
},
{title:'품명', field:'PART_NAME', headerHozAlign:'center', hozAlign:'left', width:180,
editor: false
},
{title:'검사수량', field:'INSPECTION_QTY', headerHozAlign:'center', hozAlign:'right', width:80,
editor:"input",
formatter:"money", formatterParams:{thousand:",", precision:false}
},
{title:'불량수량', field:'DEFECT_QTY', headerHozAlign:'center', hozAlign:'right', width:80,
editor:"input",
formatter:"money", formatterParams:{thousand:",", precision:false}
},
{title:'작업환경상태', field:'WORK_ENV_STATUS', headerHozAlign:'center', hozAlign:'center', width:100,
editor: fnc_customSelectEditor,
formatter: function(cell) {
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values:_WORK_ENV_STATUS_LIST});
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_WORK_ENV_STATUS_LIST}
},
{title:'측정기', field:'MEASURING_DEVICE', headerHozAlign:'center', hozAlign:'center', width:100,
editor: fnc_customSelectEditor,
formatter: function(cell) {
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values:_MEASURING_DEVICE_LIST});
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_MEASURING_DEVICE_LIST}
},
{title:'담당팀', field:'DEPT_CD', headerHozAlign:'center', hozAlign:'center', width:100,
editor: fnc_customSelectEditor,
formatter: function(cell) {
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values:_DEPT_LIST});
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_DEPT_LIST}
},
{title:'담당자', field:'USER_ID', headerHozAlign:'center', hozAlign:'center', width:100,
editor: fnc_customSelectEditor,
formatter: function(cell) {
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values:_USER_LIST});
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_USER_LIST}
},
{title:'특이사항', field:'REMARK', headerHozAlign:'center', hozAlign:'left', width:150,
editor:"input"
},
{title:'조치현황', field:'ACTION_STATUS', headerHozAlign:'center', hozAlign:'left', width:150,
editor:"input"
},
{title:'검사결과', field:'INSPECTION_RESULT', headerHozAlign:'center', hozAlign:'center', width:80,
editor: fnc_customSelectEditor,
formatter: function(cell) {
var val = cell.getValue();
if(val === 'NG') return '<span class="inspection-ng">NG</span>';
if(val === 'OK') return '<span class="inspection-ok">OK</span>';
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values:_INSPECTION_RESULT_LIST});
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_INSPECTION_RESULT_LIST}
}
];
// 그리드가 없으면 생성
if(!grid){
grid = new Tabulator("#grid", {
layout: "fitColumns",
height: "calc(100vh - 150px)",
columns: columns,
data: [],
selectableRows: true,
placeholder: "데이터가 없습니다."
});
// 셀 편집 이벤트
grid.on("cellEdited", function(cell) {
var row = cell.getRow();
var field = cell.getField();
// 프로젝트 변경 시 파트 초기화 및 목록 갱신
if (field === 'PROJECT_OBJID') {
var projectObjid = cell.getValue();
// 파트 목록 미리 로드 (캐시에 저장)
if (projectObjid) {
fn_getPartListByProject(projectObjid);
}
// 파트 초기화
row.update({
"PART_OBJID": "",
"PART_NO": "",
"PART_NAME": ""
});
// 행 다시 렌더링
row.reformat();
}
// 파트 선택 시 품번/품명 자동 설정
if (field === 'PART_OBJID') {
var partObjid = cell.getValue();
var projectObjid = row.getData().PROJECT_OBJID;
if (partObjid && projectObjid) {
var partList = fn_getPartListByProject(projectObjid);
for (var i = 0; i < partList.length; i++) {
if (partList[i].CODE == partObjid) {
row.update({
"PART_NO": partList[i].PART_NO || '',
"PART_NAME": partList[i].PART_NAME || ''
});
break;
}
}
}
}
// 불량수량 입력 시 검사결과 자동 설정
if (field === 'DEFECT_QTY') {
var defectQty = parseInt(cell.getValue()) || 0;
if (defectQty > 0) {
row.update({"INSPECTION_RESULT": "NG"});
}
}
});
}
// 데이터 조회 (마스터 OBJID가 있을 때만)
var masterObjId = $("#MASTER_OBJID").val();
if(masterObjId){
var param = {
MASTER_OBJID: masterObjId
};
grid = fnc_tabul_search(_tabul_layout_fitDataStretch, grid, "/quality/processInspectionDetailGridList.do", columns, false, false, true, param);
}
}
// 행 추가
function fn_addRow(){
rowIndex++;
var newRow = {
"ROW_INDEX": rowIndex,
"PROCESS_CD": "",
"PROJECT_OBJID": "",
"PART_OBJID": "",
"PART_NO": "",
"PART_NAME": "",
"INSPECTION_QTY": "",
"DEFECT_QTY": "",
"WORK_ENV_STATUS": "",
"MEASURING_DEVICE": "",
"DEPT_CD": "",
"USER_ID": "",
"REMARK": "",
"ACTION_STATUS": "",
"INSPECTION_RESULT": ""
};
grid.addRow(newRow, false);
}
// 행 삭제
function fn_deleteRow(){
var selectedRows = grid.getSelectedRows();
if(selectedRows.length == 0){
Swal.fire("삭제할 행을 선택하세요.");
return;
}
Swal.fire({
title: '선택한 ' + selectedRows.length + '건을 삭제하시겠습니까?',
icon: 'warning',
showCancelButton: true,
confirmButtonText: '삭제',
cancelButtonText: '취소'
}).then((result) => {
if(result.isConfirmed){
selectedRows.forEach(function(row){
row.delete();
});
}
});
}
// 저장
function fn_save(){
var inspectionDate = $("#INSPECTION_DATE").val();
var inspectorId = $("#INSPECTOR_ID").val();
if(inspectionDate == ''){
Swal.fire("검사일을 입력하세요.");
$("#INSPECTION_DATE").focus();
return;
}
if(inspectorId == ''){
Swal.fire("검사자를 선택하세요.");
$("#INSPECTOR_ID").focus();
return;
}
var gridData = grid.getData();
if(gridData.length == 0){
Swal.fire("저장할 데이터가 없습니다.");
return;
}
// 필수값 검증
for(var i = 0; i < gridData.length; i++){
if(!gridData[i].PROCESS_CD){
Swal.fire((i+1) + "번째 행의 진행공정을 선택하세요.");
return;
}
if(!gridData[i].PART_NO){
Swal.fire((i+1) + "번째 행의 품번을 입력하세요.");
return;
}
}
Swal.fire({
title: '저장하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '저장',
cancelButtonText: '취소'
}).then((result) => {
if(result.isConfirmed){
$.ajax({
url: "/quality/saveProcessInspection.do",
type: "POST",
data: {
"MASTER_OBJID": $("#MASTER_OBJID").val(),
"INSPECTION_DATE": inspectionDate,
"INSPECTOR_ID": inspectorId,
"dataList": JSON.stringify(gridData)
},
dataType: "json",
success: function(result){
if(result.RESULT == "SUCCESS"){
// 저장된 마스터 OBJID 저장
if(result.MASTER_OBJID){
$("#MASTER_OBJID").val(result.MASTER_OBJID);
}
Swal.fire({
title: '저장되었습니다.',
icon: 'success'
}).then(() => {
if(window.opener && window.opener.fn_search){
window.opener.fn_search();
}
});
} else {
Swal.fire({
title: '저장 실패',
text: result.MESSAGE || '저장 중 오류가 발생했습니다.',
icon: 'error'
});
}
},
error: function(xhr, status, error){
Swal.fire({
title: '저장 실패',
text: '서버 통신 오류가 발생했습니다.',
icon: 'error'
});
}
});
}
});
}
// 팝업 닫힐 때 부모 새로고침
window.addEventListener('unload', function() {
if(window.opener && window.opener.fn_search) {
window.opener.fn_search();
}
});
</script>
<body>
<form name="form1" id="form1" method="post">
<div class="popup_wrap">
<div class="popup_header">
<h2><%=menuName%></h2>
<div class="btnArea">
<input type="button" class="plm_btns" value="저장" id="btnSave">
<input type="button" class="plm_btns" value="닫기" id="btnClose">
</div>
</div>
<div class="popup_content">
<table class="plm_form_table">
<colgroup>
<col width="120px"><col width="*">
<col width="120px"><col width="*">
</colgroup>
<tbody>
<tr>
<td class="label">검사일</td>
<td><input type="text" name="INSPECTION_DATE" id="INSPECTION_DATE" class="date_icon"></td>
<td class="label">프로젝트번호</td>
<td><input type="text" name="PROJECT_NO" id="PROJECT_NO"></td>
</tr>
<tr>
<td class="label">품번</td>
<td><input type="text" name="PART_NO" id="PART_NO"></td>
<td class="label">품명</td>
<td><input type="text" name="PART_NAME" id="PART_NAME"></td>
</tr>
<tr>
<td class="label">불량수량</td>
<td><input type="text" name="DEFECT_QTY" id="DEFECT_QTY"></td>
<td class="label">작업환경상태</td>
<td><input type="text" name="WORK_ENV_STATUS" id="WORK_ENV_STATUS"></td>
</tr>
<tr>
<td class="label">측정기</td>
<td><input type="text" name="MEASURING_DEVICE" id="MEASURING_DEVICE"></td>
<td class="label">검사자</td>
<td><input type="text" name="INSPECTOR_NAME" id="INSPECTOR_NAME"></td>
</tr>
<tr>
<td class="label">검사결과</td>
<td>
<select name="INSPECTION_RESULT" id="INSPECTION_RESULT">
<option value="">선택</option>
<option value="OK">OK</option>
<option value="NG">NG</option>
</select>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td class="label">비고</td>
<td colspan="3"><textarea name="REMARK" id="REMARK" rows="3" style="width:100%;"></textarea></td>
</tr>
</tbody>
</table>
<body style="overflow-x: hidden;">
<form name="form1" id="form1" action="" method="post" onsubmit="return false">
<input type="hidden" name="MASTER_OBJID" id="MASTER_OBJID" value="${param.OBJID}">
<div class="plm_menu_name_gdnsi">
<h2><span>공정검사 등록</span></h2>
<div class="btnArea">
<input type="button" value="행추가" class="plm_btns" id="btnAddRow">
<input type="button" value="행삭제" class="plm_btns" id="btnDelRow">
<input type="button" value="저장" class="plm_btns" id="btnSave">
<input type="button" value="닫기" class="plm_btns" id="btnClose">
</div>
</div>
<div class="form-header">
<div>
<label>검사일<span class="required">*</span></label>
<input type="text" name="INSPECTION_DATE" id="INSPECTION_DATE" class="date_icon" style="width:120px;" value="${info.inspection_date}">
</div>
<div>
<label>검사자<span class="required">*</span></label>
<select name="INSPECTOR_ID" id="INSPECTOR_ID" class="select2" style="width:150px;">
<option value="">선택</option>
${code_map.inspector_id}
</select>
</div>
</div>
<div id="grid" style="margin: 10px;"></div>
</form>
</body>
</html>