import { HardwareAsset, SoftwareAsset, SWUser, HardwareLog } from './excelHandler'; // --- State Definitions --- export interface MasterAssetData { pc: HardwareAsset[]; server: HardwareAsset[]; storage: HardwareAsset[]; equip: HardwareAsset[]; mobile: HardwareAsset[]; subSw: SoftwareAsset[]; permSw: SoftwareAsset[]; cloud: SoftwareAsset[]; // 클라우드 배열 추가 swUsers: SWUser[]; logs: HardwareLog[]; domain: any[]; // 동료 코드 호환용 통합 배열 (프론트엔드 로직용) hw: HardwareAsset[]; sw: SoftwareAsset[]; } export interface AppState { activeCategory: 'dashboard' | 'hw' | 'sw' | 'ops'; activeSubTab: string; // '대시보드', '개인PC', '서버', '스토리지', '전산비품', '구독SW', '영구SW', '클라우드' masterData: MasterAssetData; activeCharts?: any[]; } // 초기 상태 export const state: AppState = { activeCategory: 'dashboard', activeSubTab: '대시보드', masterData: { pc: [], server: [], storage: [], equip: [], mobile: [], subSw: [], permSw: [], cloud: [], hw: [], // 호환용 sw: [], // 호환용 swUsers: [], logs: [], domain: [] } }; /** * 전용 API 엔드포인트들로부터 데이터 로드 */ export async function loadMasterDataFromDB() { try { const endpoints = [ { key: 'pc', url: `http://${location.hostname}:3000/api/pc` }, { key: 'server', url: `http://${location.hostname}:3000/api/server` }, { key: 'storage', url: `http://${location.hostname}:3000/api/storage` }, { key: 'equip', url: `http://${location.hostname}:3000/api/equip` }, { key: 'mobile', url: `http://${location.hostname}:3000/api/mobile` }, { key: 'subSw', url: `http://${location.hostname}:3000/api/sw/sub` }, { key: 'permSw', url: `http://${location.hostname}:3000/api/sw/perm` }, { key: 'cloud', url: `http://${location.hostname}:3000/api/cloud` }, { key: 'domain', url: `http://${location.hostname}:3000/api/ops/domain` }, { key: 'swUsers', url: `http://${location.hostname}:3000/api/sw-users` }, { key: 'logs', url: `http://${location.hostname}:3000/api/logs` } ]; const results = await Promise.all(endpoints.map(e => fetch(e.url))); // 기존 데이터 초기화 (재분류 전) state.masterData.pc = []; state.masterData.server = []; state.masterData.storage = []; state.masterData.equip = []; state.masterData.mobile = []; for (let i = 0; i < endpoints.length; i++) { if (results[i].ok) { const data = await results[i].json(); const key = endpoints[i].key; if (['pc', 'server', 'storage', 'equip', 'mobile'].includes(key)) { // 하드웨어 데이터는 자동 재분류 로직 통과 (data as HardwareAsset[]).forEach(asset => saveHardwareAsset(asset)); } else { (state.masterData as any)[key] = data || []; } } } // 동료 코드 호환을 위한 통합 sw 배열 생성 state.masterData.sw = [ ...state.masterData.subSw, ...state.masterData.permSw, ...state.masterData.cloud ]; // 하드웨어 통합 배열 생성 (대시보드 등에서 사용) state.masterData.hw = [ ...state.masterData.pc, ...state.masterData.server, ...state.masterData.storage, ...state.masterData.equip, ...state.masterData.mobile ]; console.log('✅ 모든 DB 데이터 로드 및 통합 완료'); return true; } catch (err) { console.warn('⚠️ 백엔드 서버 연결 실패. 로컬 데이터를 유지합니다.'); } return false; } // --- State Helpers --- export function updateState(newState: Partial) { Object.assign(state, newState); } /** * 하드웨어 자산 통합 저장 (자동 카테고리 분류) */ export function saveHardwareAsset(updatedAsset: HardwareAsset) { const type = updatedAsset.type || ''; const detailPurpose = (updatedAsset as any).상세용도 || updatedAsset.detail_purpose || ''; // 1. 타겟 카테고리 결정 (사용자 정의 그룹 기준) let targetKey: keyof MasterAssetData = 'equip'; const upperType = type.toUpperCase(); const isServer = type.includes('서버') || detailPurpose.includes('서버'); const isStorage = ['NAS', 'DAS', '스토리지'].some(t => type.includes(t)); const isMobileGroup = ['모바일', '태블릿', '노트북', '휴대폰', '핸드폰'].some(t => type.includes(t)); const isEquipGroup = ['CPU', 'RAM', 'HDD', 'GPU'].some(t => upperType.includes(t)); const isPc = type === 'PC' || type === '개인PC' || detailPurpose === '개인PC'; if (isServer) { targetKey = 'server'; } else if (isStorage) { targetKey = 'storage'; } else if (isMobileGroup) { targetKey = 'mobile'; } else if (isPc) { targetKey = 'pc'; } else if (isEquipGroup) { targetKey = 'equip'; } // 2. 모든 카테고리에서 기존 ID 자산 삭제 (중복 방지) const hwKeys: (keyof MasterAssetData)[] = ['pc', 'server', 'storage', 'equip', 'mobile']; hwKeys.forEach(key => { const arr = state.masterData[key] as HardwareAsset[]; if (Array.isArray(arr)) { const idx = arr.findIndex(a => a.id === updatedAsset.id); if (idx > -1) arr.splice(idx, 1); } }); // 3. 새로운 타겟 카테고리에 추가 (state.masterData[targetKey] as HardwareAsset[]).push(updatedAsset); // 4. 통합 hw 배열 동기화 state.masterData.hw = [ ...state.masterData.pc, ...state.masterData.server, ...state.masterData.storage, ...state.masterData.equip, ...state.masterData.mobile ]; } /** * 하드웨어 자산 통합 삭제 */ export function deleteHardwareAsset(assetId: string) { const hwKeys: (keyof MasterAssetData)[] = ['pc', 'server', 'storage', 'equip', 'mobile']; hwKeys.forEach(key => { const arr = state.masterData[key] as HardwareAsset[]; if (Array.isArray(arr)) { const idx = arr.findIndex(a => a.id === assetId); if (idx > -1) arr.splice(idx, 1); } }); // 통합 hw 배열 동기화 state.masterData.hw = [ ...state.masterData.pc, ...state.masterData.server, ...state.masterData.storage, ...state.masterData.equip, ...state.masterData.mobile ]; } /** * 소프트웨어 자산 저장 (API 연동) */ export async function saveSoftwareAsset(asset: SoftwareAsset) { try { const response = await fetch(`http://${location.hostname}:3000/api/software/save`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(asset) }); if (response.ok) { // 로컬 상태 업데이트 const key = asset.type === '구독SW' ? 'subSw' : (asset.type === '영구SW' ? 'permSw' : 'cloud'); const arr = state.masterData[key] as SoftwareAsset[]; const idx = arr.findIndex(a => a.id === asset.id); if (idx > -1) arr[idx] = asset; else arr.push(asset); // 통합 sw 배열 동기화 state.masterData.sw = [...state.masterData.subSw, ...state.masterData.permSw, ...state.masterData.cloud]; return true; } } catch (err) { console.error('SW 저장 실패:', err); } return false; } /** * 소프트웨어 자산 삭제 (API 연동) */ export async function deleteSoftwareAsset(type: string, id: string) { try { const response = await fetch(`http://${location.hostname}:3000/api/asset/${type}/${id}`, { method: 'DELETE' }); if (response.ok) { const key = type === '구독SW' ? 'subSw' : (type === '영구SW' ? 'permSw' : 'cloud'); const arr = state.masterData[key] as SoftwareAsset[]; const idx = arr.findIndex(a => a.id === id); if (idx > -1) arr.splice(idx, 1); // 통합 sw 배열 동기화 state.masterData.sw = [...state.masterData.subSw, ...state.masterData.permSw, ...state.masterData.cloud]; return true; } } catch (err) { console.error('SW 삭제 실패:', err); } return false; }