From 52145478a9fa0816c45c5fdbce7d297114d66a39 Mon Sep 17 00:00:00 2001 From: syc0123 Date: Wed, 1 Apr 2026 17:09:16 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[RAPID-micro]=20=EA=B2=AC=EC=A0=81=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EB=93=B1=EB=A1=9D/=EC=88=98=EC=A3=BC=ED=86=B5?= =?UTF-8?q?=ED=95=A9=EB=93=B1=EB=A1=9D/=EC=88=98=EC=A3=BC=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=ED=8C=9D=EC=97=85=20=EA=B7=B8=EB=A6=AC=EB=93=9C=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=20=EB=A6=AC=EC=82=AC=EC=9D=B4=EC=A6=88=20UX?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 컬럼 드래그 시 양쪽 컬럼 너비 맞교환 (테이블 전체 너비 고정) - getBoundingClientRect로 시작 너비 정확히 측정 (폭 점프 제거) - requestAnimationFrame으로 렌더링 스로틀 (빠른 드래그 시 부드러움) - 마지막 컬럼 핸들 제거 - tabulator_custom.js 임시 overflow 코드 정리 Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../estimateAndOrderRegistFormPopup.jsp | 96 ++++++++++++------ .../contractMgmt/estimateRegistFormPopup.jsp | 96 ++++++++++++------ .../contractMgmt/orderRegistFormPopup.jsp | 97 ++++++++++++++++++- WebContent/js/tabulator/tabulator_custom.js | 4 +- 4 files changed, 228 insertions(+), 65 deletions(-) diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp index bf9a41c..b4a47b4 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp @@ -65,17 +65,25 @@ position: relative; user-select: none; } + #itemListTable th, + #itemListTable td { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } #itemListTable th .col-resizer { position: absolute; - right: -4.5px; + right: 0; top: 0; - width: 7px; + width: 5px; height: 100%; cursor: col-resize; z-index: 10; + background: transparent; + transition: background 0.15s; } - #itemListTable th .col-resizer:hover { - background: rgba(0, 120, 215, 0.3); + #itemListTable.col-resizing { + user-select: none; } /* ===== Select2 드래그 복사 지원 ===== */ @@ -116,41 +124,67 @@ // ===== 컬럼 리사이즈 기능 ===== function fn_initColumnResize() { var $table = $('#itemListTable'); - if($table.length === 0) return; + if ($table.length === 0) return; - // 각 th에 리사이저 핸들 추가 - $table.find('thead th').each(function() { - if($(this).find('.col-resizer').length === 0) { - $(this).append('
'); + var $cols = $table.find('colgroup col'); + var $ths = $table.find('thead th'); + + $ths.each(function(i) { + if (i < $ths.length - 1) { + if ($(this).find('.col-resizer').length === 0) { + $(this).append('
'); + } } }); - var startX, startWidth, $th, colIndex, $col; + var dragging = false; + var startX = 0; + var startWidthL = 0; + var startWidthR = 0; + var $colL, $colR, $resizerEl; + var rafId = null; $(document).on('mousedown', '#itemListTable .col-resizer', function(e) { - $th = $(this).parent(); - colIndex = $th.index(); - $col = $table.find('colgroup col').eq(colIndex); - startX = e.pageX; - startWidth = $th.outerWidth(); - - $('body').css('cursor', 'col-resize'); - - $(document).on('mousemove.colResize', function(e) { - var newWidth = startWidth + (e.pageX - startX); - if(newWidth >= 40) { - $col.css('width', newWidth + 'px'); - $th.css({'width': newWidth + 'px', 'min-width': newWidth + 'px'}); - } - }); - - $(document).on('mouseup.colResize', function() { - $('body').css('cursor', ''); - $(document).off('mousemove.colResize mouseup.colResize'); - }); - e.preventDefault(); e.stopPropagation(); + + dragging = true; + $resizerEl = $(this); + var colIdx = $resizerEl.parent().index(); + + $colL = $cols.eq(colIdx); + $colR = $cols.eq(colIdx + 1); + + startWidthL = $colL[0].getBoundingClientRect().width; + startWidthR = $colR[0].getBoundingClientRect().width; + startX = e.clientX; + + $resizerEl.addClass('is-resizing'); + $table.addClass('col-resizing'); + $('body').css('cursor', 'col-resize'); + }); + + $(document).on('mousemove.colResize', function(e) { + if (!dragging) return; + if (rafId) return; + rafId = requestAnimationFrame(function() { + rafId = null; + var delta = e.clientX - startX; + var newLeft = startWidthL + delta; + var newRight = startWidthR - delta; + if (newLeft < 40 || newRight < 40) return; + $colL.css('width', newLeft + 'px'); + $colR.css('width', newRight + 'px'); + }); + }); + + $(document).on('mouseup.colResize mouseleave.colResize', function() { + if (!dragging) return; + dragging = false; + if (rafId) { cancelAnimationFrame(rafId); rafId = null; } + if ($resizerEl) $resizerEl.removeClass('is-resizing'); + $table.removeClass('col-resizing'); + $('body').css('cursor', ''); }); } diff --git a/WebContent/WEB-INF/view/contractMgmt/estimateRegistFormPopup.jsp b/WebContent/WEB-INF/view/contractMgmt/estimateRegistFormPopup.jsp index 2b181a0..5985d5b 100644 --- a/WebContent/WEB-INF/view/contractMgmt/estimateRegistFormPopup.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/estimateRegistFormPopup.jsp @@ -60,17 +60,25 @@ position: relative; user-select: none; } + #itemListTable th, + #itemListTable td { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } #itemListTable th .col-resizer { position: absolute; - right: -4.5px; + right: 0; top: 0; - width: 7px; + width: 5px; height: 100%; cursor: col-resize; z-index: 10; + background: transparent; + transition: background 0.15s; } - #itemListTable th .col-resizer:hover { - background: rgba(0, 120, 215, 0.3); + #itemListTable.col-resizing { + user-select: none; } /* ===== Select2 드래그 복사 지원 ===== */ @@ -112,41 +120,67 @@ // ===== 컬럼 리사이즈 기능 ===== function fn_initColumnResize() { var $table = $('#itemListTable'); - if($table.length === 0) return; + if ($table.length === 0) return; - // 각 th에 리사이저 핸들 추가 - $table.find('thead th').each(function() { - if($(this).find('.col-resizer').length === 0) { - $(this).append('
'); + var $cols = $table.find('colgroup col'); + var $ths = $table.find('thead th'); + + $ths.each(function(i) { + if (i < $ths.length - 1) { + if ($(this).find('.col-resizer').length === 0) { + $(this).append('
'); + } } }); - var startX, startWidth, $th, colIndex, $col; + var dragging = false; + var startX = 0; + var startWidthL = 0; + var startWidthR = 0; + var $colL, $colR, $resizerEl; + var rafId = null; $(document).on('mousedown', '#itemListTable .col-resizer', function(e) { - $th = $(this).parent(); - colIndex = $th.index(); - $col = $table.find('colgroup col').eq(colIndex); - startX = e.pageX; - startWidth = $th.outerWidth(); - - $('body').css('cursor', 'col-resize'); - - $(document).on('mousemove.colResize', function(e) { - var newWidth = startWidth + (e.pageX - startX); - if(newWidth >= 40) { - $col.css('width', newWidth + 'px'); - $th.css({'width': newWidth + 'px', 'min-width': newWidth + 'px'}); - } - }); - - $(document).on('mouseup.colResize', function() { - $('body').css('cursor', ''); - $(document).off('mousemove.colResize mouseup.colResize'); - }); - e.preventDefault(); e.stopPropagation(); + + dragging = true; + $resizerEl = $(this); + var colIdx = $resizerEl.parent().index(); + + $colL = $cols.eq(colIdx); + $colR = $cols.eq(colIdx + 1); + + startWidthL = $colL[0].getBoundingClientRect().width; + startWidthR = $colR[0].getBoundingClientRect().width; + startX = e.clientX; + + $resizerEl.addClass('is-resizing'); + $table.addClass('col-resizing'); + $('body').css('cursor', 'col-resize'); + }); + + $(document).on('mousemove.colResize', function(e) { + if (!dragging) return; + if (rafId) return; + rafId = requestAnimationFrame(function() { + rafId = null; + var delta = e.clientX - startX; + var newLeft = startWidthL + delta; + var newRight = startWidthR - delta; + if (newLeft < 40 || newRight < 40) return; + $colL.css('width', newLeft + 'px'); + $colR.css('width', newRight + 'px'); + }); + }); + + $(document).on('mouseup.colResize mouseleave.colResize', function() { + if (!dragging) return; + dragging = false; + if (rafId) { cancelAnimationFrame(rafId); rafId = null; } + if ($resizerEl) $resizerEl.removeClass('is-resizing'); + $table.removeClass('col-resizing'); + $('body').css('cursor', ''); }); } diff --git a/WebContent/WEB-INF/view/contractMgmt/orderRegistFormPopup.jsp b/WebContent/WEB-INF/view/contractMgmt/orderRegistFormPopup.jsp index ada99a8..80203d8 100644 --- a/WebContent/WEB-INF/view/contractMgmt/orderRegistFormPopup.jsp +++ b/WebContent/WEB-INF/view/contractMgmt/orderRegistFormPopup.jsp @@ -22,6 +22,7 @@ #itemListTable { width: 100%; border-collapse: collapse; + table-layout: fixed; } #itemListTable th, @@ -34,8 +35,32 @@ #itemListTable th { background-color: #f5f5f5; font-weight: bold; + position: relative; + user-select: none; } - + + /* ===== 컬럼 리사이즈 핸들 ===== */ + #itemListTable th, + #itemListTable td { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + #itemListTable th .col-resizer { + position: absolute; + right: 0; + top: 0; + width: 5px; + height: 100%; + cursor: col-resize; + z-index: 10; + background: transparent; + transition: background 0.15s; + } + #itemListTable.col-resizing { + user-select: none; + } + #itemListTable input[type="text"], #itemListTable input[type="number"] { width: 100%; @@ -55,6 +80,73 @@ var itemCounter = 1; var itemList = []; + // ===== 컬럼 리사이즈 기능 ===== + function fn_initColumnResize() { + var $table = $('#itemListTable'); + if ($table.length === 0) return; + + var $cols = $table.find('colgroup col'); + var $ths = $table.find('thead th'); + + $ths.each(function(i) { + if (i < $ths.length - 1) { + if ($(this).find('.col-resizer').length === 0) { + $(this).append('
'); + } + } + }); + + var dragging = false; + var startX = 0; + var startWidthL = 0; + var startWidthR = 0; + var $colL, $colR, $resizerEl; + var rafId = null; + + $(document).on('mousedown', '#itemListTable .col-resizer', function(e) { + e.preventDefault(); + e.stopPropagation(); + + dragging = true; + $resizerEl = $(this); + var colIdx = $resizerEl.parent().index(); + + $colL = $cols.eq(colIdx); + $colR = $cols.eq(colIdx + 1); + + startWidthL = $colL[0].getBoundingClientRect().width; + startWidthR = $colR[0].getBoundingClientRect().width; + startX = e.clientX; + + $resizerEl.addClass('is-resizing'); + $table.addClass('col-resizing'); + $('body').css('cursor', 'col-resize'); + }); + + $(document).on('mousemove.colResize', function(e) { + if (!dragging) return; + if (rafId) return; + rafId = requestAnimationFrame(function() { + rafId = null; + var delta = e.clientX - startX; + var newLeft = startWidthL + delta; + var newRight = startWidthR - delta; + if (newLeft < 40 || newRight < 40) return; + $colL.css('width', newLeft + 'px'); + $colR.css('width', newRight + 'px'); + }); + }); + + $(document).on('mouseup.colResize mouseleave.colResize', function() { + if (!dragging) return; + dragging = false; + if (rafId) { cancelAnimationFrame(rafId); rafId = null; } + if ($resizerEl) $resizerEl.removeClass('is-resizing'); + $table.removeClass('col-resizing'); + $('body').css('cursor', ''); + }); + } + $(function() { // console.log("===== 수주등록 팝업 로드됨 ====="); // console.log("useEstimateTemplate 값:", "${useEstimateTemplate}"); @@ -102,6 +194,9 @@ } }); + // 컬럼 리사이즈 초기화 + fn_initColumnResize(); + $('.select2').select2(); // 날짜 선택기 초기화 diff --git a/WebContent/js/tabulator/tabulator_custom.js b/WebContent/js/tabulator/tabulator_custom.js index 6a09328..55519e9 100644 --- a/WebContent/js/tabulator/tabulator_custom.js +++ b/WebContent/js/tabulator/tabulator_custom.js @@ -147,8 +147,8 @@ function fnc_tabul_search(layoutParam, gridObj, searchURL, columnParam, showChec gridObj.on("tableBuilt", function(){ //tableBuilding $(".tabulator-footer").hide(); //tabulator 페이징 영역 숨김 - - if(!isNotSearchFirst) //생성과 동시에 검색 + + if(!isNotSearchFirst) //생성과 동시에 검색 fnc_tabul_searchAjax(gridObj, searchURL, formId, hidePaging, checkValidation); }); } From ee87960a02b21bc65541d33e5ad5398da06c7bd3 Mon Sep 17 00:00:00 2001 From: syc0123 Date: Wed, 1 Apr 2026 17:18:34 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[RAPID-micro]=20=EB=B0=9C=EC=A3=BC=EC=84=9C?= =?UTF-8?q?=20=EC=86=A1=EB=B6=80=20=EB=A9=94=EC=9D=BC=20=EB=B0=9C=EC=86=A1?= =?UTF-8?q?=20=EA=B3=84=EC=A0=95=20SALES=20=E2=86=92=20PURCHASE=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 (1M context) --- src/com/pms/service/PurchaseOrderService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/com/pms/service/PurchaseOrderService.java b/src/com/pms/service/PurchaseOrderService.java index 78bcc69..aebc979 100644 --- a/src/com/pms/service/PurchaseOrderService.java +++ b/src/com/pms/service/PurchaseOrderService.java @@ -3140,9 +3140,9 @@ public class PurchaseOrderService { fromUser = CommonUtils.checkNull((String)masterInfo.get("WRITER")); } - // 발주서 메일 발송 (PURCHASE 계정 수신 불가 이슈로 SALES 계정 임시 사용 - TODO: PURCHASE 계정 정상화 후 원복) - boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_SALES); - //boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_PURCHASE); + // 발주서 메일 발송 (PURCHASE 계정 사용) + //boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_SALES); + boolean sendResult = MailUtil.sendMailWithAttachFile(fromUser, fromEmail, toUserIdList, toEmailList, ccEmailList, null, null, subject, mailContents, attachFileList, "PURCHASE_ORDER", Constants.Mail.ACCOUNT_TYPE_PURCHASE); if(sendResult) { // 메일 발송 성공 시 DB 업데이트