Compare commits

..

9 Commits

9 changed files with 353 additions and 103 deletions

View File

@@ -3197,4 +3197,12 @@ SELECT option_objid::VARCHAR AS CODE
ORDER BY CODE_ID
</select>
<!-- 사용자 권한 체크 -->
<select id="checkUserAuthority" parameterType="map" resultType="int">
SELECT COUNT(*)
FROM AUTHORITY_SUB_USER
WHERE USER_ID = #{userId}
AND MASTER_OBJID::varchar = #{masterObjid}
</select>
</mapper>

View File

@@ -149,7 +149,7 @@ String connector = person.getUserId();
},
*/
//{headerHozAlign : 'center', hozAlign : 'left', width : '125', title : '모품번', field : 'PARENT_PART_INFO' },
{headerHozAlign : 'center', hozAlign : 'left', width : '200', title : '품번', field : 'PART_NO',
{headerHozAlign : 'center', hozAlign : 'left', width : '250', title : '품번', field : 'PART_NO',
formatter:fnc_createGridAnchorTag,
cellClick:function(e, cell){
var objid = fnc_checkNull(cell.getData().OBJID);
@@ -185,11 +185,11 @@ String connector = person.getUserId();
fnc_fileDetailPopup(objid, docType, docTypeName);
}
},
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '재료', field : 'MATERIAL' },
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '열처리경도', field : 'HEAT_TREATMENT_HARDNESS' },
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '열처리방법', field : 'HEAT_TREATMENT_METHOD' },
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '표면처리', field : 'SURFACE_TREATMENT' },
{headerHozAlign : 'center', hozAlign : 'center', width : '150', title : '공급업체', field : 'MAKER' },
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '재료', field : 'MATERIAL' },
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '열처리경도', field : 'HEAT_TREATMENT_HARDNESS' },
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '열처리방법', field : 'HEAT_TREATMENT_METHOD' },
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '표면처리', field : 'SURFACE_TREATMENT' },
{headerHozAlign : 'center', hozAlign : 'center', width : '150', title : '메이커', field : 'MAKER' },
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '범주 이름', field : 'PART_TYPE_TITLE' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '90', title : '재질', field : 'MATERIAL' },
@@ -198,11 +198,11 @@ String connector = person.getUserId();
// {headerHozAlign : 'center', hozAlign : 'center', width : '80', title : 'MAKER', field : 'MAKER' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '80', title : '대분류', field : 'MAJOR_CATEGORY' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '80', title : '중분류', field : 'SUB_CATEGORY' },
{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'Revision', field : 'REVISION' },
{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'EO No', field : 'EO_NO' },
{headerHozAlign : 'center', hozAlign : 'center', width : '80', title : 'EO Date', field : 'EO_DATE' },
//{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'Revision', field : 'REVISION' },
//{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'EO No', field : 'EO_NO' },
//{headerHozAlign : 'center', hozAlign : 'center', width : '80', title : 'EO Date', field : 'EO_DATE' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '88', title : 'PART구분', field : 'PART_TYPE_TITLE' },
{headerHozAlign : 'center', hozAlign : 'center', width : '80', title : '비고', field : 'REMARK' }
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '비고', field : 'REMARK' }
];
//var grid;
@@ -325,7 +325,7 @@ String connector = person.getUserId();
// 파일 분류 및 처리
var filesByType = {
'3D': [], // stp 파일
'2D': [], // dwg 파일
'2D': [], // dwg, dxf 파일
'PDF': [] // pdf 파일
};
@@ -343,7 +343,7 @@ String connector = person.getUserId();
if(ext === 'stp' || ext === 'step') {
filesByType['3D'].push(file);
} else if(ext === 'dwg') {
} else if(ext === 'dwg' || ext === 'dxf') {
filesByType['2D'].push(file);
} else if(ext === 'pdf') {
filesByType['PDF'].push(file);
@@ -353,14 +353,14 @@ String connector = person.getUserId();
// 업로드할 파일이 있는지 확인
var totalFiles = filesByType['3D'].length + filesByType['2D'].length + filesByType['PDF'].length;
if(totalFiles === 0) {
Swal.fire('업로드 가능한 파일 형식이 없습니다. (stp, dwg, pdf만 가능)');
Swal.fire('업로드 가능한 파일 형식이 없습니다. (stp, dwg, dxf, pdf만 가능)');
return;
}
// 확인 메시지
var msg = '총 ' + totalFiles + '개의 파일을 업로드하시겠습니까?\n';
msg += '- 3D (STP): ' + filesByType['3D'].length + '개\n';
msg += '- 2D (DWG): ' + filesByType['2D'].length + '개\n';
msg += '- 2D (DWG/DXF): ' + filesByType['2D'].length + '개\n';
msg += '- PDF: ' + filesByType['PDF'].length + '개';
Swal.fire({
@@ -495,7 +495,7 @@ String connector = person.getUserId();
<input type="button" value="도면 다중 업로드" class="plm_btns" id="btnDrawingUpload">
<input type="button" value="조회" class="plm_btns" id="btnSearch">
<input type="button" value="Excel Download" class="plm_btns" id="btnExcel">
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.pdf">
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.dxf,.pdf">
</div>
</div>
<div id="plmSearchZon">

View File

@@ -141,7 +141,7 @@ ui-jqgrid tr.jqgrow td {
// {headerHozAlign : 'center', hozAlign : 'center', width : '60', title : '순', field : 'RNUM' ,frozen:true},
// {headerHozAlign : 'center', hozAlign : 'left', width : '125', title : '모품번', field : 'PARENT_PART_INFO' ,frozen:true},
{headerHozAlign : 'center', hozAlign : 'left', width : '200', title : '품번', field : 'PART_NO',frozen:true,
{headerHozAlign : 'center', hozAlign : 'left', width : '250', title : '품번', field : 'PART_NO',frozen:true,
formatter:fnc_createGridAnchorTag,
cellClick:function(e, cell){
var objid = fnc_checkNull(cell.getData().OBJID);
@@ -177,11 +177,11 @@ ui-jqgrid tr.jqgrow td {
fn_FileRegist(objid, docType, docTypeName);
}
},
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '재료', field : 'MATERIAL' },
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '열처리경도', field : 'HEAT_TREATMENT_HARDNESS' },
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '열처리방법', field : 'HEAT_TREATMENT_METHOD' },
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '표면처리', field : 'SURFACE_TREATMENT' },
{headerHozAlign : 'center', hozAlign : 'center', width : '150', title : '공급업체', field : 'MAKER' },
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '재료', field : 'MATERIAL' },
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '열처리경도', field : 'HEAT_TREATMENT_HARDNESS' },
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '열처리방법', field : 'HEAT_TREATMENT_METHOD' },
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '표면처리', field : 'SURFACE_TREATMENT' },
{headerHozAlign : 'center', hozAlign : 'center', width : '150', title : '메이커', field : 'MAKER' },
{headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '범주 이름', field : 'PART_TYPE_TITLE' },
// {headerHozAlign : 'center', hozAlign : 'left', width : '190', title : '사양(규격)', field : 'SPEC' },
@@ -189,11 +189,11 @@ ui-jqgrid tr.jqgrow td {
// {headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'MAKER', field : 'MAKER' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '대분류', field : 'MAJOR_CATEGORY' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '중분류', field : 'SUB_CATEGORY' },
{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'Revision', field : 'REVISION' },
{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'EO No', field : 'EO_NO' },
{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'EO Date', field : 'EO_DATE' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'Revision', field : 'REVISION' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'EO No', field : 'EO_NO' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'EO Date', field : 'EO_DATE' },
// {headerHozAlign : 'center', hozAlign : 'center', width : '90', title : 'PART 구분', field : 'PART_TYPE_TITLE' },
{headerHozAlign : 'center', hozAlign : 'center', width : '90', title : '비고', field : 'REMARK' }
{headerHozAlign : 'center', hozAlign : 'center', width : '120', title : '비고', field : 'REMARK' }
];
// 중복 요청 방지 플래그
@@ -430,7 +430,7 @@ ui-jqgrid tr.jqgrow td {
// 파일 분류 및 처리
var filesByType = {
'3D': [], // stp 파일
'2D': [], // dwg 파일
'2D': [], // dwg, dxf 파일
'PDF': [] // pdf 파일
};
@@ -448,7 +448,7 @@ ui-jqgrid tr.jqgrow td {
if(ext === 'stp' || ext === 'step') {
filesByType['3D'].push(file);
} else if(ext === 'dwg') {
} else if(ext === 'dwg' || ext === 'dxf') {
filesByType['2D'].push(file);
} else if(ext === 'pdf') {
filesByType['PDF'].push(file);
@@ -458,14 +458,14 @@ ui-jqgrid tr.jqgrow td {
// 업로드할 파일이 있는지 확인
var totalFiles = filesByType['3D'].length + filesByType['2D'].length + filesByType['PDF'].length;
if(totalFiles === 0) {
Swal.fire('업로드 가능한 파일 형식이 없습니다. (stp, dwg, pdf만 가능)');
Swal.fire('업로드 가능한 파일 형식이 없습니다. (stp, dwg, dxf, pdf만 가능)');
return;
}
// 확인 메시지
var msg = '총 ' + totalFiles + '개의 파일을 업로드하시겠습니까?\n';
msg += '- 3D (STP): ' + filesByType['3D'].length + '개\n';
msg += '- 2D (DWG): ' + filesByType['2D'].length + '개\n';
msg += '- 2D (DWG/DXF): ' + filesByType['2D'].length + '개\n';
msg += '- PDF: ' + filesByType['PDF'].length + '개';
Swal.fire({
@@ -615,7 +615,7 @@ ui-jqgrid tr.jqgrow td {
<input type="button" value="등록(Excel Upload)" class="plm_btns" onclick="openExcelPopup();">
<input type="button" value="도면 다중 업로드" class="plm_btns" id="btnDrawingUpload">
<input type="button" value="조회" class="plm_btns" id="btnSearch">
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.pdf">
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.dxf,.pdf">
</div>
</div>

View File

@@ -2,7 +2,27 @@
<%@ page import="com.pms.common.utils.*"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ page import="java.util.*" %>
<%@include file= "/init.jsp" %>
<%@include file= "/init.jsp" %>
<%
// 권한 체크: AUTHORITY_MASTER의 OBJID가 41000668인 그룹에 속한 사용자인지 확인
boolean hasStatusChangeAuth = false;
try {
org.apache.ibatis.session.SqlSession sqlSession = com.pms.common.SqlMapConfig.getInstance().getSqlSession();
java.util.Map<String, Object> authParam = new java.util.HashMap<String, Object>();
authParam.put("userId", connectUserId);
authParam.put("masterObjid", "41000668");
Integer authCount = (Integer)sqlSession.selectOne("common.checkUserAuthority", authParam);
hasStatusChangeAuth = (authCount != null && authCount > 0);
sqlSession.close();
} catch(Exception e) {
e.printStackTrace();
}
%>
<script>
var hasStatusChangeAuth = <%=hasStatusChangeAuth%>;
</script>
<!DOCTYPE html>
<html>
<head>
@@ -165,8 +185,8 @@ var columns = [
{headerHozAlign : 'center', hozAlign : 'center', width : '150', title : 'E-BOM', field : 'BOM_CNT',
formatter: fnc_subInfoValueFormatter,
cellClick:function(e, cell){
var objId = fnc_checkNull(cell.getData().OBJID);
//var bomReportObjId = fnc_checkNull(cell.getData().BOM_REPORMECHANICAL_TYPET_OBJID);
var objId = fnc_checkNull(cell.getData().OBJID);
// 바로 팝업 열기 (팝업창 내부에서 경고 처리)
fn_openSetStructure(objId);
}
},
@@ -498,6 +518,16 @@ function fn_openChangeDesignNote(objId){
* 상태변경 팝업
*/
function fn_openStatusChange() {
// 권한 체크
if(!hasStatusChangeAuth) {
Swal.fire({
title: '권한 없음',
text: '상태변경 권한이 없습니다.',
icon: 'error'
});
return false;
}
var selectedStructure = _tabulGrid.getSelectedData();
if(selectedStructure.length == 0){
@@ -512,8 +542,33 @@ function fn_openStatusChange() {
var selectedData = selectedStructure[0];
var objId = fnc_checkNull(selectedData.OBJID);
var partNo = fnc_checkNull(selectedData.PART_NO);
var partName = fnc_checkNull(selectedData.PART_NAME);
var currentStatus = fnc_checkNull(selectedData.STATUS);
window.open("/partMng/structureStatusChangePopup.do?objId=" + objId, "structureStatusChangePopup", "width=500, height=300, resizable=no");
// 현재 상태 표시용 텍스트 (Y/N만 존재)
var statusText = (currentStatus === 'Y') ? 'Y' : 'N';
// 상태변경 확인 경고
Swal.fire({
title: 'E-BOM 상태 변경',
html: 'E-BOM의 상태변경을 진행하시겠습니까?<br><br>' +
'<strong>품번:</strong> ' + partNo + '<br>' +
'<strong>품명:</strong> ' + partName + '<br>' +
'<strong>현재 상태:</strong> ' + statusText + '<br><br>' +
'상태를 변경하시겠습니까?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '상태변경',
cancelButtonText: '취소',
reverseButtons: false
}).then(result => {
if (result.isConfirmed) {
window.open("/partMng/structureStatusChangePopup.do?objId=" + objId, "structureStatusChangePopup", "width=500, height=300, resizable=no");
}
});
}
function saveexcelpop() {
@@ -552,21 +607,40 @@ function saveexcelpop() {
BOM_VERSION = fnc_checkNull(selectedStructure[i].REVISION);
}
// hiddenForm을 사용하여 POST 방식으로 팝업 열기 (한글 인코딩 문제 해결)
var hiddenForm = document.hiddenForm;
var url = "/partMng/openBomReportExcelImportPopUp.do";
var target = "openBomReportExcelImportPopUp";
hiddenForm.PRODUCT_CD.value = BOM_PRODUCT_CD;
hiddenForm.BOM_PART_NAME.value = BOM_PART_NAME;
hiddenForm.BOM_PART_NO.value = BOM_PART_NO;
hiddenForm.BOM_REPORT_OBJID.value = BOM_REPORT_OBJID;
hiddenForm.BOM_VERSION.value = BOM_VERSION;
window.open('', target, 'width=1920, height=860, menubars=no, scrollbars=yes, resizable=yes');
hiddenForm.action = url;
hiddenForm.target = target;
hiddenForm.submit();
// CSV 업로드 확인 경고
Swal.fire({
title: 'E-BOM CSV 업로드',
html: 'CSV 파일을 통해 E-BOM 데이터를 새로 등록합니다.<br><br>' +
'<strong>품번:</strong> ' + BOM_PART_NO + '<br>' +
'<strong>품명:</strong> ' + BOM_PART_NAME + '<br>' +
'<strong>버전:</strong> ' + BOM_VERSION + '<br><br>' +
'계속하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '계속',
cancelButtonText: '취소',
reverseButtons: false
}).then(result => {
if (result.isConfirmed) {
// hiddenForm을 사용하여 POST 방식으로 팝업 열기 (한글 인코딩 문제 해결)
var hiddenForm = document.hiddenForm;
var url = "/partMng/openBomReportExcelImportPopUp.do";
var target = "openBomReportExcelImportPopUp";
hiddenForm.PRODUCT_CD.value = BOM_PRODUCT_CD;
hiddenForm.BOM_PART_NAME.value = BOM_PART_NAME;
hiddenForm.BOM_PART_NO.value = BOM_PART_NO;
hiddenForm.BOM_REPORT_OBJID.value = BOM_REPORT_OBJID;
hiddenForm.BOM_VERSION.value = BOM_VERSION;
window.open('', target, 'width=1920, height=860, menubars=no, scrollbars=yes, resizable=yes');
hiddenForm.action = url;
hiddenForm.target = target;
hiddenForm.submit();
}
});
}
}else{
if($("#customer_cd").val()==""){

View File

@@ -6,8 +6,34 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<title><%=Constants.SYSTEM_NAME%></title>
<script>
// confirm/alert 헬퍼 함수
function showConfirm(options) {
if(typeof options === 'string') {
alert(options);
return Promise.resolve({isConfirmed: true});
}
var message = '';
if(options.title) message += options.title + '\n\n';
if(options.html) {
// HTML 태그 제거
message += options.html.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]+>/g, '');
} else if(options.text) {
message += options.text;
}
if(options.showCancelButton !== false && (options.icon === 'warning' || options.icon === 'question')) {
var result = confirm(message);
return Promise.resolve({isConfirmed: result});
} else {
alert(message);
return Promise.resolve({isConfirmed: true});
}
}
$(function(){
$('.select2').select2();
@@ -19,7 +45,7 @@ $(function(){
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
if(rightSelectedRows.length === 0) {
alert("선택된 파트가 없습니다.");
showConfirm("선택된 파트가 없습니다.");
return false;
}
@@ -50,7 +76,11 @@ $(function(){
var rowData = rightSelectedRows[i].getData();
var rightPartNo = rowData.PART_NO;
if(rightPartNo == leftPartNo){
alert("오류 Part No : ["+rightPartNo+"]\n같은 Part No끼리 연결할 수 없습니다.");
showConfirm({
title: '연결 불가',
html: '오류 Part No : <strong>['+rightPartNo+']</strong><br>같은 Part No끼리 연결할 수 없습니다.',
icon: 'error'
});
isSamePart = true;
break;
}
@@ -73,7 +103,11 @@ $(function(){
if("unique" == rightPartType){
for(var j = 0 ; j < deniedPartArr.length ; j++){
if(rightPartNo == deniedPartArr[j]){
alert("오류 Part No : "+"["+rightPartNo+"]\n이미 상위에 등록된 Part No 입니다.");
showConfirm({
title: '연결 불가',
html: '오류 Part No : <strong>['+rightPartNo+']</strong><br>이미 상위에 등록된 Part No 입니다.',
icon: 'error'
});
isDeniedPart = true;
break;
}
@@ -94,12 +128,31 @@ $(function(){
if(fnc_checkNull(leftPartNo) == ""){
var flag = fn_checkSameTopPartNo(rightCheckedArr);
if(flag == "true"){
alert("1레벨에 같은 Part No가 중복 등록될 수 없습니다.");
showConfirm({
title: '중복 등록 불가',
text: '1레벨에 같은 Part No가 중복 등록될 수 없습니다.',
icon: 'error'
});
return;
}
}
fn_relatePartInfo(leftPartChildObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
// Part 연결 확인
showConfirm({
title: 'Part 연결',
text: '선택한 Part를 연결하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '연결',
cancelButtonText: '취소',
reverseButtons: false
}).then(result => {
if (result.isConfirmed) {
fn_relatePartInfo(leftPartChildObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
}
});
});
//end of Part 연결
@@ -121,12 +174,12 @@ $(function(){
var leftPartNoList = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
if(leftPartNoList.length === 0){
alert("선택된 파트가 없습니다.");
showConfirm("선택된 파트가 없습니다.");
return false;
}
if(leftPartNoList.length > 1){
alert("한번에 1개의 파트만 변경가능합니다.");
showConfirm("한번에 1개의 파트만 변경가능합니다.");
return false;
}
@@ -141,12 +194,12 @@ $(function(){
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
if(rightSelectedRows.length === 0){
alert("선택된 파트가 없습니다.");
showConfirm("선택된 파트가 없습니다.");
return false;
}
if(rightSelectedRows.length > 1){
alert("한번에 1개의 파트만 변경가능합니다.");
showConfirm("한번에 1개의 파트만 변경가능합니다.");
return false;
}
@@ -155,7 +208,24 @@ $(function(){
var rightPartRev = rightRowData.REVISION || "";
var rightObjId = rightRowData.OBJID;
fn_changeRelatePartInfo(leftPartBomQtyObjId, rightObjId, leftPartChildObjId, leftParentPartObjid, leftPartChildObjId, leftPartObjid, rightPartNo, rightPartRev);
// Part 변경 확인
showConfirm({
title: 'Part 변경',
html: '선택한 Part를 변경하시겠습니까?<br><br>' +
'<strong>기존:</strong> ' + leftPartNo + '<br>' +
'<strong>변경:</strong> ' + rightPartNo,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '변경',
cancelButtonText: '취소',
reverseButtons: false
}).then(result => {
if (result.isConfirmed) {
fn_changeRelatePartInfo(leftPartBomQtyObjId, rightObjId, leftPartChildObjId, leftParentPartObjid, leftPartChildObjId, leftPartObjid, rightPartNo, rightPartRev);
}
});
});
});
@@ -187,11 +257,29 @@ function fn_checkSameTopPartNo(rightCheckedArr){
//구조 연결 해제
function fn_deletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId){
if(leftObjId == null){
alert("연결 해제할 Part를 선택해 주시기 바랍니다.")
showConfirm("연결 해제할 Part를 선택해 주시기 바랍니다.");
return;
}
if(!confirm("연결 해제하시겠습니까?")) return;
showConfirm({
title: 'Part 연결 해제',
text: '선택한 Part의 연결을 해제하시겠습니까?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '연결 해제',
cancelButtonText: '취소',
reverseButtons: false
}).then(result => {
if (!result.isConfirmed) return;
fn_executeDeletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId);
});
}
// 실제 Part 연결 해제 실행 함수
function fn_executeDeletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId){
$.ajax({
url: "/partMng/deleteStatusPartRelateInfo.do",
@@ -222,16 +310,35 @@ function fn_deletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo,
//구조 연결
function fn_relatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId){
if(typeof rightCheckedArr != "undefined" && rightCheckedArr.length == 0){
alert("선택된 Part가 없습니다.");
showConfirm("선택된 Part가 없습니다.");
return;
}
if(leftObjId == null){
if(!confirm("좌측에 선택된 Part정보가 없습니다.\n이대로 연결하면 1레벨로 등록됩니다.\n진행하시겠습니까?")){
return;
}
showConfirm({
title: '1레벨 등록 확인',
html: '좌측에 선택된 Part정보가 없습니다.<br>이대로 연결하면 1레벨로 등록됩니다.<br><br>진행하시겠습니까?',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '진행',
cancelButtonText: '취소',
reverseButtons: false
}).then(result => {
if (result.isConfirmed) {
fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
}
});
return;
}
fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
}
// 실제 Part 연결 실행 함수
function fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId){
$.ajax({
url: "/partMng/relatePartInfo.do",
method: 'post',

View File

@@ -438,7 +438,7 @@ function fn_uploadDrawingFiles(files) {
// 파일 분류 및 처리
var filesByType = {
'3D': [], // stp 파일
'2D': [], // dwg 파일
'2D': [], // dwg, dxf 파일
'PDF': [] // pdf 파일
};
@@ -458,24 +458,24 @@ function fn_uploadDrawingFiles(files) {
if(ext === 'stp' || ext === 'step') {
filesByType['3D'].push(file);
} else if(ext === 'dwg') {
} else if(ext === 'dwg' || ext === 'dxf') {
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만 가능)');
Swal.fire('업로드 가능한 파일 형식이 없습니다. (stp, dwg, dxf, pdf만 가능)');
return;
}
// 확인 메시지
var msg = '총 ' + totalFiles + '개의 파일을 업로드하시겠습니까?\n';
msg += '- 3D (STP): ' + filesByType['3D'].length + '개\n';
msg += '- 2D (DWG): ' + filesByType['2D'].length + '개\n';
msg += '- 2D (DWG/DXF): ' + filesByType['2D'].length + '개\n';
msg += '- PDF: ' + filesByType['PDF'].length + '개';
Swal.fire({
@@ -597,7 +597,7 @@ function fn_processDrawingUpload(bomObjId, filesByType) {
</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">
<input type="file" id="drawingFiles" multiple style="display:none;" accept=".stp,.step,.dwg,.dxf,.pdf">
</div>
<div id="structureGrid"></div>
</div>

View File

@@ -2242,6 +2242,19 @@ public class PartMngController {
String fileExt = CommonUtils.checkNull((String)fileInfo.get("fileExt"));
long fileSize = Long.parseLong(CommonUtils.checkNull(fileInfo.get("fileSize"), "0"));
// 파일 크기가 0이면 실제 저장된 파일에서 다시 확인
// if(fileSize == 0) {
// try {
// File savedFile = new File(storagePath + File.separator + savedFileName);
// if(savedFile.exists()) {
// fileSize = savedFile.length();
// System.out.println("파일 크기 재확인: " + fileSize + " bytes");
// }
// } catch(Exception e) {
// System.out.println("파일 크기 재확인 실패: " + e.getMessage());
// }
// }
// 확장자 대문자 변환 (이미 점 없이 저장됨)
fileExt = fileExt.toUpperCase();
@@ -2249,6 +2262,7 @@ public class PartMngController {
System.out.println("원본 파일명: " + originalFileName);
System.out.println("저장 파일명: " + savedFileName);
System.out.println("확장자: " + fileExt);
System.out.println("파일 크기: " + fileSize + " bytes");
System.out.println("===================================");
// 파일 확장자에 따른 문서 타입 결정
@@ -2258,7 +2272,7 @@ public class PartMngController {
if("STP".equals(fileExt) || "STEP".equals(fileExt)) {
docType = "3D_CAD";
docTypeName = "3D CAD 첨부파일";
} else if("DWG".equals(fileExt)) {
} else if("DWG".equals(fileExt) || "DXF".equals(fileExt)){
docType = "2D_DRAWING_CAD";
docTypeName = "2D(Drawing) CAD 첨부파일";
} else if("PDF".equals(fileExt)) {
@@ -2432,6 +2446,19 @@ public class PartMngController {
String fileExt = CommonUtils.checkNull((String)fileInfo.get("fileExt"));
long fileSize = Long.parseLong(CommonUtils.checkNull(fileInfo.get("fileSize"), "0"));
// 파일 크기가 0이면 실제 저장된 파일에서 다시 확인
// if(fileSize == 0) {
// try {
// File savedFile = new File(storagePath + File.separator + savedFileName);
// if(savedFile.exists()) {
// fileSize = savedFile.length();
// System.out.println("파일 크기 재확인: " + fileSize + " bytes");
// }
// } catch(Exception e) {
// System.out.println("파일 크기 재확인 실패: " + e.getMessage());
// }
// }
// 확장자 대문자 변환
fileExt = fileExt.toUpperCase();
@@ -2439,6 +2466,7 @@ public class PartMngController {
System.out.println("원본 파일명: " + originalFileName);
System.out.println("저장 파일명: " + savedFileName);
System.out.println("확장자: " + fileExt);
System.out.println("파일 크기: " + fileSize + " bytes");
System.out.println("==========================================");
// 파일 확장자에 따른 문서 타입 결정
@@ -2448,7 +2476,7 @@ public class PartMngController {
if("STP".equals(fileExt) || "STEP".equals(fileExt)) {
docType = "3D_CAD";
docTypeName = "3D CAD 첨부파일";
} else if("DWG".equals(fileExt)) {
} else if("DWG".equals(fileExt) || "DXF".equals(fileExt)) {
docType = "2D_DRAWING_CAD";
docTypeName = "2D(Drawing) CAD 첨부파일";
} else if("PDF".equals(fileExt)) {

View File

@@ -3197,4 +3197,12 @@ SELECT option_objid::VARCHAR AS CODE
ORDER BY CODE_ID
</select>
<!-- 사용자 권한 체크 -->
<select id="checkUserAuthority" parameterType="map" resultType="int">
SELECT COUNT(*)
FROM AUTHORITY_SUB_USER
WHERE USER_ID = #{userId}
AND MASTER_OBJID::varchar = #{masterObjid}
</select>
</mapper>

View File

@@ -3157,40 +3157,50 @@ public class PartMngService extends BaseService {
// 시도할 인코딩 목록 (Windows Excel CSV 기본 인코딩 우선)
String[] encodings = {"CP949", "UTF-8", "EUC-KR", "MS949"};
String bestEncoding = "UTF-8"; // 기본값
int minReplacementChars = Integer.MAX_VALUE;
for (String encoding : encodings) {
try (FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis, encoding);
BufferedReader br = new BufferedReader(isr)) {
// 처음 몇 줄을 읽어서 깨진 문자 여부 확인
// 처음 몇 줄을 읽어서 깨진 문자 개수 확인
String line;
int lineCount = 0;
boolean hasBrokenChar = false;
int replacementCharCount = 0;
while ((line = br.readLine()) != null && lineCount < 10) {
// 깨진 문자 검사 (<28> 또는 replacement character)
if (line.contains("\uFFFD") || line.contains("?")) {
hasBrokenChar = true;
break;
// replacement character (\uFFFD) 개수 세기
for (int i = 0; i < line.length(); i++) {
if (line.charAt(i) == '\uFFFD') {
replacementCharCount++;
}
}
lineCount++;
}
// 깨진 문자가 없으면 이 인코딩이 올바른 것으로 판단
if (!hasBrokenChar && lineCount > 0) {
System.out.println("CSV 인코딩 감지 성공: " + encoding);
// 깨진 문자가 없으면 바로 이 인코딩 사용
if (replacementCharCount == 0 && lineCount > 0) {
System.out.println("CSV 인코딩 감지 성공: " + encoding + " (깨진 문자 없음)");
return encoding;
}
// 깨진 문자가 가장 적은 인코딩 기억
if (replacementCharCount < minReplacementChars) {
minReplacementChars = replacementCharCount;
bestEncoding = encoding;
}
} catch (Exception e) {
// 이 인코딩으로 읽기 실패 시 다음 인코딩 시도
continue;
}
}
// 모든 시도 실패 시 기본값 UTF-8 반환
System.out.println("CSV 인코딩 감지 실패, 기본값 UTF-8 사용");
return "UTF-8";
// 가장 적은 깨진 문자를 가진 인코딩 사용
System.out.println("CSV 인코딩 감지 완료: " + bestEncoding + " (replacement chars: " + minReplacementChars + ")");
return bestEncoding;
}
/**
@@ -3334,23 +3344,38 @@ public class PartMngService extends BaseService {
// PART_TYPE 코드 조회
String partTypeCode = "";
if(!StringUtils.isBlank(partType) && rowIndex > 2) {
Map sqlParamMap = new HashMap();
sqlParamMap.put("CODE_NAME", partType);
String partNoForCheck = CommonUtils.checkNull(partNo);
sqlParamMap.put("partNo", partNoForCheck);
Map partTypeMap = sqlSession.selectOne("partMng.parttypeInfo", sqlParamMap);
if(null != partTypeMap && !StringUtils.isBlank((String)partTypeMap.get("code_id"))){
partTypeCode = (String)partTypeMap.get("code_id");
} else {
noteMsg += "부품유형 확인:" + partType + ";";
if(!StringUtils.isBlank(partType)) {
// CSV 영문 범주명을 한글로 변환 (Unassigned→조립품, Buy→구매품, Make→부품)
String partTypeForQuery = partType.trim();
String partTypeUpper = partTypeForQuery.toUpperCase();
if("UNASSIGNED".equals(partTypeUpper)) {
partTypeForQuery = "조립품";
} else if("BUY".equals(partTypeUpper)) {
partTypeForQuery = "구매품";
} else if("MAKE".equals(partTypeUpper)) {
partTypeForQuery = "부품";
}
} else if(!StringUtils.isBlank(partType) && rowIndex <= 2) {
Map sqlParamMap = new HashMap();
sqlParamMap.put("CODE_NAME", partType);
Map partTypeMap = sqlSession.selectOne("partMng.parttypeInfo", sqlParamMap);
if(null != partTypeMap && !StringUtils.isBlank((String)partTypeMap.get("code_id"))){
partTypeCode = (String)partTypeMap.get("code_id");
// 변환된 값으로 DB 조회 (기존 방식)
if(rowIndex > 2) {
Map sqlParamMap = new HashMap();
sqlParamMap.put("CODE_NAME", partTypeForQuery);
String partNoForCheck = CommonUtils.checkNull(partNo);
sqlParamMap.put("partNo", partNoForCheck);
Map partTypeMap = sqlSession.selectOne("partMng.parttypeInfo", sqlParamMap);
if(null != partTypeMap && !StringUtils.isBlank((String)partTypeMap.get("code_id"))){
partTypeCode = (String)partTypeMap.get("code_id");
} else {
noteMsg += "부품유형 확인:" + partType + ";";
}
} else {
Map sqlParamMap = new HashMap();
sqlParamMap.put("CODE_NAME", partTypeForQuery);
Map partTypeMap = sqlSession.selectOne("partMng.parttypeInfo", sqlParamMap);
if(null != partTypeMap && !StringUtils.isBlank((String)partTypeMap.get("code_id"))){
partTypeCode = (String)partTypeMap.get("code_id");
}
}
}