From 546e8e8e029116b772f294b8673cd979b4f9ecea Mon Sep 17 00:00:00 2001 From: hjjeong Date: Thu, 16 Oct 2025 13:24:08 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B2=AC=EC=A0=81=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EB=A9=94=EC=9D=BC=20=EB=B0=9C=EC=86=A1=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20UI=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 견적서 메일 발송 API 추가 (ContractMgmtController, ContractMgmtService) - 견적관리 리스트에 메일 발송 상태 및 발송일시 컬럼 추가 - 메일 내용을 견적서 형식과 동일하게 변경 (품목 테이블 포함) - 메일 제목에 영업번호 및 OBJID 포함하여 발송 이력 추적 가능 - 견적서 템플릿: 단가/금액 콤마 표시 기능 추가 - 견적서 템플릿: 비고 컬럼 너비 확대 - S/N 모달창 텍스트 색상 개선 (가독성 향상) - 견적서 수정 시 특정 템플릿만 업데이트되도록 SQL 쿼리 수정 --- .../WEB-INF/view/approval/approvalDetail.jsp | 2 +- .../view/contractMgmt/estimateList_new.jsp | 142 ++++++++- .../contractMgmt/estimateRegistFormPopup.jsp | 53 ++-- .../view/contractMgmt/estimateTemplate1.jsp | 55 ++-- .../controller/ContractMgmtController.java | 32 ++ src/com/pms/salesmgmt/mapper/contractMgmt.xml | 78 ++++- .../service/ContractMgmtService.java | 279 ++++++++++++++++++ 7 files changed, 583 insertions(+), 58 deletions(-) diff --git a/WebContent/WEB-INF/view/approval/approvalDetail.jsp b/WebContent/WEB-INF/view/approval/approvalDetail.jsp index 25bd17c..3416036 100644 --- a/WebContent/WEB-INF/view/approval/approvalDetail.jsp +++ b/WebContent/WEB-INF/view/approval/approvalDetail.jsp @@ -76,7 +76,7 @@ $(function(){ window.open(url, "", "width=1000,height=880"); }else if(targetType == "CONTRACT_ESTIMATE"){ url = "/contractMgmt/estimateRegistFormPopup.do?objId="+targetObjId+"&actionType=view"; - window.open(url, "", "width=650,height=400"); + window.open(url, "", "width=1000,height=560"); } }); diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp index f268a12..dfdf6c6 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateList_new.jsp @@ -48,8 +48,8 @@ $(document).ready(function(){ //영업활동 등록 팝업 $(".btnRegist").click(function(){ - var popup_width = 650; - var popup_height = 400; + var popup_width = 1000; + var popup_height = 560; var params = "?actionType=regist" var url = "/contractMgmt/estimateRegistFormPopup.do"+params; //window.open("/ordermgmt/ordermgmtUpdateFormPopup.do"+params, "", "width=650, height=750","menubars=no, scrollbars=yes, resizable=yes"); @@ -148,6 +148,48 @@ $(document).ready(function(){ } }); + // 메일발송 + $("#btnMail").click(function(){ + var selectedData = _tabulGrid.getSelectedData(); + if(selectedData.length < 1){ + Swal.fire("메일발송할 행을 선택해주십시오."); + return false; + } else if(selectedData.length > 1){ + Swal.fire("한번에 한개의 견적서만 발송 가능합니다."); + return false; + } else { + var apprStatus = fnc_checkNull(selectedData[0].APPR_STATUS); + var objId = fnc_checkNull(selectedData[0].OBJID); + var estStatus = fnc_checkNull(selectedData[0].EST_STATUS); + + // 결재완료 상태 확인 + if(apprStatus !== "결재완료"){ + Swal.fire("결재완료된 견적서만 발송 가능합니다."); + return false; + } + + // 견적서 존재 여부 확인 + if(estStatus === "0" || estStatus === 0){ + Swal.fire("작성된 견적서가 없습니다."); + return false; + } + + // 메일 발송 확인 + Swal.fire({ + title: '견적서 메일 발송', + text: "최종 차수의 견적서를 PDF로 발송하시겠습니까?", + icon: 'question', + showCancelButton: true, + confirmButtonText: '발송', + cancelButtonText: '취소' + }).then((result) => { + if(result.isConfirmed){ + fn_sendEstimateMail(objId); + } + }); + } + }); + fn_search(); }); @@ -198,13 +240,35 @@ var columns = [ fn_showEstimateList(objid); } }, - {headerHozAlign : 'center', hozAlign : 'center', width : '80', title : '결재상태', field : 'APPR_STATUS', - formatter:fnc_createGridAnchorTag, - cellClick:function(e, cell){ - var objid = fnc_checkNull(cell.getData().OBJID); - fn_projectConceptDetail(objid); - } - }, + {headerHozAlign : 'center', hozAlign : 'center', width : '80', title : '결재상태', field : 'APPR_STATUS', + formatter:fnc_createGridAnchorTag, + cellClick:function(e, cell){ + var APPROVAL_OBJID = fnc_checkNull(cell.getData().APPROVAL_OBJID); + var ROUTE_OBJID = fnc_checkNull(cell.getData().ROUTE_OBJID); + approval_form(APPROVAL_OBJID,ROUTE_OBJID); + } + }, + {headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '메일발송', field : 'MAIL_SEND_STATUS', + formatter: function(cell, formatterParams, onRendered){ + var status = fnc_checkNull(cell.getValue()); + var sendDate = fnc_checkNull(cell.getData().MAIL_SEND_DATE); + + if(status === 'Y'){ + return '발송완료'; + } else if(status === 'N'){ + return '발송실패'; + } else { + return '미발송'; + } +// if(status === 'Y'){ +// return '발송완료
' + sendDate + ''; +// } else if(status === 'N'){ +// return '발송실패
' + sendDate + ''; +// } else { +// return '미발송'; +// } + } + }, {headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '견적단가', field : 'EST_PRICE' }, {headerHozAlign : 'center', hozAlign : 'center', width : '100', title : '견적공급가액', field : 'EST_SUPPLY_PRICE' }, {headerHozAlign : 'center', hozAlign : 'center', width : '80', title : '환종', field : 'CONTRACT_CURRENCY_NAME' }, @@ -358,8 +422,8 @@ function fn_FileRegist(objId, docType, docTypeName){ } //영업활동등록 상세 function fn_projectConceptDetail(objId){ - var popup_width = 650; - var popup_height = 400; + var popup_width = 1000; + var popup_height = 560; var url = "/contractMgmt/estimateRegistFormPopup.do?objId="+objId; fn_centerPopup(popup_width, popup_height, url); @@ -382,7 +446,7 @@ function fn_showEstimateList(contractObjId){ data: { objId: contractObjId }, dataType: "json", success: function(data){ - console.log("견적서 목록 응답:", data); // 디버깅용 + //console.log("견적서 목록 응답:", data); // 디버깅용 if(data.result === "success" && data.list && data.list.length > 0){ var html = '
'; @@ -396,7 +460,7 @@ function fn_showEstimateList(contractObjId){ html += ''; data.list.forEach(function(item){ - console.log("견적서 항목:", item); // 디버깅용 + //console.log("견적서 항목:", item); // 디버깅용 // 대문자/소문자 모두 지원하도록 안전하게 처리 var objid = item.OBJID || item.objid || ''; @@ -511,6 +575,58 @@ function fn_showSerialNoPopup(serialNoString){ }); } +// 견적서 메일 발송 +function fn_sendEstimateMail(contractObjId){ + if(!contractObjId || contractObjId === ''){ + Swal.fire("잘못된 요청입니다."); + return; + } + + Swal.fire({ + title: '메일 발송 중...', + text: '잠시만 기다려주세요.', + allowOutsideClick: false, + didOpen: () => { + Swal.showLoading(); + } + }); + + $.ajax({ + url: "/contractMgmt/sendEstimateMail.do", + type: "POST", + data: { objId: contractObjId }, + dataType: "json", + success: function(data){ + Swal.close(); + if(data.result === "success"){ + Swal.fire({ + title: '발송 완료', + text: '견적서가 성공적으로 발송되었습니다.', + icon: 'success', + confirmButtonText: '확인' + }); + } else { + Swal.fire({ + title: '발송 실패', + text: data.message || '견적서 발송 중 오류가 발생했습니다.', + icon: 'error', + confirmButtonText: '확인' + }); + } + }, + error: function(xhr, status, error){ + Swal.close(); + console.error("메일 발송 오류:", xhr, status, error); + Swal.fire({ + title: '오류', + text: '메일 발송 중 시스템 오류가 발생했습니다.', + icon: 'error', + confirmButtonText: '확인' + }); + } + }); +} + //코드값을 받아와서 동적으로 selectbox 생성 function optionJobGroup(code){ var val=code; diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateRegistFormPopup.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateRegistFormPopup.jsp index 911b472..d11038c 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateRegistFormPopup.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateRegistFormPopup.jsp @@ -17,6 +17,25 @@ .fileListscrollTbody td { font-size: 11px !important; } + + /* S/N 입력 필드 placeholder 색상 */ + #serial_no::placeholder { + color: #999 !important; + opacity: 1; + } + + #serial_no::-webkit-input-placeholder { + color: #999 !important; + } + + #serial_no::-moz-placeholder { + color: #999 !important; + opacity: 1; + } + + #serial_no:-ms-input-placeholder { + color: #999 !important; + }