fix: 마이페이지 이용 통계 , 내정보 관리 , 비밀전호 변경 & 로그인 반응형 퍼블리싱

This commit is contained in:
hong
2026-07-28 14:30:03 +09:00
parent 2106142d93
commit cdd68f48f0
17 changed files with 1841 additions and 29794 deletions
@@ -1,93 +1,105 @@
<!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/djbank_base_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/djbank_base_layout}">
<body>
<th:block layout:fragment="contentFragment">
<div class="login-page">
<div class="login-container">
<div class="login-card">
<!-- Logo -->
<div class="login-logo">
<img th:src="@{/img/logo/logo_box.png}" alt="DJBank">
</div>
<!-- Header Message -->
<p class="login-message">로그인 하시면 더 많은 서비스를 이용하실 수 있습니다.</p>
<!-- Alert Messages -->
<div th:if="${param.logout}" class="login-alert alert-info">
<i class="fas fa-info-circle"></i>
<span>로그아웃되었습니다.</span>
</div>
<div th:if="${param.expired}" class="login-alert alert-info">
<i class="fas fa-info-circle"></i>
<span>장시간 미사용으로 세션이 만료되어 로그아웃되었습니다. 다시 로그인해주세요.</span>
</div>
<div th:if="${param.forceLogout}" class="login-alert alert-info">
<i class="fas fa-info-circle"></i>
<span>다른 기기 또는 브라우저에서 로그인되어 현재 세션이 종료되었습니다.</span>
</div>
<div th:if="${param.reason == 'auth'}" class="login-alert alert-info">
<i class="fas fa-info-circle"></i>
<span>인증된 사용자만 접근 가능한 페이지입니다. 로그인 후 이용해 주세요.</span>
</div>
<!-- Login Form -->
<form id="loginForm" role="form" name="loginForm" th:action="@{/actionLogin.do}" method="post" class="login-form">
<input type="hidden" id="message" name="message" th:value="${loginMessage}">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<input type="hidden" id="loginId" th:value="${loginId}">
<!-- ID Field -->
<div class="form-group">
<input type="text"
id="id"
name="id"
th:value="${loginId}"
class="form-input"
placeholder="아이디"
required>
<th:block layout:fragment="contentFragment">
<div class="login-page">
<div class="login-container">
<div class="login-card">
<!-- Logo & Title -->
<div class="login-header">
<div class="header-main-row">
<div class="login-lock-icon">
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="#000"
stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
</svg>
</div>
<h2 class="login-title">로그인</h2>
</div>
<p class="login-message-sub">DJ Bank에 오신걸 환영합니다</p>
</div>
<!-- Password Field -->
<div class="form-group">
<input type="password"
id="password"
name="password"
class="form-input"
placeholder="비밀번호"
required>
<!-- Alert Messages -->
<div th:if="${param.logout}" class="login-alert alert-info">
<i class="fas fa-info-circle"></i>
<span>로그아웃되었습니다.</span>
</div>
<div th:if="${param.expired}" class="login-alert alert-info">
<i class="fas fa-info-circle"></i>
<span>장시간 미사용으로 세션이 만료되어 로그아웃되었습니다. 다시 로그인해주세요.</span>
</div>
<div th:if="${param.forceLogout}" class="login-alert alert-info">
<i class="fas fa-info-circle"></i>
<span>다른 기기 또는 브라우저에서 로그인되어 현재 세션이 종료되었습니다.</span>
</div>
<div th:if="${param.reason == 'auth'}" class="login-alert alert-info">
<i class="fas fa-info-circle"></i>
<span>인증된 사용자만 접근 가능한 페이지입니다. 로그인 후 이용해 주세요.</span>
</div>
<!-- Remember Me Checkbox -->
<div class="form-checkbox">
<input id="checkId" name="checkId" type="checkbox">
<label for="checkId">아이디저장</label>
<!-- Login Form -->
<form id="loginForm" role="form" name="loginForm" th:action="@{/actionLogin.do}" method="post"
class="login-form">
<input type="hidden" id="message" name="message" th:value="${loginMessage}">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<input type="hidden" id="loginId" th:value="${loginId}">
<!-- ID Field -->
<div class="form-group input-with-icon">
<span class="input-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#767e89"
stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
</span>
<input type="text" id="id" name="id" th:value="${loginId}" class="form-input"
placeholder="아이디를 입력해주세요" required>
</div>
<!-- Password Field -->
<div class="form-group input-with-icon">
<span class="input-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#767e89"
stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
</svg>
</span>
<input type="password" id="password" name="password" class="form-input"
placeholder="비밀번호를 입력해주세요" required>
</div>
<!-- Remember Me Checkbox -->
<div class="form-checkbox">
<input id="checkId" name="checkId" type="checkbox">
<label for="checkId">아이디 저장</label>
</div>
</form>
<!-- Login Button -->
<button type="button" class="login-button" id="actionLogin">
로그인
</button>
<!-- Additional Links -->
<div class="login-links-container">
<a th:href="@{/account_recovery(tab='findId')}" class="link-btn first">아이디 찾기</a>
<a th:href="@{/account_recovery(tab='resetPassword')}" class="link-btn middle">비밀번호 초기화</a>
<a th:href="@{/signup}" class="link-btn last">회원가입</a>
</div>
</form>
<!-- Login Button -->
<button type="button" class="login-button" id="actionLogin">
로그인
</button>
<!-- Additional Links -->
<div class="login-links">
<a th:href="@{/account_recovery(tab='findId')}">아이디 찾기</a>
<span class="link-separator">|</span>
<a th:href="@{/account_recovery(tab='resetPassword')}">비밀번호 초기화</a>
<span class="link-separator">|</span>
<a th:href="@{/signup}">회원가입</a>
</div>
<!-- Loading State -->
<div class="login-loading" id="loginLoading">
<div class="spinner"></div>
<!-- Loading State -->
<div class="login-loading" id="loginLoading">
<div class="spinner"></div>
</div>
</div>
</div>
</div>
</div>
</th:block>
</th:block>
</body>
<th:block layout:fragment="contentScript">
<script th:inline="javascript">
@@ -148,8 +160,8 @@
if (data && data.duplicateSession) {
$('#loginLoading').removeClass('active');
var msg = '해당 계정은 이미 다른 곳(' + data.ipAddress + ')에서 접속 중입니다.<br>'
+ '접속 시각: ' + data.loginTime + '<br><br>'
+ '기존 접속을 해제하고 로그인하시겠습니까?';
+ '접속 시각: ' + data.loginTime + '<br><br>'
+ '기존 접속을 해제하고 로그인하시겠습니까?';
customPopups.showConfirm(msg, function (confirmed) {
if (confirmed) {
$('#loginLoading').addClass('active');
@@ -182,7 +194,7 @@
// 세션 만료 대응은 head의 익명 keepalive ping(/api/session/ping)이 담당하고,
// 제출 직전 refreshCsrfAndThen()이 CSRF 토큰 재발급 안전망 역할을 한다.
var successMsg = [[${success}]];
var successMsg = [[${ success }]];
console.log("Success message:", successMsg);
if (successMsg) {
console.log("Showing alert");
@@ -190,13 +202,13 @@
}
// 비밀번호 만료 체크 관련 코드 추가
var successMsg = [[${session.success}]];
var passwordExpired = [[${session.passwordExpired}]];
var emailVerificationRequired = [[${session.emailVerificationRequired}]];
var redirectUrl = [[${session.redirectUrl}]];
var successMsg = [[${ session.success }]];
var passwordExpired = [[${ session.passwordExpired }]];
var emailVerificationRequired = [[${ session.emailVerificationRequired }]];
var redirectUrl = [[${ session.redirectUrl }]];
if (successMsg) {
customPopups.showAlert(successMsg, function() {
customPopups.showAlert(successMsg, function () {
// 비밀번호 만료·미인증(이메일 인증 필요) 시 전용 화면으로 이동
if ((passwordExpired || emailVerificationRequired) && redirectUrl) {
window.location.href = redirectUrl;
@@ -237,7 +249,7 @@
form.classList.add('was-validated');
};
$('#actionLogin').on('click', function(event) {
$('#actionLogin').on('click', function (event) {
event.preventDefault();
actionLogin(event);
});
@@ -252,4 +264,5 @@
});
</script>
</th:block>
</html>
</html>