초기 셋팅

internalApi
박성영 1 month ago
parent ed04c2ae65
commit b10769679a

@ -1,63 +0,0 @@
package go.kr.project.carInspectionPenalty.search.controller;
import egovframework.constant.TilesConstants;
import egovframework.util.ApiResponseUtil;
import go.kr.project.api.service.VehicleInfoService;
import go.kr.project.api.model.VehicleApiResponseVO;
import go.kr.project.common.service.CommonCodeService;
import io.swagger.v3.oas.annotations.Operation;
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 java.util.List;
@Controller
@RequestMapping("/carInspectionPenalty/search")
@RequiredArgsConstructor
@Slf4j
@Tag(name = "자동차 검사 과태료 조회", description = "자동차 검사 과태료 조회 API")
public class CarInspectionPenaltyController {
private final CommonCodeService commonCodeService;
private final VehicleInfoService vehicleInfoService;
@GetMapping("/list.do")
public String list( Model model ) {
return "carInspectionPenalty/search/list" + TilesConstants.BASE;
}
/**
* API
* .
* (vmis.integration.mode) API .
*
* @param vehicleNumbers
* @return
*/
@PostMapping("/getVehiclesInfo.do")
@ResponseBody
@Operation(summary = "차량 정보 조회", description = "차량번호 리스트를 받아서 차량 기본정보와 등록원부 정보를 조회합니다.")
public ResponseEntity<?> getVehiclesInfo(@RequestBody List<String> vehicleNumbers) {
log.info("차량 정보 조회 요청 - 차량 수: {}", vehicleNumbers.size());
try {
// 차량 정보 조회 (설정에 따라 internal/external 자동 선택)
List<VehicleApiResponseVO> vehicles = vehicleInfoService.getVehiclesInfo(vehicleNumbers);
log.info("차량 정보 조회 완료 - 총 {}건", vehicles.size());
return ApiResponseUtil.success(vehicles, "차량 정보 조회가 완료되었습니다.");
} catch (Exception e) {
log.error("차량 정보 조회 중 오류 발생", e);
return ApiResponseUtil.error("조회 중 오류가 발생했습니다: " + e.getMessage());
}
}
}

@ -367,20 +367,11 @@
* 파일 업로드 팝업 열기
*/
openUploadPopup: function() {
var popupUrl = '<c:url value="/carInspectionPenalty/registration/uploadPopup.do"/>';
var popupName = 'uploadPopup';
var popupWidth = 600;
var popupHeight = 400;
var left = (window.screen.width - popupWidth) / 2;
var top = (window.screen.height - popupHeight) / 2;
var popup = window.open(
popupUrl,
popupName,
'width=' + popupWidth + ',height=' + popupHeight + ',left=' + left + ',top=' + top + ',resizable=yes,scrollbars=yes'
);
openPopup(popupUrl, 800, 450, 'uploadPopup');
// 팝업이 닫힐 때 그리드 새로고침
var checkPopupClosed = setInterval(function() {
if (popup.closed) {

@ -1,295 +1,212 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TXT 파일 업로드</title>
<link rel="stylesheet" href="<c:url value='/resources/css/common.css'/>">
<link rel="stylesheet" href="<c:url value='/resources/xit/xit-popup.css'/>">
<script src="<c:url value='/resources/js/jquery-3.6.0.min.js'/>"></script>
<script src="<c:url value='/resources/js/common.js'/>"></script>
<style>
body {
margin: 0;
padding: 20px;
font-family: 'Malgun Gothic', sans-serif;
background-color: #f5f5f5;
}
.popup-container {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.popup-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #4CAF50;
color: #333;
}
.upload-section {
margin-bottom: 20px;
}
.upload-label {
display: block;
margin-bottom: 10px;
font-weight: bold;
color: #555;
}
.file-input-wrapper {
position: relative;
display: inline-block;
width: 100%;
}
.file-input-wrapper input[type="file"] {
width: 100%;
padding: 10px;
border: 2px dashed #ddd;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.file-input-wrapper input[type="file"]:hover {
border-color: #4CAF50;
background-color: #f9f9f9;
}
.file-info {
margin-top: 10px;
padding: 10px;
background-color: #f0f0f0;
border-radius: 4px;
font-size: 13px;
color: #666;
}
.file-format-info {
margin-top: 15px;
padding: 15px;
background-color: #fff3cd;
border: 1px solid #ffc107;
border-radius: 4px;
font-size: 13px;
}
.file-format-info h4 {
margin: 0 0 10px 0;
color: #856404;
font-size: 14px;
}
.file-format-info ul {
margin: 0;
padding-left: 20px;
color: #856404;
}
.file-format-info li {
margin-bottom: 5px;
}
.button-area {
margin-top: 20px;
text-align: center;
padding-top: 20px;
border-top: 1px solid #eee;
}
.btn {
padding: 10px 30px;
margin: 0 5px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
transition: all 0.3s;
}
.btn-upload {
background-color: #4CAF50;
color: white;
}
.btn-upload:hover {
background-color: #45a049;
}
.btn-upload:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.btn-close {
background-color: #f44336;
color: white;
}
.btn-close:hover {
background-color: #da190b;
}
.loading {
display: none;
text-align: center;
padding: 20px;
}
.loading.active {
display: block;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #4CAF50;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="popup-container">
<div class="popup-title">과태료 대상 TXT 파일 업로드</div>
<div class="upload-section">
<label class="upload-label">TXT 파일 선택</label>
<div class="file-input-wrapper">
<input type="file" id="txtFile" name="txtFile" accept=".txt" />
</div>
<div class="file-info">
※ TXT 파일만 업로드 가능합니다. (최대 50MB)
</div>
</div>
<div class="file-format-info">
<h4>📋 파일 형식 안내</h4>
<ul>
<li>첫 번째 줄은 헤더로 간주되어 스킵됩니다.</li>
<li>데이터는 탭(Tab)으로 구분되어야 합니다.</li>
<li>컬럼 순서: 접수일자, 구분, 검사소코드, 검사일자, 차량번호, 소유자명, 주민등록번호, 자동차명, 자동차종류, 자동차용도, 검사종료일자, 일수, 과태료금액, 최종등록일자, 주소, 유효기간만료일자, 매매상품</li>
<li>필수 항목: 접수일자, 검사일자, 차량번호, 소유자명, 과태료금액</li>
<li>날짜 형식: YYYYMMDD (예: 20231113)</li>
<li>차량번호 형식: 12가3456 또는 123가4567</li>
</ul>
<!-- 팝업 전용 CSS -->
<link rel="stylesheet" type="text/css" href="<c:url value='/resources/xit/xit-popup.css'/>" />
<!-- TXT 파일 업로드 팝업 -->
<div class="popup_wrap">
<div class="popup_inner">
<div class="popup_tit">
<h2 class="tit">과태료 대상 TXT 파일 업로드</h2>
<a href="#" class="pop-x-btn modalclose" id="btnCloseTop"></a>
</div>
<div class="loading" id="loading">
<div class="spinner"></div>
<div>파일 업로드 중입니다. 잠시만 기다려주세요...</div>
<div class="popup_con">
<form id="uploadForm" name="uploadForm">
<div class="forms_table_non">
<table>
<colgroup>
<col style="width: 20%;" />
<col style="width: 80%;" />
</colgroup>
<tr>
<th class="th"><span class="required">*</span> TXT 파일</th>
<td>
<div class="file-input-wrapper">
<input type="file" id="txtFile" name="txtFile" accept=".txt" class="input" style="width: 100%;" />
</div>
<div class="file-info" style="margin-top: 10px; color: #666; font-size: 13px;">
※ TXT 파일만 업로드 가능합니다. (최대 50MB)
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div class="file-format-info" style="padding: 15px; background-color: #fff3cd; border: 1px solid #ffc107; border-radius: 4px;">
<ul style="margin: 0; padding-left: 20px; color: #856404; font-size: 13px;">
<li>7~10 번째 줄은 헤더 및 라인구분 기호로 간주되어 스킵됩니다.</li>
<li>데이터는 ECU-KR 한글 2Byte으로 구분됩니다.</li>
<li>컬럼 순서: 접수일자, 구분, 검사소코드, 검사일자, 차량번호, 소유자명, 주민등록번호, 자동차명, 자동차종류, 자동차용도, 검사종료일자, 일수, 과태료금액, 최종등록일자, 주소, 유효기간만료일자, 매매상품</li>
<li>필수 항목: 접수일자, 검사일자, 차량번호, 소유자명, 과태료금액</li>
<li>날짜 형식: YYYY-MM-DD (예: 2023-11-13)</li>
<li>차량번호 형식: 12가3456 또는 123가4567</li>
</ul>
</div>
</td>
</tr>
</table>
</div>
</form>
<!-- 중요로직: 로딩 표시 영역 -->
<div class="loading" id="loading" style="display: none; text-align: center; padding: 20px;">
<div class="spinner" style="border: 4px solid #f3f3f3; border-top: 4px solid #4CAF50; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto 10px;"></div>
<div>파일 업로드 중입니다. 잠시만 기다려주세요...</div>
</div>
</div>
<div class="button-area">
<button type="button" class="btn btn-upload" id="uploadBtn">파일 업로드</button>
<button type="button" class="btn btn-close" id="closeBtn">닫기</button>
<div class="popup_foot">
<button type="button" id="btnUpload" class="newbtns bg1">파일 업로드</button>
<button type="button" id="btnClose" class="newbtns bg2 modalclose">닫기</button>
</div>
</div>
</div>
<style>
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading.active {
display: block !important;
}
</style>
<script type="text/javascript">
/**
* TXT 파일 업로드 팝업 JavaScript
* 중요로직: 과태료 대상 TXT 파일을 업로드하고 검증한다.
*/
$(document).ready(function() {
/**
* 파일 업로드 버튼 클릭 이벤트
* 중요로직: 파일 선택 후 검증을 거쳐 서버로 업로드한다.
*/
$("#btnUpload").on('click', function() {
uploadFile();
});
/**
* 닫기 버튼 클릭 이벤트
*/
$("#btnClose, #btnCloseTop").on('click', function() {
closePopup();
});
/**
* 파일 선택 시 파일 정보 표시
*/
$("#txtFile").on('change', function() {
displayFileInfo(this.files[0]);
});
});
<script type="text/javascript">
$(document).ready(function() {
/**
* 파일 업로드 함수
* 중요로직: 파일 검증 후 FormData를 사용하여 파일을 서버로 전송한다.
*/
function uploadFile() {
var fileInput = document.getElementById('txtFile');
var file = fileInput.files[0];
// 중요로직: 파일 선택 여부 검증
if (!file) {
alert("파일을 선택해주세요.");
return;
}
// 중요로직: 파일 확장자 검증
var fileName = file.name;
var fileExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
if (fileExt !== 'txt') {
alert("TXT 파일만 업로드 가능합니다.");
return;
}
// 중요로직: 파일 크기 검증 (50MB)
if (file.size > 50 * 1024 * 1024) {
alert("파일 크기는 50MB를 초과할 수 없습니다.");
return;
}
// 확인 메시지
if (!confirm("선택한 파일을 업로드하시겠습니까?")) {
return;
}
// 중요로직: FormData를 사용하여 파일 데이터 구성
var formData = new FormData();
formData.append('file', file);
// 로딩 표시
$("#loading").addClass('active');
$("#btnUpload").prop('disabled', true);
// 중요로직: AJAX로 파일 업로드
$.ajax({
url: '<c:url value="/carInspectionPenalty/registration/upload.ajax"/>',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
// 로딩 숨김
$("#loading").removeClass('active');
$("#btnUpload").prop('disabled', false);
/**
* 파일 업로드 버튼 클릭
*/
$("#uploadBtn").on('click', function() {
var fileInput = document.getElementById('txtFile');
var file = fileInput.files[0];
if (response.success) {
alert(response.message);
// 파일 선택 검증
if (!file) {
alert("파일을 선택해주세요.");
return;
// 중요로직: 부모 창의 목록 새로고침
if (window.opener && window.opener.CarFfnlgTrgt && typeof window.opener.CarFfnlgTrgt.search === 'function') {
window.opener.CarFfnlgTrgt.search();
}
// 파일 확장자 검증
var fileName = file.name;
var fileExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
if (fileExt !== 'txt') {
alert("TXT 파일만 업로드 가능합니다.");
return;
}
// 파일 크기 검증 (50MB)
if (file.size > 50 * 1024 * 1024) {
alert("파일 크기는 50MB를 초과할 수 없습니다.");
return;
}
// 확인 메시지
if (!confirm("선택한 파일을 업로드하시겠습니까?")) {
return;
}
// FormData 생성
var formData = new FormData();
formData.append('file', file);
// 로딩 표시
$("#loading").addClass('active');
$("#uploadBtn").prop('disabled', true);
// AJAX 업로드
$.ajax({
url: '<c:url value="/carInspectionPenalty/registration/upload.ajax"/>',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
// 로딩 숨김
$("#loading").removeClass('active');
$("#uploadBtn").prop('disabled', false);
if (response.success) {
alert(response.message);
// 성공 시 파일 입력 초기화
fileInput.value = '';
// 부모 창 새로고침을 위해 잠시 대기 후 닫기
setTimeout(function() {
window.close();
}, 500);
} else {
alert(response.message);
}
},
error: function(xhr, status, error) {
// 로딩 숨김
$("#loading").removeClass('active');
$("#uploadBtn").prop('disabled', false);
console.error("업로드 오류:", error);
var errorMessage = "파일 업로드 중 오류가 발생했습니다.";
if (xhr.responseJSON && xhr.responseJSON.message) {
errorMessage += "\n\n" + xhr.responseJSON.message;
}
alert(errorMessage);
}
});
});
closePopup();
} else {
alert(response.message || '파일 업로드에 실패했습니다.');
}
},
error: function(xhr, status, error) {
// 로딩 숨김
$("#loading").removeClass('active');
$("#btnUpload").prop('disabled', false);
/**
* 닫기 버튼 클릭
*/
$("#closeBtn").on('click', function() {
window.close();
});
console.error("업로드 오류:", error);
/**
* 파일 선택 시 파일 정보 표시
*/
$("#txtFile").on('change', function() {
var file = this.files[0];
if (file) {
var fileSize = (file.size / 1024).toFixed(2); // KB 단위
var fileSizeText = fileSize < 1024
? fileSize + ' KB'
: (fileSize / 1024).toFixed(2) + ' MB';
$('.file-info').html(
'선택된 파일: <strong>' + file.name + '</strong><br>' +
'파일 크기: ' + fileSizeText
);
}
});
});
</script>
</body>
</html>
var errorMessage = "파일 업로드 중 오류가 발생했습니다.";
if (xhr.responseJSON && xhr.responseJSON.message) {
errorMessage += "\n\n" + xhr.responseJSON.message;
}
alert(errorMessage);
}
});
}
/**
* 파일 정보 표시 함수
* 중요로직: 선택한 파일의 이름과 크기를 화면에 표시한다.
*/
function displayFileInfo(file) {
if (file) {
var fileSize = (file.size / 1024).toFixed(2); // KB 단위
var fileSizeText = fileSize < 1024
? fileSize + ' KB'
: (fileSize / 1024).toFixed(2) + ' MB';
$('.file-info').html(
'선택된 파일: <strong>' + file.name + '</strong><br>' +
'파일 크기: ' + fileSizeText
);
}
}
/**
* 팝업 닫기 함수
*/
function closePopup() {
window.close();
}
</script>

@ -1,211 +0,0 @@
<%@ 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" %>
<!-- Main body -->
<div class="main_body">
<section id="section8" class="main_bars">
<div class="bgs-main">
<section id="section5">
<div class="sub_title"></div>
<button type="button" id="registerBtn" class="newbtn bg1">등록</button>
<button type="button" id="updaterBtn" class="newbtn bg4">수정</button>
<button type="button" id="excelDownBtn" class="newbtn bg5 iconz">
<span class="mdi mdi-microsoft-excel"></span>엑셀 다운로드
</button>
</section>
</div>
</section>
<div class="contants_body">
<div class="gs_b_top">
<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="${empty param.schCrdnYr ? dateUtil:getCurrentDateTime('yyyy') : param.schCrdnYr}"/>
</li>
</ul>
<ul class="rig2">
<li><button type="button" id="search_btn" class="newbtnss bg1">검색</button></li>
<li><button type="button" id="reset_btn" class="newbtnss bg5" style="margin-left: 5px;">초기화</button></li>
</ul>
</div>
<div class="gs_booking">
<div class="row">
<div class="col-sm-12">
<div class="box_column">
<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="btnCarExternalApiCall" 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>
<option value="100">페이지당 100</option>
</select>
<span class="page_number"><span id="currentPage"></span><span class="bar">/</span><span id="totalPages"></span> Pages</span>
</li>
</ul>
<div class="containers">
<div id="grid"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /Main body -->
<script type="text/javascript">
/**
* 단속 등록/조회 목록 관리 모듈
* 단속 목록을 조회하고 관리하는 기능을 제공합니다.
*/
(function(window, $) {
'use strict';
var SEARCH_COND = {};
// 페이징 정보를 저장할 전역 변수
var GRID_PAGINATION_INFO = {
totalCount: 0,
page: 0,
perPage: 0
};
// 검색정보 설정
var setSearchCond = function() {
var schCrdnYr = $.trim(nvl($("#schCrdnYr").val(), ""));
SEARCH_COND.schCrdnYr = schCrdnYr;
};
/**
* 단속 목록 관리 네임스페이스
*/
var CrdnRegistAndViewList = {
/**
* 선택된 행 정보
*/
selectedRow: null,
/**
* 이벤트 핸들러 설정
*/
eventBindEvents: function() {
var self = this;
// 검색 버튼 클릭 이벤트
$("#search_btn").on('click', function() {
});
// 초기화 버튼 클릭 이벤트
$("#reset_btn").on('click', function() {
// 모든 검색 조건 초기화
$("#schCrdnYr").val("${dateUtil:getCurrentDateTime('yyyy')}"); // 현재 년도로 초기화
});
// 등록 버튼 클릭 이벤트
$("#registerBtn").on('click', function() {
self.openRegisterPopup();
});
// 차량조회 버튼 클릭 이벤트
$("#btnCarExternalApiCall").on('click', function() {
self.callVehicleApi();
});
},
/**
* 차량 정보 조회 API 호출
*/
callVehicleApi: function() {
var self = this;
// 임시 테스트용 차량번호 (실제로는 그리드에서 선택된 차량번호를 가져와야 함)
var vehicleNumbers = ["12가3456", "34나5678", "56다7890", "78라1234", "90마5678",
"12바9012", "34사3456", "56아7890", "78자1234", "90차5678",
"12카9012", "34타3456", "56파7890", "78하1234", "90거5678"];
// 확인 메시지
if (!confirm("총 " + vehicleNumbers.length + "건의 차량 정보를 조회하시겠습니까?")) {
return;
}
// API 호출
$.ajax({
url: '/carInspectionPenalty/search/getVehiclesInfo.do',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(vehicleNumbers),
success: function(response) {
if (response.success) {
console.log("차량 정보 조회 성공:", response.data);
// 성공/실패 건수 계산
var successCount = 0;
var failCount = 0;
response.data.forEach(function(vehicle) {
if (vehicle.success) {
successCount++;
console.log("차량번호: " + vehicle.vhrno + " 조회 성공");
console.log("- 기본정보:", vehicle.basicInfo);
console.log("- 등록원부:", vehicle.ledgerInfo);
} else {
failCount++;
console.log("차량번호: " + vehicle.vhrno + " 조회 실패 - " + vehicle.message);
}
});
// 결과 메시지 표시
alert("차량 정보 조회가 완료되었습니다.\n\n" +
"성공: " + successCount + "건\n" +
"실패: " + failCount + "건\n\n" +
"자세한 내용은 콘솔을 확인하세요.");
// TODO: 조회된 정보를 그리드에 표시하거나 DB에 저장하는 로직 추가
} else {
alert("차량 정보 조회에 실패했습니다.\n\n" + response.message);
}
},
error: function(xhr, status, error) {
console.error("API 호출 오류:", error);
alert("차량 정보 조회 중 오류가 발생했습니다.\n\n" + error);
}
});
},
/**
* 모듈 초기화
*/
init: function() {
// 이벤트 핸들러 설정
this.eventBindEvents();
}
};
// DOM 준비 완료 시 초기화
$(document).ready(function() {
CrdnRegistAndViewList.init();
});
// 전역 네임스페이스에 모듈 노출
window.CrdnRegistAndViewList = CrdnRegistAndViewList;
})(window, jQuery);
</script>
Loading…
Cancel
Save