diff --git a/bin/main/mybatis/mapper/baseData/actType/ActTypeMapper_maria.xml b/bin/main/mybatis/mapper/baseData/actType/ActTypeMapper_maria.xml
new file mode 100644
index 0000000..077b11a
--- /dev/null
+++ b/bin/main/mybatis/mapper/baseData/actType/ActTypeMapper_maria.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO tb_act_type (
+ ACT_TYPE_CD /* 행위 유형 코드 */
+ , VLTN_BDST /* 위반 건축물 */
+ , LAWLPRVS /* 법조문 */
+ , CMPTTN_RT /* 산정률 */
+ , VLTN_BDST_DTL /* 위반 건축물 상세 */
+ , USE_YN /* 사용 여부 */
+ , REG_DT /* 등록 일시 */
+ , RGTR /* 등록자 */
+ ) VALUES (
+ #{actTypeCd} /* 행위 유형 코드 */
+ , #{vltnBdst} /* 위반 건축물 */
+ , #{lawlprvs} /* 법조문 */
+ , #{cmpttnRt} /* 산정률 */
+ , #{vltnBdstDtl} /* 위반 건축물 상세 */
+ , #{useYn} /* 사용 여부 */
+ , NOW() /* 등록 일시 - 현재 날짜 자동 설정 */
+ , #{rgtr} /* 등록자 - 세션 사용자 ID */
+ )
+
+
+
+
+ UPDATE tb_act_type
+ SET VLTN_BDST = #{vltnBdst} /* 위반 건축물 */
+ , LAWLPRVS = #{lawlprvs} /* 법조문 */
+ , CMPTTN_RT = #{cmpttnRt} /* 산정률 */
+ , VLTN_BDST_DTL = #{vltnBdstDtl} /* 위반 건축물 상세 */
+ , USE_YN = #{useYn} /* 사용 여부 */
+ , MDFCN_DT = NOW() /* 수정 일시 */
+ , MDFR = #{mdfr} /* 수정자 */
+ WHERE ACT_TYPE_CD = #{actTypeCd} /* 행위 유형 코드 */
+
+
+
+
+
diff --git a/bin/main/mybatis/mapper/baseData/cmpttnRt2/CmpttnRt2Mapper_maria.xml b/bin/main/mybatis/mapper/baseData/cmpttnRt2/CmpttnRt2Mapper_maria.xml
new file mode 100644
index 0000000..a263cc8
--- /dev/null
+++ b/bin/main/mybatis/mapper/baseData/cmpttnRt2/CmpttnRt2Mapper_maria.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO tb_cmpttn_rt_2 (
+ CMPTTN_RT_2_CD /* 산정률2 코드 */
+ , VLTN_MTTR /* 위반 사항 */
+ , CMPTTN_RT_2 /* 산정률2 */
+ , USE_YN /* 사용 여부 */
+ , REG_DT /* 등록 일시 */
+ , RGTR /* 등록자 */
+ ) VALUES (
+ #{cmpttnRt2Cd} /* 산정률2 코드 */
+ , #{vltnMttr} /* 위반 사항 */
+ , #{cmpttnRt2} /* 산정률2 */
+ , #{useYn} /* 사용 여부 */
+ , NOW() /* 등록 일시 - 현재 날짜 자동 설정 */
+ , #{rgtr} /* 등록자 - 세션 사용자 ID */
+ )
+
+
+
+
+ UPDATE tb_cmpttn_rt_2
+ SET VLTN_MTTR = #{vltnMttr} /* 위반 사항 */
+ , CMPTTN_RT_2 = #{cmpttnRt2} /* 산정률2 */
+ , USE_YN = #{useYn} /* 사용 여부 */
+ , MDFCN_DT = NOW() /* 수정 일시 */
+ , MDFR = #{mdfr} /* 수정자 */
+ WHERE CMPTTN_RT_2_CD = #{cmpttnRt2Cd} /* 산정률2 코드 */
+
+
+
+
+
diff --git a/src/main/java/go/kr/project/baseData/actType/controller/ActTypeController.java b/src/main/java/go/kr/project/baseData/actType/controller/ActTypeController.java
new file mode 100644
index 0000000..b7021ff
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/actType/controller/ActTypeController.java
@@ -0,0 +1,167 @@
+package go.kr.project.baseData.actType.controller;
+
+import egovframework.constant.MessageConstants;
+import egovframework.constant.TilesConstants;
+import egovframework.exception.MessageException;
+import egovframework.util.ApiResponseUtil;
+import egovframework.util.SessionUtil;
+import go.kr.project.baseData.actType.model.ActTypeVO;
+import go.kr.project.baseData.actType.service.ActTypeService;
+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;
+import lombok.RequiredArgsConstructor;
+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.*;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * packageName : go.kr.project.baseData.actType.controller
+ * fileName : ActTypeController
+ * author : 김의진
+ * date : 2025-09-22
+ * description : 기준자료 > 행위 유형 웹 컨트롤러
+ * 중요 로직 주석:
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-22 김의진 최초 생성
+ */
+@Controller
+@RequestMapping("/baseData/actType")
+@RequiredArgsConstructor
+@Slf4j
+@Tag(name = "기준자료: 행위 유형", description = "행위 유형 관리 API")
+public class ActTypeController {
+
+ /** 행위 유형 서비스 */
+ private final ActTypeService service;
+
+ /**
+ * 행위 유형 목록 페이지를 조회한다.
+ * @param vo 검색 조건을 담은 VO 객체
+ * @param model 뷰에 전달할 데이터를 담는 모델 객체
+ * @return 목록 페이지 뷰 이름
+ */
+ @GetMapping("/list.do")
+ @Operation(summary = "행위 유형 목록 페이지", description = "목록 페이지를 조회합니다.")
+ public String listPage(ActTypeVO vo, Model model){
+ log.debug("행위 유형 목록 페이지 조회");
+ return "baseData/actType/list" + TilesConstants.BASE;
+ }
+
+ /**
+ * 행위 유형 목록을 AJAX로 조회한다.
+ * 서버사이드 페이징을 지원하며 검색 조건에 따라 필터링된 결과를 반환한다.
+ * @param vo 검색 조건과 페이징 정보를 담은 VO 객체
+ * @return 목록 데이터와 페이징 정보를 담은 ResponseEntity
+ */
+ @PostMapping("/list.ajax")
+ @Operation(summary = "목록 조회(AJAX)", description = "페이징 목록을 JSON으로 반환")
+ @ApiResponse(responseCode = "200", description = "성공")
+ public ResponseEntity> listAjax(@ModelAttribute ActTypeVO vo){
+ log.debug("행위 유형 목록 AJAX 조회 - 검색조건: {}", vo);
+ int total = service.selectListTotalCount(vo); // 1. 총 개수 조회
+ vo.setTotalCount(total); // 2. setTotalCount
+ //vo.setPagingYn("Y"); // 3. 페이징 처리
+ return ApiResponseUtil.successWithGrid(service.selectList(vo), vo);
+ }
+
+ /**
+ * 행위 유형 등록/수정/조회 팝업 페이지를 조회한다.
+ * mode 파라미터에 따라 등록(C), 수정(U), 조회(V) 모드로 동작한다.
+ * @param vo PK 정보를 담은 VO 객체
+ * @param mode 화면 모드 (C: 등록, U: 수정, V: 조회)
+ * @param model 뷰에 전달할 데이터를 담는 모델 객체
+ * @return 팝업 페이지 뷰 이름
+ */
+ @GetMapping("/popup.do")
+ @Operation(summary = "등록/수정/조회 팝업", description = "window.open으로 호출되는 팝업, mode 파라미터로 C/U/V 구분")
+ public ModelAndView popup(
+ @Parameter(description = "행위 유형 코드") @RequestParam(required = false) String actTypeCd,
+ @Parameter(description = "화면 모드 (C:등록, U:수정, V:보기)") @RequestParam String mode,
+ Model model) {
+
+ try {
+ log.debug("행위 유형 팝업 화면 요청 - 모드: {}, 구조지수코드: {}", mode, actTypeCd);
+
+ ModelAndView mav = new ModelAndView("baseData/actType/popup" + TilesConstants.POPUP);
+ mav.addObject("mode", mode);
+
+ // 수정/조회 모드인 경우 기존 데이터 조회
+ if (("U".equals(mode) || "V".equals(mode)) && actTypeCd != null) {
+ ActTypeVO paramVO = new ActTypeVO();
+ paramVO.setActTypeCd(actTypeCd);
+
+ ActTypeVO data = service.selectOne(paramVO);
+ if (data != null) {
+ mav.addObject("data", data);
+ } else {
+ throw new MessageException("해당 행위 유형 정보를 찾을 수 없습니다.");
+ }
+ }
+
+ return mav;
+
+ } catch (Exception e) {
+ log.error("행위 유형 팝업 화면 제공 중 오류 발생", e);
+ throw new MessageException("팝업 화면을 불러오는 중 오류가 발생했습니다.");
+ }
+ }
+
+ /**
+ * 새로운 행위 유형 정보를 등록한다.
+ * @param vo 등록할 행위 유형 정보를 담은 VO 객체
+ * @return 등록 결과를 담은 ResponseEntity
+ */
+ @Operation(summary = "행위 유형 등록", description = "새로운 행위 유형 정보를 등록합니다.")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "행위 유형 등록 성공"),
+ @ApiResponse(responseCode = "400", description = "행위 유형 등록 실패"),
+ @ApiResponse(description = "오류로 인한 실패")
+ })
+ @PostMapping("/insert.ajax")
+ public ResponseEntity> insert(@ModelAttribute ActTypeVO paramVO) throws Exception {
+ // 등록자 정보 설정
+ paramVO.setRgtr(SessionUtil.getUserId());
+
+ int result = service.insert(paramVO);
+
+ if (result > 0) {
+ return ApiResponseUtil.success(MessageConstants.Common.SAVE_SUCCESS);
+ } else {
+ return ApiResponseUtil.error(MessageConstants.Common.SAVE_ERROR);
+ }
+ }
+
+ /**
+ * 기존 행위 유형 정보를 수정한다.
+ * @param vo 수정할 행위 유형 정보를 담은 VO 객체
+ * @return 수정 결과를 담은 ResponseEntity
+ */
+ @Operation(summary = "행위 유형 수정", description = "기존 행위 유형 정보를 수정합니다.")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "행위 유형 수정 성공"),
+ @ApiResponse(responseCode = "400", description = "행위 유형 수정 실패"),
+ @ApiResponse(description = "오류로 인한 실패")
+ })
+ @PostMapping("/update.ajax")
+ public ResponseEntity> update(@ModelAttribute ActTypeVO paramVO) throws Exception {
+ // 수정자 정보 설정
+ paramVO.setMdfr(SessionUtil.getUserId());
+
+ int result = service.update(paramVO);
+
+ if (result > 0) {
+ return ApiResponseUtil.success(MessageConstants.Common.UPDATE_SUCCESS);
+ } else {
+ return ApiResponseUtil.error(MessageConstants.Common.UPDATE_ERROR);
+ }
+ }
+
+}
diff --git a/src/main/java/go/kr/project/baseData/actType/mapper/ActTypeMapper.java b/src/main/java/go/kr/project/baseData/actType/mapper/ActTypeMapper.java
new file mode 100644
index 0000000..e3bd997
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/actType/mapper/ActTypeMapper.java
@@ -0,0 +1,71 @@
+package go.kr.project.baseData.actType.mapper;
+
+import go.kr.project.baseData.actType.model.ActTypeVO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * packageName : go.kr.project.baseData.actType.mapper
+ * fileName : ActTypeMapper
+ * author : 김의진
+ * date : 2025-09-22
+ * description : 행위 유형 MyBatis Mapper 인터페이스
+ * 중요한 로직 주석: SQL 쿼리와 매핑되는 메서드들을 정의하여 데이터베이스 접근을 담당한다.
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-22 김의진 최초 생성
+ */
+@Mapper
+public interface ActTypeMapper {
+
+ /**
+ * 행위 유형 목록을 조회한다.
+ * @param vo 검색 조건과 페이징 정보를 담은 VO 객체
+ * @return 행위 유형 목록
+ */
+ List selectList(ActTypeVO vo);
+
+ /**
+ * 행위 유형 목록의 총 개수를 조회한다.
+ * @param vo 검색 조건을 담은 VO 객체
+ * @return 조회된 목록의 총 개수
+ */
+ int selectListTotalCount(ActTypeVO vo);
+
+ /**
+ * 특정 코드의 행위 유형 정보를 조회한다.
+ * @param vo 조회할 PK 정보(yr, no)를 담은 VO 객체
+ * @return 조회된 행위 유형 정보
+ */
+ ActTypeVO selectOne(ActTypeVO vo);
+
+ /**
+ * 새로운 행위 유형 정보를 등록한다.
+ * @param vo 등록할 행위 유형 정보를 담은 VO 객체
+ * @return 등록된 행의 수
+ */
+ int insert(ActTypeVO vo);
+
+ /**
+ * 기존 행위 유형 정보를 수정한다.
+ * @param vo 수정할 행위 유형 정보를 담은 VO 객체
+ * @return 수정된 행의 수
+ */
+ int update(ActTypeVO vo);
+
+ /**
+ * 행위 유형 정보를 삭제한다.
+ * @param vo 삭제할 PK 정보(actTypeCd)를 담은 VO 객체
+ * @return 삭제된 행의 수
+ */
+ int delete(ActTypeVO vo);
+
+ /**
+ * PK(코드) 중복 체크를 수행한다.
+ * @param vo 중복 체크할 PK 정보(actTypeCd)를 담은 VO 객체
+ * @return 중복 건수 (0이면 중복 없음, 1이상이면 중복 존재)
+ */
+ int selectDuplicateCheck(ActTypeVO vo);
+}
diff --git a/src/main/java/go/kr/project/baseData/actType/model/ActTypeVO.java b/src/main/java/go/kr/project/baseData/actType/model/ActTypeVO.java
new file mode 100644
index 0000000..decbab4
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/actType/model/ActTypeVO.java
@@ -0,0 +1,86 @@
+package go.kr.project.baseData.actType.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import go.kr.project.common.model.PagingVO;
+import lombok.*;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * packageName : go.kr.project.baseData.actType.model
+ * fileName : ActTypeVO
+ * author : 김의진
+ * date : 2025-09-22
+ * description : 행위 유형 관련 데이터를 담는 Value Object 클래스
+ * 중요한 로직 주석: 행위 유형 테이블(tb_act_type)과 매핑되는 VO 클래스로 페이징 기능을 포함한다. *
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-22 김의진 최초 생성
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString
+public class ActTypeVO extends PagingVO {
+
+ // ==================== 기본 테이블 컬럼 ====================
+
+ /** 행위 유형 코드 (PK) - 3자리 코드 */
+ private String actTypeCd;
+
+ /** 위반 건축물 */
+ private String vltnBdst;
+
+ /** 법조문 */
+ private String lawlprvs;
+
+ /** 산정률 - DECIMAL(3,0) */
+ private BigDecimal cmpttnRt;
+
+ /** 위반 건축물 상세 */
+ private String vltnBdstDtl;
+
+ /** 사용 여부 */
+ private String useYn;
+
+ /** 등록 일시 - 테이블은 date 컬럼을 사용하지만 화면 표시용으로 문자열 타입 사용 */
+ @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;
+
+ /** 등록자 ID */
+ private String rgtr;
+
+ /** 수정 일시 */
+ @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 mdfcnDt;
+
+ /** 수정자 ID */
+ private String mdfr;
+
+ // ==================== 조인 컬럼 (코드명) ====================
+
+ /** 등록자 */
+ private String rgtrNm;
+
+ /** 수정자 */
+ private String mdfrNm;
+
+ /** 행 번호 (그리드 표시용) */
+ private Integer rowNum;
+
+ // ==================== 검색 조건 ====================
+
+ /** 검색 조건 선택 */
+ private String schType;
+ private String schTypeTxt;
+
+ /** 검색 조건 - 사용 여부 */
+ private String schUseYn;
+}
diff --git a/src/main/java/go/kr/project/baseData/actType/service/ActTypeService.java b/src/main/java/go/kr/project/baseData/actType/service/ActTypeService.java
new file mode 100644
index 0000000..a7396df
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/actType/service/ActTypeService.java
@@ -0,0 +1,69 @@
+package go.kr.project.baseData.actType.service;
+
+import go.kr.project.baseData.actType.model.ActTypeVO;
+
+import java.util.List;
+
+/**
+ * packageName : go.kr.project.baseData.actType.service
+ * fileName : ActTypeService
+ * author : 김의진
+ * date : 2025-09-22
+ * description : 행위 유형 비즈니스 로직 처리를 위한 서비스 인터페이스
+ * 중요한 로직 주석: 컨트롤러와 매퍼 사이의 비즈니스 로직을 정의하고 데이터 처리 규칙을 관리한다.
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-22 김의진 최초 생성
+ */
+public interface ActTypeService {
+
+ /**
+ * 행위 유형 목록을 조회한다.
+ * @param vo 검색 조건과 페이징 정보를 담은 VO 객체
+ * @return 행위 유형 목록
+ */
+ List selectList(ActTypeVO vo);
+
+ /**
+ * 행위 유형 목록의 총 개수를 조회한다.
+ * @param vo 검색 조건을 담은 VO 객체
+ * @return 조회된 목록의 총 개수
+ */
+ int selectListTotalCount(ActTypeVO vo);
+
+ /**
+ * 특정 코드의 행위 유형 정보를 조회한다.
+ * @param vo 조회할 PK 정보를 담은 VO 객체
+ * @return 조회된 행위 유형 정보
+ */
+ ActTypeVO selectOne(ActTypeVO vo);
+
+ /**
+ * 새로운 행위 유형 정보를 등록한다.
+ * @param vo 등록할 행위 유형 정보를 담은 VO 객체
+ * @return 등록된 행의 수
+ */
+ int insert(ActTypeVO vo);
+
+ /**
+ * 기존 행위 유형 정보를 수정한다.
+ * @param vo 수정할 행위 유형 정보를 담은 VO 객체
+ * @return 수정된 행의 수
+ */
+ int update(ActTypeVO vo);
+
+ /**
+ * 행위 유형 정보를 삭제한다.
+ * @param vo 삭제할 PK 정보(actTypeCd)를 담은 VO 객체
+ * @return 삭제된 행의 수
+ */
+ int delete(ActTypeVO vo);
+
+ /**
+ * PK(코드) 중복 체크를 수행한다.
+ * @param vo 중복 체크할 PK 정보(actTypeCd)를 담은 VO 객체
+ * @return 중복 건수 (0이면 중복 없음, 1이상이면 중복 존재)
+ */
+ int selectDuplicateCheck(ActTypeVO vo);
+}
diff --git a/src/main/java/go/kr/project/baseData/actType/service/impl/ActTypeServiceImpl.java b/src/main/java/go/kr/project/baseData/actType/service/impl/ActTypeServiceImpl.java
new file mode 100644
index 0000000..9843291
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/actType/service/impl/ActTypeServiceImpl.java
@@ -0,0 +1,194 @@
+package go.kr.project.baseData.actType.service.impl;
+
+import egovframework.exception.MessageException;
+import egovframework.util.SessionUtil;
+import egovframework.util.StringUtil;
+import go.kr.project.baseData.actType.mapper.ActTypeMapper;
+import go.kr.project.baseData.actType.model.ActTypeVO;
+import go.kr.project.baseData.actType.service.ActTypeService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * packageName : go.kr.project.baseData.actType.service.impl
+ * fileName : ActTypeServiceImpl
+ * author : 김의진
+ * date : 2025-09-22
+ * description : 행위 유형 비즈니스 로직 처리를 위한 서비스 구현체
+ * 중요한 로직 주석: 서비스 인터페이스를 구현하여 실제 비즈니스 로직을 처리하고 매퍼를 호출한다.
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-22 김의진 최초 생성
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class ActTypeServiceImpl extends EgovAbstractServiceImpl implements ActTypeService {
+
+ /** 행위 유형 매퍼 */
+ private final ActTypeMapper mapper;
+
+ /**
+ * 행위 유형 목록을 조회한다.
+ * @param vo 검색 조건과 페이징 정보를 담은 VO 객체
+ * @return 행위 유형 목록
+ */
+ @Override
+ public List selectList(ActTypeVO vo) {
+ log.debug("행위 유형 목록 조회 - 검색조건: {}", vo);
+ return mapper.selectList(vo);
+ }
+
+ /**
+ * 행위 유형 목록의 총 개수를 조회한다.
+ * @param vo 검색 조건을 담은 VO 객체
+ * @return 조회된 목록의 총 개수
+ */
+ @Override
+ public int selectListTotalCount(ActTypeVO vo) {
+ log.debug("행위 유형 총 개수 조회 - 검색조건: {}", vo);
+ return mapper.selectListTotalCount(vo);
+ }
+
+ /**
+ * 특정 코드에 해당하는 행위 유형 정보를 조회한다.
+ * @param vo 조회할 PK 정보(actTypeCd)를 담은 VO 객체
+ * @return 조회된 행위 유형 정보
+ */
+ @Override
+ public ActTypeVO selectOne(ActTypeVO vo) {
+ log.debug("행위 유형 단건 조회 - 코드: {}", vo.getActTypeCd());
+ return mapper.selectOne(vo);
+ }
+
+ /**
+ * 새로운 행위 유형 정보를 등록한다.
+ * PK(코드) 필수값 검증과 중복 체크를 수행한 후 등록을 진행한다.
+ * @param vo 등록할 행위 유형 정보를 담은 VO 객체
+ * @return 등록된 행의 수
+ * @throws MessageException PK 필수값 누락 또는 중복 시 발생
+ */
+ @Override
+ public int insert(ActTypeVO vo) {
+ log.debug("행위 유형 등록 - 코드: {}, 위반 건축물: {}", vo.getActTypeCd(), vo.getVltnBdst());
+
+ // PK(코드) 필수값 검증
+ if (vo.getActTypeCd() == null || vo.getActTypeCd().trim().isEmpty()) {
+ log.warn("행위 유형 등록 실패 - 코드 미입력");
+ throw new MessageException("코드는 필수값입니다.");
+ }
+
+ // PK 중복 체크
+ int duplicateCount = mapper.selectDuplicateCheck(vo);
+ if (duplicateCount > 0) {
+ log.warn("행위 유형 등록 실패 - 중복된 PK: 코드={}", vo.getActTypeCd());
+ throw new MessageException("이미 존재하는 행위 유형 코드입니다. 다른 값을 입력해주세요.");
+ }
+
+ // 위반 건축물 바이트 길이 검증 (한글 3바이트 기준 최대 100바이트)
+ if (vo.getVltnBdst() != null && !vo.getVltnBdst().trim().isEmpty()) {
+ int byteLength = StringUtil.calculateUtf8ByteLength(vo.getVltnBdst());
+ if (byteLength > 100) {
+ log.warn("행위 유형 등록 실패 - 위반 건축물 바이트 길이 초과: {}바이트", byteLength);
+ throw new MessageException("위반 건축물은 최대 100바이트까지 입력 가능합니다. (현재: " + byteLength + "바이트)");
+ }
+ }
+
+ // 위반 건축물 상세 바이트 길이 검증 (한글 3바이트 기준 최대 1000바이트)
+ if (vo.getVltnBdstDtl() != null && !vo.getVltnBdstDtl().trim().isEmpty()) {
+ int byteLength = StringUtil.calculateUtf8ByteLength(vo.getVltnBdstDtl());
+ if (byteLength > 1000) {
+ log.warn("행위 유형 등록 실패 - 위반 건축물 상세 바이트 길이 초과: {}바이트", byteLength);
+ throw new MessageException("위반 건축물은 최대 1000바이트까지 입력 가능합니다. (현재: " + byteLength + "바이트)");
+ }
+ }
+
+ // 등록자 정보 설정 및 등록 수행
+ vo.setRgtr(SessionUtil.getUserId());
+ int result = mapper.insert(vo);
+ log.debug("행위 유형 등록 완료 - 등록 건수: {}", result);
+ return result;
+ }
+
+ /**
+ * 기존 행위 유형 정보를 수정한다.
+ * PK(코드) 필수값 검증을 수행한 후 수정을 진행한다.
+ * @param vo 수정할 행위 유형 정보를 담은 VO 객체
+ * @return 수정된 행의 수
+ * @throws MessageException PK 필수값 누락 시 발생
+ */
+ @Override
+ public int update(ActTypeVO vo) {
+ log.debug("행위 유형 수정 - 코드: {}, 위반 건축물: {}", vo.getActTypeCd(), vo.getVltnBdst());
+
+ // PK(코드) 필수값 검증
+ if (vo.getActTypeCd() == null || vo.getActTypeCd().trim().isEmpty()) {
+ log.warn("행위 유형 등록 실패 - 코드 미입력");
+ throw new MessageException("코드는 필수값입니다.");
+ }
+
+ // 위반 건축물 바이트 길이 검증 (한글 3바이트 기준 최대 100바이트)
+ if (vo.getVltnBdst() != null && !vo.getVltnBdst().trim().isEmpty()) {
+ int byteLength = StringUtil.calculateUtf8ByteLength(vo.getVltnBdst());
+ if (byteLength > 100) {
+ log.warn("행위 유형 등록 실패 - 위반 건축물 바이트 길이 초과: {}바이트", byteLength);
+ throw new MessageException("위반 건축물은 최대 100바이트까지 입력 가능합니다. (현재: " + byteLength + "바이트)");
+ }
+ }
+
+ // 위반 건축물 상세 바이트 길이 검증 (한글 3바이트 기준 최대 1000바이트)
+ if (vo.getVltnBdstDtl() != null && !vo.getVltnBdstDtl().trim().isEmpty()) {
+ int byteLength = StringUtil.calculateUtf8ByteLength(vo.getVltnBdstDtl());
+ if (byteLength > 1000) {
+ log.warn("행위 유형 등록 실패 - 위반 건축물 상세 바이트 길이 초과: {}바이트", byteLength);
+ throw new MessageException("위반 건축물은 최대 1000바이트까지 입력 가능합니다. (현재: " + byteLength + "바이트)");
+ }
+ }
+
+ // 수정 수행
+ int result = mapper.update(vo);
+ log.debug("행위 유형 수정 완료 - 수정 건수: {}", result);
+ return result;
+ }
+
+ /**
+ * 행위 유형 정보를 삭제한다.
+ * PK(코드) 필수값 검증을 수행한 후 삭제를 진행한다.
+ * @param vo 삭제할 PK 정보(코드)를 담은 VO 객체
+ * @return 삭제된 행의 수
+ * @throws MessageException PK 필수값 누락 시 발생
+ */
+ @Override
+ public int delete(ActTypeVO vo) {
+ log.debug("행위 유형 삭제 - 코드: {}", vo.getActTypeCd());
+
+ // PK(코드) 필수값 검증
+ if (vo.getActTypeCd() == null || vo.getActTypeCd().trim().isEmpty()) {
+ log.warn("행위 유형 삭제 실패 - 코드 미입력");
+ throw new MessageException("코드는 필수값입니다.");
+ }
+
+ // 삭제 수행
+ int result = mapper.delete(vo);
+ log.debug("행위 유형 삭제 완료 - 삭제 건수: {}", result);
+ return result;
+ }
+
+ /**
+ * PK(코드) 중복 체크를 수행한다.
+ * @param vo 중복 체크할 PK 정보(actTypeCd)를 담은 VO 객체
+ * @return 중복 건수 (0이면 중복 없음, 1이상이면 중복 존재)
+ */
+ @Override
+ public int selectDuplicateCheck(ActTypeVO vo) {
+ log.debug("행위 유형 중복 체크 - 코드: {}", vo.getActTypeCd());
+ return mapper.selectDuplicateCheck(vo);
+ }
+
+
+}
diff --git a/src/main/java/go/kr/project/baseData/cmpttnRt2/controller/CmpttnRt2Controller.java b/src/main/java/go/kr/project/baseData/cmpttnRt2/controller/CmpttnRt2Controller.java
new file mode 100644
index 0000000..ee99920
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/cmpttnRt2/controller/CmpttnRt2Controller.java
@@ -0,0 +1,167 @@
+package go.kr.project.baseData.cmpttnRt2.controller;
+
+import egovframework.constant.MessageConstants;
+import egovframework.constant.TilesConstants;
+import egovframework.exception.MessageException;
+import egovframework.util.ApiResponseUtil;
+import egovframework.util.SessionUtil;
+import go.kr.project.baseData.cmpttnRt2.model.CmpttnRt2VO;
+import go.kr.project.baseData.cmpttnRt2.service.CmpttnRt2Service;
+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;
+import lombok.RequiredArgsConstructor;
+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.*;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * packageName : go.kr.project.baseData.cmpttnRt2.controller
+ * fileName : CmpttnRt2Controller
+ * author : 김의진
+ * date : 2025-09-24
+ * description : 기준자료 > 산정률2 웹 컨트롤러
+ * 중요 로직 주석:
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-24 김의진 최초 생성
+ */
+@Controller
+@RequestMapping("/baseData/cmpttnRt2")
+@RequiredArgsConstructor
+@Slf4j
+@Tag(name = "기준자료: 산정률2", description = "산정률2 관리 API")
+public class CmpttnRt2Controller {
+
+ /** 산정률2 서비스 */
+ private final CmpttnRt2Service service;
+
+ /**
+ * 산정률2 목록 페이지를 조회한다.
+ * @param vo 검색 조건을 담은 VO 객체
+ * @param model 뷰에 전달할 데이터를 담는 모델 객체
+ * @return 목록 페이지 뷰 이름
+ */
+ @GetMapping("/list.do")
+ @Operation(summary = "산정률2 목록 페이지", description = "목록 페이지를 조회합니다.")
+ public String listPage(CmpttnRt2VO vo, Model model){
+ log.debug("산정률2 목록 페이지 조회");
+ return "baseData/cmpttnRt2/list" + TilesConstants.BASE;
+ }
+
+ /**
+ * 산정률2 목록을 AJAX로 조회한다.
+ * 서버사이드 페이징을 지원하며 검색 조건에 따라 필터링된 결과를 반환한다.
+ * @param vo 검색 조건과 페이징 정보를 담은 VO 객체
+ * @return 목록 데이터와 페이징 정보를 담은 ResponseEntity
+ */
+ @PostMapping("/list.ajax")
+ @Operation(summary = "목록 조회(AJAX)", description = "페이징 목록을 JSON으로 반환")
+ @ApiResponse(responseCode = "200", description = "성공")
+ public ResponseEntity> listAjax(@ModelAttribute CmpttnRt2VO vo){
+ log.debug("산정률2 목록 AJAX 조회 - 검색조건: {}", vo);
+ int total = service.selectListTotalCount(vo); // 1. 총 개수 조회
+ vo.setTotalCount(total); // 2. setTotalCount
+ //vo.setPagingYn("Y"); // 3. 페이징 처리
+ return ApiResponseUtil.successWithGrid(service.selectList(vo), vo);
+ }
+
+ /**
+ * 산정률2 등록/수정/조회 팝업 페이지를 조회한다.
+ * mode 파라미터에 따라 등록(C), 수정(U), 조회(V) 모드로 동작한다.
+ * @param vo PK 정보를 담은 VO 객체
+ * @param mode 화면 모드 (C: 등록, U: 수정, V: 조회)
+ * @param model 뷰에 전달할 데이터를 담는 모델 객체
+ * @return 팝업 페이지 뷰 이름
+ */
+ @GetMapping("/popup.do")
+ @Operation(summary = "등록/수정/조회 팝업", description = "window.open으로 호출되는 팝업, mode 파라미터로 C/U/V 구분")
+ public ModelAndView popup(
+ @Parameter(description = "산정률2 코드") @RequestParam(required = false) String cmpttnRt2Cd,
+ @Parameter(description = "화면 모드 (C:등록, U:수정, V:보기)") @RequestParam String mode,
+ Model model) {
+
+ try {
+ log.debug("산정률2 팝업 화면 요청 - 모드: {}, 구조지수코드: {}", mode, cmpttnRt2Cd);
+
+ ModelAndView mav = new ModelAndView("baseData/cmpttnRt2/popup" + TilesConstants.POPUP);
+ mav.addObject("mode", mode);
+
+ // 수정/조회 모드인 경우 기존 데이터 조회
+ if (("U".equals(mode) || "V".equals(mode)) && cmpttnRt2Cd != null) {
+ CmpttnRt2VO paramVO = new CmpttnRt2VO();
+ paramVO.setCmpttnRt2Cd(cmpttnRt2Cd);
+
+ CmpttnRt2VO data = service.selectOne(paramVO);
+ if (data != null) {
+ mav.addObject("data", data);
+ } else {
+ throw new MessageException("해당 산정률2 정보를 찾을 수 없습니다.");
+ }
+ }
+
+ return mav;
+
+ } catch (Exception e) {
+ log.error("산정률2 팝업 화면 제공 중 오류 발생", e);
+ throw new MessageException("팝업 화면을 불러오는 중 오류가 발생했습니다.");
+ }
+ }
+
+ /**
+ * 새로운 산정률2 정보를 등록한다.
+ * @param vo 등록할 산정률2 정보를 담은 VO 객체
+ * @return 등록 결과를 담은 ResponseEntity
+ */
+ @Operation(summary = "산정률2 등록", description = "새로운 산정률2 정보를 등록합니다.")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "산정률2 등록 성공"),
+ @ApiResponse(responseCode = "400", description = "산정률2 등록 실패"),
+ @ApiResponse(description = "오류로 인한 실패")
+ })
+ @PostMapping("/insert.ajax")
+ public ResponseEntity> insert(@ModelAttribute CmpttnRt2VO paramVO) throws Exception {
+ // 등록자 정보 설정
+ paramVO.setRgtr(SessionUtil.getUserId());
+
+ int result = service.insert(paramVO);
+
+ if (result > 0) {
+ return ApiResponseUtil.success(MessageConstants.Common.SAVE_SUCCESS);
+ } else {
+ return ApiResponseUtil.error(MessageConstants.Common.SAVE_ERROR);
+ }
+ }
+
+ /**
+ * 기존 산정률2 정보를 수정한다.
+ * @param vo 수정할 산정률2 정보를 담은 VO 객체
+ * @return 수정 결과를 담은 ResponseEntity
+ */
+ @Operation(summary = "산정률2 수정", description = "기존 산정률2 정보를 수정합니다.")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "산정률2 수정 성공"),
+ @ApiResponse(responseCode = "400", description = "산정률2 수정 실패"),
+ @ApiResponse(description = "오류로 인한 실패")
+ })
+ @PostMapping("/update.ajax")
+ public ResponseEntity> update(@ModelAttribute CmpttnRt2VO paramVO) throws Exception {
+ // 수정자 정보 설정
+ paramVO.setMdfr(SessionUtil.getUserId());
+
+ int result = service.update(paramVO);
+
+ if (result > 0) {
+ return ApiResponseUtil.success(MessageConstants.Common.UPDATE_SUCCESS);
+ } else {
+ return ApiResponseUtil.error(MessageConstants.Common.UPDATE_ERROR);
+ }
+ }
+
+}
diff --git a/src/main/java/go/kr/project/baseData/cmpttnRt2/mapper/CmpttnRt2Mapper.java b/src/main/java/go/kr/project/baseData/cmpttnRt2/mapper/CmpttnRt2Mapper.java
new file mode 100644
index 0000000..248833a
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/cmpttnRt2/mapper/CmpttnRt2Mapper.java
@@ -0,0 +1,71 @@
+package go.kr.project.baseData.cmpttnRt2.mapper;
+
+import go.kr.project.baseData.cmpttnRt2.model.CmpttnRt2VO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * packageName : go.kr.project.baseData.cmpttnRt2.mapper
+ * fileName : CmpttnRt2Mapper
+ * author : 김의진
+ * date : 2025-09-24
+ * description : 산정률2 MyBatis Mapper 인터페이스
+ * 중요한 로직 주석: SQL 쿼리와 매핑되는 메서드들을 정의하여 데이터베이스 접근을 담당한다.
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-24 김의진 최초 생성
+ */
+@Mapper
+public interface CmpttnRt2Mapper {
+
+ /**
+ * 산정률2 목록을 조회한다.
+ * @param vo 검색 조건과 페이징 정보를 담은 VO 객체
+ * @return 산정률2 목록
+ */
+ List selectList(CmpttnRt2VO vo);
+
+ /**
+ * 산정률2 목록의 총 개수를 조회한다.
+ * @param vo 검색 조건을 담은 VO 객체
+ * @return 조회된 목록의 총 개수
+ */
+ int selectListTotalCount(CmpttnRt2VO vo);
+
+ /**
+ * 특정 코드의 산정률2 정보를 조회한다.
+ * @param vo 조회할 PK 정보를 담은 VO 객체
+ * @return 조회된 산정률2 정보
+ */
+ CmpttnRt2VO selectOne(CmpttnRt2VO vo);
+
+ /**
+ * 새로운 산정률2 정보를 등록한다.
+ * @param vo 등록할 산정률2 정보를 담은 VO 객체
+ * @return 등록된 행의 수
+ */
+ int insert(CmpttnRt2VO vo);
+
+ /**
+ * 기존 산정률2 정보를 수정한다.
+ * @param vo 수정할 산정률2 정보를 담은 VO 객체
+ * @return 수정된 행의 수
+ */
+ int update(CmpttnRt2VO vo);
+
+ /**
+ * 산정률2 정보를 삭제한다.
+ * @param vo 삭제할 PK 정보(cmpttnRt2Cd)를 담은 VO 객체
+ * @return 삭제된 행의 수
+ */
+ int delete(CmpttnRt2VO vo);
+
+ /**
+ * PK(코드) 중복 체크를 수행한다.
+ * @param vo 중복 체크할 PK 정보(cmpttnRt2Cd)를 담은 VO 객체
+ * @return 중복 건수 (0이면 중복 없음, 1이상이면 중복 존재)
+ */
+ int selectDuplicateCheck(CmpttnRt2VO vo);
+}
diff --git a/src/main/java/go/kr/project/baseData/cmpttnRt2/model/CmpttnRt2VO.java b/src/main/java/go/kr/project/baseData/cmpttnRt2/model/CmpttnRt2VO.java
new file mode 100644
index 0000000..bdbd23d
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/cmpttnRt2/model/CmpttnRt2VO.java
@@ -0,0 +1,80 @@
+package go.kr.project.baseData.cmpttnRt2.model;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import go.kr.project.common.model.PagingVO;
+import lombok.*;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * packageName : go.kr.project.baseData.cmpttnRt2.model
+ * fileName : CmpttnRt2VO
+ * author : 김의진
+ * date : 2025-09-24
+ * description : 산정률2 관련 데이터를 담는 Value Object 클래스
+ * 중요한 로직 주석: 산정률2 테이블(tb_cmpttn_rt2)과 매핑되는 VO 클래스로 페이징 기능을 포함한다. *
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-24 김의진 최초 생성
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString
+public class CmpttnRt2VO extends PagingVO {
+
+ // ==================== 기본 테이블 컬럼 ====================
+
+ /** 산정률2 코드 (PK) - 1자리 코드 */
+ private String cmpttnRt2Cd;
+
+ /** 위반 사항 */
+ private String vltnMttr;
+
+ /** 산정률2 - DECIMAL(3,0) */
+ private BigDecimal cmpttnRt2;
+
+ /** 사용 여부 */
+ private String useYn;
+
+ /** 등록 일시 - 테이블은 date 컬럼을 사용하지만 화면 표시용으로 문자열 타입 사용 */
+ @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;
+
+ /** 등록자 ID */
+ private String rgtr;
+
+ /** 수정 일시 */
+ @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 mdfcnDt;
+
+ /** 수정자 ID */
+ private String mdfr;
+
+ // ==================== 조인 컬럼 (코드명) ====================
+
+ /** 등록자 */
+ private String rgtrNm;
+
+ /** 수정자 */
+ private String mdfrNm;
+
+ /** 행 번호 (그리드 표시용) */
+ private Integer rowNum;
+
+ // ==================== 검색 조건 ====================
+
+ /** 검색 조건 선택 */
+ private String schType;
+ private String schTypeTxt;
+
+ /** 검색 조건 - 사용 여부 */
+ private String schUseYn;
+}
diff --git a/src/main/java/go/kr/project/baseData/cmpttnRt2/service/CmpttnRt2Service.java b/src/main/java/go/kr/project/baseData/cmpttnRt2/service/CmpttnRt2Service.java
new file mode 100644
index 0000000..ecb4517
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/cmpttnRt2/service/CmpttnRt2Service.java
@@ -0,0 +1,69 @@
+package go.kr.project.baseData.cmpttnRt2.service;
+
+import go.kr.project.baseData.cmpttnRt2.model.CmpttnRt2VO;
+
+import java.util.List;
+
+/**
+ * packageName : go.kr.project.baseData.cmpttnRt2.service
+ * fileName : CmpttnRt2Service
+ * author : 김의진
+ * date : 2025-09-24
+ * description : 산정률2 비즈니스 로직 처리를 위한 서비스 인터페이스
+ * 중요한 로직 주석: 컨트롤러와 매퍼 사이의 비즈니스 로직을 정의하고 데이터 처리 규칙을 관리한다.
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-24 김의진 최초 생성
+ */
+public interface CmpttnRt2Service {
+
+ /**
+ * 산정률2 목록을 조회한다.
+ * @param vo 검색 조건과 페이징 정보를 담은 VO 객체
+ * @return 산정률2 목록
+ */
+ List selectList(CmpttnRt2VO vo);
+
+ /**
+ * 산정률2 목록의 총 개수를 조회한다.
+ * @param vo 검색 조건을 담은 VO 객체
+ * @return 조회된 목록의 총 개수
+ */
+ int selectListTotalCount(CmpttnRt2VO vo);
+
+ /**
+ * 특정 코드의 산정률2 정보를 조회한다.
+ * @param vo 조회할 PK 정보를 담은 VO 객체
+ * @return 조회된 산정률2 정보
+ */
+ CmpttnRt2VO selectOne(CmpttnRt2VO vo);
+
+ /**
+ * 새로운 산정률2 정보를 등록한다.
+ * @param vo 등록할 산정률2 정보를 담은 VO 객체
+ * @return 등록된 행의 수
+ */
+ int insert(CmpttnRt2VO vo);
+
+ /**
+ * 기존 산정률2 정보를 수정한다.
+ * @param vo 수정할 산정률2 정보를 담은 VO 객체
+ * @return 수정된 행의 수
+ */
+ int update(CmpttnRt2VO vo);
+
+ /**
+ * 산정률2 정보를 삭제한다.
+ * @param vo 삭제할 PK 정보(cmpttnRt2Cd)를 담은 VO 객체
+ * @return 삭제된 행의 수
+ */
+ int delete(CmpttnRt2VO vo);
+
+ /**
+ * PK(코드) 중복 체크를 수행한다.
+ * @param vo 중복 체크할 PK 정보(cmpttnRt2Cd)를 담은 VO 객체
+ * @return 중복 건수 (0이면 중복 없음, 1이상이면 중복 존재)
+ */
+ int selectDuplicateCheck(CmpttnRt2VO vo);
+}
diff --git a/src/main/java/go/kr/project/baseData/cmpttnRt2/service/impl/CmpttnRt2ServiceImpl.java b/src/main/java/go/kr/project/baseData/cmpttnRt2/service/impl/CmpttnRt2ServiceImpl.java
new file mode 100644
index 0000000..3c9c1d5
--- /dev/null
+++ b/src/main/java/go/kr/project/baseData/cmpttnRt2/service/impl/CmpttnRt2ServiceImpl.java
@@ -0,0 +1,176 @@
+package go.kr.project.baseData.cmpttnRt2.service.impl;
+
+import egovframework.exception.MessageException;
+import egovframework.util.SessionUtil;
+import egovframework.util.StringUtil;
+import go.kr.project.baseData.cmpttnRt2.mapper.CmpttnRt2Mapper;
+import go.kr.project.baseData.cmpttnRt2.model.CmpttnRt2VO;
+import go.kr.project.baseData.cmpttnRt2.service.CmpttnRt2Service;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * packageName : go.kr.project.baseData.cmpttnRt2.service.impl
+ * fileName : CmpttnRt2ServiceImpl
+ * author : 김의진
+ * date : 2025-09-22
+ * description : 산정률2 비즈니스 로직 처리를 위한 서비스 구현체
+ * 중요한 로직 주석: 서비스 인터페이스를 구현하여 실제 비즈니스 로직을 처리하고 매퍼를 호출한다.
+ * ===========================================================
+ * DATE AUTHOR NOTE
+ * -----------------------------------------------------------
+ * 2025-09-22 김의진 최초 생성
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class CmpttnRt2ServiceImpl extends EgovAbstractServiceImpl implements CmpttnRt2Service {
+
+ /** 산정률2 매퍼 */
+ private final CmpttnRt2Mapper mapper;
+
+ /**
+ * 산정률2 목록을 조회한다.
+ * @param vo 검색 조건과 페이징 정보를 담은 VO 객체
+ * @return 산정률2 목록
+ */
+ @Override
+ public List selectList(CmpttnRt2VO vo) {
+ log.debug("산정률2 목록 조회 - 검색조건: {}", vo);
+ return mapper.selectList(vo);
+ }
+
+ /**
+ * 산정률2 목록의 총 개수를 조회한다.
+ * @param vo 검색 조건을 담은 VO 객체
+ * @return 조회된 목록의 총 개수
+ */
+ @Override
+ public int selectListTotalCount(CmpttnRt2VO vo) {
+ log.debug("산정률2 총 개수 조회 - 검색조건: {}", vo);
+ return mapper.selectListTotalCount(vo);
+ }
+
+ /**
+ * 특정 코드에 해당하는 산정률2 정보를 조회한다.
+ * @param vo 조회할 PK 정보(cmpttnRt2Cd)를 담은 VO 객체
+ * @return 조회된 산정률2 정보
+ */
+ @Override
+ public CmpttnRt2VO selectOne(CmpttnRt2VO vo) {
+ log.debug("산정률2 단건 조회 - 코드: {}", vo.getCmpttnRt2Cd());
+ return mapper.selectOne(vo);
+ }
+
+ /**
+ * 새로운 산정률2 정보를 등록한다.
+ * PK(코드) 필수값 검증과 중복 체크를 수행한 후 등록을 진행한다.
+ * @param vo 등록할 산정률2 정보를 담은 VO 객체
+ * @return 등록된 행의 수
+ * @throws MessageException PK 필수값 누락 또는 중복 시 발생
+ */
+ @Override
+ public int insert(CmpttnRt2VO vo) {
+ log.debug("산정률2 등록 - 코드: {}, 위반 건축물: {}", vo.getCmpttnRt2Cd(), vo.getVltnMttr());
+
+ // PK(코드) 필수값 검증
+ if (vo.getCmpttnRt2Cd() == null || vo.getCmpttnRt2Cd().trim().isEmpty()) {
+ log.warn("산정률2 등록 실패 - 코드 미입력");
+ throw new MessageException("코드는 필수값입니다.");
+ }
+
+ // PK 중복 체크
+ int duplicateCount = mapper.selectDuplicateCheck(vo);
+ if (duplicateCount > 0) {
+ log.warn("산정률2 등록 실패 - 중복된 PK: 코드={}", vo.getCmpttnRt2Cd());
+ throw new MessageException("이미 존재하는 산정률2 코드입니다. 다른 값을 입력해주세요.");
+ }
+
+ // 위반 건축물 바이트 길이 검증 (한글 3바이트 기준 최대 100바이트)
+ if (vo.getVltnMttr() != null && !vo.getVltnMttr().trim().isEmpty()) {
+ int byteLength = StringUtil.calculateUtf8ByteLength(vo.getVltnMttr());
+ if (byteLength > 100) {
+ log.warn("산정률2 등록 실패 - 위반 건축물 바이트 길이 초과: {}바이트", byteLength);
+ throw new MessageException("위반 사항은 최대 100바이트까지 입력 가능합니다. (현재: " + byteLength + "바이트)");
+ }
+ }
+
+ // 등록자 정보 설정 및 등록 수행
+ vo.setRgtr(SessionUtil.getUserId());
+ int result = mapper.insert(vo);
+ log.debug("산정률2 등록 완료 - 등록 건수: {}", result);
+ return result;
+ }
+
+ /**
+ * 기존 산정률2 정보를 수정한다.
+ * PK(코드) 필수값 검증을 수행한 후 수정을 진행한다.
+ * @param vo 수정할 산정률2 정보를 담은 VO 객체
+ * @return 수정된 행의 수
+ * @throws MessageException PK 필수값 누락 시 발생
+ */
+ @Override
+ public int update(CmpttnRt2VO vo) {
+ log.debug("산정률2 수정 - 코드: {}, 위반 건축물: {}", vo.getCmpttnRt2Cd(), vo.getVltnMttr());
+
+ // PK(코드) 필수값 검증
+ if (vo.getCmpttnRt2Cd() == null || vo.getCmpttnRt2Cd().trim().isEmpty()) {
+ log.warn("산정률2 등록 실패 - 코드 미입력");
+ throw new MessageException("코드는 필수값입니다.");
+ }
+
+ // 위반 건축물 바이트 길이 검증 (한글 3바이트 기준 최대 100바이트)
+ if (vo.getVltnMttr() != null && !vo.getVltnMttr().trim().isEmpty()) {
+ int byteLength = StringUtil.calculateUtf8ByteLength(vo.getVltnMttr());
+ if (byteLength > 100) {
+ log.warn("산정률2 등록 실패 - 위반 건축물 바이트 길이 초과: {}바이트", byteLength);
+ throw new MessageException("위반 사항은 최대 100바이트까지 입력 가능합니다. (현재: " + byteLength + "바이트)");
+ }
+ }
+
+ // 수정 수행
+ int result = mapper.update(vo);
+ log.debug("산정률2 수정 완료 - 수정 건수: {}", result);
+ return result;
+ }
+
+ /**
+ * 산정률2 정보를 삭제한다.
+ * PK(코드) 필수값 검증을 수행한 후 삭제를 진행한다.
+ * @param vo 삭제할 PK 정보(코드)를 담은 VO 객체
+ * @return 삭제된 행의 수
+ * @throws MessageException PK 필수값 누락 시 발생
+ */
+ @Override
+ public int delete(CmpttnRt2VO vo) {
+ log.debug("산정률2 삭제 - 코드: {}", vo.getCmpttnRt2Cd());
+
+ // PK(코드) 필수값 검증
+ if (vo.getCmpttnRt2Cd() == null || vo.getCmpttnRt2Cd().trim().isEmpty()) {
+ log.warn("산정률2 삭제 실패 - 코드 미입력");
+ throw new MessageException("코드는 필수값입니다.");
+ }
+
+ // 삭제 수행
+ int result = mapper.delete(vo);
+ log.debug("산정률2 삭제 완료 - 삭제 건수: {}", result);
+ return result;
+ }
+
+ /**
+ * PK(코드) 중복 체크를 수행한다.
+ * @param vo 중복 체크할 PK 정보(cmpttnRt2Cd)를 담은 VO 객체
+ * @return 중복 건수 (0이면 중복 없음, 1이상이면 중복 존재)
+ */
+ @Override
+ public int selectDuplicateCheck(CmpttnRt2VO vo) {
+ log.debug("산정률2 중복 체크 - 코드: {}", vo.getCmpttnRt2Cd());
+ return mapper.selectDuplicateCheck(vo);
+ }
+
+
+}
diff --git a/src/main/java/go/kr/project/baseData/strctIdx/controller/StrctIdxController.java b/src/main/java/go/kr/project/baseData/strctIdx/controller/StrctIdxController.java
index efb41ee..5acfb6e 100644
--- a/src/main/java/go/kr/project/baseData/strctIdx/controller/StrctIdxController.java
+++ b/src/main/java/go/kr/project/baseData/strctIdx/controller/StrctIdxController.java
@@ -87,7 +87,7 @@ public class StrctIdxController {
@Parameter(description = "화면 모드 (C:등록, U:수정, V:보기)") @RequestParam String mode,
Model model) {
- //try {
+ try {
log.debug("구조 지수 팝업 화면 요청 - 모드: {}, 구조지수코드: {}", mode, strctIdxCd);
ModelAndView mav = new ModelAndView("baseData/strctIdx/popup" + TilesConstants.POPUP);
@@ -108,10 +108,10 @@ public class StrctIdxController {
return mav;
- //} catch (Exception e) {
- // log.error("구조 지수 팝업 화면 제공 중 오류 발생", e);
- // throw new MessageException("팝업 화면을 불러오는 중 오류가 발생했습니다.");
- //}
+ } catch (Exception e) {
+ log.error("구조 지수 팝업 화면 제공 중 오류 발생", e);
+ throw new MessageException("팝업 화면을 불러오는 중 오류가 발생했습니다.");
+ }
}
/**
diff --git a/src/main/java/go/kr/project/noti/controller/NotiController.java b/src/main/java/go/kr/project/noti/controller/NotiController.java
index 51ea506..5fe8aea 100644
--- a/src/main/java/go/kr/project/noti/controller/NotiController.java
+++ b/src/main/java/go/kr/project/noti/controller/NotiController.java
@@ -1,17 +1,13 @@
package go.kr.project.noti.controller;
-import egovframework.constant.MessageConstants;
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.noti.model.NotiImpltInfoVO;
import go.kr.project.noti.model.NotiImpltTrprInfoVO;
import go.kr.project.noti.service.NotiService;
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;
@@ -21,7 +17,6 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
-import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
diff --git a/src/main/java/go/kr/project/noti/model/NotiImpltTrprInfoVO.java b/src/main/java/go/kr/project/noti/model/NotiImpltTrprInfoVO.java
index 14dae91..810dc65 100644
--- a/src/main/java/go/kr/project/noti/model/NotiImpltTrprInfoVO.java
+++ b/src/main/java/go/kr/project/noti/model/NotiImpltTrprInfoVO.java
@@ -20,7 +20,6 @@ import java.time.LocalDateTime;
* -----------------------------------------------------------
* 2025-09-11 김의진 최초 생성
*/
-@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
diff --git a/src/main/resources/mybatis/mapper/baseData/actType/ActTypeMapper_maria.xml b/src/main/resources/mybatis/mapper/baseData/actType/ActTypeMapper_maria.xml
new file mode 100644
index 0000000..077b11a
--- /dev/null
+++ b/src/main/resources/mybatis/mapper/baseData/actType/ActTypeMapper_maria.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO tb_act_type (
+ ACT_TYPE_CD /* 행위 유형 코드 */
+ , VLTN_BDST /* 위반 건축물 */
+ , LAWLPRVS /* 법조문 */
+ , CMPTTN_RT /* 산정률 */
+ , VLTN_BDST_DTL /* 위반 건축물 상세 */
+ , USE_YN /* 사용 여부 */
+ , REG_DT /* 등록 일시 */
+ , RGTR /* 등록자 */
+ ) VALUES (
+ #{actTypeCd} /* 행위 유형 코드 */
+ , #{vltnBdst} /* 위반 건축물 */
+ , #{lawlprvs} /* 법조문 */
+ , #{cmpttnRt} /* 산정률 */
+ , #{vltnBdstDtl} /* 위반 건축물 상세 */
+ , #{useYn} /* 사용 여부 */
+ , NOW() /* 등록 일시 - 현재 날짜 자동 설정 */
+ , #{rgtr} /* 등록자 - 세션 사용자 ID */
+ )
+
+
+
+
+ UPDATE tb_act_type
+ SET VLTN_BDST = #{vltnBdst} /* 위반 건축물 */
+ , LAWLPRVS = #{lawlprvs} /* 법조문 */
+ , CMPTTN_RT = #{cmpttnRt} /* 산정률 */
+ , VLTN_BDST_DTL = #{vltnBdstDtl} /* 위반 건축물 상세 */
+ , USE_YN = #{useYn} /* 사용 여부 */
+ , MDFCN_DT = NOW() /* 수정 일시 */
+ , MDFR = #{mdfr} /* 수정자 */
+ WHERE ACT_TYPE_CD = #{actTypeCd} /* 행위 유형 코드 */
+
+
+
+
+
diff --git a/src/main/resources/mybatis/mapper/baseData/cmpttnRt2/CmpttnRt2Mapper_maria.xml b/src/main/resources/mybatis/mapper/baseData/cmpttnRt2/CmpttnRt2Mapper_maria.xml
new file mode 100644
index 0000000..a263cc8
--- /dev/null
+++ b/src/main/resources/mybatis/mapper/baseData/cmpttnRt2/CmpttnRt2Mapper_maria.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO tb_cmpttn_rt_2 (
+ CMPTTN_RT_2_CD /* 산정률2 코드 */
+ , VLTN_MTTR /* 위반 사항 */
+ , CMPTTN_RT_2 /* 산정률2 */
+ , USE_YN /* 사용 여부 */
+ , REG_DT /* 등록 일시 */
+ , RGTR /* 등록자 */
+ ) VALUES (
+ #{cmpttnRt2Cd} /* 산정률2 코드 */
+ , #{vltnMttr} /* 위반 사항 */
+ , #{cmpttnRt2} /* 산정률2 */
+ , #{useYn} /* 사용 여부 */
+ , NOW() /* 등록 일시 - 현재 날짜 자동 설정 */
+ , #{rgtr} /* 등록자 - 세션 사용자 ID */
+ )
+
+
+
+
+ UPDATE tb_cmpttn_rt_2
+ SET VLTN_MTTR = #{vltnMttr} /* 위반 사항 */
+ , CMPTTN_RT_2 = #{cmpttnRt2} /* 산정률2 */
+ , USE_YN = #{useYn} /* 사용 여부 */
+ , MDFCN_DT = NOW() /* 수정 일시 */
+ , MDFR = #{mdfr} /* 수정자 */
+ WHERE CMPTTN_RT_2_CD = #{cmpttnRt2Cd} /* 산정률2 코드 */
+
+
+
+
+
diff --git a/src/main/webapp/WEB-INF/views/baseData/actType/list.jsp b/src/main/webapp/WEB-INF/views/baseData/actType/list.jsp
new file mode 100644
index 0000000..372b567
--- /dev/null
+++ b/src/main/webapp/WEB-INF/views/baseData/actType/list.jsp
@@ -0,0 +1,376 @@
+<%@ 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"%>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/views/baseData/actType/popup.jsp b/src/main/webapp/WEB-INF/views/baseData/actType/popup.jsp
new file mode 100644
index 0000000..544561e
--- /dev/null
+++ b/src/main/webapp/WEB-INF/views/baseData/actType/popup.jsp
@@ -0,0 +1,160 @@
+<%@ 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" %>
+
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/views/baseData/cmpttnRt2/list.jsp b/src/main/webapp/WEB-INF/views/baseData/cmpttnRt2/list.jsp
new file mode 100644
index 0000000..614e66f
--- /dev/null
+++ b/src/main/webapp/WEB-INF/views/baseData/cmpttnRt2/list.jsp
@@ -0,0 +1,366 @@
+<%@ 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"%>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/views/baseData/cmpttnRt2/popup.jsp b/src/main/webapp/WEB-INF/views/baseData/cmpttnRt2/popup.jsp
new file mode 100644
index 0000000..44db43a
--- /dev/null
+++ b/src/main/webapp/WEB-INF/views/baseData/cmpttnRt2/popup.jsp
@@ -0,0 +1,147 @@
+<%@ 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" %>
+
+
+
+
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/views/baseData/strctIdx/list.jsp b/src/main/webapp/WEB-INF/views/baseData/strctIdx/list.jsp
index 10a4e31..7c30b74 100644
--- a/src/main/webapp/WEB-INF/views/baseData/strctIdx/list.jsp
+++ b/src/main/webapp/WEB-INF/views/baseData/strctIdx/list.jsp
@@ -142,7 +142,7 @@
header : '구조명',
name : 'strctNm',
align : 'center',
- width : 300,
+ minwidth : 300,
sortable : true
}, {
header : '구조지수',
@@ -319,6 +319,7 @@
// 모든 검색 조건 초기화
$("#schType").val("1");
$("#schTypeTxt").val("");
+ $("#schDelYn").val("N");
// 그리드 데이터 새로고침
self.grid.instance.readData();
diff --git a/src/main/webapp/WEB-INF/views/baseData/usgIdx/list.jsp b/src/main/webapp/WEB-INF/views/baseData/usgIdx/list.jsp
index ebcca65..01a267b 100644
--- a/src/main/webapp/WEB-INF/views/baseData/usgIdx/list.jsp
+++ b/src/main/webapp/WEB-INF/views/baseData/usgIdx/list.jsp
@@ -144,7 +144,7 @@
header : '용도명',
name : 'usgNm',
align : 'center',
- width : 400,
+ minwidth : 400,
sortable : true
}, {
header : '용도지수',
diff --git a/src/main/webapp/WEB-INF/views/crdn/exmnr/list.jsp b/src/main/webapp/WEB-INF/views/crdn/exmnr/list.jsp
index 8c1416b..e68a23f 100644
--- a/src/main/webapp/WEB-INF/views/crdn/exmnr/list.jsp
+++ b/src/main/webapp/WEB-INF/views/crdn/exmnr/list.jsp
@@ -171,7 +171,7 @@
header: '조사원',
name: 'exmnr',
align: 'center',
- width: 120
+ minwidth: 120
//sortable: true
},
{
@@ -185,7 +185,19 @@
name: 'rgtrNm',
align: 'center',
width: 100
- }
+ },
+ {
+ header : '수정일시',
+ name : 'mdfcnDt',
+ align : 'center',
+ width : 150
+ },
+ {
+ header : '수정자',
+ name : 'mdfrNm',
+ align : 'center',
+ width : 100
+ }
];
},
diff --git a/src/main/webapp/WEB-INF/views/noti/list.jsp b/src/main/webapp/WEB-INF/views/noti/list.jsp
index 78ff81a..2cbe3ca 100644
--- a/src/main/webapp/WEB-INF/views/noti/list.jsp
+++ b/src/main/webapp/WEB-INF/views/noti/list.jsp
@@ -202,6 +202,12 @@
width: 100,
sortable: true
},
+ {
+ header: '진행단계',
+ name: 'impltTaskSeCdNm',
+ align: 'center',
+ width: 100
+ },
{
header: '구분',
name: 'rgnSeCdNm',
@@ -305,6 +311,10 @@
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.selectCdGroupId = '';
+ NotiList.detailGrid.instance.readData(1);
}
// 선택된 행 초기화
diff --git a/src/main/webapp/resources/xit/common_util.js b/src/main/webapp/resources/xit/common_util.js
index de5f14a..1ebe721 100644
--- a/src/main/webapp/resources/xit/common_util.js
+++ b/src/main/webapp/resources/xit/common_util.js
@@ -162,7 +162,7 @@ $(document).ready(function () {
groupSeparator: ",", // 그룹 구분자 없음
repeat: 1, // 정수부 최대 1자리 (0)
digits: 4, // 소수점 최대 4자리
- max: 0.9999,
+ max: 0.9999
});
});
@@ -194,6 +194,36 @@ $(document).ready(function () {
digits: 2 // 소수점 사용 안함
});
});
+
+ // 중요로직: Act_Type_Cd 전용 마스크 - 숫자 3자리
+ $("body").on("focus", ".actTypeCdMask", function () {
+ $(this).inputmask({
+ mask: "999", // 3자리 숫자 패턴 (선행 0 포함)
+ placeholder: "000", // 입력 안내용 플레이스홀더
+ definitions: {
+ "9": {
+ validator: "[0-9]", // 숫자만 허용
+ cardinality: 1
+ }
+ },
+ autoUnmask: true, // 마스크 제거 후 실제 값 반환
+ rightAlign: false // 왼쪽 정렬
+ });
+ });
+
+ // 중요로직: Cmpttn_Rt 전용 마스크 - 숫자 3자리
+ $("body").on("focus", ".cmpttnRtMask", function () {
+ $(this).inputmask("numeric", {
+ autoGroup: true, // 그룹화 사용 안함
+ allowMinus: false, // 음수 사용 안함
+ autoUnmask: true,
+ rightAlign: false,
+ groupSeparator: ",", // 그룹 구분자 없음
+ repeat: 3, // 정수부 최대 3자리
+ digits: 0, // 소수점 사용 안함
+ max: 100
+ });
+ });
});