diff --git a/web-ui/js/load-sections.js b/web-ui/js/load-sections.js index ce322d7..6b735ff 100644 --- a/web-ui/js/load-sections.js +++ b/web-ui/js/load-sections.js @@ -1,187 +1,104 @@ -// ✅ /js/load-sections.js - 확장 가능한 구조 (개선됨) -import { API, getAuthHeaders } from '/js/api-config.js'; +// /js/load-sections.js +import { getUser } from './auth.js'; +import { apiGet } from './api-helper.js'; -// 역할별 섹션 매핑 (쉽게 추가/수정 가능) +// 역할에 따라 불러올 섹션 HTML 파일을 매핑합니다. const SECTION_MAP = { - 'admin': '/components/sections/admin-sections.html', - 'system': '/components/sections/admin-sections.html', - 'leader': '/components/sections/leader-sections.html', - 'group_leader': '/components/sections/leader-sections.html', - 'support': '/components/sections/support-sections.html', - 'support_team': '/components/sections/support-sections.html', - 'user': '/components/sections/user-sections.html', - 'worker': '/components/sections/user-sections.html' + admin: '/components/sections/admin-sections.html', + system: '/components/sections/admin-sections.html', // system도 admin과 동일한 섹션을 사용 + leader: '/components/sections/leader-sections.html', + user: '/components/sections/user-sections.html', + default: '/components/sections/user-sections.html', // 역할이 없는 경우 기본값 }; -// 공통 섹션 (모든 사용자에게 표시) -const COMMON_SECTIONS = '/components/sections/common-sections.html'; - -async function loadSections() { +/** + * API를 통해 대시보드 통계 데이터를 가져옵니다. + * @returns {Promise} 통계 데이터 또는 에러 시 null + */ +async function fetchDashboardStats() { try { - console.log('🔄 섹션 로딩 시작'); - - // 사용자 정보 확인 - const token = localStorage.getItem('token'); - if (!token) { - console.log('❌ 토큰 없음, 로그인 페이지로 이동'); - window.location.href = '/index.html'; - return; - } - - let userInfo = { role: 'user', access_level: 'worker' }; - try { - const payload = JSON.parse(atob(token.split('.')[1])); - userInfo = { - role: payload.role || 'user', - access_level: payload.access_level || 'worker' - }; - console.log('👤 사용자 정보:', userInfo); - } catch (err) { - console.warn('⚠️ JWT 파싱 실패:', err); - } - - // ✅ 컨테이너 찾기 - 더 안전한 방식 - const possibleContainers = [ - '#sections-container', - '#admin-sections', - '#user-sections', - 'main[id$="-sections"]', - '#content-container main' - ]; - - let container = null; - for (const selector of possibleContainers) { - container = document.querySelector(selector); - if (container) { - console.log(`✅ 컨테이너 발견: ${selector}`); - break; - } - } - - if (!container) { - console.error('❌ 섹션 컨테이너를 찾을 수 없습니다'); - return; - } - - container.innerHTML = '
콘텐츠를 불러오는 중...
'; - - // 역할별 섹션 파일 결정 (수정된 버전) - console.log('🔍 사용자 정보 디버깅:'); - console.log('- userInfo.role:', userInfo.role); - console.log('- userInfo.access_level:', userInfo.access_level); - - // role이 없으므로 access_level을 우선 사용 - const effectiveRole = userInfo.access_level || userInfo.role || 'user'; - const sectionFile = SECTION_MAP[effectiveRole] || SECTION_MAP['user']; - - console.log(`📄 실제 사용될 역할: ${effectiveRole}`); - console.log(`📄 로딩할 섹션 파일: ${sectionFile}`); - - try { - // 1. 공통 섹션 로드 (있을 경우) - let commonHtml = ''; - try { - console.log('📄 공통 섹션 로딩 시도'); - const commonRes = await fetch(COMMON_SECTIONS); - if (commonRes.ok) { - commonHtml = await commonRes.text(); - console.log('✅ 공통 섹션 로딩 성공'); - } - } catch (e) { - console.log('ℹ️ 공통 섹션 없음 (정상)'); - } - - // 2. 역할별 섹션 로드 - console.log('📄 역할별 섹션 로딩 시도'); - const res = await fetch(sectionFile); - if (!res.ok) { - throw new Error(`HTTP ${res.status}: 섹션 파일을 찾을 수 없습니다 (${sectionFile})`); - } - - const roleHtml = await res.text(); - console.log('✅ 역할별 섹션 로딩 성공'); - - // 3. 조합하여 표시 - container.innerHTML = commonHtml + roleHtml; - console.log('✅ 섹션 HTML 렌더링 완료'); - - // 4. 추가 데이터 로드 (필요시) - await loadDynamicData(userInfo); - console.log('✅ 섹션 로딩 완료'); - - } catch (err) { - console.error('❌ 섹션 로드 실패:', err); - container.innerHTML = ` -
-

❌ 콘텐츠를 불러올 수 없습니다

-

오류: ${err.message}

-

잠시 후 다시 시도해주세요.

- -
- `; - } - - } catch (err) { - console.error('🔴 섹션 로딩 실패:', err); + const today = new Date().toISOString().split('T')[0]; + // 실제 백엔드 엔드포인트는 /api/dashboard/stats 와 같은 형태로 구현될 수 있습니다. + const stats = await apiGet(`/workreports?start=${today}&end=${today}`); + // 필요한 데이터 형태로 가공 (예시) + return { + today_reports_count: stats.length, + today_workers_count: new Set(stats.map(d => d.worker_id)).size, + }; + } catch (error) { + console.error('대시보드 통계 데이터 로드 실패:', error); + return null; } } -// 동적 데이터 로드 (예: 대시보드 통계) -async function loadDynamicData(userInfo) { - console.log('📊 동적 데이터 로딩 시작'); +/** + * 가상 DOM에 통계 데이터를 채워 넣습니다. + * @param {Document} doc - 파싱된 HTML 문서 객체 + * @param {object} stats - 통계 데이터 + */ +function populateStatsData(doc, stats) { + if (!stats) return; + + const todayStatsEl = doc.getElementById('today-stats'); + if (todayStatsEl) { + todayStatsEl.innerHTML = ` +

📝 오늘 등록된 작업: ${stats.today_reports_count}건

+

👥 참여 작업자: ${stats.today_workers_count}명

+ `; + } +} + +/** + * 메인 로직: 페이지에 역할별 섹션을 로드하고 내용을 채웁니다. + */ +async function initializeSections() { + const mainContainer = document.querySelector('main[id$="-sections"]'); + if (!mainContainer) { + console.error('섹션을 담을 메인 컨테이너를 찾을 수 없습니다.'); + return; + } + mainContainer.innerHTML = '
콘텐츠를 불러오는 중...
'; + + const currentUser = getUser(); + if (!currentUser) { + mainContainer.innerHTML = '
사용자 정보를 찾을 수 없습니다.
'; + return; + } - // 오늘의 작업 현황 - const todayStats = document.getElementById('today-stats'); - if (todayStats) { - try { - const today = new Date().toISOString().split('T')[0]; - const res = await fetch(`${API}/workreports?start=${today}&end=${today}`, { - headers: getAuthHeaders() - }); - if (res.ok) { - const data = await res.json(); - todayStats.innerHTML = ` -

📝 오늘 등록된 작업: ${data.length}건

-

👥 참여 작업자: ${new Set(data.map(d => d.worker_id)).size}명

- `; - console.log('✅ 오늘 통계 로딩 완료'); - } - } catch (e) { - console.error('❌ 통계 로드 실패:', e); - if (todayStats) { - todayStats.innerHTML = '

⚠️ 통계를 불러올 수 없습니다

'; - } + const sectionFile = SECTION_MAP[currentUser.role] || SECTION_MAP.default; + + try { + // 1. 역할에 맞는 HTML 템플릿과 동적 데이터를 동시에 로드 (Promise.all 활용) + const [htmlResponse, statsData] = await Promise.all([ + fetch(sectionFile), + fetchDashboardStats() + ]); + + if (!htmlResponse.ok) { + throw new Error(`섹션 파일(${sectionFile})을 불러오는 데 실패했습니다.`); } - } + const htmlText = await htmlResponse.text(); - // 빠른 링크 활성화 - initializeQuickLinks(userInfo); + // 2. 텍스트를 가상 DOM으로 파싱 + const parser = new DOMParser(); + const doc = parser.parseFromString(htmlText, 'text/html'); + + // 3. (필요 시) 역할 기반으로 가상 DOM 필터링 - 현재는 파일 자체가 역할별로 나뉘어 불필요 + // filterByRole(doc, currentUser.role); + + // 4. 가상 DOM에 동적 데이터 채우기 + populateStatsData(doc, statsData); + + // 5. 모든 수정이 완료된 HTML을 실제 DOM에 한 번에 삽입 + mainContainer.innerHTML = doc.body.innerHTML; + + console.log(`✅ ${currentUser.role} 역할의 섹션 로딩 완료.`); + + } catch (error) { + console.error('섹션 로딩 중 오류 발생:', error); + mainContainer.innerHTML = `
콘텐츠 로딩에 실패했습니다: ${error.message}
`; + } } -// 권한별 빠른 링크 표시/숨김 -function initializeQuickLinks(userInfo) { - console.log('🔗 빠른 링크 초기화'); - - // 권한에 따라 특정 링크 숨기기 - if (userInfo.role !== 'admin' && userInfo.access_level !== 'admin') { - document.querySelectorAll('.admin-only').forEach(el => { - el.style.display = 'none'; - console.log('🔒 관리자 전용 링크 숨김'); - }); - } - - if (userInfo.access_level !== 'group_leader') { - document.querySelectorAll('.leader-only').forEach(el => { - el.style.display = 'none'; - console.log('🔒 그룹장 전용 링크 숨김'); - }); - } - - console.log('✅ 빠른 링크 초기화 완료'); -} - -// 페이지 로드 시 실행 -document.addEventListener('DOMContentLoaded', loadSections); - -// 수동 새로고침 함수 (다른 곳에서 호출 가능) -window.refreshSections = loadSections; \ No newline at end of file +// DOM이 로드되면 섹션 초기화를 시작합니다. +document.addEventListener('DOMContentLoaded', initializeSections); \ No newline at end of file diff --git a/web-ui/pages/dashboard/admin.html b/web-ui/pages/dashboard/admin.html index 4f9a363..fb4e61f 100644 --- a/web-ui/pages/dashboard/admin.html +++ b/web-ui/pages/dashboard/admin.html @@ -29,7 +29,6 @@ - \ No newline at end of file