조사원 > 조사원 팝업: 조사원 상세 조회 기능 삭제, 시군구 코드명 추가, 팝업 그리드 개선 및 검색 UI 업데이트

dev
박성영 4 months ago
parent 71c536af35
commit 6d8a7995f1

@ -71,19 +71,4 @@ public class ExmnrPopController {
}
/**
* (API)
* @param exmnrId ID
* @return
*/
@Operation(summary = "조사원 상세 조회", description = "조사원 ID로 조사원 상세 정보를 조회합니다.")
@GetMapping("/detail/{exmnrId}.do")
public String selectExmnrPopDetail(
Model model,
@Parameter(description = "조사원 ID") @PathVariable String exmnrId) {
model.addAttribute("exmnrVO", exmnrPopService.selectExmnrPopDetail(exmnrId));
return "crdn/crndRegistAndView/exmnrPop/form"+ TilesConstants.BASE;
}
}

@ -26,11 +26,4 @@ public interface ExmnrPopMapper {
*/
int selectExmnrPopListTotalCount(ExmnrPopSearchVO searchVO);
/**
*
* @param exmnrId ID
* @return
*/
ExmnrPopVO selectExmnrPopDetail(String exmnrId);
}

@ -15,6 +15,7 @@ public class ExmnrPopVO {
private String exmnrId;
private String sggCd;
private String sggCdNm; // 시군구 코드명
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime regDt;

@ -23,12 +23,6 @@ public interface ExmnrPopService {
* @return
*/
int selectExmnrPopListTotalCount(ExmnrPopSearchVO searchVO);
/**
*
* @param exmnrId ID
* @return
*/
ExmnrPopVO selectExmnrPopDetail(String exmnrId);
}

@ -42,15 +42,4 @@ public class ExmnrPopServiceImpl implements ExmnrPopService {
return exmnrPopMapper.selectExmnrPopListTotalCount(searchVO);
}
/**
*
* @param exmnrId ID
* @return
*/
@Override
public ExmnrPopVO selectExmnrPopDetail(String exmnrId) {
log.debug("조사원 팝업 상세 조회 - 조사원 ID: {}", exmnrId);
return exmnrPopMapper.selectExmnrPopDetail(exmnrId);
}
}

@ -9,6 +9,7 @@
SELECT
e.EXMNR_ID as exmnrId,
e.SGG_CD as sggCd,
sgg.CD_NM as sggCdNm,
e.REG_DT as regDt,
e.RGTR as rgtr,
e.DEL_YN as delYn,
@ -16,6 +17,7 @@
e.DLTR as dltr,
e.EXMNR as exmnr
FROM tb_exmnr e
LEFT JOIN tb_cd_detail sgg ON sgg.CD_GROUP_ID = 'ORG_CD' AND sgg.CD_ID = e.SGG_CD AND sgg.USE_YN = 'Y'
WHERE 1=1
<if test='delYn != null and delYn != ""'>
AND e.DEL_YN = #{delYn}
@ -26,7 +28,7 @@
<if test='schSggCd != null and schSggCd != ""'>
AND e.SGG_CD = #{schSggCd}
</if>
ORDER BY e.REG_DT DESC, e.EXMNR_ID DESC
ORDER BY e.EXMNR ASC, e.REG_DT DESC, e.EXMNR_ID DESC
<if test="pagingYn != null and pagingYn == 'Y'.toString()">
LIMIT #{startNum}, #{endNum}
</if>
@ -55,6 +57,7 @@
SELECT
e.EXMNR_ID as exmnrId,
e.SGG_CD as sggCd,
sgg.CD_NM as sggCdNm,
e.REG_DT as regDt,
e.RGTR as rgtr,
e.DEL_YN as delYn,
@ -62,6 +65,7 @@
e.DLTR as dltr,
e.EXMNR as exmnr
FROM tb_exmnr e
LEFT JOIN tb_cd_detail sgg ON sgg.CD_GROUP_ID = 'ORG_CD' AND sgg.CD_ID = e.SGG_CD AND sgg.USE_YN = 'Y'
WHERE e.EXMNR_ID = #{exmnrId}
</select>

@ -5,21 +5,19 @@
<div class="popup_inner">
<div class="popup_tit">
<h2 class="tit">조사원 선택</h2>
<a href="#" class="pop-x-btn modalclose"></a>
<a href="#" class="pop-x-btn modalclose" onclick="window.close();"></a>
</div>
<div class="popup_con">
<!-- 검색 영역 -->
<div class="gs_b_top">
<ul class="lef">
<li class="th">검색어</li>
<li>
<input type="text" id="schExmnr" name="schExmnr" class="input" placeholder="조사원명을 입력하세요" style="width: 200px;">
<input type="text" id="schExmnr" name="schExmnr" class="input" placeholder="조사원ID 또는 조사원명을 입력하세요." style="width: 300px;">
<button type="button" id="search_btn" class="newbtnss bg1 smallb-2">검색</button>
</li>
</ul>
<ul class="rig">
<li>
<button type="button" id="search_btn" class="newbtnss bg1 smallb">검색</button>
</li>
<li style="border-right: 0px;"></li>
</ul>
</div>
@ -29,15 +27,9 @@
<div class="box_column">
<ul class="box_title" style="display: flex; justify-content: space-between; align-items: center;">
<li class="tit">단속 목록</li>
<li class="tit"></li>
<li class="rig">
<span id="totalCount" class="total-count" style="padding-left: 25px;padding-right: 25px;">총 0건</span>
<select id="perPageSelect" class="input" style="width: 112px; ">
<option value="15">페이지당 15</option>
<option value="50">페이지당 50</option>
<option value="100">페이지당 100</option>
</select>
<span class="page_number"><span id="currentPage"></span><span class="bar">/</span><span id="totalPages"></span> Pages</span>
</li>
</ul>
<div class="containers">
@ -51,261 +43,318 @@
</div>
<div class="popup_foot">
<a href="#" id="selectBtn" class="newbtns bg4" onclick="ExmnrPopPopup.selectExmnr();">선택</a>
<a href="#" class="newbtns bg1 modalclose">닫기</a>
<a href="#" class="newbtns bg1 modalclose" onclick="window.close();">닫기</a>
</div>
</div>
</div>
<script type="text/javascript">
/**
* 조사원 팝업 선택 모듈
*/
var ExmnrPopPopup = {
grid: null,
selectedRows: [],
/**
* 초기화
*/
init: function() {
this.initGrid();
this.searchExmnrList();
this.bindEvents();
},
/**
* 이벤트 바인딩
*/
bindEvents: function() {
var self = this;
// 엔터키 검색
$('#schExmnr').on('keypress', function(e) {
if (e.which === 13) {
self.searchExmnrList();
}
});
},
/**
* 그리드 초기화
* 조사원 팝업 선택 모듈
* 조사원 목록을 조회하고 선택하는 기능을 제공합니다.
*/
initGrid: function() {
var self = this;
(function(window, $) {
'use strict';
var SEARCH_COND = {};
// 데이터소스 설정
var dataSource = {
api: {
readData: {
url: '<c:url value="/crdn/crndRegistAndView/exmnrPop/list" />',
method: 'POST',
initParams: self.getSearchParams()
// 검색정보 설정
var setSearchCond = function() {
var schExmnr = $.trim(nvl($("#schExmnr").val(), ""));
SEARCH_COND.schExmnr = schExmnr;
SEARCH_COND.delYn = 'N'; // 삭제되지 않은 조사원만 조회
};
/**
* 조사원 팝업 관리 네임스페이스
*/
var ExmnrPopPopup = {
/**
* 선택된 행 정보
*/
selectedRows: [],
/**
* 그리드 관련 객체
*/
grid: {
/**
* 그리드 인스턴스
*/
instance: null,
/**
* 그리드 설정 초기화
* @returns {Object} 그리드 설정 객체
*/
initConfig: function() {
// 데이터 소스 설정
var dataSource = this.createDataSource();
// 그리드 설정 객체 생성
var gridConfig = new XitTuiGridConfig();
// 기본 설정
gridConfig.setOptDataSource(dataSource); // 데이터소스 연결
gridConfig.setOptGridId('grid'); // 그리드를 출력할 Element ID
gridConfig.setOptGridHeight(320); // 그리드 높이(단위: px)
gridConfig.setOptRowHeight(30); // 그리드 행 높이(단위: px)
gridConfig.setOptRowHeaderType('checkbox'); // 체크박스 선택
gridConfig.setOptUseClientSort(true); // 클라이언트사이드 정렬 true
gridConfig.setOptColumns(this.getGridColumns());
return gridConfig;
},
/**
* 그리드 컬럼 정의
* @returns {Array} 그리드 컬럼 배열
*/
getGridColumns: function() {
return [
{
header: '번호',
name: '_rowNum',
align: 'center',
width: 60,
sortable: false,
formatter: function(e) {
return e.row.rowKey + 1;
}
},
{
header: '조사원 ID',
name: 'exmnrId',
align: 'center',
width: 120,
sortable: true
},
{
header: '조사원명',
name: 'exmnr',
align: 'left',
width: 200,
sortable: true
},
{
header: '시군구',
name: 'sggCdNm',
align: 'center',
width: 100,
sortable: true
},
{
header: '등록일시',
name: 'regDt',
align: 'center',
width: 150,
sortable: true,
formatter: function(e) {
if (e.value) {
return e.value.substring(0, 19); // YYYY-MM-DD HH:MM:SS 형식
}
return '';
}
}
];
},
/**
* 데이터 소스 생성
* @returns {Object} 데이터 소스 설정 객체
*/
createDataSource: function() {
return {
api: {
readData: {
url: '<c:url value="/crdn/crndRegistAndView/exmnrPop/list.ajax"/>',
method: 'POST',
contentType: 'application/x-www-form-urlencoded',
processData: true
}
},
initialRequest: false, // 초기 데이터 요청 여부
serializer: function(params) {
setSearchCond();
return $.param(SEARCH_COND);
}
};
},
/**
* 그리드 인스턴스 생성
*/
create: function() {
var gridConfig = this.initConfig();
var Grid = tui.Grid;
this.instance = gridConfig.instance(Grid);
// 그리드 테마 설정
Grid.applyTheme('striped');
this.gridBindEvents();
},
/**
* 그리드 이벤트 바인딩
*/
gridBindEvents: function() {
var self = this;
// 데이터 로딩 완료 이벤트 - 체크박스 초기화
this.instance.on('successResponse', function(ev) {
var responseObj = JSON.parse(ev.xhr.response);
if( responseObj ){
var totalCount = responseObj.data.contents.length;
$("#totalCount").text('총 ' + totalCount.toLocaleString() + '건');
}
// 선택된 행 초기화
ExmnrPopPopup.selectedRows = [];
});
// 체크 이벤트
this.instance.on('check', function(ev) {
ExmnrPopPopup.onRowCheck(ev);
});
// 체크 해제 이벤트
this.instance.on('uncheck', function(ev) {
ExmnrPopPopup.onRowUncheck(ev);
});
// 전체 체크 이벤트
this.instance.on('checkAll', function(ev) {
ExmnrPopPopup.onCheckAll(ev);
});
// 전체 체크 해제 이벤트
this.instance.on('uncheckAll', function(ev) {
ExmnrPopPopup.onUncheckAll(ev);
});
},
/**
* 검색 실행
*/
search: function() {
this.instance.readData(1, SEARCH_COND, true);
}
},
contentType: 'application/x-www-form-urlencoded',
serializer: function(params) {
return $.param(params.data);
}
};
// 그리드 설정
var gridConfig = new XitTuiGridConfig();
gridConfig.setOptDataSource(dataSource);
gridConfig.setOptGridId('exmnrGrid');
gridConfig.setOptGridHeight(400);
gridConfig.setOptRowHeight(30);
gridConfig.setOptRowHeaderType('checkbox'); // 체크박스 선택
gridConfig.setOptUseClientSort(true);
// 클라이언트 사이드 페이징 설정
gridConfig.setOptPageOptions({
useClient: true, // 클라이언트 페이징 사용
perPage: 10 // 페이지당 표시 건수
});
gridConfig.setOptColumns(this.getGridColumns());
// 그리드 생성
this.grid = new XitTuiGrid(gridConfig);
// 그리드 이벤트 바인딩
this.grid.on('check', function(ev) {
self.onRowCheck(ev);
});
this.grid.on('uncheck', function(ev) {
self.onRowUncheck(ev);
});
this.grid.on('checkAll', function(ev) {
self.onCheckAll(ev);
});
this.grid.on('uncheckAll', function(ev) {
self.onUncheckAll(ev);
});
},
/**
* 그리드 컬럼 정의
*/
getGridColumns: function() {
return [
{
header: '번호',
name: '_rowNum',
align: 'center',
width: 60,
sortable: false,
formatter: function(e) {
return e.row.rowKey + 1;
/**
* 이벤트 바인딩
*/
bindEvents: function() {
var self = this;
// 검색 버튼 클릭 이벤트
$('#search_btn').on('click', function() {
self.search();
});
// 엔터키 검색
$('#schExmnr').on('keypress', function(e) {
if (e.which === 13) {
self.search();
}
});
},
/**
* 검색 실행
*/
search: function() {
this.grid.search();
},
/**
* 행 체크 이벤트
*/
onRowCheck: function(ev) {
console.log(ev);
var rowData = this.grid.instance.getRow(ev.rowKey);
// 중복 방지
var existIndex = this.selectedRows.findIndex(function(row) {
return row.exmnrId === rowData.exmnrId;
});
if (existIndex === -1) {
this.selectedRows.push(rowData);
}
console.log(this.selectedRows);
},
{
header: '조사원 ID',
name: 'exmnrId',
align: 'center',
width: 120,
sortable: true
/**
* 행 체크 해제 이벤트
*/
onRowUncheck: function(ev) {
var rowData = this.grid.instance.getRow(ev.rowKey);
this.selectedRows = this.selectedRows.filter(function(row) {
return row.exmnrId !== rowData.exmnrId;
});
},
{
header: '조사원명',
name: 'exmnr',
align: 'left',
width: 200,
sortable: true
/**
* 전체 체크 이벤트
*/
onCheckAll: function(ev) {
var self = this;
this.selectedRows = [];
// 현재 페이지의 모든 행 데이터 추가
this.grid.instance.getData().forEach(function(row) {
self.selectedRows.push(row);
});
},
{
header: '시군구 코드',
name: 'sggCd',
align: 'center',
width: 100,
sortable: true
/**
* 전체 체크 해제 이벤트
*/
onUncheckAll: function(ev) {
this.selectedRows = [];
},
{
header: '등록일시',
name: 'regDt',
align: 'center',
width: 150,
sortable: true,
formatter: function(e) {
if (e.value) {
return e.value.substring(0, 19); // YYYY-MM-DD HH:MM:SS 형식
}
return '';
/**
* 조사원 선택
*/
selectExmnr: function() {
if (this.selectedRows.length === 0) {
alert('선택된 조사원이 없습니다.');
return;
}
}
];
},
/**
* 검색 조건 가져오기
*/
getSearchParams: function() {
return {
schExmnr: $('#schExmnr').val() || '',
delYn: 'N' // 삭제되지 않은 조사원만 조회
// 부모 창으로 선택된 조사원 데이터 전달
if (window.opener && typeof window.opener.onExmnrSelected === 'function') {
window.opener.onExmnrSelected(this.selectedRows);
}
// 팝업 닫기
window.close();
},
/**
* 모듈 초기화
*/
init: function() {
this.grid.create();
this.bindEvents();
this.search();
},
};
},
/**
* 조사원 목록 검색
*/
searchExmnrList: function() {
var self = this;
var params = this.getSearchParams();
// 그리드 데이터 새로고침
this.grid.reloadData(params).then(function() {
// 총 건수 업데이트
var totalCount = self.grid.getRowCount();
$('#totalCount').text('총 ' + totalCount + '건');
// 선택 초기화
self.selectedRows = [];
}).catch(function(error) {
console.error('조사원 목록 조회 실패:', error);
alert('조사원 목록을 조회하는 중 오류가 발생했습니다.');
});
},
/**
* 검색 조건 초기화
*/
resetSearch: function() {
$('#schExmnr').val('');
this.searchExmnrList();
},
/**
* 행 체크 이벤트
*/
onRowCheck: function(ev) {
var rowData = this.grid.getRow(ev.rowKey);
// 중복 방지
var existIndex = this.selectedRows.findIndex(function(row) {
return row.exmnrId === rowData.exmnrId;
});
if (existIndex === -1) {
this.selectedRows.push(rowData);
}
},
/**
* 행 체크 해제 이벤트
*/
onRowUncheck: function(ev) {
var rowData = this.grid.getRow(ev.rowKey);
this.selectedRows = this.selectedRows.filter(function(row) {
return row.exmnrId !== rowData.exmnrId;
});
},
/**
* 전체 체크 이벤트
*/
onCheckAll: function(ev) {
var self = this;
this.selectedRows = [];
// 현재 페이지의 모든 행 데이터 추가
this.grid.getData().forEach(function(row) {
self.selectedRows.push(row);
});
},
/**
* 전체 체크 해제 이벤트
*/
onUncheckAll: function(ev) {
this.selectedRows = [];
},
/**
* 조사원 선택
*/
selectExmnr: function() {
if (this.selectedRows.length === 0) {
alert('선택된 조사원이 없습니다.');
return;
}
// 부모 창으로 선택된 조사원 데이터 전달
if (window.opener && typeof window.opener.onExmnrSelected === 'function') {
window.opener.onExmnrSelected(this.selectedRows);
}
// 팝업 닫기
window.close();
}
};
// 페이지 로드 완료 시 초기화
$(document).ready(function() {
ExmnrPopPopup.init();
});
// 전역 네임스페이스에 등록
window.ExmnrPopPopup = ExmnrPopPopup;
})(window, jQuery);
// 페이지 로드 완료 시 초기화
$(document).ready(function() {
ExmnrPopPopup.init();
});
</script>

@ -128,6 +128,9 @@
'use strict';
var CrdnPopup = {
// 자식 팝업창 참조 저장 배열
childPopups: [],
init: function() {
this.initCodeSelect();
this.setFormData();
@ -177,20 +180,25 @@
},
cancel: function() {
window.close();
// 공통 함수를 사용하여 자식 팝업창들을 닫고 현재 창 닫기
this.childPopups = closeChildPopupsAndSelf(this.childPopups);
},
/**
* 조사원 선택 팝업 열기
*/
openExmnrPopup: function() {
openExmnrPopup: function () {
var popupUrl = '<c:url value="/crdn/crndRegistAndView/exmnrPop/popup.do" />';
var popupName = 'exmnrPopup';
var popupOptions = 'width=900,height=700,scrollbars=yes,resizable=yes,left=' +
Math.round((screen.width - 900) / 2) + ',top=' +
Math.round((screen.height - 700) / 2);
window.open(popupUrl, popupName, popupOptions);
var popupOptions = 'width=900,height=700,scrollbars=yes,resizable=yes,left=' +
Math.round((screen.width - 900) / 2 + 200) + ',top=' +
Math.round((screen.height - 700) / 2);
// 팝업창을 열고 참조를 저장
var popup = window.open(popupUrl, popupName, popupOptions);
if (popup) {
this.childPopups.push(popup);
}
},
save: function() {
@ -301,14 +309,11 @@
*/
window.onExmnrSelected = function(selectedExmnrs) {
if (selectedExmnrs && selectedExmnrs.length > 0) {
// 첫 번째 선택된 조사원의 이름을 입력 필드에 설정
var exmnr = selectedExmnrs[0];
$('#exmnr').val(exmnr.exmnr);
console.log('선택된 조사원:', exmnr);
// 추가적인 처리가 필요하다면 여기에 구현
// 예: 조사원 ID를 숨겨진 필드에 저장 등
// 선택된 조사원들의 이름을 쉼표로 구분하여 입력 필드에 설정
var exmnrNames = selectedExmnrs.map(function (exmnr) {
return exmnr.exmnr;
}).join(',');
$('#exmnr').val(exmnrNames);
}
};

@ -257,6 +257,13 @@ ol {
min-width: 60px;
}
.smallb-2 {
padding: 5px 10px;
font-size: 14px;
min-width: 60px;
min-height: 31px;
}
.fullb {
display: block;
}

@ -681,3 +681,37 @@ function commonCodeSelectAjax(cdGroupId, selectId, firstOptionText, selectedValu
});
}
/**
* 자식 팝업창들을 모두 닫고 현재 창을 닫는 공통 함수
*
* @param {Array} childPopups - 자식 팝업창 참조 배열
* @returns {Array} 초기화된 배열
*/
function closeChildPopupsAndSelf(childPopups) {
// 자식 팝업창들이 배열이 아닌 경우 빈 배열로 초기화
if (!Array.isArray(childPopups)) {
childPopups = [];
}
// 열려있는 자식 팝업창들을 먼저 닫기
for (var i = 0; i < childPopups.length; i++) {
try {
if (childPopups[i] && !childPopups[i].closed) {
childPopups[i].close();
}
} catch (e) {
// 팝업창 접근 오류 무시 (이미 닫혔거나 접근 권한 없음)
console.warn('팝업창 닫기 중 오류 발생:', e.message);
}
}
// 자식 팝업 배열 초기화
childPopups.length = 0;
// 자신의 창 닫기
window.close();
// 초기화된 배열 반환
return childPopups;
}

@ -9,7 +9,7 @@
display: flex;
align-items: flex-start;
justify-content: center;
padding-top: 20px;
padding-top: 10px;
overflow-y: auto;
}

Loading…
Cancel
Save