통지 색상 css 적용 다시 백엔드 처리로 변경

dev
박성영 2 months ago
parent 63949ac522
commit 3a98c21457

@ -9,7 +9,7 @@ import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.*;
/**
@ -30,17 +30,76 @@ import java.util.List;
public class NotiServiceImpl extends EgovAbstractServiceImpl implements NotiService {
private final NotiMapper mapper;
// ==================== 이행정보(TB_IMPLT_INFO) 관련 메서드 ====================
@Override
public int selectImpltInfoListTotalCount(NotiImpltInfoVO vo) {
return mapper.selectImpltInfoListTotalCount(vo);
}
}
@Override
public List<NotiImpltInfoVO> selectImpltInfoList(NotiImpltInfoVO vo) {
return mapper.selectImpltInfoList(vo);
List<NotiImpltInfoVO> list = mapper.selectImpltInfoList(vo);
// 중요로직: 같은 단속년도(crdnYr), 단속번호(crdnNo) 그룹별로 그리드 행에 CSS 클래스를 적용
applyRowColorByGroup(list);
return list;
}
/**
* ,
* : .
* @param list
*/
private void applyRowColorByGroup(List<NotiImpltInfoVO> list) {
// 단속년도 + 단속번호 조합을 키로 하여 그룹 인덱스 매핑
Map<String, Integer> groupIndexMap = new LinkedHashMap<>();
int groupIndex = 0;
// 첫 번째 패스: 각 단속년도+단속번호 조합에 그룹 인덱스 할당
for (NotiImpltInfoVO item : list) {
if (item.getCrdnYr() != null && item.getCrdnNo() != null) {
String groupKey = item.getCrdnYr() + "-" + item.getCrdnNo();
if (!groupIndexMap.containsKey(groupKey)) {
groupIndexMap.put(groupKey, groupIndex++);
}
}
}
// 두 번째 패스: 각 항목에 _attributes 설정
for (NotiImpltInfoVO item : list) {
try {
if (item.getCrdnYr() != null && item.getCrdnNo() != null) {
String groupKey = item.getCrdnYr() + "-" + item.getCrdnNo();
Integer currentGroupIndex = groupIndexMap.get(groupKey);
if (currentGroupIndex != null) {
// TUI Grid _attributes 설정
Map<String, Object> attributes = new HashMap<>();
Map<String, Object> className = new HashMap<>();
List<String> rowClass = new ArrayList<>();
// 그룹 인덱스의 홀/짝에 따라 색상 클래스 적용
if (currentGroupIndex % 2 == 0) {
rowClass.add("tui-grid-custom-color-blue");
} else {
rowClass.add("tui-grid-custom-color-red");
}
className.put("row", rowClass);
attributes.put("className", className);
item.set_attributes(attributes);
}
}
} catch (Exception e) {
// 예외 발생 시 로그를 남기고 계속 진행
log.warn("Failed to apply row color for crdnYr: {}, crdnNo: {}",
item.getCrdnYr(), item.getCrdnNo(), e);
}
}
}
// ==================== 이행 대상자 정보(TB_IMPLT_TRPR_INFO) 관련 메서드 ====================

@ -20,7 +20,7 @@
<li class="th">단속 년도</li>
<li>
<input type="text" id="schCrdnYr" name="schCrdnYr" maxlength="4" class="input calender yearpicker" style="width: 80px;" autocomplete="off" value="${dateUtil:getCurrentDateTime('yyyy')}"/>
</li>
</li>
<li class="th">진행단계</li>
<li>
<select id="schImpltTaskSeCd" name="schImpltTaskSeCd" class="input" style="width: 120px;">
@ -29,7 +29,7 @@
<option value="2">시정명령</option>
<option value="3">시정촉구</option>
</select>
</li>
</li>
<li class="th">행정처분시작일</li>
<li>
<input type="text" id="schImpltBgngYmd1" name="schImpltBgngYmd1" class="input calender datepicker"
@ -41,16 +41,16 @@
<li>
<input type="text" id="schImpltBgngYmd2" name="schImpltBgngYmd2" class="input calender datepicker"
style="width: 120px;" maxlength="10" validation-check="required"
value="${dateUtil:getCurrentDateTime('yyyy-MM-dd')}"
value="${dateUtil:getCurrentDateTime('yyyy-MM-dd')}"
onchange="calculateDaysBetween();" />
</li>
</li>
</ul>
<ul class="rig2">
<li><button type="button" id="search_btn" class="newbtnss bg1">검색</button></li>
<li><button type="button" id="reset_btn" class="newbtnss bg5" style="margin-left: 5px;">초기화</button></li>
</ul>
</div>
<div class="gs_booking">
<div class="gs_booking">
<div class="row">
<div class="col-sm-12">
<div class="box_column">
@ -72,10 +72,8 @@
</div>
</div>
</div>
<!-- 하단 영역 (상세그룹 코드 관리) -->
<!-- 하단 영역 (이행자 목록) -->
<div class="gs_booking" style="margin-top: 30px;">
<div class="row">
<div class="col-sm-12">
@ -90,38 +88,32 @@
</div>
</div>
</div>
<!-- //하단 영역 (상세그룹 코드 관리) -->
</div>
</div>
<!-- /Main body -->
<style type="text/css">
/* 중요로직: TUI Grid 행 색상 클래스 정의 (메인 화면용) */
.tui-grid-custom-color-blue { background-color: #e9f4ff !important; }
.tui-grid-custom-color-red { background-color: #ffecec !important; }
</style>
<script type="text/javascript">
/**
* 이행정보 목록 관리 모듈
* 이행정보 목록을 조회하고 관리하는 기능을 제공합니다.
*
* 중요한 기능:
* - 같은 단속년도, 단속번호를 가진 행들은 그룹별로 색상으로 구분됩니다.
* - 그룹 인덱스가 짝수: 파란색 배경 (tui-grid-custom-color-blue)
* - 그룹 인덱스가 홀수: 빨간색 배경 (tui-grid-custom-color-red)
* - 색상 처리는 프론트엔드에서 데이터 로딩 후 _attributes를 통해 적용됩니다.
*/
(function(window, $) {
'use strict';
var SEARCH_MASTER_COND = {};
// 페이징 정보 저장할 전역 변수
// 페이징 정보 저장
var GRID_PAGINATION_INFO = {
totalCount: 0,
page: 0,
perPage: 0
};
// 초기 검색 조건 값 (페이지 최초 로딩 시 값)
// 초기 검색 조건 값
var INITIAL_SEARCH_VALUES = {
schCrdnYr: '${dateUtil:getCurrentDateTime("yyyy")}',
schImpltTaskSeCd: '',
@ -135,106 +127,48 @@
var schImpltTaskSeCd = $.trim(nvl($("#schImpltTaskSeCd").val(), ""));
var schImpltBgngYmd1 = $.trim(nvl($("#schImpltBgngYmd1").val(), "")).replace(/-/g, "");
var schImpltBgngYmd2 = $.trim(nvl($("#schImpltBgngYmd2").val(), "")).replace(/-/g, "");
SEARCH_MASTER_COND.schCrdnYr = schCrdnYr;
SEARCH_MASTER_COND.schImpltTaskSeCd = schImpltTaskSeCd;
SEARCH_MASTER_COND.schImpltBgngYmd1 = schImpltBgngYmd1;
SEARCH_MASTER_COND.schImpltBgngYmd2 = schImpltBgngYmd2;
//console.log(SEARCH_MASTER_COND.schImpltBgngYmd2);
};
/**
* 조사원 목록 관리 네임스페이스
*/
var NotiList = {
/**
* 선택된 행 정보
*/
schImpltInfoId: '',
schImpltInfoId: '',
selectedRow: null,
/**
* 마스터 그리드 관련 객체
*/
masterGrid: {
/**
* 그리드 인스턴스
*/
masterGrid: {
instance: null,
/**
* 그리드 설정 초기화
* @returns {Object} 그리드 설정 객체
*/
initConfig: function() {
// 현재 선택된 perPage 값 가져오기
var dataSource = this.createDataSource();
var perPage = parseInt($('#perPageSelect').val() || 10, 10);
// 그리드 설정 객체 생성
var gridConfig = new XitTuiGridConfig();
// 기본 설정
gridConfig.setOptGridId('masterGrid'); // 그리드를 출력할 Element ID
gridConfig.setOptGridHeight(170); // 그리드 높이(단위: px)
gridConfig.setOptRowHeight(30); // 그리드 행 높이(단위: px)
gridConfig.setOptRowHeaderType('rowNum'); // 행 첫번째 셀 타입(rowNum: 순번, checkbox: 체크박스, '': 출력 안함)
gridConfig.setOptUseClientSort(false); // 서버사이드 정렬 false
// 페이징 옵션 설정
gridConfig.setOptDataSource(dataSource);
gridConfig.setOptGridId('masterGrid');
gridConfig.setOptGridHeight(170);
gridConfig.setOptRowHeight(30);
gridConfig.setOptRowHeaderType('rowNum');
gridConfig.setOptUseClientSort(false);
gridConfig.setOptPageOptions({
useClient: false, // 클라이언트 페이징 여부(false: 서버 페이징)
perPage: perPage // 페이지당 표시 건수
useClient: false,
perPage: perPage
});
gridConfig.setOptColumns(this.getGridColumns());
return gridConfig;
},
/**
* 그리드 컬럼 정의
* @returns {Array} 그리드 컬럼 배열
*/
getGridColumns: function() {
var self = this;
return [
{
header: '단속년도',
name: 'crdnYr',
align: 'center',
width: 90
},
{
header: '단속번호',
name: 'crdnNo',
align: 'center',
width: 100,
sortable: true
},
{
header: '행위번호',
name: 'actNo',
align: 'center',
width: 60
},
{
header: '진행단계',
name: 'impltTaskSeCdNm',
align: 'center',
width: 100
},
{
header: '지역구분',
name: 'rgnSeCdNm',
align: 'center',
width: 100
},
{
header: '단속동',
name: 'stdgEmdCdNm',
align: 'center',
width: 100
},
{ header: '단속년도', name: 'crdnYr', align: 'center', width: 90 },
{ header: '단속번호', name: 'crdnNo', align: 'center', width: 100, sortable: true },
{ header: '행위번호', name: 'actNo', align: 'center', width: 60 },
{ header: '진행단계', name: 'impltTaskSeCdNm', align: 'center', width: 100 },
{ header: '지역구분', name: 'rgnSeCdNm', align: 'center', width: 100 },
{ header: '단속동', name: 'stdgEmdCdNm', align: 'center', width: 100 },
{
header: '행정처분시작일',
name: 'impltBgngYmd',
@ -253,172 +187,64 @@
return e.value ? moment(e.value).format('YYYY-MM-DD') : '';
}
},
{
header: '위치',
name: 'lotnoWholAddr',
align: 'left',
minWidth: 300,
formatter: function(e) {
return e.value;
}
},
{
header: '용도',
name: 'usgIdxCdNm',
align: 'left',
width: 130,
formatter: function(e) {
return e.value;
{ header: '위치', name: 'lotnoWholAddr', align: 'left', minWidth: 300 },
{ header: '용도', name: 'usgIdxCdNm', align: 'left', width: 130 },
{ header : '행위유형', name : 'actTypeCdNm', align : 'center', width : 140 },
{ header: '등록일시', name: 'regDt', align: 'center', width: 130 },
{ header: '등록자', name: 'rgtrNm', align: 'center', width: 100 }
];
},
createDataSource: function() {
return {
api: {
readData: {
url: '<c:url value="/noti/impltInfolist.ajax"/>',
method: 'POST',
contentType: 'application/x-www-form-urlencoded',
processData: true
}
},
{
header : '행위유형',
name : 'actTypeCdNm',
align : 'center',
width : 140
initialRequest: false,
serializer: function(params) {
setMasterSearchCond();
SEARCH_MASTER_COND.perPage = params.perPage;
SEARCH_MASTER_COND.page = params.page;
return $.param(SEARCH_MASTER_COND);
},
{
header: '등록일시',
name: 'regDt',
align: 'center',
width: 130
},
{
header: '등록자',
name: 'rgtrNm',
align: 'center',
width: 100
}
];
};
},
/**
* 그리드 인스턴스 생성
*/
create: function() {
var gridConfig = this.initConfig();
var Grid = tui.Grid;
this.instance = gridConfig.instance(Grid);
// 그리드 테마 설정
Grid.applyTheme('striped');
this.gridBindEvents();
},
/**
* AJAX로 그리드 데이터 로드
* 중요로직: 데이터를 직접 가져와서 색상 _attributes를 적용한 후 그리드에 바인딩
* @param page 페이지 번호
*/
loadData: function(page) {
var self = this;
// 검색 조건 설정
setMasterSearchCond();
SEARCH_MASTER_COND.page = page || 1;
SEARCH_MASTER_COND.perPage = parseInt($('#perPageSelect').val() || 10, 10);
$.ajax({
url: '<c:url value="/noti/impltInfolist.ajax"/>',
type: 'POST',
data: SEARCH_MASTER_COND,
dataType: 'json',
success: function(response) {
if (response && response.success) {
var data = response.data || {};
var contents = data.contents || [];
var pagination = data.pagination || {};
// 중요로직: 색상 _attributes 적용
var processedData = self.applyRowColorToData(contents);
// 그리드에 데이터 설정
self.instance.resetData(processedData);
// 페이징 정보 업데이트
$("#currentPage").text(pagination.page || 1);
$("#totalPages").text(pagination.totalPages || 0);
$("#totalCount").text('총 ' + (pagination.totalCount || 0).toLocaleString() + '건');
// 페이징 정보 저장
GRID_PAGINATION_INFO.totalCount = pagination.totalCount || 0;
GRID_PAGINATION_INFO.page = pagination.page || 1;
GRID_PAGINATION_INFO.perPage = pagination.perPage || 10;
// 하단 그리드 초기화
NotiList.schImpltInfoId = '';
NotiList.selectedRow = null;
NotiList.detailGrid.instance.readData(1);
} else {
alert('데이터 조회에 실패했습니다.');
}
},
error: function(xhr, status, error) {
console.error('AJAX Error:', error);
alert('데이터 조회 중 오류가 발생했습니다.');
}
});
},
/**
* 단속년도, 단속번호 그룹별로 행 색상 _attributes 적용
* 중요한 로직 주석: 같은 단속년도와 단속번호를 가진 행들에게 그룹별로 다른 색상을 적용합니다.
* @param dataList 원본 데이터 배열
* @returns 색상 _attributes가 적용된 데이터 배열
*/
applyRowColorToData: function(dataList) {
// 단속년도 + 단속번호 조합을 키로 하여 그룹 인덱스 매핑
var groupIndexMap = {};
var groupIndex = 0;
// 첫 번째 패스: 각 단속년도+단속번호 조합에 그룹 인덱스 할당
for (var i = 0; i < dataList.length; i++) {
var item = dataList[i];
if (item.crdnYr && item.crdnNo) {
var groupKey = item.crdnYr + '-' + item.crdnNo;
if (!groupIndexMap[groupKey]) {
groupIndexMap[groupKey] = groupIndex++;
}
}
}
// 두 번째 패스: 각 항목에 _attributes 설정
for (var i = 0; i < dataList.length; i++) {
var item = dataList[i];
if (item.crdnYr && item.crdnNo) {
var groupKey = item.crdnYr + '-' + item.crdnNo;
var currentGroupIndex = groupIndexMap[groupKey];
if (currentGroupIndex !== undefined) {
// 그룹 인덱스의 홀/짝에 따라 색상 클래스 적용
var cssClass = (currentGroupIndex % 2 === 0)
? 'tui-grid-custom-color-blue'
: 'tui-grid-custom-color-red';
// TUI Grid _attributes 설정
item._attributes = {
className: {
row: [cssClass]
}
};
}
}
}
return dataList;
},
/**
* 그리드 이벤트 바인딩
*/
gridBindEvents: function() {
var self = this;
// 페이지 변경 이벤트
this.instance.on('page', function(ev) {
self.loadData(ev.page);
// 데이터 로딩 완료 이벤트
this.instance.on('successResponse', function(ev) {
var responseObj = JSON.parse(ev.xhr.response);
if( responseObj ){
$("#currentPage").text(responseObj.data.pagination.page);
$("#totalPages").text(responseObj.data.pagination.totalPages);
var totalCount = responseObj.data.pagination.totalCount;
$("#totalCount").text('총 ' + totalCount.toLocaleString() + '건');
GRID_PAGINATION_INFO.totalCount = responseObj.data.pagination.totalCount;
GRID_PAGINATION_INFO.page = responseObj.data.pagination.page;
GRID_PAGINATION_INFO.perPage = responseObj.data.pagination.perPage;
NotiList.schImpltInfoId = '';
NotiList.selectedRow = null;
NotiList.detailGrid.instance.readData(1);
}
});
this.instance.on('focusChange', function(ev) {
@ -433,14 +259,12 @@
NotiList.detailGrid.instance.readData(1);
});
// 행 클릭 이벤트
this.instance.on('click', function(ev) {
if (ev.rowKey !== undefined && ev.rowKey !== null) {
NotiList.selectedRow = self.instance.getRow(ev.rowKey);
}
});
// 행 더블클릭 이벤트
this.instance.on('dblclick', function(ev) {
var rowKey = ev.rowKey;
var rowData = self.instance.getRow(rowKey);
@ -448,20 +272,16 @@
NotiList.openImpltTaskPopup(NotiList.selectedRow.crdnYr, NotiList.selectedRow.crdnNo, NotiList.selectedRow.impltTaskSeCd);
}
});
}
},
openImpltTaskPopup: function(crdnYr, crdnNo, impltTaskSeCd) {
if (!this.selectedRow) {
alert('수정할 단속 건을 선택해주세요.');
return;
}
// 기존 이행정보가 있는지 확인하여 모드 결정
var self = this;
}
$.ajax({
url: '<c:url value="/crdn/crndRegistAndView/crdnImpltTask/selectImpltInfo.ajax"/>',
type: 'GET',
@ -479,94 +299,38 @@
openPopup(url, 1200, 610, 'impltTaskPopup');
}
});
},
},
detailGrid : {
/**
* 그리드 인스턴스
*/
instance : null,
/**
* 그리드 설정 초기화
* @returns {Object} 그리드 설정 객체
*/
initConfig : function() {
// 데이터 소스 설정
var dataSource = this.createDataSource();
// 그리드 설정 객체 생성
var gridConfig = new XitTuiGridConfig();
// 기본 설정
gridConfig.setOptDataSource(dataSource); // 데이터소스 연결
gridConfig.setOptGridId('detailGrid'); // 그리드를 출력할 Element ID
gridConfig.setOptGridHeight(170); // 그리드 높이(단위: px)
gridConfig.setOptRowHeight(30); // 그리드 행 높이(단위: px)
gridConfig.setOptRowHeaderType('rowNum'); // 행 첫번째 셀 타입(rowNum: 순번, checkbox: 체크박스, '': 출력 안함)
gridConfig.setOptUseClientSort(true); // 서버사이드 정렬 false
gridConfig.setOptDataSource(dataSource);
gridConfig.setOptGridId('detailGrid');
gridConfig.setOptGridHeight(170);
gridConfig.setOptRowHeight(30);
gridConfig.setOptRowHeaderType('rowNum');
gridConfig.setOptUseClientSort(true);
gridConfig.setOptColumns(this.getGridColumns());
return gridConfig;
},
/**
* 그리드 컬럼 정의
* @returns {Array} 그리드 컬럼 배열
*/
getGridColumns : function() {
var self = this;
return [
{
header : '행위번호',
name : 'actNo',
align : 'center',
width : 60
},
{
header : '행위유형',
name : 'actTypeCdNm',
align : 'center',
width : 140
},
{
header : '소유자,행위자 구분',
name : 'impltTrprSeCdNm',
align : 'center',
width : 120
},
{
header : '성명',
name : 'impltTrprFlnm',
align : 'center',
width : 200
},
{
header : '우편번호',
name : 'impltTrprZip',
align : 'center',
width : 80
},
{
header : '주소',
name : 'impltTrprAddr',
align : 'center',
width : 350
},
{
header : '상세주소',
name : 'impltTrprDaddr',
align : 'center',
width : 350
}
return [
{ header : '행위번호', name : 'actNo', align : 'center', width : 60 },
{ header : '행위유형', name : 'actTypeCdNm', align : 'center', width : 140 },
{ header : '소유자,행위자 구분', name : 'impltTrprSeCdNm', align : 'center', width : 120 },
{ header : '성명', name : 'impltTrprFlnm', align : 'center', width : 200 },
{ header : '우편번호', name : 'impltTrprZip', align : 'center', width : 80 },
{ header : '주소', name : 'impltTrprAddr', align : 'center', width : 350 },
{ header : '상세주소', name : 'impltTrprDaddr', align : 'center', width : 350 }
];
},
/**
* 데이터 소스 생성
* @returns {Object} 데이터 소스 설정 객체
*/
createDataSource : function() {
return {
api : {
@ -577,77 +341,54 @@
processData : true
}
},
initialRequest : false, // 초기 데이터 요청 여부
initialRequest : false,
serializer : function(params) {
// 검색 폼 데이터
//setDetailSearchCond();
var searchParams = $.param({schImpltInfoId: NotiList.schImpltInfoId, schActNo: NotiList.schActNo });
//console.log(searchParams);
var searchParams = $.param({schImpltInfoId: NotiList.schImpltInfoId, schActNo: NotiList.schActNo });
return searchParams;
}
};
},
/**
* 그리드 인스턴스 생성
*/
create : function() {
var gridConfig = this.initConfig();
var Grid = tui.Grid;
this.instance = gridConfig.instance(Grid);
// 그리드 테마 설정
Grid.applyTheme('striped');
},
}
},
/**
* 목록 새로고침
*/
refreshList: function() {
if (this.masterGrid.instance) {
this.masterGrid.loadData(GRID_PAGINATION_INFO.page);
this.masterGrid.instance.readData(GRID_PAGINATION_INFO.page);
}
},
/**
* 이벤트 핸들러 설정
*/
eventBindEvents: function() {
var self = this;
// 수정 버튼 클릭 이벤트
$("#updaterBtn").on('click', function() {
// 선택된 행 확인
if (!self.selectedRow) {
alert('수정할 단속 건을 선택해주세요.');
return;
}
// 선택된 행의 데이터로 팝업 열기
NotiList.openImpltTaskPopup(NotiList.selectedRow.crdnYr, NotiList.selectedRow.crdnNo, NotiList.selectedRow.impltTaskSeCd);
});
// 검색 버튼 클릭 이벤트
$("#search_btn").on('click', function() {
self.masterGrid.loadData(1);
self.masterGrid.instance.readData(1);
});
// 초기화 버튼 클릭 이벤트
$("#reset_btn").on('click', function() {
// 페이지 최초 로딩 시 값으로 검색 조건 초기화
$("#schCrdnYr").val(INITIAL_SEARCH_VALUES.schCrdnYr);
$("#schImpltTaskSeCd").val(INITIAL_SEARCH_VALUES.schImpltTaskSeCd);
$("#schImpltBgngYmd1").val(INITIAL_SEARCH_VALUES.schImpltBgngYmd1);
$("#schImpltBgngYmd2").val(INITIAL_SEARCH_VALUES.schImpltBgngYmd2);
// 그리드 데이터 새로고침
self.masterGrid.loadData(1);
self.masterGrid.instance.readData(1);
});
// 엔터키 검색
$(".gs_b_top input").on('keypress', function(e) {
if (e.which === 13) {
e.preventDefault();
@ -655,39 +396,29 @@
}
});
// perPage 변경 이벤트
$('#perPageSelect').on('change', function() {
self.masterGrid.loadData(1);
var perPage = parseInt($(this).val(), 10);
self.masterGrid.instance.setPerPage(perPage);
});
},
/**
* 모듈 초기화
*/
init: function() {
// 그리드 생성
this.masterGrid.create();
this.detailGrid.create();
// 이벤트 핸들러 설정
this.eventBindEvents();
// 초기 데이터 로드
var initialPage = ${param.page eq null or param.page eq 0 ? 1 : param.page};
this.masterGrid.loadData(initialPage);
this.masterGrid.instance.readData(${param.page eq null or param.page eq 0 ? 1 : param.page});
}
};
// 팝업 콜백 함수 (팝업에서 호출)
window.refreshCrdnList = function() {
NotiList.refreshList();
};
// DOM 준비 완료 시 초기화
$(document).ready(function() {
NotiList.init();
});
})(window, jQuery);
</script>
</script>

Loading…
Cancel
Save