/** * Created by maprex on 2021-06-17 */ 'use strict'; define([ 'app', 'angular' ], function (app, angular) { app.controller('projectTimelineController', ['$scope', '$rootScope', '$log', '$q', '$resourceProvider', '$controller', '$injector', 'Gantt', 'SweetAlert', '$filter', function ($scope, $rootScope, $log, $q, $resourceProvider, $controller, $injector, Gantt, SweetAlert, $filter) { $scope.fn = { getPageList : getPageList, // 목록을 조회한다. makeSearchConditions : makeSearchConditions, // 검색조건을 가져옴 startExecute : startExecute, initSearch : initSearch }; $scope.vm = { search : { name : "", // 프로젝트 명 userIds : [], // 관리자 statuses : [], // 상태 }, arrProjects : [], // 프로젝트 배열 projectIssues : new Object(), // 프로젝트 전체 이슈 projectCompleteIssues : new Object(), // 프로젝트 완료 이슈 searchView : false, // 상세 검색 조건 표시 여부 detailView : false, // 상세 모드 변경 값 tableConfigs : [], // 테이블 셋팅 정보 responseData : { data : [] }, projectName : "", // 프로젝트 검색 projects : [], // 프로젝트 page : { selectedPage : 0, selectedPageRowCount : String(99999) }, options : { statuses : [{ fieldKey : "01", fieldValue : $filter("translate")("common.wait") // "대기" }, { fieldKey : "02", fieldValue : $filter("translate")("common.progress") // "진행" }, { fieldKey : "03", fieldValue : $filter("translate")("common.end") // "종료" }] }, useGantt : false, chart : null // 간트차트 }; angular.extend(this, $controller('autoCompleteController', {$scope : $scope, $injector : $injector})); $scope.init = function () { var workProjects = $rootScope.projects; workProjects.forEach(project => { if (project.id > 0) { $scope.vm.projects.push(project); } }); $scope.fn.startExecute(); } // 검색 조건 초기화 function initSearch() { $state.go($state.current, {}, {reload : true}); } // 이슈 검색 조건을 만든다. function makeSearchConditions() { var conditions = { name: $scope.vm.search.name, statuses : (function () { var statuses = []; angular.forEach($scope.vm.search.statuses, function (status) { statuses.push(status.fieldKey); }); return statuses; })(), } return conditions; } function drawGanttChart(useProject = false) { google.charts.load('current', {'packages':['gantt'], 'language': 'ko'}); google.charts.setOnLoadCallback(drawChart); } function toMilliseconds(minutes) { return minutes * 60 * 1000; } // 검색조건에서 해당 프로젝트 찾기 function findProjectSearch(projectId) { var projects = $scope.vm.projects; var find = false; for (let i = 0; i < projects.length; i++) { if (projects[i].id == projectId) { find = true; break; } } return find; } function getPageList(selectedPage) { if (chart != null) chart.clearChart(); // 현재 페이지 정보 var currentPage = 0; // $rootScope.spinner = true; // 현재 선택된 프로젝트를 검색 기본으로 추가 if ($rootScope.workProject != null && $rootScope.workProject.id > -1) { var find = findProjectSearch($rootScope.workProject.id); if (!find) { $scope.vm.projects.push($rootScope.workProject); } } var conditions = $scope.fn.makeSearchConditions(); Gantt.findProject($resourceProvider.getContent(conditions, $resourceProvider.getPageContent(currentPage, $scope.vm.page.selectedPageRowCount))).then(function (result) { if (result.data.message.status === "success") { $scope.vm.page.selectedPage = currentPage + 1; $scope.vm.responseData = result.data; drawGanttChart(); } else { //SweetAlert.error($filter("translate")("issue.failedIssueLookup"), result.data.message.message); // 이슈 조회 실패 } }); } // 프로젝트리스트에 해당 아이디가 존재하는지 여부 확인 function containsIssue(projectId) { return projectId in $scope.vm.projectIssues; } var chart; var otherData; var options; function drawChart() { var responseData = $scope.vm.responseData; var page = responseData.page; otherData = new google.visualization.DataTable(); otherData.addColumn('string', 'Task ID'); otherData.addColumn('string', 'Task Name'); otherData.addColumn('string', 'Resource'); otherData.addColumn('date', '시작'); otherData.addColumn('date', '종료'); otherData.addColumn('number', '기간'); otherData.addColumn('number', '진행율'); otherData.addColumn('string', '상위프로젝트'); var data = responseData.data; var trackHeight = 35; var bottomHeight = 50; $scope.vm.arrProjects = []; $scope.vm.projectIssues = new Object(); if (page.totalCount > 0) { data.forEach(el => { addIssue(el.projectId, el); }); for (const [key, value] of Object.entries($scope.vm.projectIssues)) { var projectObj = $rootScope.findProject(key); if (projectObj != null) { var issues = $scope.vm.projectIssues[key]; var completeIssues = $scope.vm.projectCompleteIssues[key]; var start = null; if (projectObj.startDate != null) { start = new Date(projectObj.startDate); start.setHours(0, 0, 0); } var end = null; if (projectObj.endDate != null) { end = new Date(projectObj.endDate); end.setHours(23, 59, 59); } var duration = 0; if (start != null && end != null) { duration = end.getTime() - start.getTime(); } var percent = 0; var endCount = completeIssues == null ? 0 : completeIssues.length.toFixed(2); var totalCount = issues == null ? 0 : issues.length; if (totalCount > 0) { percent = parseInt(endCount / totalCount * 100.0); } var depend = null; if (projectObj.parentProjectId != null && containsIssue(projectObj.parentProjectId)) { depend = String(projectObj.parentProjectId); } $scope.vm.arrProjects.push(projectObj.id); otherData.addRow([String(projectObj.id), projectObj.name, String(projectObj.id), start, end, duration, percent, depend]); } } $scope.vm.useGantt = true; } else { otherData.addRow(["none", "일감이 없습니다", "none", new Date(), null, toMilliseconds(0), 100, null]); $scope.vm.useGantt = false; } var dataCount = $scope.vm.arrProjects.length; var chartHeight = dataCount * trackHeight + bottomHeight; options = { gantt: { defaultStartDate : new Date(), barHeight : 18, barCornerRadius : 1, criticalPathEnabled: true, // Critical path arrows will be the same as other arrows. arrow: { angle: 50, width: 1, color: '#0066cc', radius: 2 }, labelStyle: { fontName: 'NanumSquare', fontSize: 12, color: '#d5c209' }, trackHeight : trackHeight }, height: chartHeight, animation: {"startup": true} }; var container = document.getElementById('chart_div'); if (container == null) { return; } chart = new google.visualization.Gantt(container); hideChartTooltip(container, chart); google.visualization.events.addListener(chart, 'onmouseover', function (e) { }); google.visualization.events.addListener(chart, 'click', function() { }); google.visualization.events.addListener(chart, 'select', function() { var selection = chart.getSelection(); $rootScope.changeLastProject($scope.vm.arrProjects[selection[0].row]); }); window.addEventListener('resize', function() { chart.draw(otherData, options); }, false); //화면 크기에 따라 그래프 크기 변경 chart.draw(otherData, options); } // 이슈를 배열에 추가 function addIssue(projectId, issue) { if ($scope.vm.projectCompleteIssues[projectId] == null) $scope.vm.projectCompleteIssues[projectId] = []; if ($scope.vm.projectIssues[projectId] == null) $scope.vm.projectIssues[projectId] = []; if (issue.issueStatusType == "CLOSE") { $scope.vm.projectCompleteIssues[projectId].push(issue); } $scope.vm.projectIssues[projectId].push(issue); } // google chart 기본 tooltip 가리기 function hideChartTooltip(container, chart) { google.visualization.events.addOneTimeListener(chart, 'ready', function () { var observer = new MutationObserver(function (nodes) { Array.prototype.forEach.call(nodes, function(node) { if (node.addedNodes.length > 0) { Array.prototype.forEach.call(node.addedNodes, function(addedNode) { if ((addedNode.tagName === 'rect') && (addedNode.getAttribute('fill') === 'white')) { addedNode.setAttribute('fill', 'transparent'); addedNode.setAttribute('stroke', 'transparent'); Array.prototype.forEach.call(addedNode.parentNode.getElementsByTagName('text'), function(label) { label.setAttribute('fill', 'transparent'); }); } }); } }); }); observer.observe(container, { childList: true, subtree: true }); }); } function startExecute() { $scope.fn.getPageList(); } $rootScope.$on('changeProjectChartTab', function(evt) { if (chart != null) { $scope.fn.startExecute(); } }); }]); });