453 lines
22 KiB
HTML
453 lines
22 KiB
HTML
<!doctype html>
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_base_layout}">
|
|
<body>
|
|
<section layout:fragment="contentFragment" class="content">
|
|
<div class="content_wrap">
|
|
<div class="sub_title2">
|
|
<h2 class="title add6">장기미사용 제한 해제</h2>
|
|
</div>
|
|
<div class="inner i_cs10 h_inner2">
|
|
<div class="top_info2 m_btm">
|
|
<p>Kbank API Portal을 <span>90일 이상 접속하지 않았을 경우 로그인이 제한</span>됩니다.<br>
|
|
다시 서비스를 이용하시려면 <span>'장기미사용 제한 해제'</span>를 하셔야 이용하실 수 있습니다.</p>
|
|
</div>
|
|
<div class="form_type">
|
|
<form id="accountForm" role="form" name="accountForm" th:action="@{/dormant_account/verify}"
|
|
method="post">
|
|
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
|
<input type="hidden" id="mobileNumber" name="mobileNumber">
|
|
<!-- 아이디 입력 -->
|
|
<div class="info1 form_top">
|
|
<p class="title w_tit">
|
|
<span class="dot">아이디</span>
|
|
</p>
|
|
<div class="info_line">
|
|
<div class="info_box1 w_inp4">
|
|
<input type="text" name="loginId" th:value="${loginId}" class="common_input_type_1 input-readonly" placeholder="이메일 아이디"
|
|
readonly required>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 비밀번호 입력 -->
|
|
<div class="info1 pt28">
|
|
<p class="title w_tit">
|
|
<span class="dot">비밀번호</span>
|
|
</p>
|
|
<div class="info_line">
|
|
<div class="info_box1 w_inp4">
|
|
<input type="password" name="password" class="common_input_type_1" placeholder="비밀번호"
|
|
required>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- 휴대폰 번호 입력 -->
|
|
<div class="info1 pt28">
|
|
<p class="title w_tit">
|
|
<span class="dot">휴대폰 번호</span>
|
|
</p>
|
|
<div class="info_line">
|
|
<div class="info_box1 w_inp5">
|
|
<span class="input">
|
|
<div class="custom_select ct_sc w_inp10 h_inp2 select_mobile_prefix">
|
|
<div class="select_selected active">선택</div>
|
|
<ul class="common_selecttype select_hide select_items ct_sc2">
|
|
<li>010</li>
|
|
<li>011</li>
|
|
<li>016</li>
|
|
<li>017</li>
|
|
<li>018</li>
|
|
</ul>
|
|
</div>
|
|
</span>
|
|
<span class="dash">-</span>
|
|
<span class="input">
|
|
<input type="tel" maxlength="4" name="phoneMiddle" class="common_input_type_1 w_inp11"
|
|
placeholder="앞자리" required>
|
|
</span>
|
|
<span class="dash">-</span>
|
|
<span class="input">
|
|
<input type="tel" maxlength="4" name="phoneLast" class="common_input_type_1 w_inp11" placeholder="뒷자리"
|
|
required>
|
|
</span>
|
|
</div>
|
|
<div class="btn_check">
|
|
<a class="common_btn_type_2 cbt btn_auth"
|
|
th:hx-post="@{/auth/request_auth_number}"
|
|
hx-include="#mobileNumber"
|
|
hx-target="#authNumberContainer"
|
|
hx-swap="none">
|
|
<span>인증번호 받기</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 인증번호 입력 -->
|
|
<div class="info1 pt28 auth-number-container" id="authNumberContainer">
|
|
<p class="title w_tit">
|
|
<span class="dot">인증번호 입력</span>
|
|
</p>
|
|
<div class="info_line">
|
|
<div class="info_box1 w_inp5">
|
|
<div class="certify_box">
|
|
<input type="number" id="authNumber" name="authNumber"
|
|
class="common_input_type_1 w_input auth-number-input" placeholder="SMS 인증번호"
|
|
required>
|
|
<span class="certify_time" id="certify_time">03:00</span>
|
|
</div>
|
|
</div>
|
|
<div class="btn_check">
|
|
<a class="common_btn_type_2 cbt btn_verify_auth"
|
|
th:hx-post="@{/auth/verify_auth_number}"
|
|
hx-include="#mobileNumber, #authNumber"
|
|
hx-target="#authNumberValidation"
|
|
hx-swap="none">
|
|
<span>인증번호 확인</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="authNumberValidation"></div>
|
|
<!-- 제출 버튼 -->
|
|
<div class="btn_application m_top">
|
|
<a href="/login" class="common_btn_type_1 gray"><span>취소</span></a>
|
|
<div class="btn_gap"></div>
|
|
<button type="submit" class="common_btn_type_1"><span>제한 해제</span></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<th:block layout:fragment="contentScript">
|
|
<script th:if="${error}" th:inline="javascript">
|
|
$(document).ready(function () {
|
|
customPopups.showAlert([[${error}]]);
|
|
});
|
|
</script>
|
|
<script th:if="${success}" th:inline="javascript">
|
|
$(document).ready(function () {
|
|
customPopups.showAlert([[${success}]]);
|
|
});
|
|
</script>
|
|
<script th:inline="javascript">
|
|
function combineMobileNumber(evt) {
|
|
let form = $('#accountForm');
|
|
let prefix = form.find('.select_mobile_prefix .select_selected').text().trim();
|
|
let middle = form.find('input[name="phoneMiddle"]').val().trim();
|
|
let last = form.find('input[name="phoneLast"]').val().trim();
|
|
|
|
if (prefix === '선택' || !middle || !last) {
|
|
customPopups.showAlert('휴대폰 번호를 올바르게 입력해주세요.');
|
|
evt.preventDefault();
|
|
return;
|
|
}
|
|
|
|
let combinedNumber = `${prefix}-${middle}-${last}`;
|
|
|
|
if (combinedNumber.trim().length === 0) {
|
|
customPopups.showAlert('휴대폰 번호를 올바르게 입력해주세요.');
|
|
evt.preventDefault();
|
|
return;
|
|
}
|
|
$('#mobileNumber').val(combinedNumber);
|
|
|
|
return combinedNumber;
|
|
}
|
|
|
|
document.body.addEventListener('htmx:beforeRequest', function (evt) {
|
|
combineMobileNumber(evt);
|
|
});
|
|
|
|
document.body.addEventListener('htmx:configRequest', function (evt) {
|
|
let mobileNumber = combineMobileNumber(evt);
|
|
if (mobileNumber) {
|
|
evt.detail.parameters['mobileNumber'] = mobileNumber;
|
|
}
|
|
});
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
let countdownInterval;
|
|
let isAuthVerified = false;
|
|
|
|
// 이전 입력값 복원 코드 추가
|
|
const savedLoginId = sessionStorage.getItem('dormant_loginId');
|
|
const savedMobileNumber = sessionStorage.getItem('dormant_mobileNumber');
|
|
|
|
if (savedLoginId) {
|
|
$('input[name="loginId"]').val(savedLoginId);
|
|
}
|
|
|
|
if (savedMobileNumber) {
|
|
const [prefix, middle, last] = savedMobileNumber.split('-');
|
|
$('.select_mobile_prefix .select_selected').text(prefix);
|
|
$('input[name="phoneMiddle"]').val(middle);
|
|
$('input[name="phoneLast"]').val(last);
|
|
}
|
|
|
|
function startAuthNumberTimer() {
|
|
clearInterval(countdownInterval);
|
|
let remainingTime = 180; // 3분
|
|
|
|
function updateRemainingTime() {
|
|
if (remainingTime <= 0) {
|
|
clearInterval(countdownInterval);
|
|
let timerElement = document.getElementById('certify_time');
|
|
if (timerElement) {
|
|
timerElement.textContent = '입력 시간이 초과되었습니다.';
|
|
}
|
|
customPopups.showAlert('입력 시간이 초과되었습니다. 인증번호를 다시 발송해주세요.');
|
|
|
|
// Re-enable mobile number related fields
|
|
let form = $('#accountForm');
|
|
let mobilePrefix = form.find('.select_mobile_prefix');
|
|
let phoneMiddle = form.find('input[name="phoneMiddle"]');
|
|
let phoneLast = form.find('input[name="phoneLast"]');
|
|
let authButton = document.querySelector('.btn_auth');
|
|
let verifyAuthButton = document.querySelector('.btn_verify_auth');
|
|
let authNumberInput = document.getElementById('authNumber');
|
|
|
|
// Enable mobile number fields
|
|
mobilePrefix.removeClass('disabled');
|
|
phoneMiddle.prop('readonly', false);
|
|
phoneLast.prop('readonly', false);
|
|
if (authButton) {
|
|
authButton.disabled = false;
|
|
}
|
|
if (verifyAuthButton) {
|
|
verifyAuthButton.disabled = true;
|
|
}
|
|
if (authNumberInput) {
|
|
authNumberInput.readOnly = true;
|
|
}
|
|
|
|
} else {
|
|
let minutes = Math.floor(remainingTime / 60);
|
|
let seconds = remainingTime % 60;
|
|
let timerElement = document.getElementById('certify_time');
|
|
if (timerElement) {
|
|
timerElement.textContent = `남은 시간: ${minutes}:${seconds.toString().padStart(2, '0')}`;
|
|
}
|
|
remainingTime--;
|
|
}
|
|
}
|
|
|
|
updateRemainingTime();
|
|
countdownInterval = setInterval(updateRemainingTime, 1000);
|
|
}
|
|
|
|
function displayTestAuthNotice(authNumber) {
|
|
const noticeHtml = `
|
|
<div class="test-env-notice" style="margin-top: 12px; padding: 12px 16px; background-color: #FFF4E6; border: 1px solid #FFB84D; border-radius: 4px;">
|
|
<div class="test-env-notice__content" style="display: flex; align-items: flex-start; gap: 8px;">
|
|
<svg class="test-env-notice__icon" style="flex-shrink: 0; margin-top: 2px; width: 20px; height: 20px;" viewBox="0 0 20 20" fill="none">
|
|
<path d="M10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM11 15H9V13H11V15ZM11 11H9V5H11V11Z" fill="#FF9800"/>
|
|
</svg>
|
|
<div class="test-env-notice__text-container" style="flex: 1;">
|
|
<p style="margin: 0; font-size: 14px; color: #E65100; font-weight: 500;">테스트 환경 안내</p>
|
|
<p style="margin: 4px 0 0 0; font-size: 13px; color: #5D4037; line-height: 1.5;">
|
|
현재 테스트 환경입니다. 실제로 SMS가 발송되지 않으며, 인증번호는
|
|
<strong style="color: #E65100; font-family: monospace; font-size: 14px; font-weight: bold;">${authNumber}</strong>
|
|
입니다.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// 기존 안내 메시지 제거
|
|
$('.test-env-notice').remove();
|
|
|
|
// 인증번호 입력 container 바로 앞에 안내 메시지 삽입
|
|
const authNumberContainer = document.getElementById('authNumberContainer');
|
|
if (authNumberContainer) {
|
|
const noticeDiv = document.createElement('div');
|
|
noticeDiv.className = 'test-auth-notice-container info1 pt28';
|
|
noticeDiv.innerHTML = `<div class="info_line"><div class="info_box1">${noticeHtml}</div></div>`;
|
|
authNumberContainer.parentNode.insertBefore(noticeDiv, authNumberContainer);
|
|
}
|
|
}
|
|
|
|
function handleAuthNumberRequest(response) {
|
|
if (response.valid) {
|
|
// 테스트 환경 인증번호 표시
|
|
if (response.authNumber) {
|
|
displayTestAuthNotice(response.authNumber);
|
|
}
|
|
|
|
// Disable mobile number related fields
|
|
let form = $('#accountForm');
|
|
let mobilePrefix = form.find('.select_mobile_prefix');
|
|
let phoneMiddle = form.find('input[name="phoneMiddle"]');
|
|
let phoneLast = form.find('input[name="phoneLast"]');
|
|
let authButton = document.querySelector('.btn_auth');
|
|
|
|
// Disable all mobile number related fields
|
|
mobilePrefix.addClass('disabled');
|
|
phoneMiddle.prop('disabled', true);
|
|
phoneLast.prop('disabled', true);
|
|
if (authButton) {
|
|
authButton.disabled = true;
|
|
}
|
|
|
|
startAuthNumberTimer();
|
|
customPopups.showAlert(response.message || '인증번호가 발송되었습니다.');
|
|
} else {
|
|
customPopups.showAlert(response.message || '알 수 없는 오류가 발생했습니다.');
|
|
let authButton = document.querySelector('.btn_auth');
|
|
if (authButton) {
|
|
authButton.disabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleAuthNumberVerification(response) {
|
|
customPopups.showAlert(response.message);
|
|
if (response.valid) {
|
|
let authNumberInput = document.getElementById('authNumber');
|
|
let verifyAuthButton = document.querySelector('.btn_verify_auth');
|
|
let timerElement = document.getElementById('certify_time');
|
|
|
|
// Disable auth number input and verify button
|
|
if (authNumberInput) {
|
|
authNumberInput.readOnly = true;
|
|
authNumberInput.disabled = true;
|
|
}
|
|
if (verifyAuthButton) {
|
|
verifyAuthButton.disabled = true;
|
|
}
|
|
|
|
clearInterval(countdownInterval);
|
|
if (timerElement) {
|
|
timerElement.textContent = '인증 완료';
|
|
}
|
|
isAuthVerified = true;
|
|
document.dispatchEvent(new Event('authVerified'));
|
|
}
|
|
}
|
|
|
|
document.body.addEventListener('htmx:afterSwap', function (event) {
|
|
let targetId = event.detail.target ? event.detail.target.id : null;
|
|
if (targetId && ['authNumberContainer', 'authNumberValidation'].includes(targetId)) {
|
|
let response;
|
|
try {
|
|
response = typeof event.detail.xhr.response === 'string'
|
|
? JSON.parse(event.detail.xhr.response)
|
|
: event.detail.xhr.response;
|
|
} catch (e) {
|
|
console.error('Failed to parse response as JSON:', event.detail.xhr.response);
|
|
customPopups.showAlert('서버에서 예상치 못한 응답을 받았습니다.');
|
|
return;
|
|
}
|
|
|
|
switch (targetId) {
|
|
case 'authNumberContainer':
|
|
handleAuthNumberRequest(response);
|
|
break;
|
|
case 'authNumberValidation':
|
|
handleAuthNumberVerification(response);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
document.body.addEventListener('htmx:responseError', function (event) {
|
|
customPopups.showAlert('처리 중 오류가 발생했습니다. 다시 시도해주세요.');
|
|
});
|
|
|
|
let verifyAuthButton = document.querySelector('.btn_verify_auth');
|
|
if (verifyAuthButton) {
|
|
verifyAuthButton.addEventListener('click', function () {
|
|
let form = $('#accountForm');
|
|
let authNumberInput = form.find('.auth-number-input');
|
|
let authNumber = authNumberInput.val().trim();
|
|
|
|
if (authNumber.length !== 6) {
|
|
customPopups.showAlert('6자리 인증번호를 입력해주세요.');
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
|
|
function validateForm() {
|
|
const form = $('#accountForm');
|
|
const loginId = form.find('input[name="loginId"]').val().trim();
|
|
const password = form.find('input[name="password"]').val().trim();
|
|
const mobileNumber = $('#mobileNumber').val().trim();
|
|
|
|
// 이전 입력값 복원을 위한 데이터 저장
|
|
sessionStorage.setItem('dormant_loginId', loginId);
|
|
sessionStorage.setItem('dormant_mobileNumber', mobileNumber);
|
|
|
|
// 아이디 검증
|
|
if (!loginId) {
|
|
customPopups.showAlert('아이디를 입력해주세요.');
|
|
return false;
|
|
}
|
|
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
if (!emailRegex.test(loginId)) {
|
|
customPopups.showAlert('올바른 이메일 형식으로 입력해주세요.');
|
|
return false;
|
|
}
|
|
|
|
// 비밀번호 검증
|
|
if (!password) {
|
|
customPopups.showAlert('비밀번호를 입력해주세요.');
|
|
return false;
|
|
}
|
|
if (password.length < 8) {
|
|
customPopups.showAlert('비밀번호는 8자리 이상이어야 합니다.');
|
|
return false;
|
|
}
|
|
|
|
// 인증번호 검증
|
|
if (!isAuthVerified) {
|
|
customPopups.showAlert('휴대폰 인증을 완료해주세요.');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Form submit handler
|
|
$('#accountForm').on('submit', function (e) {
|
|
// 휴대폰 번호 입력 검증
|
|
let mobileNumber = combineMobileNumber();
|
|
if (!mobileNumber) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
|
|
// 인증번호 받기 여부 검증
|
|
if (!document.getElementById('authNumberContainer') ||
|
|
document.getElementById('authNumberContainer').style.display === 'none') {
|
|
e.preventDefault();
|
|
customPopups.showAlert('인증번호 받기를 진행해 주세요.');
|
|
return false;
|
|
}
|
|
|
|
// 인증 완료 여부 검증
|
|
if (!isAuthVerified) {
|
|
e.preventDefault();
|
|
customPopups.showAlert('휴대폰 번호 인증을 먼저 진행해주세요.');
|
|
return false;
|
|
}
|
|
|
|
if (!validateForm()) {
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// 휴대폰 번호 입력 필드에 숫자만 입력되도록 실시간 검증
|
|
$('input[name="phoneMiddle"], input[name="phoneLast"]').on('input', function() {
|
|
this.value = this.value.replace(/[^\d]/g, '');
|
|
});
|
|
});
|
|
</script>
|
|
</th:block>
|
|
</body>
|
|
</html>
|