From 655d501e4b4d6ae54a2528d1bd04afa42a6fb9d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EC=A7=80=EC=9D=B8?= Date: Fri, 27 Feb 2026 11:15:22 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=91=EC=85=80=EB=8B=A4=EC=9A=B4=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=EC=8B=9C=20progres=20=ED=91=9C=EC=8B=9C=20=20-=20?= =?UTF-8?q?=EA=B1=B4=EC=84=A4=ED=98=84=EC=9E=A5=EA=B4=80=EB=A6=AC:=20?= =?UTF-8?q?=EB=B0=9C=EC=A3=BC=EA=B8=B0=EA=B4=80=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EB=82=B4=EC=97=AD=20=20-=20API=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC:=20=EC=99=B8=EB=B6=80=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=97=B0=EB=8F=99=20=ED=86=B5=EA=B3=84(API=ED=98=B8=EC=B6=9C?= =?UTF-8?q?=20=EB=A1=9C=EA=B7=B8)=20=20-=20API=20=EA=B4=80=EB=A6=AC:=20API?= =?UTF-8?q?=20=EC=97=B0=EB=8F=99=20=ED=86=B5=EA=B3=84(API=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EB=A1=9C=EA=B7=B8)=20=20-=20API=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC:=20API=20=EC=8B=A0=EC=B2=AD=20=EA=B4=80=EB=A6=AC(API?= =?UTF-8?q?=ED=98=B8=EC=B6=9C=20=EB=A1=9C=EA=B7=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApiInDataManagementController.java | 4 +- .../ApiKeyManagementController.java | 4 +- .../ApiOutDataManagementController.java | 4 +- ...nstructionProjectManagementController.java | 9 +- .../geoinfo/util/ExcelMergeHeaderUtil.java | 81 ++++++++--- .../construction-site-index.jsp | 128 +----------------- .../construction-user-login-history.jsp | 126 ++++++++++++++--- .../mgmtApi/api-request-statistics-index.jsp | 101 ++++++++++++-- .../views/admins/mgmtApi/mgmt-api-key.jsp | 101 ++++++++++++-- .../views/admins/mgmtApi/mgmt-api-outdata.jsp | 103 ++++++++++++-- 10 files changed, 458 insertions(+), 203 deletions(-) diff --git a/src/main/java/geoinfo/admins/apiManagement/ApiInDataManagementController.java b/src/main/java/geoinfo/admins/apiManagement/ApiInDataManagementController.java index 48d58ec..6402dfa 100644 --- a/src/main/java/geoinfo/admins/apiManagement/ApiInDataManagementController.java +++ b/src/main/java/geoinfo/admins/apiManagement/ApiInDataManagementController.java @@ -210,7 +210,7 @@ public class ApiInDataManagementController { String[] headers = {"rn","apiKey","accessId","accessType","accessTable","accessDt" ,"ipAddress"}; String[] headerName = {"No.", "API_KEY", "ACCESS_ID", "ACCESS_TYPE", "ACCESS_TABLE", "ACCESS_DT", "IP_ADDRESS"}; - final int[] headerWidths = {1325, 15900, 4240, 6360, 5830, 8830, 6890}; + final int[] headerWidths = {1325, 15900, 4240, 4240, 8830, 5830, 5390}; String[] columnType = {"String", "String", "String", "String", "String", "String", "String"}; String sheetName = "Sheet1"; @@ -221,7 +221,7 @@ public class ApiInDataManagementController { List listData = (List) apiInDataManagementService.selectWebApiLogList(params); int idx = 0; - ExcelMergeHeaderUtil.listToExcel(listData, response, headers, headerName, columnType, sheetName, excelFileName); + ExcelMergeHeaderUtil.listToExcel(listData, response, headers, headerName, headerWidths, columnType, sheetName, excelFileName); } } diff --git a/src/main/java/geoinfo/admins/apiManagement/ApiKeyManagementController.java b/src/main/java/geoinfo/admins/apiManagement/ApiKeyManagementController.java index 4fc7aed..75b4eae 100644 --- a/src/main/java/geoinfo/admins/apiManagement/ApiKeyManagementController.java +++ b/src/main/java/geoinfo/admins/apiManagement/ApiKeyManagementController.java @@ -87,7 +87,7 @@ public class ApiKeyManagementController { String[] headers = {"rn","userid","userType","apiKey","startDt","endDt","approveYn"}; String[] headerName = {"No.", "사용자 ID", "사용자 구분", "API KEY", "신청일", "만료일", "승인상태"}; - final int[] headerWidths = {1325, 15900, 4240, 6360, 5830, 8830, 6890}; + final int[] headerWidths = {1325, 5360, 4240, 15900, 5830, 5830, 3640}; String[] columnType = {"String", "String", "String", "String", "String", "String", "String"}; String sheetName = "Sheet1"; @@ -103,7 +103,7 @@ public class ApiKeyManagementController { rowData.put("approveYn", "Y".equals(approveYn) ? "승인" : "미승인"); } - ExcelMergeHeaderUtil.listToExcel(listData, response, headers, headerName, columnType, sheetName, excelFileName); + ExcelMergeHeaderUtil.listToExcel(listData, response, headers, headerName, headerWidths, columnType, sheetName, excelFileName); } /** diff --git a/src/main/java/geoinfo/admins/apiManagement/ApiOutDataManagementController.java b/src/main/java/geoinfo/admins/apiManagement/ApiOutDataManagementController.java index ef69d9a..7e0965e 100644 --- a/src/main/java/geoinfo/admins/apiManagement/ApiOutDataManagementController.java +++ b/src/main/java/geoinfo/admins/apiManagement/ApiOutDataManagementController.java @@ -207,7 +207,7 @@ public class ApiOutDataManagementController { String[] headers = {"rn","apiKey","accessId","accessType","accessTable","accessDt" ,"ipAddress"}; String[] headerName = {"No.", "API_KEY", "ACCESS_ID", "ACCESS_TYPE", "ACCESS_TABLE", "ACCESS_DT", "IP_ADDRESS"}; - final int[] headerWidths = {1325, 15900, 4240, 6360, 5830, 8830, 6890}; + final int[] headerWidths = {1325, 15900, 4240, 4240, 8830, 5830, 5390}; String[] columnType = {"String", "String", "String", "String", "String", "String", "String"}; String sheetName = "Sheet1"; @@ -219,6 +219,6 @@ public class ApiOutDataManagementController { List listData = (List) apiOutDataManagementService.selectWebApiLogList(params); int idx = 0; - ExcelMergeHeaderUtil.listToExcel(listData, response, headers, headerName, columnType, sheetName, excelFileName); + ExcelMergeHeaderUtil.listToExcel(listData, response, headers, headerName, headerWidths, columnType, sheetName, excelFileName); } } diff --git a/src/main/java/geoinfo/admins/constructionProjectManagement/ConstructionProjectManagementController.java b/src/main/java/geoinfo/admins/constructionProjectManagement/ConstructionProjectManagementController.java index 4316f13..2d77fcc 100644 --- a/src/main/java/geoinfo/admins/constructionProjectManagement/ConstructionProjectManagementController.java +++ b/src/main/java/geoinfo/admins/constructionProjectManagement/ConstructionProjectManagementController.java @@ -1116,7 +1116,6 @@ public class ConstructionProjectManagementController { @RequestMapping(value = "admins/constructionProjectManagement/excel.do") public void constructionProjectManagementExcel(HttpServletRequest request, HttpServletResponse response, HSSFWorkbook workbook, @RequestParam HashMap params) throws Exception { - HashMap map = new HashMap(); String[] headers = {"num","userid","userName","companyName","datetime","note"}; String[] headerNames = {"번호", "아이디", "이름", "소속", "로그인일시", "로그인여부"}; @@ -1127,8 +1126,6 @@ public class ConstructionProjectManagementController { String excelFileName = "국토지반_발주기관_로그인_내역"; -// int startIndex = 0; - Long totalCount = 0L; // DB 조회 /** pageing */ PaginationInfo paginationInfo = new PaginationInfo(); @@ -1150,7 +1147,11 @@ public class ConstructionProjectManagementController { int totalCnt = resultList.size() == 0 ? 0 : Integer.valueOf(((EgovMap) resultList.get(0)).get("totalrows").toString()); paginationInfo.setTotalRecordCount(totalCnt); - + if (resultList == null || resultList.isEmpty()) { + response.setContentType("text/html;charset=UTF-8"); + response.getWriter().write(""); + return; + } ExcelMergeHeaderUtil.listToExcelMergeHeaderForLoginHistory(resultList, response, headers, headerNames, headerWidths, columnType, sheetName, excelFileName); } diff --git a/src/main/java/geoinfo/util/ExcelMergeHeaderUtil.java b/src/main/java/geoinfo/util/ExcelMergeHeaderUtil.java index d9f93e0..7fdefc1 100644 --- a/src/main/java/geoinfo/util/ExcelMergeHeaderUtil.java +++ b/src/main/java/geoinfo/util/ExcelMergeHeaderUtil.java @@ -140,10 +140,11 @@ public class ExcelMergeHeaderUtil { } public static void listToExcel(List list, HttpServletResponse response, String[] headers, - String[] headerNames, String[] columnType, String sheetName, String excelFileName) throws IOException { + String[] headerNames, int[] headerWidths, String[] columnType, String sheetName, String excelFileName) throws IOException { if (ExcelMergeHeaderUtil.isNotEmpty(list)) { // 메모리에 100개의 행을 유지합니다. 행의 수가 넘으면 디스크에 적습니다. - XSSFWorkbook wb = new XSSFWorkbook(); +// XSSFWorkbook wb = new XSSFWorkbook(); + Workbook wb = new SXSSFWorkbook(200); Sheet sheet = wb.createSheet(sheetName); Row headerRow = sheet.createRow(0); CellStyle cellStyle1 = wb.createCellStyle(); // 쉼표들어간 숫자 양식 @@ -162,7 +163,8 @@ public class ExcelMergeHeaderUtil { headerFont.setColor(IndexedColors.WHITE.getIndex()); // 글씨 색상 흰색 headerStyle.setFont(headerFont); // 헤더 스타일에 적용 - XSSFDataFormat format = wb.createDataFormat(); +// XSSFDataFormat format = wb.createDataFormat(); + DataFormat format = wb.createDataFormat(); cellStyle1.setDataFormat(format.getFormat("#,##0")); cellStyle2.setDataFormat(format.getFormat("#")); headerStyle.setBorderTop(BorderStyle.THIN); @@ -214,22 +216,45 @@ public class ExcelMergeHeaderUtil { Cell cell = headerRow.createCell(j); cell.setCellValue(headerNames[j]); cell.setCellStyle(headerStyle); - sheet.autoSizeColumn(j); sheet.setColumnWidth(j, (sheet.getColumnWidth(j)) + 1000); + sheet.setColumnWidth(j, headerWidths[j]); } + // 엑셀이름 한글깨짐방지 - String outputFileName = new String(excelFileName.getBytes("KSC5601"), "8859_1"); + String encodedFileName = URLEncoder.encode(excelFileName, "UTF-8").replaceAll("\\+", "%20"); - response.setHeader("Set-Cookie", "fileDownload=true; path=/"); - response.setHeader("Content-Disposition", String.format("attachment; filename=\"" + outputFileName + "_" - + ExcelMergeHeaderUtil.getTimeStampString("yyyyMMdd_HHmm") + ".xlsx\"")); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName + "_" + + ExcelMergeHeaderUtil.getTimeStampString("yyyyMMdd_HHmm") + ".xlsx"); - wb.write(response.getOutputStream()); + // ========================= + // 엑셀을 ByteArray로 생성 + // ========================= + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + wb.write(bos); + + if (wb instanceof SXSSFWorkbook) { + ((SXSSFWorkbook) wb).dispose(); // temp 파일 정리 + } + wb.close(); + + byte[] fileBytes = bos.toByteArray(); + response.setContentLength(fileBytes.length); + + // ========================= + // 전송 + // ========================= + OutputStream os = response.getOutputStream(); + os.write(fileBytes); + os.flush(); + os.close(); + wb.close(); } else { createNoDataAlert(response); } + } public static void listToExcelMergeHeader(List list, HttpServletResponse response, String[] headers, @@ -472,7 +497,8 @@ public class ExcelMergeHeaderUtil { String excelFileName) throws IOException { if (ExcelMergeHeaderUtil.isNotEmpty(list)) { // 메모리에 100개의 행을 유지합니다. 행의 수가 넘으면 디스크에 적습니다. - XSSFWorkbook wb = new XSSFWorkbook(); +// XSSFWorkbook wb = new XSSFWorkbook(); + Workbook wb = new SXSSFWorkbook(200); Sheet sheet = wb.createSheet(sheetName); Row headerRow = sheet.createRow(headerNames.length); CellStyle cellStyle1 = wb.createCellStyle(); // 쉼표들어간 숫자 양식 @@ -491,7 +517,8 @@ public class ExcelMergeHeaderUtil { headerFont.setColor(IndexedColors.WHITE.getIndex()); // 글씨 색상 흰색 headerStyle.setFont(headerFont); // 헤더 스타일에 적용 - XSSFDataFormat format = wb.createDataFormat(); +// XSSFDataFormat format = wb.createDataFormat(); + DataFormat format = wb.createDataFormat(); cellStyle1.setDataFormat(format.getFormat("#,##0")); cellStyle2.setDataFormat(format.getFormat("#")); headerStyle.setBorderTop(BorderStyle.THIN); @@ -561,14 +588,36 @@ public class ExcelMergeHeaderUtil { } } + // 엑셀이름 한글깨짐방지 - String outputFileName = new String(excelFileName.getBytes("KSC5601"), "8859_1"); + String encodedFileName = URLEncoder.encode(excelFileName, "UTF-8").replaceAll("\\+", "%20"); - response.setHeader("Set-Cookie", "fileDownload=true; path=/"); - response.setHeader("Content-Disposition", String.format("attachment; filename=\"" + outputFileName + "_" - + ExcelMergeHeaderUtil.getTimeStampString("yyyyMMdd_HHmm") + ".xlsx\"")); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName + "_" + + ExcelMergeHeaderUtil.getTimeStampString("yyyyMMdd_HHmm") + ".xlsx"); - wb.write(response.getOutputStream()); + // ========================= + // 엑셀을 ByteArray로 생성 + // ========================= + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + wb.write(bos); + + if (wb instanceof SXSSFWorkbook) { + ((SXSSFWorkbook) wb).dispose(); // temp 파일 정리 + } + wb.close(); + + byte[] fileBytes = bos.toByteArray(); + response.setContentLength(fileBytes.length); + + // ========================= + // 전송 + // ========================= + OutputStream os = response.getOutputStream(); + os.write(fileBytes); + os.flush(); + os.close(); + wb.close(); } else { createNoDataAlert(response); diff --git a/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-site-index.jsp b/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-site-index.jsp index 07b2c5b..b690c12 100644 --- a/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-site-index.jsp +++ b/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-site-index.jsp @@ -572,133 +572,7 @@ return str.replace(/^\s+|\s+$/g, ''); } - // 엑셀 다운로드 - function clickExcelDownload(){ - /* - const params = new URLSearchParams(); - - params.append("constTag", trim($('#const-tag').val())); - params.append("constName", trim($('#const-name').val())); - params.append("constStartDate", trim($('#const-start-date').val())); - params.append("constEndDate", trim($('#const-end-date').val())); - params.append("constStateCode", trim($('#const-state-code').val())); - params.append("projectStateCode", trim($('#project-state-code').val())); - params.append("constCompanyName", trim($('#company-dept').val())); - params.append("constCompanyAdmin", trim($('#company-admin').val())); - params.append("constCompanyTel", trim($('#company-tel').val())); - params.append("excelDownload", "Y"); - - // 페이지 정보 - const pagingEle = document.getElementById('paging'); - params.append("nPage", pagingEle.getAttribute("data-npage")); - params.append("nCount", pagingEle.getAttribute("data-ncount")); - - // AJAX가 아닌 직접 다운로드 요청 - window.location.href = "/admins/drilling/inquiry/excel.do?" + params.toString(); - $('#excelDownload').val(""); - */ - - const params = new URLSearchParams(); - params.append("constTag", trim($('#const-tag').val())); - params.append("constName", trim($('#const-name').val())); - params.append("excelDownload", "Y"); - - parent[1].showLoadingBar(); - - fetch("/admins/drilling/inquiry/excel.do", { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded" - }, - body: params.toString() - }) - .then(response => { - if (!response.ok) throw new Error("다운로드 실패"); - - const disposition = response.headers.get("Content-Disposition"); - let fileName = "excel.xlsx"; - - if (disposition && disposition.includes("filename=")) { - fileName = disposition.split("filename=")[1].replace(/"/g, ""); - } - - return response.blob().then(blob => ({ blob, fileName })); - }) - .then(({ blob, fileName }) => { - - const url = window.URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = fileName; - document.body.appendChild(a); - a.click(); - a.remove(); - window.URL.revokeObjectURL(url); - }) - .catch(err => { - alert("엑셀 다운로드 중 오류 발생"); - console.error(err); - }) - .finally(() => { - $('#excelDownload').val(""); - parent.hideLoadingBar(); - }); - } - - let currentJobId = null; - - function startExcelDownload() { - - const params = new URLSearchParams(); - params.append("constTag", trim($('#const-tag').val())); - params.append("constName", trim($('#const-name').val())); - params.append("excelDownload", "Y"); - - - parent.showLoadingBar(); -// parent.document.getElementById("progressWrap").style.display = "block"; - - fetch("/admins/drilling/inquiry/excel/start.do", { - method: "POST", - headers: {"Content-Type":"application/x-www-form-urlencoded"}, - body: params.toString() - }) - .then(res => res.json()) - .then(data => { - currentJobId = data.jobId; - pollProgress(); - }); - - $('#excelDownload').val(""); - } - - function pollProgress() { - - fetch("/admins/drilling/inquiry/excel/progress.do?jobId=" + currentJobId) - .then(res => res.json()) - .then(data => { - - let percent = data.progress; - - if(percent < 0){ - alert("엑셀 생성 중 오류 발생"); - return; - } - - parent.document.getElementById("progressBar").style.width = percent + "%"; - parent.document.getElementById("progressText").innerText = percent + "%"; - - if(percent < 100){ - setTimeout(pollProgress, 500); - } else { - setTimeout(function(){ - window.location = "/admins/drilling/inquiry/excel/download.do?jobId=" + currentJobId; - parent.hideLoadingBar(); - }, 700); - } - }); - } - + // 엑셀 다운로드(progress표시) $(document).ready(function() { $(document).on("click", '#btnSubmit', function(e) { diff --git a/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-user-login-history.jsp b/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-user-login-history.jsp index 3b5c454..306cc5b 100644 --- a/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-user-login-history.jsp +++ b/src/main/webapp/WEB-INF/views/admins/constructionProjectManagement/construction-user-login-history.jsp @@ -393,30 +393,112 @@ function drawMultiLineChart(labels, datasets, type){ } } -// 엑셀 다운로드 -function clickExcelDownload(){ - const params = new URLSearchParams(); +// 엑셀 다운로드(progress표시) +$(document).ready(function() { + $(document).on("click", '#btnSubmit', function(e) { + + var canvasModal = parent.document.getElementById("canvasModal"); + var canvas = parent.document.getElementById("canvas"); + var ctx = canvas.getContext("2d"); - params.append("constTag", ""); - params.append("constName", ""); - params.append("constStartDate", ""); - params.append("constEndDate", ""); - params.append("constStateCode", ""); - params.append("projectStateCode", ""); - params.append("constCompanyName", ""); - params.append("constCompanyAdmin", ""); - params.append("constCompanyTel", ""); - params.append("excelDownload", "Y"); + function showPer(per) { + ctx.clearRect(0, 0, canvas.width, canvas.height); - // 페이지 정보 - const pagingEle = document.getElementById('paging'); - params.append("nPage", "0"); - params.append("nCount", "10000"); + // 원형 진행률 + ctx.strokeStyle = "#f66"; + ctx.lineWidth = 10; + ctx.beginPath(); + ctx.arc(canvas.width/2, canvas.height/2, 50, -Math.PI/2, (-Math.PI/2 + 2*Math.PI*per/100)); + ctx.stroke(); - // AJAX가 아닌 직접 다운로드 요청 - window.location.href = "/admins/constructionProjectManagement/excel.do?" + params.toString(); - $('#excelDownload').val(""); -} + // 숫자 표시 + ctx.font = '20px Arial'; + ctx.fillStyle = "#fff"; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(per + '%', canvas.width/2, canvas.height/2); + } + + const params = new URLSearchParams(); + params.append("constTag", ""); + params.append("constName", ""); + params.append("constStartDate", ""); + params.append("constEndDate", ""); + params.append("constStateCode", ""); + params.append("projectStateCode", ""); + params.append("constCompanyName", ""); + params.append("constCompanyAdmin", ""); + params.append("constCompanyTel", ""); + params.append("excelDownload", "Y"); + + // 페이지 정보 + const pagingEle = document.getElementById('paging'); + params.append("nPage", "0"); + params.append("nCount", "10000"); + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/admins/constructionProjectManagement/excel.do?" + params.toString(), true); + xhr.responseType = "blob"; + + var fakePer = 0; + var fakeInterval; + + xhr.onloadstart = function () { + canvasModal.style.display = "flex"; // 모달 표시 + fakePer = 0; + showPer(4); + + // fake progress 시작 (0~90%) + fakeInterval = setInterval(function() { + if (fakePer < 90) { + fakePer += Math.random() * 3; // 0~3%씩 증가 + showPer(Math.floor(fakePer)); + } + }, 100); // 0.1초마다 증가 + }; + + xhr.onprogress = function (e) { + if (e.lengthComputable) { + showPer(Math.floor((e.loaded / e.total) * 100)); + } + }; + + xhr.onload = function () { + if (xhr.status === 200) { + var blob = xhr.response; + + // 서버에서 보낸 Content-Disposition 헤더 확인 + var disposition = xhr.getResponseHeader('Content-Disposition'); + var fileName = "excel.xlsx"; // 기본 파일명 + if (disposition && disposition.indexOf('filename*=') !== -1) { + var matches = disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); + if (matches != null && matches[1]) { + fileName = decodeURIComponent(matches[1]); + // 접두사 UTF-8'' 제거 + fileName = fileName.replace(/^UTF-8''/, ''); + } + } + + // Blob 다운로드 + var link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + link.download = fileName; // 서버에서 가져온 이름 사용 + document.body.appendChild(link); // Firefox에서 필요 + link.click(); + document.body.removeChild(link); + } + }; + + xhr.onloadend = function () { + clearInterval(fakeInterval); // fake progress 중지 + showPer(100); + setTimeout(function () { + canvasModal.style.display = "none"; // 모달 숨김 + }, 500); + }; + + xhr.send(); + }); +}); @@ -506,7 +588,7 @@ function clickExcelDownload(){
- +
diff --git a/src/main/webapp/WEB-INF/views/admins/mgmtApi/api-request-statistics-index.jsp b/src/main/webapp/WEB-INF/views/admins/mgmtApi/api-request-statistics-index.jsp index 9fdda81..a4cdcc1 100644 --- a/src/main/webapp/WEB-INF/views/admins/mgmtApi/api-request-statistics-index.jsp +++ b/src/main/webapp/WEB-INF/views/admins/mgmtApi/api-request-statistics-index.jsp @@ -463,7 +463,8 @@

API 호출 로그

- + +
@@ -1011,15 +1012,97 @@ URL.revokeObjectURL(url); } - // 엑셀 다운로드 - function clickExcelDownload(){ - const params = new URLSearchParams(); + // 엑셀 다운로드(progress표시) + $(document).ready(function() { + $(document).on("click", '#btnSubmit', function(e) { + + var canvasModal = parent.document.getElementById("canvasModal"); + var canvas = parent.document.getElementById("canvas"); + var ctx = canvas.getContext("2d"); - // AJAX가 아닌 직접 다운로드 요청 - window.location.href = "/admins/mgmtApiLog/excel.do?" + params.toString(); - $('#excelDownload').val(""); - } - + function showPer(per) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // 원형 진행률 + ctx.strokeStyle = "#f66"; + ctx.lineWidth = 10; + ctx.beginPath(); + ctx.arc(canvas.width/2, canvas.height/2, 50, -Math.PI/2, (-Math.PI/2 + 2*Math.PI*per/100)); + ctx.stroke(); + + // 숫자 표시 + ctx.font = '20px Arial'; + ctx.fillStyle = "#fff"; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(per + '%', canvas.width/2, canvas.height/2); + } + + const params = new URLSearchParams(); + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/admins/mgmtApiLog/excel.do?" + params.toString(), true); + xhr.responseType = "blob"; + + var fakePer = 0; + var fakeInterval; + + xhr.onloadstart = function () { + canvasModal.style.display = "flex"; // 모달 표시 + fakePer = 0; + showPer(4); + + // fake progress 시작 (0~90%) + fakeInterval = setInterval(function() { + if (fakePer < 90) { + fakePer += Math.random() * 3; // 0~3%씩 증가 + showPer(Math.floor(fakePer)); + } + }, 100); // 0.1초마다 증가 + }; + + xhr.onprogress = function (e) { + if (e.lengthComputable) { + showPer(Math.floor((e.loaded / e.total) * 100)); + } + }; + + xhr.onload = function () { + if (xhr.status === 200) { + var blob = xhr.response; + + // 서버에서 보낸 Content-Disposition 헤더 확인 + var disposition = xhr.getResponseHeader('Content-Disposition'); + var fileName = "excel.xlsx"; // 기본 파일명 + if (disposition && disposition.indexOf('filename*=') !== -1) { + var matches = disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); + if (matches != null && matches[1]) { + fileName = decodeURIComponent(matches[1]); + // 접두사 UTF-8'' 제거 + fileName = fileName.replace(/^UTF-8''/, ''); + } + } + + // Blob 다운로드 + var link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + link.download = fileName; // 서버에서 가져온 이름 사용 + document.body.appendChild(link); // Firefox에서 필요 + link.click(); + document.body.removeChild(link); + } + }; + + xhr.onloadend = function () { + clearInterval(fakeInterval); // fake progress 중지 + showPer(100); + setTimeout(function () { + canvasModal.style.display = "none"; // 모달 숨김 + }, 500); + }; + + xhr.send(); + }); + }); /** * API 호출 통계 날짜 유효검사 */ diff --git a/src/main/webapp/WEB-INF/views/admins/mgmtApi/mgmt-api-key.jsp b/src/main/webapp/WEB-INF/views/admins/mgmtApi/mgmt-api-key.jsp index 296ed3b..be07630 100644 --- a/src/main/webapp/WEB-INF/views/admins/mgmtApi/mgmt-api-key.jsp +++ b/src/main/webapp/WEB-INF/views/admins/mgmtApi/mgmt-api-key.jsp @@ -174,7 +174,8 @@
- + +
@@ -265,15 +266,97 @@ return html; } - // 엑셀 다운로드 - function clickExcelDownload(){ - const params = new URLSearchParams(); + // 엑셀 다운로드(progress표시) + $(document).ready(function() { + $(document).on("click", '#btnSubmit', function(e) { + + var canvasModal = parent.document.getElementById("canvasModal"); + var canvas = parent.document.getElementById("canvas"); + var ctx = canvas.getContext("2d"); - // AJAX가 아닌 직접 다운로드 요청 - window.location.href = "/admins/mgmtApiKey/excel.do?" + params.toString(); - $('#excelDownload').val(""); - } - + function showPer(per) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // 원형 진행률 + ctx.strokeStyle = "#f66"; + ctx.lineWidth = 10; + ctx.beginPath(); + ctx.arc(canvas.width/2, canvas.height/2, 50, -Math.PI/2, (-Math.PI/2 + 2*Math.PI*per/100)); + ctx.stroke(); + + // 숫자 표시 + ctx.font = '20px Arial'; + ctx.fillStyle = "#fff"; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(per + '%', canvas.width/2, canvas.height/2); + } + + const params = new URLSearchParams(); + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/admins/mgmtApiKey/excel.do?" + params.toString(), true); + xhr.responseType = "blob"; + + var fakePer = 0; + var fakeInterval; + + xhr.onloadstart = function () { + canvasModal.style.display = "flex"; // 모달 표시 + fakePer = 0; + showPer(4); + + // fake progress 시작 (0~90%) + fakeInterval = setInterval(function() { + if (fakePer < 90) { + fakePer += Math.random() * 3; // 0~3%씩 증가 + showPer(Math.floor(fakePer)); + } + }, 100); // 0.1초마다 증가 + }; + + xhr.onprogress = function (e) { + if (e.lengthComputable) { + showPer(Math.floor((e.loaded / e.total) * 100)); + } + }; + + xhr.onload = function () { + if (xhr.status === 200) { + var blob = xhr.response; + + // 서버에서 보낸 Content-Disposition 헤더 확인 + var disposition = xhr.getResponseHeader('Content-Disposition'); + var fileName = "excel.xlsx"; // 기본 파일명 + if (disposition && disposition.indexOf('filename*=') !== -1) { + var matches = disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); + if (matches != null && matches[1]) { + fileName = decodeURIComponent(matches[1]); + // 접두사 UTF-8'' 제거 + fileName = fileName.replace(/^UTF-8''/, ''); + } + } + + // Blob 다운로드 + var link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + link.download = fileName; // 서버에서 가져온 이름 사용 + document.body.appendChild(link); // Firefox에서 필요 + link.click(); + document.body.removeChild(link); + } + }; + + xhr.onloadend = function () { + clearInterval(fakeInterval); // fake progress 중지 + showPer(100); + setTimeout(function () { + canvasModal.style.display = "none"; // 모달 숨김 + }, 500); + }; + + xhr.send(); + }); + }); // 승인처리하기 function toggleApproveKey(ele) { let apiSeq = $(ele).data("seq") diff --git a/src/main/webapp/WEB-INF/views/admins/mgmtApi/mgmt-api-outdata.jsp b/src/main/webapp/WEB-INF/views/admins/mgmtApi/mgmt-api-outdata.jsp index c2137c6..2dc8410 100644 --- a/src/main/webapp/WEB-INF/views/admins/mgmtApi/mgmt-api-outdata.jsp +++ b/src/main/webapp/WEB-INF/views/admins/mgmtApi/mgmt-api-outdata.jsp @@ -462,7 +462,8 @@

API 호출 로그

- + +
@@ -1010,16 +1011,98 @@ document.body.removeChild(a); URL.revokeObjectURL(url); } - - // 엑셀 다운로드 - function clickExcelDownload(){ - const params = new URLSearchParams(); - // AJAX가 아닌 직접 다운로드 요청 - window.location.href = "/admins/mgmtApiLog/o_excel.do?" + params.toString(); - $('#excelDownload').val(""); - } - + // 엑셀 다운로드(progress표시) + $(document).ready(function() { + $(document).on("click", '#btnSubmit', function(e) { + + var canvasModal = parent.document.getElementById("canvasModal"); + var canvas = parent.document.getElementById("canvas"); + var ctx = canvas.getContext("2d"); + + function showPer(per) { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // 원형 진행률 + ctx.strokeStyle = "#f66"; + ctx.lineWidth = 10; + ctx.beginPath(); + ctx.arc(canvas.width/2, canvas.height/2, 50, -Math.PI/2, (-Math.PI/2 + 2*Math.PI*per/100)); + ctx.stroke(); + + // 숫자 표시 + ctx.font = '20px Arial'; + ctx.fillStyle = "#fff"; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText(per + '%', canvas.width/2, canvas.height/2); + } + + const params = new URLSearchParams(); + var xhr = new XMLHttpRequest(); + xhr.open("GET", "/admins/mgmtApiLog/o_excel.do?" + params.toString(), true); + xhr.responseType = "blob"; + + var fakePer = 0; + var fakeInterval; + + xhr.onloadstart = function () { + canvasModal.style.display = "flex"; // 모달 표시 + fakePer = 0; + showPer(4); + + // fake progress 시작 (0~90%) + fakeInterval = setInterval(function() { + if (fakePer < 90) { + fakePer += Math.random() * 3; // 0~3%씩 증가 + showPer(Math.floor(fakePer)); + } + }, 100); // 0.1초마다 증가 + }; + + xhr.onprogress = function (e) { + if (e.lengthComputable) { + showPer(Math.floor((e.loaded / e.total) * 100)); + } + }; + + xhr.onload = function () { + if (xhr.status === 200) { + var blob = xhr.response; + + // 서버에서 보낸 Content-Disposition 헤더 확인 + var disposition = xhr.getResponseHeader('Content-Disposition'); + var fileName = "excel.xlsx"; // 기본 파일명 + if (disposition && disposition.indexOf('filename*=') !== -1) { + var matches = disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); + if (matches != null && matches[1]) { + fileName = decodeURIComponent(matches[1]); + // 접두사 UTF-8'' 제거 + fileName = fileName.replace(/^UTF-8''/, ''); + } + } + + // Blob 다운로드 + var link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + link.download = fileName; // 서버에서 가져온 이름 사용 + document.body.appendChild(link); // Firefox에서 필요 + link.click(); + document.body.removeChild(link); + } + }; + + xhr.onloadend = function () { + clearInterval(fakeInterval); // fake progress 중지 + showPer(100); + setTimeout(function () { + canvasModal.style.display = "none"; // 모달 숨김 + }, 500); + }; + + xhr.send(); + }); + }); /** * API 호출 통계 날짜 유효검사 */