비밀번호 찾기 스타일 적용

This commit is contained in:
현성필
2025-11-15 16:31:39 +09:00
parent 672dd24b9a
commit 15e57ef9a2
3 changed files with 332 additions and 410 deletions
+1
View File
@@ -6864,6 +6864,7 @@ select.form-control {
min-height: calc(100vh - 200px); min-height: calc(100vh - 200px);
margin-top: 60px; margin-top: 60px;
margin-bottom: 60px; margin-bottom: 60px;
border-radius: 12px;
} }
.account-recovery-container { .account-recovery-container {
File diff suppressed because one or more lines are too long
@@ -1,462 +1,383 @@
<!doctype html> <!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" <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}"> xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kjbank_base_layout}">
<body> <body>
<section layout:fragment="contentFragment" class="content"> <th:block layout:fragment="contentFragment">
<div class="content_wrap"> <div class="account-recovery-page">
<!-- 타이틀 --> <div class="account-recovery-container">
<div class="sub_title2" id="title-reset-password"> <div class="account-recovery-card">
<h2 class="title add8">비밀번호 초기화</h2> <!-- Logo -->
<div class="account-recovery-logo">
<img th:src="@{/img/logo/logo_box.png}" alt="광주은행">
</div> </div>
<div class="inner i_cs10 h_inner2"> <!-- Header Title -->
<!-- 탭 메뉴 --> <h2 class="account-recovery-title">비밀번호 초기화</h2>
<div class="tab-wrap">
<div class="tabs">
<ul class="tab_nav tabm">
<li><a th:href="@{/account_recovery(tab='findId')}">아이디 찾기</a></li>
<li class="active"><a href="">비밀번호 초기화</a></li>
</ul>
<!-- 비밀번호 초기화 폼 --> <!-- Tab Navigation -->
<div class="tab active"> <div class="account-recovery-tabs">
<div class="form_type"> <a th:href="@{/account_recovery(tab='findId')}" class="tab-link">아이디 찾기</a>
<form id="accountForm" role="form" name="accountForm" th:action="@{/reset_password}" <a href="#" class="tab-link active">비밀번호 초기화</a>
method="post"> </div>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<input type="hidden" id="mobileNumber" name="mobileNumber" th:value="${mobileNumber}">
<!-- 성명 입력 --> <!-- Alert Messages -->
<div class="info1 p_top2"> <div id="alertContainer"></div>
<p class="title w_tit">
<span class="dot">성명</span>
</p>
<div class="info_line">
<div class="info_box1 w_inp4">
<input type="text" name="userName"
th:value="${userName}" class="common_input_type_1" placeholder="성명"
required>
</div>
</div>
</div>
<!-- 아이디 입력 (이메일) --> <!-- Account Recovery Form -->
<div class="info1 pt28"> <form id="accountForm" role="form" name="accountForm" th:action="@{/reset_password}" method="post" class="account-recovery-form">
<p class="title w_tit"> <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<span class="dot">이메일 아이디</span> <input type="hidden" id="mobileNumber" name="mobileNumber" th:value="${mobileNumber}">
</p>
<div class="info_line">
<div class="info_box1 w_inp4">
<input type="text" name="loginId" th:value="${loginId}"
class="common_input_type_1" placeholder="이메일 아이디">
</div>
</div>
</div>
<!-- 휴대폰 번호 입력 --> <!-- Name Field -->
<div class="info1 pt28"> <div class="form-group">
<p class="title w_tit"> <label for="userName" class="form-label">성명</label>
<span class="dot">휴대폰 번호</span> <input type="text"
</p> id="userName"
<div class="info_line"> name="userName"
<div class="info_box1 w_inp5"> th:value="${userName}"
<span class="input"> class="form-input"
<div class="custom_select ct_sc w_inp10 h_inp2 select_mobile_prefix" id="prefix_select"> placeholder="성명"
<div class="select_selected active">선택</div> required>
<ul class="common_selecttype select_hide select_items ct_sc2"> </div>
<li>010</li>
<li>011</li> <!-- Email ID Field -->
<li>016</li> <div class="form-group">
<li>017</li> <label for="loginId" class="form-label">이메일 아이디</label>
<li>018</li> <input type="email"
</ul> id="loginId"
</div> name="loginId"
</span> th:value="${loginId}"
<span class="dash">-</span> class="form-input"
<span class="input"> placeholder="이메일 아이디"
<input type="tel" maxlength="4" name="phoneMiddle" class="common_input_type_1 w_inp11" required>
placeholder="앞자리" required> </div>
</span>
<span class="dash">-</span> <!-- Phone Number Fields -->
<span class="input"> <div class="form-group">
<input type="tel" maxlength="4" name="phoneLast" class="common_input_type_1 w_inp11" <label class="form-label">휴대폰 번호</label>
placeholder="뒷자리" required> <div class="phone-input-group">
</span> <select id="phonePrefix" class="form-select phone-prefix" required>
</div> <option value="">선택</option>
<div class="btn_check"> <option value="010">010</option>
<a class="common_btn_type_2 cbt btn_auth" <option value="011">011</option>
th:hx-post="@{/auth/request_auth_number}" <option value="016">016</option>
hx-include="#mobileNumber" <option value="017">017</option>
hx-target="#authNumberContainer" <option value="018">018</option>
hx-swap="none"> </select>
<span>인증번호 받기</span> <span class="phone-separator">-</span>
</a> <input type="tel"
</div> id="phoneMiddle"
</div> name="phoneMiddle"
</div> maxlength="4"
<!-- 인증번호 입력 --> class="form-input phone-middle"
<div class="info1 pt28 auth-number-container" id="authNumberContainer"> placeholder="0000"
<p class="title w_tit"> pattern="[0-9]*"
<span class="dot">인증번호 입력</span> inputmode="numeric"
</p> required>
<div class="info_line"> <span class="phone-separator">-</span>
<div class="info_box1 w_inp5"> <input type="tel"
<div class="certify_box"> id="phoneLast"
<input type="text" name="authNumber" id="authNumber" maxlength="6" name="phoneLast"
pattern="[0-9]*" maxlength="4"
inputmode="numeric" class="form-input phone-last"
class="common_input_type_1 w_input auth-number-input" placeholder="0000"
placeholder="SMS 인증번호" required> pattern="[0-9]*"
<span class="certify_time" id="certify_time">03:00</span> inputmode="numeric"
</div> required>
</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 type="button" class="common_btn_type_1 gray btn_cancel"><span>취소</span></a>
<div class="btn_gap"></div>
<button type="button" class="common_btn_type_1" onclick="validateAndSubmit()"><span>비밀번호 초기화</span>
</button>
</div>
</form>
</div>
</div>
</div>
</div> </div>
</div>
<!-- Auth Number Request Button -->
<button type="button" class="auth-request-button" id="requestAuthButton">
인증번호 받기
</button>
<!-- Auth Number Input -->
<div class="form-group auth-number-group" id="authNumberGroup" style="display: none;">
<label for="authNumber" class="form-label">인증번호 입력</label>
<div class="auth-input-group">
<input type="text"
id="authNumber"
name="authNumber"
maxlength="6"
class="form-input auth-input"
placeholder="인증번호 6자리"
pattern="[0-9]*"
inputmode="numeric"
required>
<span class="auth-timer" id="authTimer">03:00</span>
</div>
</div>
<!-- Auth Number Verify Button -->
<button type="button" class="auth-verify-button" id="verifyAuthButton" style="display: none;">
인증번호 확인
</button>
<!-- Submit Buttons -->
<div class="form-actions">
<button type="button" class="cancel-button" id="cancelButton">취소</button>
<button type="submit" class="submit-button" id="submitButton">비밀번호 초기화</button>
</div>
</form>
<!-- Loading State -->
<div class="loading-overlay" id="loadingOverlay">
<div class="spinner"></div>
</div> </div>
</div>
</div> </div>
</section> </div>
</th:block>
</body> </body>
<th:block layout:fragment="contentScript"> <th:block layout:fragment="contentScript">
<script th:inline="javascript"> <script th:inline="javascript">
$(document).ready(function() { $(document).ready(function() {
// 모든 종류의 에러 메시지 처리를 통합 const errorMsg = [[${error}]];
const errorMessage = [[${errorMessage}]]; if (errorMsg) {
const error = [[${error}]]; showAlert(errorMsg, 'error');
const success = [[${success}]]; }
if (errorMessage) { const paramError = new URL(window.location.href).searchParams.get('error');
customPopups.showAlert(errorMessage); if (paramError) {
} showAlert(decodeURIComponent(paramError), 'error');
if (error) { }
customPopups.showAlert(error); });
}
if (success) {
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) { // Alert 표시 함수
customPopups.showAlert('휴대폰 번호를 올바르게 입력해주세요.'); function showAlert(message, type = 'info') {
evt.preventDefault(); const alertContainer = $('#alertContainer');
return; const alertClass = type === 'error' ? 'alert-error' : type === 'success' ? 'alert-success' : 'alert-info';
} const iconClass = type === 'error' ? 'fa-exclamation-circle' : type === 'success' ? 'fa-check-circle' : 'fa-info-circle';
let combinedNumber = `${prefix}-${middle}-${last}`; const alertHtml = `
<div class="account-alert ${alertClass}">
<i class="fas ${iconClass}"></i>
<span>${message}</span>
</div>
`;
if (combinedNumber.trim().length === 0) { alertContainer.html(alertHtml);
customPopups.showAlert('휴대폰 번호를 올바르게 입력해주세요.'); setTimeout(() => alertContainer.empty(), 5000);
evt.preventDefault(); }
return;
}
$('#mobileNumber').val(combinedNumber);
return combinedNumber; // 휴대폰 번호 결합 함수
function combineMobileNumber() {
const prefix = $('#phonePrefix').val();
const middle = $('#phoneMiddle').val().trim();
const last = $('#phoneLast').val().trim();
if (!prefix || prefix === '' || !middle || !last) {
return null;
}
return `${prefix}-${middle}-${last}`;
}
// 타이머 변수
let countdownInterval;
let isAuthNumberRequested = false;
let isAuthVerified = false;
// 인증번호 타이머 시작
function startAuthTimer() {
clearInterval(countdownInterval);
let remainingTime = 180; // 3분
function updateTimer() {
if (remainingTime <= 0) {
clearInterval(countdownInterval);
$('#authTimer').text('시간 초과').css('color', '#FF6B6B');
showAlert('입력 시간이 초과되었습니다. 인증번호를 다시 발송해주세요.', 'error');
// 필드 활성화
$('#phonePrefix, #phoneMiddle, #phoneLast').prop('disabled', false);
$('#requestAuthButton').prop('disabled', false);
isAuthNumberRequested = false;
} else {
const minutes = Math.floor(remainingTime / 60);
const seconds = remainingTime % 60;
$('#authTimer').text(`${minutes}:${seconds.toString().padStart(2, '0')}`);
remainingTime--;
} }
}
// 폼 전체 유효성 검증 함수 updateTimer();
function validateAndSubmit() { countdownInterval = setInterval(updateTimer, 1000);
const form = document.getElementById('accountForm'); }
// 성명 검증 // 인증번호 요청 버튼
const userName = form.querySelector('input[name="userName"]').value.trim(); $('#requestAuthButton').on('click', function() {
if (!userName) { const userName = $('#userName').val().trim();
customPopups.showAlert('성명을 입력해주세요.'); if (!userName) {
return false; showAlert('성명을 입력해주세요.', 'error');
} return;
}
// 이메일 아이디 검증 const loginId = $('#loginId').val().trim();
const loginId = form.querySelector('input[name="loginId"]').value.trim(); if (!loginId) {
if (!loginId) { showAlert('이메일 아이디를 입력해주세요.', 'error');
customPopups.showAlert('이메일 아이디를 입력해주세요.'); return;
return false; }
}
// 이메일 형식 검증 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(loginId)) {
if (!emailRegex.test(loginId)) { showAlert('올바른 이메일 형식을 입력해주세요.', 'error');
customPopups.showAlert('올바른 이메일 형식을 입력해주세요.'); return;
return false; }
}
// 휴대폰 번호 검증 const mobileNumber = combineMobileNumber();
const prefix = form.querySelector('.select_mobile_prefix .select_selected').textContent.trim(); if (!mobileNumber) {
const phoneMiddle = form.querySelector('input[name="phoneMiddle"]').value.trim(); showAlert('휴대폰 번호를 올바르게 입력해주세요.', 'error');
const phoneLast = form.querySelector('input[name="phoneLast"]').value.trim(); return;
}
if (prefix === '선택' || !phoneMiddle || !phoneLast) { $('#mobileNumber').val(mobileNumber);
customPopups.showAlert('휴대폰 번호를 올바르게 입력해주세요.'); $('#loadingOverlay').fadeIn(200);
return false;
}
// 인증번호 요청 여부 검증 $.ajax({
if (!window.isAuthNumberRequested) { url: '/auth/request_auth_number',
customPopups.showAlert('휴대폰 인증을 먼저 진행해주세요.'); type: 'POST',
return false; data: {
} mobileNumber: mobileNumber,
_csrf: $('input[name="_csrf"]').val()
},
success: function(response) {
$('#loadingOverlay').fadeOut(200);
// 인증 완료 여부 검증 if (response.valid) {
const authNumberInput = document.getElementById('authNumber'); showAlert(response.message || '인증번호가 발송되었습니다.', 'success');
if (!authNumberInput?.disabled) {
customPopups.showAlert('휴대폰 인증을 완료해주세요.');
return false;
}
// 모든 검증을 통과하면 휴대폰 번호 결합 후 form submit // 휴대폰 번호 필드 비활성화
combineMobileNumber({ $('#phonePrefix, #phoneMiddle, #phoneLast').prop('disabled', true);
preventDefault: () => { $('#requestAuthButton').prop('disabled', true);
}
});
// 세션 검증을 위한 파라미터 추가 // 인증번호 입력 영역 표시
const currentAction = form.getAttribute('action'); $('#authNumberGroup').slideDown(300);
form.setAttribute('action', currentAction + (currentAction.includes('?') ? '&' : '?') + 'showError=true'); $('#verifyAuthButton').slideDown(300);
form.submit(); isAuthNumberRequested = true;
startAuthTimer();
} else {
showAlert(response.message || '인증번호 발송에 실패했습니다.', 'error');
}
},
error: function() {
$('#loadingOverlay').fadeOut(200);
showAlert('처리 중 오류가 발생했습니다. 다시 시도해주세요.', 'error');
} }
});
});
// HTMX 이벤트 리스너 // 인증번호 확인 버튼
document.body.addEventListener('htmx:beforeRequest', function (evt) { $('#verifyAuthButton').on('click', function() {
combineMobileNumber(evt); if (!isAuthNumberRequested) {
}); showAlert('휴대폰 번호 인증을 먼저 진행해주세요.', 'error');
return;
}
document.body.addEventListener('htmx:configRequest', function (evt) { const authNumber = $('#authNumber').val().trim();
evt.detail.parameters['mobileNumber'] = combineMobileNumber(evt);
});
// 메인 초기화 및 이벤트 바인딩 if (authNumber.length !== 6) {
document.addEventListener('DOMContentLoaded', function () { showAlert('인증번호 6자리를 입력해주세요.', 'error');
// 기존 휴대폰 번호 복원 return;
const mobileNumber = document.getElementById('mobileNumber')?.value; }
if (mobileNumber) {
const mobileParts = mobileNumber.split('-');
if (mobileParts.length === 3) {
const PrefixSelect = document.querySelector('#prefix_select .select_selected');
if (PrefixSelect) {
PrefixSelect.textContent = mobileParts[0];
}
const orgMiddleInput = document.querySelector('[name="phoneMiddle"]');
if (orgMiddleInput) {
orgMiddleInput.value = mobileParts[1];
}
const orgLastInput = document.querySelector('[name="phoneLast"]');
if (orgLastInput) {
orgLastInput.value = mobileParts[2];
}
}
}
// 셀렉트 박스 활성화 const mobileNumber = $('#mobileNumber').val();
activateSelect(); $('#loadingOverlay').fadeIn(200);
// 인증 관련 변수 초기화 $.ajax({
let countdownInterval; url: '/auth/verify_auth_number',
window.isAuthNumberRequested = false; type: 'POST',
window.isAuthVerified = false; data: {
mobileNumber: mobileNumber,
authNumber: authNumber,
_csrf: $('input[name="_csrf"]').val()
},
success: function(response) {
$('#loadingOverlay').fadeOut(200);
// 인증번호 타이머 함수 if (response.valid) {
function startAuthNumberTimer() { showAlert(response.message || '인증이 완료되었습니다.', 'success');
clearInterval(countdownInterval);
let remainingTime = 180; // 3분
function updateRemainingTime() { // 인증번호 입력 필드 비활성화
if (remainingTime <= 0) { $('#authNumber').prop('disabled', true);
clearInterval(countdownInterval); $('#verifyAuthButton').prop('disabled', true);
let timerElement = document.getElementById('certify_time');
if (timerElement) {
timerElement.textContent = '입력 시간이 초과되었습니다.';
}
customPopups.showAlert('입력 시간이 초과되었습니다. 인증번호를 다시 발송해주세요.');
let form = $('#accountForm'); clearInterval(countdownInterval);
let mobilePrefix = form.find('.select_mobile_prefix'); $('#authTimer').text('인증 완료').css('color', '#6BCF7F');
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');
// 입력 필드 활성화 isAuthVerified = true;
mobilePrefix.removeClass('disabled'); } else {
phoneMiddle.prop('readonly', false); showAlert(response.message || '인증번호가 일치하지 않습니다.', 'error');
phoneLast.prop('readonly', false); }
if (authButton) { },
authButton.disabled = false; error: function() {
} $('#loadingOverlay').fadeOut(200);
if (verifyAuthButton) { showAlert('처리 중 오류가 발생했습니다. 다시 시도해주세요.', 'error');
verifyAuthButton.disabled = true; }
} });
if (authNumberInput) { });
authNumberInput.readOnly = true;
}
window.isAuthNumberRequested = false;
} 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); $('#accountForm').on('submit', function(e) {
} e.preventDefault();
// 인증번호 요청 처리 함수 const userName = $('#userName').val().trim();
function handleAuthNumberRequest(response) { if (!userName) {
if (response.valid) { showAlert('성명을 입력해주세요.', 'error');
let form = $('#accountForm'); return;
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');
mobilePrefix.addClass('disabled'); const loginId = $('#loginId').val().trim();
phoneMiddle.prop('disabled', true); if (!loginId) {
phoneLast.prop('disabled', true); showAlert('이메일 아이디를 입력해주세요.', 'error');
if (authButton) { return;
authButton.disabled = true; }
}
window.isAuthNumberRequested = true; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
startAuthNumberTimer(); if (!emailRegex.test(loginId)) {
customPopups.showAlert(response.message || '인증번호가 발송되었습니다.'); showAlert('올바른 이메일 형식을 입력해주세요.', 'error');
} else { return;
customPopups.showAlert(response.message || '알 수 없는 오류가 발생했습니다.'); }
let authButton = document.querySelector('.btn_auth');
if (authButton) {
authButton.disabled = false;
}
}
}
// 인증번호 확인 처리 함수 const mobileNumber = combineMobileNumber();
function handleAuthNumberVerification(response) { if (!mobileNumber) {
customPopups.showAlert(response.message); showAlert('휴대폰 번호를 올바르게 입력해주세요.', 'error');
if (response.valid) { return;
let authNumberInput = document.getElementById('authNumber'); }
let verifyAuthButton = document.querySelector('.btn_verify_auth');
let timerElement = document.getElementById('certify_time');
if (authNumberInput) { if (!isAuthNumberRequested) {
authNumberInput.readOnly = true; showAlert('휴대폰 인증을 먼저 진행해주세요.', 'error');
authNumberInput.disabled = true; return;
} }
if (verifyAuthButton) {
verifyAuthButton.disabled = true;
}
clearInterval(countdownInterval); if (!isAuthVerified) {
if (timerElement) { showAlert('휴대폰 인증을 완료해주세요.', 'error');
timerElement.textContent = '인증 완료'; return;
} }
window.isAuthVerified = true;
document.dispatchEvent(new Event('authVerified'));
}
}
// HTMX 응답 처리 $('#mobileNumber').val(mobileNumber);
document.body.addEventListener('htmx:afterSwap', function (event) { this.submit();
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': $('#cancelButton').on('click', function() {
handleAuthNumberRequest(response); window.location.href = '/login';
break; });
case 'authNumberValidation':
handleAuthNumberVerification(response);
break;
}
}
});
// HTMX 에러 처리 // 기존 휴대폰 번호 복원
document.body.addEventListener('htmx:responseError', function (event) { $(document).ready(function() {
customPopups.showAlert('처리 중 오류가 발생했습니다. 다시 시도해주세요.'); const savedMobileNumber = $('#mobileNumber').val();
}); if (savedMobileNumber) {
const parts = savedMobileNumber.split('-');
// 인증번호 확인 버튼 이벤트 if (parts.length === 3) {
let verifyAuthButton = document.querySelector('.btn_verify_auth'); $('#phonePrefix').val(parts[0]);
if (verifyAuthButton) { $('#phoneMiddle').val(parts[1]);
verifyAuthButton.addEventListener('click', function (e) { $('#phoneLast').val(parts[2]);
if (!window.isAuthNumberRequested) { }
e.preventDefault(); }
customPopups.showAlert('휴대폰 번호 인증을 먼저 진행해주세요.'); });
return; </script>
}
let form = $('#accountForm');
let authNumberInput = form.find('.auth-number-input');
let authNumber = authNumberInput.val().trim();
if (authNumber.length !== 6) {
e.preventDefault();
customPopups.showAlert('입력된 인증번호가 유효하지 않습니다.');
return;
}
});
}
// 취소 버튼 이벤트
let cancelButton = document.querySelector('.btn_cancel');
if (cancelButton) {
cancelButton.addEventListener('click', function () {
location.href = '/login';
});
}
// 폼 제출 이벤트 처리
const accountForm = document.getElementById('accountForm');
if (accountForm) {
accountForm.addEventListener('submit', function (e) {
e.preventDefault();
validateAndSubmit();
});
}
});
</script>
</th:block> </th:block>
</html> </html>