import { state } from '../../core/state'; import { HardwareAsset } from '../../core/excelHandler'; import { openHwModal } from '../../components/Modal/HWModal'; import { calculateAssetAge, normalizeDate } from '../../core/utils'; declare var Chart: any; export function renderHwDashboard(container: HTMLElement) { const allHw = state.masterData.hw || []; // 1. 데이터 가공 let totalAge = 0; let countWithDate = 0; let over5YearsCount = 0; let latestAsset: HardwareAsset | null = null; let latestYear = 0; const ageGroups = { stable: 0, warning: 0, critical: 0 }; const yearlyCount: Record = {}; allHw.forEach(a => { const pDate = a.구매일 || (a as any).purchase_date; if (!pDate) return; const age = calculateAssetAge(pDate); totalAge += age; countWithDate++; // 노후도 분류 if (age >= 5) { over5YearsCount++; ageGroups.critical++; } else if (age >= 3) { ageGroups.warning++; } else { ageGroups.stable++; } // 연도별 도입 현황 추출 const year = normalizeDate(pDate).split('-')[0]; if (year && year.length === 4) { yearlyCount[year] = (yearlyCount[year] || 0) + 1; const yNum = parseInt(year); if (yNum > latestYear) { latestYear = yNum; latestAsset = a; } } }); const avgAge = countWithDate > 0 ? (totalAge / countWithDate).toFixed(1) : '0'; const over5Rate = allHw.length > 0 ? Math.round((over5YearsCount / allHw.length) * 100) : 0; // 교체 시급 대상 TOP 10 (오래된 순) const criticalList = [...allHw] .filter(a => (a.구매일 || (a as any).purchase_date)) .sort((a, b) => { const dateA = new Date(normalizeDate(a.구매일 || (a as any).purchase_date)).getTime(); const dateB = new Date(normalizeDate(b.구매일 || (b as any).purchase_date)).getTime(); return dateA - dateB; }) .slice(0, 10); // 2. UI 렌더링 container.innerHTML = `
전체 평균 사용 연수
${avgAge}
5년 이상 노후 자산 비율
${over5Rate}%
최신 도입 모델 (${latestYear}년)
${(latestAsset as any)?.모델명 || '정보 없음'}

자산 노후도 분포

연도별 자산 도입 추이

⚠️ 교체 검토 대상 (가장 오래된 자산 TOP 10)

${criticalList.map((a, i) => ` `).join('')}
순위 자산번호 유형 모델명 사용자/담당자 구매연월 연령
${i + 1} ${a.자산코드 || '-'} ${a.type} ${a.모델명 || a.명칭 || '-'} ${a.사용자 || a.담당자_정 || '-'} ${a.구매일 || (a as any).purchase_date || '-'} ${calculateAssetAge(a.구매일 || (a as any).purchase_date)}년
`; // 3. 차트 초기화 setTimeout(() => { initAgingCharts(ageGroups, yearlyCount); // 행 클릭 이벤트 바인딩 container.querySelectorAll('.clickable-row').forEach(row => { row.addEventListener('click', () => { const id = row.getAttribute('data-id'); const asset = allHw.find(h => h.id === id); if (asset) openHwModal(asset, 'view'); }); }); }, 100); } function initAgingCharts(ageGroups: any, yearlyCount: Record) { const agingCtx = document.getElementById('chart-aging-dist') as HTMLCanvasElement; if (agingCtx) { new Chart(agingCtx, { type: 'doughnut', data: { labels: ['안정 (3년 미만)', '주의 (3~5년)', '위험 (5년 이상)'], datasets: [{ data: [ageGroups.stable, ageGroups.warning, ageGroups.critical], backgroundColor: ['#1E5149', '#9CA3AF', '#E11D48'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'right' } }, cutout: '70%' } }); } const trendCtx = document.getElementById('chart-purchase-trend') as HTMLCanvasElement; if (trendCtx) { const years = Object.keys(yearlyCount).sort(); new Chart(trendCtx, { type: 'bar', data: { labels: years, datasets: [{ label: '도입 수량', data: years.map(y => yearlyCount[y]), backgroundColor: '#1E5149', borderRadius: 4 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } }, x: { grid: { display: false } } } } }); } }