OWL ITS + 탐지시스템(인터넷 진흥원)
jhjang
2021-11-17 61037a004e28c5e508a62f42022d20d6872dc672
- 이슈 상세 페이지에 하위 일감 기능 추가
14개 파일 변경됨
286 ■■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/domain/Issue.java 10 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/repository/IssueRepository.java 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/IssueService.java 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java 24 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/IssueVo.java 20 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/condition/IssueCondition.java 8 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/controller/IssueController.java 10 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/form/IssueForm.java 9 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/migration/V1_11__Alter_Table.sql 2 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js 12 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/i18n/ko/global.json 10 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueDetail.controller.js 119 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/components/issue/issue.service.js 6 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueDetail.html 50 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/Issue.java
@@ -101,6 +101,10 @@
    @JoinColumn(name = "workflow_status_id")
    private WorkflowStatus workflowStatus;
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "parent_issue_id")
    private Issue parentIssue;
    public Long getId() {
        return id;
    }
@@ -321,5 +325,11 @@
        this.issueRelations.clear();
    }
    public Issue getParentIssue() {
        return parentIssue;
    }
    public void setParentIssue(Issue parentIssue) {
        this.parentIssue = parentIssue;
    }
}
src/main/java/kr/wisestone/owl/repository/IssueRepository.java
@@ -2,6 +2,10 @@
import kr.wisestone.owl.domain.Issue;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface IssueRepository extends JpaRepository<Issue, Long> {
    List<Issue> findByParentIssueId(@Param("parentIssueId") Long parentIssueId);
}
src/main/java/kr/wisestone/owl/service/IssueService.java
@@ -68,4 +68,6 @@
    void reservationIssue();
    Map<String, Object> findTask(IssueCondition taskCondition);
    void modifyParentIssue(IssueForm issueForm);
}
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -799,6 +799,7 @@
                    this.setAttachedFiles(issue, issueVo);  //  첨부 파일 정보 셋팅
                    this.setIssueCustomFields(issue, issueVo);  //  사용자 정의 필드 값 정보 셋팅
                    this.setRelationIssue(issue, issueVo);        //연관 일감 셋팅
                    this.setDownIssues(issue, issueVo);
                    break;
@@ -812,6 +813,13 @@
        log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_DETAIL));
        resJsonData.put(Constants.RES_KEY_CONTENTS, issueVo);
    }
    // 하위 이슈 정보를 셋팅한다
    private void setDownIssues(Issue issue, IssueVo issueVo) {
        List<Issue> downIssues = this.issueRepository.findByParentIssueId(issue.getId());
        List<IssueVo> issueVos = ConvertUtil.convertObjectsToClasses(downIssues, IssueVo.class);
        issueVo.setIssueDownVos(issueVos);
    }
    //  이슈 상세 정보를 셋팅한다.
@@ -833,6 +841,7 @@
        this.setIssueComments(issue, issueVo);  //  댓글 정보 셋팅
        this.setIssueHistory(issue, issueVo);   //  이슈 기록 정보 셋팅
        this.setRelationIssue(issue, issueVo);        //연관 일감 셋팅
        this.setDownIssues(issue, issueVo);
    }
    //  등록자 정보 추가
@@ -2513,4 +2522,19 @@
        return tasks;
    }
    @Transactional
    @Override
    public void modifyParentIssue(IssueForm issueForm) {
        Issue issue = this.issueRepository.getOne(issueForm.getId());
        Long parentIssueId = issueForm.getParentIssueId();
        if (parentIssueId != null) {
            Issue parentIssue = this.issueRepository.getOne(parentIssueId);
            issue.setParentIssue(parentIssue);
        } else  {
            issue.setParentIssue(null);
        }
        this.issueRepository.saveAndFlush(issue);
    }
}
src/main/java/kr/wisestone/owl/vo/IssueVo.java
@@ -44,11 +44,13 @@
    private List<IssueTypeCustomFieldVo> issueTypeCustomFieldVos = Lists.newArrayList();
    private List<IssueCustomFieldValueVo> issueCustomFieldValueVos = Lists.newArrayList();
    private List<IssueRelationVo> issueRelations = Lists.newArrayList();
    private List<IssueVo> issueDownVos = Lists.newArrayList();
    private List<IssueVo> issueRelationVos = Lists.newArrayList();
    private Long attachedFileCount;
    private Long issueCommentCount;
    private String modifyByName;    //  변경자 정보 - 이슈 변경 정보 상세 확인에서 사용
    private WorkflowStatusVo workflowStatusVo;
    private Long parentIssueId;     // 상위 일감
    public IssueVo(){}
@@ -379,4 +381,22 @@
    public void setDepartmentVos(List<DepartmentVo> departmentVos) {
        this.departmentVos = departmentVos;
    }
    public Long getParentIssueId() {
        return parentIssueId;
    }
    public void setParentIssueId(Long parentIssueId) {
        this.parentIssueId = parentIssueId;
    }
    public List<IssueVo> getIssueDownVos() {
        return issueDownVos;
    }
    public void setIssueDownVos(List<IssueVo> issueDownVos) {
        this.issueDownVos = issueDownVos;
    }
}
src/main/java/kr/wisestone/owl/web/condition/IssueCondition.java
@@ -33,6 +33,7 @@
    private Long workspaceId;
    private String projectType;
    private String deep;
    private Long parentIssueId;     // 상위 일감
    private List<Long> projectIds = Lists.newArrayList();
    private List<Long> issueStatusIds = Lists.newArrayList();
    private List<Long> issueTypeIds = Lists.newArrayList();
@@ -406,4 +407,11 @@
        this.excludeIds = excludeIds;
    }
    public Long getParentIssueId() {
        return parentIssueId;
    }
    public void setParentIssueId(Long parentIssueId) {
        this.parentIssueId = parentIssueId;
    }
}
src/main/java/kr/wisestone/owl/web/controller/IssueController.java
@@ -88,6 +88,16 @@
        return this.setSuccessMessage(resJsonData);
    }
    //  하위 이슈 추가
    @RequestMapping(value = "/issue/modifyParentIssue", produces = MediaType.APPLICATION_JSON_VALUE)
    public
    @ResponseBody
    Map<String, Object> modifyParentIssue(@RequestBody Map<String, Map<String, Object>> params) {
        Map<String, Object> resJsonData = new HashMap<>();
        this.issueService.modifyParentIssue(IssueForm.make(params.get(Constants.REQ_KEY_CONTENT)));
        return this.setSuccessMessage(resJsonData);
    }
    //  이슈 삭제
    @RequestMapping(value = "/issue/remove", produces = MediaType.APPLICATION_JSON_VALUE)
    public
src/main/java/kr/wisestone/owl/web/form/IssueForm.java
@@ -40,6 +40,7 @@
    private Long companyId;    //업체필드
    private Long ispId;    //ISP필드
    private Long hostingId;    //호스팅필드
    private Long parentIssueId; // 상위 이슈
    public IssueForm() {
    }
@@ -312,4 +313,12 @@
    public void setHostingId(Long hostingId) {
        this.hostingId = hostingId;
    }
    public Long getParentIssueId() {
        return parentIssueId;
    }
    public void setParentIssueId(Long parentIssueId) {
        this.parentIssueId = parentIssueId;
    }
}
src/main/resources/migration/V1_11__Alter_Table.sql
@@ -127,3 +127,5 @@
-- 이슈 타입 프로젝트
ALTER TABLE `issue_type` ADD COLUMN  `project_id` BIGINT(11) NULL;
-- 상위 이슈
ALTER TABLE `issue` ADD COLUMN  `parent_issue_id` BIGINT(11) NULL;
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js
@@ -199,9 +199,14 @@
                                            break;
                                        // 연관일감 이동
                                        // 연관 일감 이동
                                        case "ISSUE_RELATION_MOVE" :
                                            makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data.issueRelation)\">" + scope.data.title + "</span></a>";
                                            break;
                                        // 연관 일감 이동
                                        case "ISSUE_DOWN_MOVE" :
                                            makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data.id)\">" + scope.data.title + "</span></a>";
                                            break;
                                            // 연관일감 구분
@@ -214,6 +219,11 @@
                                            makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeRelationIssue(data.id)">';
                                            break;
                                        // 하위 일감 삭제
                                        case "ISSUE_DOWN_DELETE":
                                            makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeDownIssue(data.id)">';
                                            break;
                                        //  이름을 클릭하면 수정 팝업 표시
                                        case "COMMON_MODIFY" :
                                            if (scope.data.modifyPermissionCheck) {
src/main/webapp/i18n/ko/global.json
@@ -293,7 +293,15 @@
        "normalList" : "이슈 목록",
        "timeLine" : "타임 라인",
        "useProjects" : "사용 프로젝트",
        "companyInfo" : "업체/ISP/호스팅"
        "companyInfo" : "업체/ISP/호스팅",
        "downIssue": "하위 이슈",
        "downIssueTitle": "하위 이슈 제목",
        "downIssueType": "하위 이슈 구분",
        "addDownIssue": "하위 이슈 추가",
        "downIssueRemove" : "하위 이슈 삭제",
        "failedToIssueAddIssueDown": "하위 이슈 추가 실패",
        "failedToIssueDeleteIssueDown": "하위 이슈 삭제 실패",
        "errorSelectDownIssue" : "하위 이슈가 선택되지 않았습니다."
    },
    "project": {
        "createProject": "프로젝트 만들기",
src/main/webapp/scripts/app/issue/issueDetail.controller.js
@@ -32,6 +32,7 @@
                $scope.fn.reservation = reservation;    //  예약 정보를 확인 및 변경 한다.
                $scope.fn.getIssueListCallBack = getIssueListCallBack;
                $scope.fn.addRelationIssue = addRelationIssue;      // 연관 이슈 추가
                $scope.fn.addDownIssue = addDownIssue;      // 하위 이슈 추가
                //  이슈 목록 컨트롤러 vm, fn 상속 중
@@ -61,10 +62,20 @@
                $scope.vm.relationIssueType = $scope.vm.relationIssueTypes[0];
                $scope.vm.form = {
                    issues : []
                    issues : [], //연관 일감
                    issuesDown : []  // 하위 일감
                };
                $scope.vm.issueName = "";
                $scope.vm.issueNameDown = "";       // 선택된 하위 일감 이름
                $scope.vm.autoCompletePageDown = {
                    issue : {
                        page : 0,
                        totalPage : 0
                    },
                };
                $scope.vm.issueName = "";       // 선택된 연관 일감 이름
                $scope.vm.autoCompletePage = {
                    issue : {
                        page : 0,
@@ -80,10 +91,60 @@
                    changeDetailView : changeDetailView
                };
                $scope.vm.downResponseData = [];
                $scope.vm.downTableConfigs = [];
                //  테이블 이벤트
                $scope.downTableEvent = {
                    removeDownIssue : removeDownIssue,   // 연관 일감 삭제
                    changeDetailView : changeDetailView
                };
                function changeDetailView(issue) {
                    //  이슈 번호를 저장한 후 이슈 목록으로 이동한다.
                    // $rootScope.$broadcast("makeIssueSearch", issue);
                    $scope.$parent.tableEvent.changeDetailView(issue.id);
                }
                // 하위 일감 삭제
                function removeDownIssue(id) {
                    //  삭제 알림
                    SweetAlert.swal({
                            title : $filter("translate")("issue.downIssueRemove"), // 연관 일감 삭제
                            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;
                                var contents = {
                                    id : id
                                };
                                Issue.modifyParentIssue($resourceProvider.getContent(
                                    contents,
                                    $resourceProvider.getPageContent(0, 10))).then(function (result) {
                                    if (result.data.message.status === "success") {
                                        $scope.fn.getIssueDetail();
                                    }
                                    else {
                                        SweetAlert.error($filter("translate")("issue.failedToIssueDeleteIssueDown"), result.data.message.message); // "연관일감 삭제 실패"
                                    }
                                    $rootScope.spinner = false;
                                });
                            }
                        });
                }
                // 연관 일감 삭제
@@ -133,7 +194,25 @@
                    $scope.vm.autoCompletePage.issue.totalPage = result.data.page.totalPage;
                }
                //  이슈 테이블 설정
                //  하위 이슈 테이블 설정
                function makeTableConfigsDown() {
                    $scope.vm.downTableConfigs = [];
                    $scope.vm.downTableConfigs.push($tableProvider.config()
                        .setHName("issue.downIssueTitle")
                        .setDType("renderer")
                        .setHWidth("width-60 bold")
                        .setHSort(false)
                        .setDRenderer("ISSUE_DOWN_MOVE"))
                    $scope.vm.downTableConfigs.push($tableProvider.config()
                        .setHName("issue.relationIssueDelete")
                        .setDType("renderer")
                        .setHWidth("width-10 bold")
                        .setDRenderer("ISSUE_DOWN_DELETE")
                        .setHSort(false)
                        .setDAlign("text-center"))
                }
                //  연관 이슈 테이블 설정
                function makeTableConfigs() {
                    $scope.vm.relTableConfigs = [];
                    $scope.vm.relTableConfigs.push($tableProvider.config()
@@ -175,6 +254,32 @@
                //         }
                //     });
                // }
                // 하위 이슈 추가
                function addDownIssue() {
                    if ($scope.vm.issueNameDown.length == 0 || $scope.vm.form.issuesDown.length == 0
                        || $scope.vm.issueNameDown != $scope.vm.form.issuesDown[0].title) {
                        SweetAlert.error($filter("translate")("issue.errorSelectDownIssue"), "");
                        return;
                    }
                    var contents = {
                        id : $scope.vm.form.issuesDown[0].id,
                        parentIssueId : $rootScope.currentDetailIssueId
                    };
                    Issue.modifyParentIssue($resourceProvider.getContent(
                        contents,
                        $resourceProvider.getPageContent(0, 10))).then(function (result) {
                        if (result.data.message.status === "success") {
                            $scope.fn.getIssueDetail();
                        }
                        else {
                            SweetAlert.error($filter("translate")("issue.failedToIssueAddIssueDown"), result.data.message.message); // "연관일감 생성 실패"
                        }
                    });
                }
                // 연관 이슈 추가
@@ -316,6 +421,8 @@
                                $scope.vm.issueName = "";
                                $scope.vm.form.issues = [];
                                $scope.vm.form.issues.push(result.data.data);
                                $scope.vm.form.issuesDown = [];
                                $scope.vm.form.issuesDown.push(result.data.data);
                                makeTableConfigs();
                                angular.forEach(result.data.data.issueRelationVos, function (issueRelationVo){
@@ -323,7 +430,13 @@
                                    $scope.vm.form.issues.push(issueRelationVo.issueRelation);
                                });
                                makeTableConfigsDown();
                                angular.forEach(result.data.data.issueDownVos, function (issueDownVo){
                                    $scope.vm.form.issuesDown.push(issueDownVo.issue);
                                });
                                $scope.vm.viewer.issueRelationVos = result.data.data.issueRelationVos;
                                $scope.vm.viewer.issueDownVos = result.data.data.issueDownVos;
                            }
                        }
                        else {
src/main/webapp/scripts/components/issue/issue.service.js
@@ -44,6 +44,12 @@
                    return response;
                });
            },
            modifyParentIssue : function (conditions) {
                return $http.post("issue/modifyParentIssue", conditions).then(function (response) {
                    $log.debug("상위 일감 수정 결과 : ", response);
                    return response;
                });
            },
            modify : function (conditions) {
                conditions.url = "issue/modify";
                return $upload.upload(conditions).progress(function (evt) {
src/main/webapp/views/issue/issueDetail.html
@@ -1,10 +1,12 @@
<!-- 이슈 목록 -->
<!--
<div class="support-tickets">
    <div class="support-tickets-header">
<!--        <div class="tickets-control">-->
<!--            <h5 translate="issue.issueList">-->
<!--                이슈 목록-->
<!--            </h5>-->
<!--        </div>-->
        <div class="tickets-control">
            <h5 translate="issue.issueList">
                이슈 목록
            </h5>
        </div>
        <div class="tickets-filter">
            <div class="dataTables_length">
@@ -50,8 +52,9 @@
        </div>
    </div>
    <!--    테이블 -->
-->
    <!-- 테이블 -->
<!--
    <div class="support-ticket ">
        <div class="st-body">
            <div class="table-responsive">
@@ -60,8 +63,9 @@
            </div>
        </div>
    </div>
-->
    <!--    페이징 -->
<!--
    <div class="controls-below-table text-center">
        <ul uib-pagination
            boundary-links-numbes="true"
@@ -78,7 +82,7 @@
        </ul>
    </div>
</div>
-->
<!--    상세 화면   -->
<div class="support-ticket-content-w" ng-controller="issueDetailController">
    <div class="support-ticket-content">
@@ -255,7 +259,6 @@
                </div>
                <h6 class="todo-content-subheader mt-20" translate="issue.relationIssue">연관 일감</h6>
                <!--    테이블 -->
                <div class="mt-10 issue-detail-word-break width-100">
                    <js-table data="vm.viewer.issueRelationVos" table-configs="vm.relTableConfigs"
@@ -294,6 +297,33 @@
                    </div>
                </div>
                <h6 class="todo-content-subheader mt-20" translate="issue.downIssue">하위 일감</h6>
                <!--    테이블 -->
                <div class="mt-10 issue-detail-word-break width-100">
                    <js-table data="vm.viewer.issueDownVos" table-configs="vm.downTableConfigs"
                              event="downTableEvent" detail-view="true" hide-header="false" use-sort="false"></js-table>
                    <div class="row">
                        <div class="col-sm-6">
                            <js-autocomplete-single data-input-name="issue"
                                                    selected-model="vm.form.issuesDown"
                                                    search="vm.issueNameDown"
                                                    source="fn.getIssueList(vm.issueNameDown, vm.form.issuesDown, vm.autoCompletePageDown.issue.page, fn.getIssueListCallBack)"
                                                    page="vm.autoCompletePageDown.issue.page"
                                                    total-page="vm.autoCompletePageDown.issue.totalPage"
                                                    input-disabled="false"
                                                    translation-texts="{ empty : 'common.emptyIssue' }"
                                                    extra-settings="{ displayProp : 'title' , idProp : 'id', imageable : false, imagePathProp : '',
                                            type : '', maxlength : 200, autoResize : true, stopRemoveBodyEvent : true }"></js-autocomplete-single>
                        </div>
                        <div class="col-auto vertical-middle">
                            <button type="button" class="btn btn-primary form-control input-sm"
                                    ng-click="fn.addDownIssue()"
                                    translate="issue.addDownIssue">추가</button>
                        </div>
                    </div>
                </div>
                <h6 class="todo-content-subheader mt-20" translate="common.content">내용</h6>
                <div class="box mt-10 issue-detail-word-break width-100" >