var selectedPdServiceId; // 제품(서비스) 아이디 var selectedVersionIds; // 선택된 버전 아이디 var selectedAlmProjectIds; // 선택된 ALM Project 아이디 var selectedAssigneeEmails; // 선택된 담당자 아이디 var previousStartDate = null; var previousEndDate = null; var pdServiceListData; var versionListData; var selectedIndex; // 데이터테이블 선택한 인덱스 var selectedPage; // 데이터테이블 선택한 인덱스 var searchOptionalParam; var currentDate; let fullCalendar = null; let fullTimeLine = null; let userLocale = navigator.language || "en"; //////////////////////////////////////////////////////////////////////////////////////// //Document Ready //////////////////////////////////////////////////////////////////////////////////////// function execDocReady() { var pluginGroups = [ [ "../reference/light-blue/lib/vendor/jquery.ui.widget.js", "../reference/light-blue/lib/vendor/http_blueimp.github.io_JavaScript-Templates_js_tmpl.js", "../reference/light-blue/lib/vendor/http_blueimp.github.io_JavaScript-Load-Image_js_load-image.js", "../reference/light-blue/lib/vendor/http_blueimp.github.io_JavaScript-Canvas-to-Blob_js_canvas-to-blob.js", "../reference/light-blue/lib/jquery.iframe-transport.js", "../reference/light-blue/lib/jquery.fileupload.js", "../reference/light-blue/lib/jquery.fileupload-fp.js", "../reference/light-blue/lib/jquery.fileupload-ui.js", "../reference/lightblue4/docs/lib/widgster/widgster.js", "../reference/lightblue4/docs/lib/slimScroll/jquery.slimscroll.min.js", "../reference/jquery-plugins/timerStyles.js" ], [ "../reference/jquery-plugins/select2-4.0.2/dist/css/select2_lightblue4.css", "../reference/jquery-plugins/lou-multi-select-0.9.12/css/multiselect-lightblue4.css", "../reference/jquery-plugins/multiple-select-1.5.2/dist/multiple-select-bluelight.css", "../reference/jquery-plugins/select2-4.0.2/dist/js/select2.min.js", "../reference/jquery-plugins/lou-multi-select-0.9.12/js/jquery.quicksearch.js", "../reference/jquery-plugins/lou-multi-select-0.9.12/js/jquery.multi-select.js", "../reference/jquery-plugins/multiple-select-1.5.2/dist/multiple-select.min.js", //날짜 검색 "../reference/light-blue/lib/bootstrap-datepicker.js", "../reference/jquery-plugins/datetimepicker-2.5.20/build/jquery.datetimepicker.min.css", "../reference/jquery-plugins/datetimepicker-2.5.20/build/jquery.datetimepicker.full.min.js" ], [ // lightblue4 "../reference/jquery-plugins/dataTables-1.10.16/media/css/jquery.dataTables_lightblue4.css", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Responsive/css/responsive.dataTables_lightblue4.css", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Select/css/select.dataTables_lightblue4.css", "../reference/jquery-plugins/dataTables-1.10.16/media/js/jquery.dataTables.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Responsive/js/dataTables.responsive.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Select/js/dataTables.select.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/RowGroup/js/dataTables.rowsGroup.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/dataTables.buttons.min.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/buttons.html5.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/buttons.print.js", "../reference/jquery-plugins/dataTables-1.10.16/extensions/Buttons/js/jszip.min.js" ], [ "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jsuites.js", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/index.js", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jsuites.css", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jspreadsheet.css", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jspreadsheet.datatables.css", "../reference/jquery-plugins/jspreadsheet-ce-4.13.1/dist/jspreadsheet.theme.css", "../reference/jquery-plugins/fullcalendar-6.1.15/dist/index.global.js", "./js/common/jspreadsheet/spreadsheet.js", "./css/jspreadsheet/custom_sheet.css", //chart Colors "./js/common/colorPalette.js" // 추가적인 플러그인 그룹들을 이곳에 추가하면 됩니다.(그룹 최대 4개) ] ]; loadPluginGroupsParallelAndSequential(pluginGroups) .then(function() { console.log('모든 플러그인 로드 완료'); //사이드 메뉴 처리 $('.widget').widgster(); setSideMenu("sidebar_menu_report", "sidebar_menu_report_full_data"); //제품(서비스) 셀렉트 박스 이니시에이터 makePdServiceSelectBox(); //버전 멀티 셀렉트 박스 이니시에이터 makeVersionMultiSelectBox(); // 작업자 목록 멀티 셀렉트 박스 이니시에이터 makeAssigneesMultiSelectBox(); // ALM 프로젝트 멀티 셀렉트 박스 이니시에이터 makeProjectMultiSelectBox(); //날짜 dateTimePicker(); // 제품 서비스 검색 필터 초기화 pdServiceFilterClear(); // 높이 조정 $('.top-menu-div').matchHeight({ target: $('.top-menu-div-default') }); // 오늘 날짜 설정 currentDate = getCurrentDate(); // 테이블 초기화 fetchJiraProjects(); fetchAssignees(); fetchExcelData(); }) .catch(function(e) { console.error('플러그인 로드 중 오류 발생'); console.error(e); }); }//.execDocReady /////////////////////// // 제품 서비스 검색 필터 초기화 ////////////////////// function pdServiceFilterClear() { $("#pdservice_filter_clear").on("click", function() { $("#selected_pdService").val(null).trigger("change"); $("#multiple-version option").remove(); $("#multiple-version").multipleSelect("refresh"); selectedPdServiceId = null; selectedVersionIds = null; let optionalParams = setOptionalParams(); if (!isAllAssigneesSelected()) { optionalParams.emailAddress = selectedAssigneeEmails; } fetchExcelData(undefined, optionalParams); }); } /////////////////////// //제품 서비스 셀렉트 박스 ////////////////////// function makePdServiceSelectBox() { //제품 서비스 셀렉트 박스 이니시에이터 $(".chzn-select").each(function() { $(this).select2($(this).data()); }); //제품 서비스 셀렉트 박스 데이터 바인딩 $.ajax({ url: "/auth-user/api/arms/pdServicePure/getPdServiceMonitor.do", type: "GET", contentType: "application/json;charset=UTF-8", dataType: "json", progress: true, statusCode: { 200: function(data) { ////////////////////////////////////////////////////////// pdServiceListData = []; for (var k in data.response) { var obj = data.response[k]; pdServiceListData.push({ "pdServiceId": obj.c_id, "pdServiceName": obj.c_title }); var newOption = new Option(obj.c_title, obj.c_id, false, false); $("#selected_pdService").append(newOption).trigger("change"); } ////////////////////////////////////////////////////////// console.log("[fullDataSheet :: makePdServiceSelectBox] :: pdServiceListData => "); console.table(pdServiceListData); } } }); $("#selected_pdService").on("select2:open", function() { //슬림스크롤 makeSlimScroll(".select2-results__options"); }); // --- select2 ( 제품(서비스) 검색 및 선택 ) 이벤트 --- // $("#selected_pdService").on("select2:select", function(e) { selectedPdServiceId = $("#selected_pdService").val(); //refreshDetailChart(); 변수값_초기화(); // 제품( 서비스 ) 선택했으니까 자동으로 버전을 선택할 수 있게 유도 // 디폴트는 base version 을 선택하게 하고 ( select all ) //~> 이벤트 연계 함수 :: Version 표시 jsTree 빌드 bind_VersionData_By_PdService(); }); } // end makePdServiceSelectBox() function bind_VersionData_By_PdService() { $("#multiple-version option").remove(); $.ajax({ url: "/auth-user/api/arms/pdService/getVersionList?c_id=" + $("#selected_pdService").val(), type: "GET", dataType: "json", progress: true, statusCode: { 200: function(data) { ////////////////////////////////////////////////////////// var pdServiceVersionIds = []; versionListData = []; for (var k in data.response) { var obj = data.response[k]; pdServiceVersionIds.push(obj.c_id); versionListData.push({"c_id" : obj.c_id, "c_title" : obj.c_title, "start_date" : obj.c_pds_version_start_date, "end_date" : obj.c_pds_version_end_date}); var newOption = new Option(obj.c_title, obj.c_id, true, false); $("#multiple-version").append(newOption); } selectedVersionIds = pdServiceVersionIds.join(","); $("#multiple-version") .multipleSelect("refresh") .multipleSelect("checkAll"); // 시작일 종료일 세팅(datetimepicker) setEdgeDateRange(versionListData); let optionalParams = setOptionalParams(); if (!isAllAssigneesSelected()) { optionalParams.emailAddress = selectedAssigneeEmails; } fetchExcelData(selectedPdServiceId, optionalParams); if (data.length > 0) { console.log("display 재설정."); } } } }); } //////////////////////////////////////// //버전 멀티 셀렉트 박스 //////////////////////////////////////// function makeVersionMultiSelectBox() { //버전 선택시 셀렉트 박스 이니시에이터 $("#multiple-version").multipleSelect({ filter: true, // selectBox 닫혔을 때 onClose: function() { var versionTag = $("#multiple-version").val(); console.log("[ fullDataSheet :: makeVersionMultiSelectBox ] :: versionTag"); console.log(versionTag); selectedVersionIds = versionTag.join(","); if (versionTag === null || versionTag == "") { alert("버전이 선택되지 않았습니다."); $("#multiple-version").siblings(".ms-parent").css("z-index", 1000); return; } let filteredVersionData = versionListData.filter(item => versionTag.includes(item.c_id.toString())); // 시작일 종료일 세팅(datetimepicker) setEdgeDateRange(filteredVersionData); let optionalParams = setOptionalParams(); $("#multiple-version").siblings(".ms-parent").css("z-index", 1000); if (!isAllAssigneesSelected()) { optionalParams.emailAddress = selectedAssigneeEmails; } fetchExcelData(selectedPdServiceId, optionalParams); }, // selectBox 열렸을 때 onOpen: function() { $("#multiple-version").siblings(".ms-parent").css("z-index", 9999); } }); } //////////////////////////////////////// // 작업자 select 이벤트 핸들링 //////////////////////////////////////// function makeAssigneesMultiSelectBox () { // ALM 프로젝트 선택 시 셀렉트 박스 이니시에이터 $("#multiple-assignees").multipleSelect({ filter: true, onClose: function() { let assigneesArray = $("#multiple-assignees").val(); let assigneesString = assigneesArray.join(","); if(assigneesString === selectedAssigneeEmails) { return false; } else { selectedAssigneeEmails = assigneesString; } let optionalParams = setOptionalParams(); if (!isAllAssigneesSelected()) { optionalParams.emailAddress = selectedAssigneeEmails; } fetchExcelData(selectedPdServiceId, optionalParams); $("#multiple-assignees").siblings(".ms-parent").css("z-index", 1000); }, onOpen: function() { $("#multiple-assignees").siblings(".ms-parent").css("z-index", 9999); } }); } //////////////////////////////////////// // ALM 프로젝트 select 이벤트 핸들링 //////////////////////////////////////// function makeProjectMultiSelectBox () { // ALM 프로젝트 선택 시 셀렉트 박스 이니시에이터 $("#multiple-alm-project").multipleSelect({ filter: true, onClose: function() { let projectIds = $("#multiple-alm-project").val(); selectedAlmProjectIds = projectIds.join(","); let optionalParams = setOptionalParams(); if (!isAllAssigneesSelected()) { optionalParams.emailAddress = selectedAssigneeEmails; } fetchExcelData(selectedPdServiceId, optionalParams); $("#multiple-alm-project").siblings(".ms-parent").css("z-index", 1000); }, onOpen: function() { $("#multiple-alm-project").siblings(".ms-parent").css("z-index", 9999); } }); } //////////////////////////////////////// // 검색 조건을 선택하여 API 호출 시, 제품 버전이 모두 선택되어 있는지 체크하는 함수 // 모두 선택 된 경우, query param 으로 보낼 필요가 없기 때문 //////////////////////////////////////// function isAllVersionsSelected() { if (!selectedVersionIds) { return false; } return $("#multiple-version option").length === selectedVersionIds.split(",").length; } //////////////////////////////////////// // 검색 조건을 선택하여 API 호출 시, 작업자가 모두 선택되어 있는지 체크하는 함수 // 모두 선택 된 경우, query param 으로 보낼 필요가 없기 때문 //////////////////////////////////////// function isAllAssigneesSelected() { if (!selectedAssigneeEmails) { return false; } return $("#multiple-assignees option").length === selectedAssigneeEmails.split(",").length; } //////////////////////////////////////// // 선택 된 제품, 제품 버전 ID 값을 서버에 전달하여 관련 ALM 프로젝트 목록 조회 //////////////////////////////////////// function fetchJiraProjects() { $("#multiple-alm-project option").remove(); $.ajax({ url: "/auth-user/api/arms/jiraProjectPure/getJiraProjects.do", type: "GET", dataType: "json", success: function(data) { console.log("[Jira Projects] Data:", data); for (var k in data.response) { let obj = data.response[k]; let newOption = new Option(obj.c_title, obj.c_id, true, false); $("#multiple-alm-project").append(newOption); } $("#multiple-alm-project").multipleSelect("refresh"); }, error: function(xhr, status, error) { console.error("[Jira Projects] Error:", error); } }); } //////////////////////////////////////// // 모든 검색 필터(제품, 제품 버전, ALM 프로젝트, 날짜 등) 선택이 완료 된 경우, 데이터를 조회한다. //////////////////////////////////////// function fetchAssignees(pdServiceId, optionalParams = {}) { $("#multiple-assignees option").remove(); let urlBuilder = new UrlBuilder() .setBaseUrl('/auth-user/api/arms/report/full-data/assignee-list'); const { pdServiceVersionIds = null, almProjectIds = null, startDate = null, endDate = null, emailAddress = null } = optionalParams; const optionalQueryParams = { pdServiceVersionIds, almProjectIds, startDate, endDate, emailAddress }; Object.entries(optionalQueryParams).forEach(([key, value]) => { if (value) { urlBuilder.addQueryParam(key, value); } }); const url = urlBuilder.build(); $.ajax({ url: url, type: "GET", dataType: "json", success: function(data) { console.log(data.response); for (var k in data.response) { let obj = data.response[k]; let displayName = obj.displayName + "(" + obj.emailAddress + ")"; let newOption = new Option(displayName, obj.emailAddress, true, false); $("#multiple-assignees").append(newOption); } $("#multiple-assignees").multipleSelect("refresh"); }, error: function(xhr, status, error) { console.error("[GET Assignees] Error:", error); } }); } function fetchExcelData(pdServiceId, optionalParams = {}) { let urlBuilder = new UrlBuilder() .setBaseUrl('/auth-user/api/arms/report/full-data/excel-data'); if (pdServiceId !== undefined) { urlBuilder.addQueryParam("pdServiceId", pdServiceId); } const { pdServiceVersionIds = null, almProjectIds = null, startDate = null, endDate = null, emailAddress = null } = optionalParams; const optionalQueryParams = { pdServiceVersionIds, almProjectIds, startDate, endDate, emailAddress }; Object.entries(optionalQueryParams).forEach(([key, value]) => { if (value) { urlBuilder.addQueryParam(key, value); } }); searchOptionalParam = optionalQueryParams; const url = urlBuilder.build(); console.log("[ reportFullData :: fetchExcelData ] ::requestURL => ", url); $.ajax({ url: url, type: "GET", dataType: "json", success: function(data) { console.log("[ reportFullData :: fetchExcelData ] :: excelData.legnth => ", data !== null ? data.response.length : 0); drawExcel("spreadsheet", data.response); let sortedData = [...data.response].sort((a, b) => new Date(a.createDate) - new Date(b.createDate)); drawCalendar(sortedData); }, error: function(xhr, status, error) { console.error(error); } }); } function updateHeaderTextStyle() { //$("#spreadsheet")[0] const headers = $("#spreadsheet")[0].querySelectorAll(".jexcel > thead > tr > td"); // 특정 헤더 값을 수정하고 스타일 적용 headers.forEach((header) => { const title = header.innerText; if (title.includes("요구사항")) { let updatedReqHTML = title.replace( "요구사항", '요구사항' ); header.innerHTML = updatedReqHTML; } else if (title.includes("이슈")) { let updatedIssueHTML = title.replace( "이슈", '이슈' ); header.innerHTML = updatedIssueHTML; } }); } //////////////////////////////////////// // 기간 설정 세팅 //////////////////////////////////////// function dateTimePicker() { $('#date_timepicker_start').datetimepicker({ format: 'Y-m-d', formatDate: 'Y/m/d', timepicker: false, theme: 'dark', lang: "kr", onShow: function(ct) { this.setOptions({ maxDate: $('#date_timepicker_end').val() ? $('#date_timepicker_end').val() : false }); }, onClose: function(dp, $input) { // 달력이 닫힐 때만 API 호출 let newStartDate = $input.val(); if (previousStartDate !== newStartDate && newStartDate) { previousStartDate = newStartDate; let optionalParams = setOptionalParams(); if (!isAllAssigneesSelected()) { optionalParams.emailAddress = selectedAssigneeEmails; } fetchExcelData(selectedPdServiceId, optionalParams); } } }); $('#date_timepicker_end').datetimepicker({ format: 'Y-m-d', formatDate: 'Y/m/d', timepicker: false, theme: 'dark', lang: "kr", onShow: function(ct) { this.setOptions({ minDate: $('#date_timepicker_start').val() ? $('#date_timepicker_start').val() : false }); }, onClose: function(dp, $input) { let newEndDate = $input.val(); if (previousEndDate !== newEndDate && newEndDate) { previousEndDate = newEndDate; let optionalParams = setOptionalParams(); if (!isAllAssigneesSelected()) { optionalParams.emailAddress = selectedAssigneeEmails; } fetchExcelData(selectedPdServiceId, optionalParams); } } }); } //////////////////////////////////////// // 선택한 버전 - min,max 날짜 세팅 //////////////////////////////////////// function setEdgeDateRange(versionData) { if (!versionData || Object.keys(versionData).length === 0) { console.log("[ fullDataSheet :: setEdgeDateRange ] :: versionData 가 없습니다."); return false; } let minMaxDate = versionData.reduce((acc, curr) => { const startDate = new Date(curr.start_date); const endDate = new Date(curr.end_date); if (!acc.min || startDate < acc.min) { acc.min = startDate; } if (!acc.max || endDate > acc.max) { acc.max = endDate; } return acc; }, { min: null, max: null }); console.log("[ fullDataSheet :: setEdgeDateRange ] :: " + "minMaxDate.min => " + minMaxDate.min+ ", minMaxDate.max => " +minMaxDate.max); const oneMonthAgo = new Date(minMaxDate.max); oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1); if (oneMonthAgo > minMaxDate.min) { oneMonthAgo.setTime(minMaxDate.min.getTime()); } $('#date_timepicker_start').datetimepicker('setOptions', { value: oneMonthAgo }); $('#date_timepicker_end').datetimepicker('setOptions', { value: minMaxDate.max }); } // -------------------- 데이터 테이블을 만드는 템플릿으로 쓰기에 적당하게 리팩토링 함. ------------------ // // 데이터 테이블 구성 이후 꼭 구현해야 할 메소드 : 열 클릭시 이벤트 function dataTableClick(tempDataTable, selectedData) { console.log(selectedData); } // 데이터 테이블 데이터 렌더링 이후 콜백 함수. function dataTableCallBack(settings, json) { console.log("check"); } function dataTableDrawCallback(tableInfo) { console.log(tableInfo); } ///////////////////////////////////////////////// // 엑셀 그리기 ///////////////////////////////////////////////// function drawExcel(target, data) { var columnList = [ { readOnly: true, type: "text", name:"pdServiceName", title: "제품(서비스)", wRatio: 0.1 }, //0 { readOnly: true, type: "text", name:"pdServiceVersionNames", title: "버전(일정)", wRatio: 0.1 }, //1 버전(시작일 ~ 종료일) { readOnly: true, type: "text", name:"almProjectName", title: "ALM Project", wRatio: 0.1 }, //2 ALM Project { readOnly: true, type: "text", name:"isReqName", title: "ALM 이슈 구분", wRatio: 0.1 }, //3 요구사항 이슈, 연결이슈, 하위이슈 { readOnly: true, type: "text", name: "key", title: "ALM 이슈 키", wRatio: 0.1 }, //4 (필수) { readOnly: true, type: "text", name:"reqTitle", title: "A-RMS 요구사항", wRatio: 0.2 }, //5 암스가 생성한 요구사항 { readOnly: true, type: "text", name:"reqState", title: "A-RMS 요구사항 상태", wRatio: 0.1 }, //6 암스 요구사항 상태 { readOnly: true, type: "text", name:"issueTitle", title: "ALM 이슈 제목", wRatio: 0.2 }, //7 { readOnly: true, type: "text", name:"issueStatus", title: "ALM 이슈 상태", wRatio: 0.1 }, //8 { readOnly: true, type: "text", name:"assigneeName", title: "ALM 이슈 담당자", wRatio: 0.1 }, //9 { readOnly: true, type: "calendar", options: {format: "YYYY/MM/DD"}, name: "createDate", title: "ALM 이슈 생성일", wRatio: 0.1 }, //10 { readOnly: true, type: "calendar", options: {format: "YYYY/MM/DD"}, name: "updatedDate", title: "ALM 이슈 수정일", wRatio: 0.1 }, //11 { readOnly: true, type: "calendar", options: {format: "YYYY/MM/DD"}, name: "resolutionDate", title: "ALM 이슈 해결일", wRatio: 0.1 }, //12 해결된 날짜 또는 닫힌 날짜 { readOnly: true, type: "hidden", name: "pdServiceVersions", title: "버전키", wRatio: 0.1 }, //13 (필수X) { readOnly: true, type: "hidden", name: "pdServiceId", title: "제품서비스키", wRatio: 0.1 }, //14 (필수X) { readOnly: true, type: "hidden", name: "assigneeEmail", title: "담당자메일", wRatio: 0.1 }, //15 (필수X) { readOnly: true, type: "hidden", name: "upperKey", title: "upperKey", wRatio: 0.1 }, //16 (필수X) { readOnly: true, type: "hidden", name: "issueID", title: "issueID", wRatio: 0.1 }, //17 (필수X) { readOnly: true, type: "hidden", name: "parentReqKey", title: "parentReqKey", wRatio: 0.1 }, //18 (필수X) { readOnly: true, type: "hidden", name: "etc", title: "etc", wRatio: 0.1 }, //19 (필수X) { readOnly: true, type: "hidden", name: "isReq", title: "isReq", wRatio: 0.1 }, //20 (필수X) { readOnly: true, type: "hidden", name: "creqLink", title: "cReqLink", wRatio: 0.1 }, //21 (필수X) { readOnly: true, type: "hidden", name: "deletedDate", title: "deletedDate", wRatio: 0.1 }, //22 (필수X) { readOnly: true, type: "hidden", name: "dummy", title: "dummy", wRatio: 0.1 } //22 (필수X) ]; var customOption = { toolbar: toolbarCustom, pagination: 30, contextMenu: [], search: true, allowInsertRow: false, allowInsertColumn: false, columnSorting: false, onload: function (element) { var $jexcel = $(element); var $searchInput = $('' + ' ' + ''); $jexcel.find(".jexcel_toolbar_item[data-k='undo']").addClass("fa fa-mail-reply "); $jexcel.find(".jexcel_toolbar_item[data-k='redo']").addClass("fa fa-mail-forward "); $jexcel.find(".jexcel_toolbar_item[data-k='save']").addClass("fa fa-save"); $jexcel.find(".jexcel_toolbar_item[data-k='text-align'][data-v='left']").addClass("fa fa-align-left fa-flip-vertical"); $jexcel.find(".jexcel_toolbar_item[data-k='text-align'][data-v='center']").addClass("fa fa-align-center fa-flip-vertical"); $jexcel.find(".jexcel_toolbar_item[data-k='text-align'][data-v='right']").addClass("fa fa-align-right fa-flip-vertical"); $jexcel.find(".jexcel_toolbar_item[data-k='font-weight'][data-v='bold']").addClass("fa fa-bold"); $jexcel.find(".jexcel_toolbar_item[data-k='font-style'][data-v='italic']").addClass("fa fa-italic"); $jexcel.find(".jexcel_toolbar_item[data-k='text-decoration'][data-v='underline']").addClass("fa fa-underline"); $jexcel.find(".jexcel_toolbar_item[data-k='text-decoration'][data-v='line-through']").addClass("fa fa-strikethrough"); $jexcel.find(".jexcel_toolbar_item[data-k='color']").addClass("fa fa-font"); $jexcel.find(".jexcel_toolbar_item[data-k='background-color']").addClass("fa fa-font fa-background"); $jexcel.find(".jexcel_filter").addClass("hidden"); $jexcel.find(".jexcel_toolbar_item[data-k='search-box']").addClass("search-box").append($searchInput); // 검색 input 에 focus 일때, 선택 초기화 var $inputField = $searchInput.find('input.jexcel_search'); if ($inputField.length) { $inputField.on('focus', function() { if (element.jexcel) { element.jexcel.resetSelection(); } }); } // 헤더 텍스트 스타일 업데이트(요구사항, 이슈) updateHeaderTextStyle(); }, updateTable: function(instace, cell, col, row, val, id) { cell.style.whiteSpace = "normal"; cell.style.textAlign = "left"; cell.style.color = "#a4c6ff"; if (col === 20 && val !== true) { // 현재 행(row)에 해당하는 모든 셀 가져오기 let rowCells = cell.parentElement.children; // 해당 행의 모든 셀의 글꼴 색상을 red로 변경 for (let i = 0; i < 14; i++) { rowCells[i].style.color = "#f8f8f8"; } } } }; SpreadsheetFunctions.setTargetId(target); SpreadsheetFunctions.setDefaultTargetRect(); SpreadsheetFunctions.setColumns(columnList); SpreadsheetFunctions.setColumnWidth(SpreadsheetFunctions.getTargetRect("width")); SpreadsheetFunctions.setOptions(customOption); SpreadsheetFunctions.startObserver(); SpreadsheetFunctions.setExcelData(data); SpreadsheetFunctions.drawExcel(SpreadsheetFunctions.getTargetId()); } var SpreadsheetFunctions = (function () { let targetId = { "v" : "", "jq" : ""}; let targetRect = {"width" : 0, "height" : 0}; let excelData; // 엑셀 데이터 let excelColumns; // 엑셀 컬럼 let customOptions;// 엑셀 커스텀 옵션들 :: 정의 안할 경우 default var setDefaultTargetRect = function () { let defaultWidth = $(getTargetId("jq")).width(); let defaultHeight = $(getTargetId("jq")).height(); setTargetRect(defaultWidth, defaultHeight); }; var setTargetRect = function(width, height) { targetRect.width = width; targetRect.height = height; }; var getTargetRect = function (type) { if (type === "width") { return targetRect.width; } else if (type === "height") { return targetRect.height; } else { return targetRect; } }; var setTargetId = function (target) { targetId.v = target; targetId.jq = "#"+target; }; var getTargetId = function (type) { if (type === "jq") { return targetId.jq; } else { return targetId.v; } }; var setExcelData = function(data) { excelData = data; }; var getExcelData = function () { return excelData; }; var setColumns = function(columns) { excelColumns = columns; }; var getColumns = function () { return excelColumns; }; var setColumnWidth = function (width) { if (excelColumns) { excelColumns = excelColumns.map(column => ({ ...column, width: (width * column.wRatio) -1 })); } }; function setColumnWidthAsync(width) { return new Promise((resolve) => { if (excelColumns) { excelColumns = excelColumns.map(column => ({ ...column, width: (width * column.wRatio) - 1 })); } resolve(); // 컬럼 너비 설정이 완료된 후 resolve 호출 }); } var setOptions = function(options) { customOptions = options; }; var getOptions = function() { return customOptions ? customOptions : null; }; var resizeObserver = new ResizeObserver(function(entries) { for (let entry of entries) { setTargetRect(entry.contentRect.width, entry.contentRect.height); handleResize(entry.target.id, getTargetRect("width"), getTargetRect("height")); } }); // 모달요소 크기 변화 관찰(Observer) function startObserver() { resizeObserver.observe($(getTargetId("jq"))[0]); } function handleResize(id, width, height) { if (id === getTargetId() && height !== 0) { if (excelData) { drawResizedExcel(getTargetId()); } else { console.log("Spreadsheet.handleResize :: 엑셀 데이터 없음"); } } else { console.log("Spreadsheet.handleResize :: id 불일치 또는 height 가 0 입니다."); } } function drawResizedExcel(target) { let $targetId = "#"+target; if($($targetId).length > 0 && $($targetId)[0].jexcel) { $($targetId)[0].jexcel.destroy(); } setColumnWidthAsync(getTargetRect("width") - 50).then(() => { $($targetId).spreadsheet($.extend({}, { columns: getColumns(), data: getExcelData() }, getOptions())); let jexcel_content_height = getTargetRect("height") - 40 - 30 - 35 - 34; $($targetId + " .jexcel_content").css("max-height", jexcel_content_height); $($targetId + " .jexcel_content").css("width", "100%"); }); } function drawExcel(target) { let $targetId = "#"+target; if($($targetId).length > 0 && $($targetId)[0].jexcel) { $($targetId)[0].jexcel.destroy(); } $($targetId).spreadsheet($.extend({}, { columns: getColumns(), data: getExcelData() }, getOptions())); let jexcel_content_height = getTargetRect("height") - 40 - 30 - 35 - 34; $($targetId + " .jexcel_content").css("max-height", jexcel_content_height); $($targetId + " .jexcel_content").css("width", "100%"); } return { setTargetId, getTargetId, setTargetRect, getTargetRect, setDefaultTargetRect, setExcelData, getExcelData, setColumns, getColumns, setColumnWidth, setOptions, getOptions, startObserver, drawExcel }; })(); /////////////////////////////////////////////////// // 엑셀데이터 Export (JSON) ///////////////////////////////////////////////// function jsonExport() { let csvDataList = $(SpreadsheetFunctions.getTargetId("jq"))[0].jexcel.getData(); if (csvDataList.length === 0) { console.log("[ reportFullData :: jsonExport ] :: excelData 가 없습니다."); return false; } const jsonArray = csvDataList.map(row => { const jsonObject = {}; SpreadsheetFunctions.getColumns().forEach((column,index) => { jsonObject[column.title] = row[index]; }); return jsonObject; }); //let jsonResult = [jsonArray]; let currentDate = date_YYMMDD(); let fileName = "fullData_" + currentDate; downloadJSON(fileName, jsonArray); } function downloadJSON(filename, jsonObject) { const jsonData = JSON.stringify(jsonObject, null, 2); const blob = new Blob([jsonData], { type: 'application/json' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = filename; link.click(); URL.revokeObjectURL(link.href); } /////////////////////////////////////////////////// // 엑셀데이터 Export (CSV) ///////////////////////////////////////////////// function csvExport() { $(".jexcel_toolbar_item.material-icons.fa.fa-save").click(); } function excelExport() { let urlBuilder = new UrlBuilder() .setBaseUrl('/auth-user/api/arms/report/full-data/excel-data-down'); if (selectedPdServiceId) { urlBuilder.addQueryParam("pdServiceId", selectedPdServiceId); } if (selectedVersionIds) { urlBuilder.addQueryParam("pdServiceVersionIds", selectedVersionIds); } Object.entries(searchOptionalParam).forEach(([key, value]) => { if (value) { urlBuilder.addQueryParam(key, value); } }); let fileName = "ARMS_FULL_DATA_SEARCH_"+currentDate; urlBuilder.addQueryParam("fileName",fileName); const url = urlBuilder.build(); $.ajax({ url: url, type: "GET", xhrFields: { responseType: 'blob' // 바이너리 데이터를 받을 수 있도록 설정 }, success: function(data, status, xhr) { // 서버에서 받은 blob 데이터를 사용하여 파일 다운로드 처리 const blob = new Blob([data], { type: 'application/octet-stream' }); const link = document.createElement('a'); const url = window.URL.createObjectURL(blob); // 파일 이름이 Content-Disposition 헤더에서 제공된 경우 이를 사용 const contentDisposition = xhr.getResponseHeader('Content-Disposition'); let downLoadfileName = fileName+'.xlsx'; //기본 파일명 if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { const fileNameMatch = contentDisposition.match(/filename="(.+)"/); if (fileNameMatch != null && fileNameMatch.length === 2) { downLoadfileName = fileNameMatch[1]; } } link.href = url; link.setAttribute('download', downLoadfileName); // 파일 이름 설정 document.body.appendChild(link); link.click(); link.parentNode.removeChild(link); }, error: function(xhr, status, error) { console.error(error); } }); } let date_YYMMDD = function () { let date = new Date(); let year = String(date.getFullYear()).slice(2); let month = String(date.getMonth() + 1).padStart(2, '0'); let day = String(date.getDate()).padStart(2, '0'); return year + month + day; } /////////////////////////////////////////////////// // fetchExcelData API 콜 이전 선택 인자들 값 세팅 ///////////////////////////////////////////////// function setOptionalParams() { let optionalParams = {}; if (!isEmpty($("#date_timepicker_start").val())) { optionalParams.startDate = $("#date_timepicker_start").val(); } if (!isEmpty($("#date_timepicker_end").val())) { optionalParams.endDate = $("#date_timepicker_end").val(); } if (!isAllVersionsSelected()) { optionalParams.pdServiceVersionIds = selectedVersionIds; } if (!isEmpty(selectedAlmProjectIds)) { optionalParams.almProjectIds = selectedAlmProjectIds; } return optionalParams; } var getCurrentDate = function () { let today = new Date(); let year = today.getFullYear().toString(); let month = (today.getMonth() + 1).toString().padStart(2, "0"); let day = today.getDate().toString().padStart(2, "0"); return year+month+day; }; let toolbarCustom = [ { type: "i", k: "undo", onclick: function () { spreadsheet.undo(); } }, { type: "i", k: "redo", onclick: function () { spreadsheet.redo(); } }, { type: "i", k: "save", onclick: function () { excelExport(); } }, { type: "select", k: "font-family", v: ["Arial", "Verdana"] }, { type: "select", k: "font-size", v: ["9px", "10px", "11px", "12px", "13px", "14px", "15px", "16px", "17px", "18px", "19px", "20px"] }, { type: "i", k: "text-align", v: "left" }, { type: "i", k: "text-align", v: "center" }, { type: "i", k: "text-align", v: "right" }, { type: "i", k: "font-weight", v: "bold" }, { type: "i", k: "font-style", v: "italic" }, { type: "i", k: "text-decoration", v: "underline" }, { type: "i", k: "text-decoration", v: "line-through" }, { type: "color", k: "color" }, { type: "color", k: "background-color" }, { type: "i", k: "search-box", v: [] } ]; function getRandomColor() { const letters = "0123456789ABCDEF"; let color = "#"; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; } function drawCalendar(data) { let Issue = data.filter(item => item.isReq === true); let childIssue = data.filter(item => item.isReq === false); let events = []; let groupColors = {}; Issue.forEach(item => { let groupId = item.key; if (!groupColors[groupId]) { groupColors[groupId] = getRandomColor(groupId); } events.push({ groupId: groupId, title: `[ ${item.key} ] - ${item.issueTitle}`, start: new Date(item.createDate), end: item.resolutionDate ? new Date(item.resolutionDate) : new Date(item.updatedDate), color: groupColors[groupId] }); childIssue.forEach(child => { if (child.parentReqKey === item.key) { events.push({ groupId: groupId, title: `[ ${item.key} - Sub ] - ${child.issueTitle}`, start: new Date(child.createDate), end: child.resolutionDate ? new Date(child.resolutionDate) : new Date(child.updatedDate), color: groupColors[groupId] }); } }); }); if (!fullCalendar) { let calendarEl = document.getElementById("full-data-calendar-req"); fullCalendar = new FullCalendar.Calendar(calendarEl, { headerToolbar: { left: "prevYear,prev,next,nextYear today", center: "title", right: "multiMonthYear,dayGridMonth,dayGridWeek,dayGridDay" }, editable: false, eventStartEditable: false, eventDurationEditable: false, timeZone: "local", locale: userLocale, dateClick: function(arg) { console.log(arg); }, eventMouseEnter: function(info) { let tooltip = createTooltip(info); document.body.appendChild(tooltip); info.el.addEventListener("mouseleave", () => { tooltip.remove(); }); }, initialDate: new Date().toISOString().split("T")[0], navLinks: true, editable: true, dayMaxEvents: true, initialView: "dayGridMonth", eventClick: function(info) { let eventObj = info.event; alert( "Event: " + eventObj.title + "\n" + "Start: " + eventObj.start.toLocaleString() + "\n" + "End: " + (eventObj.end ? eventObj.end.toLocaleString() : "Not set") + "\n" ); info.jsEvent.preventDefault(); // 기본 동작 방지 } }); fullCalendar.render(); } else { fullCalendar.removeAllEventSources(); } fullCalendar.addEventSource(events); } function createTooltip(info) { let tooltip = document.createElement("div"); tooltip.classList.add("fc-tooltip"); tooltip.style.position = "absolute"; tooltip.style.background = "#333"; tooltip.style.color = "#fff"; tooltip.style.padding = "5px"; tooltip.style.borderRadius = "3px"; tooltip.style.pointerEvents = "none"; tooltip.style.zIndex = 9999; tooltip.innerText = info.event.title; document.body.appendChild(tooltip); let rect = tooltip.getBoundingClientRect(); let pageX = info.jsEvent.pageX; let pageY = info.jsEvent.pageY; if (pageX + rect.width > window.innerWidth) { pageX -= rect.width + 20; } if (pageY + rect.height > window.innerHeight) { pageY -= rect.height + 20; } tooltip.style.top = `${pageY + 10}px`; tooltip.style.left = `${pageX + 10}px`; return tooltip; }