- 토큰 저장 키 통일 (access_token으로 일관성 확보) - 일일공수 페이지 API 스크립트 로딩 순서 수정 - 프로젝트 관리 페이지 비활성 프로젝트 표시 문제 해결 - 업로드 카테고리에 '기타' 항목 추가 (백엔드 schemas.py 포함) - 비밀번호 변경 기능 API 연동으로 수정 - 프로젝트 드롭다운 z-index 문제 해결 - CORS 설정 및 Nginx 구성 개선 - 비밀번호 해싱 방식 pbkdf2_sha256으로 변경 (bcrypt 72바이트 제한 해결)
138 lines
6.2 KiB
JavaScript
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');
|
|
}
|
|
});
|