재부과 메뉴에서 재부과 여러건 등록 처리,

단속메뉴의 재부과 기능 공유
dev
박성영 2 months ago
parent 56305d5222
commit f95a57b28a

@ -1,7 +1,11 @@
package go.kr.project.levy.levyRelevy.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import egovframework.constant.TilesConstants;
import egovframework.exception.MessageException;
import egovframework.util.ApiResponseUtil;
import egovframework.util.SessionUtil;
import go.kr.project.common.model.CmmnCodeSearchVO;
import go.kr.project.common.service.CommonCodeService;
import go.kr.project.crdn.crndRegistAndView.main.model.CrdnRegistAndViewVO;
@ -9,6 +13,7 @@ import go.kr.project.crdn.crndRegistAndView.main.service.CrdnImpltTaskService;
import go.kr.project.levy.levyRelevy.model.LevyRelevyVO;
import go.kr.project.levy.levyRelevy.service.LevyRelevyService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -17,12 +22,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* packageName : go.kr.project.levy.levyRelevy.controller
@ -49,8 +52,12 @@ public class LevyRelevyController {
/** 이행정보 서비스 */
private final CrdnImpltTaskService crdnImpltTaskService;
/** 공통코드 서비스 */
private final CommonCodeService commonCodeService;
/** JSON 파싱을 위한 ObjectMapper */
private final ObjectMapper objectMapper;
/**
* , .
* @param model
@ -151,4 +158,104 @@ public class LevyRelevyController {
return ApiResponseUtil.successWithGrid(list, paramVO);
}
/**
* ( )
* @param crdnList (JSON )
* @param model
* @return
*/
@GetMapping("/relevyPopup.do")
@Operation(summary = "재부과 팝업 화면", description = "재부과 등록을 위한 팝업 화면을 제공합니다 (복수 건 처리 가능).")
public String relevyPopup(
@Parameter(description = "재부과 대상 목록 (JSON)", required = true) @RequestParam String crdnList,
Model model) {
log.debug("재부과 팝업 화면 요청 - crdnList: {}", crdnList);
model.addAttribute("crdnList", crdnList);
return "levy/levyRelevy/relevyPopup" + TilesConstants.POPUP;
}
/**
* AJAX
* @param crdnYr
* @param crdnNo
* @return ResponseEntity
*/
@GetMapping("/selectCrdnInfo.ajax")
@Operation(summary = "단속 정보 조회 (AJAX)", description = "재부과를 위한 단속 정보를 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "단속 정보 조회 성공"),
@ApiResponse(responseCode = "400", description = "단속 정보 조회 실패"),
@ApiResponse(description = "오류로 인한 실패")
})
public ResponseEntity<?> selectCrdnInfo(
@Parameter(description = "단속 연도", required = true) @RequestParam String crdnYr,
@Parameter(description = "단속 번호", required = true) @RequestParam String crdnNo) {
log.debug("단속 정보 조회 요청: crdnYr={}, crdnNo={}", crdnYr, crdnNo);
LevyRelevyVO searchVO = LevyRelevyVO.builder()
.crdnYr(crdnYr)
.crdnNo(crdnNo)
.build();
LevyRelevyVO crdnInfo = service.selectCrdnInfo(searchVO);
if (crdnInfo == null) {
throw new MessageException("단속 정보가 존재하지 않습니다.");
}
return ApiResponseUtil.success(crdnInfo);
}
/**
* AJAX
* :
*
* @param crdnListJson (JSON )
* @param relevyRsn
* @return ResponseEntity
*/
@PostMapping("/saveBatchRelevy.ajax")
@Operation(summary = "일괄 재부과 저장 (AJAX)", description = "복수 건의 재부과를 일괄 처리하여 저장합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "재부과 저장 성공"),
@ApiResponse(responseCode = "400", description = "재부과 저장 실패"),
@ApiResponse(description = "오류로 인한 실패")
})
public ResponseEntity<?> saveBatchRelevy(
@Parameter(description = "재부과 대상 목록 (JSON)", required = true) @RequestParam String crdnListJson,
@Parameter(description = "재부과 사유", required = true) @RequestParam String relevyRsn) {
log.debug("일괄 재부과 저장 요청 - crdnListJson: {}, relevyRsn: {}", crdnListJson, relevyRsn);
// 필수값 검증
if (relevyRsn == null || relevyRsn.trim().isEmpty()) {
throw new MessageException("재부과 사유를 입력해주세요.");
}
try {
// 중요로직: JSON 문자열을 List<Map>으로 파싱
List<Map<String, String>> crdnList = objectMapper.readValue(
crdnListJson,
new TypeReference<List<Map<String, String>>>() {}
);
if (crdnList == null || crdnList.isEmpty()) {
throw new MessageException("재부과 대상 정보가 없습니다.");
}
// 등록자 정보 설정
String userId = SessionUtil.getUserId();
// 일괄 재부과 처리
List<Map<String, Object>> resultList = service.processBatchRelevy(crdnList, relevyRsn, userId);
return ApiResponseUtil.success(resultList);
} catch (Exception e) {
log.error("일괄 재부과 저장 중 오류 발생", e);
throw new MessageException("재부과 저장 중 오류가 발생했습니다: " + e.getMessage());
}
}
}

@ -41,4 +41,11 @@ public interface LevyRelevyMapper {
*/
List<LevyRelevyVO> selectRelevyChainList(LevyRelevyVO vo);
/**
* .
* @param vo VO (crdnYr, crdnNo )
* @return
*/
LevyRelevyVO selectCrdnInfo(LevyRelevyVO vo);
}

@ -3,6 +3,7 @@ package go.kr.project.levy.levyRelevy.service;
import go.kr.project.levy.levyRelevy.model.LevyRelevyVO;
import java.util.List;
import java.util.Map;
/**
* packageName : go.kr.project.levy.levyRelevy.service
@ -41,4 +42,23 @@ public interface LevyRelevyService {
*/
List<LevyRelevyVO> selectRelevyChainList(LevyRelevyVO vo);
/**
* .
*
* @param vo VO (crdnYr, crdnNo )
* @return
*/
LevyRelevyVO selectCrdnInfo(LevyRelevyVO vo);
/**
* .
* :
*
* @param crdnList (crdnYr, crdnNo )
* @param relevyRsn
* @param userId ID
* @return ( )
*/
List<Map<String, Object>> processBatchRelevy(List<Map<String, String>> crdnList, String relevyRsn, String userId);
}

@ -1,5 +1,8 @@
package go.kr.project.levy.levyRelevy.service.impl;
import egovframework.exception.MessageException;
import go.kr.project.crdn.crndRegistAndView.main.service.CrdnRelevyService;
import go.kr.project.crdn.crndRegistAndView.main.model.CrdnRelevyVO;
import go.kr.project.levy.levyRelevy.mapper.LevyRelevyMapper;
import go.kr.project.levy.levyRelevy.model.LevyRelevyVO;
import go.kr.project.levy.levyRelevy.service.LevyRelevyService;
@ -7,7 +10,10 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -32,6 +38,9 @@ public class LevyRelevyServiceImpl extends EgovAbstractServiceImpl implements Le
private final LevyRelevyMapper mapper;
/** 단속 재부과 서비스 (CRDN 패키지의 재부과 로직 재사용) */
private final CrdnRelevyService crdnRelevyService;
/**
* .
* :
@ -87,4 +96,116 @@ public class LevyRelevyServiceImpl extends EgovAbstractServiceImpl implements Le
return mapper.selectRelevyChainList(vo);
}
/**
* .
*
* @param vo VO (crdnYr, crdnNo )
* @return
*/
@Override
public LevyRelevyVO selectCrdnInfo(LevyRelevyVO vo) {
return mapper.selectCrdnInfo(vo);
}
/**
* .
* : ,
*
* @param crdnList (crdnYr, crdnNo )
* @param relevyRsn
* @param userId ID
* @return ( )
*/
@Override
@Transactional
public List<Map<String, Object>> processBatchRelevy(List<Map<String, String>> crdnList, String relevyRsn, String userId) {
log.info("일괄 재부과 처리 시작 - 대상 건수: {}", crdnList.size());
String currentYear = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy"));
List<String> duplicateList = new ArrayList<>();
// 중요로직: 1단계 - 전체 건에 대해 재부과 중복 체크
log.info("1단계: 전체 재부과 대상 중복 체크 시작");
for (Map<String, String> crdnItem : crdnList) {
String srcCrdnYr = crdnItem.get("crdnYr");
String srcCrdnNo = crdnItem.get("crdnNo");
CrdnRelevyVO checkVO = new CrdnRelevyVO();
checkVO.setCrdnYr(srcCrdnYr);
checkVO.setCrdnNo(srcCrdnNo);
checkVO.setCurrentYear(currentYear);
CrdnRelevyVO existingRelevy = crdnRelevyService.selectRelevyCheckOne(checkVO);
if (existingRelevy != null) {
String duplicateInfo = String.format("%s-%s (기존 재부과: %s-%s)",
srcCrdnYr, srcCrdnNo,
existingRelevy.getCrdnYr(), existingRelevy.getCrdnNo());
duplicateList.add(duplicateInfo);
log.warn("재부과 중복 발견: {}", duplicateInfo);
}
}
// 중요로직: 2단계 - 중복이 발견되면 전체 취소 및 메시지 표출
if (!duplicateList.isEmpty()) {
StringBuilder errorMsg = new StringBuilder();
errorMsg.append("선택한 단속 건 중 이미 당해년도 재부과가 존재하는 건이 있습니다.\n\n");
errorMsg.append("[중복된 재부과 대상 목록]\n");
for (int i = 0; i < duplicateList.size(); i++) {
errorMsg.append(String.format("%d. %s\n", i + 1, duplicateList.get(i)));
}
errorMsg.append("\n재부과를 진행할 수 없습니다.");
log.error("재부과 중복 건 발견으로 전체 취소 - 중복 건수: {}", duplicateList.size());
throw new MessageException(errorMsg.toString());
}
log.info("재부과 중복 체크 완료 - 모든 건이 정상입니다.");
// 중요로직: 3단계 - 각 단속 건에 대해 재부과 처리 수행
List<Map<String, Object>> resultList = new ArrayList<>();
int successCount = 0;
log.info("2단계: 재부과 처리 시작");
for (Map<String, String> crdnItem : crdnList) {
String srcCrdnYr = crdnItem.get("crdnYr");
String srcCrdnNo = crdnItem.get("crdnNo");
try {
log.info("재부과 처리 중: srcCrdnYr={}, srcCrdnNo={}", srcCrdnYr, srcCrdnNo);
// CrdnRelevyService의 processRelevy 메서드를 재사용
CrdnRelevyVO relevyVO = new CrdnRelevyVO();
relevyVO.setSrcCrdnYr(srcCrdnYr);
relevyVO.setSrcCrdnNo(srcCrdnNo);
relevyVO.setRelevyRsn(relevyRsn);
relevyVO.setRgtr(userId);
Map<String, Object> result = crdnRelevyService.processRelevy(relevyVO);
// 성공 결과 저장
Map<String, Object> successResult = new HashMap<>();
successResult.put("srcCrdnYr", srcCrdnYr);
successResult.put("srcCrdnNo", srcCrdnNo);
successResult.put("crdnYr", result.get("newCrdnYr"));
successResult.put("crdnNo", result.get("newCrdnNo"));
successResult.put("success", true);
resultList.add(successResult);
successCount++;
log.info("재부과 처리 성공: srcCrdnYr={}, srcCrdnNo={}, newCrdnNo={}",
srcCrdnYr, srcCrdnNo, result.get("newCrdnNo"));
} catch (Exception e) {
log.error("재부과 처리 실패: srcCrdnYr={}, srcCrdnNo={}", srcCrdnYr, srcCrdnNo, e);
// 트랜잭션 롤백을 위해 예외 재발생
throw new MessageException("재부과 처리 중 오류 발생: " + srcCrdnYr + "-" + srcCrdnNo + " - " + e.getMessage());
}
}
log.info("일괄 재부과 처리 완료 - 성공: {}", successCount);
return resultList;
}
}

@ -332,4 +332,36 @@
ORDER BY c.CRDN_YR DESC, c.CRDN_NO ASC
</select>
<!-- 단속 정보 단건 조회 (재부과 팝업용) -->
<select id="selectCrdnInfo" parameterType="LevyRelevyVO" resultType="LevyRelevyVO">
/* LevyRelevyMapper.selectCrdnInfo : 단속 정보 단건 조회 */
SELECT
c.CRDN_YR, /* 단속 연도 */
c.CRDN_NO, /* 단속 번호 */
c.SGG_CD, /* 시군구 코드 */
sgg.CD_NM AS SGG_CD_NM,
c.RGN_SE_CD, /* 지역 구분 코드 */
rgn.CD_NM AS RGN_SE_CD_NM,
c.DSCL_MTHD_CD, /* 단속 방법 코드 */
dscl.CD_NM AS DSCL_MTHD_CD_NM,
c.DSCL_YMD, /* 적발 일자 */
c.EXMNR, /* 조사원 */
c.CRDN_PRCS_STTS_CD, /* 단속 처리 상태 코드 */
stts.CD_NM AS CRDN_PRCS_STTS_CD_NM,
p.LOTNO_WHOL_ADDR, /* 지번 전체 주소 */
p.STDG_EMD_CD, /* 법정동 읍면동 코드 */
emd.CD_NM AS STDG_EMD_CD_NM,
p.ZIP /* 우편번호 */
FROM tb_crdn c
LEFT JOIN tb_cd_detail sgg ON sgg.CD_GROUP_ID = 'ORG_CD' AND sgg.CD_ID = c.SGG_CD
LEFT JOIN tb_cd_detail rgn ON rgn.CD_GROUP_ID = 'RGN_SE_CD' AND rgn.CD_ID = c.RGN_SE_CD
LEFT JOIN tb_cd_detail dscl ON dscl.CD_GROUP_ID = 'DSCL_MTHD_CD' AND dscl.CD_ID = c.DSCL_MTHD_CD
LEFT JOIN tb_cd_detail stts ON stts.CD_GROUP_ID = 'CRDN_PRCS_STTS_CD' AND stts.CD_ID = c.CRDN_PRCS_STTS_CD
LEFT JOIN tb_pstn_info p ON p.CRDN_YR = c.CRDN_YR AND p.CRDN_NO = c.CRDN_NO AND p.DEL_YN = 'N'
LEFT JOIN tb_cd_detail emd ON emd.CD_GROUP_ID = 'STDG_EMD_CD' AND emd.CD_ID = p.STDG_EMD_CD
WHERE c.DEL_YN = 'N'
AND c.CRDN_YR = #{crdnYr}
AND c.CRDN_NO = #{crdnNo}
</select>
</mapper>

@ -20,12 +20,20 @@
<ul class="lef">
<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:getCurrentDateAdd('yyyy', 'year', -1)}"/>
<input type="text" id="schCrdnYr" name="schCrdnYr" maxlength="4" class="input calender yearpicker" style="width: 80px;" autocomplete="off" value="${dateUtil:getCurrentDateAdd('yyyy', 'year', -1)}" readonly />
</li>
<li class="th">단속 번호</li>
<li>
<input type="text" id="schCrdnNo" name="schCrdnNo" maxlength="6" class="input" style="width: 100px;" autocomplete="off"/>
</li>
<li class="th">재부과 대상</li>
<li>
<select id="schRelevyTrgtYn" name="schRelevyTrgtYn" class="input" style="width: 120px;">
<option value="">전체</option>
<option value="Y" <c:if test="${param.schRelevyTrgtYn eq 'Y'}">selected</c:if>>대상</option>
<option value="N" <c:if test="${param.schRelevyTrgtYn eq 'N'}">selected</c:if>>비대상</option>
</select>
</li>
<li class="th">지역 구분</li>
<li>
<select id="schRgnSeCd" name="schRgnSeCd" class="input" style="width: 120px;">
@ -63,14 +71,6 @@
</c:forEach>
</select>
</li>
<li class="th">재부과 대상</li>
<li>
<select id="schRelevyTrgtYn" name="schRelevyTrgtYn" class="input" style="width: 120px;">
<option value="">전체</option>
<option value="Y" <c:if test="${param.schRelevyTrgtYn eq 'Y'}">selected</c:if>>대상</option>
<option value="N" <c:if test="${param.schRelevyTrgtYn eq 'N'}">selected</c:if>>비대상</option>
</select>
</li>
<li class="th">가중 부과 대상</li>
<li>
<select id="schAgrvtnLevyTrgtYn" name="schAgrvtnLevyTrgtYn" class="input" style="width: 120px;">
@ -113,6 +113,7 @@
<ul class="box_title" style="display: flex; justify-content: space-between; align-items: center;">
<li class="tit">단속 목록</li>
<li class="rig">
<button type="button" id="btnBatchRelevy" class="newbtn bg3">재부과</button>
<span id="totalCount" class="total-count" style="padding-left: 25px;padding-right: 25px;">총 0건</span>
</li>
</ul>
@ -665,6 +666,62 @@
}
},
/**
* 일괄 재부과 팝업 열기 (복수 선택 가능)
*/
openBatchRelevyPopup: function() {
var self = this;
// 체크된 행 가져오기
var checkedRows = self.grid.instance.getCheckedRows();
// 체크된 행 확인
if (!checkedRows || checkedRows.length === 0) {
alert('재부과를 진행할 단속 건을 선택해주세요.');
return;
}
// 중요로직: 재부과 대상 여부 확인 (relevyTrgtYn === 'Y'인 것만 허용)
var invalidRows = checkedRows.filter(function(row) {
return row.relevyTrgtYn !== 'Y';
});
if (invalidRows.length > 0) {
alert('재부과 대상이 아닌 단속 건이 포함되어 있습니다.\n재부과 대상만 선택해주세요.');
return;
}
// 단속년도/번호 배열 생성
var crdnList = checkedRows.map(function(row) {
return {
crdnYr: row.crdnYr,
crdnNo: row.crdnNo
};
});
// 첫 번째 선택 정보
var firstRow = checkedRows[0];
var firstInfo = firstRow.crdnYr + '-' + firstRow.crdnNo;
// 추가 선택 정보
var additionalCount = checkedRows.length - 1;
var selectionInfo = additionalCount > 0 ?
firstInfo + ' 외 ' + additionalCount + '건' :
firstInfo;
// 확인 메시지
if (!confirm('[' + selectionInfo + ']\n재부과를 진행하시겠습니까?')) {
return;
}
// 중요로직: JSON 문자열로 변환하여 URL 파라미터로 전달
var crdnListJson = JSON.stringify(crdnList);
var url = '<c:url value="/levy/levyRelevy/relevyPopup.do"/>' +
'?crdnList=' + encodeURIComponent(crdnListJson);
openPopup(url, 1200, 600, 'batchRelevyPopup');
},
/**
* 이벤트 핸들러 설정
*/
@ -748,6 +805,11 @@
popUrl += params;
openPopup(popUrl, 570, 530, '주소 찾기');
});
// 일괄 재부과 버튼 클릭 이벤트
$("#btnBatchRelevy").on('click', function() {
self.openBatchRelevyPopup();
});
},
/**

@ -0,0 +1,281 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dateUtil" uri="http://egovframework.go.kr/functions/date-util" %>
<div class="popup_wrap">
<div class="popup_inner">
<div class="popup_tit">
<h2 class="tit">재부과 등록</h2>
<a href="#" class="pop-x-btn modalclose"></a>
</div>
<div class="popup_con">
<div class="forms_table_non">
<form id="relevyForm" name="relevyForm">
<input type="hidden" id="mode" name="mode" value="C" />
<input type="hidden" id="crdnListJson" name="crdnListJson" value="" />
<table>
<colgroup>
<col style="width: 20%;" />
<col style="width: 30%;" />
<col style="width: 20%;" />
<col style="width: 30%;" />
</colgroup>
<tr>
<th class="th">단속 년도</th>
<td id="firstCrdnYr"></td>
<th class="th">단속 번호</th>
<td id="firstCrdnNo"></td>
</tr>
<tr>
<th class="th">지역구분</th>
<td id="firstRgnSeCdNm"></td>
<th class="th">법정동</th>
<td id="firstStdgEmdCdNm"></td>
</tr>
<tr>
<th class="th">적발방법</th>
<td id="firstDsclMthdCdNm"></td>
<th class="th">적발일자</th>
<td id="firstDsclYmd"></td>
</tr>
<tr>
<th class="th">조사원</th>
<td id="firstExmnr"></td>
<th class="th">현재 진행단계</th>
<td id="firstCrdnPrcsSttsCdNm"></td>
</tr>
<tr>
<th class="th">위치</th>
<td colspan="3" id="firstLotnoWholAddr"></td>
</tr>
<tr>
<th class="th"><span class="required">*</span> 재부과 사유</th>
<td colspan="3">
<textarea id="relevyRsn" name="relevyRsn" class="textarea" style="width: 100%; height: 80px;" rows="3" placeholder="재부과 사유를 입력해주세요." validation-check="required" maxlength="1000"></textarea>
</td>
</tr>
</table>
<!-- 추가 선택 건수 표시 영역 -->
<div id="additionalInfoArea" style="display: none; margin-top: 15px; padding: 10px; background-color: #f9f9f9; border: 1px solid #ddd; border-radius: 4px;">
<p style="margin: 0; font-size: 14px; color: #333;">
<strong>그 외 재부과 대상:</strong> <span id="additionalCount" style="color: #007bff; font-weight: bold;"></span>
</p>
</div>
</form>
</div>
</div>
<!-- 팝업 버튼 -->
<div class="popup_foot">
<a href="#" id="btnSave" class="newbtns bg1">저장</a>
<a href="#" class="newbtns bg2 modalclose">닫기</a>
</div>
</div>
</div>
<script type="text/javascript">
(function(window, $) {
'use strict';
var BatchRelevyPopup = {
/**
* 재부과 대상 목록
*/
crdnList: [],
/**
* 첫 번째 단속 정보
*/
firstCrdnInfo: null,
/**
* URL에서 파라미터 파싱
*/
parseUrlParams: function() {
var self = this;
var urlParams = new URLSearchParams(window.location.search);
var crdnListParam = urlParams.get('crdnList');
if (crdnListParam) {
try {
self.crdnList = JSON.parse(decodeURIComponent(crdnListParam));
$('#crdnListJson').val(JSON.stringify(self.crdnList));
} catch (e) {
console.error('crdnList 파싱 오류:', e);
alert('재부과 대상 정보 파싱에 실패했습니다.');
window.close();
}
}
if (!self.crdnList || self.crdnList.length === 0) {
alert('재부과 대상 정보가 없습니다.');
window.close();
}
},
/**
* 첫 번째 단속 정보 조회
*/
loadFirstCrdnInfo: function() {
var self = this;
var firstCrdn = self.crdnList[0];
$.ajax({
url: '<c:url value="/levy/levyRelevy/selectCrdnInfo.ajax"/>',
type: 'GET',
data: {
crdnYr: firstCrdn.crdnYr,
crdnNo: firstCrdn.crdnNo
},
success: function(response) {
if (response && response.success && response.data) {
self.firstCrdnInfo = response.data;
self.displayFirstCrdnInfo();
self.displayAdditionalInfo();
} else {
alert('첫 번째 단속 정보 조회에 실패했습니다.');
window.close();
}
},
error: function(xhr, status, error) {
console.error('첫 번째 단속 정보 조회 실패:', error);
alert('첫 번째 단속 정보 조회 중 오류가 발생했습니다.');
window.close();
}
});
},
/**
* 첫 번째 단속 정보 화면 표시
*/
displayFirstCrdnInfo: function() {
var data = this.firstCrdnInfo;
$("#firstCrdnYr").text(data.crdnYr || '');
$("#firstCrdnNo").text(data.crdnNo || '');
$("#firstRgnSeCdNm").text(data.rgnSeCdNm || '');
$("#firstStdgEmdCdNm").text(data.stdgEmdCdNm || '');
$("#firstLotnoWholAddr").text((data.zip ? '(' + data.zip + ') ' : '') + (data.lotnoWholAddr || ''));
$("#firstDsclMthdCdNm").text(data.dsclMthdCdNm || '');
$("#firstDsclYmd").text(data.dsclYmd ? moment(data.dsclYmd).format('YYYY-MM-DD') : '');
$("#firstExmnr").text(data.exmnr || '');
$("#firstCrdnPrcsSttsCdNm").text(data.crdnPrcsSttsCdNm || '');
},
/**
* 추가 선택 건수 표시
*/
displayAdditionalInfo: function() {
var additionalCount = this.crdnList.length - 1;
if (additionalCount > 0) {
$("#additionalCount").text(additionalCount + '건');
$("#additionalInfoArea").show();
} else {
$("#additionalInfoArea").hide();
}
},
/**
* 재부과 저장
*/
saveRelevy: function() {
var self = this;
if (!self.validate()) return;
var totalCount = self.crdnList.length;
var confirmMsg = totalCount > 1 ?
'재부과를 등록하시겠습니까?\n\n선택된 ' + totalCount + '건의 단속 정보를 복사하여 새로운 단속 건으로 등록됩니다.' :
'재부과를 등록하시겠습니까?\n\n원본 단속 정보를 복사하여 새로운 단속 건으로 등록됩니다.';
if (!confirm(confirmMsg)) {
return;
}
var formData = $("#relevyForm").serialize();
$.ajax({
url: '<c:url value="/levy/levyRelevy/saveBatchRelevy.ajax"/>',
type: 'POST',
data: formData,
success: function(response) {
if (response && response.success) {
var resultMsg = '재부과가 성공적으로 등록되었습니다.';
if (response.data && response.data.length > 0) {
resultMsg += '\n\n생성된 단속번호:';
response.data.forEach(function(item, index) {
resultMsg += '\n' + (index + 1) + '. ' + item.crdnYr + '-' + item.crdnNo;
});
}
alert(resultMsg);
// 부모 창의 목록 새로고침
if (window.opener && window.opener.LevyRelevyList) {
window.opener.LevyRelevyList.refreshList();
}
// 팝업 닫기
window.close();
} else {
alert(response.message || '재부과 등록에 실패했습니다.');
}
},
error: function(xhr, status, error) {
console.error('재부과 등록 실패:', error);
alert('재부과 등록 중 오류가 발생했습니다.');
}
});
},
validate: function() {
var isValid = validateFormByAttributes('relevyForm');
if (isValid) {
// 재부과 사유 글자수 검증 (varchar(1000) 제한)
var relevyRsn = $.trim($('#relevyRsn').val());
if (relevyRsn && relevyRsn.length > 1000) {
var relevyRsnElement = document.getElementById('relevyRsn');
errorElementCreate(relevyRsnElement, '재부과 사유는 1000자 이내로 입력하세요. (현재: ' + relevyRsn.length + '자)', false);
$('#relevyRsn').focus();
return false;
}
}
return isValid;
},
/**
* 이벤트 바인딩
*/
bindEvents: function() {
var self = this;
// 저장 버튼 클릭
$("#btnSave").on('click', function(e) {
e.preventDefault();
self.saveRelevy();
});
// 팝업 닫기
$(".modalclose").on('click', function(e) {
e.preventDefault();
window.close();
});
},
/**
* 초기화
*/
init: function() {
this.parseUrlParams();
this.bindEvents();
this.loadFirstCrdnInfo();
}
};
// DOM 준비 완료 시 초기화
$(document).ready(function() {
BatchRelevyPopup.init();
});
})(window, jQuery);
</script>
Loading…
Cancel
Save