feat: 모든 카테고리(HW, SW, SW 사용자) DB 일괄 덮어쓰기 저장 기능 구현

This commit is contained in:
2026-04-17 15:07:54 +09:00
parent a805d9ce06
commit c5c6acea6a
27 changed files with 2863 additions and 996 deletions

View File

@@ -1,8 +1,9 @@
import { state } from './core/state';
import { renderSidebar } from './components/Sidebar';
import { state, loadMasterDataFromDB } from './core/state';
import { renderNavigation } from './components/Navigation';
import { renderDashboard } from './views/DashboardView';
import { renderTable } from './views/AssetTableView';
import { downloadTemplate, exportToExcel, parseExcel, HardwareAsset } from './core/excelHandler';
import { downloadTemplate, exportToExcel, parseExcel, HardwareAsset, SoftwareAsset, SWUser } from './core/excelHandler';
import { initBaseModal } from './components/Modal/BaseModal';
import { initPcModal } from './components/Modal/PCModal';
import { initHwModal, openHwModal } from './components/Modal/HWModal';
import { initStorageModal } from './components/Modal/StorageModal';
@@ -11,40 +12,109 @@ import { initSwUserModal } from './components/Modal/SWUserModal';
import { initDashboardDetailModal } from './components/Modal/DashboardDetailModal';
import { createIcons, Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Laptop, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2, History, RefreshCcw } from 'lucide';
// --- DB 저장을 위한 헬퍼 함수 ---
async function saveAllHwToDB(assets: HardwareAsset[]) {
try {
const response = await fetch('http://localhost:3000/api/hw/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(assets)
});
if (!response.ok) throw new Error('HW DB 저장 실패');
console.log('✅ HW DB 저장 완료');
} catch (err) {
console.error('❌ HW DB 저장 실패:', err);
}
}
async function saveAllSwToDB(assets: SoftwareAsset[]) {
try {
const response = await fetch('http://localhost:3000/api/sw/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(assets)
});
if (!response.ok) throw new Error('SW DB 저장 실패');
console.log('✅ SW DB 저장 완료');
} catch (err) {
console.error('❌ SW DB 저장 실패:', err);
}
}
async function saveAllSwUsersToDB(users: SWUser[]) {
try {
const response = await fetch('http://localhost:3000/api/sw-users/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(users)
});
if (!response.ok) throw new Error('SW User DB 저장 실패');
console.log('✅ SW User DB 저장 완료');
} catch (err) {
console.error('❌ SW User DB 저장 실패:', err);
}
}
// --- App Initialization ---
function initApp() {
console.log('🚀 ITAM System Initializing...');
const mainContent = document.getElementById('main-content')!;
if (!mainContent) return;
// 1. 초기 뷰 렌더링 (대시보드)
renderDashboard(mainContent);
// 1. 전역 모달 및 내비게이션 초기화
const { closeAllModals } = initBaseModal();
// 2. 사이드바 초기화
renderSidebar((tab) => {
if (tab === '대시보드') {
renderDashboard(mainContent);
document.getElementById('btn-add-asset')?.classList.add('hidden');
} else {
try {
renderNavigation((tab) => {
if (tab === '대시보드') {
renderDashboard(mainContent);
} else {
renderTable(mainContent);
}
});
initPcModal(() => {
saveAllHwToDB(state.masterData.hw);
renderTable(mainContent);
document.getElementById('btn-add-asset')?.classList.remove('hidden');
}
// 상단 타이틀 업데이트
const titleEl = document.getElementById('current-tab-title')!;
if (titleEl) {
const catName = state.activeCategory === 'hw' ? '하드웨어' : '소프트웨어';
titleEl.textContent = `${catName} / ${state.activeSubTab}`;
}, closeAllModals);
initHwModal(() => {
saveAllHwToDB(state.masterData.hw);
renderTable(mainContent);
}, closeAllModals);
initStorageModal(() => {
saveAllHwToDB(state.masterData.hw);
renderTable(mainContent);
}, closeAllModals);
initSwModal(() => {
saveAllSwToDB(state.masterData.sw);
renderTable(mainContent);
}, closeAllModals);
initSwUserModal(() => {
saveAllSwUsersToDB(state.masterData.swUsers);
renderTable(mainContent);
}, closeAllModals);
initDashboardDetailModal();
} catch (e) {
console.error('❌ Initialization failed:', e);
}
// 2. 초기 렌더링
renderDashboard(mainContent);
// 3. 비동기 데이터 로드
loadMasterDataFromDB().then((success) => {
if (success) {
if (state.activeSubTab === '대시보드') renderDashboard(mainContent);
else renderTable(mainContent);
}
});
// 3. 모달 초기화 (HTML 주입 및 이벤트 바인딩)
initPcModal(() => renderTable(mainContent), () => {});
initHwModal();
initStorageModal(() => renderTable(mainContent), () => {});
initSwModal(() => renderTable(mainContent), () => {});
initSwUserModal(() => renderTable(mainContent), () => {});
initDashboardDetailModal();
// 4. 전역 버튼 이벤트 바인딩
// 4. 이벤트 바인딩
document.getElementById('btn-download-template')?.addEventListener('click', () => downloadTemplate());
document.getElementById('btn-export-excel')?.addEventListener('click', () => exportToExcel(state.masterData));
@@ -54,36 +124,29 @@ function initApp() {
if (file) {
const data = await parseExcel(file);
state.masterData = data;
// 엑셀 업로드 시 모든 카테고리 일괄 덮어쓰기 저장
await Promise.all([
saveAllHwToDB(data.hw),
saveAllSwToDB(data.sw),
saveAllSwUsersToDB(data.swUsers)
]);
renderTable(mainContent);
}
});
document.getElementById('btn-add-asset')?.addEventListener('click', () => {
if (state.activeSubTab === '서버' || state.activeSubTab === '전산비품' || state.activeSubTab === '스토리지') {
const newAsset: HardwareAsset = {
openHwModal({
id: Math.random().toString(36).substring(2, 9),
type: state.activeSubTab,
: '한맥',
: '',
: '',
: '',
: '',
IP주소: '',
MACaddress: '',
HW사양: '',
OS: '',
: '',
: ''
};
openHwModal(newAsset);
: '한맥', : '', : '', : '', : '', IP주소: '', MACaddress: '', HW사양: '', OS: '', : '', : ''
} as any);
}
});
// 전역 아이콘 초기화
createIcons({
icons: { Download, Upload, FileSpreadsheet, Plus, X, LayoutDashboard, Monitor, Server, Database, Laptop, CalendarClock, Key, Cpu, Layers, Users, Paperclip, Edit2, History, RefreshCcw }
});
}
// Start the app
document.addEventListener('DOMContentLoaded', initApp);