From 0262afee3d2f8e791a5d5d79974ab6e24ec34f05 Mon Sep 17 00:00:00 2001 From: hjjeong Date: Fri, 27 Mar 2026 17:32:26 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../view/contractMgmt/estimateTemplate1.jsp | 115 ++++++++++++------ .../view/contractMgmt/estimateTemplate2.jsp | 40 +++--- 2 files changed, 102 insertions(+), 53 deletions(-) diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp index 166724f..31a6d85 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateTemplate1.jsp @@ -64,6 +64,9 @@ String templateObjId = CommonUtils.checkNull(request.getParameter("templateObjId .no-print { display: none !important; } + .delete-btn-cell button { + display: none !important; + } } body { @@ -160,13 +163,15 @@ body { width: 100%; border-collapse: collapse; margin-bottom: 30px; + table-layout: fixed; } .items-table th, .items-table td { border: 1px solid #000; - padding: 3px 5px; + padding: 8px 2px; text-align: center; + vertical-align: middle; font-size: 9pt; line-height: 1.3; } @@ -176,14 +181,15 @@ body { font-weight: bold; } -.items-table .col-no { width: 6%; } -.items-table .col-desc { width: 20%; } +.items-table .col-no { width: 4%; } +.items-table .col-desc { width: 12%; } .items-table .col-spec { width: 22%; } -.items-table .col-qty { width: 7%; } -.items-table .col-unit { width: 8%; } -.items-table .col-price { width: 11%; } -.items-table .col-amount { width: 11%; } -.items-table .col-note { width: 15%; } +.items-table .col-qty { width: 4%; } +.items-table .col-unit { width: 5%; } +.items-table .col-price { width: 14%; } +.items-table .col-amount { width: 15%; } +.items-table .col-note { width: 9%; white-space: normal; word-break: break-all; } +.items-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .items-table .text-left { text-align: left; @@ -191,6 +197,8 @@ body { .items-table .text-right { text-align: right; + overflow: hidden; + word-break: break-all; } .notes-section { @@ -262,6 +270,12 @@ textarea { width: 100%; font-family: inherit; font-size: inherit; + box-sizing: border-box; +} + +.item-price, +.item-amount { + text-align: right; } .item-amount { @@ -269,9 +283,12 @@ textarea { } textarea { - resize: vertical; - min-height: 25px; - padding: 2px; + resize: none; + height: 1.3em; + min-height: auto; + padding: 0 2px; + white-space: nowrap; + overflow: hidden; } .editable { @@ -373,7 +390,7 @@ $(function(){ $(document).on("blur", ".item-price", function(){ var val = $(this).val().replace(/,/g, ""); if(!isNaN(val) && val !== "") { - $(this).val(Number(val).toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 2})); + $(this).val(Number(val).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})); } fn_calculateTotal(); }); @@ -502,10 +519,16 @@ function fn_calculateTotalKRW(total) { $("#totalAmountKRW").text("₩" + addComma(totalKRW)); } -// 금액 포맷 (소수점 2자리 + 천단위 콤마) +// 금액 포맷 (항상 소수점 2자리, 천단위 콤마) function addComma(num) { if(num === '' || num === null || num === undefined) return ''; - return Number(num).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}); + // DB에 콤마가 포함된 값이 저장된 경우를 위해 콤마 제거 후 파싱 + var n = Number(String(num).replace(/,/g, '')); + if(isNaN(n)) return ''; + return n.toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); } // 통화 기호 반환 @@ -702,7 +725,7 @@ function fn_loadContractItems(contractObjId) { itemsHtml += ''; itemsHtml += '계'; itemsHtml += '0'; - itemsHtml += ''; + itemsHtml += ''; itemsHtml += ''; // 원화환산 공급가액 행 추가 (숨김) @@ -864,7 +887,7 @@ function fn_loadData() { itemsHtml += ''; itemsHtml += '계'; itemsHtml += '0'; - itemsHtml += ''; + itemsHtml += ''; itemsHtml += ''; // 원화환산 공급가액 행 추가 (숨김) @@ -1082,7 +1105,7 @@ function fn_loadTemplateData(templateObjId){ itemsHtml += ''; itemsHtml += '계'; itemsHtml += '0'; - itemsHtml += ''; + itemsHtml += ''; itemsHtml += ''; // 원화환산 공급가액 행 추가 (숨김) @@ -1422,7 +1445,7 @@ function fn_save() { 규 격
SPECIFICATION 수량
Q'TY 단위
UNIT - 단 가
UNIT
PRICE + 단 가
UNIT PRICE 금 액
AMOUNT 비고 @@ -1458,7 +1481,7 @@ function fn_save() { 계 0 - + @@ -1521,15 +1544,17 @@ function fn_replaceFormElementsWithText() { $('.estimate-container').find('input[type="text"], textarea, select').each(function(idx) { var $el = $(this); var displayText = ''; - + if ($el.is('select')) { displayText = $el.find('option:selected').text() || ''; } else { displayText = $el.val() || ''; } - + var computedStyle = window.getComputedStyle(this); - var elWidth = $el.outerWidth(); + // 단가/금액 컬럼이 좁아 잘릴 수 있으므로 부모 td의 내부 너비 사용 + var parentTd = $el.closest('td'); + var elWidth = parentTd.length > 0 ? parentTd.innerWidth() : $el.outerWidth(); var span = $(''); span.text(displayText); span.css({ @@ -1604,29 +1629,31 @@ function fn_generatePdf() { } }); - // 버튼 영역 임시 숨김 + // 버튼 영역 임시 숨김 (삭제 버튼 셀 전체 숨김으로 PDF에 노출 방지) $('.btn-area').hide(); - + $('.btn-delete-row').hide(); + $('.btn-delete-total-row').hide(); + // 폼 요소를 텍스트로 변환 (html2canvas 글자 잘림 방지) var formBackup = fn_replaceFormElementsWithText(); - + // PDF 생성을 위해 스타일 조정 var container = $('.estimate-container'); var originalBg = container.css('background'); var originalShadow = container.css('box-shadow'); var originalPadding = container.css('padding'); - + // 깔끔한 PDF를 위해 배경, 그림자, 패딩 제거 container.css({ 'background': 'white', 'box-shadow': 'none', 'padding': '10mm' }); - + // body 배경색도 흰색으로 var originalBodyBg = $('body').css('background-color'); $('body').css('background-color', 'white'); - + // 견적서 컨테이너 캡처 html2canvas(document.querySelector('.estimate-container'), { scale: 2, // 적절한 해상도 (파일 크기 최적화) @@ -1645,6 +1672,8 @@ function fn_generatePdf() { fn_restoreFormElements(formBackup); // 버튼 영역 다시 표시 $('.btn-area').show(); + $('.btn-delete-row').show(); + $('.btn-delete-total-row').show(); try { // Canvas를 JPEG 이미지로 변환 (PNG보다 파일 크기 작음) @@ -1696,6 +1725,8 @@ function fn_generatePdf() { }).catch(function(error) { fn_restoreFormElements(formBackup); $('.btn-area').show(); + $('.btn-delete-row').show(); + $('.btn-delete-total-row').show(); Swal.close(); console.error('Canvas 캡처 오류:', error); Swal.fire({ @@ -1709,7 +1740,7 @@ function fn_generatePdf() { // PDF를 Base64로 생성하여 서버로 전송하는 함수 function fn_generateAndUploadPdf(callback) { console.log('fn_generateAndUploadPdf 호출됨'); - + // 라이브러리 로드 확인 if(typeof html2canvas === 'undefined' || typeof jsPDF === 'undefined') { console.error('필요한 라이브러리가 로드되지 않았습니다.'); @@ -1718,30 +1749,32 @@ function fn_generateAndUploadPdf(callback) { } return; } - - // 버튼 영역 임시 숨김 + + // 버튼 영역 임시 숨김 (삭제 버튼 셀 전체 숨김으로 PDF에 노출 방지) $('.btn-area').hide(); - + $('.btn-delete-row').hide(); + $('.btn-delete-total-row').hide(); + // 폼 요소를 텍스트로 변환 (html2canvas 글자 잘림 방지) var formBackup = fn_replaceFormElementsWithText(); - + // PDF 생성을 위해 스타일 조정 var container = $('.estimate-container'); var originalBg = container.css('background'); var originalShadow = container.css('box-shadow'); var originalPadding = container.css('padding'); - + // 깔끔한 PDF를 위해 배경, 그림자, 패딩 제거 container.css({ 'background': 'white', 'box-shadow': 'none', 'padding': '10mm' }); - + // body 배경색도 흰색으로 var originalBodyBg = $('body').css('background-color'); $('body').css('background-color', 'white'); - + // 견적서 컨테이너 캡처 html2canvas(document.querySelector('.estimate-container'), { scale: 2, // 적절한 해상도 (파일 크기 최적화) @@ -1750,7 +1783,7 @@ function fn_generateAndUploadPdf(callback) { backgroundColor: '#ffffff' }).then(function(canvas) { console.log('Canvas 캡처 완료'); - + // 스타일 복원 container.css({ 'background': originalBg, @@ -1758,12 +1791,14 @@ function fn_generateAndUploadPdf(callback) { 'padding': originalPadding }); $('body').css('background-color', originalBodyBg); - + // 폼 요소 복원 fn_restoreFormElements(formBackup); - + // 버튼 영역 다시 표시 $('.btn-area').show(); + $('.btn-delete-row').show(); + $('.btn-delete-total-row').show(); try { // Canvas를 JPEG 이미지로 변환 (PNG보다 파일 크기 작음) @@ -1809,6 +1844,8 @@ function fn_generateAndUploadPdf(callback) { }).catch(function(error) { fn_restoreFormElements(formBackup); $('.btn-area').show(); + $('.btn-delete-row').show(); + $('.btn-delete-total-row').show(); console.error('Canvas 캡처 오류:', error); if(callback && typeof callback === 'function') { callback(null); diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateTemplate2.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateTemplate2.jsp index 2573c81..7dc1cdb 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateTemplate2.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateTemplate2.jsp @@ -29,6 +29,9 @@ boolean isApproved = "결재완료".equals(apprStatus) || "결재중".equals(app .no-print { display: none !important; } + .delete-btn-cell button { + display: none !important; + } } body { @@ -530,10 +533,16 @@ function fn_calculateSubtotal(tbody) { tbody.find(".subtotal-amount").val(addComma(total)); } -// 금액 포맷 (소수점 2자리 + 천단위 콤마) +// 금액 포맷 (항상 소수점 2자리, 천단위 콤마) function addComma(num) { if(num === '' || num === null || num === undefined) return ''; - return Number(num).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}); + // DB에 콤마가 포함된 값이 저장된 경우를 위해 콤마 제거 후 파싱 + var n = Number(String(num).replace(/,/g, '')); + if(isNaN(n)) return ''; + return n.toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); } // 카테고리 추가 @@ -558,7 +567,7 @@ function fn_addCategory() { '' + '' + newCategoryNo + '' + '' + newCategoryName + '' + - '' + + '' + '' + '' + '' + @@ -622,7 +631,7 @@ function fn_createCategoryFromData(category) { '' + '' + categoryNo + '' + '' + categoryName + '' + - '' + + '' + '' + '' + '' + @@ -1069,9 +1078,10 @@ function fn_generateAndUploadPdf(callback) { return; } - // 버튼 영역 임시 숨김 + // 버튼 영역 임시 숨김 (삭제 버튼 셀 전체 숨김으로 PDF에 노출 방지) $('.estimate-btn-area').hide(); - + $('.btn-delete-category').hide(); + // textarea를 div로 변환 (줄바꿈 보존) var textareaBackup = []; $('textarea').each(function(index) { @@ -1140,7 +1150,8 @@ function fn_generateAndUploadPdf(callback) { // 버튼 영역 다시 표시 $('.estimate-btn-area').show(); - + $('.btn-delete-category').show(); + try { // Canvas를 JPEG 이미지로 변환 (PNG보다 파일 크기 작음) var imgData = canvas.toDataURL('image/jpeg', 0.85); // 85% 품질 @@ -1189,6 +1200,7 @@ function fn_generateAndUploadPdf(callback) { }); $('.estimate-btn-area').show(); + $('.btn-delete-category').show(); console.error('Canvas 캡처 오류:', error); if(callback && typeof callback === 'function') { callback(null); @@ -1302,7 +1314,7 @@ function fn_generateAndUploadPdf(callback) { 1 기구 - + @@ -1366,7 +1378,7 @@ Z: SRG25 P급, C0 2 초음파 스핀들 모듈 - + @@ -1407,7 +1419,7 @@ Z: SRG25 P급, C0 3 전장 - + @@ -1451,7 +1463,7 @@ SIEMENS CONTROL PANEL 828D 4 UTILITY - + @@ -1521,7 +1533,7 @@ LUBRICATION 5 Option - + @@ -1570,7 +1582,7 @@ NV4Blue(Renishaw) 6 Set up - + @@ -1615,7 +1627,7 @@ NV4Blue(Renishaw) 7 포장/물류 - +