Merge remote-tracking branch 'origin/dev' into dev

dev
kjh 3 months ago
commit e75c0380a8

@ -327,6 +327,7 @@ public class CrdnActInfoController {
@GetMapping("/photoView.do")
public String photoView(
@Parameter(description = "행위정보ID") @RequestParam String actInfoId,
@Parameter(description = "조치정보ID") @RequestParam(required = false) String actnInfoId,
@Parameter(description = "사진순번") @RequestParam String crdnPhotoSn,
@Parameter(description = "단속조치사진구분") @RequestParam String crdnPhotoSeCd,
Model model) {
@ -336,6 +337,7 @@ public class CrdnActInfoController {
// 중요한 로직 주석: 해당 행위정보의 모든 사진 목록 조회
CrdnPhotoVO searchVO = CrdnPhotoVO.builder()
.actInfoId(actInfoId)
.actnInfoId(actnInfoId)
.crdnPhotoSeCd(crdnPhotoSeCd) // 단속 사진
.build();
@ -610,9 +612,7 @@ public class CrdnActInfoController {
List<CrdnPhotoVO> photoList = photoService.selectPhotoList(photoVO);
return ApiResponseUtil.success(
new HashMap<String, Object>() {{ put("photoList", photoList); }}
);
return ApiResponseUtil.success(photoList);
} catch (Exception e) {
log.error("조치사진 목록 조회 중 오류 발생: {}", actnInfoId, e);
@ -662,54 +662,4 @@ public class CrdnActInfoController {
}
}
/**
* (View)
* : .
* @param actnInfoId ID
* @param crdnPhotoSn
* @param model
* @return JSP
*/
@Operation(summary = "조치사진 원본 보기", description = "조치사진을 원본 크기로 보여주는 페이지를 반환합니다.")
@GetMapping("/actnPhotoView.do")
public String actnPhotoView(
@Parameter(description = "조치정보ID") @RequestParam String actnInfoId,
@Parameter(description = "사진순번") @RequestParam String crdnPhotoSn,
Model model) {
log.debug("조치사진 원본 보기 요청 - actnInfoId: {}, crdnPhotoSn: {}", actnInfoId, crdnPhotoSn);
try {
// 중요한 로직 주석: 조치사진 목록 조회 (같은 조치정보의 다른 사진들도 함께)
CrdnPhotoVO searchVO = CrdnPhotoVO.builder()
.actnInfoId(actnInfoId)
.crdnPhotoSeCd("2") // 조치사진
.build();
List<CrdnPhotoVO> photoList = photoService.selectPhotoList(searchVO);
// 중요한 로직 주석: 현재 보고 있는 사진의 인덱스 찾기
int currentIndex = 0;
for (int i = 0; i < photoList.size(); i++) {
if (photoList.get(i).getCrdnPhotoSn().equals(crdnPhotoSn)) {
currentIndex = i;
break;
}
}
// 중요한 로직 주석: JSP에서 사용할 데이터 전달
model.addAttribute("actnInfoId", actnInfoId);
model.addAttribute("crdnPhotoSn", crdnPhotoSn);
model.addAttribute("photoList", photoList);
model.addAttribute("currentIndex", currentIndex);
model.addAttribute("totalCount", photoList.size());
return "crdn/crndRegistAndView/crdnActInfo/actnPhotoView";
} catch (Exception e) {
log.error("조치사진 원본 보기 중 오류 발생: actnInfoId={}, crdnPhotoSn={}", actnInfoId, crdnPhotoSn, e);
model.addAttribute("errorMessage", "조치사진을 불러올 수 없습니다.");
return "error/500";
}
}
}

@ -124,15 +124,188 @@
* 조치정보 관리 팝업 JavaScript
* 중요한 로직 주석: crdnActInfoRegistPopup.jsp와 동일한 구조, levyPrvntcPopup.jsp의 탭 패턴 적용
*/
var CrdnActnInfoManage = {
var crdnActnInfoRegistPopup = {
// 기본 정보
actInfoId: '${actInfoId}',
crdnYr: '${crdnYr}',
crdnNo: '${crdnNo}',
pstnInfoId: '${pstnInfoId}',
actnInfoIdSelect: null,
// 그리드 인스턴스
grid: null,
/**
* 그리드 관련 객체
*/
grid: {
/**
* 그리드 인스턴스
*/
instance: null,
/**
* 그리드 설정 초기화
* @returns {Object} 그리드 설정 객체
*/
initConfig: function() {
// 데이터 소스 설정
var dataSource = this.createDataSource();
// 그리드 설정 객체 생성
var gridConfig = new XitTuiGridConfig();
// 기본 설정
gridConfig.setOptDataSource(dataSource);
gridConfig.setOptGridId('actnInfoGrid');
gridConfig.setOptGridHeight(150);
gridConfig.setOptRowHeight(30);
gridConfig.setOptUseClientSort(true);
gridConfig.setOptRowHeaderType('');
gridConfig.setOptColumns(this.getGridColumns());
return gridConfig;
},
/**
* 그리드 컬럼 정의
* @returns {Array} 그리드 컬럼 배열
*/
getGridColumns: function() {
return [
{
header: '조치정보ID',
name: 'actnInfoId',
hidden: true
},
{
header: '순번',
name: 'rownum',
width: 60,
align: 'center'
},
{
header: '조치일자',
name: 'actnYmd',
width: 100,
align: 'center',
formatter: function(e) {
return e.value ? moment(e.value).format('YYYY-MM-DD') : '';
}
},
{
header: '조치면적(㎡)',
name: 'actnArea',
width: 100,
align: 'right',
formatter: function(e) {
return e.value ? parseFloat(e.value).toLocaleString() : '-';
}
},
{
header: '조치비고',
name: 'actnRmrk',
minWidth: 200,
},
{
header: '수정일시',
name: 'mdfcnDt',
width: 130,
align: 'center',
}
];
},
/**
* 데이터 소스 생성
* @returns {Object} 데이터 소스 설정 객체
*/
createDataSource: function() {
var self = crdnActnInfoRegistPopup;
return {
api: {
readData: {
url: '<c:url value="/crdn/crndRegistAndView/crdnActInfo/actnInfoList.ajax"/>',
method: 'POST',
contentType: 'application/x-www-form-urlencoded',
processData: true
}
},
initialRequest: false,
serializer: function(params) {
var defaultParams = $.param(params);
var extra = $.param({ actInfoId: self.actInfoId });
return defaultParams + '&' + extra;
}
};
},
/**
* 그리드 인스턴스 생성
*/
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);
var totalCount = 0;
if (responseObj && responseObj.data && responseObj.data.contents) {
totalCount = responseObj.data.contents.length;
$('#actnTotalCount').text('총 ' + totalCount + '건');
}
});
this.instance.on('onGridUpdated', function() {
const firstVisibleColumn = self.instance.getColumns().find(column => !column.hidden);
var allRows = self.instance.getData();
var rowKey = null;
if (allRows && allRows.length > 0) {
allRows.forEach(function(row) {
if( crdnActnInfoRegistPopup.actnInfoIdSelect === null ){
rowKey = allRows[0].rowKey;
crdnActnInfoRegistPopup.actnInfoIdSelect = row.actnInfoId;
}else if (crdnActnInfoRegistPopup.actnInfoIdSelect === row.actnInfoId) {
rowKey = row.rowKey
}
// 2. 행 전체 선택 (파란색 배경)
self.instance.setSelectionRange({
start: [rowKey, 0],
end: [rowKey, self.instance.getColumns().length - 1]
});
// 2. 첫 번째 보이는 컬럼으로 포커스 이동 및 스크롤
self.instance.focus(rowKey, firstVisibleColumn.name, true);
});
}
});
this.instance.on('focusChange', function(ev) {
if (ev.rowKey !== null) {
crdnActnInfoRegistPopup.actnInfoIdSelect = ev.actnInfoId;
var rowData = self.grid.instance.getRow(ev.rowKey);
self.loadActnInfoToForm(rowData);
}
});
this.instance.on('click', function(ev) {
if (ev.rowKey !== null) {
crdnActnInfoRegistPopup.actnInfoIdSelect = ev.actnInfoId;
}
});
}
},
// 선택된 조치사진 파일들
actnSelectedFiles: [],
@ -141,7 +314,7 @@
* 초기화
*/
init: function() {
this.initGrid();
this.grid.create();
this.eventBindEvents();
this.loadActnInfoList();
},
@ -164,11 +337,6 @@
self.switchTab($(this).parent().data('tab'));
});
// 조치정보 추가 버튼
$('#btnAddActn').on('click', function() {
self.clearActnForm();
});
// 조치정보 저장 버튼
$('#btnSaveActn').on('click', function() {
self.saveActnInfo();
@ -218,138 +386,12 @@
}
},
/**
* 조치정보 그리드 초기화
*/
initGrid: function() {
var self = this;
// 데이터 소스 설정
var dataSource = {
api: {
readData: {
url: '<c:url value="/crdn/crndRegistAndView/crdnActInfo/actnInfoList.ajax"/>',
method: 'POST',
contentType: 'application/x-www-form-urlencoded',
processData: true
}
},
initialRequest: false,
serializer: function(params) {
var defaultParams = $.param(params);
var extra = $.param({ actInfoId: self.actInfoId });
return defaultParams + '&' + extra;
}
};
// 그리드 설정 객체 생성
var gridConfig = new XitTuiGridConfig();
// 기본 설정
gridConfig.setOptDataSource(dataSource);
gridConfig.setOptGridId('actnInfoGrid');
gridConfig.setOptGridHeight(150);
gridConfig.setOptRowHeight(30);
gridConfig.setOptUseClientSort(true);
gridConfig.setOptRowHeaderType('');
gridConfig.setOptColumns([
{
header: '조치정보ID',
name: 'actnInfoId',
hidden: true
},
{
header: '순번',
name: 'rownum',
width: 60,
align: 'center'
},
{
header: '조치일자',
name: 'actnYmd',
width: 100,
align: 'center',
formatter: function(e) {
return e.value ? moment(e.value).format('YYYY-MM-DD') : '';
}
},
{
header: '조치면적(㎡)',
name: 'actnArea',
width: 100,
align: 'right',
formatter: function(e) {
return e.value ? parseFloat(e.value).toLocaleString() : '-';
}
},
{
header: '조치비고',
name: 'actnRmrk',
minWidth: 200,
},
{
header: '수정일시',
name: 'mdfcnDt',
width: 130,
align: 'center',
}
]);
// 그리드 인스턴스 생성
var Grid = tui.Grid;
this.grid = gridConfig.instance(Grid);
// 그리드 테마 설정
Grid.applyTheme('striped');
// 그리드 이벤트 바인딩
this.bindGridEvents();
},
/**
* 그리드 이벤트 바인딩
*/
bindGridEvents: function() {
var self = this;
// 데이터 로딩 완료 이벤트
this.grid.on('successResponse', function(ev) {
var responseObj = JSON.parse(ev.xhr.response);
var totalCount = 0;
if (responseObj && responseObj.data && responseObj.data.contents) {
totalCount = responseObj.data.contents.length;
$('#actnTotalCount').text('총 ' + totalCount + '건');
}
});
// 그리드 렌더링 및 데이터 업데이트 완료 이벤트
this.grid.on('onGridUpdated', function() {
var allRows = self.grid.getData();
if (allRows && allRows.length > 0) {
// 첫 번째 행 선택
//self.grid.focus(0, 'actnYmd', true);
//self.loadActnInfoToForm(allRows[0]);
}
});
// 행 포커스 변경 이벤트
this.grid.on('focusChange', function(ev) {
if (ev.rowKey !== null) {
var rowData = self.grid.getRow(ev.rowKey);
self.loadActnInfoToForm(rowData);
}
});
},
/**
* 조치정보 목록 조회
*/
loadActnInfoList: function() {
if (this.grid) {
this.grid.readData();
if (this.grid.instance) {
this.grid.instance.readData();
}
},
@ -398,24 +440,17 @@
if (response && response.data && response.data.length > 0) {
$.each(response.data, function(index, photo) {
var previewHtml =
'<div class="photo-preview-item existing-photo" data-actn-info-id="' + photo.actnInfoId +
'" data-photo-sn="' + photo.crdnPhotoSn + '" data-photo-type="2">' +
'<div class="photo-preview-item existing-photo" data-act-info-id="' + photo.actInfoId + '" data-photo-sn="' + photo.crdnPhotoSn + '" data-photo-type="1">' +
' <div class="photo-thumbnail">' +
' <img src="<c:url value="/crdn/crndRegistAndView/crdnActInfo/photoThumbnail.do"/>?actnInfoId=' +
photo.actnInfoId + '&crdnPhotoSn=' + photo.crdnPhotoSn + '" alt="' + photo.crdnPhotoNm + '">' +
' <img src="<c:url value='/crdn/crndRegistAndView/crdnActInfo/downloadPhoto.do'/>?actInfoId=' + photo.actInfoId + '&crdnPhotoSn=' + photo.crdnPhotoSn + '"' +
' alt="' + photo.orgnlPhotoNm + '" onclick="viewOriginalPhoto(\'' + photo.actnInfoId + '\', \'' + photo.actInfoId + '\', \'' + photo.crdnPhotoSn + '\', \'' + photo.crdnPhotoSeCd + '\')">' +
' </div>' +
' <div class="photo-info">' +
' <div class="photo-name" title="' + photo.crdnPhotoNm + '">' + photo.crdnPhotoNm + '</div>' +
' <div class="photo-type">[조치]</div>' +
' <div class="photo-buttons">' +
' <button type="button" class="view-photo-btn" onclick="CrdnActnInfoManage.viewOriginalActnPhoto(\'' +
photo.actnInfoId + '\', \'' + photo.crdnPhotoSn + '\')">보기</button>' +
' <button type="button" class="delete-photo-btn" onclick="CrdnActnInfoManage.deleteExistingActnPhoto(\'' +
photo.actnInfoId + '\', \'' + photo.crdnPhotoSn + '\')">삭제</button>' +
' </div>' +
' <div class="photo-name" title="' + photo.orgnlPhotoNm + '">' + photo.orgnlPhotoNm + '</div>' +
' <div class="photo-type">[단속]</div>' +
' <button type="button" class="delete-photo-btn" onclick="deleteExistingPhoto(\'' + photo.actInfoId + '\', \'' + photo.crdnPhotoSn + '\', \'1\')">삭제</button>' +
' </div>' +
'</div>';
$('#actnPhotoPreviewContainer').append(previewHtml);
});
}
@ -471,14 +506,9 @@
contentType: false,
success: function(response) {
if (response && response.success) {
alert(mode === 'C' ? '조치정보가 등록되었습니다.' : '조치정보가 수정되었습니다.');
// 폼 초기화
self.clearActnForm();
// 그리드 새로고침
if (self.grid) {
self.grid.readData();
if (self.grid.instance) {
self.grid.instance.readData();
}
} else {
@ -523,8 +553,8 @@
self.clearActnForm();
// 그리드 새로고침
if (self.grid) {
self.grid.readData();
if (self.grid.instance) {
self.grid.instance.readData();
}
} else {
@ -554,7 +584,7 @@
$('#actnPhotoFiles').val('');
this.actnSelectedFiles = [];
self.grid.readData();
self.grid.instance.readData();
console.log('조치정보 폼 초기화 완료');
},
@ -644,7 +674,7 @@
' <div class="photo-info">' +
' <div class="photo-name" title="' + file.name + '">' + file.name + '</div>' +
' <div class="photo-type">[' + photoTypeName + ']</div>' +
' <button type="button" class="delete-photo-btn" onclick="CrdnActnInfoManage.deleteNewPhoto(this, \'' + photoType + '\')">삭제</button>' +
' <button type="button" class="delete-photo-btn" onclick="crdnActnInfoRegistPopup.deleteNewPhoto(this, \'' + photoType + '\')">삭제</button>' +
' </div>' +
'</div>';
@ -704,14 +734,6 @@
});
},
/**
* 조치사진 원본 보기 (crdnActInfoRegistPopup.jsp의 viewOriginalActnPhoto 패턴)
*/
viewOriginalActnPhoto: function(actnInfoId, crdnPhotoSn) {
var url = '<c:url value="/crdn/crndRegistAndView/crdnActInfo/actnPhotoView.do"/>?actnInfoId=' + actnInfoId + '&crdnPhotoSn=' + crdnPhotoSn;
openPopup(url, 1000, 700, '_blank');
},
/**
* 팝업 닫기
*/
@ -727,8 +749,17 @@
}
};
/**
* 원본 사진 보기 (기존 DB 사진)
* 중요한 로직 주석: 등록된 사진을 photoView 페이지에서 원본 크기로 표시하고 다운로드 버튼을 제공한다.
*/
function viewOriginalPhoto(actnInfoId, actInfoId, crdnPhotoSn, crdnPhotoSeCd) {
var url = '<c:url value="/crdn/crndRegistAndView/crdnActInfo/photoView.do"/>?actnInfoId=' + actnInfoId + '&actInfoId=' + actInfoId + '&crdnPhotoSn=' + crdnPhotoSn + '&crdnPhotoSeCd=' + crdnPhotoSeCd ;
openPopup(url, 1000, 700, '_blank');
}
// DOM 준비 완료 시 초기화
$(document).ready(function() {
CrdnActnInfoManage.init();
crdnActnInfoRegistPopup.init();
});
</script>
Loading…
Cancel
Save