feat: 모바일 UX 대폭 개선 + PWA 구현 + 로그인 루프 수정

- 모바일 하단 네비: 메뉴 제거, 4개 핵심 기능(홈/TBM/작업보고/출근) SVG 아이콘
- 모바일 사이드바 스킵: 768px 이하에서 사이드바 미로드, 레이아웃 오프셋 해결
- 모바일 헤더: 햄버거 메뉴 숨김, 본문 margin/overflow 정리
- TBM 모바일: 풀스크린 모달, 저장 버튼 하단 고정, 터치 UX 개선
- PWA: manifest.json, sw.js(network-first), 앱 아이콘, iOS 메타태그, 킬스위치
- 로그인 무한루프 수정: 토큰 만료 검증, 쿠키 정리, loginPage 경로 수정
- 신고 메뉴 tkreport 리다이렉트: navbar + sidebar cross-system-link 적용
- TBM API: 작업장별 안전점검 체크리스트 조회 엔드포인트 추가
- 안전점검 체크리스트 관리 UI 개선
- tkuser: 이슈유형 관리 기능 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-02-24 08:20:50 +09:00
parent 3cc29c03a8
commit d36303101e
60 changed files with 1418 additions and 270 deletions

View File

@@ -491,28 +491,35 @@
}
}
// 3. 사이드바 컨테이너 생성 (없으면)
let sidebarContainer = document.getElementById('sidebar-container');
if (!sidebarContainer) {
sidebarContainer = document.createElement('div');
sidebarContainer.id = 'sidebar-container';
document.body.prepend(sidebarContainer);
console.log('📦 사이드바 컨테이너 생성됨');
// 3. 네비바 로드 (모바일이면 사이드바 스킵)
var isMobile = window.innerWidth <= 768;
if (!isMobile) {
// 데스크톱: 사이드바 컨테이너 생성 및 로드
let sidebarContainer = document.getElementById('sidebar-container');
if (!sidebarContainer) {
sidebarContainer = document.createElement('div');
sidebarContainer.id = 'sidebar-container';
document.body.prepend(sidebarContainer);
}
console.log('📥 컴포넌트 로딩 시작 (데스크톱: 네비바+사이드바)');
await Promise.all([
loadComponent('navbar', '#navbar-container', (doc) => processNavbar(doc, currentUser, accessiblePageKeys)),
loadComponent('sidebar-nav', '#sidebar-container', (doc) => processSidebar(doc, currentUser, accessiblePageKeys))
]);
setupNavbarEvents();
setupSidebarEvents();
document.body.classList.add('has-sidebar');
} else {
// 모바일: 네비바만 로드, 사이드바 없음
console.log('📥 컴포넌트 로딩 시작 (모바일: 네비바만)');
await loadComponent('navbar', '#navbar-container', (doc) => processNavbar(doc, currentUser, accessiblePageKeys));
setupNavbarEvents();
}
// 4. 네비바와 사이드바 동시 로드
console.log('📥 컴포넌트 로딩 시작');
await Promise.all([
loadComponent('navbar', '#navbar-container', (doc) => processNavbar(doc, currentUser, accessiblePageKeys)),
loadComponent('sidebar-nav', '#sidebar-container', (doc) => processSidebar(doc, currentUser, accessiblePageKeys))
]);
console.log('✅ 컴포넌트 로딩 완료');
// 5. 이벤트 설정
setupNavbarEvents();
setupSidebarEvents();
document.body.classList.add('has-sidebar');
// 6. 페이지 전환 로딩 인디케이터 설정
setupPageTransitionLoader();
@@ -527,9 +534,69 @@
setTimeout(loadNotifications, 200);
setInterval(loadNotifications, 30000);
// 10. PWA 설정 (manifest + 서비스 워커 + iOS 메타태그)
setupPWA();
console.log('✅ app-init 완료');
}
// ===== PWA 설정 =====
function setupPWA() {
// manifest.json 동적 추가
if (!document.querySelector('link[rel="manifest"]')) {
var manifest = document.createElement('link');
manifest.rel = 'manifest';
manifest.href = '/manifest.json';
document.head.appendChild(manifest);
}
// iOS 홈 화면 앱 메타태그
if (!document.querySelector('meta[name="apple-mobile-web-app-capable"]')) {
var metaTags = [
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
{ name: 'apple-mobile-web-app-status-bar-style', content: 'default' },
{ name: 'apple-mobile-web-app-title', content: 'TK공장' },
{ name: 'theme-color', content: '#1e40af' }
];
metaTags.forEach(function(tag) {
var meta = document.createElement('meta');
meta.name = tag.name;
meta.content = tag.content;
document.head.appendChild(meta);
});
// iOS 아이콘
var appleIcon = document.createElement('link');
appleIcon.rel = 'apple-touch-icon';
appleIcon.href = '/img/icon-192x192.png';
document.head.appendChild(appleIcon);
}
// 서비스 워커 등록 (킬스위치 포함)
if ('serviceWorker' in navigator) {
// 킬스위치: ?sw-kill 파라미터로 서비스 워커 해제
if (window.location.search.includes('sw-kill')) {
navigator.serviceWorker.getRegistrations().then(function(regs) {
regs.forEach(function(r) { r.unregister(); });
caches.keys().then(function(keys) {
keys.forEach(function(k) { caches.delete(k); });
});
console.log('SW 해제 완료');
window.location.replace(window.location.pathname);
});
return;
}
navigator.serviceWorker.register('/sw.js')
.then(function(reg) {
console.log('SW 등록 완료');
})
.catch(function(err) {
console.warn('SW 등록 실패:', err);
});
}
}
// ===== 페이지 전환 로딩 인디케이터 =====
function setupPageTransitionLoader() {
// 로딩 바 스타일 추가