src/main/webapp/assets/styles/main.css | ●●●●● 패치 | 보기 | raw | blame | 히스토리 | |
src/main/webapp/i18n/ko/global.json | ●●●●● 패치 | 보기 | raw | blame | 히스토리 | |
src/main/webapp/scripts/app/issue/issue.js | ●●●●● 패치 | 보기 | raw | blame | 히스토리 | |
src/main/webapp/scripts/app/issue/issueAddTreeTableConfig.controller.js | ●●●●● 패치 | 보기 | raw | blame | 히스토리 | |
src/main/webapp/scripts/app/issue/issueListTree.controller.js | ●●●●● 패치 | 보기 | raw | blame | 히스토리 | |
src/main/webapp/scripts/main.js | ●●●●● 패치 | 보기 | raw | blame | 히스토리 | |
src/main/webapp/views/issue/issueAddTreeTableConfig.html | ●●●●● 패치 | 보기 | raw | blame | 히스토리 | |
src/main/webapp/views/issue/issueList.html | ●●●●● 패치 | 보기 | raw | blame | 히스토리 | |
src/main/webapp/views/issue/issueListTree.html | ●●●●● 패치 | 보기 | raw | blame | 히스토리 |
src/main/webapp/assets/styles/main.css
@@ -30174,3 +30174,39 @@ } /* 간트차트 end */ /* 트리구조 임시 */ .tree-container { background-color: #f1f0f0; border: 1px solid #c2c2c2; padding: 20px; } .tree-body { } .tree{ margin-top: 5px; } .tree{ list-style: none; /* 기본 리스트 스타일 제거 */ padding-left: 0px; } .tree ul { list-style: none; /* 기본 리스트 스타일 제거 */ } .tree li { padding-top: 5px; margin-bottom: 5px; list-style-position: inside; padding-left: 10px; } .tree li:before{ content: '└ ' } src/main/webapp/i18n/ko/global.json
@@ -275,6 +275,7 @@ "relationIssueType6" : "다음 일감을 우선 진행", "updateIssueUser" : "일감 담당자 변경", "normalList" : "일감 목록", "treeList" : "하위/연관 일감 검색", "timeLine" : "타임 라인" }, "project": { src/main/webapp/scripts/app/issue/issue.js
@@ -33,11 +33,11 @@ loadController: ["$q", function ($q) { var deferred = $q.defer(); require([ 'issueListTimelineController', 'issueManagerController', 'issueListController', 'issueAddController', 'issueModifyController', 'issueDetailController', 'issueImportExcelController', 'issueListTreeController','issueListTimelineController', 'issueManagerController', 'issueListController', 'issueAddController', 'issueModifyController', 'issueDetailController', 'issueImportExcelController', 'chartLoader', 'jsTable', 'tableColumnGenerator', 'modalFormAutoScroll', 'summerNote', 'summerNote-ko-KR', 'fullScroll', 'workflowService', 'priorityService', 'issueSearchService', 'issueTableConfigService', 'inputRegex', 'severityService', 'issueTypeService', 'issueTypeCustomFieldService', 'issueService', 'issueStatusService', 'issueUserService', 'issueModifyUserController', 'customFieldService', 'issueSearchFieldKeyViewElement', 'issueSearchCustomFieldViewElement', 'tableUserImage', 'fullScroll', 'issueCommentService', 'detectIssueEditor', 'formSubmit', 'issueModifyStatusController', 'jsShortCut', 'issueAddTableConfigController', 'domAppend', 'issueDetailImagePreview', 'issueSendMailController', 'htmlDiff', 'issueVersionViewController', 'issueVersionService', 'issueAddTableConfigController','issueAddTreeTableConfigController', 'domAppend', 'issueDetailImagePreview', 'issueSendMailController', 'htmlDiff', 'issueVersionViewController', 'issueVersionService', 'jsHtmlDiff', 'issueReservationController', 'issueReservationService', 'issueVersionService', 'issueStatusAutoFocus', 'issueRelationService' ], function () { deferred.resolve(); src/main/webapp/scripts/app/issue/issueAddTreeTableConfig.controller.js
New file @@ -0,0 +1,186 @@ /** * Created by wisestone on 2019-02-07. */ 'use strict'; define([ 'app', 'angular' ], function (app, angular) { app.controller('issueAddTreeTableConfigController', ['$scope', '$rootScope', '$log', '$resourceProvider', '$uibModalInstance', 'SweetAlert', '$timeout', 'IssueTableConfig', 'CustomField', '$q', '$filter', function ($scope, $rootScope, $log, $resourceProvider, $uibModalInstance, SweetAlert, $timeout, IssueTableConfig, CustomField, $q, $filter) { // 함수 모음 $scope.fn = { cancel : cancel, // 팝업 창 닫기 formSubmit : formSubmit, // 폼 전송 formCheck : formCheck, // 폼 체크 getCustomFields : getCustomFields, // 사용자 정의 필드 목록을 가져온다. getIssueTableConfigs : getIssueTableConfigs // 이슈 목록 테이블 설정 정보를 가져온다. }; // 변수 모음 $scope.vm = { issueTableConfigs : [{ name : $filter("translate")("common.priority"), // 우선순위 key : "PRIORITY", width : "width-100-p", position : 1, display : true }, { name : $filter("translate")("common.importance"), // 중요도 key : "SEVERITY", width : "width-80-p", position : 2, display : true }, { name : $filter("translate")("issue.issueType"), // 이슈 타입 key : "ISSUE_TYPE", width : "width-140-p", position : 3, display : true }, { name : $filter("translate")("common.assignee"), // 담당자 key : "ASSIGNEE", width : "width-100-p", position : 4, display : true }, { name : $filter("translate")("common.register"), // 등록자 key : "REGISTER", width : "width-100-p", position : 5, display : false }, { name : $filter("translate")("common.period"), // 기간 key : "PERIOD", width : "width-140-p", position : 6, display : false }, { name : $filter("translate")("common.lastChangeDate"), // 최근 변경일 key : "MODIFY_DATE", width : "width-100-p", position : 7, display : false }] }; // 폼 전송 function formCheck(formInvalid) { if (formInvalid) { return true; } return false; } // 폼 전송 function formSubmit() { $rootScope.spinner = true; var content = { issueTableConfigs : JSON.stringify($scope.vm.issueTableConfigs) }; IssueTableConfig.add($resourceProvider.getContent(content, $resourceProvider.getPageContent(0, 0))).then(function (result) { if (result.data.message.status === "success") { SweetAlert.success($filter("translate")("issue.completedSavingIssueTable"), $filter("translate")("issue.saveIssueTableSettingsInformation")); // "이슈 테이블 설정 저장 완료", "이슈 테이블 설정 정보가 저장되었습니다." // 변경된 이슈 테이블 정보를 이슈 목록 테이블에 갱신한다. $rootScope.$broadcast("getIssueTableConfigs", {}); } else { SweetAlert.error($filter("translate")("issue.failedToSaveIssueTableSetting"), result.data.message.message); // 이슈 테이블 설정 저장 실패 } $rootScope.spinner = false; }); } // 팝업 창 닫기 function cancel() { $rootScope.$broadcast("closeLayer"); // 팝업이 열리고 나서 js-multi, js-single 등에서 body 이벤트가 날아가는 현상 수정 $uibModalInstance.dismiss('cancel'); $(document).unbind("keydown"); // 단축키 이벤트 제거 } // 사용자 정의 필드 목록을 가져온다. function getCustomFields() { var deferred = $q.defer(); CustomField.find($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 1000))).then(function (result) { if (result.data.message.status !== "success") { SweetAlert.error($filter("translate")("issue.failedToUserDefinedFieldListLookup"), result.data.message.message); // 사용자 정의 필드 목록 조회 실패 } deferred.resolve(result.data.data); }); return deferred.promise; } // 이슈 목록 테이블 설정 정보를 가져온다. function getIssueTableConfigs() { var deferred = $q.defer(); IssueTableConfig.detail($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 1000))).then(function (result) { if (result.data.message.status !== "success") { SweetAlert.error($filter("translate")("issue.failedToIssueTableColumnLookup"), result.data.message.message); // 이슈 테이블 컬럼 조회 실패 } deferred.resolve(result.data.data); }); return deferred.promise; } // 사용자 정의 필드를 조회한 후 표시할 이슈 테이블 컬럼을 준비한다. $scope.fn.getCustomFields().then(function (result) { var count = 7; angular.forEach(result, function (customField) { $scope.vm.issueTableConfigs.push({ name : customField.name, key : "CUSTOM_FIELD_" + customField.id, width : "width-100-p", display : false, position : count }); count++; }); // 이슈 목록 테이블 설정 정보를 가져온다. $scope.fn.getIssueTableConfigs().then(function (issueTableConfigs) { if ($rootScope.isDefined(issueTableConfigs)) { $rootScope.spinner = true; var saveTableConfigs = JSON.parse(issueTableConfigs); angular.forEach(saveTableConfigs, function (saveTableConfig) { for (var count in $scope.vm.issueTableConfigs) { var issueTableConfig = $scope.vm.issueTableConfigs[count]; if (issueTableConfig.key === saveTableConfig.key) { issueTableConfig.display = saveTableConfig.display; issueTableConfig.width = saveTableConfig.width; issueTableConfig.position = saveTableConfig.position; break; } } }); $rootScope.spinner = false; } }); }); }]); }); src/main/webapp/scripts/app/issue/issueListTree.controller.js
New file @@ -0,0 +1,880 @@ /** * Created by wisestone on 2017-12-21. */ 'use strict'; define([ 'app', 'angular' ], function (app, angular) { app.controller('issueListTreeController', ['$scope', '$rootScope', '$log', '$resourceProvider', '$tableProvider', '$state', '$uibModal', '$q', '$controller', '$injector', 'SweetAlert', 'Issue', 'IssueType', 'Priority', 'Severity', 'IssueStatus', 'CustomField', 'IssueSearch', 'IssueTableConfig', '$timeout', '$filter', function ($scope, $rootScope, $log, $resourceProvider, $tableProvider, $state, $uibModal, $q, $controller, $injector, SweetAlert, Issue, IssueType, Priority, Severity, IssueStatus, CustomField, IssueSearch, IssueTableConfig, $timeout, $filter) { // 함수 $scope.fn = { initSearch : initSearch, // 검색 초기화 getPageList : getPageList, // 목록 조회 changePageRowCount : changePageRowCount, // 페이지 변경 makeTableConfigs : makeTableConfigs, // 테이블 설정 setTableColumn : setTableColumn, // 테이블의 컬럼을 만들어준다. add : add, // 이슈 생성 modify : modify, // 이슈 수정 modifyMultiIssueStatus : modifyMultiIssueStatus, // 이슈 다중 상태 변경 removes : removes, // 이슈 삭제 addIssueTableConfig : addIssueTableConfig, // 이슈 목록 테이블 설정 listView : listView, // 목록 화면으로 변경 importExcel : importExcel, // 엑셀 import 기능 팝업 호출 getIssueTypes : getIssueTypes, // 이슈 유형 목록을 가져온다. getPriorities : getPriorities, // 우선순위 목록을 가져온다. getSeverities : getSeverities, // 중요도 목록을 가져온다. getIssueStatuses : getIssueStatuses, // 이슈 상태 목록을 가져온다. getCustomFields : getCustomFields, // 사용자 정의 필드 목록을 가져온다. makeVmSearchObject : makeVmSearchObject, // 검색 조건을 기억한다. getVmSearchObject : getVmSearchObject, // 저장한 검색 조건을 가져와서 vm 에 셋팅한다. makeSearchConditions : makeSearchConditions, // 검색 조건을 만든다. getIssueTableConfigs : getIssueTableConfigs, // 사용자 이슈 목록 테이블 설정 값을 가져와서 적용한다. startExecute : startExecute // 컨트롤 로딩시 처음으로 시작되는 함수 }; // 변수 $scope.vm = { search : { title : "", // 제목 description : "", // 내용 combinationIssueNumber : "", // 이슈 번호 projectType : "BTS_PROJECT", // 프로젝트 유형 registerDateRange : "", // 등록일 기간 검색 startDateRange : "", // 시작일 기간 검색 completeDateRange : "", // 완료일 기간 검색 severityIds : [], // 중요도 검색 priorityIds : [], // 우선순위 검색 issueStatusIds : [], // 이슈 상태 검색 issueTypeIds : [] // 이슈 유형 검색 }, searchView : false, // 상세 검색 조건 표시 여부 detailView : false, // 상세 모드 변경 값 page : { selectedPage : 0, selectedPageRowCount : String(10) }, tableConfigs : [], // 테이블 셋팅 정보 responseData : { data : [] }, projectName : "", // 프로젝트 검색 userName : "", // 담당자 검색 registerName : "", // 등록자 검색 projects : [], // 프로젝트 issueStatuses : [], // 이슈 상태 issueTypes : [], // 이슈 유형 priorities : [], // 우선 순위 severities : [], // 중요도 users : [], // 담당자 registers : [], // 등록자 customFields : [], // 사용자 정의 필드 issueTableConfigs : [] // 이슈 테이블 설정 }; // 테이블 이벤트 $scope.tableEvent = { changeDetailView : changeDetailView // 상세 화면으로 변경 }; angular.extend(this, $controller('autoCompleteController', {$scope : $scope, $injector : $injector})); // 이슈 목록 데이터 갱신 $scope.$on("getIssueList", function () { $scope.fn.getPageList($scope.vm.page.selectedPage - 1); }); // 이슈 테이블 설정 정보 갱신 $scope.$on("getIssueTableConfigs", function () { $scope.fn.startExecute(); }); // 검색 조건을 기억한다. - 적용 보류 function makeVmSearchObject() { var content = { conditions : JSON.stringify({ search : $scope.vm.search, projects : $scope.vm.projects, users : $scope.vm.users, registers : $scope.vm.registers }) }; IssueSearch.add($resourceProvider.getContent(content, $resourceProvider.getPageContent(0, 0))).then(function (result) { if (result.data.message.status === "success") { } else { SweetAlert.error($filter("translate")("issue.failedToSaveFieldConditions"), result.data.message.message); // 검색 필드 조건 저장 실패 } }); } // 서버에 저장한 이슈 검색 조건을 가져온다. function getVmSearchObject() { IssueSearch.detail($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 0))).then(function (result) { if (result.data.message.status === "success") { if ($rootScope.isDefined(result.data.data)) { var issueListSearchObject = JSON.parse(result.data.data); // 이슈 번호만 적용한다. - 삭제시 처리방법때문에 다른 속성은 적용 보류 $scope.vm.search = issueListSearchObject.search; /*$scope.vm.users = issueListSearchObject.users; $scope.vm.projects = issueListSearchObject.projects; $scope.vm.registers = issueListSearchObject.registers;*/ $scope.fn.getPageList(0, true); } else { $scope.fn.getPageList(0); } } else { SweetAlert.error($filter("translate")("issue.failedToGetSearchFieldCondition"), result.data.message.message); // 검색 필드 조건 가져오기 실패 } }); } // 상세 화면으로 변경한다. function changeDetailView(id) { $scope.vm.tableConfigs = []; $scope.vm.detailView = true; $scope.fn.makeTableConfigs(); // chrome 에서 마우스 떠난걸 감지 못해서 이벤트 추가. $(".full-height-scroll").trigger("mouseleave"); // 테이블을 다시 그릴수 있게 데이터 바인딩을 다시한다. var temp = angular.copy($scope.vm.responseData.data); $scope.vm.responseData.data = angular.copy(temp); // 현재 상세화면으로 보려고하는 이슈 id를 기억한다. $rootScope.currentDetailIssueId = id; // 이슈 상세 화면 요청 $rootScope.$broadcast("getIssueDetail", { id : id }); } // 목록 화면으로 변경한다. function listView() { $scope.vm.detailView = false; // 이슈 테이블 설정 $scope.fn.makeTableConfigs(); var temp = angular.copy($scope.vm.responseData.data); $scope.vm.responseData.data = angular.copy(temp); // 마지막으로 보고있던 이슈 id를 초기화한다. $rootScope.currentDetailIssueId = null; } // 이슈 테이블 설정 function makeTableConfigs() { $scope.vm.tableConfigs = []; $scope.vm.tableConfigs.push($tableProvider.config() .setDType("checkbox") .setHWidth("width-20-p") .setDAlign("text-center")); // 상세형 일때때 if ($scope.vm.detailView) { $scope.vm.tableConfigs.push($tableProvider.config() .setHName("issue.issueTitle") .setDName("title") .setDType("renderer") .setHWidth("width-100 bold") .setDRenderer("ISSUE_DETAIL_FLOATING")); } else { $scope.vm.tableConfigs.push($tableProvider.config() .setHName("issue.issueTitle") .setDName("title") .setDType("renderer") .setHWidth("bold") .setDRenderer("ISSUE_DETAIL_FLOATING")); angular.forEach($scope.vm.issueTableConfigs, function (issueTableConfig) { // 표시 대상인 컬럼만 화면에 그려준다. if (issueTableConfig.display) { // 테이블의 컬럼을 만들어준다. $scope.fn.setTableColumn(issueTableConfig); } }); } } // 테이블의 컬럼을 만들어준다. function setTableColumn(issueTableConfig) { // 일반 컬럼 switch(issueTableConfig.key) { case "PRIORITY" : // 우선순위 $scope.vm.tableConfigs.push($tableProvider.config() .setHName("common.priority") .setDName("priorityName") .setDType("renderer") .setHWidth("bold " + issueTableConfig.width) .setDAlign("text-center") .setDRenderer("COMMON_PRIORITY")); break; case "SEVERITY" : // 중요도 $scope.vm.tableConfigs.push($tableProvider.config() .setHName("common.importance") .setDName("severityName") .setDType("renderer") .setHWidth("bold " + issueTableConfig.width) .setDAlign("text-center") .setDRenderer("COMMON_SEVERITY")); break; case "ISSUE_TYPE" : // 이슈 타입 $scope.vm.tableConfigs.push($tableProvider.config() .setHName("issue.issueType") .setHWidth("bold " + issueTableConfig.width) .setDAlign("text-center") .setDName("issueTypeName")); break; case "ASSIGNEE" : // 담당자 $scope.vm.tableConfigs.push($tableProvider.config() .setHName("common.assignee") .setDType("renderer") .setHWidth("bold " + issueTableConfig.width) .setDAlign("text-center") .setDRenderer("ISSUE_USER")); break; case "REGISTER" : // 등록자 $scope.vm.tableConfigs.push($tableProvider.config() .setHName("common.register") .setDType("renderer") .setHWidth("bold " + issueTableConfig.width) .setDAlign("text-center") .setDRenderer("REGISTER")); break; case "PERIOD" : // 기간 $scope.vm.tableConfigs.push($tableProvider.config() .setHName("common.period") .setDType("renderer") .setHWidth("bold " + issueTableConfig.width) .setDAlign("text-center") .setDRenderer("ISSUE_DUE_DATE")); break; case "MODIFY_DATE" : // 최근 변경일 $scope.vm.tableConfigs.push($tableProvider.config() .setHName("common.lastChangeDate") .setHWidth("bold " + issueTableConfig.width) .setDAlign("text-center") .setDName("modifyDate")); break; } // 사용자 정의 필드 컬럼 if (issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) { // 만약 이슈 테이블 컬럼명이 표시되지 않으면 이쪽이 문제 for (var count in $scope.vm.customFields) { var customField = $scope.vm.customFields[count]; if (customField.id === Number(issueTableConfig.key.substring(13))) { $scope.vm.tableConfigs.push($tableProvider.config() .setHName(customField.name) .setDType("renderer") .setHWidth("bold " + issueTableConfig.width) .setDAlign("text-center") .setColumnHint(customField) .setDRenderer("ISSUE_CUSTOM_FIELD_VALUE_VIEW")); break; } } } } // 검색 필드 초기화 function initSearch() { $state.go($state.current, {}, {reload : true}); /*IssueSearch.remove($resourceProvider.getContent({screen : "ISSUE_LIST"}, $resourceProvider.getPageContent(0, 0))).then(function (result) { if (result.data.message.status == "success") { $state.go($state.current, {}, {reload : true}); } else { SweetAlert.swal("검색 필드 초기화 실패", result.data.message.message, "error"); } });*/ } // 이슈 검색 조건을 만든다. function makeSearchConditions() { var conditions = { title : $scope.vm.search.title, description : $scope.vm.search.description, projectType : $scope.vm.search.projectType, combinationIssueNumber : $scope.vm.search.combinationIssueNumber.trim(), beginRegisterDate : "", endRegisterDate : "", beginStartDate : "", endStartDate : "", beginCompleteDate : "", endCompleteDate : "", projectIds : (function () { var projectIds = []; angular.forEach($scope.vm.projects, function (project) { projectIds.push(project.id); }); return projectIds; })(), issueStatusIds : (function () { var issueStatusIds = []; angular.forEach($scope.vm.search.issueStatusIds, function (issueStatusId) { issueStatusIds.push(issueStatusId.fieldKey); }); return issueStatusIds; })(), issueTypeIds : (function () { var issueTypeIds = []; angular.forEach($scope.vm.search.issueTypeIds, function (issueTypeId) { issueTypeIds.push(issueTypeId.fieldKey); }); return issueTypeIds; })(), priorityIds : (function () { var priorityIds = []; angular.forEach($scope.vm.search.priorityIds, function (priorityId) { priorityIds.push(priorityId.fieldKey); }); return priorityIds; })(), severityIds : (function () { var severityIds = []; angular.forEach($scope.vm.search.severityIds, function (severityId) { severityIds.push(severityId.fieldKey); }); return severityIds; })(), userIds : (function () { var userIds = []; angular.forEach($scope.vm.users, function (user) { userIds.push(user.id); }); return userIds; })(), registerIds : (function () { var registerIds = []; angular.forEach($scope.vm.registers, function (register) { registerIds.push(register.id); }); return registerIds; })(), issueCustomFields : (function () { var issueCustomFields = []; angular.forEach($scope.vm.customFields, function (customField) { var useValues = []; if (angular.isArray(customField.useValues)) { angular.forEach(customField.useValues, function (useValue) { useValues.push(useValue.value); }); } else { useValues.push(customField.useValues); } // useValues 를 배열로 변환한다. var temp = angular.copy(customField); temp.useValues = useValues; issueCustomFields.push(temp); }); return issueCustomFields; })() }; // 등록일 if ($rootScope.isDefined($scope.vm.search.registerDateRange)) { var registerDateRange = $scope.vm.search.registerDateRange.split("~"); conditions.beginRegisterDate = registerDateRange[0].trim(); conditions.endRegisterDate = registerDateRange[1].trim(); } // 시작일 if ($rootScope.isDefined($scope.vm.search.startDateRange)) { var startDateRange = $scope.vm.search.startDateRange.split("~"); conditions.beginStartDate = startDateRange[0].trim(); conditions.endStartDate = startDateRange[1].trim(); } // 종료일 if ($rootScope.isDefined($scope.vm.search.completeDateRange)) { var completeDateRange = $scope.vm.search.completeDateRange.split("~"); conditions.beginCompleteDate = completeDateRange[0].trim(); conditions.endCompleteDate = completeDateRange[1].trim(); } return conditions; } // 이슈 목록을 조회한다. function getPageList(selectedPage, detail = false) { if (selectedPage < 0) { selectedPage = 0; } // 현재 페이지 정보 var currentPage = 0; // 쿠키에 선택한 페이지 정보가 없으면 기본 페이지 정보 0 을 저장 if (angular.isUndefined(selectedPage) || selectedPage === "") { currentPage = $scope.vm.page.selectedPage; } else { currentPage = selectedPage; } // 검색 조건을 저장한다. //$scope.fn.makeVmSearchObject(); // 현재 선택된 프로젝트를 검색 기본으로 추가 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(); Issue.find($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; if (detail) { changeDetailView(result.data.data[0].id); } } else { SweetAlert.error($filter("translate")("issue.failedIssueLookup"), result.data.message.message); // 이슈 조회 실패 } }); } // 검색조건에서 해당 프로젝트 찾기 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 changePageRowCount() { $scope.fn.getPageList(0); } // 엑셀 import 팝업 호출 function importExcel() { $uibModal.open({ templateUrl : 'views/issue/issueExcelImport.html', size : "lg", controller : 'issueImportExcelController', backdrop : 'static' }); } // 이슈 생성 팝업 호출 function add() { $uibModal.open({ templateUrl : 'views/issue/issueAdd.html', size : "lg", controller : 'issueAddController', backdrop : 'static' }); } // 이슈 다중 상태 변경 function modifyMultiIssueStatus() { var issueIds = []; angular.forEach($scope.vm.responseData.data, function (data) { if (data.checked) { issueIds.push(data.id); } }); if (issueIds.length < 1) { SweetAlert.warning($filter("translate")("issue.selectionCheck"), $filter("translate")("issue.selectIssueToChangeStatus")); // 선택 대상 확인, 상태 변경할 이슈를 선택하세요. return; } $uibModal.open({ templateUrl : 'views/issue/issueModifyStatus.html', size : "md", controller : 'issueModifyStatusController', backdrop : 'static', resolve : { parameter : function () { return { issueIds : issueIds }; } } }); } // 이슈 수정 팝업 호출 function modify(id) { $uibModal.open({ templateUrl : 'views/issue/issueModify.html', size : "lg", controller : 'issueModifyController', backdrop : 'static', resolve : { parameter : function () { return { id : id }; } } }); } // 이슈 삭제 function removes() { var removeIds = []; var removePermission = true; angular.forEach($scope.vm.responseData.data, function (data) { if (data.checked && data.modifyPermissionCheck) { removeIds.push(data.id); } if (data.checked && !data.modifyPermissionCheck) { removePermission = false; } }); if (!removePermission) { SweetAlert.swal({ html : true, title : $filter("translate")("common.deleteFailed"), // 삭제 실패 text : $filter("translate")("issue.notHaveDeletePermissionExistsAnIssue"), // 삭제 권한이 없는 이슈가 존재합니다. type : "error" }); return; } if (removeIds.length < 1) { SweetAlert.swal({ title : $filter("translate")("common.checkPurgingTargets"), // 삭제 대상 확인 text : $filter("translate")("common.selectDestinationDeletion"), // 삭제 대상을 선택하세요. type : "warning" }); return; } // 삭제 알림 SweetAlert.swal({ title : $filter("translate")("issue.deleteIssue"), // 이슈 삭제 text : $filter("translate")("issue.wantToDeleteSelectIssue"), // 선택한 이슈을 삭제하겠습니까? 삭제된 이슈은 복구할 수 없습니다. type : "warning", showCancelButton : true, confirmButtonColor : "#DD6B55", confirmButtonText : $filter("translate")("common.delete"), // 삭제 cancelButtonText : $filter("translate")("common.cancel"), // 취소 closeOnConfirm : false, closeOnCancel : true }, function (isConfirm) { SweetAlert.close(); if (isConfirm) { $rootScope.spinner = true; Issue.remove($resourceProvider.getContent( { removeIds : removeIds }, $resourceProvider.getPageContent(0, 0))).then(function (result) { if (result.data.message.status === "success") { $timeout(function () { SweetAlert.success($filter("translate")("common.deleteSucceeded"), result.data.message.message); // 삭제 성공 }, 100); $scope.fn.listView(); $scope.fn.getPageList(0); } else { $timeout(function () { SweetAlert.error($filter("translate")("common.deleteFailed"), result.data.message.message); // 삭제 실패 }, 100); } $rootScope.spinner = false; }); } }); } // 이슈 목록 테이블 설정 function addIssueTableConfig() { $uibModal.open({ templateUrl : 'views/issue/issueAddTreeTableConfig.html', size : "lg", controller : 'issueAddTreeTableConfigController', backdrop : 'static', resolve : {} }); } // 이슈 상태 목록 function getIssueStatuses() { var deferred = $q.defer(); $scope.vm.issueStatuses = []; IssueStatus.find($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 1000))).then(function (result) { if (result.data.message.status === "success") { angular.forEach(result.data.data, function (issueType) { $scope.vm.issueStatuses.push({ fieldKey : issueType.id, fieldValue : issueType.name }); }); } else { SweetAlert.swal($filter("translate")("common.failedToIssueStatusListLookup"), result.data.message.message, "error"); // 이슈 상태 목록 조회 실패 } deferred.resolve(result.data.data); }); return deferred.promise; } // 이슈 유형 목록 function getIssueTypes() { var deferred = $q.defer(); $scope.vm.issueTypes = []; IssueType.find($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 1000))).then(function (result) { if (result.data.message.status === "success") { angular.forEach(result.data.data, function (issueType) { $scope.vm.issueTypes.push({ fieldKey : issueType.id, fieldValue : issueType.name }); }); } else { SweetAlert.swal($filter("translate")("issue.failedToIssueTypeListLookup"), result.data.message.message, "error"); // 이슈 유형 목록 조회 실패 } deferred.resolve(result.data.data); }); return deferred.promise; } // 우선순위 목록 function getPriorities() { var deferred = $q.defer(); $scope.vm.priorities = []; Priority.find($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 1000))).then(function (result) { if (result.data.message.status === "success") { angular.forEach(result.data.data, function (prioritiy) { $scope.vm.priorities.push({ fieldKey : prioritiy.id, fieldValue : prioritiy.name }); }); } else { SweetAlert.swal($filter("translate")("issue.failedToPriorityListLookup"), result.data.message.message, "error"); // 우선순위 목록 조회 실패 } deferred.resolve(result.data.data); }); return deferred.promise; } // 중요도 목록 function getSeverities() { var deferred = $q.defer(); $scope.vm.severities = []; Severity.find($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 1000))).then(function (result) { if (result.data.message.status === "success") { angular.forEach(result.data.data, function (severity) { $scope.vm.severities.push({ fieldKey : severity.id, fieldValue : severity.name }); }); } else { SweetAlert.swal($filter("translate")("issue.failedToCriticalListLookup"), result.data.message.message, "error"); // 중요도 목록 조회 실패 } deferred.resolve(result.data.data); }); return deferred.promise; } // 사용자 정의 필드 목록 function getCustomFields() { var deferred = $q.defer(); $scope.vm.customFields = []; CustomField.find($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 1000))).then(function (result) { if (result.data.message.status === "success") { angular.forEach(result.data.data, function (customField) { switch (customField.customFieldType) { case "INPUT" : customField.useValues = ""; break; case "MULTI_SELECT" : case "SINGLE_SELECT" : customField.useValues = []; break; } $scope.vm.customFields.push(customField); }); } else { SweetAlert.swal($filter("translate")("issue.failedToUserDefinedFieldListLookup"), result.data.message.message, "error"); // 사용자 정의 필드 목록 조회 실패 } deferred.resolve(result.data.data); }); return deferred.promise; } // 사용자 이슈 목록 테이블 설정 값을 가져와서 적용한다. function getIssueTableConfigs() { var deferred = $q.defer(); IssueTableConfig.detail($resourceProvider.getContent({}, $resourceProvider.getPageContent(0, 1000))).then(function (result) { if (result.data.message.status !== "success") { SweetAlert.error($filter("translate")("issue.failedToIssueTableColumnLookup"), result.data.message.message); // 이슈 테이블 컬럼 조회 실패 } deferred.resolve(result.data.data); }); return deferred.promise; } // 최초 실행 function startExecute() { // 파라미터 읽기 var params = $rootScope.previousGetParams; if ($rootScope.isDefined(params)) { $rootScope.$broadcast("makeIssueSearch", { projectKey : params.projectKey, issueNumber : params.issueNumber }); $rootScope.previousGetParams = null; return; } var promises = { getIssueTypes : $scope.fn.getIssueTypes(), getPriorities : $scope.fn.getPriorities(), getSeverities : $scope.fn.getSeverities(), getIssueStatuses : $scope.fn.getIssueStatuses(), getCustomFields : $scope.fn.getCustomFields() }; $q.all(promises).then(function (results){ $log.debug("promises 결과 " , results); // 이슈 테이블 설정 조회 및 적용 후 // 이슈 검색 조건 가져오기 후 // 이슈 조회 // 사용자 이슈 목록 테이블 설정 값을 가져와서 적용한다. $scope.fn.getIssueTableConfigs().then(function (issueTableConfigs) { if ($rootScope.isDefined(issueTableConfigs)) { // 이슈 테이블 설정 정보를 저장 한다. $scope.vm.issueTableConfigs = JSON.parse(issueTableConfigs); $scope.vm.issueTableConfigs.sort(function (a, b) { return a.position < b.position ? -1 : a.position > b.position ? 1: 0; }); } else { // 최초 업무 공간에 들어왔을 경우 $scope.vm.issueTableConfigs = [{ name : $filter("translate")("common.priority"), // 우선순위 key : "PRIORITY", width : "width-80-p", position : 1, display : true }, { name : $filter("translate")("common.importance"), // 중요도 key : "SEVERITY", width : "width-80-p", position : 2, display : true }, { name : $filter("translate")("issue.issueType"), // 이슈 타입 key : "ISSUE_TYPE", width : "width-140-p", position : 3, display : true }, { name : $filter("translate")("common.assignee"), // 담당자 key : "ASSIGNEE", width : "width-140-p", position : 4, display : true }]; } // 이슈 테이블 설정 $scope.fn.makeTableConfigs(); // 서버에 저장한 이슈 검색 조건을 가져와서 이슈 목록 검색을 진행한다. $scope.fn.getVmSearchObject(); }); }); } $scope.fn.startExecute(); } ]); } ); src/main/webapp/scripts/main.js
@@ -179,10 +179,12 @@ 'issueModifyController' : 'app/issue/issueModify.controller', // 이슈 수정 컨트롤러 'issueDetailController' : 'app/issue/issueDetail.controller', // 이슈 상세 컨트롤러 'issueListController' : 'app/issue/issueList.controller', // 이슈 목록 컨트롤러 'issueListTreeController' : 'app/issue/issueListTree.controller', // 이슈 하위/연관일감 검색 컨트롤러 'issueManagerController' : 'app/issue/issueManager.controller', // 이슈 관리 컨트롤러 'issueImportExcelController' : 'app/issue/issueImportExcel.controller', // 이슈 엑셀 대량 import 'issueModifyStatusController' : 'app/issue/issueModifyStatus.controller', // 이슈 다중 상태 변경 컨트롤러 'issueAddTableConfigController' : 'app/issue/issueAddTableConfig.controller', // 이슈 테이블 설정 컨트롤러 'issueAddTreeTableConfigController' : 'app/issue/issueAddTreeTableConfig.controller', // 이슈 하위/연관일감 검색 테이블 설정 컨트롤러 'issueSendMailController' : 'app/issue/issueSendMail.controller', // 이슈 이메일 발송 컨트롤러 'issueVersionViewController' : 'app/issue/issueVersionView.controller', // 이슈 버전 확인 컨트롤러 'issueReservationController' : 'app/issue/issueReservation.controller', // 이슈 발생 예약 컨트롤러 src/main/webapp/views/issue/issueAddTreeTableConfig.html
New file @@ -0,0 +1,95 @@ <div class="formModal"> <div class="modal-header faded smaller"> <div class="modal-title"> <strong translate="issue.setIssueTableDisplay">이슈 테이블 표시 설정</strong> </div> <button aria-label="Close" class="close" type="button" ng-click="fn.cancel()"> <span aria-hidden="true"> ×</span> </button> </div> <div class="modal-body"> <form role="form" name="issueTableConfigForm"> <table class="table table-dash table-lightborder table-layout-fixed"> <thead> <tr> <th class="text-center width-80-p"> <span translate="issue.columnName">컬럼명</span> </th> <!-- <th class="text-center width-80-p">--> <!-- <span translate="issue.area">넓이</span>--> <!-- </th>--> <th class="text-center width-80-p"> <span translate="issue.displayed">표시 여부</span> </th> <th class="text-center width-40-p"> <span translate="issue.sequence">순서</span> </th> </tr> </thead> <tbody> <tr> <td class="text-center"> <span class="bold" translate="issue.issueTitle">이슈 제목</span> </td> <td class="text-center" colspan="2"> <span class="text-danger bold" translate="issue.cannotChangedIssueTitle">이슈 제목은 변경할 수 없습니다.</span> </td> </tr> <tr ng-repeat="issueTableConfig in vm.issueTableConfigs"> <td class="text-center"> <span class="bold">{{issueTableConfig.name}}</span> </td> <!-- <td class="text-center">--> <!-- <select class="form-control" ng-model="issueTableConfig.width">--> <!-- <option>선택하세요.</option>--> <!-- <option value="width-20-p">20px</option>--> <!-- <option value="width-30-p">30px</option>--> <!-- <option value="width-40-p">40px</option>--> <!-- <option value="width-50-p">50px</option>--> <!-- <option value="width-60-p">60px</option>--> <!-- <option value="width-70-p">70px</option>--> <!-- <option value="width-80-p">80px</option>--> <!-- <option value="width-90-p">90px</option>--> <!-- <option value="width-100-p">100px</option>--> <!-- <option value="width-110-p">110px</option>--> <!-- <option value="width-120-p">120px</option>--> <!-- <option value="width-130-p">130px</option>--> <!-- <option value="width-140-p">140px</option>--> <!-- <option value="width-150-p">150px</option>--> <!-- <option value="width-160-p">160px</option>--> <!-- <option value="width-170-p">170px</option>--> <!-- <option value="width-180-p">180px</option>--> <!-- <option value="width-190-p">190px</option>--> <!-- <option value="width-200-p">200px</option>--> <!-- <option value="width-220-p">220px</option>--> <!-- <option value="width-240-p">240px</option>--> <!-- <option value="width-260-p">260px</option>--> <!-- <option value="width-280-p">280px</option>--> <!-- <option value="width-300-p">300px</option>--> <!-- <option value="width-20">20%</option>--> <!-- <option value="width-30">30%</option>--> <!-- <option value="width-40">40%</option>--> <!-- <option value="width-50">50%</option>--> <!-- </select>--> <!-- </td>--> <td class="text-center"> <label class='switch'><input type='checkbox' ng-model='issueTableConfig.display'><span class='slider round'></span></label> </td> <td class="text-center"> <input type="text" class="form-control" ng-model="issueTableConfig.position" maxlength="2" input-regex="[^0-9]"> </td> </tr> </tbody> </table> </form> </div> <div class="modal-footer buttons-on-right"> <button type="button" class="btn btn-md btn-grey" ng-click="fn.cancel()"><span translate="common.close">닫기</span></button> <button type="button" class="btn btn-md btn-primary bold" ng-disabled="fn.formCheck(issueTableConfigForm.$invalid)" ng-click="fn.formSubmit()"><span translate="common.save">저장</span> </button> </div> </div> src/main/webapp/views/issue/issueList.html
@@ -9,6 +9,9 @@ <a class="nav-link cursor" ng-class="{ 'active' : vm.tab == 'ISSUE_LIST' }" ng-click="fn.changeTab('ISSUE_LIST')" translate="issue.normalList">일감 목록</a> </li> <li class="nav-item"> <a class="nav-link cursor" ng-class="{ 'active' : vm.tab == 'ISSUE_TREE_LIST' }" ng-click="fn.changeTab('ISSUE_TREE_LIST')" translate="issue.treeList">구조 목록</a> </li> <li class="nav-item"> <a class="nav-link cursor" ng-class="{ 'active' : vm.tab == 'ISSUE_TIMELINE' }" ng-click="fn.changeTab('ISSUE_TIMELINE')" translate="issue.timeLine">타임 라인</a> </li> </ul> @@ -21,6 +24,10 @@ <div ng-include include-replace src="'views/issue/issueListNormal.html'"></div> </div> <div ng-show="vm.tab == 'ISSUE_TREE_LIST'"> <div ng-include include-replace src="'views/issue/issueListTree.html'"></div> </div> <div ng-show="vm.tab == 'ISSUE_TIMELINE'"> <div ng-include include-replace src="'views/issue/issueListTimeline.html'"></div> </div> src/main/webapp/views/issue/issueListTree.html
New file @@ -0,0 +1,410 @@ <div class="container-fluid" ng-controller="issueListTreeController"> <div class="row"> <div class="col-sm-12" > <div class="element-wrapper" ng-if="!vm.detailView"> <div class="element-box"> <div class="row" > <div class="col-sm-12"> <div class="searchdiv"> <form name="issueSearchForm" role="form" ng-enter="fn.getPageList(0)"> <div class="row"> <div class="col-sm-6"> <div class="input-group"> <input class="form-control" type="text" tabindex="-1" maxlength="300" kr-input owl-auto-focus ng-model="vm.search.title" placeholder="{{'issue.pleaseEnterIssueName' | translate}}"> <div class="input-group-prepend ml-10"> <button class="btn btn-navy" ng-click="fn.getPageList(0)"> <span translate="common.search">검색</span></button> </div> </div> </div> </div> <div class="row"> <div class="col-sm-12"> <div class="tabfilter"> <div translate="common.selectedSearchCriteria">선택한 검색 조건</div> <!-- 프로젝트 --> <issue-search-array-view-element lists="vm.projects" type="'project'"></issue-search-array-view-element> <!-- 이슈 타입 --> <issue-search-field-key-view-element lists="vm.issueTypes" keys="vm.search.issueTypeIds"></issue-search-field-key-view-element> <!-- 이슈 상태 --> <issue-search-field-key-view-element lists="vm.issueStatuses" keys="vm.search.issueStatusIds"></issue-search-field-key-view-element> <!-- 이슈 번호 --> <p ng-if="$root.isDefined(vm.search.combinationIssueNumber)"> {{vm.search.combinationIssueNumber}} <span ng-click="vm.search.combinationIssueNumber = ''">×</span> </p> <!-- 이슈 내용 --> <p ng-if="$root.isDefined(vm.search.description)"> {{vm.search.description}} <span ng-click="vm.search.description = ''">×</span> </p> <!-- 우선 순위 --> <issue-search-field-key-view-element lists="vm.priorities" keys="vm.search.priorityIds"></issue-search-field-key-view-element> <!-- 중요도 --> <issue-search-field-key-view-element lists="vm.severities" keys="vm.search.severityIds"></issue-search-field-key-view-element> <!-- 담당자 --> <issue-search-array-view-element lists="vm.users" type="'user'"></issue-search-array-view-element> <!-- 등록자 --> <issue-search-array-view-element lists="vm.registers" type="'user'"></issue-search-array-view-element> <!-- 시작일 --> <p ng-if="$root.isDefined(vm.search.startDateRange)"> {{vm.search.startDateRange}} <span ng-click="vm.search.startDateRange = ''">×</span> </p> <!-- 종료일 --> <p ng-if="$root.isDefined(vm.search.completeDateRange)"> {{vm.search.completeDateRange}} <span ng-click="vm.search.completeDateRange = ''">×</span> </p> <!-- 등록일 --> <p ng-if="$root.isDefined(vm.search.registerDateRange)"> {{vm.search.registerDateRange}} <span ng-click="vm.search.registerDateRange = ''">×</span> </p> <!-- 텍스트 입력 필드 --> <issue-search-custom-field-view-element custom-fields="vm.customFields"></issue-search-custom-field-view-element> </div> </div> </div> <div class=""> <label class="issue-search-label" ng-class="{ 'icon-reverse' : vm.searchView }" ng-click="vm.searchView = !vm.searchView"> <span translate="common.detailedSearch">상세검색</span> </label> <div ng-if="vm.searchView"> <div class="row"> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="common.project">프로젝트</span></label> <js-autocomplete-multi data-input-name="projects" selected-model="vm.projects" search="vm.projectName" input-disabled="false" translation-texts="{ empty : 'common.emptyProject', selectList : 'common.' }" source="fn.getProjectList(vm.projectName, vm.projects, null, null, ['01', '02', '03'])" extra-settings="{ displayProp : 'name' , idProp : 'id', imageable : false, imagePathProp : '', type : '', maxlength : 100}"></js-autocomplete-multi> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="issue.issueType">이슈 타입</span></label> <ng-dropdown-multiselect class="multiSelect cursor" data-input-name="issueStatuses" selected-model="vm.search.issueTypeIds" options="::vm.issueTypes"></ng-dropdown-multiselect> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="issue.issueStatus">이슈 상태</span></label> <ng-dropdown-multiselect class="multiSelect cursor" data-input-name="issueStatuses" selected-model="vm.search.issueStatusIds" options="::vm.issueStatuses"></ng-dropdown-multiselect> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="issue.issueNumber">이슈 번호</span></label> <input type="text" name="name" class="form-control input-sm" autocomplete="off" kr-input maxlength="20" ng-model="vm.search.combinationIssueNumber"> </div> </div> </div> <div class="row"> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="issue.issueContent">이슈 내용</span></label> <input type="text" name="description" class="form-control input-sm" kr-input maxlength="20" autocomplete="off" ng-model="vm.search.description"> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="common.priority">우선 순위</span></label> <ng-dropdown-multiselect class="multiSelect cursor" data-input-name="priorities" selected-model="vm.search.priorityIds" options="::vm.priorities"></ng-dropdown-multiselect> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="common.importance">중요도</span></label> <ng-dropdown-multiselect class="multiSelect cursor" data-input-name="severities" selected-model="vm.search.severityIds" options="::vm.severities"></ng-dropdown-multiselect> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="common.assignee">담당자</span></label> <js-autocomplete-multi data-input-name="users" selected-model="vm.users" search="vm.userName" input-disabled="false" source="fn.getUserList(vm.userName, vm.users)" translation-texts="{ count : 'common.userNum', empty : 'common.emptyUser' }" extra-settings="{ displayProp : 'byName' , idProp : 'id', widthable : false, width : '', imageable : true, imagePathProp : 'profile', type : 'user', maxlength : 100 }"> </js-autocomplete-multi> </div> </div> </div> <div class="row"> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="common.register">등록자</span></label> <js-autocomplete-multi data-input-name="registers" selected-model="vm.registers" search="vm.registerName" input-disabled="false" source="fn.getUserList(vm.registerName, vm.registers)" translation-texts="{ count : 'common.userNum', empty : 'common.emptyUser' }" extra-settings="{ displayProp : 'byName' , idProp : 'id', widthable : false, width : '', imageable : true, imagePathProp : 'profile', type : 'user', maxlength : 100 }"> </js-autocomplete-multi> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="common.registrationDate">등록일</span></label> <input type="text" readonly class="form-control input-sm input-readonly" ng-model="vm.search.registerDateRange" modal-form-auto-scroll date-format="YY-MM-DD" parent-el="'#createdWidget'" date-range-picker> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="common.startDate">시작일</span></label> <input type="text" readonly class="form-control input-sm input-readonly" ng-model="vm.search.startDateRange" date-format="YY-MM-DD" parent-el="'#createdWidget'" date-range-picker> </div> </div> <div class="col-lg-3"> <div class="form-group"> <label> <span translate="common.endDate">종료일</span></label> <input type="text" readonly class="form-control input-sm input-readonly" ng-model="vm.search.completeDateRange" modal-form-auto-scroll date-format="YY-MM-DD" parent-el="'#createdWidget'" date-range-picker> </div> </div> <div class="col-lg-3" ng-repeat="customField in vm.customFields"> <label>{{::customField.name}}</label> <div ng-switch on="customField.customFieldType"> <div ng-switch-when="INPUT"> <input type="text" class="form-control input-sm" ng-model="customField.useValues" maxlength="100"> </div> <div ng-switch-default> <ng-dropdown-multiselect class="multiSelect cursor" data-input-name="customField.name" selected-model="customField.useValues" extra-settings="{ 'idProp' : 'value', 'externalIdProp' : 'value', 'displayProp' : 'value', 'stringTypeOption' : 'true', 'stopRemoveBodyEvent' : 'true' }" options="::customField.customFieldValueVos"></ng-dropdown-multiselect> </div> </div> </div> </div> <div class="row"> <div class="col-sm-12"> <div class="form-buttons-w text-center mb-20"> <button class="btn btn-xlg btn-navy" ng-click="fn.getPageList(0)"> <i class="os-icon os-icon-ui-37"></i> <span translate="common.search">검색</span> </button> <button class="btn btn-xlg btn-white" ng-click="fn.initSearch()"> <i class="os-icon os-icon-grid-18"></i> <span translate="common.reset">초기화</span> </button> </div> </div> </div> </div> </div> </form> </div> </div> </div> <div class="controls-above-table mt-30"> <div class="row"> <!-- 좌측 --> <div class="col-7"> <div class="dataTables_length"> <label> <select name="pageRow" tabindex="-1" class="form-control form-control-sm" ng-change="fn.changePageRowCount()" ng-model="vm.page.selectedPageRowCount"> <option value="10">10</option> <option value="50">50</option> <option value="100">100</option> </select> 1-1 / 2건</span> </label> </div> </div> <!-- 우측 --> <div class="col-5 " > <form class="form-inline justify-content-sm-end pull-right" method="post" action="/issue/downloadExcel" name="issueListForm" > <!--span class="badge-tip" function-tool-tip data-placement="top" data-toggle="tooltip" data-original-title="엑셀 다운로드, 일괄 변경 등 다양한 기능을 제공합니다.">?</span--> <input type="hidden" name="conditions"> <div class="btn-group"> <button aria-expanded="false" aria-haspopup="true" tabindex="-1" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" type="button"><span translate="common.addFunction">추가기능</span> </button> <div aria-labelledby="dropdownMenuButton2" class="dropdown-menu left-menu" x-placement="bottom-start" > <a class="dropdown-item cursor" ng-click="fn.addIssueTableConfig()"> <span translate="issue.settingTableDisplay">테이블 표시 설정</span></a> </div> </div> </form> </div> </div> </div> <!-- <div class="table-responsive"> <js-table data="vm.responseData.data" table-configs="vm.tableConfigs" event="tableEvent" detail-view="vm.detailView"></js-table> </div> --> <!-- 트리구조 임시 --> <div class="tree-container"> <div class="tree-body"> <h5 class="tree-title"><button class="btn btn-primary">홈페이지 변조 탐지</button></h5> <ul class="tree"> <li> <a href="#" class="btn btn-success">https://land.daum.com/news/expertColumnView.naver?artcl_seq=6580&page= | 2020.10.13 22:10:22</a> <a href="#" class="btn btn-info">연관 일감1</a> <a href="#" class="btn btn-info">연관 일감2</a> <ul> <li> <a href="#" class="btn btn-warning">https://dict.daum.com/elkodict/moderngreek/#/main | 2020.10.13 22:10:22</a> </li> </ul> </li> <li> <a href="#" class="btn btn-success">https://land.naver.com/news/region.naver | 2020.10.13 22:10:22</a> <a href="#" class="btn btn-info">연관 일감1</a> <ul> <li> <a href="#" class="btn btn-warning">https://sports.news.naver.com/news.nhn?oid=236&aid=0000218017 | 2020.10.13 22:10:22</a> </li> </ul> </li> </ul> </div> <hr> <div class="tree-body"> <h5 class="tree-title"><button class="btn btn-primary">MCF</button></h5> <ul class="tree"> <li> <a href="#" class="btn btn-success">https://land.naver.com/news/region.naver | 2020.10.13 22:10:22</a> <a href="#" class="btn btn-info">연관 일감1</a> <ul> <li> <a href="#" class="btn btn-warning">https://sports.news.naver.com/news.nhn?oid=236&aid=0000218017 | 2020.10.13 22:10:22</a> </li> </ul> </li> </ul> </div> </div> <div class="controls-below-table text-center"> <ul uib-pagination boundary-links-numbes="true" items-per-page="vm.page.selectedPageRowCount" total-items="vm.responseData.page.totalCount" ng-model="vm.page.selectedPage" max-size="10" ng-click="fn.getPageList(vm.page.selectedPage - 1)" class="pagination pagination-sm" previous-text="<" next-text=">" first-text="" last-text=""> </ul> </div> </div> </div> </div> </div> <div class="row support-index" ng-show="vm.detailView"> <div ng-include include-replace src="'views/issue/issueDetail.html'"></div> </div> </div>