CSS 소스맵(main.css.map) 누락된 소스 경로 수정
This commit is contained in:
@@ -24,6 +24,8 @@ import com.eactive.apim.portal.portaluser.repository.UserPasswordHistoryReposito
|
|||||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||||
import com.eactive.apim.portal.template.entity.MessageRequest;
|
import com.eactive.apim.portal.template.entity.MessageRequest;
|
||||||
import com.eactive.apim.portal.template.repository.MessageRequestRepository;
|
import com.eactive.apim.portal.template.repository.MessageRequestRepository;
|
||||||
|
import com.eactive.apim.portal.user.entity.UserLog;
|
||||||
|
import com.eactive.apim.portal.user.repository.UserLogRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -74,6 +76,7 @@ public class LoginFinalizer {
|
|||||||
private final PortalOrgRepository portalOrgRepository;
|
private final PortalOrgRepository portalOrgRepository;
|
||||||
private final UserSessionService userSessionService;
|
private final UserSessionService userSessionService;
|
||||||
private final PortalPropertyService portalPropertyService;
|
private final PortalPropertyService portalPropertyService;
|
||||||
|
private final UserLogRepository userLogRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 로그인 확정 후처리를 수행하고 최종 이동 URL 을 반환한다.
|
* 로그인 확정 후처리를 수행하고 최종 이동 URL 을 반환한다.
|
||||||
@@ -96,11 +99,19 @@ public class LoginFinalizer {
|
|||||||
// 기존 세션이 끊기는 건인지) 기록한다. 현재 세션 등록(registerSession)은 이 뒤에 일어나므로
|
// 기존 세션이 끊기는 건인지) 기록한다. 현재 세션 등록(registerSession)은 이 뒤에 일어나므로
|
||||||
// 여기서 조회되는 활성 세션은 항상 "다른 곳"의 세션이다.
|
// 여기서 조회되는 활성 세션은 항상 "다른 곳"의 세션이다.
|
||||||
boolean duplicate = userSessionService.getActiveSession(normalizedUsername).isPresent();
|
boolean duplicate = userSessionService.getActiveSession(normalizedUsername).isPresent();
|
||||||
|
// 화면 표시용 "직전 로그인" 조회 — 이번 로그인 기록(logSuccess) 삽입 전에 조회해야
|
||||||
|
// 방금 로그인이 아닌 그 이전 성공 로그인을 얻는다.
|
||||||
|
Optional<UserLog> previousLogin = userLogRepository
|
||||||
|
.findFirstByLoginIdAndSuccessOrderByLoginTimeDesc(rawUsername, true);
|
||||||
userLogService.logSuccess(rawUsername, ip, sessionId, loginType, request.getHeader("User-Agent"),
|
userLogService.logSuccess(rawUsername, ip, sessionId, loginType, request.getHeader("User-Agent"),
|
||||||
duplicate);
|
duplicate);
|
||||||
|
|
||||||
String contextPath = request.getContextPath();
|
String contextPath = request.getContextPath();
|
||||||
HttpSession session = request.getSession();
|
HttpSession session = request.getSession();
|
||||||
|
previousLogin.ifPresent(log -> {
|
||||||
|
session.setAttribute("previousLoginDate", log.getLoginTime());
|
||||||
|
session.setAttribute("previousLoginIp", log.getIp());
|
||||||
|
});
|
||||||
|
|
||||||
applyPostLoginState(user, session, rawUsername, contextPath);
|
applyPostLoginState(user, session, rawUsername, contextPath);
|
||||||
|
|
||||||
|
|||||||
@@ -1277,6 +1277,9 @@ hr {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
.mobile-drawer .drawer-welcome.authenticated .last-login-info {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
.mobile-drawer .drawer-footer {
|
.mobile-drawer .drawer-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@@ -1716,10 +1719,22 @@ hr {
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.last-login-info {
|
||||||
|
font-family: "Spoqa Han Sans Neo", "SpoqaHanSans", "Noto Sans KR", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
font-size: 9pt;
|
||||||
|
color: var(--text-gray);
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0 6px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.header-user-info {
|
.header-user-info {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.auth-group .last-login-info {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* 원래 있던 Footer 스타일 (주석 처리)
|
/* 원래 있던 Footer 스타일 (주석 처리)
|
||||||
.global-footer {
|
.global-footer {
|
||||||
@@ -5466,6 +5481,8 @@ select.form-control {
|
|||||||
}
|
}
|
||||||
.auth-group.authenticated {
|
.auth-group.authenticated {
|
||||||
gap: 0;
|
gap: 0;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
.auth-group .login-btn {
|
.auth-group .login-btn {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
@@ -5769,6 +5786,7 @@ select.form-control {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 16px;
|
top: 16px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
width: max-content;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
&.authenticated {
|
&.authenticated {
|
||||||
gap: 0;
|
gap: 0;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,9 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 16px;
|
top: 16px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
// body > * { width: 100% } 전역 리셋이 body 직계 자식인 이 플로팅 위젯에도 걸려
|
||||||
|
// 뷰포트 전체 폭으로 늘어나는 문제 방지 (fixed 위젯은 콘텐츠 크기만큼만 차지해야 함)
|
||||||
|
width: max-content;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -692,6 +692,10 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.last-login-info {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1320,9 +1324,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.last-login-info {
|
||||||
|
font-family: $font-family-primary;
|
||||||
|
font-size: 9pt;
|
||||||
|
color: var(--text-gray);
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0 6px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
// Mobile responsive
|
// Mobile responsive
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.header-user-info {
|
.header-user-info {
|
||||||
display: none; // Hide on mobile, use drawer instead
|
display: none; // Hide on mobile, use drawer instead
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auth-group .last-login-info {
|
||||||
|
display: none; // 데스크톱 상단바 전용. 모바일은 drawer(.welcome-user-info) 쪽에 별도 노출
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -89,6 +89,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="last-login-info" th:if="${session.previousLoginDate != null}"
|
||||||
|
th:text="|직전 로그인 : ${#temporals.format(session.previousLoginDate, 'yyyy-MM-dd HH:mm')} · ${session.previousLoginIp}|">직전 로그인 : 2026-08-25 14:32 · 121.162.0.0</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -176,6 +178,8 @@
|
|||||||
<div class="welcome-user-info">
|
<div class="welcome-user-info">
|
||||||
<p class="welcome-user-name">[[${#authentication.principal.userName}]]님</p>
|
<p class="welcome-user-name">[[${#authentication.principal.userName}]]님</p>
|
||||||
<p class="welcome-text">API Portal에 오신것을 환영합니다.</p>
|
<p class="welcome-text">API Portal에 오신것을 환영합니다.</p>
|
||||||
|
<p class="last-login-info" th:if="${session.previousLoginDate != null}"
|
||||||
|
th:text="|직전 로그인 : ${#temporals.format(session.previousLoginDate, 'yyyy-MM-dd HH:mm')} · ${session.previousLoginIp}|">직전 로그인 : 2026-08-25 14:32 · 121.162.0.0</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user