607 lines
17 KiB
Plaintext
607 lines
17 KiB
Plaintext
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
|
<%@ page import="com.pms.common.utils.*"%>
|
|
<%@ page import="java.util.*" %>
|
|
<%@include file= "/init.jsp" %>
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
<title><%=Constants.SYSTEM_NAME%></title>
|
|
<link href="/css/tabulator/tabulator.min.css" rel="stylesheet">
|
|
<script type="text/javascript" src="/js/tabulator/tabulator.min.js"></script>
|
|
<style>
|
|
::-webkit-scrollbar {
|
|
width: 10px;
|
|
height: 15px;
|
|
}
|
|
#structureTableWrap1 {
|
|
top: 56px;
|
|
width: 99%;
|
|
}
|
|
#structureName {
|
|
margin-bottom: 10px;
|
|
font-weight: bold;
|
|
}
|
|
#structureName2 {
|
|
margin-bottom: 10px;
|
|
font-size: 12px;
|
|
color: #666;
|
|
}
|
|
/* Tabulator 커스텀 스타일 */
|
|
.tabulator-row.level-1 { background-color: #fde9d9 !important; }
|
|
.tabulator-row.level-2 { background-color: #daeef3 !important; }
|
|
.tabulator-row.level-3 { background-color: #e4dfec !important; }
|
|
.tabulator-row.level-4 { background-color: #ebf1de !important; }
|
|
.tabulator-row.level-5 { background-color: #f2f2f2 !important; }
|
|
.tabulator-row.level-6 { background-color: #f2dcdb !important; }
|
|
.tabulator-row.level-7 { background-color: #eeece1 !important; }
|
|
.tabulator-row.level-8 { background-color: #dce6f1 !important; }
|
|
.tabulator-row.level-9 { background-color: #FFFFEB !important; }
|
|
.tabulator-row.level-10 { background-color: #ffffff !important; }
|
|
|
|
/* 파일 아이콘 스타일은 basic.css에서 관리 */
|
|
</style>
|
|
<script>
|
|
var _tabulGrid;
|
|
var selectedRowData = null;
|
|
|
|
$(function(){
|
|
if('${param.readonly}' == 'readonly'){
|
|
$("#structureName2").hide();
|
|
}
|
|
|
|
$("#btnExcel").click(function() {
|
|
fn_excel();
|
|
});
|
|
|
|
// 도면 업로드 버튼 클릭
|
|
$("#btnDrawingUpload").click(function() {
|
|
$("#drawingFiles").click();
|
|
});
|
|
|
|
// 파일 선택 이벤트
|
|
$("#drawingFiles").change(function() {
|
|
fn_uploadDrawingFiles(this.files);
|
|
});
|
|
|
|
// Tabulator 초기화
|
|
fn_initGrid();
|
|
});
|
|
|
|
// Tabulator 그리드 초기화
|
|
function fn_initGrid() {
|
|
var maxLevel = ${empty MAXLEV ? 1 : MAXLEV};
|
|
|
|
// 컬럼 정의
|
|
var columns = [
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'center',
|
|
width: 60,
|
|
title: '선택',
|
|
field: 'RADIO',
|
|
formatter: function(cell) {
|
|
var rowData = cell.getData();
|
|
return '<input type="radio" name="checkedPartNo" value="' + rowData.CHILD_OBJID + '" ' +
|
|
'data-OBJID="' + rowData.OBJID + '" ' +
|
|
'data-PART_NO="' + rowData.PART_NO + '" ' +
|
|
'data-PARENT_PART_NO="' + rowData.PARENT_PART_NO + '" ' +
|
|
'data-PART_NO_QTY="' + rowData.LAST_PART_OBJID + '" ' +
|
|
'data-PARENT_PARTS="' + rowData.PARENT_PARTS + '" ' +
|
|
'data-LAST_PART_OBJID="' + rowData.LAST_PART_OBJID + '" ' +
|
|
'data-PARENT_OBJID="' + rowData.PARENT_OBJID + '" ' +
|
|
'data-PART_OBJID="' + rowData.PART_OBJID + '" ' +
|
|
'data-BOM_LAST_PART_OBJID="' + rowData.BOM_LAST_PART_OBJID + '">';
|
|
},
|
|
cellClick: function(e, cell) {
|
|
var radio = $(e.target);
|
|
if(radio.is(':radio')) {
|
|
selectedRowData = cell.getData();
|
|
// 다른 라디오 버튼 해제
|
|
$('input[name=checkedPartNo]').not(radio).prop('checked', false);
|
|
}
|
|
}
|
|
}
|
|
];
|
|
|
|
// 수준 컬럼 그룹 (헤더는 하나, 서브 컬럼은 여러개)
|
|
var levelColumns = [];
|
|
for(var i = 1; i <= maxLevel; i++) {
|
|
levelColumns.push({
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'center',
|
|
width: 30,
|
|
title: i,
|
|
field: 'LEVEL_' + i,
|
|
formatter: function(cell) {
|
|
return cell.getValue() === '*' ? '*' : '';
|
|
}
|
|
});
|
|
}
|
|
|
|
columns.push({
|
|
title: '수준',
|
|
headerHozAlign: 'center',
|
|
columns: levelColumns
|
|
});
|
|
|
|
// 나머지 컬럼 추가
|
|
columns.push(
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'left',
|
|
width: 150,
|
|
title: '품번',
|
|
field: 'PART_NO',
|
|
formatter: function(cell) {
|
|
var rowData = cell.getData();
|
|
return '<a href="#" onclick="openPartMngPopup(\'' +
|
|
rowData.PART_OBJID + '\',\'' +
|
|
rowData.LAST_PART_OBJID + '\',\'' +
|
|
rowData.CHILD_OBJID + '\',\'' +
|
|
rowData.BOM_LAST_PART_OBJID + '\');">' +
|
|
rowData.PART_NO + '</a>';
|
|
}
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'left',
|
|
width: 200,
|
|
title: '품명',
|
|
field: 'PART_NAME'
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'center',
|
|
width: 60,
|
|
title: '수량',
|
|
field: 'QTY_TEMP',
|
|
editor: function(cell, onRendered, success, cancel) {
|
|
var rowData = cell.getData();
|
|
if(rowData.STATUS === 'adding') {
|
|
var input = $('<input type="text" style="width:100%; text-align:center;" maxlength="3"/>');
|
|
input.val(cell.getValue() || '0');
|
|
input.on('keydown', function(e) {
|
|
if(e.keyCode === 13) {
|
|
success(input.val());
|
|
} else if(e.keyCode === 27) {
|
|
cancel();
|
|
}
|
|
});
|
|
input.on('blur', function() {
|
|
success(input.val());
|
|
});
|
|
return input[0];
|
|
}
|
|
return false;
|
|
},
|
|
cellEdited: function(cell) {
|
|
var rowData = cell.getData();
|
|
fn_saveQty(rowData.CHILD_OBJID, cell.getValue(), rowData.PART_OBJID);
|
|
}
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'center',
|
|
width: 100,
|
|
title: '항목 수량',
|
|
field: 'ITEM_QTY'
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'center',
|
|
width: 60,
|
|
title: '3D',
|
|
field: 'CU01_CNT',
|
|
formatter: function(cell) {
|
|
var rowData = cell.getData();
|
|
var isEmpty = cell.getValue() == 0;
|
|
return '<a href="#" class="File file_' + (isEmpty ? 'empty_' : '') + 'icon" ' +
|
|
'data-OBJID="' + rowData.LAST_PART_OBJID + '" ' +
|
|
'data-docType="3D_CAD" ' +
|
|
'data-docTypeName="3D CAD 첨부파일"></a>';
|
|
}
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'center',
|
|
width: 60,
|
|
title: '2D',
|
|
field: 'CU02_CNT',
|
|
formatter: function(cell) {
|
|
var rowData = cell.getData();
|
|
var isEmpty = cell.getValue() == 0;
|
|
return '<a href="#" class="File file_' + (isEmpty ? 'empty_' : '') + 'icon" ' +
|
|
'data-OBJID="' + rowData.LAST_PART_OBJID + '" ' +
|
|
'data-docType="2D_DRAWING_CAD" ' +
|
|
'data-docTypeName="2D(Drawing) CAD 첨부파일"></a>';
|
|
}
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'center',
|
|
width: 60,
|
|
title: 'PDF',
|
|
field: 'CU03_CNT',
|
|
formatter: function(cell) {
|
|
var rowData = cell.getData();
|
|
var isEmpty = cell.getValue() == 0;
|
|
return '<a href="#" class="File file_' + (isEmpty ? 'empty_' : '') + 'icon" ' +
|
|
'data-OBJID="' + rowData.LAST_PART_OBJID + '" ' +
|
|
'data-docType="2D_PDF_CAD" ' +
|
|
'data-docTypeName="2D(PDF) CAD 첨부파일"></a>';
|
|
}
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'left',
|
|
width: 100,
|
|
title: '재료',
|
|
field: 'MATERIAL'
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'left',
|
|
width: 120,
|
|
title: '열처리경도',
|
|
field: 'HEAT_TREATMENT_HARDNESS'
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'left',
|
|
width: 120,
|
|
title: '열처리방법',
|
|
field: 'HEAT_TREATMENT_METHOD'
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'left',
|
|
width: 120,
|
|
title: '표면처리',
|
|
field: 'SURFACE_TREATMENT'
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'left',
|
|
width: 120,
|
|
title: '공급업체',
|
|
field: 'MAKER'
|
|
},
|
|
{
|
|
headerHozAlign: 'center',
|
|
hozAlign: 'center',
|
|
width: 120,
|
|
title: '범주 이름',
|
|
field: 'PART_TYPE_TITLE'
|
|
}
|
|
);
|
|
|
|
_tabulGrid = new Tabulator("#structureGrid", {
|
|
layout: "fitColumns",
|
|
height: "650px",
|
|
pagination: false,
|
|
columns: columns,
|
|
rowFormatter: function(row) {
|
|
var data = row.getData();
|
|
$(row.getElement()).addClass('level-' + data.LEVEL);
|
|
},
|
|
ajaxURL: "/partMng/getStructureTreeJson.do",
|
|
ajaxParams: {
|
|
objId: "${info.OBJID}",
|
|
bomReportObjId: "${info.OBJID}",
|
|
search_type: "working" // adding 상태 포함해서 조회
|
|
},
|
|
ajaxResponse: function(url, params, response) {
|
|
// 서버 응답 데이터 가공
|
|
var processedData = [];
|
|
if(response && response.length > 0) {
|
|
var maxLevel = response[0].MAX_LEVEL || 1;
|
|
|
|
response.forEach(function(item) {
|
|
// Level 표시를 위한 동적 필드 생성
|
|
for(var i = 1; i <= maxLevel; i++) {
|
|
item['LEVEL_' + i] = (item.LEVEL == i) ? '*' : '';
|
|
}
|
|
processedData.push(item);
|
|
});
|
|
}
|
|
return processedData;
|
|
}
|
|
});
|
|
|
|
// 파일 아이콘 클릭 이벤트 (동적으로 생성된 요소)
|
|
$(document).on('click', '.File', function(e) {
|
|
e.preventDefault();
|
|
var popup_width = 800;
|
|
var popup_height = 335;
|
|
|
|
var objId = $(this).attr("data-OBJID");
|
|
var docType = $(this).attr("data-docType");
|
|
var docTypeName = $(this).attr("data-docTypeName");
|
|
var params = "?targetObjId=" + objId + "&docType=" + docType + "&docTypeName=" + docTypeName;
|
|
var url = "/projectConcept/FileRegistPopup.do" + params;
|
|
|
|
fn_centerPopup(popup_width, popup_height, url);
|
|
});
|
|
}
|
|
|
|
// 수량 저장
|
|
function fn_saveQty(leftObjId, qty, leftQtyParObjId){
|
|
$.ajax({
|
|
url: "/partMng/structureQtySave.do",
|
|
method: 'post',
|
|
data: {
|
|
"BOM_REPORT_OBJID": "${info.OBJID}",
|
|
"CHILD_OBJID": leftObjId,
|
|
"QTY_TEMP": qty,
|
|
"OBJID": leftQtyParObjId
|
|
},
|
|
dataType: 'json',
|
|
success: function(data) {
|
|
if(data.result){
|
|
Swal.fire('저장하였습니다.');
|
|
_tabulGrid.replaceData(); // 그리드 새로고침
|
|
|
|
// 부모 창(E-BOM 목록) 새로고침
|
|
if(window.opener && window.opener.fn_search) {
|
|
window.opener.fn_search();
|
|
}
|
|
}
|
|
},
|
|
error: function(jqxhr, status, error){
|
|
Swal.fire('저장 중 오류가 발생했습니다.');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Part 상세 팝업
|
|
function openPartMngPopup(objId, lastPartObjid, childObjid, BOM_LAST_PART_OBJID){
|
|
var popup_width = 800;
|
|
var popup_height = 500;
|
|
|
|
var hiddenForm = document.hiddenForm;
|
|
var url = "/partMng/partMngFormPopUp.do";
|
|
|
|
if("" != objId){
|
|
url = "/partMng/partMngDetailPopUp.do?ACTION_TYPE=work";
|
|
}
|
|
|
|
var target = "partMngPopUp";
|
|
|
|
fn_centerPopup(popup_width, popup_height, url, target);
|
|
hiddenForm.action = url;
|
|
hiddenForm.OBJID.value = fnc_checkNull(BOM_LAST_PART_OBJID, objId);
|
|
if('working' == '${param.actionType}')
|
|
hiddenForm.OBJID.value = lastPartObjid;
|
|
hiddenForm.LAST_PART_OBJID.value = lastPartObjid;
|
|
hiddenForm.CHILD_OBJID.value = childObjid;
|
|
hiddenForm.target = target;
|
|
hiddenForm.submit();
|
|
}
|
|
|
|
// Excel 다운로드
|
|
function fn_excel() {
|
|
document.form1.actionType.value = "excel";
|
|
var form = document.form1;
|
|
form.action = "/partMng/structurePopupLeft.do";
|
|
form.submit();
|
|
}
|
|
|
|
// 선택된 행 데이터 가져오기 (Center 프레임에서 사용)
|
|
function getSelectedRowData() {
|
|
return selectedRowData;
|
|
}
|
|
|
|
// 필터 적용 함수
|
|
function fn_applyFilter() {
|
|
var partNo = $("#filterPartNo").val().trim();
|
|
var partName = $("#filterPartName").val().trim();
|
|
|
|
// 빈 값이 아닌 필터만 추가
|
|
var filters = [];
|
|
if(partNo) {
|
|
filters.push({field: "PART_NO", type: "like", value: partNo});
|
|
}
|
|
if(partName) {
|
|
filters.push({field: "PART_NAME", type: "like", value: partName});
|
|
}
|
|
|
|
// 필터가 있으면 적용, 없으면 전체 표시
|
|
if(filters.length > 0) {
|
|
_tabulGrid.setFilter(filters);
|
|
} else {
|
|
_tabulGrid.clearFilter();
|
|
}
|
|
}
|
|
|
|
// 필터 초기화 함수
|
|
function fn_resetFilter() {
|
|
$("#filterPartNo").val("");
|
|
$("#filterPartName").val("");
|
|
_tabulGrid.clearFilter();
|
|
}
|
|
|
|
// 도면 업로드 처리 함수
|
|
function fn_uploadDrawingFiles(files) {
|
|
if(!files || files.length === 0) {
|
|
Swal.fire('파일을 선택해주세요.');
|
|
return;
|
|
}
|
|
|
|
// 품번 목록 조회 (현재 BOM의 모든 품번)
|
|
var bomObjId = "${info.OBJID}";
|
|
if(!bomObjId) {
|
|
Swal.fire('BOM 정보를 찾을 수 없습니다.');
|
|
return;
|
|
}
|
|
|
|
// 파일 분류 및 처리
|
|
var filesByType = {
|
|
'3D': [], // stp 파일
|
|
'2D': [], // dwg 파일
|
|
'PDF': [] // pdf 파일
|
|
};
|
|
|
|
// 파일 확장자 확인 및 분류
|
|
for(var i = 0; i < files.length; i++) {
|
|
var file = files[i];
|
|
var fileName = file.name;
|
|
var lastDotIndex = fileName.lastIndexOf('.');
|
|
|
|
if(lastDotIndex === -1) {
|
|
continue; // 확장자가 없는 파일은 스킵
|
|
}
|
|
|
|
var ext = fileName.substring(lastDotIndex + 1).toLowerCase();
|
|
|
|
console.log('파일명: ' + fileName + ', 확장자: ' + ext); // 디버깅용
|
|
|
|
if(ext === 'stp' || ext === 'step') {
|
|
filesByType['3D'].push(file);
|
|
} else if(ext === 'dwg') {
|
|
filesByType['2D'].push(file);
|
|
} else if(ext === 'pdf') {
|
|
filesByType['PDF'].push(file);
|
|
}
|
|
}
|
|
|
|
// 업로드할 파일이 있는지 확인
|
|
var totalFiles = filesByType['3D'].length + filesByType['2D'].length + filesByType['PDF'].length;
|
|
if(totalFiles === 0) {
|
|
Swal.fire('업로드 가능한 파일 형식이 없습니다. (stp, dwg, pdf만 가능)');
|
|
return;
|
|
}
|
|
|
|
// 확인 메시지
|
|
var msg = '총 ' + totalFiles + '개의 파일을 업로드하시겠습니까?\n';
|
|
msg += '- 3D (STP): ' + filesByType['3D'].length + '개\n';
|
|
msg += '- 2D (DWG): ' + filesByType['2D'].length + '개\n';
|
|
msg += '- PDF: ' + filesByType['PDF'].length + '개';
|
|
|
|
Swal.fire({
|
|
title: '도면 다증 업로드',
|
|
text: msg,
|
|
icon: 'question',
|
|
showCancelButton: true,
|
|
confirmButtonText: '업로드',
|
|
cancelButtonText: '취소'
|
|
}).then(function(result) {
|
|
if(result.isConfirmed) {
|
|
fn_processDrawingUpload(bomObjId, filesByType);
|
|
}
|
|
});
|
|
}
|
|
|
|
// 실제 업로드 처리
|
|
function fn_processDrawingUpload(bomObjId, filesByType) {
|
|
// FormData 생성
|
|
var formData = new FormData();
|
|
formData.append('bomObjId', bomObjId);
|
|
|
|
// 모든 파일을 files 이름으로 추가 (MultipartRequest가 처리)
|
|
var allFiles = filesByType['3D'].concat(filesByType['2D']).concat(filesByType['PDF']);
|
|
for(var i = 0; i < allFiles.length; i++) {
|
|
formData.append('files', allFiles[i]);
|
|
}
|
|
|
|
// 로딩 표시 (구버전 SweetAlert2)
|
|
Swal.fire({
|
|
title: '업로드 중...',
|
|
text: '파일을 업로드하는 중입니다. 잠시만 기다려주세요.',
|
|
allowOutsideClick: false,
|
|
allowEscapeKey: false,
|
|
allowEnterKey: false,
|
|
showConfirmButton: false,
|
|
onOpen: function() {
|
|
Swal.showLoading();
|
|
}
|
|
});
|
|
|
|
// AJAX 업로드
|
|
$.ajax({
|
|
url: '/partMng/uploadDrawingFiles.do',
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: function(response) {
|
|
Swal.close();
|
|
|
|
if(response.result === 'success') {
|
|
var successMsg = '도면 업로드가 완료되었습니다.\n\n';
|
|
successMsg += '- 성공: ' + response.successCount + '개\n';
|
|
if(response.failCount > 0) {
|
|
successMsg += '- 실패: ' + response.failCount + '개\n';
|
|
}
|
|
if(response.notFoundCount > 0) {
|
|
successMsg += '- 품번 미존재: ' + response.notFoundCount + '개\n';
|
|
}
|
|
|
|
Swal.fire({
|
|
title: '업로드 완료',
|
|
text: successMsg,
|
|
icon: response.failCount > 0 ? 'warning' : 'success'
|
|
}).then(function() {
|
|
// 그리드 새로고침
|
|
_tabulGrid.replaceData();
|
|
// 파일 input 초기화
|
|
$("#drawingFiles").val('');
|
|
});
|
|
} else {
|
|
Swal.fire({
|
|
title: '업로드 실패',
|
|
text: response.message || '도면 업로드 중 오류가 발생했습니다.',
|
|
icon: 'error'
|
|
});
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
Swal.close();
|
|
console.error('Upload error:', error);
|
|
console.error('Response:', xhr.responseText);
|
|
Swal.fire({
|
|
title: '업로드 실패',
|
|
text: '서버 오류가 발생했습니다: ' + error,
|
|
icon: 'error'
|
|
});
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
</head>
|
|
<body class="backcolor">
|
|
<form name="hiddenForm" id="hiddenForm" method="post">
|
|
<input type="hidden" name="OBJID" id="OBJID">
|
|
<input type="hidden" name="LAST_PART_OBJID" id="LAST_PART_OBJID">
|
|
<input type="hidden" name="CHILD_OBJID" id="CHILD_OBJID">
|
|
</form>
|
|
|
|
<form name="form1" action="" method="post" onsubmit="return false;">
|
|
<input type="hidden" name="objid" id="objid" value="${info.OBJID}" />
|
|
<input type="hidden" name="objId" id="objId" value="${info.OBJID}" />
|
|
<input type="hidden" name="actionType" value="" />
|
|
<!-- 필터 값을 저장하기 위한 hidden 필드 (top frame에서 값 전달) -->
|
|
<input type="hidden" id="filterPartNo" />
|
|
<input type="hidden" id="filterPartName" />
|
|
<div id="structureTableWrap1">
|
|
<div id="structureName">
|
|
<span style="font-weight: bold; color: #333;">
|
|
<c:choose>
|
|
<c:when test="${not empty info.PART_NO}">
|
|
${info.PART_NO}
|
|
</c:when>
|
|
<c:otherwise>
|
|
(${info.CUSTOMER_NAME}_${info.CUSTOMER_PROJECT_NAME}_${info.UNIT_NAME})_${info.REVISION}
|
|
</c:otherwise>
|
|
</c:choose>
|
|
</span>
|
|
<input type="button" value="Excel Download" class="plm_btns structure_btn" id="btnExcel" style="float:right;">
|
|
<input type="button" value="도면 다중 업로드" class="plm_btns structure_btn" id="btnDrawingUpload" style="float:right; margin-right:5px;">
|
|
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.pdf">
|
|
</div>
|
|
<div id="structureGrid"></div>
|
|
</div>
|
|
</form>
|
|
</body>
|
|
</html>
|