Files
M-Project/frontend/static/js/common-header.js
hyungi 41b557a709 Fix: 페이지 간 이동 시 로그아웃 문제 해결 및 기능 개선
- 토큰 저장 키 통일 (access_token으로 일관성 확보)
- 일일공수 페이지 API 스크립트 로딩 순서 수정
- 프로젝트 관리 페이지 비활성 프로젝트 표시 문제 해결
- 업로드 카테고리에 '기타' 항목 추가 (백엔드 schemas.py 포함)
- 비밀번호 변경 기능 API 연동으로 수정
- 프로젝트 드롭다운 z-index 문제 해결
- CORS 설정 및 Nginx 구성 개선
- 비밀번호 해싱 방식 pbkdf2_sha256으로 변경 (bcrypt 72바이트 제한 해결)
2025-10-25 07:22:20 +09:00

138 lines
6.2 KiB
JavaScript

// 공통 헤더 생성 및 관리
class CommonHeader {
static create(currentPage = '') {
return `
<!-- 헤더 -->
<header class="bg-white shadow-sm sticky top-0 z-50">
<div class="container mx-auto px-4 py-3">
<div class="flex justify-between items-center">
<h1 class="text-xl font-bold text-gray-800">
<i class="fas fa-clipboard-check text-blue-500 mr-2"></i>작업보고서
</h1>
<div class="flex items-center gap-4">
<span class="text-sm text-gray-600" id="userDisplay"></span>
<button onclick="AuthCommon.logout()" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-sign-out-alt"></i>
</button>
</div>
</div>
</div>
</header>
<!-- 네비게이션 -->
<nav class="bg-white border-b">
<div class="container mx-auto px-4">
<div class="flex gap-2 py-2 overflow-x-auto">
<a href="daily-work.html" class="nav-link" id="dailyWorkBtn" style="display: none;">
<i class="fas fa-calendar-check mr-2"></i>일일 공수
</a>
${this.getNavButton('index.html', 'mainBtn', 'fas fa-camera-retro', '부적합 등록', currentPage === 'main')}
${this.getNavButton('issue-view.html', 'issueViewBtn', 'fas fa-search', '부적합 조회', currentPage === 'issue-view')}
${this.getNavButtonInternal('list', 'listBtn', 'fas fa-list', '목록 관리', currentPage === 'list')}
${this.getNavButtonInternal('summary', 'summaryBtn', 'fas fa-chart-bar', '보고서', currentPage === 'summary')}
<a href="project-management.html" class="nav-link" style="display:none;" id="projectBtn">
<i class="fas fa-folder-open 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>
`;
}
static getNavButton(href, id, iconClass, text, isActive = false) {
const activeClass = isActive ? ' active' : '';
return `<a href="${href}" class="nav-link${activeClass}" id="${id}">
<i class="${iconClass} mr-2"></i>${text}
</a>`;
}
static getNavButtonInternal(section, id, iconClass, text, isActive = false) {
const activeClass = isActive ? ' active' : '';
if (section === 'list' || section === 'summary') {
return `<button class="nav-link${activeClass}" onclick="showSection('${section}')" style="display:none;" id="${id}">
<i class="${iconClass} mr-2"></i>${text}
</button>`;
}
return `<a href="index.html#${section}" class="nav-link${activeClass}" style="display:none;" id="${id}">
<i class="${iconClass} mr-2"></i>${text}
</a>`;
}
static init(currentPage = '') {
// 헤더 HTML 삽입
const headerContainer = document.getElementById('header-container');
if (headerContainer) {
headerContainer.innerHTML = this.create();
}
// 현재 페이지 활성화
this.setActivePage(currentPage);
}
static setActivePage(currentPage) {
// 모든 nav-link에서 active 클래스 제거
document.querySelectorAll('.nav-link').forEach(link => {
link.classList.remove('active');
});
// 현재 페이지에 active 클래스 추가
const activeElement = document.getElementById(currentPage);
if (activeElement) {
activeElement.classList.add('active');
}
}
}
// 관리자 버튼 클릭 처리 (전역 함수)
function handleAdminClick() {
if (window.currentUser && window.currentUser.role === 'admin') {
window.location.href = 'admin.html';
} else {
// 비밀번호 변경 모달 표시
if (typeof showPasswordChangeModal === 'function') {
showPasswordChangeModal();
}
}
}
// 섹션 전환 (메인 페이지용)
function showSection(sectionName) {
if (typeof window.showSection === 'function') {
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');
}
});