- 알림 시스템 구축 (navbar 알림 아이콘, 드롭다운) - 알림 수신자 설정 기능 (계정관리 페이지) - 시설설비 관리 페이지 추가 (수리 워크플로우) - 수리 신청 → 접수 → 처리중 → 완료 상태 관리 - 사이드바 메뉴 구조 개선 (공장 관리 카테고리) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
81 lines
3.0 KiB
JavaScript
81 lines
3.0 KiB
JavaScript
// /js/component-loader.js
|
|
import { config } from './config.js';
|
|
|
|
// 캐시 버전 (컴포넌트 변경 시 증가)
|
|
const CACHE_VERSION = 'v4';
|
|
|
|
/**
|
|
* 컴포넌트 HTML을 캐시에서 가져오거나 fetch
|
|
*/
|
|
async function getComponentHtml(componentName, componentPath) {
|
|
const cacheKey = `component_${componentName}_${CACHE_VERSION}`;
|
|
|
|
// 캐시에서 먼저 확인
|
|
const cached = sessionStorage.getItem(cacheKey);
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
|
|
// 캐시 없으면 fetch
|
|
const response = await fetch(componentPath);
|
|
if (!response.ok) {
|
|
throw new Error(`컴포넌트 파일을 불러올 수 없습니다: ${response.statusText}`);
|
|
}
|
|
const htmlText = await response.text();
|
|
|
|
// 캐시에 저장
|
|
try {
|
|
sessionStorage.setItem(cacheKey, htmlText);
|
|
} catch (e) {
|
|
// sessionStorage 용량 초과 시 무시
|
|
}
|
|
|
|
return htmlText;
|
|
}
|
|
|
|
/**
|
|
* 공용 HTML 컴포넌트를 페이지의 특정 위치에 동적으로 로드합니다.
|
|
* @param {string} componentName - 로드할 컴포넌트의 이름 (e.g., 'sidebar', 'navbar'). config.js의 components 객체에 정의된 키와 일치해야 합니다.
|
|
* @param {string} containerSelector - 컴포넌트가 삽입될 DOM 요소의 CSS 선택자 (e.g., '#sidebar-container').
|
|
* @param {function(Document): void} [domProcessor=null] - DOM에 삽입하기 전에 로드된 HTML(Document)을 조작하는 선택적 함수.
|
|
* (e.g., 역할 기반 메뉴 필터링)
|
|
*/
|
|
export async function loadComponent(componentName, containerSelector, domProcessor = null) {
|
|
const container = document.querySelector(containerSelector);
|
|
if (!container) {
|
|
console.warn(`⚠️ 컴포넌트를 삽입할 컨테이너를 찾을 수 없습니다: ${containerSelector} (선택사항일 수 있음)`);
|
|
return;
|
|
}
|
|
|
|
const componentPath = config.components[componentName];
|
|
if (!componentPath) {
|
|
console.error(`🔴 설정 파일(config.js)에서 '${componentName}' 컴포넌트의 경로를 찾을 수 없습니다.`);
|
|
container.innerHTML = `<p>${componentName} 로딩 실패</p>`;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const htmlText = await getComponentHtml(componentName, componentPath);
|
|
|
|
if (domProcessor) {
|
|
// 1. 텍스트를 가상 DOM으로 파싱
|
|
const parser = new DOMParser();
|
|
const doc = parser.parseFromString(htmlText, 'text/html');
|
|
|
|
// 2. DOM 프로세서(콜백)를 실행하여 DOM 조작
|
|
await domProcessor(doc);
|
|
|
|
// 3. 조작된 HTML을 실제 DOM에 삽입
|
|
container.innerHTML = doc.body.innerHTML;
|
|
} else {
|
|
// DOM 조작이 필요 없는 경우, 바로 삽입
|
|
container.innerHTML = htmlText;
|
|
}
|
|
|
|
console.log(`✅ '${componentName}' 컴포넌트 로딩 완료: ${containerSelector}`);
|
|
|
|
} catch (error) {
|
|
console.error(`🔴 '${componentName}' 컴포넌트 로딩 실패:`, error);
|
|
container.innerHTML = `<p>${componentName} 로딩에 실패했습니다. 관리자에게 문의하세요.</p>`;
|
|
}
|
|
} |