feat(ui): /orderlist 미인증 시 dbx-main 로그인으로 위임, 프로필 헤더 개선

- read_root() 가 세션 미인증 시 dbx-main /login?next=/orderlist/ 로 302.
  OMS 는 더 이상 자체 로그인 UI 를 가지지 않는다.
- index.html: #login-screen 블록 제거, dashboard 만 렌더.
- 우측 상단 프로필 영역을 메인 페이지 스타일로 개편:
  이름 + 이메일 + 아바타(Google picture URL, 폴백 아이콘) + 로그아웃 텍스트 버튼.
- main.py 가 세션의 user_name/user_email/user_picture 를 HTML placeholder 로 치환.
- app.js checkAuth() 단순화: 화면 토글 제거, 401 시 dbx-main 로그인으로 자동 이동.
- style.css 에 새 프로필 영역 CSS 추가.

Google 아바타가 보이려면 dbx-main 도 같이 user_picture 를 세션 top-level 에
저장하도록 수정됨 (dbx-main 별도 커밋).
This commit is contained in:
2026-05-24 14:20:42 +09:00
parent 1eabd7183c
commit 931ad173ab
4 changed files with 163 additions and 51 deletions
+78
View File
@@ -1769,4 +1769,82 @@ input[type="checkbox"] {
}
}
/* ── 우측 상단 프로필 영역 (메인 페이지 스타일) ───────────── */
.nav-profile-area .profile-info {
display: flex;
align-items: center;
gap: 10px;
}
.nav-profile-area .profile-name-block {
display: flex;
flex-direction: column;
line-height: 1.2;
text-align: right;
}
.nav-profile-area .profile-name {
font-size: 14px;
font-weight: 700;
color: inherit;
white-space: nowrap;
}
.nav-profile-area .profile-email {
font-size: 11px;
color: rgba(120, 120, 130, 0.75);
white-space: nowrap;
}
.nav-profile-area .profile-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.08);
flex-shrink: 0;
}
.nav-profile-area .profile-avatar-img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.nav-profile-area .profile-avatar-icon {
color: rgba(80, 80, 90, 0.7);
font-size: 16px;
}
.nav-profile-area .btn-logout-text {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
background: rgba(0, 0, 0, 0.05);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 8px;
color: inherit;
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
line-height: 1;
}
.nav-profile-area .btn-logout-text:hover {
background: rgba(0, 0, 0, 0.1);
border-color: rgba(0, 0, 0, 0.2);
}
/* 모바일에서 이메일은 숨겨 공간 절약 */
@media (max-width: 720px) {
.nav-profile-area .profile-email { display: none; }
.nav-profile-area .btn-logout-text span { display: none; }
}
/* Force UI Update */
+14 -26
View File
@@ -20,26 +20,9 @@
<!-- MAIN APP CONTAINER -->
<div class="app-container" id="app">
<!-- LOGIN SCREEN (Visible when unauthenticated) -->
<div id="login-screen" class="screen active glass-panel">
<div class="login-box">
<div class="logo">
<i class="fa-solid fa-boxes-packing logo-icon"></i>
<h2>OMS system</h2>
</div>
<p class="subtitle">Enter the corporate order management center.</p>
<div class="oauth-buttons">
<button class="btn btn-primary" style="width: 100%;"
onclick="window.location.href='/login'">
<i class="fa-solid fa-right-to-bracket"></i> 로그인
</button>
</div>
<p class="auth-hint">Access restricted to approved users.</p>
</div>
</div>
<!-- DASHBOARD SCREEN (Visible when authenticated) -->
<div id="dashboard-screen" class="screen hidden">
<!-- DASHBOARD SCREEN — 미인증 사용자는 서버 단에서 dbx-main 로그인으로 리다이렉트되므로
OMS 자체 로그인 UI 는 더 이상 존재하지 않는다 (SSO 원칙). -->
<div id="dashboard-screen" class="screen active">
<!-- Unified Top Header Bar -->
<header class="unified-header glass-panel fade-in">
<!-- 1. Logo Section -->
@@ -111,16 +94,21 @@
</div>
</div>
<!-- 3. Profile Section -->
<!-- 3. Profile Section — 메인 페이지 스타일 (이름 + 이메일 + 아바타 + 로그아웃 버튼) -->
<div class="nav-profile-area">
<button id="btn-data-management" class="icon-btn mini-icon-btn nav-tool-btn" title="데이터 관리"><i
class="fa-solid fa-database"></i></button>
<div class="user-profile mini-profile">
<span id="user-name">Loading...</span>
<div class="avatar mini-avatar"><i class="fa-solid fa-user"></i></div>
<div class="profile-info">
<div class="profile-name-block">
<span class="profile-name" id="user-name">__USER_NAME__</span>
<span class="profile-email">__USER_EMAIL__</span>
</div>
<div class="profile-avatar">__USER_AVATAR__</div>
</div>
<button class="icon-btn mini-icon-btn" onclick="window.location.href='/logout'" title="Logout"><i
class="fa-solid fa-right-from-bracket"></i></button>
<button class="btn-logout-text" onclick="window.location.href='/logout'" title="로그아웃">
<i class="fa-solid fa-right-from-bracket"></i>
<span>로그아웃</span>
</button>
</div>
</header>
+10 -14
View File
@@ -3,8 +3,7 @@ document.addEventListener('DOMContentLoaded', () => {
const appUrl = (path) => `${APP_BASE_PATH}${path.startsWith('/') ? path : `/${path}`}`;
// --- Elements ---
const loginScreen = document.getElementById('login-screen');
const dashboardScreen = document.getElementById('dashboard-screen');
// loginScreen 은 더 이상 존재하지 않음 (서버에서 미인증 사용자를 dbx-main 으로 리다이렉트)
const userNameEl = document.getElementById('user-name');
const searchInputs = {
@@ -185,26 +184,23 @@ document.addEventListener('DOMContentLoaded', () => {
}
// --- Authentication ---
// 미인증 사용자는 서버(read_root) 가 이미 dbx-main 로그인으로 리다이렉트하므로
// 여기서는 is_admin 확인 + 세션 만료 시 다시 dbx-main 으로 보내는 역할만 한다.
async function checkAuth() {
try {
const res = await fetch(appUrl('/api/users/me'));
if (res.ok) {
currentUser = await res.json();
userNameEl.textContent = currentUser.name;
loginScreen.classList.remove('active');
loginScreen.classList.add('hidden');
dashboardScreen.classList.remove('hidden');
dashboardScreen.classList.add('active');
if (userNameEl && currentUser.name) {
userNameEl.textContent = currentUser.name;
}
if (btnDataManagement) {
btnDataManagement.style.display = currentUser.is_admin ? 'inline-flex' : 'none';
}
} else {
loginScreen.classList.remove('hidden');
loginScreen.classList.add('active');
dashboardScreen.classList.add('hidden');
dashboardScreen.classList.remove('active');
} else if (res.status === 401) {
// 세션 만료 — dbx-main 로그인으로 위임 (next 로 현재 위치 보존)
const next = encodeURIComponent((APP_BASE_PATH || '') + '/');
window.location.href = appUrl('/login') + '?next=' + next;
}
} catch (error) {
console.error('Auth check error', error);