OWL ITS + 탐지시스템(인터넷 진흥원)
wyu
2022-01-06 7b3861cb48507674af980e5579f61a853d093ed8
하위이슈목록/연관이슈목록 모든 컬럼 정렬 (기간 제외) 수정
8개 파일 추가됨
8개 파일 변경됨
1398 ■■■■ 파일 변경됨
src/main/webapp/custom_components/js-down/down.provider.js 232 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-down/downColumnGenerator.directive.js 141 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-down/js-down.directive.js 36 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-down/js-down.html 47 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-rel/js-rel.directive.js 36 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-rel/js-rel.html 47 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-rel/rel.provider.js 239 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-rel/relColumnGenerator.directive.js 142 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js 234 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issue.js 2 ●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueDetail.controller.js 186 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/app/issue/issueList.controller.js 5 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/components/auth/auth.interceptor.js 10 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/config.js 11 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/scripts/main.js 22 ●●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/views/issue/issueDetail.html 8 ●●●● 패치 | 보기 | raw | blame | 히스토리
src/main/webapp/custom_components/js-down/down.provider.js
New file
@@ -0,0 +1,232 @@
'use strict';
define(['app', 'angular'],
    function (app, angular) {
        app.provider("$downProvider", function () {
            return {
                $get : function ($log) {
                    return {
                        config : function () {
                            var tableConfig = {
                                hName : "",    //    헤더 이름
                                hWidth : "",    //    칼럼 길이
                                hChecked : false,    //    체크 박스 선택 여부
                                hAlign : "text-center",    //    헤더 정렬 기준
                                hSort : true,    //    정렬 가능 여부
                                dName : "",    //    데이터 이름
                                dAlign : "text-left",    //    데이터 정렬 기준
                                dRenderer : "",    //    렌더러 여부
                                dVisible : "",  //      bootstrap 반응형 컬럼 표시 여부
                                dType : "none",        // 태그 타입
                                dDateFormat : "",   //  날짜 형식
                                rowSpan : 0,    //  rowspan 을 지원한다.
                                colSpan : 0,    //  colspan 을 지원한다.
                                subHead : false,    //  만약 rowspan, colspan 을 사용하게 되면 true 로 셋팅.
                                columnHint : "",    //  컬럼 정보를 추출하기 위한 힌트 정보를 준다 - downColumnGenerator 의 사용자 정의 필드 부분에서 사용
                                columnTooltip : "", // hover 시 툴팁 보여주기
                                setHName : function (hName) {
                                    this.hName = hName;
                                    return this;
                                },
                                setHWidth : function (hWidth) {
                                    this.hWidth = hWidth;
                                    return this;
                                },
                                setHChecked : function (hChecked) {
                                    this.hChecked = hChecked;
                                    return this;
                                },
                                setHAlign : function (hAlign) {
                                    this.hAlign = hAlign;
                                    return this;
                                },
                                setHSort : function (hSort) {
                                    this.hSort = hSort;
                                    return this;
                                },
                                setDName : function (dName) {
                                    this.dName = dName;
                                    return this;
                                },
                                setDAlign : function (dAlign) {
                                    this.dAlign = dAlign;
                                    return this;
                                },
                                setDRenderer : function (dRenderer) {
                                    this.dRenderer = dRenderer;
                                    return this;
                                },
                                setDVisible : function (dVisible) {
                                    this.dVisible = dVisible;
                                    return this;
                                },
                                setDType : function (dType) {
                                    this.dType = dType;
                                    return this;
                                },
                                setDDateFormat : function (dDateFormat) {
                                    this.dDateFormat = dDateFormat;
                                    return this;
                                },
                                setRowSpan : function (dRowSpan) {
                                    this.rowSpan = dRowSpan;
                                    return this;
                                },
                                setColSpan : function (dColSpan) {
                                    this.colSpan = dColSpan;
                                    return this;
                                },
                                setSubHead : function (dSubHead) {
                                    this.subHead = dSubHead;
                                    return this;
                                },
                                setColumnHint : function (dColumnHint) {
                                    this.columnHint = dColumnHint;
                                    return this;
                                },
                                setColumnTooltip : function (hTooltip) {
                                    this.columnTooltip = hTooltip;
                                    return this;
                                }
                            };
                            return tableConfig;
                        },
                        toggleChecked : function (checkStatus, datas) {
                            //  전체 선택 체크 박스를 클릭했을 경우
                            angular.forEach(datas, function (data) {
                                data.checked = checkStatus;
                            });
                        },
                        radioChecked : function (target, datas) {
                            //  해당 row 가 라디오 버튼일 경우
                            angular.forEach(datas, function (data) {
                                if (target.id == data.id) {
                                    data.checked = true;
                                }
                                else {
                                    data.checked = false;
                                }
                            });
                        },
                        rowChecked : function (tableConfig, target, datas) {
                            //  각 row 의 체크박스/라디오 버튼을 클릭했을 경우
                            if (tableConfig[0].dType == "checkbox") {
                                target.checked = !target.checked;
                                for (var data in datas) {
                                    if (!data.checked) {
                                        this.hChecked = false;
                                        break;
                                    }
                                }
                            }
                            else if (tableConfig[0].dType == "radio") {
                                this.radioChecked(target, datas);
                            }
                        },
                        orderByColumn : "",  // table order By column name
                        reverse : true,
                        setOrderByColumn : function (column) {
                            if (column == "") {
                                return;
                            }
                            if (this.orderByColumn == column) {
                                this.reverse = !this.reverse;
                            }
                            else {
                                this.reverse = true;
                            }
                            this.orderByColumn = column;
                            return this;
                        },
                        getDateFormat : function (formatType, date) {
                            if (formatType == "" || formatType == null) {
                                formatType = "01";
                            }
                            Date.prototype.format = function (f) {
                                if (!this.valueOf()) {
                                    return " ";
                                }
                                var weekName = ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"];
                                var d = this;
                                return f.replace(/(yyyy|yy|MM|dd|E|hh|mm|ss|a\/p)/gi, function ($1) {
                                    switch ($1) {
                                        case "yyyy":
                                            return d.getFullYear();
                                        case "yy":
                                            return (d.getFullYear() % 1000).zf(2);
                                        case "MM":
                                            return (d.getMonth() + 1).zf(2);
                                        case "dd":
                                            return d.getDate().zf(2);
                                        case "E":
                                            return weekName[d.getDay()];
                                        case "HH":
                                            return d.getHours().zf(2);
                                        case "hh":
                                            var h = d.getHours();
                                            return ((h = d.getHours() % 12) ? h : 12).zf(2);
                                        case "mm":
                                            return d.getMinutes().zf(2);
                                        case "ss":
                                            return d.getSeconds().zf(2);
                                        case "a/p":
                                            return d.getHours() < 12 ? "오전" : "오후";
                                        default:
                                            return $1;
                                    }
                                });
                            };
                            String.prototype.string = function (len) {
                                var s = '', i = 0;
                                while (i++ < len) {
                                    s += this;
                                }
                                return s;
                            };
                            String.prototype.zf = function (len) {
                                return "0".string(len - this.length) + this;
                            };
                            Number.prototype.zf = function (len) {
                                return this.toString().zf(len);
                            };
                            var dateFormat = "";
                            var dynamicTime = false;
                            var today = new Date().format("yyyy-MM-dd");
                            var compareDate = new Date(date).format("yyyy-MM-dd");
                            if (today == compareDate) {
                                dynamicTime = true;
                            }
                            switch (formatType) {
                                case "01":  //  날짜
                                    dateFormat = "yyyy-MM-dd";
                                    break;
                                case "02":  //  날짜 + 시간
                                    dateFormat = "yyyy-MM-dd HH:mm";
                                    break;
                                case "03":  //  유동적 표시
                                    if (dynamicTime) {
                                        dateFormat = "HH:mm";
                                    }
                                    else {
                                        dateFormat = "yyyy-MM-dd HH:mm";
                                    }
                                    break;
                            }
                            return dateFormat;
                        }
                    }
                }
            }
        });
    });
src/main/webapp/custom_components/js-down/downColumnGenerator.directive.js
New file
@@ -0,0 +1,141 @@
'use strict';
define(['app', 'angular'],
    function (app, angular) {
        app.directive('downColumnGenerator', ['$compile', '$log', '$rootScope', '$downProvider', '$filter',
            function ($compile, $log, $rootScope, $downProvider, $filter) {
                return {
                    restrict : "A",
                    compile : function (tElement, tAttrs) {
                        return function (scope, element, attrs) {
                            scope.data = scope[attrs["downColumnGenerator"]];
                            var myData = scope.data;
                            var makeTag = "";
                            scope.tableConfigs.forEach(function (tableConfig, index) {
                                if (tableConfig.colSpan > 0) {
                                    return;
                                }
                                // 하위 단계 표시 추가
                                var myToken = "";
                                if ( scope.data.depth > 0)  {
                                    for(var i=0; i<scope.data.depth; i++) {
                                        if (i == scope.data.depth - 1) {
                                            myToken += treeStartToken;
                                        } else {
                                            myToken += "&emsp;";
                                        }
                                    }
                                    myToken += "&nbsp;";
                                }
                                makeTag = '<td class="' + tableConfig.dAlign + ' ' + tableConfig.dVisible + '">';
                                if (tableConfig.dType === "checkbox") {
                                    //  체크 박스일때
                                    /*if (scope.data.defaultYn) {
                                        makeTag += '<input type="checkbox" ng-checked="data.checked == true ? true : false" disabled ng-click="$root.$downProvider.rowChecked(tableConfigs, data, fn.getResponseData())">';
                                    }
                                    else {*/
                                    makeTag += '<input type="checkbox" ng-checked="data.checked == true ? true : false" ng-click="$root.$downProvider.rowChecked(tableConfigs, data, fn.getResponseData())">';
                                    //}
                                    tableConfig.hChecked = false;
                                }
                                else if (tableConfig.dType === "radio") {
                                    //  라디오 버튼일때
                                    makeTag += '<input type="radio" ng-checked="data.checked == true ? true : false" ng-click="$root.$downProvider.rowChecked(tableConfigs, data, fn.getResponseData())">';
                                }
                                else if (tableConfig.dType === "renderer") {
                                    //  랜더러 일때
                                    switch (tableConfig.dRenderer) {
                                        // 하위 이슈 이동(제목)
                                        case "ISSUE_DOWN_MOVE" :
                                            makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data)\">" + scope.data.title + "</span></a>";
                                            break;
                                        // 하위 이슈 타입
                                        case "ISSUE_DOWN_STATUS_TYPE" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.issueStatusVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.issueStatusVo.color + "\", \"color\": \"#FFFFFF\" }'>" + scope.data.issueStatusVo.name + "</span>";
                                            break;
                                        // 하위 이슈 삭제
                                        case "ISSUE_DOWN_DELETE":
                                            if (scope.data.modifyPermissionCheck) {
                                                makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeDownIssue(data.id)">';
                                            }
                                            break;
                                        // 하위 이슈 우선 순위
                                        case "DOWN_COMMON_PRIORITY" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>";
                                            break;
                                        // 하위 이슈 중요도
                                        case "DOWN_COMMON_SEVERITY" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>";
                                            break;
                                        // 하위 이슈 담당부서
                                        case "DOWN_ISSUE_DEPARTMENT" :
                                            makeTag += "<ul class='ul-not-comma'>";
                                            makeTag += "<div style='color: #000000'>";
                                            angular.forEach(scope.data.departmentVos, function (departments) {
                                                makeTag += "<li>" + departments.departmentName + "</li>";
                                            });
                                            makeTag += "</div>";
                                            makeTag += "</ul>";
                                            break;
                                        // 하위 이슈 등록자
                                        case "DOWN_REGISTER":
                                            scope.data.registerVos = [scope.data.registerVo];
                                            makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>';
                                            break;
                                        // 하위 이슈 기간
                                        case "DOWN_ISSUE_DUE_DATE" :
                                            if (!$rootScope.isDefined(scope.data.startDate) && !$rootScope.isDefined(scope.data.completeDate)) {
                                                makeTag += "<span translate='common.noDate'>기간 없음</span>";
                                            }
                                            else {
                                                makeTag += "<span>" + scope.data.startDate + " ~ " + scope.data.completeDate + "</span>";
                                            }
                                            break;
                                        // 하위 이슈 사용자 정의 필드
                                        case "DOWN_ISSUE_CUSTOM_FIELD_VALUE_VIEW" :
                                            var values = [];
                                            for (var count in scope.data.issueCustomFieldValueVos) {
                                                var issueCustomFieldValueVo = scope.data.issueCustomFieldValueVos[count];
                                                //  테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다.
                                                if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) {
                                                    values.push(issueCustomFieldValueVo.useValue);
                                                }
                                            }
                                            angular.forEach(values, function (value) {
                                                makeTag += '<span class="table-word-break-all">' + value + '<span><br>';
                                            });
                                            break;
                                    }
                                }
                                makeTag += '</td>';
                                var linkFn = $compile(makeTag);
                                var content = linkFn(scope);
                                element.append(content);
                            });
                        }
                    }
                }
        }]);
    });
src/main/webapp/custom_components/js-down/js-down.directive.js
New file
@@ -0,0 +1,36 @@
'use strict';
define(['app'],
    function (app) {
        app.directive('jsDown', ['$log',
            function ($log) {
                return {
                    restrict : 'E',
                    scope : {
                        event : '=',
                        data : '=',
                        tableConfigs : '=',
                        hideHeader : '=', // 헤더 부분 숨김 여부
                        useSort : '=', // 정령 기능 사용 여부
                        detailView : "="    //  이슈 목록 상세형 변경을 위해 사용. 다른 화면은 사용하지 않음.
                    },
                    replace : true,
                    templateUrl : '/custom_components/js-down/js-down.html',
                    controller : function ($scope, $element, $attrs) {
                        $scope.fn = {
                            getResponseData : getResponseData
                        };
                        //  테이블 정보 가져오기
                        function getResponseData() {
                            return $scope.data;
                        }
                    },
                    link : function (scope, element, attrs) {
                    }
                };
            }])
    });
src/main/webapp/custom_components/js-down/js-down.html
New file
@@ -0,0 +1,47 @@
<table class="table table-striped table-layout-fixed" ng-class="{ 'width768' : !detailView }" bindonce>
    <!-- 테이블 머리 -->
    <thead>
    <tr ng-if="hideHeader != true">
        <th bindonce ng-repeat="tableConfig in tableConfigs"
            bo-class="[tableConfig.hAlign, tableConfig.hWidth, tableConfig.dVisible]"
            ng-click="$root.$downProvider.setOrderByColumn(tableConfig.dName)"
            bo-style="{ 'cursor' : tableConfig.dName != '' ? 'pointer' : '' }"
            rowspan="{{tableConfig.rowSpan}}"
            colspan="{{tableConfig.colSpan}}"
            ng-if="!tableConfig.subHead">
            <!-- 체크 박스일 경우 -->
            <div bo-switch="tableConfig.dType">
                <div bo-switch-when="checkbox">
                    <input type="checkbox" tabindex="-1" ng-model="tableConfig.hChecked" ng-click="$root.$downProvider.toggleChecked(tableConfig.hChecked, fn.getResponseData())">
                </div>
                <div bo-switch-default>
                    <span ng-if="tableConfig.columnTooltip != ''" function-tool-tip data-placement="top" data-toggle="tooltip" data-original-title="{{tableConfig.columnTooltip}}"
                          translate="{{tableConfig.hName}}"></span>
                    <span ng-if="tableConfig.columnTooltip == ''" translate="{{tableConfig.hName}}"></span>
                    <span ng-if="($root.$downProvider.orderByColumn == tableConfig.dName) && (tableConfig.dName != '')"><i class="fa fa-arrow-circle-down" ng-show="!$root.$downProvider.reverse"></i>
                        <i class="fa fa-arrow-circle-up" ng-show="$root.$downProvider.reverse"></i>
                    </span>
                </div>
            </div>
        </th>
    </tr>
    </thead>
    <tbody>
    <tr ng-if="useSort != false" ng-repeat="row in fn.getResponseData() | orderBy:$root.$downProvider.orderByColumn:$root.$downProvider.reverse"
        bo-class="[row.checked == true ? 'table-active' : '', tableConfig.hWidth]"
        down-column-generator="row">
    </tr>
    <tr ng-if="useSort == false" ng-repeat="row in fn.getResponseData()"
        bo-class="[row.checked == true ? 'table-active' : '', tableConfig.hWidth]"
        down-column-generator="row">
    </tr>
    <tr ng-if="fn.getResponseData().length == 0">
        <td colspan="{{tableConfigs.length}}">
            <span translate="common.noData">데이터가 없습니다.</span>
        </td>
    </tr>
    </tbody>
</table>
src/main/webapp/custom_components/js-rel/js-rel.directive.js
New file
@@ -0,0 +1,36 @@
'use strict';
define(['app'],
    function (app) {
        app.directive('jsRel', ['$log',
            function ($log) {
                return {
                    restrict : 'E',
                    scope : {
                        event : '=',
                        data : '=',
                        tableConfigs : '=',
                        hideHeader : '=', // 헤더 부분 숨김 여부
                        useSort : '=', // 정령 기능 사용 여부
                        detailView : "="    //  이슈 목록 상세형 변경을 위해 사용. 다른 화면은 사용하지 않음.
                    },
                    replace : true,
                    templateUrl : '/custom_components/js-rel/js-rel.html',
                    controller : function ($scope, $element, $attrs) {
                        $scope.fn = {
                            getResponseData : getResponseData
                        };
                        //  테이블 정보 가져오기
                        function getResponseData() {
                            return $scope.data;
                        }
                    },
                    link : function (scope, element, attrs) {
                    }
                };
            }])
    });
src/main/webapp/custom_components/js-rel/js-rel.html
New file
@@ -0,0 +1,47 @@
<table class="table table-striped table-layout-fixed" ng-class="{ 'width768' : !detailView }" bindonce>
    <!-- 테이블 머리 -->
    <thead>
    <tr ng-if="hideHeader != true">
        <th bindonce ng-repeat="tableConfig in tableConfigs"
            bo-class="[tableConfig.hAlign, tableConfig.hWidth, tableConfig.dVisible]"
            ng-click="$root.$relProvider.setOrderByColumn(tableConfig.dName)"
            bo-style="{ 'cursor' : tableConfig.dName != '' ? 'pointer' : '' }"
            rowspan="{{tableConfig.rowSpan}}"
            colspan="{{tableConfig.colSpan}}"
            ng-if="!tableConfig.subHead">
            <!-- 체크 박스일 경우 -->
            <div bo-switch="tableConfig.dType">
                <div bo-switch-when="checkbox">
                    <input type="checkbox" tabindex="-1" ng-model="tableConfig.hChecked" ng-click="$root.$relProvider.toggleChecked(tableConfig.hChecked, fn.getResponseData())">
                </div>
                <div bo-switch-default>
                    <span ng-if="tableConfig.columnTooltip != ''" function-tool-tip data-placement="top" data-toggle="tooltip" data-original-title="{{tableConfig.columnTooltip}}"
                          translate="{{tableConfig.hName}}"></span>
                    <span ng-if="tableConfig.columnTooltip == ''" translate="{{tableConfig.hName}}"></span>
                    <span ng-if="($root.$relProvider.orderByColumn == tableConfig.dName) && (tableConfig.dName != '')"><i class="fa fa-arrow-circle-down" ng-show="!$root.$relProvider.reverse"></i>
                        <i class="fa fa-arrow-circle-up" ng-show="$root.$relProvider.reverse"></i>
                    </span>
                </div>
            </div>
        </th>
    </tr>
    </thead>
    <tbody>
    <tr ng-if="useSort != false" ng-repeat="row in fn.getResponseData() | orderBy:$root.$relProvider.orderByColumn:$root.$relProvider.reverse"
        bo-class="[row.checked == true ? 'table-active' : '', tableConfig.hWidth]"
        rel-column-generator="row">
    </tr>
    <tr ng-if="useSort == false" ng-repeat="row in fn.getResponseData()"
        bo-class="[row.checked == true ? 'table-active' : '', tableConfig.hWidth]"
        rel-column-generator="row">
    </tr>
    <tr ng-if="fn.getResponseData().length == 0">
        <td colspan="{{tableConfigs.length}}">
            <span translate="common.noData">데이터가 없습니다.</span>
        </td>
    </tr>
    </tbody>
</table>
src/main/webapp/custom_components/js-rel/rel.provider.js
New file
@@ -0,0 +1,239 @@
'use strict';
define(['app', 'angular'],
    function (app, angular) {
        app.provider("$relProvider", function () {
            return {
                $get : function ($log) {
                    return {
                        config : function () {
                            var tableConfig = {
                                hName : "",    //    헤더 이름
                                hWidth : "",    //    칼럼 길이
                                hChecked : false,    //    체크 박스 선택 여부
                                hAlign : "text-center",    //    헤더 정렬 기준
                                hSort : true,    //    정렬 가능 여부
                                dName : "",    //    데이터 이름
                                dAlign : "text-left",    //    데이터 정렬 기준
                                dRenderer : "",    //    렌더러 여부
                                dVisible : "",  //      bootstrap 반응형 컬럼 표시 여부
                                dType : "none",        // 태그 타입
                                dDateFormat : "",   //  날짜 형식
                                rowSpan : 0,    //  rowspan 을 지원한다.
                                colSpan : 0,    //  colspan 을 지원한다.
                                subHead : false,    //  만약 rowspan, colspan 을 사용하게 되면 true 로 셋팅.
                                columnHint : "",    //  컬럼 정보를 추출하기 위한 힌트 정보를 준다 - relColumnGenerator 의 사용자 정의 필드 부분에서 사용
                                columnTooltip : "", // hover 시 툴팁 보여주기
                                setHName : function (hName) {
                                    this.hName = hName;
                                    return this;
                                },
                                setHWidth : function (hWidth) {
                                    this.hWidth = hWidth;
                                    return this;
                                },
                                setHChecked : function (hChecked) {
                                    this.hChecked = hChecked;
                                    return this;
                                },
                                setHAlign : function (hAlign) {
                                    this.hAlign = hAlign;
                                    return this;
                                },
                                setHSort : function (hSort) {
                                    this.hSort = hSort;
                                    return this;
                                },
                                setDName : function (dName) {
                                    this.dName = dName;
                                    return this;
                                },
                                setDAlign : function (dAlign) {
                                    this.dAlign = dAlign;
                                    return this;
                                },
                                setDRenderer : function (dRenderer) {
                                    this.dRenderer = dRenderer;
                                    return this;
                                },
                                setDVisible : function (dVisible) {
                                    this.dVisible = dVisible;
                                    return this;
                                },
                                setDType : function (dType) {
                                    this.dType = dType;
                                    return this;
                                },
                                setDDateFormat : function (dDateFormat) {
                                    this.dDateFormat = dDateFormat;
                                    return this;
                                },
                                setRowSpan : function (dRowSpan) {
                                    this.rowSpan = dRowSpan;
                                    return this;
                                },
                                setColSpan : function (dColSpan) {
                                    this.colSpan = dColSpan;
                                    return this;
                                },
                                setSubHead : function (dSubHead) {
                                    this.subHead = dSubHead;
                                    return this;
                                },
                                setColumnHint : function (dColumnHint) {
                                    this.columnHint = dColumnHint;
                                    return this;
                                },
                                setColumnTooltip : function (hTooltip) {
                                    this.columnTooltip = hTooltip;
                                    return this;
                                }
                            };
                            return tableConfig;
                        },
                        toggleChecked : function (checkStatus, datas) {
                            //  전체 선택 체크 박스를 클릭했을 경우
                            angular.forEach(datas, function (data) {
                                /*if (angular.isDefined(data.defaultYn)) {
                                    if (!data.defaultYn) {
                                        data.checked = checkStatus;
                                    }
                                }
                                else {*/
                                    data.checked = checkStatus;
                                //}
                            });
                        },
                        radioChecked : function (target, datas) {
                            //  해당 row 가 라디오 버튼일 경우
                            angular.forEach(datas, function (data) {
                                if (target.id == data.id) {
                                    data.checked = true;
                                }
                                else {
                                    data.checked = false;
                                }
                            });
                        },
                        rowChecked : function (tableConfig, target, datas) {
                            //  각 row 의 체크박스/라디오 버튼을 클릭했을 경우
                            if (tableConfig[0].dType == "checkbox") {
                                target.checked = !target.checked;
                                for (var data in datas) {
                                    if (!data.checked) {
                                        this.hChecked = false;
                                        break;
                                    }
                                }
                            }
                            else if (tableConfig[0].dType == "radio") {
                                this.radioChecked(target, datas);
                            }
                        },
                        orderByColumn : "",  // table order By column name
                        reverse : true,
                        setOrderByColumn : function (column) {
                            if (column == "") {
                                return;
                            }
                            if (this.orderByColumn == column) {
                                this.reverse = !this.reverse;
                            }
                            else {
                                this.reverse = true;
                            }
                            this.orderByColumn = column;
                            return this;
                        },
                        getDateFormat : function (formatType, date) {
                            if (formatType == "" || formatType == null) {
                                formatType = "01";
                            }
                            Date.prototype.format = function (f) {
                                if (!this.valueOf()) {
                                    return " ";
                                }
                                var weekName = ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"];
                                var d = this;
                                return f.replace(/(yyyy|yy|MM|dd|E|hh|mm|ss|a\/p)/gi, function ($1) {
                                    switch ($1) {
                                        case "yyyy":
                                            return d.getFullYear();
                                        case "yy":
                                            return (d.getFullYear() % 1000).zf(2);
                                        case "MM":
                                            return (d.getMonth() + 1).zf(2);
                                        case "dd":
                                            return d.getDate().zf(2);
                                        case "E":
                                            return weekName[d.getDay()];
                                        case "HH":
                                            return d.getHours().zf(2);
                                        case "hh":
                                            var h = d.getHours();
                                            return ((h = d.getHours() % 12) ? h : 12).zf(2);
                                        case "mm":
                                            return d.getMinutes().zf(2);
                                        case "ss":
                                            return d.getSeconds().zf(2);
                                        case "a/p":
                                            return d.getHours() < 12 ? "오전" : "오후";
                                        default:
                                            return $1;
                                    }
                                });
                            };
                            String.prototype.string = function (len) {
                                var s = '', i = 0;
                                while (i++ < len) {
                                    s += this;
                                }
                                return s;
                            };
                            String.prototype.zf = function (len) {
                                return "0".string(len - this.length) + this;
                            };
                            Number.prototype.zf = function (len) {
                                return this.toString().zf(len);
                            };
                            var dateFormat = "";
                            var dynamicTime = false;
                            var today = new Date().format("yyyy-MM-dd");
                            var compareDate = new Date(date).format("yyyy-MM-dd");
                            if (today == compareDate) {
                                dynamicTime = true;
                            }
                            switch (formatType) {
                                case "01":  //  날짜
                                    dateFormat = "yyyy-MM-dd";
                                    break;
                                case "02":  //  날짜 + 시간
                                    dateFormat = "yyyy-MM-dd HH:mm";
                                    break;
                                case "03":  //  유동적 표시
                                    if (dynamicTime) {
                                        dateFormat = "HH:mm";
                                    }
                                    else {
                                        dateFormat = "yyyy-MM-dd HH:mm";
                                    }
                                    break;
                            }
                            return dateFormat;
                        }
                    }
                }
            }
        });
    });
src/main/webapp/custom_components/js-rel/relColumnGenerator.directive.js
New file
@@ -0,0 +1,142 @@
'use strict';
define(['app', 'angular'],
    function (app, angular) {
        app.directive('relColumnGenerator', ['$compile', '$log', '$rootScope', '$relProvider', '$filter',
            function ($compile, $log, $rootScope, $relProvider, $filter) {
                return {
                    restrict : "A",
                    compile : function (tElement, tAttrs) {
                        return function (scope, element, attrs) {
                            scope.data = scope[attrs["relColumnGenerator"]];
                            var myData = scope.data;
                            var makeTag = "";
                            scope.tableConfigs.forEach(function (tableConfig, index) {
                                if (tableConfig.colSpan > 0) {
                                    return;
                                }
                                // 하위 단계 표시 추가
                                var myToken = "";
                                if ( scope.data.depth > 0)  {
                                    for(var i=0; i<scope.data.depth; i++) {
                                        if (i == scope.data.depth - 1) {
                                            myToken += treeStartToken;
                                        } else {
                                            myToken += "&emsp;";
                                        }
                                    }
                                    myToken += "&nbsp;";
                                }
                                makeTag = '<td class="' + tableConfig.dAlign + ' ' + tableConfig.dVisible + '">';
                                if (tableConfig.dType === "checkbox") {
                                    //  체크 박스일때
                                    /*if (scope.data.defaultYn) {
                                        makeTag += '<input type="checkbox" ng-checked="data.checked == true ? true : false" disabled ng-click="$root.$relProvider.rowChecked(tableConfigs, data, fn.getResponseData())">';
                                    }
                                    else {*/
                                    makeTag += '<input type="checkbox" ng-checked="data.checked == true ? true : false" ng-click="$root.$relProvider.rowChecked(tableConfigs, data, fn.getResponseData())">';
                                    //}
                                    tableConfig.hChecked = false;
                                }
                                else if (tableConfig.dType === "radio") {
                                    //  라디오 버튼일때
                                    makeTag += '<input type="radio" ng-checked="data.checked == true ? true : false" ng-click="$root.$relProvider.rowChecked(tableConfigs, data, fn.getResponseData())">';
                                }
                                else if (tableConfig.dType === "renderer") {
                                    //  랜더러 일때
                                    switch (tableConfig.dRenderer) {
                                        // 연관 이슈 이동(제목)
                                        case "ISSUE_RELATION_MOVE" :
                                            makeTag += "<span class=\"titlename cursor text-center\" ng-click=\"event.changeDetailView(data.issueRelation)\">" + scope.data.title + "</span></a>";
                                            break;
                                        // 연관이슈 구분
                                        case "ISSUE_RELATION_TYPE":
                                            makeTag += "<span>" + scope.data.relationIssueTypeName + "</span>";
                                            break;
                                        // 연관이슈 삭제
                                        case "ISSUE_RELATION_DELETE":
                                            if (scope.data.modifyPermissionCheck) {
                                                makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeRelationIssue(data.id)">';
                                            }
                                            break;
                                        // 연관 이슈 우선순위
                                        case "REL_COMMON_PRIORITY" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>";
                                            break;
                                        // 연관 이슈 중요도
                                        case "REL_COMMON_SEVERITY" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>";
                                            break;
                                        // 연관 이슈 등록자
                                        case "REL_REGISTER":
                                            scope.data.registerVos = [scope.data.issueRelation.registerVo];
                                            makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>';
                                            break;
                                            break;
                                        // 연관 이슈 담당부서
                                        case "REL_ISSUE_DEPARTMENT" :
                                            makeTag += "<ul class='ul-not-comma'>";
                                            makeTag += "<div style='color: #000000'>";
                                            angular.forEach(scope.data.issueRelation.departmentVos, function (departments) {
                                                makeTag += "<li>" + departments.departmentName + "</li>";
                                            });
                                            makeTag += "</div>";
                                            makeTag += "</ul>";
                                            break;
                                        // 연관 이슈 목록에서 기간 표시
                                        case "REL_ISSUE_DUE_DATE" :
                                            if (!$rootScope.isDefined(scope.data.issueRelation.startDate) && !$rootScope.isDefined(scope.data.issueRelation.completeDate)) {
                                                makeTag += "<span translate='common.noDate'>기간 없음</span>";
                                            } else {
                                                makeTag += "<span>" + scope.data.issueRelation.startDate + " ~ " + scope.data.issueRelation.completeDate + "</span>";
                                            }
                                            break;
                                        // 연관 이슈 사용자 정의 필드
                                        case "REL_ISSUE_CUSTOM_FIELD_VALUE_VIEW" :
                                            var values = [];
                                            for (var count in scope.data.issueRelation.issueCustomFieldValueVos) {
                                                var issueCustomFieldValueVo = scope.data.issueRelation.issueCustomFieldValueVos[count];
                                                //  테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다.
                                                if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) {
                                                    values.push(issueCustomFieldValueVo.useValue);
                                                }
                                            }
                                            angular.forEach(values, function (value) {
                                                makeTag += '<span class="table-word-break-all cursor">' + value + '<span><br>';
                                            });
                                            break;
                                    }
                                }
                                makeTag += '</td>';
                                var linkFn = $compile(makeTag);
                                var content = linkFn(scope);
                                element.append(content);
                            });
                        }
                    }
                }
        }]);
    });
src/main/webapp/custom_components/js-table/tableColumnGenerator.directive.js
@@ -235,148 +235,148 @@
                                            break;*/
                                        // 연관 이슈 이동(제목)
                                        case "ISSUE_RELATION_MOVE" :
                                            makeTag += "<span class=\"titlename cursor text-center\" ng-click=\"event.changeDetailView(data.issueRelation)\">" + scope.data.title + "</span></a>";
                                            break;
                                        // case "ISSUE_RELATION_MOVE" :
                                        //     makeTag += "<span class=\"titlename cursor text-center\" ng-click=\"event.changeDetailView(data.issueRelation)\">" + scope.data.title + "</span></a>";
                                        //     break;
                                        // 연관이슈 구분
                                        case "ISSUE_RELATION_TYPE":
                                            makeTag += "<span>" + scope.data.relationIssueTypeName + "</span>";
                                            break;
                                        // case "ISSUE_RELATION_TYPE":
                                        //     makeTag += "<span>" + scope.data.relationIssueTypeName + "</span>";
                                        //     break;
                                        // 연관이슈 삭제
                                        case "ISSUE_RELATION_DELETE":
                                            if (scope.data.modifyPermissionCheck) {
                                                makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeRelationIssue(data.id)">';
                                            }
                                            break;
                                        // case "ISSUE_RELATION_DELETE":
                                        //     if (scope.data.modifyPermissionCheck) {
                                        //         makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeRelationIssue(data.id)">';
                                        //     }
                                        //     break;
                                        // 연관 이슈 우선순위
                                        case "REL_COMMON_PRIORITY" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>";
                                            break;
                                        // case "REL_COMMON_PRIORITY" :
                                        //     makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>";
                                        //     break;
                                        // 연관 이슈 중요도
                                        case "REL_COMMON_SEVERITY" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>";
                                            break;
                                        // case "REL_COMMON_SEVERITY" :
                                        //     makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>";
                                        //     break;
                                        // 연관 이슈 등록자
                                        case "REL_REGISTER":
                                            scope.data.registerVos = [scope.data.issueRelation.registerVo];
                                            makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>';
                                            break;
                                            break;
                                        // case "REL_REGISTER":
                                        //     scope.data.registerVos = [scope.data.issueRelation.registerVo];
                                        //     makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>';
                                        //     break;
                                        //
                                        //     break;
                                        // 연관 이슈 담당부서
                                        case "REL_ISSUE_DEPARTMENT" :
                                            makeTag += "<ul class='ul-not-comma'>";
                                            makeTag += "<div style='color: #000000'>";
                                            angular.forEach(scope.data.issueRelation.departmentVos, function (departments) {
                                                makeTag += "<li>" + departments.departmentName + "</li>";
                                            });
                                            makeTag += "</div>";
                                            makeTag += "</ul>";
                                            break;
                                        // case "REL_ISSUE_DEPARTMENT" :
                                        //     makeTag += "<ul class='ul-not-comma'>";
                                        //     makeTag += "<div style='color: #000000'>";
                                        //     angular.forEach(scope.data.issueRelation.departmentVos, function (departments) {
                                        //         makeTag += "<li>" + departments.departmentName + "</li>";
                                        //     });
                                        //     makeTag += "</div>";
                                        //     makeTag += "</ul>";
                                        //     break;
                                        // 연관 이슈 목록에서 기간 표시
                                        case "REL_ISSUE_DUE_DATE" :
                                            if (!$rootScope.isDefined(scope.data.issueRelation.startDate) && !$rootScope.isDefined(scope.data.issueRelation.completeDate)) {
                                                makeTag += "<span translate='common.noDate'>기간 없음</span>";
                                            }
                                            else {
                                                makeTag += "<span>" + scope.data.issueRelation.startDate + " ~ " + scope.data.issueRelation.completeDate + "</span>";
                                            }
                                            break;
                                        // case "REL_ISSUE_DUE_DATE" :
                                        //     if (!$rootScope.isDefined(scope.data.issueRelation.startDate) && !$rootScope.isDefined(scope.data.issueRelation.completeDate)) {
                                        //         makeTag += "<span translate='common.noDate'>기간 없음</span>";
                                        //     }
                                        //     else {
                                        //         makeTag += "<span>" + scope.data.issueRelation.startDate + " ~ " + scope.data.issueRelation.completeDate + "</span>";
                                        //     }
                                        //     break;
                                        // 연관 이슈 사용자 정의 필드
                                        case "REL_ISSUE_CUSTOM_FIELD_VALUE_VIEW" :
                                            var values = [];
                                            for (var count in scope.data.issueRelation.issueCustomFieldValueVos) {
                                                var issueCustomFieldValueVo = scope.data.issueRelation.issueCustomFieldValueVos[count];
                                                //  테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다.
                                                if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) {
                                                    values.push(issueCustomFieldValueVo.useValue);
                                                }
                                            }
                                            angular.forEach(values, function (value) {
                                                makeTag += '<span class="table-word-break-all cursor">' + value + '<span><br>';
                                            });
                                            break;
                                        // case "REL_ISSUE_CUSTOM_FIELD_VALUE_VIEW" :
                                        //     var values = [];
                                        //
                                        //     for (var count in scope.data.issueRelation.issueCustomFieldValueVos) {
                                        //         var issueCustomFieldValueVo = scope.data.issueRelation.issueCustomFieldValueVos[count];
                                        //         //  테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다.
                                        //         if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) {
                                        //             values.push(issueCustomFieldValueVo.useValue);
                                        //         }
                                        //     }
                                        //     angular.forEach(values, function (value) {
                                        //         makeTag += '<span class="table-word-break-all cursor">' + value + '<span><br>';
                                        //     });
                                        //
                                        //     break;
                                        // 하위 이슈 이동(제목)
                                        case "ISSUE_DOWN_MOVE" :
                                            makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data)\">" + scope.data.title + "</span></a>";
                                            break;
                                        // 하위 이슈 타입
                                        case "ISSUE_DOWN_STATUS_TYPE" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.issueStatusVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.issueStatusVo.color + "\", \"color\": \"#FFFFFF\" }'>" + scope.data.issueStatusVo.name + "</span>";
                                            break;
                                        // case "ISSUE_DOWN_MOVE" :
                                        //     makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data)\">" + scope.data.title + "</span></a>";
                                        //     break;
                                        //
                                        // // 하위 이슈 타입
                                        // case "ISSUE_DOWN_STATUS_TYPE" :
                                        //     makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.issueStatusVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.issueStatusVo.color + "\", \"color\": \"#FFFFFF\" }'>" + scope.data.issueStatusVo.name + "</span>";
                                        //     break;
                                        //
                                        // 하위 이슈 삭제
                                        case "ISSUE_DOWN_DELETE":
                                            if (scope.data.modifyPermissionCheck) {
                                                makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeDownIssue(data.id)">';
                                            }
                                            break;
                                        // case "ISSUE_DOWN_DELETE":
                                        //     if (scope.data.modifyPermissionCheck) {
                                        //         makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeDownIssue(data.id)">';
                                        //     }
                                        //     break;
                                        //
                                        // 하위 이슈 우선 순위
                                        case "DOWN_COMMON_PRIORITY" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>";
                                            break;
                                        // case "DOWN_COMMON_PRIORITY" :
                                        //     makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>";
                                        //     break;
                                        //
                                        // 하위 이슈 중요도
                                        case "DOWN_COMMON_SEVERITY" :
                                            makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>";
                                            break;
                                        // case "DOWN_COMMON_SEVERITY" :
                                        //     makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>";
                                        //     break;
                                        //
                                        // 하위 이슈 담당부서
                                        case "DOWN_ISSUE_DEPARTMENT" :
                                            makeTag += "<ul class='ul-not-comma'>";
                                            makeTag += "<div style='color: #000000'>";
                                            angular.forEach(scope.data.departmentVos, function (departments) {
                                                makeTag += "<li>" + departments.departmentName + "</li>";
                                            });
                                            makeTag += "</div>";
                                            makeTag += "</ul>";
                                            break;
                                        // case "DOWN_ISSUE_DEPARTMENT" :
                                        //     makeTag += "<ul class='ul-not-comma'>";
                                        //     makeTag += "<div style='color: #000000'>";
                                        //     angular.forEach(scope.data.departmentVos, function (departments) {
                                        //         makeTag += "<li>" + departments.departmentName + "</li>";
                                        //     });
                                        //     makeTag += "</div>";
                                        //     makeTag += "</ul>";
                                        //     break;
                                        //
                                        // 하위 이슈 등록자
                                        case "DOWN_REGISTER":
                                            scope.data.registerVos = [scope.data.registerVo];
                                            makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>';
                                            break;
                                        // case "DOWN_REGISTER":
                                        //     scope.data.registerVos = [scope.data.registerVo];
                                        //     makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>';
                                        //     break;
                                        //
                                        // 하위 이슈 기간
                                        case "DOWN_ISSUE_DUE_DATE" :
                                            if (!$rootScope.isDefined(scope.data.startDate) && !$rootScope.isDefined(scope.data.completeDate)) {
                                                makeTag += "<span translate='common.noDate'>기간 없음</span>";
                                            }
                                            else {
                                                makeTag += "<span>" + scope.data.startDate + " ~ " + scope.data.completeDate + "</span>";
                                            }
                                            break;
                                        // case "DOWN_ISSUE_DUE_DATE" :
                                        //     if (!$rootScope.isDefined(scope.data.startDate) && !$rootScope.isDefined(scope.data.completeDate)) {
                                        //         makeTag += "<span translate='common.noDate'>기간 없음</span>";
                                        //     }
                                        //     else {
                                        //         makeTag += "<span>" + scope.data.startDate + " ~ " + scope.data.completeDate + "</span>";
                                        //     }
                                        //     break;
                                        //
                                        // 하위 이슈 사용자 정의 필드
                                        case "DOWN_ISSUE_CUSTOM_FIELD_VALUE_VIEW" :
                                            var values = [];
                                            for (var count in scope.data.issueCustomFieldValueVos) {
                                                var issueCustomFieldValueVo = scope.data.issueCustomFieldValueVos[count];
                                                //  테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다.
                                                if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) {
                                                    values.push(issueCustomFieldValueVo.useValue);
                                                }
                                            }
                                            angular.forEach(values, function (value) {
                                                makeTag += '<span class="table-word-break-all">' + value + '<span><br>';
                                            });
                                            break;
                                        // case "DOWN_ISSUE_CUSTOM_FIELD_VALUE_VIEW" :
                                        //     var values = [];
                                        //
                                        //     for (var count in scope.data.issueCustomFieldValueVos) {
                                        //         var issueCustomFieldValueVo = scope.data.issueCustomFieldValueVos[count];
                                        //         //  테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다.
                                        //         if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) {
                                        //             values.push(issueCustomFieldValueVo.useValue);
                                        //         }
                                        //     }
                                        //     angular.forEach(values, function (value) {
                                        //         makeTag += '<span class="table-word-break-all">' + value + '<span><br>';
                                        //     });
                                        //
                                        //     break;
                                        //  이름을 클릭하면 수정 팝업 표시
                                        case "COMMON_MODIFY" :
src/main/webapp/scripts/app/issue/issue.js
@@ -34,7 +34,7 @@
                            var deferred = $q.defer();
                            require([
                                'issueListTimelineController', 'issueManagerController', 'issueListController', 'issueAddController', 'issueModifyController', 'issueDetailController', 'issueAddRelationController', 'issueAddDownController', 'issueImportExcelController',
                                'chartLoader', 'jsTable', 'jsTree', 'tableColumnGenerator', 'treeColumnGenerator', 'modalFormAutoScroll', 'summerNote', 'summerNote-ko-KR', 'fullScroll', 'workflowService', 'priorityService', 'issueSearchService', 'issueTableConfigService', 'inputRegex',
                                'chartLoader', 'jsTable', 'jsTree', 'jsRel', 'jsDown', 'tableColumnGenerator', 'treeColumnGenerator', 'relColumnGenerator', 'downColumnGenerator', 'modalFormAutoScroll', 'summerNote', 'summerNote-ko-KR', 'fullScroll', 'workflowService', 'priorityService', 'issueSearchService', 'issueTableConfigService', 'inputRegex',
                                'severityService', 'issueTypeService', 'issueTypeCustomFieldService', 'issueService', 'issueStatusService', 'emailTemplateService','issueUserService','issueDepartmentService','issueModifyUserController', 'issueModifyDepartmentController', 'customFieldService', 'issueSearchFieldKeyViewElement',
                                'issueSearchCustomFieldViewElement', 'tableUserImage', 'fullScroll', 'issueCommentService', 'detectIssueEditor', 'formSubmit', 'issueModifyStatusController', 'downIssueModifyStatusController', 'jsShortCut',
                                'issueAddTableConfigController','issueAddRelationTableConfigController','issueAddDownTableConfigController','domAppend', 'issueDetailImagePreview', 'issueSendMailPartnersController', 'issueCommonSendMailController', 'htmlDiff', 'issueVersionViewController', 'issueVersionService',
src/main/webapp/scripts/app/issue/issueDetail.controller.js
@@ -8,9 +8,9 @@
        'angular'
    ],
    function (app, angular) {
        app.controller('issueDetailController', ['$scope', '$rootScope', '$log', '$resourceProvider', '$tableProvider', '$state', '$uibModal', '$q',
        app.controller('issueDetailController', ['$scope', '$rootScope', '$log', '$resourceProvider', '$tableProvider', '$relProvider', '$downProvider', '$state', '$uibModal', '$q',
            '$controller', '$injector', 'SweetAlert', '$timeout', 'Issue', 'IssueComment', 'IssueRelation', 'AttachedFile',  'Priority', 'Severity','IssueStatus', 'IssueTableConfig', '$filter',
            function ($scope, $rootScope, $log, $resourceProvider, $tableProvider, $state, $uibModal, $q, $controller, $injector, SweetAlert, $timeout, Issue, IssueComment, IssueRelation, AttachedFile, Priority, Severity, IssueStatus, IssueTableConfig, $filter) {
            function ($scope, $rootScope, $log, $resourceProvider, $tableProvider, $relProvider, $downProvider, $state, $uibModal, $q, $controller, $injector, SweetAlert, $timeout, Issue, IssueComment, IssueRelation, AttachedFile, Priority, Severity, IssueStatus, IssueTableConfig, $filter) {
                //  IssueListController vm, fn 변수 상속.
@@ -310,90 +310,98 @@
                }
                //  테이블의 연관 이슈 컬럼을 만들어준다.
                function setRelTableColumn(Rel_issueTableConfig) {
                function setRelTableColumn(issueTableConfig) {
                    //  연관 이슈 컬럼
                    switch(Rel_issueTableConfig.key) {
                    switch(issueTableConfig.key) {
                        case "RELATION_ISSUE_TYPE" :    // 연관 이슈 구분
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("issue.relationIssueType")
                                .setDName("relationIssueType")
                                .setDType("renderer")
                                .setDAlign("text-center")
                                .setHWidth("bold " + Rel_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDRenderer("ISSUE_RELATION_TYPE"))
                                /*.setHWidth("width-30 bold")*/
                                /*.setHSort(false)*/
                            break;
                        case "RELATION_ISSUE_TITLE" :   // 연관 이슈 제목
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("issue.relationIssueTitle")
                                .setDName("title")
                                .setDType("renderer")
                                .setDAlign("text-center")
                                .setHWidth("bold " + Rel_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDRenderer("ISSUE_RELATION_MOVE"))
                                /*.setHWidth("width-60 bold")*/
                                /*.setHSort(true)*/
                            break;
                        case "RELATION_PRIORITY" :   // 연관 이슈 우선순위
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("common.priority")
                                .setDName("priorityVo.id")
                                .setDType("renderer")
                                .setHWidth("bold " + Rel_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("REL_COMMON_PRIORITY"));
                            break;
                        case "RELATION_SEVERITY" :   //  연관 이슈 중요도
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("common.importance")
                                .setDName("severityVo.id")
                                .setDType("renderer")
                                .setHWidth("bold " + Rel_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("REL_COMMON_SEVERITY"));
                            break;
                        case "RELATION_ASSIGNEE_TEAM" :   // 연관 이슈 담당부서
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("common.assigneeTeam")
                                .setDName("departmentVos.departmentName")
                                .setDType("renderer")
                                .setHWidth("bold " + Rel_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("REL_ISSUE_DEPARTMENT"));
                            break;
                        case "RELATION_REGISTER" :   // 연관 이슈  등록자
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                        case "RELATION_REGISTER" :   // 연관 이슈 등록자
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("common.register")
                                .setDName("registerVo.id")
                                .setDType("renderer")
                                .setHWidth("bold " + Rel_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("REL_REGISTER"));
                            break;
                        case "RELATION_PERIOD" : // 연관 이슈 기간
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("common.period")
                                .setDType("renderer")
                                .setHWidth("bold " + Rel_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("REL_ISSUE_DUE_DATE"));
                            break;
                        case "RELATION_MODIFY_DATE" : // 연관 이슈  최근 변경일
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                        case "RELATION_MODIFY_DATE" : // 연관 이슈 최근 변경일
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("common.lastChangeDate")
                                .setHWidth("bold " + Rel_issueTableConfig.width)
                                .setDAlign("text-center"));
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDName("modifyDate"));
                            break;
                    }
                    //  사용자 정의 필드 컬럼
                    if (Rel_issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) {
                    if (issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) {
                        //  만약 이슈 테이블 컬럼명이 표시되지 않으면 이쪽이 문제
                        for (var count in $scope.vm.customFields) {
                            var customField = $scope.vm.customFields[count];
                            if (customField.id === Number(Rel_issueTableConfig.key.substring(13))) {
                                $scope.vm.relTableConfigs.push($tableProvider.config()
                            if (customField.id === Number(issueTableConfig.key.substring(13))) {
                                $scope.vm.relTableConfigs.push($relProvider.config()
                                    .setHName(customField.name)
                                    .setDName("relCustomFieldName" + [count])
                                    .setDType("renderer")
                                    .setHWidth("bold " + Rel_issueTableConfig.width)
                                    .setHWidth("bold " + issueTableConfig.width)
                                    .setDAlign("text-center")
                                    .setColumnHint(customField)
                                    .setDRenderer("REL_ISSUE_CUSTOM_FIELD_VALUE_VIEW"));
@@ -405,88 +413,96 @@
                //  테이블의 하위 이슈 컬럼을 만들어준다.
                function setDownTableColumn(Down_issueTableConfig) {
                function setDownTableColumn(issueTableConfig) {
                    // if (issueTableConfig == null) return;
                    //  하위 이슈 컬럼
                    switch(Down_issueTableConfig.key) {
                    switch(issueTableConfig.key) {
                        case "DOWN_ISSUE_TITLE" :   //  하위 이슈 제목
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("issue.downIssueTitle")
                                .setDName("title")
                                .setDType("renderer")
                                .setHWidth("bold " + Down_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("ISSUE_DOWN_MOVE"));
                            break;
                        case "ISSUE_DOWN_STATUS_TYPE" : //  이슈 상태
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                        case "ISSUE_DOWN_STATUS_TYPE" : // 하위 이슈 상태
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("issue.issueStatus")
                                .setDName("issueStatusVo.id")
                                .setDType("renderer")
                                .setHWidth("bold " + Down_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("ISSUE_DOWN_STATUS_TYPE"));
                            break;
                        case "DOWN_PRIORITY" :   // 하위 이슈 우선순위
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("common.priority")
                                .setDName("priorityVo.id")
                                .setDType("renderer")
                                .setHWidth("bold " + Down_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("DOWN_COMMON_PRIORITY"));
                            break;
                        case "DOWN_SEVERITY" :   //  중요도
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                        case "DOWN_SEVERITY" :   // 하위 이슈 중요도
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("common.importance")
                                .setDName("severityVo.id")
                                .setDType("renderer")
                                .setHWidth("bold " + Down_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("DOWN_COMMON_SEVERITY"));
                            break;
                        case "DOWN_ASSIGNEE_TEAM" :   //  담당부서
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                        case "DOWN_ASSIGNEE_TEAM" :   // 하위 이슈 담당부서
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("common.assigneeTeam")
                                .setDName("departmentVos.departmentName")
                                .setDType("renderer")
                                .setHWidth("bold " + Down_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("DOWN_ISSUE_DEPARTMENT"));
                            break;
                        case "DOWN_REGISTER" :   //  등록자
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                        case "DOWN_REGISTER" :   // 하위 이슈 등록자
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("common.register")
                                .setDName("registerVo.id")
                                .setDType("renderer")
                                .setHWidth("bold " + Down_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("DOWN_REGISTER"));
                            break;
                        case "DOWN_PERIOD" : //  기간
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                        case "DOWN_PERIOD" : // 하위 이슈 기간
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("common.period")
                                .setDType("renderer")
                                .setHWidth("bold " + Down_issueTableConfig.width)
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDRenderer("DOWN_ISSUE_DUE_DATE"));
                            break;
                        case "DOWN_MODIFY_DATE" : //  최근 변경일
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                        case "DOWN_MODIFY_DATE" : // 하위 이슈 최근 변경일
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("common.lastChangeDate")
                                .setHWidth("bold " + Down_issueTableConfig.width)
                                .setDAlign("text-center"));
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
                                .setDName("modifyDate"));
                            break;
                    }
                    //  사용자 정의 필드 컬럼
                    if (Down_issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) {
                    if (issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) {
                        //  만약 이슈 테이블 컬럼명이 표시되지 않으면 이쪽이 문제
                        for (var count in $scope.vm.customFields) {
                            var customField = $scope.vm.customFields[count];
                            if (customField.id === Number(Down_issueTableConfig.key.substring(13))) {
                                $scope.vm.downTableConfigs.push($tableProvider.config()
                            if (customField.id === Number(issueTableConfig.key.substring(13))) {
                                $scope.vm.downTableConfigs.push($downProvider.config()
                                    .setHName(customField.name)
                                    .setDName("downCustomFieldName" + [count])
                                    .setDType("renderer")
                                    .setHWidth("bold " + Down_issueTableConfig.width)
                                    .setHWidth("bold " + issueTableConfig.width)
                                    .setDAlign("text-center")
                                    .setColumnHint(customField)
                                    .setDRenderer("DOWN_ISSUE_CUSTOM_FIELD_VALUE_VIEW"));
@@ -500,18 +516,18 @@
                //  연관 이슈 테이블 설정
                function makeRelTableConfigs() {
                    $scope.vm.relTableConfigs = [];
                    $scope.vm.relTableConfigs.push($tableProvider.config()
                    $scope.vm.relTableConfigs.push($relProvider.config()
                        .setDType("checkbox")
                        .setHWidth("width-20-p")
                        .setDAlign("text-center"))
                    $scope.vm.relTableConfigs.push($tableProvider.config()
                    $scope.vm.relTableConfigs.push($relProvider.config()
                        .setHName("issue.relationIssueType")
                        .setDType("renderer")
                        .setDAlign("text-center")
                        .setHWidth("width-60-p bold")
                        .setHSort(false)
                        .setDRenderer("ISSUE_RELATION_TYPE"))
                    $scope.vm.relTableConfigs.push($tableProvider.config()
                    $scope.vm.relTableConfigs.push($relProvider.config()
                        .setHName("issue.relationIssueTitle")
                        .setDType("renderer")
                        .setDAlign("text-center")
@@ -519,7 +535,7 @@
                        .setHSort(false)
                        .setDRenderer("ISSUE_RELATION_MOVE"))
                    /*if($scope.vm.viewer.modifyPermissionCheck) {
                        $scope.vm.relTableConfigs.push($tableProvider.config()
                        $scope.vm.relTableConfigs.push($relProvider.config()
                            .setHName("issue.relationIssueDelete")
                            .setDType("renderer")
                            .setDAlign("text-center")
@@ -528,11 +544,11 @@
                            .setHSort(false)
                            .setDAlign("text-center"))
                    }*/
                    angular.forEach($scope.vm.relTableConfigs, function (Rel_issueTableConfig) {
                    angular.forEach($scope.vm.relTableConfigs, function (issueTableConfig) {
                        //  표시 대상인 컬럼만 화면에 그려준다.
                        if (Rel_issueTableConfig.display) {
                        if (issueTableConfig.display) {
                            //  테이블의 컬럼을 만들어준다.
                            $scope.fn.setRelTableColumn(Rel_issueTableConfig);
                            $scope.fn.setRelTableColumn(issueTableConfig);
                        }
                    });
                }
@@ -540,11 +556,11 @@
                //  하위 이슈 테이블 설정
                function makeDownTableConfigs() {
                    $scope.vm.downTableConfigs = [];
                    $scope.vm.downTableConfigs.push($tableProvider.config()
                    $scope.vm.downTableConfigs.push($downProvider.config()
                        .setDType("checkbox")
                        .setHWidth("width-20-p")
                        .setDAlign("text-center"))
                    $scope.vm.downTableConfigs.push($tableProvider.config()
                    $scope.vm.downTableConfigs.push($downProvider.config()
                        .setHName("issue.downIssueTitle")
                        .setDType("renderer")
                        .setDAlign("text-center")
@@ -552,7 +568,7 @@
                        .setHSort(false)
                        .setDRenderer("ISSUE_DOWN_MOVE"))
                    /*if($scope.vm.viewer.modifyPermissionCheck){
                        $scope.vm.downTableConfigs.push($tableProvider.config()
                        $scope.vm.downTableConfigs.push($downProvider.config()
                            .setHName("issue.relationIssueDelete")
                            .setDType("renderer")
                            .setDAlign("text-center")
@@ -562,11 +578,11 @@
                            .setDAlign("text-center"))
                    }*/
                    angular.forEach($scope.vm.downTableConfigs, function (Down_issueTableConfig) {
                    angular.forEach($scope.vm.downTableConfigs, function (issueTableConfig) {
                        //  표시 대상인 컬럼만 화면에 그려준다.
                        if (Down_issueTableConfig.display) {
                        if (issueTableConfig.display) {
                            //  테이블의 컬럼을 만들어준다.
                            $scope.fn.setDownTableColumn(Down_issueTableConfig);
                            $scope.fn.setDownTableColumn(issueTableConfig);
                        }
                    });
                }
@@ -579,7 +595,7 @@
                    }
                    var issueTableConfigs = issueTableConfigVo.issueTableConfigs;
                    //  연관 슈 목록 테이블 설정 값을 가져와서 적용한다.
                    //  연관 이슈 목록 테이블 설정 값을 가져와서 적용한다.
                    if ($rootScope.isDefined(issueTableConfigs)) {
                        //  이슈 테이블 설정 정보를 저장 한다.
@@ -590,34 +606,34 @@
                        });
                        $scope.vm.relTableConfigs = [];
    /*                  $scope.vm.relTableConfigs.push($tableProvider.config()
    /*                  $scope.vm.relTableConfigs.push($relProvider.config()
                           .setHName("issue.relationIssueType")
                           .setDType("renderer")
                           .setDAlign("text-center")
                           .setHWidth("width-30-p bold")
                           .setHSort(false)
                           .setDRenderer("ISSUE_RELATION_TYPE"))
                        $scope.vm.relTableConfigs.push($tableProvider.config()
                        $scope.vm.relTableConfigs.push($relProvider.config()
                           .setHName("issue.relationIssueTitle")
                           .setDType("renderer")
                           .setDAlign("text-center")
                           .setHWidth("width-60-p bold")
                           .setHSort(false)
                           .setDRenderer("ISSUE_RELATION_MOVE"))*/
                        $scope.vm.relTableConfigs.push($tableProvider.config()
                        $scope.vm.relTableConfigs.push($relProvider.config()
                            .setDType("checkbox")
                            .setHWidth("width-20-p")
                            .setDAlign("text-center"))
                        angular.forEach($scope.vm.issueRelTableConfigs, function (Rel_issueTableConfig) {
                        angular.forEach($scope.vm.issueRelTableConfigs, function (issueTableConfig) {
                            //  표시 대상인 컬럼만 화면에 그려준다.
                            if (Rel_issueTableConfig.display) {
                            if (issueTableConfig.display) {
                                //  테이블의 컬럼을 만들어준다.
                                $scope.fn.setRelTableColumn(Rel_issueTableConfig);
                                $scope.fn.setRelTableColumn(issueTableConfig);
                            }
                        });
                        /*if($scope.vm.viewer.modifyPermissionCheck) {
                            $scope.vm.relTableConfigs.push($tableProvider.config()
                            $scope.vm.relTableConfigs.push($relProvider.config()
                                .setHName("issue.relationIssueDelete")
                                .setDType("renderer")
                                .setHWidth("width-40-p bold")
@@ -636,7 +652,7 @@
                    if (issueTableConfigVo == null) return;
                    var issueTableConfigs = issueTableConfigVo.issueTableConfigs;
                    //  연관 슈 목록 테이블 설정 값을 가져와서 적용한다.
                    //  연관 이슈 목록 테이블 설정 값을 가져와서 적용한다.
                    if ($rootScope.isDefined(issueTableConfigs)) {
                        //  이슈 테이블 설정 정보를 저장 한다.
                        $scope.vm.issueDownTableConfigs = [];
@@ -645,26 +661,26 @@
                            return a.position < b.position ? -1 : a.position > b.position ? 1 : 0;
                        });
                        $scope.vm.downTableConfigs = [];
/*                      $scope.vm.downTableConfigs.push($tableProvider.config()
/*                      $scope.vm.downTableConfigs.push($downProvider.config()
                            .setHName("issue.downIssueTitle")
                            .setDType("renderer")
                            .setDAlign("text-center")
                            .setHWidth("width-60-p bold")
                            .setHSort(false)
                            .setDRenderer("ISSUE_DOWN_MOVE"))*/
                        $scope.vm.downTableConfigs.push($tableProvider.config()
                        $scope.vm.downTableConfigs.push($downProvider.config()
                            .setDType("checkbox")
                            .setHWidth("width-20-p")
                            .setDAlign("text-center"))
                        angular.forEach($scope.vm.issueDownTableConfigs, function (Down_issueTableConfig) {
                        angular.forEach($scope.vm.issueDownTableConfigs, function (issueTableConfig) {
                            //  표시 대상인 컬럼만 화면에 그려준다.
                            if (Down_issueTableConfig.display) {
                            if (issueTableConfig.display) {
                                //  테이블의 컬럼을 만들어준다.
                                $scope.fn.setDownTableColumn(Down_issueTableConfig);
                                $scope.fn.setDownTableColumn(issueTableConfig);
                            }
                        });
                        /*if($scope.vm.viewer.modifyPermissionCheck) {
                            $scope.vm.downTableConfigs.push($tableProvider.config()
                            $scope.vm.downTableConfigs.push($downProvider.config()
                                .setHName("issue.relationIssueDelete")
                                .setDType("renderer")
                                .setHWidth("width-40-p bold")
@@ -975,6 +991,8 @@
                                $scope.vm.viewer.startDate = result.data.data.startDate == null ? "common.unspecified" : result.data.data.startDate; // 미지정
                                $scope.vm.viewer.completeDate = result.data.data.completeDate == null ? "common.unspecified" : result.data.data.completeDate; // 미지정
                                $scope.vm.rangeDate = result.data.data.startDate + "~" + result.data.data.completeDate
                                //  이슈 유형에 연결된 사용자 정의 필드 정보를 입력 폼에서 사용할 수 있게 가공한다.
                                $scope.fn.setFormByIssueTypeCustomFields(result.data.data.issueTypeCustomFieldVos);
                                //  이슈에서 사용자가 선택한 사용자 정의 필드 값을 입력 폼에 셋팅한다.
src/main/webapp/scripts/app/issue/issueList.controller.js
@@ -336,7 +336,7 @@
                        case "ISSUE_TITLE" :   //  이슈 제목
                            $scope.vm.tableConfigs.push($tableProvider.config()
                                .setHName("issue.issueTitle")
                                .setDName("issueNumber") /* todo 이건 타이틀로 변경해야하는데*/
                                .setDName("issueTitle")
                                .setDType("renderer")
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
@@ -373,7 +373,7 @@
                        case "ASSIGNEE_TEAM" :   //  담당부서
                            $scope.vm.tableConfigs.push($tableProvider.config()
                                .setHName("common.assigneeTeam")
                                .setDName("departmentName") /* todo 체크*/
                                .setDName("departmentName")
                                .setDType("renderer")
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
@@ -391,7 +391,6 @@
                        case "PERIOD" : //  기간
                            $scope.vm.tableConfigs.push($tableProvider.config()
                                .setHName("common.period")
                                .setDName("startDate")
                                .setDType("renderer")
                                .setHWidth("bold " + issueTableConfig.width)
                                .setDAlign("text-center")
src/main/webapp/scripts/components/auth/auth.interceptor.js
@@ -11,6 +11,16 @@
                        $tableProvider.setOrderByColumn();
                        $tableProvider.reverse = false;
                        //  연관 테이블 컬럼 정렬 초기화
                        var $relProvider = $injector.get('$relProvider');
                        $relProvider.setOrderByColumn();
                        $relProvider.reverse = false;
                        //  하위 테이블 컬럼 정렬 초기화
                        var $downProvider = $injector.get('$downProvider');
                        $downProvider.setOrderByColumn();
                        $downProvider.reverse = false;
                        if (angular.isDefined(config.data)) {
                            $log.debug(config.url + " : ", config.data);
                        }
src/main/webapp/scripts/config.js
@@ -35,7 +35,7 @@
                //  로그 제어
                $logProvider.debugEnabled(true);
            })
            .run(function ($rootScope, $state, $sce, $log, $injector, $translate, $tableProvider, Principal, Auth, Language, SweetAlert, $filter, Workspace, $resourceProvider, User, constants, Project) {
            .run(function ($rootScope, $state, $sce, $log, $injector, $translate, $tableProvider, $relProvider, $downProvider, Principal, Auth, Language, SweetAlert, $filter, Workspace, $resourceProvider, User, constants, Project) {
                $rootScope.$state = $state;
                //  html 태그 웹 보안 적용하여 바인딩.
@@ -117,6 +117,12 @@
                //  테이블 설정 및 기능을 관리하는 서비스
                $rootScope.$tableProvider = $tableProvider;
                //  연관테이블 설정 및 기능 관리하는 서비스
                $rootScope.$relProvider = $relProvider;
                //  하위테이블 설정 및 기능 관리하는 서비스
                $rootScope.$downProvider = $downProvider;
                //  html tag convert - 신뢰할 수 있는 입력 값일 때만 사용, 사용자가 등록하는 값에는 사용 금지
                $rootScope.trustAsHtml = function (string) {
@@ -568,6 +574,9 @@
                    //  table orderBy column init setting
                    $tableProvider.setOrderByColumn();
                    $tableProvider.reverse = false;
                    $relProvider.setOrderByColumn();
                    $relProvider.reverse = false;
                    //  이슈 목록->상세화면에서 마지막으로 접근한 이슈 아이디 - 라우트 탈때마다 초기화
                    $rootScope.currentDetailIssueId = null;
                    // 사용자 정보를 가져온다.
src/main/webapp/scripts/main.js
@@ -56,13 +56,19 @@
        'commonController' : 'app/common/common.controller', //  공통 컨트롤러
        'tableProvider' : '../custom_components/js-table/table.provider', //  테이블 속성 값을 관리한다.
        'treeProvider' : '../custom_components/js-tree/tree.provider', //   트리 속성 값을 관리한다.
        'relProvider' : '../custom_components/js-rel/rel.provider', //   연관 테이블 속성 값을 관리한다.
        'downProvider' : '../custom_components/js-down/down.provider', //   하위 테이블 속성 값을 관리한다.
        'resourceProvider' : 'components/utils/resource.provider',   //  공통적으로 서버 json 전송에 사용
        'lodash' : '../bower_components/lodash/lodash.min', //  멀티 셀렉트, auto complete 컴포넌트들에서 사용
        'angularDropMultiSelect' : '../custom_components/angular-multi-select/angularjs-dropdown-multiselect',  //  멀티 셀렉트 컴포넌트
        'jsTable' : '../custom_components/js-table/js-table.directive',   //  목록 화면에서 사용되는 테이블을 호출한다.
        'jsTree' : '../custom_components/js-tree/js-tree.directive',   //  목록 화면에서 사용되는 테이블(트리구조)을 호출한다.
        'jsRel' : '../custom_components/js-rel/js-rel.directive',   //  이슈상세 화면에서 사용되는 연관 테이블을 호출한다.
        'jsDown' : '../custom_components/js-down/js-down.directive',   //  이슈상세 화면에서 사용되는 하위 테이블을 호출한다.
        'tableColumnGenerator' : '../custom_components/js-table/tableColumnGenerator.directive', //  테이블 랜더러를 담당한다.
        'treeColumnGenerator' : '../custom_components/js-tree/treeColumnGenerator.directive', //  테이블 랜더러를 담당한다.
        'treeColumnGenerator' : '../custom_components/js-tree/treeColumnGenerator.directive', //  이슈리스트 트리 랜더러를 담당한다.
        'relColumnGenerator' : '../custom_components/js-rel/relColumnGenerator.directive', //  이슈상세 연관 랜더러를 담당한다.
        'downColumnGenerator' : '../custom_components/js-down/downColumnGenerator.directive', //  이슈상세 하위 랜더러를 담당한다.
        'jsAutoCompleteMulti' : '../custom_components/js-autocomplete-multi/js-autocomplete-multi', //  다중 선택이 가능한 autoComplete 컴포넌트
        'jsInputAutoComplete' : '../custom_components/js-input-autocomplete/js-input-autocomplete',   //  input 박스에 autoComplete 기능이 붙은 컴포넌트
        'jsAutoCompleteSingle' : '../custom_components/js-autocomplete-single/js-autocomplete-single',   //  input 박스에 한개의 대상만 선택 가능할수 있는 autoComplete 기능이 붙은 컴포넌트
@@ -410,10 +416,22 @@
        'jsTree' : {
            deps : ['app']
        },
        'jsRel' : {
            deps : ['app']
        },
        'jsDown' : {
            deps : ['app']
        },
        'tableColumnGenerator' : {
            deps : ['app']
        },
        'treeColumnGenerator' : {
            deps : ['app']
        },
        'relColumnGenerator' : {
            deps : ['app']
        },
        'downColumnGenerator' : {
            deps : ['app']
        },
        'ngStomp' : {
@@ -536,6 +554,8 @@
    'resourceProvider',
    'tableProvider',
    'treeProvider',
    'relProvider',
    'downProvider',
    'permissionService',
    'authService',
    'userInviteService',
src/main/webapp/views/issue/issueDetail.html
@@ -509,8 +509,8 @@
                <!--  연관 이슈 테이블 -->
                <div class="mt-10 issue-detail-word-break width-100">
                    <js-table data="vm.viewer.issueRelationVos" table-configs="vm.relTableConfigs"
                              event="relTableEvent" detail-view="true" hide-header="false" use-sort="true"></js-table>
                    <js-rel data="vm.viewer.issueRelationVos" table-configs="vm.relTableConfigs"
                              event="relTableEvent" detail-view="true" hide-header="false" use-sort="true"></js-rel>
                    <div class="row" ng-if="vm.viewer.modifyPermissionCheck">
                        <div class="col-sm-4">
@@ -579,8 +579,8 @@
                <!-- 하위 이슈 테이블 -->
                <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="true"></js-table>
                    <js-down data="vm.viewer.issueDownVos" table-configs="vm.downTableConfigs"
                              event="downTableEvent" detail-view="true" hide-header="false" use-sort="true"></js-down>
                    <div class="row" ng-if="vm.viewer.modifyPermissionCheck">
                        <div class="col-sm-6">