Fix: 페이지 간 이동 시 로그아웃 문제 해결 및 기능 개선
- 토큰 저장 키 통일 (access_token으로 일관성 확보) - 일일공수 페이지 API 스크립트 로딩 순서 수정 - 프로젝트 관리 페이지 비활성 프로젝트 표시 문제 해결 - 업로드 카테고리에 '기타' 항목 추가 (백엔드 schemas.py 포함) - 비밀번호 변경 기능 API 연동으로 수정 - 프로젝트 드롭다운 z-index 문제 해결 - CORS 설정 및 Nginx 구성 개선 - 비밀번호 해싱 방식 pbkdf2_sha256으로 변경 (bcrypt 72바이트 제한 해결)
This commit is contained in:
@@ -1,5 +1,30 @@
|
||||
// API 기본 설정
|
||||
const API_BASE_URL = '/api';
|
||||
// API 기본 설정 (Cloudflare 터널 + 로컬 환경 지원)
|
||||
const API_BASE_URL = (() => {
|
||||
const hostname = window.location.hostname;
|
||||
const protocol = window.location.protocol;
|
||||
const port = window.location.port;
|
||||
|
||||
console.log('🔧 API URL 생성 - hostname:', hostname, 'protocol:', protocol, 'port:', port);
|
||||
|
||||
// 로컬 환경 (포트 있음)
|
||||
if (port === '16080') {
|
||||
const url = `${protocol}//${hostname}:${port}/api`;
|
||||
console.log('🏠 로컬 환경 URL:', url);
|
||||
return url;
|
||||
}
|
||||
|
||||
// Cloudflare 터널 환경 (m.hyungi.net) - 강제 HTTPS
|
||||
if (hostname === 'm.hyungi.net') {
|
||||
const url = `https://m-api.hyungi.net/api`;
|
||||
console.log('☁️ Cloudflare 환경 URL:', url);
|
||||
return url;
|
||||
}
|
||||
|
||||
// 기타 환경
|
||||
const url = '/api';
|
||||
console.log('🌐 기타 환경 URL:', url);
|
||||
return url;
|
||||
})();
|
||||
|
||||
// 토큰 관리
|
||||
const TokenManager = {
|
||||
@@ -76,23 +101,29 @@ const AuthAPI = {
|
||||
formData.append('username', username);
|
||||
formData.append('password', password);
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.detail || '로그인 실패');
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: formData.toString()
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
console.error('로그인 에러:', error);
|
||||
throw new Error(error.detail || '로그인 실패');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
TokenManager.setToken(data.access_token);
|
||||
TokenManager.setUser(data.user);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('로그인 요청 에러:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
TokenManager.setToken(data.access_token);
|
||||
TokenManager.setUser(data.user);
|
||||
return data;
|
||||
},
|
||||
|
||||
logout: () => {
|
||||
@@ -103,6 +134,8 @@ const AuthAPI = {
|
||||
|
||||
getMe: () => apiRequest('/auth/me'),
|
||||
|
||||
getCurrentUser: () => apiRequest('/auth/me'),
|
||||
|
||||
createUser: (userData) => apiRequest('/auth/users', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(userData)
|
||||
@@ -252,12 +285,12 @@ function checkAdminAuth() {
|
||||
const ProjectsAPI = {
|
||||
getAll: (activeOnly = false) => {
|
||||
const params = activeOnly ? '?active_only=true' : '';
|
||||
return apiRequest(`/projects${params}`);
|
||||
return apiRequest(`/projects/${params}`);
|
||||
},
|
||||
|
||||
get: (id) => apiRequest(`/projects/${id}`),
|
||||
|
||||
create: (projectData) => apiRequest('/projects', {
|
||||
create: (projectData) => apiRequest('/projects/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(projectData)
|
||||
}),
|
||||
|
||||
@@ -39,8 +39,7 @@ class AuthCommon {
|
||||
'dailyWorkBtn',
|
||||
'listBtn',
|
||||
'summaryBtn',
|
||||
'projectBtn',
|
||||
'adminBtn'
|
||||
'projectBtn'
|
||||
];
|
||||
|
||||
adminMenus.forEach(menuId => {
|
||||
@@ -49,6 +48,20 @@ class AuthCommon {
|
||||
element.style.display = isAdmin ? '' : 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// 관리자 버튼 처리 (드롭다운 vs 단순 버튼)
|
||||
const adminBtnContainer = document.getElementById('adminBtnContainer');
|
||||
const userPasswordBtn = document.getElementById('userPasswordBtn');
|
||||
|
||||
if (isAdmin) {
|
||||
// 관리자: 드롭다운 메뉴 표시
|
||||
if (adminBtnContainer) adminBtnContainer.style.display = '';
|
||||
if (userPasswordBtn) userPasswordBtn.style.display = 'none';
|
||||
} else {
|
||||
// 일반 사용자: 비밀번호 변경 버튼만 표시
|
||||
if (adminBtnContainer) adminBtnContainer.style.display = 'none';
|
||||
if (userPasswordBtn) userPasswordBtn.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
static logout() {
|
||||
|
||||
@@ -33,9 +33,22 @@ class CommonHeader {
|
||||
<a href="project-management.html" class="nav-link" style="display:none;" id="projectBtn">
|
||||
<i class="fas fa-folder-open mr-2"></i>프로젝트 관리
|
||||
</a>
|
||||
<a href="admin.html" class="nav-link" style="display:none;" id="adminBtn">
|
||||
<i class="fas fa-users-cog mr-2"></i>관리
|
||||
</a>
|
||||
<div class="relative" style="display:none;" id="adminBtnContainer">
|
||||
<button class="nav-link" id="adminBtn" onclick="toggleAdminMenu()">
|
||||
<i class="fas fa-users-cog mr-2"></i>관리 <i class="fas fa-chevron-down ml-1"></i>
|
||||
</button>
|
||||
<div id="adminMenu" class="absolute right-0 mt-1 w-48 bg-white rounded-md shadow-lg border border-gray-200 z-50 hidden">
|
||||
<a href="admin.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-users-cog mr-2"></i>사용자 관리
|
||||
</a>
|
||||
<button onclick="showPasswordChangeModal()" class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-key mr-2"></i>비밀번호 변경
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="nav-link" style="display:none;" id="userPasswordBtn" onclick="showPasswordChangeModal()">
|
||||
<i class="fas fa-key mr-2"></i>비밀번호 변경
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -104,3 +117,21 @@ function showSection(sectionName) {
|
||||
window.showSection(sectionName);
|
||||
}
|
||||
}
|
||||
|
||||
// 관리자 메뉴 토글
|
||||
function toggleAdminMenu() {
|
||||
const menu = document.getElementById('adminMenu');
|
||||
if (menu) {
|
||||
menu.classList.toggle('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// 메뉴 외부 클릭 시 닫기
|
||||
document.addEventListener('click', function(event) {
|
||||
const adminBtn = document.getElementById('adminBtn');
|
||||
const adminMenu = document.getElementById('adminMenu');
|
||||
|
||||
if (adminBtn && adminMenu && !adminBtn.contains(event.target) && !adminMenu.contains(event.target)) {
|
||||
adminMenu.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user