OWL ITS + 탐지시스템(인터넷 진흥원)
jhjang
2021-11-15 b31979feb926bad9e0070332fb5ed7a896fd378d
Merge remote-tracking branch 'origin/master'
2개 파일 추가됨
15개 파일 변경됨
648 ■■■■ 파일 변경됨
src/main/java/kr/wisestone/owl/domain/IssueUser.java 12 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java 13 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/service/impl/UserServiceImpl.java 4 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/vo/IssueVo.java 9 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/resources/migration/V1_1__Initial_Setup.sql 6 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/assets/styles/main.css 32 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/i18n/ko/global.json 9 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueCompanyFieldDetail.controller.js 85 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueList.controller.js 8 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/components/utils/autoComplete.controller.js 40 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueAdd.html 383 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueCompanyFieldDetail.html 37 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueDetail.html 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueListNormal.html 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueListTimeline.html 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueModify.html 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueModifyUser.html 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/java/kr/wisestone/owl/domain/IssueUser.java
@@ -23,6 +23,10 @@
    @JoinColumn(name = "workspace_id")
    private Workspace workspace;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;
    public IssueUser() {
    }
@@ -62,4 +66,12 @@
    public void setWorkspace(Workspace workspace) {
        this.workspace = workspace;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartment(Department department) {
        this.department = department;
    }
}
src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -744,6 +744,7 @@
        issueVo.setSeverityVo(ConvertUtil.copyProperties(issue.getSeverity(), SeverityVo.class));
        this.setRegister(issue, issueVo);   //  등록자 정보 셋팅
        this.setIssueUser(issue, issueVo);  //  담당자 정보 셋팅
        this.setIssueDepartment(issue, issueVo);  //  담당부서 정보 셋팅
        this.setAttachedFiles(issue, issueVo);  //  첨부 파일 정보 셋팅
        this.setIssueCustomFields(issue, issueVo);  //  사용자 정의 필드 값 정보 셋팅
        this.setIssueComments(issue, issueVo);  //  댓글 정보 셋팅
@@ -830,6 +831,18 @@
        issueVo.setUserVos(userVos);
    }
    //  이슈 담당부서 정보를 셋팅한다.
    private void setIssueDepartment(Issue issue, IssueVo issueVo) {
        List<DepartmentVo> departmentVos = Lists.newArrayList();
        for (IssueUser issueUser : issue.getIssueUsers()) {
            DepartmentVo departmentVo = ConvertUtil.copyProperties(issueUser.getDepartment(), DepartmentVo.class);
            departmentVo.setByName(departmentVo.getByName());
            departmentVos.add(departmentVo);
        }
        issueVo.setDepartmentVos(departmentVos);
    }
    //  이슈 첨부파일 정보를 셋팅한다.
    private void setAttachedFiles(Issue issue, IssueVo issueVo) {
        List<AttachedFileVo> attachedFileVos = Lists.newArrayList();
src/main/java/kr/wisestone/owl/service/impl/UserServiceImpl.java
@@ -237,11 +237,11 @@
        } else if(validAdmin == 1) {    // 라이센스 입력 관리자
            DepartmentForm departmentForm = new DepartmentForm();
            /*DepartmentForm departmentForm = new DepartmentForm();
            departmentForm.setDepartmentName("부서 없음");
            Department department = this.departmentService.add(departmentForm);
            this.departmentRepository.saveAndFlush(department);
            this.departmentRepository.saveAndFlush(department);*/
            Workspace primaryWorkspace = this.workspaceService.getPrimaryWorkspace();
src/main/java/kr/wisestone/owl/vo/IssueVo.java
@@ -37,6 +37,7 @@
    private UserVo registerVo;  //  이슈 상세에서 사용
    private Boolean modifyPermissionCheck = Boolean.FALSE;
    private List<UserVo> userVos = Lists.newArrayList();
    private List<DepartmentVo> departmentVos = Lists.newArrayList(); //담당부서 추가
    private List<AttachedFileVo> attachedFileVos = Lists.newArrayList();
    private List<IssueCommentVo> issueCommentVos = Lists.newArrayList();
    private List<IssueHistoryVo> issueHistoryVos = Lists.newArrayList();
@@ -370,4 +371,12 @@
    public  List<IssueVo> getIssueRelationIssueVos() { return  this.issueRelationVos; }
    public void setIssueRelationIssueVos(List<IssueVo> issueRelationVos) { this.issueRelationVos = issueRelationVos; }
    public List<DepartmentVo> getDepartmentVos() {
        return departmentVos;
    }
    public void setDepartmentVos(List<DepartmentVo> departmentVos) {
        this.departmentVos = departmentVos;
    }
}
src/main/resources/migration/V1_1__Initial_Setup.sql
@@ -303,7 +303,8 @@
-- 테이블 owl_en_1.5.issue_user 구조 내보내기
CREATE TABLE IF NOT EXISTS `issue_user` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `user_id` bigint(20) NOT NULL,
    `user_id` bigint(20) NULL,
    `department_id` bigint(20) NOT NULL,
    `issue_id` bigint(20) NOT NULL,
    `workspace_id` bigint(20) NOT NULL,
    `register_id` bigint(20) NOT NULL,
@@ -314,7 +315,8 @@
    KEY `userIdAndIssueIdIndex` (`user_id`,`issue_id`),
    KEY `issueIdIndex` (`issue_id`),
    KEY `workspaceIdIndex` (`workspace_id`),
    KEY `userIdIndex` (`user_id`)
    KEY `userIdIndex` (`user_id`),
    KEY `departmentIdIndex` (`department_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 테이블 데이터 owl_en_1.5.issue_user:~0 rows (대략적) 내보내기
src/main/webapp/assets/styles/main.css
@@ -3132,6 +3132,29 @@
    border-color: #292b2c;
}
.btn-indigo {
    color: #fff;
    background-color: #1973EB;
    border-color: #1973EB;
}
.btn-indigo:hover {
    color: #fff;
    background-color: #0f0165;
    border-color: #0f0165;
}
.btn-indigo:focus, .btn-secondary.focus {
    -webkit-box-shadow: 0 0 0 0.2rem rgba(41, 43, 44, 0.5);
    box-shadow: 0 0 0 0.2rem rgba(41, 43, 44, 0.5);
}
.btn-indigo.disabled, .btn-secondary:disabled {
    color: #fff;
    background-color: #292b2c;
    border-color: #292b2c;
}
.btn-success {
    color: #fff;
    background-color: #5eb314;
@@ -28580,7 +28603,6 @@
.tab .tablabel::after {
    display: inline-block;
    color: #4d8bf5;
    background-color:;
    width: 30px;
    font-size: 0.80rem;
    line-height: 40px;
@@ -30173,4 +30195,12 @@
    width: 100%
}
.fontcolor_green {
    color: #6C9266;
    font-size: 15px;
}
.fontcolor_neon_green {
    color: #282c34;
    font-size: 15px;
}
/* 간트차트 end */
src/main/webapp/i18n/ko/global.json
@@ -767,7 +767,10 @@
        "departmentName": "부서명",
        "departmentEx": "부서설명",
        "departmentCount": "부서인원",
        "departmentUser": "부서 팀원"
        "departmentUser": "부서 팀원",
        "detectingInfo": "탐지정보",
        "detectingData": "탐지일시",
        "import": "가져오기"
    },
    "tasks": {
        "agileBoardTitle": "칸반 보드"
@@ -798,12 +801,14 @@
        "successToApiTokenAdd" : "API 토큰 생성 성공"
    },
    "companyField" : {
        "info": "업체 정보",
        "add" : "업체 생성",
        "name" : "업체 이름",
        "company" : "업체 분류",
        "profitYN" : "영리/비영리",
        "industry" : "산업 분류",
        "domain" : "도메인",
        "ipAdress" : "ip주소",
        "manager" : "담당자",
        "tel" : "전화번호",
        "code" : "코드",
@@ -819,6 +824,7 @@
        "invalidTelFormat": "전화번호 형식이 맞지 않습니다. xxx-xxx-xxxx 형식으로 입력하세요."
    },
    "ispField" : {
        "info": "ISP 정보",
        "add" : "ISP 생성",
        "name" : "ISP 이름",
        "manager" : "담당자",
@@ -836,6 +842,7 @@
        "invalidCodeFormat": "코드명에는 특수 문자를 입력 할 수 없습니다."
    },
    "hostingField" : {
        "info": "호스팅 정보",
        "add" : "호스팅 생성",
        "name" : "호스팅 이름",
        "manager" : "담당자",
src/main/webapp/scripts/app/issue/issueCompanyFieldDetail.controller.js
New file
@@ -0,0 +1,85 @@
/**
 * Created by wisestone on 2018-02-19.
 */
'use strict';
define([
        'app'
    ],
    function (app) {
        app.controller('companyFieldAddController', ['$scope', '$rootScope', '$log', '$resourceProvider', 'SweetAlert', '$uibModal', '$uibModalInstance', '$state', 'CompanyField', '$filter',
            function ($scope, $rootScope, $log, $resourceProvider, SweetAlert, $uibModal, $uibModalInstance, $state, CompanyField, $filter) {
                $scope.fn = {
                    cancel : cancel,    //  팝업 창 닫기
                    formSubmit : formSubmit,    //  폼 전송
                    formCheck : formCheck,   //  폼 체크
                };
                $scope.vm = {
                    form : {
                        name : "",  //업체명
                        //companyType : "", //업체분류
                        //profitYN : "",  //영리/비영리
                        //industry : "",  //산업분류
                        //domain : "",  //도메인
                        manager : "",   //담당자
                        tel : "",  //전화번호
                        email : "",  //이메일
                        memo : ""  //비고
                    }
                };
                //  폼 체크
                function formCheck(formInvalid) {
                    if (formInvalid) {
                        return true;
                    }
                    return false;
                }
                //  폼 전송
                function formSubmit(condition) {
                    $rootScope.spinner = true;
                    var content = {
                        name : $rootScope.preventXss($scope.vm.form.name),    //  업체명
                        //companyType : $scope.vm.form.companyType, //업체분류
                        //profitYN : $scope.vm.form.profitYN,  //영리/비영리
                        //industry : $scope.vm.form.industry,  //산업분류
                        //domain : $scope.vm.form.domain,  //도메인
                        manager : $scope.vm.form.manager,   //담당자
                        tel : $scope.vm.form.tel,  //전화번호
                        email : $scope.vm.form.email,  //이메일
                        memo : $scope.vm.form.memo  //비고
                    };
                    CompanyField.add($resourceProvider.getContent(content,
                        $resourceProvider.getPageContent(0, 10))).then(function (result) {
                        if (result.data.message.status === "success") {
                            $scope.fn.cancel();
                            //  목록 화면 갱신
                            $rootScope.$broadcast("getPageList", {});
                        }
                        else {
                            SweetAlert.error($filter("translate")("companyField.failedCompanyFieldRegistration"), result.data.message.message);
                        }
                        $rootScope.spinner = false;
                    });
                }
                //  팝업 창 닫기
                function cancel() {
                    $rootScope.$broadcast("closeLayer");    //  팝업이 열리고 나서 js-multi, js-single 등에서 body 이벤트가 날아가는 현상 수정
                    $uibModalInstance.dismiss('cancel');
                    $(document).unbind("keydown");  //  단축키 이벤트 제거
                }
            }
        ]);
    }
);
src/main/webapp/scripts/app/issue/issueList.controller.js
@@ -240,9 +240,9 @@
                                .setDAlign("text-center")
                                .setDName("issueTypeName"));
                            break;
                        case "ASSIGNEE" :   //  담당자
                        case "ASSIGNEETEAM" :   //  담당부서
                            $scope.vm.tableConfigs.push($tableProvider.config()
                                .setHName("common.assignee")
                                .setHName("common.assigneeTeam")
                                .setDType("renderer")
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
@@ -866,8 +866,8 @@
                                    position : 3,
                                    display : true
                                }, {
                                    name : $filter("translate")("common.assignee"), // 담당자
                                    key : "ASSIGNEE",
                                    name : $filter("translate")("common.assigneeTeam"), // 담당부서
                                    key : "ASSIGNEETEAM",
                                    width : "width-140-p",
                                    position : 4,
                                    display : true
src/main/webapp/scripts/components/utils/autoComplete.controller.js
@@ -17,6 +17,7 @@
                var User = $injector.get("User");
                var Project = $injector.get("Project");
                var Workflow = $injector.get("Workflow");
                var CompanyField = $injector.get("CompanyField");
                var Issue = $injector.get("Issue");
                var UserWorkspace = $injector.get("UserWorkspace");
                var $log = $injector.get("$log");
@@ -28,6 +29,7 @@
                $scope.fn.getIssueList = getIssueList;  //  일감 목록 정보를 조회한다.
                $scope.fn.getWorkflowList = getWorkflowList;    //  워크플로우 목록 정보를 조회한다.
                $scope.fn.getUserDepartmentList = getUserDepartmentList;    //  부서 목록 정보를 조회한다.
                $scope.fn.getCompanyFieldList = getCompanyFieldList;    //  부서 목록 정보를 조회한다.
                function getUserList(query, excludeList, page, callBack) {
                    var conditions = {
@@ -94,6 +96,8 @@
                    var deferred = $q.defer();
                    Project.findWork($resourceProvider.getContent(         //  페이징 업데이트가 필요한 컴포넌트 일경우, page 업데이트가 있을 경우 기본 10개씩 가져오고 아닐경우 25개씩 가져온다.
                        conditions, $resourceProvider.getPageContent($rootScope.isDefined(page) ? page : 0, $rootScope.isDefined(page) ? 10 : 25))).then(function (result) {
                        if (result.data.message.status === "success") {
@@ -111,6 +115,42 @@
                    return deferred.promise;
                }
                function getCompanyFieldList(query, excludeList, page, callBack, statuses, roleTypes) {
                    var conditions = {
                        companyName : query,
                        excludeIds : (function () {
                            var excludeIds = [];
                            angular.forEach(excludeList, function (exclude) {
                                excludeIds.push(exclude.id);
                            });
                            return excludeIds;
                        })()
                    };
                    var deferred = $q.defer();
                    CompanyField.find($resourceProvider.getContent(         //  페이징 업데이트가 필요한 컴포넌트 일경우, page 업데이트가 있을 경우 기본 10개씩 가져오고 아닐경우 25개씩 가져온다.
                        conditions, $resourceProvider.getPageContent($rootScope.isDefined(page) ? page : 0, $rootScope.isDefined(page) ? 10 : 25))).then(function (result) {
                        if (result.data.message.status === "success") {
                            if ($rootScope.isDefined(callBack)) {
                                callBack(result);
                            }
                            deferred.resolve(result.data.data);
                        }
                        else {
                            SweetAlert.swal($filter("translate")("common.failedToProjectListLookUp"), result.data.message.message, "error"); // "프로젝트 목록 조회 실패"
                        }
                    });
                    return deferred.promise;
                }
                function getUserDepartmentList(query, excludeList, page, callBack) {
                    var conditions = {
                        departmentName : query,
src/main/webapp/views/issue/issueAdd.html
@@ -136,7 +136,7 @@
            <div class="row">
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label class="issue-label"> <span translate="common.assignee">담당자</span> </label>
                        <label class="issue-label"> <span translate="common.assigneeTeam">담당부서</span> </label>
                        <js-input-autocomplete data-input-name="users"
                                               selected-model="vm.form.users"
                                               search="vm.userName"
@@ -148,7 +148,6 @@
                                               extra-settings="{ displayProp : 'byName' , idProp : 'id', imageable : true, imagePathProp : 'profile',
                                               type : 'user', maxlength : 100, autoResize : true, stopRemoveBodyEvent : true }"></js-input-autocomplete>
                        <small translate="issue.setUpUsersParticipatingInProject">프로젝트에 참여하는 사용자를 설정합니다.</small>
                        <div class="select3-selection__choicediv">
                            <span class="select3-selection__choice" ng-repeat="user in vm.form.users">
                                <span class="avatar-w"><img ng-src="{{user.profile}}"></span>
@@ -158,10 +157,10 @@
                            </span>
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="issueAddForm5" class="issue-label"> <span translate="common.period">기간</span>
                        </label>
                        <label for="issueAddForm5" class="issue-label"> <span translate="common.period">기간</span></label>
                        <input id="issueAddForm5"
                               tabindex="-1"
                               type="text"
@@ -179,7 +178,8 @@
                            </div>
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label class="issue-label"><span translate="common.attachFiles">파일 첨부</span></label>
                        <div class="filebox input-group">
@@ -196,9 +196,6 @@
                                   multiple
                                   ng-file-select="fn.onFileSelect($files)">
                        </div>
                        <small translate="issue.attachOnlyFiles">hwp, jpg, png, txt, pptx, ppt, pdf, xlsx, xls, docx,
                            zip, gif, jpeg, doc, tif, bmp, wmv, avi, mp4, mkv, mov 파일만 첨부할 수 있습니다.
                        </small>
                        <div class="select2-selection__choicediv">
                            <div class="select2-selection__choice2" ng-repeat="file in vm.form.files">
@@ -230,59 +227,335 @@
                        </div>
                    </div>
                </div>
            </div>
                <div class="col-lg-8 bdl1">
                    <div class="row">
                        <div class="col-md-12">
                            <div class="form-group mgb5" ng-show="vm.form.issueCustomFields.length < 1">
                                <label class="issue-label" translate="issue.notIssueTypeCustomFields">이슈 타입에 연결된 사용자 정의
                                    필드가 없습니다.</label>
            <div class="row">
                <div class="col-lg-4 fontcolor_green">
                    <label class="issue-label"><span class="fontcolor_green" translate="common.detectingInfo">탐지정보</span></label>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="detectingDateAddForm" class="issue-label"> <span translate="common.detectingData">탐지일시</span> </label>
                        <input id="detectingDateAddForm"
                               tabindex="-1"
                               type="text"
                               readonly
                               class="form-control cursor"
                               placeholder="{{'issue.clickToSelectDate' | translate}}"
                               ng-model="vm.form.startCompleteDateRange"
                               modal-form-auto-scroll
                               date-format="YYYY-MM-DD"
                               parent-el="'#createdWidget2'"
                               date-range-picker>
                        <div class="row">
                            <div class="col-xs-12">
                                <div id="createdWidget2" class="bootstrap-datepicker"></div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="domainAddForm" class="issue-label"><span translate="companyField.domain">도메인</span></label>
                        <input id="domainAddForm"
                               name="domain"
                               type="text"
                               class="form-control"
                               kr-input
                               input-regex="[^a-zA-Z0-9 가-힣ㄱ-ㅎㅏ-ㅣ\u318D\u119E\u11A2\u2022\u2025a\u00B7\uFE55]"
                               autocomplete="off"
                               ng-model="vm.form.domain"
                               ng-maxlength="200"
                               maxlength="200">
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="ipAdressAddForm" class="issue-label"><span translate="companyField.ipAdress">ip주소</span></label>
                        <input id="ipAdressAddForm"
                               name="ipAdress"
                               type="text"
                               class="form-control"
                               kr-input
                               input-regex="[^a-zA-Z0-9 가-힣ㄱ-ㅎㅏ-ㅣ\u318D\u119E\u11A2\u2022\u2025a\u00B7\uFE55]"
                               autocomplete="off"
                               ng-model="vm.form.ipAdress"
                               ng-maxlength="200"
                               maxlength="200">
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-4 fontcolor_green">
                    <label class="issue-label"><span class="fontcolor_green" translate="companyField.info">업체정보</span></label>
                    <button class="btn btn-sm col-lg-6 btn-indigo" ng-click="fn.companyImport()">
                        &nbsp; &nbsp;  <span translate="common.import">가져오기</span> &nbsp; &nbsp;
                    </button>
                </div>
            </div>
                        <div class="col-md-6" ng-repeat="issueCustomField in vm.form.issueCustomFields">
                            <div class="form-group mgb5">
                                <label class="issue-label">{{issueCustomField.customFieldVo.name}}</label>
                                <div ng-switch on="issueCustomField.customFieldVo.customFieldType">
                                    <!-- 기본 입력 -->
                                    <div ng-switch-when="INPUT">
                                        <input type="text" class="form-control input-sm"
                                               ng-model="issueCustomField.useValues"
                                               maxlength="100"
                                               autocomplete="off"
                                               kr-input
                                               ng-required="issueCustomField.fieldOption == '01'">
                                    </div>
                                    <!-- 단일 셀렉트 -->
                                    <div ng-switch-when="SINGLE_SELECT">
                                        <select class="form-control input-sm issue-select-label"
                                                ng-required="issueCustomField.fieldOption == '01'"
                                                ng-model="issueCustomField.useValues">
                                            <option value="" value="" translate="common.choose">선택하세요.</option>
                                            <option ng-repeat="customFieldValueVo in issueCustomField.customFieldVo.customFieldValueVos"
                                                    value="{{customFieldValueVo.value}}"
                                                    ng-selected="$root.selectOption(issueCustomField.useValues, customFieldValueVo.value)">
                                                {{customFieldValueVo.value}}
                                            </option>
                                        </select>
                                    </div>
                                    <!-- 멀티 셀렉트 -->
                                    <div ng-switch-when="MULTI_SELECT">
                                        <ng-dropdown-multiselect class="multiSelect cursor"
                                                                 data-input-name=""
                                                                 modal-form-auto-scroll
                                                                 selected-model="issueCustomField.useValues"
                                                                 extra-settings="{ 'idProp' : 'value', 'externalIdProp' : 'value', 'displayProp' : 'value', 'stringTypeOption' : 'true', stopRemoveBodyEvent : true }"
                                                                 options="issueCustomField.customFieldVo.customFieldValueVos"></ng-dropdown-multiselect>
                                    </div>
                                </div>
                            </div>
            <div class="row">
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="companyFieldNameAddForm" class="issue-label"> <span translate="companyField.name">업체명</span> </label>
                        <input id="companyFieldNameAddForm"
                               name="companyName"
                               type="text"
                               class="form-control"
                               autofocus
                               kr-input
                               input-regex="[^a-zA-Z0-9 가-힣ㄱ-ㅎㅏ-ㅣ\u318D\u119E\u11A2\u2022\u2025a\u00B7\uFE55]"
                               autocomplete="off"
                               ng-model="vm.form.companyName"
                               ng-maxlength="100"
                               maxlength="100"
                               required>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="companyFieldManagerAddForm" class="issue-label"><span translate="companyField.manager">담당자</span></label>
                        <input id="companyFieldManagerAddForm"
                               name="companyManager"
                               type="text"
                               class="form-control"
                               autofocus
                               kr-input
                               input-regex="[^a-zA-Z0-9 가-힣ㄱ-ㅎㅏ-ㅣ\u318D\u119E\u11A2\u2022\u2025a\u00B7\uFE55]"
                               autocomplete="off"
                               ng-model="vm.form.companyManager"
                               ng-maxlength="100"
                               maxlength="100"
                               required>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="companyFieldTelAddForm" class="issue-label"><span translate="companyField.tel">전화번호</span></label>
                        <input id="companyFieldTelAddForm"
                               name="companyTel"
                               type="text"
                               class="form-control"
                               kr-input
                               ng-pattern="/^\d{2,3}-\d{3,4}-\d{4}$/"
                               autocomplete="off"
                               ng-model="vm.form.companyTel"
                               maxlength="20">
                        <div ng-show="issueAddForm.companyTel.$error.pattern" class="help-block form-text text-danger"
                             translate="companyField.invalidTelFormat">전화번호 형식이 맞지 않습니다. xxx-xxx-xxxx 형식으로 입력하세요.
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="companyFieldEmailAddForm" class="issue-label"><span translate="companyField.email">이메일</span></label>
                        <input id="companyFieldEmailAddForm"
                               name="companyEmail"
                               type="email"
                               class="form-control"
                               autocomplete="off"
                               maxLength="50"
                               ng-model="vm.form.companyEmail"
                               kr-input
                               ng-pattern="/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/">
                        <div ng-show="issueAddForm.companyEmail.$error.pattern" class="help-block form-text text-danger"
                             translate="users.invalidEmailFormat">이메일 형식이 맞지 않습니다.
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="companyFieldDescAddForm" class="issue-label"><span translate="companyField.desc">비고</span></label>
                        <input id="companyFieldDescAddForm"
                               name="companyDesc"
                               type="text"
                               class="form-control"
                               kr-input
                               autocomplete="off"
                               ng-model="vm.form.companyDesc"
                               ng-maxlength="200"
                               maxlength="200">
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-4 fontcolor_green">
                    <label class="issue-label"><span class="fontcolor_green" translate="ispField.info">ISP 정보</span></label>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="ispFieldNameAddForm" class="issue-label"> <span translate="ispField.name">ISP 이름</span> </label>
                        <input id="ispFieldNameAddForm"
                               name=ispName"
                               type="text"
                               class="form-control"
                               autofocus
                               kr-input
                               input-regex="[^a-zA-Z0-9 가-힣ㄱ-ㅎㅏ-ㅣ\u318D\u119E\u11A2\u2022\u2025a\u00B7\uFE55]"
                               autocomplete="off"
                               ng-model="vm.form.ispName"
                               ng-maxlength="100"
                               maxlength="100"
                               required>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="ispFieldManagerAddForm" class="issue-label"><span translate="ispField.manager">담당자</span></label>
                        <input id="ispFieldManagerAddForm"
                               name="ispManager"
                               type="text"
                               class="form-control"
                               kr-input
                               input-regex="[^a-zA-Z0-9 가-힣ㄱ-ㅎㅏ-ㅣ\u318D\u119E\u11A2\u2022\u2025a\u00B7\uFE55]"
                               autocomplete="off"
                               ng-model="vm.form.ispManager"
                               ng-maxlength="100"
                               maxlength="100">
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="ispFieldTelAddForm" class="issue-label"><span translate="ispField.tel">전화번호</span></label>
                        <input id="ispFieldTelAddForm"
                               name="ispTel"
                               type="text"
                               class="form-control"
                               kr-input
                               ng-pattern="/^\d{2,3}-\d{3,4}-\d{4}$/"
                               autocomplete="off"
                               ng-model="vm.form.ispTel"
                               maxlength="20">
                        <div ng-show="issueAddForm.ispTel.$error.pattern" class="help-block form-text text-danger"
                             translate="companyField.invalidTelFormat">전화번호 형식이 맞지 않습니다. xxx-xxx-xxxx 형식으로 입력하세요.
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="ispFieldEmailAddForm" class="issue-label"><span translate="ispField.email">이메일</span></label>
                        <input id="ispFieldEmailAddForm"
                               name="ispEmail"
                               type="email"
                               class="form-control"
                               autocomplete="off"
                               maxLength="50"
                               ng-model="vm.form.ispEmail"
                               kr-input
                               ng-pattern="/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/">
                        <div ng-show="issueAddForm.ispEmail.$error.pattern" class="help-block form-text text-danger"
                             translate="users.invalidEmailFormat">이메일 형식이 맞지 않습니다.
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="ispFieldDescAddForm" class="issue-label"><span translate="ispField.desc">비고</span></label>
                        <input id="ispFieldDescAddForm"
                               name="ispDesc"
                               type="text"
                               class="form-control"
                               kr-input
                               autocomplete="off"
                               ng-model="vm.form.ispDesc"
                               ng-maxlength="200"
                               maxlength="200">
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-4 fontcolor_green">
                    <label class="issue-label"><span class="fontcolor_green" translate="hostingField.info">호스팅 정보</span></label>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="hostingFieldNameAdd" class="issue-label"> <span translate="hostingField.name">호스팅 이름</span> </label>
                        <input id="hostingFieldNameAdd"
                               name="hostingName"
                               type="text"
                               class="form-control"
                               autofocus
                               kr-input
                               input-regex="[^a-zA-Z0-9 가-힣ㄱ-ㅎㅏ-ㅣ\u318D\u119E\u11A2\u2022\u2025a\u00B7\uFE55]"
                               autocomplete="off"
                               ng-model="vm.form.hostingName"
                               ng-maxlength="100"
                               maxlength="100"
                               required>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mb10">
                        <label for="hostingFieldManagerAdd" class="issue-label"><span translate="hostingField.manager">담당자</span></label>
                        <input id="hostingFieldManagerAdd"
                               name="hostingManager"
                               type="text"
                               class="form-control"
                               kr-input
                               input-regex="[^a-zA-Z0-9 가-힣ㄱ-ㅎㅏ-ㅣ\u318D\u119E\u11A2\u2022\u2025a\u00B7\uFE55]"
                               autocomplete="off"
                               ng-model="vm.form.hostingManager"
                               ng-maxlength="100"
                               maxlength="100">
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="hostingFieldTelAdd" class="issue-label"><span translate="hostingField.tel">전화번호</span></label>
                        <input id="hostingFieldTelAdd"
                               name="hostingTel"
                               type="text"
                               class="form-control"
                               kr-input
                               ng-pattern="/^\d{2,3}-\d{3,4}-\d{4}$/"
                               autocomplete="off"
                               ng-model="vm.form.hostingTel"
                               maxlength="20">
                        <div ng-show="issueAddForm.hostingTel.$error.pattern" class="help-block form-text text-danger"
                             translate="companyField.invalidTelFormat">전화번호 형식이 맞지 않습니다. xxx-xxx-xxxx 형식으로 입력하세요.
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="hostingFieldEmailAdd" class="issue-label"><span translate="hostingField.email">이메일</span></label>
                        <input id="hostingFieldEmailAdd"
                               name="hostingEmail"
                               type="email"
                               class="form-control"
                               autocomplete="off"
                               maxLength="50"
                               ng-model="vm.form.hostingEmail"
                               kr-input
                               ng-pattern="/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/">
                        <div ng-show="issueAddForm.hostingEmail.$error.pattern" class="help-block form-text text-danger"
                             translate="users.invalidEmailFormat">이메일 형식이 맞지 않습니다.
                        </div>
                    </div>
                </div>
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label for="hostingFieldDescAdd" class="issue-label"><span translate="hostingField.desc">비고</span></label>
                        <input id="hostingFieldDescAdd"
                               name="hostingDesc"
                               type="text"
                               class="form-control"
                               kr-input
                               autocomplete="off"
                               ng-model="vm.form.hostingDesc"
                               ng-maxlength="200"
                               maxlength="200">
                    </div>
                </div>
            </div>
        </form>
    </div>
src/main/webapp/views/issue/issueCompanyFieldDetail.html
New file
@@ -0,0 +1,37 @@
<div class="formModal">
    <div class="modal-header faded smaller">
        <div class="modal-title">
            <strong>업체 정보</strong>
        </div>
        <button aria-label="Close" class="close" type="button" ng-click="fn.cancel()">
            <span aria-hidden="true"> &times;</span>
        </button>
    </div>
    <div class="modal-body">
        <form role="form" name="companyFieldImportForm">
            <div class="form-group">
                <label><span translate="companyField.name">업체 이름</span>
                       <code class="highlighter-rouge">*</code></label>
                <js-autocomplete-single data-input-name="companyField"
                                        selected-model="vm.form.companyFields"
                                        search="vm.companyName"
                                        source="fn.getCompanyFieldList(vm.companyName, vm.form.companyFields, vm.autoCompletePage.companyField.page, fn.getCompanyFieldListCallBack)"
                                        page="vm.autoCompletePage.companyField.page"
                                        total-page="vm.autoCompletePage.companyField.totalPage"
                                        input-disabled="false"
                                        extra-settings="{ displayProp : 'name' , idProp : 'id', imageable : false, imagePathProp : '',
                                                type : '', maxlength : 200, autoResize : false, stopRemoveBodyEvent : true }"></js-autocomplete-single>
            </div>
            <div class="modal-footer buttons-on-right">
                <button type="button" class="btn btn-md btn-grey" ng-click="fn.cancel()"><span translate="common.cancel">취소</span></button>
                <button type="button" class="btn btn-md btn-primary bold"
                        js-short-cut
                        js-short-cut-action="(fn.formCheck(companyFieldModifyForm.$invalid) || $root.spinner) ? null : fn.formSubmit()"
                        ng-disabled="fn.formCheck(companyFieldImportForm.$invalid)"
                        ng-click="fn.formSubmit()"><span translate="common.save">저장</span>
                </button>
            </div>
        </form>
    </div>
</div>
src/main/webapp/views/issue/issueDetail.html
@@ -207,7 +207,7 @@
                <div class="row">
                    <div class="col-xxl-12">
                        <div class="form-group">
                            <label class="issue-detail-label"><span translate="common.assignee">담당자</span> </label>
                            <label class="issue-detail-label"><span translate="common.assigneeTeam">담당부서</span> </label>
                            <div class="">
                                <div class="select3-selection__choicediv">
                                    <span class="select3-selection__choice" ng-repeat="user in vm.viewer.userVos">
src/main/webapp/views/issue/issueListNormal.html
@@ -185,7 +185,7 @@
                                            <div class="col-lg-3">
                                                <div class="form-group">
                                                    <label> <span translate="common.assignee">담당자</span></label>
                                                    <label> <span translate="common.assigneeTeam">담당부서</span></label>
                                                    <js-autocomplete-multi data-input-name="users"
                                                                           selected-model="vm.users"
                                                                           search="vm.userName"
src/main/webapp/views/issue/issueListTimeline.html
@@ -184,7 +184,7 @@
                                            <div class="col-lg-3">
                                                <div class="form-group">
                                                    <label> <span translate="common.assignee">담당자</span></label>
                                                    <label> <span translate="common.assigneeTeam">담당부서</span></label>
                                                    <js-autocomplete-multi data-input-name="users"
                                                                           selected-model="vm.users"
                                                                           search="vm.userName"
src/main/webapp/views/issue/issueModify.html
@@ -138,7 +138,7 @@
            <div class="row">
                <div class="col-lg-4">
                    <div class="form-group mgb5">
                        <label class="issue-label"> <span translate="common.assignee">담당자</span> </label>
                        <label class="issue-label"> <span translate="common.assigneeTeam">담당부서</span> </label>
                        <js-input-autocomplete data-input-name="users"
                                               selected-model="vm.form.users"
                                               search="vm.userName"
src/main/webapp/views/issue/issueModifyUser.html
@@ -12,7 +12,7 @@
        <form role="form" name="issueUserModifyForm">
            <div class="form-group">
                <div class="form-group mgb5">
                    <label class="issue-label"> <span translate="common.assignee">담당자</span> </label>
                    <label class="issue-label"> <span translate="common.assigneeTeam">담당부서</span> </label>
                    <js-input-autocomplete data-input-name="users"
                                           selected-model="vm.form.users"
                                           search="vm.userName"