V20260210 #161

Merged
hjjeong merged 6 commits from V20260210 into main 2026-03-05 09:10:28 +00:00
12 changed files with 890 additions and 420 deletions

View File

@@ -768,6 +768,7 @@ function fn_loadData() {
$("#recipient").val(data.estimate.RECIPIENT || "").trigger('change');
$("#part_name").val(data.estimate.PART_NAME || "");
$("#part_objid").val(data.estimate.PART_OBJID || "");
$("#model_code").val(data.estimate.PART_NAME || "");
// 환종 표시
if(data.estimate.CONTRACT_CURRENCY_NAME) {
@@ -1239,7 +1240,7 @@ function fn_generateAndUploadPdf(callback) {
<!-- 설비 Model 헤더 -->
<div class="model-header">
설비 Model : <span class="editable" style="display: inline-block; min-width: 200px;">
<input type="text" id="model_code" value="RUV-RA500S" style="text-align: center; font-weight: bold;">
<input type="text" id="model_code" value="${not empty items[0] ? items[0].PART_NAME : ''}" style="text-align: center; font-weight: bold;">
</span>
</div>

View File

@@ -226,9 +226,9 @@ function fn_addRow(resultDate, assemblyQty, inspectionQty, shipWaitQty) {
var html = '<tr id="row_' + _rowIndex + '" data-row-index="' + _rowIndex + '">';
html += '<td><input type="text" class="date-input" name="RESULT_DATE_' + _rowIndex + '" value="' + (resultDate || today) + '" placeholder="YYYY-MM-DD"></td>';
html += '<td><input type="number" class="qty-input assembly-qty" name="ASSEMBLY_QTY_' + _rowIndex + '" value="' + (assemblyQty || 0) + '" min="0" onchange="fn_updateTotals()"></td>';
html += '<td><input type="number" class="qty-input inspection-qty" name="INSPECTION_QTY_' + _rowIndex + '" value="' + (inspectionQty || 0) + '" min="0" onchange="fn_updateTotals()"></td>';
html += '<td><input type="number" class="qty-input ship-wait-qty" name="SHIP_WAIT_QTY_' + _rowIndex + '" value="' + (shipWaitQty || 0) + '" min="0" onchange="fn_updateTotals()"></td>';
html += '<td><input type="number" class="qty-input assembly-qty" name="ASSEMBLY_QTY_' + _rowIndex + '" value="' + (assemblyQty || 0) + '" min="0" onchange="fn_validateAndUpdate(this, \'assembly-qty\', \'완조립\')"></td>';
html += '<td><input type="number" class="qty-input inspection-qty" name="INSPECTION_QTY_' + _rowIndex + '" value="' + (inspectionQty || 0) + '" min="0" onchange="fn_validateAndUpdate(this, \'inspection-qty\', \'검사\')"></td>';
html += '<td><input type="number" class="qty-input ship-wait-qty" name="SHIP_WAIT_QTY_' + _rowIndex + '" value="' + (shipWaitQty || 0) + '" min="0" onchange="fn_validateAndUpdate(this, \'ship-wait-qty\', \'포장\')"></td>';
html += '<td><button type="button" class="delete-btn" onclick="fn_deleteRow(' + _rowIndex + ')">삭제</button></td>';
html += '</tr>';
@@ -242,6 +242,47 @@ function fn_deleteRow(rowIndex) {
fn_updateTotals();
}
// 총생산수량 반환
function fn_getTotalProdQty() {
return parseInt($("#TOTAL_PROD_QTY").text().replace(/,/g, "")) || 0;
}
// 특정 컬럼의 총합 계산 (excludeEl: 제외할 input)
function fn_getColumnTotal(className, excludeEl) {
var total = 0;
$("." + className).each(function() {
if(excludeEl && this === excludeEl) return;
total += parseInt($(this).val()) || 0;
});
return total;
}
// 입력값 검증 후 총수량 업데이트
function fn_validateAndUpdate(inputEl, className, labelName) {
var totalProdQty = fn_getTotalProdQty();
var othersTotal = fn_getColumnTotal(className, inputEl);
var currentVal = parseInt($(inputEl).val()) || 0;
var maxAllowed = totalProdQty - othersTotal;
if(maxAllowed < 0) maxAllowed = 0;
if(currentVal < 0) {
$(inputEl).val(0);
currentVal = 0;
}
if(currentVal > maxAllowed) {
Swal.fire({
icon: 'warning',
title: labelName + ' 수량 초과',
text: labelName + ' 총합이 총생산수량(' + totalProdQty + ')을 초과할 수 없습니다. (입력 가능: ' + maxAllowed + ')'
});
$(inputEl).val(maxAllowed);
}
fn_updateTotals();
}
// 총수량 업데이트
function fn_updateTotals() {
var totalAssembly = 0;
@@ -298,6 +339,25 @@ function fn_save() {
}
}
// 총생산수량 초과 검사
var totalProdQty = fn_getTotalProdQty();
var totalAssembly = fn_getColumnTotal('assembly-qty');
var totalInspection = fn_getColumnTotal('inspection-qty');
var totalShipWait = fn_getColumnTotal('ship-wait-qty');
if(totalAssembly > totalProdQty) {
Swal.fire('완조립 총합(' + totalAssembly + ')이 총생산수량(' + totalProdQty + ')을 초과합니다.');
return;
}
if(totalInspection > totalProdQty) {
Swal.fire('검사 총합(' + totalInspection + ')이 총생산수량(' + totalProdQty + ')을 초과합니다.');
return;
}
if(totalShipWait > totalProdQty) {
Swal.fire('포장 총합(' + totalShipWait + ')이 총생산수량(' + totalProdQty + ')을 초과합니다.');
return;
}
if(!confirm('저장하시겠습니까?')) return;
$.ajax({

View File

@@ -7,283 +7,408 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<style>
html, body { height: 100%; margin: 0; overflow: hidden; }
#wbsTaskList td { text-align: center; padding: 2px 4px; }
#wbsTaskList input[type="text"] { width: 95%; }
#wbsTaskList select { width: 80px; }
</style>
<script>
var rowSeq = 0;
var isEditMode = ("${templateObjId}" !== "");
$(document).ready(function(){
$("#product1").prop("disabled","disabled");
if(isEditMode){
loadExistingTasks();
$("#title").val("${masterInfo.TITLE}");
$("#product").val("${masterInfo.PRODUCT_OBJID}");
} else {
addTotalRow();
}
$("#templateDownload").click(function(){
location.href="/template/WBS_EXCEL_IMPORT_TEMPLATE.xlsx";
});
$("#product1").prop("disabled","disabled");
fnc_datepick();
fnc_setFileDropZone(
"excelImportDropZone",
"${OBJID}",
"WBS_EXCEL_IMPORT",
"WBS Excel Import Template",
"setExcelFileArea",
true,
"fileUploadPreProc",
"/project/excelImportFileProc.do",
null
"excelImportDropZone",
"${OBJID}",
"WBS_EXCEL_IMPORT",
"WBS Excel Import Template",
"setExcelFileArea",
true,
"fileUploadPreProc",
"/project/excelImportFileProc.do",
null
);
//fnc_getOEMList("OEM_OBJID","");
//Excel File Upload된 파일 목록 부분을 초기화 한다.
$("#excelImportList").hide();
});
//Excel 파일 업로드 후 처리함수
function setExcelFileArea(){
setUploadTemplateFile();
}
//템플릿 업로드 후 처리
function setUploadTemplateFile(){
var docType = "WBS_EXCEL_IMPORT";
var deleteCallBackFN = "excelFileDelete";
$.ajax({
url:"/common/getFileList.do",
type:"POST",
data:{"targetObjId":"${OBJID}", "docType":docType},
dataType:"json",
async:false,
success:function(data){
$.each(data, function(i){
var s = "<tr>";
s += "<td><a href='javascript:fnc_downloadFile(\""+data[i].OBJID+"\")'>"+data[i].REAL_FILE_NAME+"</a></td>";
s += "<td>"+data[i].FILE_SIZE+"</td>";
s += "<td><div class='delete_btn' onclick='javascript:fnc_deleteFile(\""+data[i].OBJID+"\", \""+deleteCallBackFN+"\")'></div></td>";
s += "</tr>";
$("#excelImportArea").append(s);
});
//$("#excelImportList").show();
parsingExcelFile();
},
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
Swal.fire(jqxhr.status);
Swal.fire(jqxhr.responseText);
}
});
}
function excelFileDelete(){
$("#excelImportArea").empty();
$("#excelImportList").hide();
$("#wbsTaskList").empty();
}
function parsingExcelFile(){
$("#wbsTaskList").empty();
var appendText = "";
$.ajax({
url:"/project/parsingExcelFile.do",
type:"POST",
data:{"targetObjId":"${OBJID}", "docType":"WBS_EXCEL_IMPORT"},
dataType:"json",
async:false,
success:function(data){
if(0 < data.length){
var resultList = data;
if(0 < resultList.length){
for (var i = 0; i < resultList.length; i++) {
var WBS_OBJID = resultList[i].WBS_OBJID;
/* var STEP = resultList[i].STEP;
var TASK1 = resultList[i].TASK1; */
var TASK_NAME = resultList[i].TASK_NAME;
//var USER_ID = resultList[i].USER_ID;
var UNIT_NO = resultList[i].UNIT_NO;
appendText += " <tr>";
appendText += " <input type='hidden' name='WBS_TASK_OBJID' value='"+WBS_OBJID+"'>";
//appendText += " <input type='hidden' name='TASK_CHARGER_ID_CODE_"+WBS_OBJID+"' id='TASK_CHARGER_ID_CODE_"+WBS_OBJID+"' value='"+USER_ID+"'>";
/* appendText += " <td>";
appendText += " <input type='text' name='STEP_"+WBS_OBJID+"' id='STEP_"+WBS_OBJID+"' value='"+STEP+"'>";
appendText += " </td>";
appendText += " <td>";
appendText += " <input type='text' name='TASK1_NAME_"+WBS_OBJID+"' id='TASK1_NAME_"+WBS_OBJID+"' value='"+TASK1+"'>";
appendText += " </td>"; */
appendText += " <td>";
appendText += " <input type='text' name='TASK_NAME_"+WBS_OBJID+"' id='TASK_NAME_"+WBS_OBJID+"' value='"+TASK_NAME+"'>";
appendText += " </td>";
appendText += " <td>";
appendText += " <input type='text' name='UNIT_NO_"+WBS_OBJID+"' id='UNIT_NO_"+WBS_OBJID+"' value='"+UNIT_NO+"'>";
/* appendText += " <select name='TASK_CHARGER_ID_"+WBS_OBJID+"' id='TASK_CHARGER_ID_"+WBS_OBJID+"'></select>"; */
appendText += " </td>";
appendText += " </tr>";
}
}else{
appendText += " <tr>";
appendText += " <td colspan='4'>조회된 내용이 없습니다.</td>";
appendText += " </tr>";
}
}
},
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
Swal.fire(jqxhr.status);
Swal.fire(jqxhr.responseText);
}
});
$("#wbsTaskList").append(appendText);
fn_setSelectData();
}
/*
저장 전 개정중인 정보의 존재여부를 확인한다.
*/
function fn_checkWBSTemplateRevision(){
var resultFlag = true;
$.ajax({
type:"POST",
url : "/project/checkWBSTemplateProduct.do",
data : {"PRODUCT":fnc_checkNull($("#product").val()),"TITLE":fnc_checkNull($("#title").val())},
dataType:"json",
async:false,
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
Swal.fire(jqxhr.status);
Swal.fire(jqxhr.responseText);
},
success:function(data){
if(0 < data.length){
resultFlag = false;
function addTotalRow(){
var objId = generateObjId();
var tr = '<tr id="row_total" data-depth="0">';
tr += '<td></td>';
tr += '<input type="hidden" name="WBS_TASK_OBJID" value="' + objId + '">';
tr += '<input type="hidden" name="UNIT_NO_' + objId + '" id="UNIT_NO_' + objId + '" value="0">';
tr += '<input type="hidden" name="UPPER_TASK_OBJID_' + objId + '" id="UPPER_TASK_OBJID_' + objId + '" value="">';
tr += '<input type="hidden" name="TASK_LEVEL_' + objId + '" id="TASK_LEVEL_' + objId + '" value="0">';
tr += '<td></td><td></td><td></td>';
tr += '<td style="font-weight:bold;">TOTAL';
tr += '<input type="hidden" name="TASK_NAME_' + objId + '" value="TOTAL">';
tr += '</td>';
tr += '</tr>';
$("#wbsTaskList").append(tr);
}
function loadExistingTasks(){
$.ajax({
url:"/project/getWBSTemplateTaskList.do",
type:"POST",
data:{"OBJID":"${templateObjId}"},
dataType:"json",
async:false,
success:function(data){
if(!data || data.length == 0) return;
for(var i = 0; i < data.length; i++){
var d = data[i];
var objId = d.OBJID;
var taskLevel = fnc_checkNull(d.TASK_LEVEL);
var depth = parseInt(taskLevel) || 0;
if(depth === 0){
var tr = '<tr id="row_total" data-depth="0">';
tr += '<td></td>';
tr += '<input type="hidden" name="WBS_TASK_OBJID" value="' + objId + '">';
tr += '<input type="hidden" name="UNIT_NO_' + objId + '" id="UNIT_NO_' + objId + '" value="0">';
tr += '<input type="hidden" name="UPPER_TASK_OBJID_' + objId + '" id="UPPER_TASK_OBJID_' + objId + '" value="">';
tr += '<input type="hidden" name="TASK_LEVEL_' + objId + '" id="TASK_LEVEL_' + objId + '" value="0">';
tr += '<td></td><td></td><td></td>';
tr += '<td style="font-weight:bold;">TOTAL';
tr += '<input type="hidden" name="TASK_NAME_' + objId + '" value="TOTAL">';
tr += '</td>';
tr += '</tr>';
$("#wbsTaskList").append(tr);
} else {
var unitNo = fnc_checkNull(d.UNIT_NO);
var taskName = fnc_checkNull(d.TASK_NAME);
var tr = '<tr id="row_' + objId + '">';
tr += '<td><input type="checkbox" name="rowCheck" value="' + objId + '"></td>';
tr += '<input type="hidden" name="WBS_TASK_OBJID" value="' + objId + '">';
tr += '<input type="hidden" name="UNIT_NO_' + objId + '" id="UNIT_NO_' + objId + '" value="' + unitNo + '">';
tr += '<input type="hidden" name="UPPER_TASK_OBJID_' + objId + '" id="UPPER_TASK_OBJID_' + objId + '" value="">';
tr += '<input type="hidden" name="TASK_LEVEL_' + objId + '" id="TASK_LEVEL_' + objId + '" value="' + depth + '">';
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="1" style="width:80%;text-align:center;"' + (depth==1 ? ' value="'+unitNo+'"' : '') + '></td>';
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="2" style="width:80%;text-align:center;"' + (depth==2 ? ' value="'+unitNo+'"' : '') + '></td>';
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="3" style="width:80%;text-align:center;"' + (depth==3 ? ' value="'+unitNo+'"' : '') + '></td>';
tr += '<td><input type="text" name="TASK_NAME_' + objId + '" id="TASK_NAME_' + objId + '" value="' + taskName + '"></td>';
tr += '</tr>';
$("#wbsTaskList").append(tr);
bindLevelInput(objId);
}
}
});
return resultFlag;
}
function saveWBS(){
var formData = $("#form1").serialize();
if( $("#title").val()==""){
Swal.fire('기계형식을 입력해 주세요');
return;
},
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
}
if( $("#customer_product").val()==""){
Swal.fire('고객사_장비목적 입력해 주세요');
return;
});
}
function setExcelFileArea(){
setUploadTemplateFile();
}
function setUploadTemplateFile(){
var docType = "WBS_EXCEL_IMPORT";
var deleteCallBackFN = "excelFileDelete";
$.ajax({
url:"/common/getFileList.do",
type:"POST",
data:{"targetObjId":"${OBJID}", "docType":docType},
dataType:"json",
async:false,
success:function(data){
$.each(data, function(i){
var s = "<tr>";
s += "<td><a href='javascript:fnc_downloadFile(\""+data[i].OBJID+"\")'>"+data[i].REAL_FILE_NAME+"</a></td>";
s += "<td>"+data[i].FILE_SIZE+"</td>";
s += "<td><div class='delete_btn' onclick='javascript:fnc_deleteFile(\""+data[i].OBJID+"\", \""+deleteCallBackFN+"\")'></div></td>";
s += "</tr>";
$("#excelImportArea").append(s);
});
parsingExcelFile();
},
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
}
if(fn_checkWBSTemplateRevision()){
if(0 < $("input[name='WBS_TASK_OBJID']").length){
if(confirm("해당 WBS 정보를 저장하시겠습니까?")){
$.ajax({
type:"POST",
url : "/project/saveExcelUploadWBS.do",
data : $("#form1").serialize(),
dataType:"json",
async:false,
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
Swal.fire(jqxhr.status);
Swal.fire(jqxhr.responseText);
},
success: function(result){
if(null != result){
Swal.fire(result.message);
opener.fn_search();
self.close();
}
}
});
});
}
function excelFileDelete(){
$("#excelImportArea").empty();
$("#excelImportList").hide();
// TOTAL 행만 남기고 나머지 제거
$("#wbsTaskList tr:not(#row_total)").remove();
}
function parsingExcelFile(){
// TOTAL 행만 남기고 나머지 제거
$("#wbsTaskList tr:not(#row_total)").remove();
$.ajax({
url:"/project/parsingExcelFile.do",
type:"POST",
data:{"targetObjId":"${OBJID}", "docType":"WBS_EXCEL_IMPORT"},
dataType:"json",
async:false,
success:function(data){
if(data && 0 < data.length){
for(var i = 0; i < data.length; i++){
var WBS_OBJID = data[i].WBS_OBJID;
var TASK_NAME = data[i].TASK_NAME;
var UNIT_NO = data[i].UNIT_NO;
var lvl = String(UNIT_NO);
var depth = (lvl.match(/\./g) || []).length + 1;
var tr = '<tr id="row_' + WBS_OBJID + '">';
tr += '<td><input type="checkbox" name="rowCheck" value="' + WBS_OBJID + '"></td>';
tr += '<input type="hidden" name="WBS_TASK_OBJID" value="' + WBS_OBJID + '">';
tr += '<input type="hidden" name="UNIT_NO_' + WBS_OBJID + '" id="UNIT_NO_' + WBS_OBJID + '" value="' + UNIT_NO + '">';
tr += '<input type="hidden" name="UPPER_TASK_OBJID_' + WBS_OBJID + '" id="UPPER_TASK_OBJID_' + WBS_OBJID + '" value="">';
tr += '<input type="hidden" name="TASK_LEVEL_' + WBS_OBJID + '" id="TASK_LEVEL_' + WBS_OBJID + '" value="' + depth + '">';
tr += '<td>' + (depth==1 ? '<input type="text" class="lvl_input" data-objid="'+WBS_OBJID+'" data-level="1" style="width:80%;text-align:center;" value="'+UNIT_NO+'">' : '<input type="text" class="lvl_input" data-objid="'+WBS_OBJID+'" data-level="1" style="width:80%;text-align:center;">') + '</td>';
tr += '<td>' + (depth==2 ? '<input type="text" class="lvl_input" data-objid="'+WBS_OBJID+'" data-level="2" style="width:80%;text-align:center;" value="'+UNIT_NO+'">' : '<input type="text" class="lvl_input" data-objid="'+WBS_OBJID+'" data-level="2" style="width:80%;text-align:center;">') + '</td>';
tr += '<td>' + (depth==3 ? '<input type="text" class="lvl_input" data-objid="'+WBS_OBJID+'" data-level="3" style="width:80%;text-align:center;" value="'+UNIT_NO+'">' : '<input type="text" class="lvl_input" data-objid="'+WBS_OBJID+'" data-level="3" style="width:80%;text-align:center;">') + '</td>';
tr += '<td><input type="text" name="TASK_NAME_' + WBS_OBJID + '" id="TASK_NAME_' + WBS_OBJID + '" value="' + TASK_NAME + '"></td>';
tr += '</tr>';
$("#wbsTaskList").append(tr);
bindLevelInput(WBS_OBJID);
}
}else{
Swal.fire("저장할 정보가 없습니다.");
}
}else{
Swal.fire("이미 해당 기계형식으로 등록된 정보가 존재합니다.");
},
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
}
});
}
function fileUploadPreProc(){
preFileDelete();
}
function preFileDelete(){
if(confirm("파일을 업로드하시겠습니까?\n기존에 업로드된 파일은 삭제됩니다.")){
$.ajax({
url:"/common/deleteFileInfo.do",
type:"POST",
data:{"targetObjId":"${OBJID}"},
dataType:"json",
async:true,
success:function(data){
excelFileDelete();
},
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
}
});
}
}
function bindLevelInput(objId){
$("#row_" + objId + " .lvl_input").on("input", function(){
var curObjId = $(this).data("objid");
var level = $(this).data("level");
$("#row_" + curObjId + " .lvl_input").not(this).val("");
$("#UNIT_NO_" + curObjId).val($(this).val());
$("#TASK_LEVEL_" + curObjId).val($(this).val() ? level : "");
});
}
function generateObjId(){
return String(Math.abs(Math.floor(Math.random() * 2147483647))) + String(++rowSeq);
}
function addRow(){
var objId = generateObjId();
var tr = '<tr id="row_' + objId + '">';
tr += '<td><input type="checkbox" name="rowCheck" value="' + objId + '"></td>';
tr += '<input type="hidden" name="WBS_TASK_OBJID" value="' + objId + '">';
tr += '<input type="hidden" name="UNIT_NO_' + objId + '" id="UNIT_NO_' + objId + '" value="">';
tr += '<input type="hidden" name="UPPER_TASK_OBJID_' + objId + '" id="UPPER_TASK_OBJID_' + objId + '" value="">';
tr += '<input type="hidden" name="TASK_LEVEL_' + objId + '" id="TASK_LEVEL_' + objId + '" value="">';
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="1" style="width:80%;text-align:center;"></td>';
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="2" style="width:80%;text-align:center;"></td>';
tr += '<td><input type="text" class="lvl_input" data-objid="' + objId + '" data-level="3" style="width:80%;text-align:center;"></td>';
tr += '<td><input type="text" name="TASK_NAME_' + objId + '" id="TASK_NAME_' + objId + '"></td>';
tr += '</tr>';
var checked = $("input[name='rowCheck']:checked");
if(checked.length > 0){
checked.last().closest("tr").after(tr);
checked.prop("checked", false);
} else {
$("#wbsTaskList").append(tr);
}
bindLevelInput(objId);
}
function deleteRow(){
var checked = $("input[name='rowCheck']:checked");
if(checked.length == 0){
Swal.fire('삭제할 행을 선택해 주세요');
return;
}
checked.each(function(){
var objId = $(this).val();
if($("#row_" + objId).attr("id") !== "row_total"){
$("#row_" + objId).remove();
}
});
}
function fn_checkWBSTemplateRevision(){
var resultFlag = true;
$.ajax({
type:"POST",
url : "/project/checkWBSTemplateProduct.do",
data : {"PRODUCT":fnc_checkNull($("#product").val()),"TITLE":fnc_checkNull($("#title").val())},
dataType:"json",
async:false,
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
},
success:function(data){
if(0 < data.length){
resultFlag = false;
}
}
});
return resultFlag;
}
function getRowDepth(tr){
var objId = $(tr).find("input[name='WBS_TASK_OBJID']").val();
var taskLevel = $.trim($("#TASK_LEVEL_" + objId).val());
if(taskLevel !== "") return parseInt(taskLevel);
var unitNo = $.trim($("#UNIT_NO_" + objId).val());
if(unitNo === "0") return 0;
if(unitNo === "") return -1;
return (unitNo.match(/\./g) || []).length + 1;
}
function calculateParentRelations(){
var rows = $("#wbsTaskList tr");
var totalObjId = $("#row_total").find("input[name='WBS_TASK_OBJID']").val();
rows.each(function(idx){
var trId = $(this).attr("id");
if(trId === "row_total") return true;
var objId = $(this).find("input[name='WBS_TASK_OBJID']").val();
var depth = getRowDepth(this);
var parentObjId = "";
if(depth === 1){
parentObjId = totalObjId;
} else if(depth > 1){
var prevRows = $(this).prevAll("tr");
prevRows.each(function(){
var prevDepth = getRowDepth(this);
if(prevDepth === depth - 1){
parentObjId = $(this).find("input[name='WBS_TASK_OBJID']").val();
return false;
}
});
}
$("#UPPER_TASK_OBJID_" + objId).val(parentObjId);
});
}
function saveWBS(){
if($("#title").val() == ""){
Swal.fire('제목을 입력해 주세요');
return;
}
if($("input[name='WBS_TASK_OBJID']").length == 0){
Swal.fire('등록할 항목을 추가해 주세요');
return;
}
var isValid = true;
$("input[name='WBS_TASK_OBJID']").each(function(){
var objId = $(this).val();
if($(this).closest("tr").attr("id") === "row_total") return true;
var level = $.trim($("#UNIT_NO_" + objId).val());
var taskName = $.trim($("#TASK_NAME_" + objId).val());
if(level == "" || taskName == ""){
isValid = false;
return false;
}
});
if(!isValid){
Swal.fire('수준과 Unit Name / 공정을 모두 입력해 주세요');
return;
}
//파일을 삭제한다.
//Excel 파일 삭제 시 파트 첨부파일도 모두 삭제한다.
function fileUploadPreProc(){
var templateTitle = fnc_checkNull($("#title").val());
preFileDelete();
}
//파일을 삭제한다.
//Excel 파일 삭제 시 파트 첨부파일도 모두 삭제한다.
function preFileDelete(){
if(confirm("파일을 업로드하시겠습니까?\n기존에 업로드된 파일은 삭제됩니다.")){
$.ajax({
url:"/common/deleteFileInfo.do",
type:"POST",
data:{"targetObjId":"${OBJID}"},
dataType:"json",
async:true,
success:function(data){
excelFileDelete();
},
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
Swal.fire(jqxhr.status);
Swal.fire(jqxhr.responseText);
}
});
if(!isEditMode){
if(!fn_checkWBSTemplateRevision()){
Swal.fire("이미 해당 제목으로 등록된 정보가 존재합니다.");
return;
}
}
//파일을 삭제한다.
//Excel 파일 삭제 시 파트 첨부파일도 모두 삭제한다.
function fileDelete(){
if(confirm("Excel 파일을 변경하시겠습니까?.")){
calculateParentRelations();
Swal.fire({
title: '저장하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '확인',
cancelButtonText: '취소'
}).then(function(result){
if(result.isConfirmed){
$.ajax({
url:"/common/deleteFileInfo.do",
type:"POST",
data:{"targetObjId":"${OBJID}"},
url : "/project/saveExcelUploadWBS.do",
data : $("#form1").serialize(),
dataType:"json",
async:true,
success:function(data){
excelFileDelete();
},
async:false,
error: function(jqxhr, status, error){
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
Swal.fire(jqxhr.status);
Swal.fire(jqxhr.responseText);
}
Swal.fire(jqxhr.statusText + ", " + status + ", " + error);
},
success: function(result){
if(null != result){
Swal.fire(result.message);
opener.fn_search();
self.close();
}
}
});
}
}
function fn_setSelectData(){
$("input[name='WBS_TASK_OBJID']").each(function(i){
var targetVal = $(this).val();
var userSelectId = "TASK_CHARGER_ID_"+targetVal;
var userSelectedVal = $("#TASK_CHARGER_ID_CODE_"+targetVal).val();
fnc_getUserList2(userSelectId, userSelectedVal);
});
}
});
}
</script>
</head>
<body>
<form name="form1" id="form1" action="" method="post">
<input type="hidden" name="importPopObjid" id="importPopObjid" value="${OBJID}">
<input type="hidden" name="product" id="product" value="${param.product}">
<input type="hidden" name="templateObjId" id="templateObjId" value="${templateObjId}">
<div class="content-box">
<div class="content-box-s">
<div class="plm_menu_name">
<h2>
<span>WBS Excel Upload</span>
<span>${empty templateObjId ? 'WBS 템플릿 등록' : 'WBS 템플릿 수정'}</span>
</h2>
</div>
<div id="plmSearchZon" style="width:auto;">
@@ -291,28 +416,20 @@ $(document).ready(function(){
<tbody>
<tr>
<td class="align_r">
<label for="" class="">제품구분</label>
<label for="">제품구분</label>
</td>
<td>
<select name="product1" id="product1" style="" class="select2" autocomplete="off">
<option value="">선택</option>
${code_map.product_cd}
</select>
<select name="product1" id="product1" style="" class="select2" autocomplete="off">
<option value="">선택</option>
${code_map.product_cd}
</select>
</td>
<td class="align_r">
<label for="title" class="">기계형식</label>
<label for="title">제목</label>
</td>
<td>
<input id="title" name="title" type="text" value="">
</td>
<td class="align_r">
<label for="customer_product" class="">고객사_장비목적</label>
</td>
<td>
<input id="customer_product" name="customer_product" type="text" value="">
</td>
</tr>
</tbody>
</table>
@@ -320,7 +437,9 @@ $(document).ready(function(){
<section class="contents_page_basic_margin">
<div class="btn_wrap">
<div class="plm_btn_wrap">
<input type="button" value="Template Download" id="templateDownload" class="plm_btns">
<input type="button" value="Template Download" id="templateDownload" class="plm_btns">
<input type="button" value="추가" class="plm_btns" onclick="addRow();">
<input type="button" value="삭제" class="plm_btns" onclick="deleteRow();">
<input type="button" value="저장" class="plm_btns" onclick="saveWBS();">
<input type="button" value="닫기" id="btn_close" class="plm_btns" onclick="javascript:self.close();">
</div>
@@ -335,31 +454,42 @@ $(document).ready(function(){
</tbody>
</table>
</div>
<div class="in_table_scroll_wrap _table1" style="height:26px;width:99.2%;">
<table class="plm_table">
<colgroup>
<col width="70%" /><!-- 단계 -->
<col width="30%" /><!-- TASK명 -->
</colgroup>
<thead>
<tr class="plm_thead">
<td>UNIT Name</td>
<td>UNIT No</td>
</tr>
</thead>
</table>
</div>
<div class="in_table_scroll_wrap _table2" style="height:560px;width:100%;">
<table class="pmsPopupForm" style="margin:0px;">
<colgroup>
<col width="70%" /><!-- 단계 -->
<col width="30%" /><!-- TASK명 -->
</colgroup>
<tbody id="wbsTaskList"></tbody>
</table>
</div>
<div style="width:100%;">
<table class="plm_table" style="width:100%;border-collapse:collapse;">
<colgroup>
<col width="5%" />
<col width="8%" />
<col width="8%" />
<col width="8%" />
<col width="71%" />
</colgroup>
<thead>
<tr class="plm_thead">
<td rowspan="2">선택</td>
<td colspan="3">수준</td>
<td rowspan="2">Unit Name / 공정</td>
</tr>
<tr class="plm_thead">
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</thead>
</table>
</div>
<div style="width:100%;height:calc(100vh - 280px);overflow-y:auto;">
<table class="plm_table" style="width:100%;border-collapse:collapse;">
<colgroup>
<col width="5%" />
<col width="8%" />
<col width="8%" />
<col width="8%" />
<col width="71%" />
</colgroup>
<tbody id="wbsTaskList"></tbody>
</table>
</div>
</section>
</div>
</div>

View File

@@ -92,14 +92,14 @@ $(document).ready(function(){
var columns = [
{headerHozAlign : 'center', hozAlign : 'left', width : '250', title : '제품구분', field : 'PRODUCT_NAME' },
{headerHozAlign : 'center', hozAlign : 'left', width : '250', title : '기계형식', field : 'TITLE' },
{headerHozAlign : 'center', hozAlign : 'left', /* width : '250', */ title : '고객사_장비목적', field : 'CUSTOMER_PRODUCT',
formatter:fnc_createGridAnchorTag,
cellClick:function(e, cell){
var objid = fnc_checkNull(cell.getData().OBJID);
fn_openTemplateMasterPopUp(objid);
}
},
{headerHozAlign : 'center', hozAlign : 'left', /* width : '250', */ title : '제목', field : 'TITLE' },
// {headerHozAlign : 'center', hozAlign : 'left', /* width : '250', */ title : '고객사_장비목적', field : 'CUSTOMER_PRODUCT',
// formatter:fnc_createGridAnchorTag,
// cellClick:function(e, cell){
// var objid = fnc_checkNull(cell.getData().OBJID);
// fn_openTemplateMasterPopUp(objid);
// }
// },
{headerHozAlign : 'center', hozAlign : 'center', width : '250', title : 'UNIT', field : 'WBS_TASK_CNT0',
formatter:fnc_getFolderIcon,
cellClick:function(e, cell){
@@ -130,18 +130,12 @@ function fn_openTemplateMasterPopUp(objId){
}
function fn_openWBSTaskListPopUp(objId){
var hiddenForm = document.hiddenForm;
var popup_width = 800;
var popup_height = 700;
var url = "/project/wbsTemplateTaskListDetailPopUp.do";
var popup_width = 1340;
var popup_height = 700;
var url = "/project/WBSExcelImportPopUp.do?templateObjId=" + objId;
var target = "openWBSTaskListPopUp";
fn_centerPopup(popup_width, popup_height, url, target);
hiddenForm.action = url;
hiddenForm.OBJID.value = objId;
hiddenForm.target = target;
hiddenForm.submit();
}
function _fnc_datepick(){

View File

@@ -119,7 +119,8 @@ var _ACTION_RESULT_LIST = [
{"CODE": "", "NAME": "선택"},
{"CODE": "수정", "NAME": "수정완료"},
{"CODE": "폐기", "NAME": "폐기"},
{"CODE": "특채", "NAME": "특채완료"}
{"CODE": "특채", "NAME": "특채완료"},
{"CODE": "검사완료", "NAME": "검사완료"}
];
// 검사자 목록
var _INSPECTOR_LIST = [];

View File

@@ -181,6 +181,8 @@ function fn_select2Editor(cell, onRendered, success, cancel, editorParams) {
var select = document.createElement("select");
select.style.width = "100%";
select.style.opacity = "0";
select.style.position = "absolute";
// 옵션 생성
if(values && values.length > 0) {
@@ -203,21 +205,32 @@ function fn_select2Editor(cell, onRendered, success, cancel, editorParams) {
width: "100%"
});
$(select).select2("open");
$(select).on("select2:select select2:clear", function(e) {
var selectedVal = $(select).val() || "";
// 콜백 호출 (프로젝트 변경 시 연동 처리 등)
if(typeof editorParams.onSelect === "function") {
editorParams.onSelect(cell, selectedVal);
}
success(selectedVal);
});
$(select).on("select2:close", function() {
setTimeout(function() { success($(select).val() || ""); }, 100);
});
});
var isCleared = false;
$(select).on("select2:select", function(e) {
var selectedVal = $(select).val() || "";
if(typeof editorParams.onSelect === "function") {
editorParams.onSelect(cell, selectedVal);
}
success(selectedVal);
});
$(select).on("select2:clear", function(e) {
isCleared = true;
if(typeof editorParams.onSelect === "function") {
editorParams.onSelect(cell, "");
}
setTimeout(function() {
$(select).select2("close");
success("");
}, 0);
});
$(select).on("select2:close", function() {
if(isCleared) return;
success($(select).val() || "");
});
return container;

View File

@@ -26,9 +26,10 @@ String loginUserId = CommonUtils.checkNull(person.getUserId());
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<link href="/css/tabulator/tabulator.min.css" rel="stylesheet">
<link href="/css/select2/select2.min.css" rel="stylesheet">
<link href="/css/select2.css" rel="stylesheet">
<script type="text/javascript" src="/js/tabulator/tabulator.min.js"></script>
<script type="text/javascript" src="/js/select2/select2.min.js"></script>
<script type="text/javascript" src="/js/tabulator/tabulator_custom.js"></script>
<script type="text/javascript" src="/js/select2.js"></script>
<style>
body, html {
@@ -301,17 +302,18 @@ var today = "${today}";
// 현재 수정 중인 INSPECTION_GROUP_ID (수정 모드일 때 사용)
var currentInspectionGroupId = "<%=INSPECTION_GROUP_ID%>";
// 입고관리 데이터 (드롭박스용)
var deliveryDataList = [];
// 전체 품목 데이터 (드롭박스용)
var allPartList = [];
var modelNameList = [];
var partNoList = [];
var partNameList = [];
// 코드 목록 (드롭박스용)
var productTypeList = ["Machine", "A/S", "D/S", "B/S", "C/T", "A/C", "W/M", "기타"];
var defectTypeList = ["외관불량", "치수불량", "기능불량", "재료불량", "조립불량", "도장불량", "용접불량", "기타"];
var defectCauseList = ["작업자 실수", "설비 이상", "자재 불량", "설계 오류", "공정 이상", "환경 요인", "기타"];
var responsibleDeptList = ["사용자 정보(부서)", "구매", "생산기술", "제조1팀", "제조2팀", "제조3팀", "연구소", "외주업체", "품질"];
// 불량유형 목록 (코드 0001820)
var _DEFECT_TYPE_LIST = [];
// 불량원인: 불량유형 선택에 따라 동적 조회
var responsibleDeptList = [];
// 작업자 목록 (서버에서 조회)
var workerList = [
<c:forEach var="worker" items="${workerList}" varStatus="status">
@@ -321,8 +323,27 @@ var workerList = [
var processStatusList = ["수정", "폐기"];
var dispositionTypeList = ["수정완료", "폐기", "특채완료"];
// 검사자 목록
var inspectorList = [];
$(document).ready(function(){
// 입고관리 데이터 로드
// 검사자 목록 조회
inspectorList = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getUserselect"})
);
// 귀책부서 목록 조회 (DEPT_INFO)
var deptResult = fnc_getJsonAllDataListBySqlId({"sqlId": "common.getDeptselect"});
if(deptResult && deptResult.length > 0) {
deptResult.forEach(function(d) { responsibleDeptList.push(d.NAME); });
}
// 불량유형 목록 조회
_DEFECT_TYPE_LIST = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getCodeselect", "code": "0001820"})
);
// 전체 품목 데이터 로드
fn_loadDeliveryData();
// 그리드 초기화
@@ -348,35 +369,27 @@ $(document).ready(function(){
$("#btnDelRight").click(fn_delRightRow);
});
// 입고관리 데이터 로드
// 전체 품목 데이터 로드
function fn_loadDeliveryData(){
$.ajax({
url: "/purchaseOrder/getDeliveryListForDropdown.do",
type: "POST",
async: false,
dataType: "json",
success: function(result){
if(result && result.list){
deliveryDataList = result.list;
var modelSet = {}, partNoSet = {}, partNameSet = {};
deliveryDataList.forEach(function(item){
if(item.MODEL_NAME && item.MODEL_NAME != '') modelSet[item.MODEL_NAME] = item;
if(item.PART_NO && item.PART_NO != '') partNoSet[item.PART_NO] = item;
if(item.PART_NAME && item.PART_NAME != '') partNameSet[item.PART_NAME] = item;
});
modelNameList = Object.keys(modelSet);
partNoList = Object.keys(partNoSet);
partNameList = Object.keys(partNameSet);
console.log("입고관리 데이터 로드 완료:", deliveryDataList.length + "건");
}
},
error: function(xhr, status, error){
console.error("입고관리 데이터 로드 실패:", error);
}
});
var result = fnc_getJsonAllDataListBySqlId({"sqlId": "salesMng.getAllPartMngList"});
if(result && result.length > 0){
allPartList = result;
var modelSet = {}, partNoSet = {}, partNameSet = {};
allPartList.forEach(function(item){
var partName = item.PART_NAME || '';
var partNo = item.PART_NO || '';
if(partName != '') modelSet[partName] = true;
if(partNo != '') partNoSet[partNo] = true;
if(partName != '') partNameSet[partName] = true;
});
modelNameList = Object.keys(modelSet);
partNoList = Object.keys(partNoSet);
partNameList = Object.keys(partNameSet);
console.log("전체 품목 데이터 로드 완료:", allPartList.length + "건");
}
}
// Select2 에디터 생성 함수
@@ -386,6 +399,8 @@ function createSelect2Editor(options, allowClear) {
var container = document.createElement("span");
var select = document.createElement("select");
select.style.width = "100%";
select.style.opacity = "0";
select.style.position = "absolute";
var emptyOption = document.createElement("option");
emptyOption.value = "";
@@ -410,14 +425,28 @@ function createSelect2Editor(options, allowClear) {
allowClear: allowClear !== false,
dropdownParent: $('body')
});
$(select).on('select2:select select2:clear', function(e) {
success($(select).val() || '');
});
$(select).select2('open');
});
var isCleared = false;
$(select).on('select2:select', function(e) {
success($(select).val() || '');
});
$(select).on('select2:clear', function(e) {
isCleared = true;
setTimeout(function() {
$(select).select2('close');
success('');
}, 0);
});
$(select).on('select2:close', function() {
if(isCleared) return;
success($(select).val() || '');
});
return container;
};
}
@@ -439,7 +468,14 @@ function fn_initLeftGrid(){
editorParams: { elementAttributes: { type: "date" } },
editable: isEditable
},
{title:"검사자", field:"INSPECTOR", editor:"input", minWidth:70, headerSort:false, editable: isEditable},
{title:"검사자", field:"INSPECTOR", minWidth:80, headerSort:false,
editor: fnc_customSelectEditor,
editorParams: {valueId:"CODE", labelId:"NAME", values: inspectorList},
formatter: function(cell) {
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values: inspectorList});
},
editable: isEditable
},
{title:"품명(모델명)", field:"MODEL_NAME", minWidth:110, headerSort:false,
editor: createSelect2Editor(modelNameList),
editable: isEditable
@@ -471,12 +507,11 @@ function fn_initLeftGrid(){
cellEdited: function(cell){
var partNo = cell.getValue();
if(partNo){
var matched = deliveryDataList.find(function(d){ return d.PART_NO == partNo; });
var matched = allPartList.find(function(d){ return d.PART_NO == partNo; });
if(matched){
cell.getRow().update({
PART_NAME: matched.PART_NAME || '',
PART_OBJID: matched.PART_OBJID || '',
RECEIPT_QTY: matched.RECEIPT_QTY || matched.DELIVERY_QTY || ''
PART_OBJID: matched.OBJID || ''
});
}
}
@@ -488,11 +523,11 @@ function fn_initLeftGrid(){
cellEdited: function(cell){
var partName = cell.getValue();
if(partName){
var matched = deliveryDataList.find(function(d){ return d.PART_NAME == partName; });
var matched = allPartList.find(function(d){ return d.PART_NAME == partName; });
if(matched){
cell.getRow().update({
PART_NO: matched.PART_NO || '',
RECEIPT_QTY: matched.RECEIPT_QTY || matched.DELIVERY_QTY || ''
PART_OBJID: matched.OBJID || ''
});
}
}
@@ -587,11 +622,39 @@ function fn_initRightGrid(){
}
},
{title:"불량유형", field:"DEFECT_TYPE", minWidth:85, headerSort:false,
editor: createSelect2Editor(defectTypeList),
editor: fnc_customSelectEditor,
formatter: function(cell) {
var val = cell.getValue();
if(!val || val === '') return '';
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values:_DEFECT_TYPE_LIST});
},
editorParams: {valueId:"CODE", labelId:"NAME", values:_DEFECT_TYPE_LIST},
editable: isEditable
},
{title:"불량원인", field:"DEFECT_CAUSE", minWidth:85, headerSort:false,
editor: createSelect2Editor(defectCauseList),
editor: fnc_customSelectEditor,
formatter: function(cell) {
var val = cell.getValue();
if(!val || val === '') return '';
var defectType = cell.getData().DEFECT_TYPE;
if(defectType) {
var reasonList = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getCodeselect", "code": defectType})
);
return fnc_customSelectFormatter(cell, {valueId:"CODE", labelId:"NAME", values: reasonList});
}
return '';
},
editorParams: function(cell) {
var defectType = cell.getData().DEFECT_TYPE;
if(defectType) {
var reasonList = [{"CODE": "", "NAME": "선택"}].concat(
fnc_getJsonAllDataListBySqlId({"sqlId": "common.getCodeselect", "code": defectType})
);
return {valueId:"CODE", labelId:"NAME", values: reasonList};
}
return {valueId:"CODE", labelId:"NAME", values: [{"CODE": "", "NAME": "선택"}]};
},
editable: isEditable
},
{title:"귀책부서", field:"RESPONSIBLE_DEPT", minWidth:80, headerSort:false,
@@ -646,14 +709,21 @@ function fn_initRightGrid(){
rowFormatter: function(row){
var data = row.getData();
if(data.IS_SAVED || data.IS_LOCKED === 'Y'){
row.getElement().style.backgroundColor = "#e8f5e9"; // 연한 초록색
row.getElement().style.backgroundColor = "#e8f5e9";
row.getElement().style.color = "#555";
} else {
row.getElement().style.backgroundColor = ""; // 원래 색상
row.getElement().style.backgroundColor = "";
row.getElement().style.color = "";
}
}
});
// 불량유형 변경 시 불량원인 초기화
rightGrid.on("cellEdited", function(cell) {
if(cell.getField() === 'DEFECT_TYPE') {
cell.getRow().update({"DEFECT_CAUSE": ""});
}
});
}
// 우측 그리드에 데이터 표시 (선택된 좌측 행의 불량 데이터)
@@ -712,8 +782,10 @@ function fn_addLeftRow(){
var newObjId = result.OBJID;
leftGrid.addRow({
ROW_ID: newObjId, // OBJID를 ROW_ID로 사용
OBJID: newObjId, // 서버에서 생성한 실제 OBJID
ROW_ID: newObjId,
OBJID: newObjId,
INSPECTION_DATE: today,
INSPECTOR: loginUserId,
MODEL_NAME: "",
PRODUCT_TYPE: "",
WORK_ORDER_NO: "",

View File

@@ -68,6 +68,36 @@ body, html {
padding: 20px;
overflow: auto;
}
.vendor-context-menu {
position: fixed;
background: #fff;
border: 1px solid #ccc;
box-shadow: 2px 2px 8px rgba(0,0,0,0.2);
z-index: 10000;
border-radius: 4px;
padding: 4px 0;
min-width: 180px;
}
.vendor-context-menu .ctx-item {
padding: 8px 16px;
cursor: pointer;
font-size: 13px;
white-space: nowrap;
}
.vendor-context-menu .ctx-item:hover {
background: #e3f2fd;
}
.vendor-context-menu .ctx-item.disabled {
color: #aaa;
cursor: default;
}
.vendor-context-menu .ctx-item.disabled:hover {
background: transparent;
}
.vendor-context-menu .ctx-divider {
border-top: 1px solid #eee;
margin: 4px 0;
}
</style>
</head>
<body>
@@ -137,6 +167,7 @@ var bomReportObjid = "${resolvedBomReportObjid}";
var mbomHeaderObjid = "${resolvedMbomHeaderObjid}"; // MBOM_HEADER.OBJID (M-BOM 관리 화면에서 사용하는 ID)
var vendorList = []; // 공급업체 목록
var processingVendorList = []; // 가공업체 목록 (Select2용 배열)
var copiedVendorData = { field: null, value: null, displayName: '' }; // 복사된 업체 정보
// 디버그: resultMap 내용 확인 (주석처리)
// console.log("=== JSP resultMap 디버그 ===");
@@ -875,6 +906,149 @@ function fn_initGrid() {
row.reformat();
}
});
// 공급업체/가공업체 셀 우클릭 → 복사/붙여넣기 컨텍스트 메뉴
_tabulGrid.on("cellContext", function(e, cell) {
var field = cell.getField();
if(field !== 'VENDOR_PM' && field !== 'PROCESSING_VENDOR') return;
e.preventDefault();
fn_showVendorContextMenu(e, cell);
});
// 다른 곳 클릭 시 컨텍스트 메뉴 닫기
$(document).on('click', function() {
$('.vendor-context-menu').remove();
});
}
// 업체 복사/붙여넣기 컨텍스트 메뉴 표시
function fn_showVendorContextMenu(e, cell) {
$('.vendor-context-menu').remove();
var field = cell.getField();
var cellValue = cell.getValue();
var fieldLabel = (field === 'VENDOR_PM') ? '공급업체' : '가공업체';
var displayName = fn_getVendorDisplayName(cellValue);
var menu = $('<div class="vendor-context-menu"></div>');
// 복사
var copyLabel = cellValue ? '<b>복사</b> : ' + displayName : '<b>복사</b> (값 없음)';
var $copyItem = $('<div class="ctx-item">' + copyLabel + '</div>');
if(cellValue) {
$copyItem.on('click', function() {
copiedVendorData = { field: field, value: cellValue, displayName: displayName };
menu.remove();
Swal.fire({ toast: true, position: 'top-end', icon: 'success', title: fieldLabel + ' 복사: ' + displayName, showConfirmButton: false, timer: 1200 });
});
} else {
$copyItem.addClass('disabled');
}
menu.append($copyItem);
menu.append('<div class="ctx-divider"></div>');
// 선택행에 붙여넣기
var hasCopied = copiedVendorData.value && copiedVendorData.field === field;
var pasteLabel = hasCopied
? '<b>선택행에 붙여넣기</b> : ' + copiedVendorData.displayName
: '<b>선택행에 붙여넣기</b> (복사된 ' + fieldLabel + ' 없음)';
var $pasteItem = $('<div class="ctx-item">' + pasteLabel + '</div>');
if(hasCopied) {
$pasteItem.on('click', function() {
menu.remove();
fn_pasteVendorToCheckedRows(copiedVendorData.field, copiedVendorData.value);
});
} else {
$pasteItem.addClass('disabled');
}
menu.append($pasteItem);
menu.append('<div class="ctx-divider"></div>');
// 전체행에 붙여넣기
var pasteAllLabel = hasCopied
? '<b>전체행에 붙여넣기</b> : ' + copiedVendorData.displayName
: '<b>전체행에 붙여넣기</b> (복사된 ' + fieldLabel + ' 없음)';
var $pasteAllItem = $('<div class="ctx-item">' + pasteAllLabel + '</div>');
if(hasCopied) {
$pasteAllItem.on('click', function() {
menu.remove();
fn_pasteVendorToAllRows(copiedVendorData.field, copiedVendorData.value);
});
} else {
$pasteAllItem.addClass('disabled');
}
menu.append($pasteAllItem);
// 화면 밖으로 나가지 않도록 위치 보정
var menuX = e.pageX;
var menuY = e.pageY;
$('body').append(menu);
var menuWidth = menu.outerWidth();
var menuHeight = menu.outerHeight();
if(menuX + menuWidth > $(window).width()) menuX = $(window).width() - menuWidth - 5;
if(menuY + menuHeight > $(window).height()) menuY = $(window).height() - menuHeight - 5;
menu.css({ left: menuX + 'px', top: menuY + 'px' });
}
// 업체 OBJID → 업체명 변환
function fn_getVendorDisplayName(value) {
if(!value) return '';
for(var i = 0; i < processingVendorList.length; i++) {
if(processingVendorList[i].id == value) return processingVendorList[i].text;
}
return value;
}
// 체크된 행에 업체값 붙여넣기
function fn_pasteVendorToCheckedRows(field, value) {
var count = 0;
$('.rowCheck:checked').each(function() {
var row = $(this).closest('.tabulator-row');
if(row.length > 0 && _tabulGrid) {
var rowComponent = _tabulGrid.getRow(row[0]);
if(rowComponent) {
var updateData = {};
updateData[field] = value;
rowComponent.update(updateData);
count++;
}
}
});
var fieldLabel = (field === 'VENDOR_PM') ? '공급업체' : '가공업체';
if(count > 0) {
Swal.fire({ toast: true, position: 'top-end', icon: 'success', title: fieldLabel + ' ' + count + '건 적용 완료', showConfirmButton: false, timer: 1500 });
} else {
Swal.fire({ title: '알림', text: '체크된 행이 없습니다.\n먼저 적용할 행을 체크해주세요.', icon: 'info' });
}
}
// 전체 행에 업체값 붙여넣기
function fn_pasteVendorToAllRows(field, value) {
var fieldLabel = (field === 'VENDOR_PM') ? '공급업체' : '가공업체';
var displayName = fn_getVendorDisplayName(value);
Swal.fire({
title: '전체 적용',
text: '모든 행의 ' + fieldLabel + '을(를) "' + displayName + '"(으)로 변경하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '적용',
cancelButtonText: '취소'
}).then(function(result) {
if(result.isConfirmed) {
var rows = _tabulGrid.getRows();
var count = 0;
rows.forEach(function(row) {
var updateData = {};
updateData[field] = value;
row.update(updateData);
count++;
});
Swal.fire({ toast: true, position: 'top-end', icon: 'success', title: fieldLabel + ' 전체 ' + count + '건 적용 완료', showConfirmButton: false, timer: 1500 });
}
});
}
// 기존 구매리스트 조회
@@ -944,11 +1118,7 @@ function fn_loadFromMBom(callback) {
var list = (data && data.list) ? data.list : [];
if(list.length > 0) {
// console.log("M-BOM 데이터 " + list.length + "건 로드됨");
_tabulGrid.setData(list);
} else {
// console.log("M-BOM 데이터 없음!");
// 알림 제거 - 머지 모드에서는 알림 안 띄움
}
if(typeof callback === "function"){
callback(list);

View File

@@ -2282,14 +2282,27 @@ public class ProjectController {
@RequestMapping("/project/WBSExcelImportPopUp.do")
public String partMngExcelImportPopUp(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
String objid = CommonUtils.createObjId();
String templateObjId = CommonUtils.nullToEmpty((String)paramMap.get("templateObjId"));
Map code_map = new HashMap();
try{
code_map.put("product_cd", commonService.bizMakeOptionList("0000001", CommonUtils.nullToEmpty((String)paramMap.get("product")),"common.getCodeselect")); //공장
code_map.put("product_cd", commonService.bizMakeOptionList("0000001", CommonUtils.nullToEmpty((String)paramMap.get("product")),"common.getCodeselect"));
if(!"".equals(templateObjId)){
Map templateParam = new HashMap();
templateParam.put("OBJID", templateObjId);
Map masterInfo = service.getWBSTemplateMasterInfo(request, templateParam);
List taskList = service.getWBSTemplateTaskList(request, templateParam);
request.setAttribute("masterInfo", masterInfo);
request.setAttribute("taskList", taskList);
request.setAttribute("templateObjId", templateObjId);
String productObjId = CommonUtils.nullToEmpty((String)masterInfo.get("PRODUCT_OBJID"));
code_map.put("product_cd", commonService.bizMakeOptionList("0000001", productObjId, "common.getCodeselect"));
}
}catch(Exception e){
e.printStackTrace();
}
request.setAttribute("OBJID",objid);
request.setAttribute("code_map",code_map);
return "/project/WBSExcelImportPopUp";

View File

@@ -5611,29 +5611,38 @@
,PARENT_OBJID
,TASK_NAME
,TASK_SEQ
,TASK_LEVEL
,USER_ID
,WRITER
,REG_DATE
,UNIT_NO
,UPPER_TASK_OBJID
) VALUES (
#{objid}
,#{parent_objid}
,#{task_name}
,#{task_seq}
,#{task_level}
,#{user_id}
,#{writer}
,now()
,now()
,#{unit_no}
,#{upper_task_objid}
) ON
CONFLICT (OBJID) DO
UPDATE SET
TASK_NAME = #{task_name}
,TASK_SEQ = #{task_seq}
,USER_ID = #{user_id}
,UNIT_NO = #{unit_no}
TASK_NAME = #{task_name}
,TASK_SEQ = #{task_seq}
,TASK_LEVEL = #{task_level}
,USER_ID = #{user_id}
,UNIT_NO = #{unit_no}
,UPPER_TASK_OBJID = #{upper_task_objid}
</insert>
<delete id="deleteWBSTemplateTaskByMaster" parameterType="map">
DELETE FROM PMS_WBS_TASK_STANDARD WHERE PARENT_OBJID = #{parent_objid}
</delete>
<select id="getWBSTemplateMasterInfo" parameterType="map" resultType="map">
SELECT
OBJID
@@ -5654,14 +5663,16 @@
,T.PARENT_OBJID
,T.TASK_NAME
,T.TASK_SEQ
,T.TASK_LEVEL
,T.USER_ID
,(SELECT USER_NAME FROM USER_INFO WHERE USER_ID = T.USER_ID) AS USER_ID_TITLE
,T.WRITER
,T.REG_DATE
,T.UNIT_NO
,T.UPPER_TASK_OBJID
FROM PMS_WBS_TASK_STANDARD AS T
WHERE T.PARENT_OBJID = #{OBJID}
ORDER BY UNIT_NO
ORDER BY CAST(T.TASK_SEQ AS INTEGER)
</select>

View File

@@ -3305,7 +3305,7 @@ WITH RECURSIVE VIEW_BOM(
A.PART_NO,
A.PART_NAME,
A.QTY,
A.QTY,
A.ITEM_QTY,
A.QTY,
A.REGDATE,
A.SEQ,
@@ -3368,7 +3368,7 @@ WITH RECURSIVE VIEW_BOM(
B.PART_NO,
B.PART_NAME,
B.QTY,
B.QTY,
B.ITEM_QTY,
B.QTY,
B.REGDATE,
B.SEQ,
@@ -3445,6 +3445,7 @@ GROUPED_BOM AS (
MIN(V.CHILD_OBJID) AS CHILD_OBJID,
MIN(V.PART_NAME) AS PART_NAME,
SUM(COALESCE(NULLIF(V.QTY::TEXT, '')::NUMERIC, 0)) AS QTY,
SUM(COALESCE(NULLIF(V.ITEM_QTY::TEXT, '')::NUMERIC, 0)) AS ITEM_QTY,
MIN(V.SEQ) AS SEQ,
MIN(V.STATUS) AS STATUS,
MIN(V.LEV) AS LEV,
@@ -3476,6 +3477,7 @@ GROUPED_BOM AS (
COUNT(*) AS GROUPED_COUNT
FROM VIEW_BOM V
WHERE COALESCE(V.PRODUCTION_QTY, 0) > 0
AND V.LEV > 1
GROUP BY V.PART_NO, V.PART_OBJID,
COALESCE(V.SUPPLY_TYPE, ''),
COALESCE(V.RAW_MATERIAL, ''),
@@ -3494,7 +3496,7 @@ SELECT
G.PART_NO,
G.PART_NAME,
G.QTY,
G.QTY AS ITEM_QTY,
G.ITEM_QTY,
G.QTY AS QTY_TEMP,
G.LEV AS LEVEL,
0 AS SUB_PART_CNT,
@@ -3507,7 +3509,7 @@ SELECT
G.RAW_MATERIAL_SPEC,
G.RAW_MATERIAL,
G.RAW_MATERIAL_SIZE AS SIZE,
CASE WHEN G.PROCESSING_VENDOR IS NULL THEN '0000008377' ELSE G.PROCESSING_VENDOR END AS PROCESSING_VENDOR,
G.PROCESSING_VENDOR,
G.PROCESSING_DEADLINE,
G.GRINDING_DEADLINE,
G.REQUIRED_QTY,

View File

@@ -2940,51 +2940,54 @@ public class ProjectService {
try{
PersonBean person = (PersonBean)request.getSession().getAttribute(Constants.PERSON_BEAN);
String writer = CommonUtils.checkNull(person.getUserId());
String product = CommonUtils.checkNull(request.getParameter("product"));
String title = CommonUtils.checkNull(request.getParameter("title"));
String customer_product = CommonUtils.checkNull(request.getParameter("customer_product"));
Map templateMapsterSqlParamMap = new HashMap();
String wbsMasterObjId = CommonUtils.createObjId();
templateMapsterSqlParamMap.put("objid" , wbsMasterObjId);
templateMapsterSqlParamMap.put("product" , product);
templateMapsterSqlParamMap.put("title" , title);
templateMapsterSqlParamMap.put("writer" , writer);
templateMapsterSqlParamMap.put("customer_product" , customer_product);
//템플릿 마스터를 저장한다.
sqlSession.insert("project.saveWBSTaskTemp",templateMapsterSqlParamMap);
String templateObjId = CommonUtils.checkNull(request.getParameter("templateObjId"));
String wbsMasterObjId;
if(!"".equals(templateObjId)){
wbsMasterObjId = templateObjId;
Map deleteParam = new HashMap();
deleteParam.put("parent_objid", wbsMasterObjId);
sqlSession.delete("project.deleteWBSTemplateTaskByMaster", deleteParam);
} else {
wbsMasterObjId = CommonUtils.createObjId();
Map templateMasterSqlParamMap = new HashMap();
templateMasterSqlParamMap.put("objid", wbsMasterObjId);
templateMasterSqlParamMap.put("product", product);
templateMasterSqlParamMap.put("title", title);
templateMasterSqlParamMap.put("writer", writer);
templateMasterSqlParamMap.put("customer_product", customer_product);
sqlSession.insert("project.saveWBSTaskTemp", templateMasterSqlParamMap);
}
String[] wbsObjIdList = request.getParameterValues("WBS_TASK_OBJID");
if(null != wbsObjIdList || 0 < wbsObjIdList.length){
if(null != wbsObjIdList && 0 < wbsObjIdList.length){
for(int i = 0;i<wbsObjIdList.length;i++){
String wbsObjId = CommonUtils.checkNull(wbsObjIdList[i]);
Map wbsSqlParamMap = new HashMap();
String TASK_NAME = CommonUtils.checkNull(request.getParameter("TASK_NAME_"+wbsObjId));
//String MANAGER_USER_ID = CommonUtils.checkNull(request.getParameter("TASK_CHARGER_ID_"+wbsObjId));
String UNIT_NO = CommonUtils.checkNull(request.getParameter("UNIT_NO_"+wbsObjId));
String UNIT_NO = CommonUtils.checkNull(request.getParameter("UNIT_NO_"+wbsObjId));
String UPPER_TASK_OBJID = CommonUtils.checkNull(request.getParameter("UPPER_TASK_OBJID_"+wbsObjId));
String TASK_LEVEL = CommonUtils.checkNull(request.getParameter("TASK_LEVEL_"+wbsObjId));
wbsSqlParamMap.put("objid", wbsObjId);
wbsSqlParamMap.put("task_name", TASK_NAME);
wbsSqlParamMap.put("task_seq", i+1);
wbsSqlParamMap.put("task_level", TASK_LEVEL);
wbsSqlParamMap.put("unit_no", UNIT_NO);
//wbsSqlParamMap.put("user_id", MANAGER_USER_ID);
wbsSqlParamMap.put("upper_task_objid", UPPER_TASK_OBJID);
wbsSqlParamMap.put("parent_objid", wbsMasterObjId);
wbsSqlParamMap.put("writer", writer);
System.out.println("wbsSqlParamMap:"+wbsSqlParamMap);
sqlSession.insert("project.saveWBSTemplateTaskInfo", wbsSqlParamMap);
//제품구분(0000001) 공통코드 등록 처리
// this.checkAndSaveUnitCodeInfo(request, wbsSqlParamMap, sqlSession);
}
sqlSession.commit();
}