OWL ITS + 탐지시스템(인터넷 진흥원)
이민희
2021-12-09 17a9cb0fc114804ab81cb1eaa2dd5919a0194dd1
Merge branch 'master' of http://192.168.0.25:9001/r/owl-kisa
1개 파일 추가됨
16개 파일 변경됨
326 ■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/common/IssueCustomFieldValueFormComparator.java 20 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/mapper/IssueMapper.java 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java 121 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/IssueVo.java 9 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/web/condition/IssueCondition.java 14 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/mybatis/query-template/issue-template.xml 38 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/bower_components/bootstrap-daterangepicker/daterangepicker.js 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js 13 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/i18n/ko/global.json 5 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/index.html 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueDetail.controller.js 16 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/project/projectList.controller.js 22 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/components/utils/dateRangePicker.directive.js 5 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/api/apiSetting.html 7 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/api/apiSettingSpec.html 13 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueDetail.html 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/login/login.html 33 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/common/IssueCustomFieldValueFormComparator.java
New file
@@ -0,0 +1,20 @@
package kr.wisestone.owl.common;
import kr.wisestone.owl.web.form.IssueApiForm;
import kr.wisestone.owl.web.form.IssueCustomFieldValueForm;
import java.util.Comparator;
public class IssueCustomFieldValueFormComparator implements Comparator<IssueCustomFieldValueForm> {
    @Override
    public int compare(IssueCustomFieldValueForm o1, IssueCustomFieldValueForm o2) {
        if (o1.getCustomFieldId() > o2.getCustomFieldId()) {
            return 1;
        } else if (o1.getCustomFieldId() < o2.getCustomFieldId()) {
            return -1;
        } else {
            return 0;
        }
    }
}
src/main/java/kr/wisestone/owl/mapper/IssueMapper.java
@@ -51,6 +51,6 @@
    Long countByDepartment(IssueCondition issueCondition);
    List<Map<String, Object>> findNotCompleteByParentIssueId(Long parentIssueId);
    List<Map<String, Object>> findNotCompleteByParentIssueId(IssueCondition issueCondition);
}
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -3,6 +3,7 @@
import com.google.common.collect.Lists;
import com.sun.org.apache.bcel.internal.generic.NEW;
import kr.wisestone.owl.common.ExcelConditionCheck;
import kr.wisestone.owl.common.IssueCustomFieldValueFormComparator;
import kr.wisestone.owl.config.CommonConfiguration;
import kr.wisestone.owl.constant.Constants;
import kr.wisestone.owl.constant.ElasticSearchConstants;
@@ -263,11 +264,8 @@
            List<IssueVo> issueVos = this.findIssue(issueApiForm, customFieldApiOverlaps, user.getId());
            int size = issueVos.size();
            if (size == 1) {
            if (size > 0) {
                issueForm.setParentIssueId(issueVos.get(0).getId());
            } else if (size > 1) {
                throw new OwlRuntimeException(
                        this.messageAccessor.getMessage(MsgConstants.API_OVERLAP_ERROR));
            }
            issueForm.setIsApi(Issue.IS_API_YES);
@@ -328,39 +326,36 @@
    }
    // 중복된 상위 이슈 검색
    private List<IssueVo> findIssue(IssueApiForm issueApiForm, List<CustomFieldApiOverlap> customFieldApiOverlaps, Long userId) {
    private List<IssueVo> findIssue(IssueApiForm issueApiform, List<CustomFieldApiOverlap> customFieldApiOverlaps, Long userId) {
        List<IssueCustomFieldValueForm> issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues();
        List<IssueVo> resultIssueVos = Lists.newArrayList();
        String comma = ",";
        List<IssueVo> resultIssueVos = new ArrayList<>();
        if (issueCustomFieldValueForms.size() > 0) {
            String concatUseValue = "";
            int useIdx = 0;
        if (customFieldApiOverlaps != null && customFieldApiOverlaps.size() > 0) {
            for (CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
                for (IssueCustomFieldValueForm issueCustomFieldValue : issueApiForm.getIssueCustomFieldValues()) {
                    IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
                    issueCustomFieldValueCondition.setUseParentIssueId(true);
                    if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValue.getCustomFieldId())) {
                        issueCustomFieldValueCondition.setUseValue(issueCustomFieldValue.getUseValue());
            IssueCustomFieldValueFormComparator comp = new IssueCustomFieldValueFormComparator();
            Collections.sort(issueCustomFieldValueForms, comp);
                        List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
                        if (results != null && results.size() > 0) {
                            List<IssueVo> findIssueVos = new ArrayList<>();
                            Collections.copy(resultIssueVos, findIssueVos);
                            resultIssueVos.clear();
                            for (Map<String, Object> result : results) {
                                IssueVo issueVo = ConvertUtil.convertMapToClass(result, IssueVo.class);
                                if (findIssueVos.size() == 0) {
                                    resultIssueVos.add(issueVo);
                                } else {
                                    IssueVo findIssueVo = findIssueVo(findIssueVos, issueVo.getId());
                                    if (findIssueVo != null) {
                                        resultIssueVos.add(findIssueVo);
                                    }
                                }
                            }
                        } else {
                            resultIssueVos.clear();
                            return resultIssueVos;
            for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) {
                for(CustomFieldApiOverlap customFieldApiOverlap : customFieldApiOverlaps) {
                    if (customFieldApiOverlap.getCustomField().getId().equals(issueCustomFieldValueForm.getCustomFieldId())) {
                        if (useIdx > 0) {
                            concatUseValue = concatUseValue.concat(comma);
                        }
                        concatUseValue = concatUseValue.concat(issueCustomFieldValueForm.getUseValue());
                        useIdx++;
                    }
                }
            }
            IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
            issueCustomFieldValueCondition.setUseValue(concatUseValue);
            List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
            if (results != null && results.size() > 0) {
                for (Map<String, Object> result : results) {
                    resultIssueVos.add(ConvertUtil.convertMapToClass(result, IssueVo.class));
                }
            }
        }
@@ -773,6 +768,7 @@
        int totalPage = (int) Math.ceil((totalCount - 1) / pageable.getPageSize()) + 1;
        //  이슈 아이디 초기화
        issueCondition.setIsApi(issueCondition.getIsApi());
        issueCondition.setIssueIds(Lists.newArrayList());
        //  Map 에 있는 데이터를 IssueVo 데이터로 변환한다.
        this.setMapToIssueVo(results, issueVos, issueCondition, user);
@@ -1483,42 +1479,25 @@
    public List<IssueVo> findIssue(IssueApiForm issueApiform) {
        List<IssueCustomFieldValueForm> issueCustomFieldValueForms = issueApiform.getIssueCustomFieldValues();
        List<IssueVo> resultIssueVos = new ArrayList<>();
        List<IssueVo> resultIssueVos = Lists.newArrayList();
        String comma = ",";
        IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
        issueCustomFieldValueCondition.setUseParentIssueId(false);
        if (issueCustomFieldValueForms.size() > 0) {
            for (IssueCustomFieldValueForm issueCustomFieldValueForm : issueCustomFieldValueForms) {
                CustomField customField = this.customFieldService.getCustomField(issueCustomFieldValueForm.getCustomFieldId());
                CustomFieldType customFieldType = CustomFieldType.DATETIME;
                if (customFieldType.equals(customField.getCustomFieldType())) {
                    continue;
            String concatUseValue = "";
            for (int i = 0; i < issueCustomFieldValueForms.size(); i++) {
                IssueCustomFieldValueForm issueCustomFieldValueForm = issueCustomFieldValueForms.get(i);
                if (i > 0) {
                    concatUseValue = concatUseValue.concat(comma);
                }
//                issueCustomFieldValueCondition.addUseValue(issueCustomFieldValueForm.getUseValue());
                issueCustomFieldValueCondition.setUseValue(issueCustomFieldValueForm.getUseValue());
                List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
                if (results != null && results.size() > 0) {
                    List<IssueVo> findIssueVos = new ArrayList<>();
                    Collections.copy(resultIssueVos, findIssueVos);
                    resultIssueVos.clear();
                    for (Map<String, Object> result : results) {
                        IssueVo issueVo = ConvertUtil.convertMapToClass(result, IssueVo.class);
                concatUseValue = concatUseValue.concat(issueCustomFieldValueForm.getUseValue());
            }
                        issueVo.setParentIssueVo(this.getParentIssueVo(MapUtil.getLong(result, "parentIssueId")));
                        if (findIssueVos.size() == 0) {
                            resultIssueVos.add(issueVo);
                        } else {
                            IssueVo findIssueVo = findIssueVo(findIssueVos, issueVo.getId());
                            if (findIssueVo != null) {
                                resultIssueVos.add(findIssueVo);
                            }
                        }
                    }
                } else {
                    resultIssueVos.clear();
                    return resultIssueVos;
            IssueCustomFieldValueCondition issueCustomFieldValueCondition = new IssueCustomFieldValueCondition();
            issueCustomFieldValueCondition.setUseValue(concatUseValue);
            List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition);
            if (results != null && results.size() > 0) {
                for (Map<String, Object> result : results) {
                    resultIssueVos.add(ConvertUtil.convertMapToClass(result, IssueVo.class));
                }
            }
        }
@@ -1534,15 +1513,6 @@
            }
        }
        return null;
    }
    // 하위 이슈가 모두 종료 처리 되었을 경우 상위이슈도 완료 처리
    private void setParentIssueComplete(Issue parentIssue) {
        if (parentIssue != null) {
            this.issueMapper.findNotCompleteByParentIssueId(parentIssue.getId());
        }
    }
@@ -1570,10 +1540,12 @@
                }
                if (parentIssue != null) {
                    List<Map<String, Object>> results = this.issueMapper.findNotCompleteByParentIssueId(parentIssue.getId());
                    IssueCondition issueCondition = new IssueCondition(issueVo.getId(), parentIssue.getId());
                    List<Map<String, Object>> results = this.issueMapper.findNotCompleteByParentIssueId(issueCondition);
                    // 하위 일감이 모두 종료 상태일때 상위 일감도 종료 처리
                    if (results == null || results.size() == 0) {
                        parentIssue.setIssueStatus(issueType.getIssueStatus());
                        this.issueRepository.saveAndFlush(parentIssue);
                    }
                }
@@ -1660,6 +1632,7 @@
            this.issueHistoryService.detectIssueStatus(issue, issueForm, detectIssueChange, oldIssueStatus, issueStatus);
        }
        // db에 저장
        issue = this.saveIssue(issueForm, checkIssueData);
        //  이슈 이력 등록
src/main/java/kr/wisestone/owl/vo/IssueVo.java
@@ -31,6 +31,7 @@
    private Long severityId;
    private String severityName;
    private String severityColor;
    private String isApi;
    private ProjectVo projectVo;    //  이슈 상세에서 사용
    private IssueStatusVo issueStatusVo;    //  이슈 상세에서 사용
    private IssueTypeVo issueTypeVo;    //  이슈 상세에서 사용
@@ -231,6 +232,14 @@
        this.severityColor = severityColor;
    }
    public String getIsApi() {
        return isApi;
    }
    public void setIsApi(String isApi) {
        this.isApi = isApi;
    }
    public Boolean getModifyPermissionCheck() {
        return modifyPermissionCheck;
    }
src/main/java/kr/wisestone/owl/web/condition/IssueCondition.java
@@ -34,6 +34,7 @@
    private Long workspaceId;
    private String projectType;
    private String deep;
    private String isApi;
    private Long parentIssueId;     // 상위 일감
    private String useValue;
    private List<Long> projectIds = Lists.newArrayList();
@@ -55,6 +56,11 @@
    private Boolean hideIssue;
    public IssueCondition(){}
    public IssueCondition(Long issueId, Long parentIssueId){
        this.id = issueId;
        this.parentIssueId = parentIssueId;
    }
    //  대시보드 위기관리 위젯에서 사용
    public IssueCondition(List<String> issueIds){
        this.issueIds = issueIds;
@@ -301,6 +307,14 @@
        this.deep = deep;
    }
    public String getIsApi() {
        return isApi;
    }
    public void setIsApi(String isApi) {
        this.isApi = isApi;
    }
    public List<Long> getProjectIds() {
        return projectIds;
    }
src/main/resources/mybatis/query-template/issue-template.xml
@@ -15,6 +15,7 @@
        issue.complete_date as completeDate,
        issue.issue_number as issueNumber,
        issue.register_date as registerDate,
        issue.is_api as isApi,
        SUBSTRING(issue.modify_date, 1, 19) as modifyDate,
        project.id as projectId,
        project.name as projectName,
@@ -965,8 +966,6 @@
                    AND is_api = #{isApi};
    </select>
    <!--    이슈 상태를 사용하는 이슈 갯수를 조회한다. -->
    <select id="countByIssueStatusId" resultType="java.lang.Long" parameterType="java.lang.Long">
        SELECT COUNT(DISTINCT id) FROM
@@ -977,29 +976,32 @@
    <!--    특정 사용자 정의 필드 값이 같은 이슈를 조회 -->
    <select id="findByCustomFieldValue" resultType="java.util.HashMap" parameterType="kr.wisestone.owl.web.condition.IssueCustomFieldValueCondition">
        SELECT
        issue_custom.issue_id as id,
        iss.parent_issue_id as parentIssueId
        FROM issue_custom_field_value issue_custom
        INNER JOIN issue iss ON iss.id = issue_custom.issue_id
        WHERE 1=1
        AND issue_custom.use_value = #{useValue}
        <choose>
          <when test="useParentIssueId.equals(true)">
              AND iss.parent_issue_id IS NULL
          </when>
          <otherwise>
              AND iss.parent_issue_id IS NOT NULL
          </otherwise>
        </choose>
            issue.id as id,
            issue.title as title,
            customFieldValue.customFieldType AS customFieldType,
            GROUP_CONCAT(customFieldValue.useValue) AS concatUseValue
        FROM issue issue FORCE INDEX(reverseIndex)
        INNER JOIN issue_status as issStatus ON issue.issue_status_id = issStatus.id
        LEFT OUTER JOIN (
            SELECT cf.id AS customFieldId, cf.custom_field_type AS customFieldType, issue_custom.use_value AS useValue, issue_custom.issue_id AS issueId
            FROM issue_custom_field_value issue_custom
            INNER JOIN custom_field cf ON cf.id = issue_custom.custom_field_id
            ORDER BY issue_custom.id ASC) customFieldValue ON customFieldValue.issueId = issue.id
        WHERE issStatus.issue_status_type != 'CLOSE'
        GROUP BY issue.id
        HAVING concatUseValue LIKE CONCAT('%', #{useValue}, '%')
    </select>
    <!--  종료 안된 하위 이슈 가져오기 -->
    <select id="findNotCompleteByParentIssueId" resultType="java.util.HashMap" parameterType="java.lang.Long">
    <select id="findNotCompleteByParentIssueId" resultType="java.util.HashMap" parameterType="kr.wisestone.owl.web.condition.IssueCondition">
        SELECT
        iss.id as id
        iss.id as id,
        iss.title as title
        FROM issue iss
        INNER JOIN issue_status issueStatus on iss.issue_status_id = issueStatus.id
        WHERE iss.parent_issue_id = #{parentIssueId}
        AND iss.id != #{id}
        AND issueStatus.issue_status_type != 'CLOSE'
    </select>
</mapper>
src/main/webapp/bower_components/bootstrap-daterangepicker/daterangepicker.js
@@ -108,7 +108,7 @@
                      '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
                      '<div class="calendar-time">' +
                        '<div></div>' +
                        '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
                        '<i class="fa fa-clock-o glyphicon glyphicon-time" style="position: relative; left:12.3rem; bottom: 1.23rem "></i>' +
                      '</div>' +
                    '</div>' +
                    '<div class="calendar-table"></div>' +
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js
@@ -75,13 +75,9 @@
                                        //  프로젝트 이름(프로젝트 리스트에서 사용)
                                        case "PROJECT_NAME" :
                                            if ($rootScope.workProject != null && $rootScope.workProject.id == scope.data.id) {
                                                // makeTag += "<span class='titlenameSelect cursor table-word-break-all sub-line' ng-click='event.changeLastProject(data.id)'>" + myToken + scope.data.name.replace(/</gi, '&lt;') + "</span>";
                                                makeTag += "<span class='titlenameSelect cursor table-word-break-all sub-line' ng-click='event.moveIssue(data.id)'>" + myToken + scope.data.name.replace(/</gi, '&lt;') + "</span>";
                                                // makeTag += "<span class='titlenameSelect cursor table-word-break-all sub-line' ng-click='event.changeDetailView(data.id)'>" + myToken + scope.data.name.replace(/</gi, '&lt;') + "</span>";
                                                makeTag += "<span class='titlenameSelect cursor table-word-break-all sub-line' ng-click='event.changeLastProject(data.id)'>" + myToken + scope.data.name.replace(/</gi, '&lt;') + "</span>";
                                            } else {
                                                // makeTag += "<span class='titlename cursor table-word-break-all sub-line' ng-click='event.changeLastProject(data.id)'>" + myToken + scope.data.name.replace(/</gi, '&lt;') + "</span>";
                                                makeTag += "<span class='titlename cursor table-word-break-all sub-line' ng-click='event.moveIssue(data.id)'>" + myToken + scope.data.name.replace(/</gi, '&lt;') + "</span>";
                                                // makeTag += "<span class='titlename cursor table-word-break-all sub-line' ng-click='event.changeDetailView(data.id)'>" + myToken + scope.data.name.replace(/</gi, '&lt;') + "</span>";
                                                makeTag += "<span class='titlename cursor table-word-break-all sub-line' ng-click='event.changeLastProject(data.id)'>" + myToken + scope.data.name.replace(/</gi, '&lt;') + "</span>";
                                            }
                                            break;
@@ -306,7 +302,6 @@
                                        // 하위 이슈 이동(제목)
                                        case "ISSUE_DOWN_MOVE" :
                                            makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data)\">" + scope.data.title + "</span></a>";
                                            break;
@@ -429,8 +424,8 @@
                                            makeTag += '<span class="number-tag">' + scope.data.projectKey + ' - ' + scope.data.issueNumber + '</span>';
                                            makeTag += ' <span class="tag"> / </span> ';
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.issueStatusColor + "\"," + "\"border-color\"" + " : \"" + scope.data.issueStatusColor + "\", \"color\": \"#FFFFFF\" }'>" + scope.data.issueStatusName + "</span>";
                                            // makeTag += ' <span class="tag"> / </span> ';
                                            // makeTag += '<span class="tag">' + scope.data.projectName + '</span>';
                                            makeTag += '<span class="tag"> &nbsp;/ </span> ';
                                            makeTag += '<span class="tag">' +'<span>API:&nbsp;</span>' + scope.data.isApi + '</span>';
                                            makeTag += '</div>';
                                            makeTag += '<div class="titlename cursor text-left" ng-click="event.changeDetailView(data.id)">' + scope.data.title.replace(/</gi, '&lt;') + '</div>';
                                            makeTag += '<div class="extra-infodiv text-left">';
src/main/webapp/i18n/ko/global.json
@@ -888,12 +888,13 @@
        "failedToApiMonitor": "API 기록 조회 실패",
        "requestSample": "API 요청 샘플",
        "requestSampleAdd": "이슈 추가",
        "requestSampleModify": "이슈 수정",
        "requestSampleModify": "이슈 상태 수정",
        "downIssueOverlapSetting" : "하위 이슈 처리 기준 항목",
        "upIssueCompleteIssueStatus" : "상위 이슈 자동종료 이슈 상태 설정",
        "autoCompleteIssueStatus" : "자동 종료 설정할 이슈 상태",
        "successToApiAutoCompleteIssueStatus" : "자동 종료 이슈 상태 설정 완료",
        "failedToApiAutoCompleteIssueStatus" : "자동 종료 이슈 상태 설정 실패"
        "failedToApiAutoCompleteIssueStatus" : "자동 종료 이슈 상태 설정 실패",
        "requestSampleModifyDesc" : "(수정시 customField 항목은 검색 용도로 사용됨)"
    },
    "companyField" : {
        "info": "업체정보",
src/main/webapp/index.html
@@ -21,7 +21,7 @@
    <meta name="google-site-verification" content="yhmSp9Zsw5oecXjp43Ndu0w9rBA3FNpnNZ8bQFA_iDA"/>
    <meta name="viewport" content="user-scalable=no,initial-scale=1,maximum-scale=1">
    <title>OWL ITS</title>
    <title>탐지정보 통합관리</title>
    <link type="text/css" rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.css">
    <link type="text/css" rel="stylesheet" href="bower_components/jquery-ui/themes/base/jquery-ui.css">
src/main/webapp/scripts/app/issue/issueDetail.controller.js
@@ -50,6 +50,7 @@
                $scope.fn.setDownTableConfigs = setDownTableConfigs;
                $scope.fn.containsPartner = containsPartner;
                $scope.fn.onActivate = onActivate;
                $scope.fn.issueBack = issueBack;
                //  이슈 목록 컨트롤러 vm, fn 상속 중
                $scope.vm.viewer = {};
@@ -125,6 +126,12 @@
                    //$rootScope.$broadcast("makeIssueSearch",issue);
                    $scope.$parent.tableEvent.changeDetailView(issue.id);
                    $scope.fn.onActivate();
                }
                // 상위 이슈 클릭시 상위 이슈로 이동
                function issueBack() {
                    $rootScope.currentDetailIssueId = $scope.vm.viewer.parentIssueVo.id
                    $rootScope.$broadcast("getIssueDetail", {id: $rootScope.currentDetailIssueId});
                }
                function onActivate() {
@@ -490,6 +497,7 @@
                // 연관 이슈 테이블 설정
                function setRelTableConfigs(issueTableConfigVo) {
                    if (issueTableConfigVo == null) return;
                    var issueTableConfigs = issueTableConfigVo.issueTableConfigs;
                    //  연관 슈 목록 테이블 설정 값을 가져와서 적용한다.
@@ -541,6 +549,7 @@
                // 하위 이슈 상세 조회 결과 설정
                function setDownTableConfigs(issueTableConfigVo) {
                    if (issueTableConfigVo == null) return;
                    var issueTableConfigs = issueTableConfigVo.issueTableConfigs;
                    //  연관 슈 목록 테이블 설정 값을 가져와서 적용한다.
@@ -656,7 +665,6 @@
                //     $scope.fn.getIssueDetail();
                // });
                // todo 이건 또 뭐지
                $scope.$watch(function() {
                    return $rootScope.currentDetailIssueId;
                }, function() {
@@ -889,11 +897,7 @@
                                    angular.forEach(result.data.data.issueDownVos, function (issueDownVo){
                                        //$scope.vm.form.issuesDown.push(issueDownVo.issueDown);
                                        $scope.vm.form.issuesDown.push(issueDownVo);
                                        // 간헐적인 하위 이슈 갱신 오류 방지
                                        // $scope.$on("getIssueDetail", function (event, args) {
                                        //      $scope.fn.getIssueDetail();
                                        //  });
                                    });
                                }
                                $scope.vm.viewer.issueRelationVos = result.data.data.issueRelationVos;
src/main/webapp/scripts/app/project/projectList.controller.js
@@ -69,9 +69,7 @@
                $scope.tableEvent = {
                    modify : modify,
                    projectCustomFieldConfig : projectCustomFieldConfig,
                    changeLastProject : changeLastProject,
                    moveIssue : moveIssue,
                    changeDetailView : changeDetailView
                    changeLastProject : changeLastProject
                };
                angular.extend(this, $controller('autoCompleteController', {$scope : $scope, $injector : $injector}));
@@ -363,22 +361,8 @@
                }
                function changeLastProject(projectId) {
                    $rootScope.changeLastProject(projectId);
                }
                function moveIssue(projectId) {
                    // $rootScope.currentDetailIssueId = null;
                    // 이슈 번호를 저장한 후 이슈 목록으로 이동한다.
                    // $rootScope.$broadcast("makeIssueSearch", {id :$rootScope.currentDetailIssueId});
                    //$rootScope.$broadcast("makeIssueSearch", {id :$rootScope.issueTypeMenu.id});
                    $rootScope.$broadcast("makeIssueSearch",projectId);
                }
                function changeDetailView() {
                    // $rootScope.$broadcast("getIssueDetail", {id: $rootScope.currentDetailIssueId});
                    //$scope.$broadcast("getIssueDetail", {id: $rootScope.currentDetailIssueId});
                    // $rootScope.$broadcast("getIssueDetail", {id :$rootScope.currentDetailIssueId});
                    //$rootScope.$broadcast("getIssueList", {id :$rootScope.issueTypeMenu.id});
                    //$rootScope.changeLastProject(projectId);
                    $state.go("issues.list")
                }
                $scope.fn.makeTableConfigs();
src/main/webapp/scripts/components/utils/dateRangePicker.directive.js
@@ -77,7 +77,8 @@
                                    });
                                } else if ($attrs["rangeType"] === "singleDate") {
                                    $($element).daterangepicker({
                                        timePicker: false,
                                        timePicker: true,
                                        timePickerSeconds : true,
                                        autoUpdateInput: true,
                                        autoApply : true,
                                        singleDatePicker : true,
@@ -85,7 +86,7 @@
                                        //parentEl : $scope.parentEl !== undefined ? $scope.parentEl : "",
                                        locale: {
                                            format: 'YYYY-MM-DD',
                                            format: 'YYYY-MM-DD/hh-mm-ss A',
                                            applyLabel: options.applyLabel,
                                            cancelLabel: options.cancelLabel,
                                            daysOfWeek: options.daysOfWeek,
src/main/webapp/views/api/apiSetting.html
@@ -1,13 +1,6 @@
<div class="row">
    <div class="col-sm-12">
        <div class="element-wrapper">
            <div class="element-actions">
                <button ng-click="fn.add()"
                        class="btn btn-xlg btn-danger"><i class="os-icon os-icon-plus"></i> <span translate="api.addOverlapField">필드 만들기</span>
                </button>
            </div>
            <div class="element-actions" ng-if="$root.checkMngPermission('USER_PERMISSION_MNG_ISSUE_STATUS')">
            </div>
            <h6 class="element-header" translate="api.setting">
src/main/webapp/views/api/apiSettingSpec.html
@@ -99,7 +99,7 @@
<div class="element-box">
    <div class="row">
        <div class="col-md-1">
            <label for="issue-detectingInfo" class="issue-label">
            <label class="issue-label">
                <span translate="api.requestSampleAdd">이슈 추가</span>
            </label>
        </div>
@@ -108,12 +108,17 @@
        </div>
        <div class="col-md-1"></div>
        <div class="col-md-1">
            <label for="issue-detectingInfo" class="issue-label">
            <label class="issue-label">
                <span translate="api.requestSampleModify">이슈 수정</span>
            </label>
            <label class="text-info">
                <span translate="api.requestSampleModifyDesc">수정시</span>
            </label>
        </div>
        <div>
            <pre>{{vm.sampleJsonModify}}</pre>
        <div class="col-md-2">
            <div>
                <pre>{{vm.sampleJsonModify}}</pre>
            </div>
        </div>
    </div>
</div>
src/main/webapp/views/issue/issueDetail.html
@@ -87,7 +87,7 @@
<div class="support-ticket-content-w" ng-controller="issueDetailController">
    <div class="support-ticket-content">
        <span ng-if="vm.viewer.parentIssueVo != null" class="badge" ng-style="{'background-color' : '#353535', 'border-color' : vm.viewer.issueStatusVo.color, 'color' : '#FFFFFF' }">
            <span>상위 이슈:{{vm.viewer.parentIssueVo.title}}</span>
            <span class="cursor" ng-click="fn.issueBack()">상위 이슈:{{vm.viewer.parentIssueVo.title}}</span>
        </span>
        <div class="">
@@ -97,7 +97,7 @@
            <span class="ticket-header">
                <div class="tasks-header-w">
                    <span class="tags">
                        <span class="tag">{{vm.viewer.projectVo.projectKey}}-{{vm.viewer.issueNumber}} &nbsp; / &nbsp; {{vm.viewer.projectVo.name}}</span>
                        <span class="tag">{{vm.viewer.projectVo.projectKey}}-{{vm.viewer.issueNumber}} &nbsp; / &nbsp; {{vm.viewer.projectVo.name}} &nbsp; / &nbsp; <span>API :&nbsp;{{vm.viewer.isApi}}</span></span>
                    </span>
                </div>
            </span>
src/main/webapp/views/login/login.html
@@ -1,23 +1,24 @@
<div class="content-i">
    <div class="content-box">
        <div class="row mt-30">
        <div class="row mt-30" style="margin-right: 32rem">
            <div class="m-0">
                <div class="flex">
                    <div class="loginbackdiv">
                        <div class="loginback">
                            <img src="/assets/images/logo-kisa-vertical.png"/>
                            <div class="stardiv">
                            <!--    <div class="stars"></div>
                                <div class="twinkling"></div>
                            </div>
                            <div class="bgdiv">
                            </div>
                            <div class="login-circle">
                                <div class="circle1"></div>
                                <div class="circle2"></div>
                                <div class="circle3"></div>-->
                            </div>
                        </div>
<!--                        <div class="loginback">-->
<!--                            <img src="/assets/images/logo-kisa-vertical.png"/>-->
<!--                            <div class="stardiv">-->
<!--                                <div class="stars"></div>-->
<!--                                <div class="twinkling"></div>-->
<!--                            </div>-->
<!--                            <div class="bgdiv">-->
<!--                            </div>-->
<!--                            <div class="login-circle">-->
<!--                                <div class="circle1"></div>-->
<!--                                <div class="circle2"></div>-->
<!--                                <div class="circle3"></div>-->
<!--                            </div>-->
<!--                        </div>-->
<!--                    </div>-->
                    </div>
                    <div class="logincont">
                        <div class="auth-box-w">
@@ -131,7 +132,7 @@
                </div>
                -->
                <div class="footer-s" >
                    <small>CopyRight WISESTONE All rights reserved.</small>
                    <small style="margin-left: 8.8rem">CopyRight WISESTONE All rights reserved.</small>
                </div>
            </div>
        </div>