diff --git a/WebContent/WEB-INF/view/common/FileDetailPopup.jsp b/WebContent/WEB-INF/view/common/FileDetailPopup.jsp index 8cd9fc1..474574c 100644 --- a/WebContent/WEB-INF/view/common/FileDetailPopup.jsp +++ b/WebContent/WEB-INF/view/common/FileDetailPopup.jsp @@ -138,7 +138,16 @@ function fileDelete(fileObjId){ dataType:"json", async:true, success:function(data){ - fn_fileCallback("sr","${docType}"); + fn_fileCallback("sr","${docType}"); + // 부모 창의 그리드 새로고침 + if(opener && typeof opener.fn_search == "function"){ + opener.fn_search(); + } + // Tabulator 그리드가 있는 경우 + if(opener && opener._tabulGrid){ + opener._tabulGrid.replaceData(); + } + // 기존 콜백 함수도 실행 if(fnc_checkNull(callbackFnc) != ""){ opener.eval(callbackFnc+"();"); } diff --git a/WebContent/WEB-INF/view/common/FileRegistPopup.jsp b/WebContent/WEB-INF/view/common/FileRegistPopup.jsp index 99431e0..071f60f 100644 --- a/WebContent/WEB-INF/view/common/FileRegistPopup.jsp +++ b/WebContent/WEB-INF/view/common/FileRegistPopup.jsp @@ -164,7 +164,16 @@ function fileDelete(fileObjId){ dataType:"json", async:false, success:function(data){ - fn_fileCallback("sr","${docType}"); + fn_fileCallback("sr","${docType}"); + // 부모 창의 그리드 새로고침 + if(opener && typeof opener.fn_search == "function"){ + opener.fn_search(); + } + // Tabulator 그리드가 있는 경우 + if(opener && opener._tabulGrid){ + opener._tabulGrid.replaceData(); + } + // 기존 콜백 함수도 실행 if(fnc_checkNull(callbackFnc) != ""){ opener.eval(callbackFnc+"();"); } diff --git a/WebContent/WEB-INF/view/partMng/structurePopupLeft.jsp b/WebContent/WEB-INF/view/partMng/structurePopupLeft.jsp index 699053b..ec465ff 100644 --- a/WebContent/WEB-INF/view/partMng/structurePopupLeft.jsp +++ b/WebContent/WEB-INF/view/partMng/structurePopupLeft.jsp @@ -39,27 +39,7 @@ .tabulator-row.level-9 { background-color: #FFFFEB !important; } .tabulator-row.level-10 { background-color: #ffffff !important; } -.file_icon, .file_empty_icon { - display: inline-block; - width: 20px; - height: 20px; - line-height: 20px; - text-align: center; - cursor: pointer; - font-size: 16px; -} -.file_icon { - color: #4CAF50; -} -.file_icon::before { - content: '📄'; -} -.file_empty_icon { - color: #ccc; -} -.file_empty_icon::before { - content: '○'; -} +/* 파일 아이콘 스타일은 basic.css에서 관리 */ @@ -453,12 +590,10 @@ function fn_resetFilter() { - + + + -
- ※수량 변경 후, 엔터치시면 저장됩니다.(신규 추가 파트만 가능) -
-
diff --git a/WebContent/WEB-INF/view/projectConcept/FileRegistPopup.jsp b/WebContent/WEB-INF/view/projectConcept/FileRegistPopup.jsp index 19d2644..216746a 100644 --- a/WebContent/WEB-INF/view/projectConcept/FileRegistPopup.jsp +++ b/WebContent/WEB-INF/view/projectConcept/FileRegistPopup.jsp @@ -35,6 +35,14 @@ $(document).ready(function(){ function refeshAttachFileArea(){ srAreaDraw(); + // 부모 창의 그리드도 새로고침 + if(opener && typeof opener.fn_search == "function"){ + opener.fn_search(); + } + // Tabulator 그리드가 있는 경우 + if(opener && opener._tabulGrid){ + opener._tabulGrid.replaceData(); + } } //형상 영역을 display 한다. @@ -112,7 +120,15 @@ function fileDelete(fileObjId){ dataType:"json", async:true, success:function(data){ - fn_fileCallback("sr","${docType}"); + fn_fileCallback("sr","${docType}"); + // 부모 창의 그리드 새로고침 + if(opener && typeof opener.fn_search == "function"){ + opener.fn_search(); + } + // Tabulator 그리드가 있는 경우 + if(opener && opener._tabulGrid){ + opener._tabulGrid.replaceData(); + } }, error: function(jqxhr, status, error){ } diff --git a/src/com/pms/controller/PartMngController.java b/src/com/pms/controller/PartMngController.java index fc97f02..be6ee74 100644 --- a/src/com/pms/controller/PartMngController.java +++ b/src/com/pms/controller/PartMngController.java @@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.oreilly.servlet.MultipartRequest; +import com.pms.common.FileRenameClass; import com.pms.common.JsonUtil; import com.pms.common.SqlMapConfig; import com.pms.common.bean.PersonBean; @@ -2136,4 +2138,188 @@ public class PartMngController { return "/ajax/ajaxResult"; } + + /** + * 도면 파일 일괄 업로드 + * 파일명에 품번이 포함된 경우 자동 매칭하여 업로드 + * - stp 파일 -> 3D CAD 컬럼 + * - dwg 파일 -> 2D Drawing CAD 컬럼 + * - pdf 파일 -> 2D PDF CAD 컬럼 + * + * @param request + * @param session + * @param bomObjId BOM OBJID + * @return + */ + @RequestMapping(value="/partMng/uploadDrawingFiles.do", method=RequestMethod.POST) + @ResponseBody + public Map uploadDrawingFiles( + HttpServletRequest request, + HttpSession session) { + + Map resultMap = new HashMap<>(); + MultipartRequest multi = null; + FileRenameClass frc = null; + + try { + PersonBean person = (PersonBean)session.getAttribute(Constants.PERSON_BEAN); + String userId = person != null ? person.getUserId() : "plmAdmin"; + + // MultipartRequest로 파일 업로드 처리 + String storagePath = Constants.FILE_STORAGE; + int maxSize = 1024*1024*1024*9; // 9GB + + File storage = new File(storagePath); + if(!storage.exists()) storage.mkdirs(); + + frc = new FileRenameClass(); + multi = new MultipartRequest(request, storagePath, maxSize, "UTF-8", frc); + java.util.List fileList = frc.getFileList(); + + // MultipartRequest에서 bomObjId 파라미터 가져오기 + String bomObjId = multi.getParameter("bomObjId"); + + if(bomObjId == null || bomObjId.isEmpty()) { + resultMap.put("result", "fail"); + resultMap.put("message", "BOM ID가 전달되지 않았습니다."); + return resultMap; + } + + // BOM 정보 조회 + Map bomParam = new HashMap<>(); + bomParam.put("objId", bomObjId); + Map bomInfo = partMngService.getBOMStructureStandardInfo(request, bomParam); + + if(bomInfo == null) { + resultMap.put("result", "fail"); + resultMap.put("message", "BOM 정보를 찾을 수 없습니다."); + return resultMap; + } + + // 해당 BOM의 모든 파트 정보 조회 + bomParam.put("SEARCH_BOM_OBJID", bomObjId); + ArrayList partList = commonService.selectList("partMng.partMngListByBom", request, bomParam); + + if(partList == null || partList.isEmpty()) { + resultMap.put("result", "fail"); + resultMap.put("message", "BOM에 등록된 파트가 없습니다."); + return resultMap; + } + + // 품번 기준 파트 맵 생성 + Map partNoMap = new HashMap<>(); + for(Map part : partList) { + String partNo = CommonUtils.checkNull((String)part.get("PART_NO")); + if(!partNo.isEmpty()) { + partNoMap.put(partNo, part); + } + } + + int successCount = 0; + int failCount = 0; + int notFoundCount = 0; + + // 업로드된 파일 처리 + if(fileList != null && !fileList.isEmpty()) { + for(Object fileObj : fileList) { + Map fileInfo = (Map)fileObj; + String originalFileName = CommonUtils.checkNull((String)fileInfo.get("realFileName")); + String savedFileName = CommonUtils.checkNull((String)fileInfo.get("savedFileName")); + String fileExt = CommonUtils.checkNull((String)fileInfo.get("fileExt")); + long fileSize = Long.parseLong(CommonUtils.checkNull(fileInfo.get("fileSize"), "0")); + + // 확장자 대문자 변환 (이미 점 없이 저장됨) + fileExt = fileExt.toUpperCase(); + + System.out.println("========== 파일 업로드 처리 =========="); + System.out.println("원본 파일명: " + originalFileName); + System.out.println("저장 파일명: " + savedFileName); + System.out.println("확장자: " + fileExt); + System.out.println("==================================="); + + // 파일 확장자에 따른 문서 타입 결정 + String docType = ""; + String docTypeName = ""; + + if("STP".equals(fileExt) || "STEP".equals(fileExt)) { + docType = "3D_CAD"; + docTypeName = "3D CAD 첨부파일"; + } else if("DWG".equals(fileExt)) { + docType = "2D_DRAWING_CAD"; + docTypeName = "2D(Drawing) CAD 첨부파일"; + } else if("PDF".equals(fileExt)) { + docType = "2D_PDF_CAD"; + docTypeName = "2D(PDF) CAD 첨부파일"; + } else { + // 지원하지 않는 확장자는 스킵 + System.out.println("지원하지 않는 확장자: " + fileExt + ", 파일명: " + originalFileName); + continue; + } + + // 파일명에서 품번 찾기 (파일명에 품번이 포함되어 있는 경우) + String matchedPartNo = null; + System.out.println("품번 매칭 시작 - 파일명: " + originalFileName); + for(String partNo : partNoMap.keySet()) { + System.out.println(" 품번 확인: " + partNo + " -> " + (originalFileName.contains(partNo) ? "매칭!" : "미매칭")); + if(originalFileName.contains(partNo)) { + matchedPartNo = partNo; + System.out.println(" ✓ 품번 매칭 성공: " + partNo); + break; + } + } + + if(matchedPartNo == null) { + System.out.println(" ✗ 품번 매칭 실패 - 파일명에서 품번을 찾을 수 없음"); + } + + if(matchedPartNo == null) { + notFoundCount++; + continue; + } + + // 해당 파트에 파일 정보 저장 + Map partInfo = partNoMap.get(matchedPartNo); + String partObjId = CommonUtils.checkNull((String)partInfo.get("OBJID")); + + Map fileMap = new HashMap<>(); + fileMap.put("OBJID", CommonUtils.createObjId()); + fileMap.put("TARGET_OBJID", partObjId); + fileMap.put("SAVED_FILE_NAME", savedFileName); + fileMap.put("REAL_FILE_NAME", originalFileName); + fileMap.put("DOC_TYPE", docType); + fileMap.put("DOC_TYPE_NAME", docTypeName); + fileMap.put("FILE_SIZE", String.valueOf(fileSize)); + fileMap.put("FILE_EXT", fileExt); + fileMap.put("FILE_PATH", storagePath); + fileMap.put("WRITER", userId); + + try { + // 파일 정보 DB 저장 + partMngService.insertDrawingFile(fileMap); + successCount++; + } catch(Exception e) { + e.printStackTrace(); + failCount++; + } + } + } + + resultMap.put("result", "success"); + resultMap.put("successCount", successCount); + resultMap.put("failCount", failCount); + resultMap.put("notFoundCount", notFoundCount); + resultMap.put("message", "업로드가 완료되었습니다."); + + } catch(Exception e) { + e.printStackTrace(); + resultMap.put("result", "error"); + resultMap.put("message", "업로드 중 오류가 발생했습니다: " + e.getMessage()); + } finally { + if(frc != null) { + frc.clear(); + } + } + + return resultMap; + } } diff --git a/src/com/pms/mapper/partMng.xml b/src/com/pms/mapper/partMng.xml index c3840e0..79b5912 100644 --- a/src/com/pms/mapper/partMng.xml +++ b/src/com/pms/mapper/partMng.xml @@ -162,10 +162,10 @@ P.HEAT_TREATMENT_HARDNESS, P.HEAT_TREATMENT_METHOD, P.SURFACE_TREATMENT - ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.DOC_TYPE IN ('3D_CAD')) CU01_CNT - ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) CU02_CNT - ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.DOC_TYPE IN ('2D_PDF_CAD')) CU03_CNT - ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.DOC_TYPE IN ('2D_PDF_CAD','2D_DRAWING_CAD')) CU_TOTAL_CNT + ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) CU01_CNT + ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) CU02_CNT + ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) CU03_CNT + ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD','2D_DRAWING_CAD')) CU_TOTAL_CNT FROM PART_MNG P AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT - ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT - ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT + ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT + ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT + ,(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT ,V.LEV ,(SELECT OBJID FROM VIEW_BOM VT WHERE V.BOM_REPORT_OBJID = VT.BOM_REPORT_OBJID AND VT.LEV = 1 ORDER BY SEQ LIMIT 1) AS ROOT_OBJID diff --git a/src/com/pms/service/PartMngService.java b/src/com/pms/service/PartMngService.java index 1d13470..55e9600 100644 --- a/src/com/pms/service/PartMngService.java +++ b/src/com/pms/service/PartMngService.java @@ -4869,4 +4869,27 @@ public class PartMngService extends BaseService { return result; } + + /** + * 도면 파일 정보 DB 저장 + * @param fileMap 파일 정보 + */ + public void insertDrawingFile(Map fileMap) { + SqlSession sqlSession = null; + try { + sqlSession = SqlMapConfig.getInstance().getSqlSession(false); + sqlSession.insert("partMng.insertpartfileInfo", fileMap); + sqlSession.commit(); + } catch(Exception e) { + e.printStackTrace(); + if(sqlSession != null) { + sqlSession.rollback(); + } + throw e; + } finally { + if(sqlSession != null) { + sqlSession.close(); + } + } + } }