sso_users.user_id를 단일 식별자로 통합. JWT에서 worker_id 제거, department_id/is_production 추가. 백엔드 15개 모델, 11개 컨트롤러, 4개 서비스, 7개 라우트, 프론트엔드 32+ JS/11+ HTML 변환. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
104 lines
3.8 KiB
JavaScript
104 lines
3.8 KiB
JavaScript
// /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', // system도 admin과 동일한 섹션을 사용
|
|
leader: '/components/sections/leader-sections.html',
|
|
user: '/components/sections/user-sections.html',
|
|
default: '/components/sections/user-sections.html', // 역할이 없는 경우 기본값
|
|
};
|
|
|
|
/**
|
|
* API를 통해 대시보드 통계 데이터를 가져옵니다.
|
|
* @returns {Promise<object|null>} 통계 데이터 또는 에러 시 null
|
|
*/
|
|
async function fetchDashboardStats() {
|
|
try {
|
|
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.user_id)).size,
|
|
};
|
|
} catch (error) {
|
|
console.error('대시보드 통계 데이터 로드 실패:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 가상 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 = `
|
|
<p>📝 오늘 등록된 작업: ${stats.today_reports_count}건</p>
|
|
<p>👥 참여 작업자: ${stats.today_workers_count}명</p>
|
|
`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 메인 로직: 페이지에 역할별 섹션을 로드하고 내용을 채웁니다.
|
|
*/
|
|
async function initializeSections() {
|
|
const mainContainer = document.querySelector('main[id$="-sections"]');
|
|
if (!mainContainer) {
|
|
console.error('섹션을 담을 메인 컨테이너를 찾을 수 없습니다.');
|
|
return;
|
|
}
|
|
mainContainer.innerHTML = '<div class="loading">콘텐츠를 불러오는 중...</div>';
|
|
|
|
const currentUser = getUser();
|
|
if (!currentUser) {
|
|
mainContainer.innerHTML = '<div class="error-state">사용자 정보를 찾을 수 없습니다.</div>';
|
|
return;
|
|
}
|
|
|
|
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();
|
|
|
|
// 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 = `<div class="error-state">콘텐츠 로딩에 실패했습니다: ${error.message}</div>`;
|
|
}
|
|
}
|
|
|
|
// DOM이 로드되면 섹션 초기화를 시작합니다.
|
|
document.addEventListener('DOMContentLoaded', initializeSections); |