241 lines
8.4 KiB
TypeScript
241 lines
8.4 KiB
TypeScript
import { state, loadMasterDataFromDB, saveAsset } from './core/state';
|
|
import { renderNavigation } from './components/Navigation';
|
|
import { renderDashboard } from './views/DashboardView';
|
|
import { renderSWTable } from './views/SW_Table';
|
|
import { renderLocationView } from './views/LocationView';
|
|
import { initBaseModal } from './components/Modal/BaseModal';
|
|
import { initHwModal, openHwModal } from './components/Modal/HWModal';
|
|
import { initSwModal, openSwModal } from './components/Modal/SWModal';
|
|
import { initSwUserModal } from './components/Modal/SWUserModal';
|
|
import { initDomainModal, openDomainModal } from './components/Modal/DomainModal';
|
|
import { initPartsMasterModal, openPartsMasterModal } from './components/Modal/PartsMasterModal';
|
|
import { initUserModal, openUserModal } from './components/Modal/UserModal';
|
|
import { initDashboardDetailModal } from './components/Modal/DashboardDetailModal';
|
|
import { initGuide } from './components/Guide';
|
|
import { pcFlowModal } from './components/Modal/PCFlowModal';
|
|
import { createIcons, Plus, X, LayoutDashboard, Monitor, Server, Database, Laptop, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2, History, RefreshCcw, BookOpen, Settings } from 'lucide';
|
|
|
|
|
|
// 화면 갱신 통합 핸들러
|
|
function refreshView() {
|
|
const mainContent = document.getElementById('main-content')!;
|
|
if (!mainContent) return;
|
|
|
|
if (state.activeSubTab === '대시보드') {
|
|
renderDashboard(mainContent);
|
|
return;
|
|
}
|
|
|
|
// 서버 탭이 아닐 경우 '자산현황(위치)' 뷰 진입 방지 및 강제 리스트 모드 전환
|
|
if (state.activeSubTab !== '서버' && state.viewMode === 'location') {
|
|
state.viewMode = 'list';
|
|
}
|
|
|
|
const isServerTab = state.activeSubTab === '서버';
|
|
|
|
mainContent.innerHTML = `
|
|
<div class="view-header">
|
|
<div class="view-toggle-container" style="${isServerTab ? '' : 'display:none;'}">
|
|
<button class="mode-toggle-btn ${state.viewMode === 'location' ? 'active' : ''}" data-mode="location">자산현황(위치)</button>
|
|
<button class="mode-toggle-btn ${state.viewMode === 'list' ? 'active' : ''}" data-mode="list">자산목록</button>
|
|
</div>
|
|
</div>
|
|
<div id="view-body" style="flex: 1; overflow: hidden; display: flex; flex-direction: column;"></div>
|
|
`;
|
|
|
|
// 이벤트 바인딩
|
|
mainContent.querySelectorAll('.mode-toggle-btn').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const mode = (btn as HTMLElement).getAttribute('data-mode') as any;
|
|
state.viewMode = mode;
|
|
refreshView();
|
|
});
|
|
});
|
|
|
|
const viewBody = document.getElementById('view-body')!;
|
|
if (state.viewMode === 'location') {
|
|
renderLocationView(viewBody);
|
|
} else {
|
|
renderSWTable(viewBody); // 리스트 형식
|
|
}
|
|
}
|
|
|
|
// 통합 갱신 (저장은 이미 개별 모달에서 처리됨)
|
|
async function refreshAllData() {
|
|
await loadMasterDataFromDB();
|
|
refreshView();
|
|
}
|
|
|
|
// --- App Initialization ---
|
|
function initApp() {
|
|
const mainContent = document.getElementById('main-content')!;
|
|
if (!mainContent) return;
|
|
|
|
const { closeAllModals } = initBaseModal();
|
|
|
|
try {
|
|
renderNavigation((tab) => {
|
|
refreshView();
|
|
});
|
|
|
|
initHwModal(() => refreshAllData(), closeAllModals);
|
|
initSwModal(() => refreshAllData(), closeAllModals);
|
|
initSwUserModal(() => {
|
|
loadMasterDataFromDB().then(() => refreshView());
|
|
}, closeAllModals);
|
|
initDomainModal(() => refreshAllData(), closeAllModals);
|
|
initPartsMasterModal(() => refreshAllData(), closeAllModals);
|
|
initUserModal(() => refreshAllData(), closeAllModals);
|
|
|
|
initDashboardDetailModal();
|
|
initGuide();
|
|
pcFlowModal.init(() => {
|
|
loadMasterDataFromDB().then(() => refreshView());
|
|
});
|
|
|
|
loadMasterDataFromDB().then((success) => {
|
|
if (success) {
|
|
refreshView();
|
|
}
|
|
});
|
|
} catch (e) { console.error('❌ Initialization failed:', e); }
|
|
|
|
console.log('🚀 ITAM App Multi-Table Optimized');
|
|
|
|
// --- 통합 이벤트 위임 (Dynamic Elements 지원) ---
|
|
document.addEventListener('click', (e) => {
|
|
const target = e.target as HTMLElement;
|
|
|
|
// 자산 추가
|
|
if (target.closest('#btn-add-asset')) {
|
|
const tab = state.activeSubTab;
|
|
const cat = state.activeCategory;
|
|
const newId = Math.random().toString(36).substring(2, 9);
|
|
|
|
if (cat === 'hw') {
|
|
if (tab === '부품 마스터') {
|
|
openPartsMasterModal({ id: '' } as any, 'add');
|
|
} else {
|
|
openHwModal({ id: newId, asset_code: '', category: tab } as any, 'add');
|
|
}
|
|
} else if (cat === 'sw') {
|
|
const swType = tab === '외부SW' ? '외부SW' : (tab === '내부SW' ? '내부SW' : '외부SW');
|
|
openSwModal({ id: newId, asset_type: swType } as any, 'add');
|
|
} else if (cat === 'ops') {
|
|
if (tab === '도메인') openDomainModal(null);
|
|
else if (tab === '사용자') openUserModal({ id: '' }, 'add');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// 부품 마스터 탭으로 바로가기 연동
|
|
if (target.closest('#btn-goto-parts-master')) {
|
|
state.activeCategory = 'hw';
|
|
state.activeSubTab = '부품 마스터';
|
|
renderNavigation((tab) => { refreshView(); });
|
|
refreshView();
|
|
return;
|
|
}
|
|
|
|
// PC 이동/반납 모달 열기
|
|
if (target.closest('#btn-pc-flow')) {
|
|
pcFlowModal.open();
|
|
return;
|
|
}
|
|
});
|
|
|
|
createIcons({
|
|
icons: { Plus, X, LayoutDashboard, Monitor, Server, Database, Laptop, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2, History, RefreshCcw, BookOpen, Settings }
|
|
});
|
|
window.addEventListener('refresh-view', () => refreshView());
|
|
}
|
|
|
|
/**
|
|
* 헤더 역할 전환 토글 로직
|
|
*/
|
|
function initRoleSwitcher() {
|
|
const checkbox = document.getElementById('role-toggle-checkbox') as HTMLInputElement;
|
|
const userLabel = document.querySelector('.role-label.user');
|
|
const adminLabel = document.querySelector('.role-label.admin');
|
|
|
|
if (!checkbox || !userLabel || !adminLabel) return;
|
|
|
|
checkbox.addEventListener('change', () => {
|
|
const mainContent = document.getElementById('main-content')!;
|
|
if (checkbox.checked) {
|
|
state.currentUserRole = 'admin';
|
|
userLabel.classList.remove('active');
|
|
adminLabel.classList.add('active');
|
|
document.body.classList.add('admin-mode');
|
|
|
|
// 관리자 모드 전환 시 대시보드로 이동
|
|
state.activeCategory = 'hw';
|
|
state.activeSubTab = '대시보드';
|
|
refreshView();
|
|
renderNavigation((tab) => {
|
|
if (tab === '대시보드') {
|
|
renderDashboard(mainContent);
|
|
} else {
|
|
renderSWTable(mainContent);
|
|
}
|
|
});
|
|
} else {
|
|
state.currentUserRole = 'user';
|
|
adminLabel.classList.remove('active');
|
|
userLabel.classList.add('active');
|
|
document.body.classList.remove('admin-mode');
|
|
|
|
// 실무자 모드 전환 시 서버 목록으로 이동
|
|
state.activeCategory = 'hw';
|
|
state.activeSubTab = '서버';
|
|
refreshView();
|
|
renderNavigation((tab) => {
|
|
if (tab === '대시보드') {
|
|
renderDashboard(mainContent);
|
|
} else {
|
|
renderSWTable(mainContent);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 앱 초기화 (로그인 과정 없이 즉시 시작)
|
|
*/
|
|
function initializeAppDirectly() {
|
|
const loginContainer = document.getElementById('login-container');
|
|
const appLayout = document.getElementById('app-layout');
|
|
const checkbox = document.getElementById('role-toggle-checkbox') as HTMLInputElement;
|
|
const userLabel = document.querySelector('.role-label.user');
|
|
const adminLabel = document.querySelector('.role-label.admin');
|
|
|
|
// 기본 권한 설정: 실무자 (User)
|
|
state.currentUserRole = 'user';
|
|
state.activeCategory = 'hw';
|
|
state.activeSubTab = '서버'; // 실무자 기본 탭
|
|
|
|
// UI 상태 동기화
|
|
if (checkbox) checkbox.checked = false;
|
|
if (userLabel) userLabel.classList.add('active');
|
|
if (adminLabel) adminLabel.classList.remove('active');
|
|
document.body.classList.remove('admin-mode');
|
|
|
|
// 화면 전환
|
|
if (loginContainer) loginContainer.style.display = 'none';
|
|
if (appLayout) appLayout.style.display = 'flex';
|
|
|
|
// 앱 초기화
|
|
initRoleSwitcher();
|
|
initApp();
|
|
|
|
// 로고 클릭 시 새로고침 (초기 화면 복귀 효과)
|
|
const brand = document.querySelector('.brand') as HTMLElement;
|
|
if (brand) {
|
|
brand.style.cursor = 'pointer';
|
|
brand.onclick = () => location.reload();
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', initializeAppDirectly);
|