단속 > 단속 등록&열람: 상태 업데이트 기능 추가 및 가중부과대상 UI/검색 조건 구현

dev
박성영 4 months ago
parent 3158f8af7a
commit 74384a1476

@ -158,6 +158,24 @@ public class DateUtil {
}
}
/**
* yyyyMMdd yyyy-MM-dd
* @param dateStr (yyyyMMdd , : "20250825")
* @return (yyyy-MM-dd , : "2025-08-25"), null
*/
public static String formatDateString(String dateStr) {
if (dateStr == null || dateStr.length() != 8) {
return null;
}
try {
// yyyyMMdd 형식으로 파싱한 후 yyyy-MM-dd 형식으로 포맷
LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyyMMdd"));
return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
} catch (Exception e) {
return null;
}
}
/**
* LocalDate
* @param date LocalDate

@ -281,4 +281,47 @@ public class CrdnRegistAndViewController {
}
}
/**
* .
*
* @param crdnYr
* @param crdnNo
* @param crdnPrcsSttsCd
* @return ResponseEntity
* @throws Exception
*/
@Operation(summary = "단속 상태 업데이트", description = "단속의 처리 상태를 업데이트합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "단속 상태 업데이트 성공"),
@ApiResponse(responseCode = "400", description = "단속 상태 업데이트 실패"),
@ApiResponse(description = "오류로 인한 실패")
})
@PostMapping("/updateStatus.ajax")
public ResponseEntity<?> updateStatus(
@Parameter(description = "단속 연도") @RequestParam String crdnYr,
@Parameter(description = "단속 번호") @RequestParam String crdnNo,
@Parameter(description = "처리 상태 코드") @RequestParam String crdnPrcsSttsCd) throws Exception {
try {
log.debug("단속 상태 업데이트 요청 - 단속연도: {}, 단속번호: {}, 상태코드: {}", crdnYr, crdnNo, crdnPrcsSttsCd);
CrdnRegistAndViewVO paramVO = new CrdnRegistAndViewVO();
paramVO.setCrdnYr(crdnYr);
paramVO.setCrdnNo(crdnNo);
paramVO.setCrdnPrcsSttsCd(crdnPrcsSttsCd);
int result = service.updateStatus(paramVO);
if (result > 0) {
return ApiResponseUtil.success("단속 상태가 성공적으로 업데이트되었습니다.");
} else {
return ApiResponseUtil.error("단속 상태 업데이트에 실패했습니다.");
}
} catch (Exception e) {
log.error("단속 상태 업데이트 중 오류 발생", e);
return ApiResponseUtil.error("단속 상태 업데이트 중 오류가 발생했습니다.");
}
}
}

@ -84,4 +84,11 @@ public interface CrdnRegistAndViewMapper {
*/
void createSequence(String sequenceName);
/**
* .
* @param vo (crdnYr, crdnNo, crdnPrcsSttsCd, crdnPrcsYmd) VO
* @return
*/
int updateStatus(CrdnRegistAndViewVO vo);
}

@ -95,6 +95,9 @@ public class CrdnRegistAndViewVO extends PagingVO {
/** 재부과 여부 */
private String relevyYn;
/** 가중 부과 대상 여부 */
private String agrvtnLevyTrgtYn;
/* 단속 처리 상태 코드 */
private String crdnPrcsSttsCd;
@ -161,5 +164,8 @@ public class CrdnRegistAndViewVO extends PagingVO {
/** 검색 조건 - 진행단계 코드 */
private String schCrdnPrcsSttsCd;
/** 검색 조건 - 가중 부과 대상 여부 */
private String schAgrvtnLevyTrgtYn;
}

@ -73,4 +73,12 @@ public interface CrdnRegistAndViewService {
*/
int selectDuplicateCheck(CrdnRegistAndViewVO vo);
/**
* .
*
* @param vo (crdnYr, crdnNo, crdnPrcsSttsCd) VO
* @return
*/
int updateStatus(CrdnRegistAndViewVO vo);
}

@ -235,4 +235,32 @@ public class CrdnRegistAndViewServiceImpl extends EgovAbstractServiceImpl implem
log.debug("년도별 시퀀스 생성 완료 - 시퀀스명: {}", sequenceName);
}
}
/**
* .
*
* @param vo (crdnYr, crdnNo, crdnPrcsSttsCd) VO
* @return
*/
@Override
public int updateStatus(CrdnRegistAndViewVO vo) {
log.debug("단속 상태 업데이트 - 단속연도: {}, 단속번호: {}, 상태코드: {}", vo.getCrdnYr(), vo.getCrdnNo(), vo.getCrdnPrcsSttsCd());
// PK(단속연도+단속번호) 필수값 검증
validatePrimaryKey(vo);
// 처리 상태 코드 필수값 검증
if (vo.getCrdnPrcsSttsCd() == null || vo.getCrdnPrcsSttsCd().trim().isEmpty()) {
log.warn("단속 상태 업데이트 실패 - 처리상태코드 미입력");
throw new MessageException("처리 상태 코드는 필수값입니다.");
}
// 단속 처리 일자를 현재 일자로 설정 (yyyyMMdd 형식)
vo.setCrdnPrcsYmd(LocalDate.now().toString().replace("-", ""));
// 상태 업데이트 수행
int result = mapper.updateStatus(vo);
log.debug("단속 상태 업데이트 완료 - 업데이트 건수: {}", result);
return result;
}
}

@ -33,6 +33,7 @@
c.FRST_CRDN_YR,
c.FRST_CRDN_NO,
c.RELEVY_YN,
c.AGRVTN_LEVY_TRGT_YN,
c.CRDN_PRCS_STTS_CD,
stts.CD_NM AS CRDN_PRCS_STTS_CD_NM,
c.CRDN_PRCS_YMD,
@ -65,6 +66,9 @@
<if test="schCrdnPrcsSttsCd != null and schCrdnPrcsSttsCd != ''">
AND c.CRDN_PRCS_STTS_CD = #{schCrdnPrcsSttsCd}
</if>
<if test="schAgrvtnLevyTrgtYn != null and schAgrvtnLevyTrgtYn != ''">
AND c.AGRVTN_LEVY_TRGT_YN = #{schAgrvtnLevyTrgtYn}
</if>
ORDER BY c.CRDN_YR DESC, c.CRDN_NO DESC
<if test="pagingYn == 'Y'">
limit #{startIndex}, #{perPage} /* 서버사이드 페이징 처리 */
@ -95,6 +99,9 @@
<if test="schCrdnPrcsSttsCd != null and schCrdnPrcsSttsCd != ''">
AND c.CRDN_PRCS_STTS_CD = #{schCrdnPrcsSttsCd}
</if>
<if test="schAgrvtnLevyTrgtYn != null and schAgrvtnLevyTrgtYn != ''">
AND c.AGRVTN_LEVY_TRGT_YN = #{schAgrvtnLevyTrgtYn}
</if>
</select>
<!-- 단속 단건 조회 -->
@ -127,6 +134,7 @@
c.FRST_CRDN_YR,
c.FRST_CRDN_NO,
c.RELEVY_YN,
c.AGRVTN_LEVY_TRGT_YN,
c.CRDN_PRCS_STTS_CD,
stts.CD_NM AS CRDN_PRCS_STTS_CD_NM,
c.CRDN_PRCS_YMD,
@ -172,6 +180,7 @@
FRST_CRDN_YR,
FRST_CRDN_NO,
RELEVY_YN,
AGRVTN_LEVY_TRGT_YN,
CRDN_PRCS_STTS_CD,
CRDN_PRCS_YMD,
REG_DT,
@ -201,6 +210,7 @@
#{frstCrdnYr},
#{frstCrdnNo},
#{relevyYn},
#{agrvtnLevyTrgtYn},
#{crdnPrcsSttsCd},
REPLACE(#{crdnPrcsYmd}, '-', ''),
NOW(),
@ -218,21 +228,8 @@
DSCL_YMD = REPLACE(#{dsclYmd}, '-', ''),
EXMNR = #{exmnr},
RMRK = #{rmrk},
DSPS_BFHD_BGNG_YMD = REPLACE(#{dspsBfhdBgngYmd}, '-', ''),
DSPS_BFHD_END_YMD = REPLACE(#{dspsBfhdEndYmd}, '-', ''),
CRC_CMD_BGNG_YMD = REPLACE(#{crcCmdBgngYmd}, '-', ''),
CRC_CMD_END_YMD = REPLACE(#{crcCmdEndYmd}, '-', ''),
CRC_URG_BGNG_YMD = REPLACE(#{crcUrgBgngYmd}, '-', ''),
CRC_URG_END_YMD = REPLACE(#{crcUrgEndYmd}, '-', ''),
LEVY_PRVNTC_BGNG_YMD = REPLACE(#{levyPrvntcBgngYmd}, '-', ''),
LEVY_PRVNTC_END_YMD = REPLACE(#{levyPrvntcEndYmd}, '-', ''),
LEVY_BGNG_YMD = REPLACE(#{levyBgngYmd}, '-', ''),
LEVY_END_YMD = REPLACE(#{levyEndYmd}, '-', ''),
PAY_URG_BGNG_YMD = REPLACE(#{payUrgBgngYmd}, '-', ''),
PAY_URG_END_YMD = REPLACE(#{payUrgEndYmd}, '-', ''),
FRST_CRDN_YR = #{frstCrdnYr},
FRST_CRDN_NO = #{frstCrdnNo},
RELEVY_YN = #{relevyYn}
RELEVY_YN = #{relevyYn},
AGRVTN_LEVY_TRGT_YN = #{agrvtnLevyTrgtYn}
WHERE CRDN_YR = #{crdnYr}
AND CRDN_NO = #{crdnNo}
AND DEL_YN = 'N'
@ -257,7 +254,6 @@
FROM tb_crdn
WHERE CRDN_YR = #{crdnYr}
AND CRDN_NO = #{crdnNo}
AND DEL_YN = 'N'
</select>
<!-- 시퀀스 존재 여부 확인 -->
@ -277,4 +273,15 @@
CACHE 20
</update>
<!-- 단속 상태 업데이트 -->
<update id="updateStatus" parameterType="go.kr.project.crdn.crndRegistAndView.model.CrdnRegistAndViewVO">
/* CrdnRegistAndViewMapper.updateStatus : 단속 상태 업데이트 */
UPDATE tb_crdn
SET CRDN_PRCS_STTS_CD = #{crdnPrcsSttsCd},
CRDN_PRCS_YMD = #{crdnPrcsYmd}
WHERE CRDN_YR = #{crdnYr}
AND CRDN_NO = #{crdnNo}
AND DEL_YN = 'N'
</update>
</mapper>

@ -50,4 +50,10 @@
<function-signature>java.lang.String getSessionExpiryTime(javax.servlet.http.HttpServletRequest, java.lang.String)</function-signature>
</function>
<function>
<name>formatDateString</name>
<function-class>egovframework.util.DateUtil</function-class>
<function-signature>java.lang.String formatDateString(java.lang.String)</function-signature>
</function>
</taglib>

@ -62,6 +62,14 @@
</c:forEach>
</select>
</li>
<li class="th">가중 부과 대상</li>
<li>
<select id="schAgrvtnLevyTrgtYn" name="schAgrvtnLevyTrgtYn" class="input" style="width: 120px;">
<option value="">전체</option>
<option value="Y" <c:if test="${param.schAgrvtnLevyTrgtYn eq 'Y'}">selected</c:if>>대상</option>
<option value="N" <c:if test="${param.schAgrvtnLevyTrgtYn eq 'N'}">selected</c:if>>비대상</option>
</select>
</li>
</ul>
<ul class="rig2">
<li><button type="button" id="search_btn" class="newbtnss bg1">검색</button></li>
@ -74,8 +82,15 @@
<div class="box_column">
<ul class="box_title" style="display: flex; justify-content: space-between; align-items: center;">
<li class="tit">단속 목록</li>
<li style="text-align: right;">
<span id="totalCount" class="total-count" style="padding-right: 25px;">총 0건</span>
<li class="rig">
<button type="button" id="btnDsps" class="newbtn bg2-1">처분사전</button>
<button type="button" id="btnCrcCmd" class="newbtn bg2-1">시정명령</button>
<button type="button" id="btnCrcUrg" class="newbtn bg2-1">시정촉구</button>
<button type="button" id="btnLevyPrvntc" class="newbtn bg2-1">부과예고</button>
<button type="button" id="btnLevy" class="newbtn bg2-1">부과</button>
<button type="button" id="btnPayUrg" class="newbtn bg2-1">납부촉구</button>
<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>
@ -113,6 +128,7 @@
var schDsclMthdCd = $.trim(nvl($("#schDsclMthdCd").val(), ""));
var schExmnr = $.trim(nvl($("#schExmnr").val(), ""));
var schCrdnPrcsSttsCd = $.trim(nvl($("#schCrdnPrcsSttsCd").val(), ""));
var schAgrvtnLevyTrgtYn = $.trim(nvl($("#schAgrvtnLevyTrgtYn").val(), ""));
SEARCH_COND.schCrdnYr = schCrdnYr;
SEARCH_COND.schCrdnNo = schCrdnNo;
@ -120,6 +136,7 @@
SEARCH_COND.schDsclMthdCd = schDsclMthdCd;
SEARCH_COND.schExmnr = schExmnr;
SEARCH_COND.schCrdnPrcsSttsCd = schCrdnPrcsSttsCd;
SEARCH_COND.schAgrvtnLevyTrgtYn = schAgrvtnLevyTrgtYn;
};
/**
@ -230,6 +247,15 @@
return e.value === 'Y' ? '재부과' : '일반';
}
},
{
header: '가중부과대상',
name: 'agrvtnLevyTrgtYn',
align: 'center',
width: 100,
formatter: function(e) {
return e.value === 'Y' ? '대상' : '비대상';
}
},
{
header: '진행단계',
name: 'crdnPrcsSttsCdNm',
@ -373,6 +399,57 @@
}
},
/**
* 단속 상태를 업데이트합니다.
* 선택된 행이 있을 때만 상태를 업데이트합니다.
*
* @param statusCode 변경할 상태 코드
* @param statusName 상태명 (확인 메시지용)
*/
updateStatus: function(statusCode, statusName) {
var self = this;
// 선택된 행 확인
if (!this.selectedRow) {
alert('상태를 변경할 단속 건을 선택해주세요.');
return;
}
var crdnYr = this.selectedRow.crdnYr;
var crdnNo = this.selectedRow.crdnNo;
// 확인 메시지
if (!confirm(crdnYr + '-' + crdnNo + ' 단속 건의 상태를 [' + statusName + ']으로 변경하시겠습니까?')) {
return;
}
// AJAX 요청으로 상태 업데이트
$.ajax({
url: '<c:url value="/crdn/crndRegistAndView/updateStatus.ajax"/>',
type: 'POST',
data: {
crdnYr: crdnYr,
crdnNo: crdnNo,
crdnPrcsSttsCd: statusCode
},
success: function(response) {
if (response && response.success) {
alert('단속 상태가 성공적으로 변경되었습니다.');
// 목록 새로고침
self.refreshList();
// 선택된 행 초기화
self.selectedRow = null;
} else {
alert(response.message || '상태 변경에 실패했습니다.');
}
},
error: function(xhr, status, error) {
console.error('상태 업데이트 요청 실패:', error);
alert('상태 변경 중 오류가 발생했습니다.');
}
});
},
/**
* 이벤트 핸들러 설정
*/
@ -407,6 +484,31 @@
self.openRegisterPopup();
});
// 상태 업데이트 버튼 클릭 이벤트들
$("#btnDsps").on('click', function() {
self.updateStatus('20', '처분사전');
});
$("#btnCrcCmd").on('click', function() {
self.updateStatus('30', '시정명령');
});
$("#btnCrcUrg").on('click', function() {
self.updateStatus('40', '시정촉구');
});
$("#btnLevyPrvntc").on('click', function() {
self.updateStatus('50', '부과예고');
});
$("#btnLevy").on('click', function() {
self.updateStatus('60', '부과');
});
$("#btnPayUrg").on('click', function() {
self.updateStatus('70', '납부촉구');
});
// 엔터키 검색
$(".gs_b_top input").on('keypress', function(e) {
if (e.which === 13) {

@ -22,7 +22,7 @@
<col style="width: 30%;"/>
</colgroup>
<tr>
<th class="th"><span class="required">*</span>단속 년도</th>
<th class="th"><span class="required">*</span> 단속 년도</th>
<td>
<c:choose>
<c:when test="${param.mode eq 'C'}">
@ -67,7 +67,7 @@
<th class="th"><span class="required">*</span> 적발일자</th>
<td colspan="3">
<input type="text" id="dsclYmd" name="dsclYmd" class="input calender datepicker" validation-check="required"
value="${data.dsclYmd}" maxlength="10" style="width: 120px;" autocomplete="off"/>
value="${dateUtil:formatDateString(data.dsclYmd)}" maxlength="10" style="width: 120px;" autocomplete="off"/>
</td>
</tr>
<tr>
@ -87,6 +87,16 @@
</select>
</td>
</tr>
<tr>
<th class="th"><span class="required">*</span> 가중부과대상</th>
<td colspan="3">
<select id="agrvtnLevyTrgtYn" name="agrvtnLevyTrgtYn" class="input" validation-check="required">
<option value="">선택하세요</option>
<option value="N" selected>비대상</option>
<option value="Y">대상</option>
</select>
</td>
</tr>
<tr>
<th class="th">비고</th>
<td colspan="3">
@ -101,8 +111,6 @@
<c:choose>
<c:when test="${param.mode eq 'V'}">
<a href="#" id="btnDelete" class="newbtns bg2">삭제</a>
</c:when>
<c:when test="${not empty data.crdnYr and not empty data.crdnNo}">
<a href="#" id="btnSave" class="newbtns bg4">수정</a>
</c:when>
<c:otherwise>
@ -133,9 +141,8 @@
setFormData: function() {
var mode = $("#mode").val();
if (mode === 'U' || mode === 'V') {
$("#rgnSeCd").val('${data.rgnSeCd}');
$("#dsclMthdCd").val('${data.dsclMthdCd}');
$("#relevyYn").val('${data.relevyYn}');
$("#agrvtnLevyTrgtYn").val('${data.agrvtnLevyTrgtYn}');
}
},

@ -219,6 +219,14 @@ ol {
border-color: #6c757d;
}
.newbtn.bg2-1,
.newbtns.bg2-1,
.newbtnss.bg2-1 {
background-color: #484e54;
color: #fff;
border-color: #484e54;
}
.newbtn.bg3,
.newbtns.bg3,
.newbtnss.bg3 {

Loading…
Cancel
Save