/* ===== Dashboard (대시보드) ===== */ const today = new Date().toISOString().substring(0, 10); function updateDateTime() { const now = new Date(); const days = ['일', '월', '화', '수', '목', '금', '토']; const h = String(now.getHours()).padStart(2, '0'); const m = String(now.getMinutes()).padStart(2, '0'); const el = document.getElementById('dateTimeDisplay'); if (el) el.textContent = `${now.getFullYear()}년 ${now.getMonth()+1}월 ${now.getDate()}일 (${days[now.getDay()]}) ${h}:${m}`; } async function loadDashboard() { updateDateTime(); const results = await Promise.allSettled([ api('/tbm/sessions/date/' + today).catch(() => ({ data: [] })), api('/notifications/unread').catch(() => ({ data: [] })), api('/equipments/repair-requests?status=pending').catch(() => ({ data: [] })), api('/attendance/today-summary').catch(() => ({ data: {} })), ]); const tbmData = results[0].status === 'fulfilled' ? results[0].value : { data: [] }; const notifData = results[1].status === 'fulfilled' ? results[1].value : { data: [] }; const repairData = results[2].status === 'fulfilled' ? results[2].value : { data: [] }; const attendData = results[3].status === 'fulfilled' ? results[3].value : { data: {} }; const tbmSessions = tbmData.data || []; const notifications = notifData.data || []; const repairs = repairData.data || []; const attendance = attendData.data || {}; // Stats document.getElementById('statTbm').textContent = tbmSessions.length; document.getElementById('statWorkers').textContent = attendance.checked_in_count || 0; document.getElementById('statRepairs').textContent = repairs.length; document.getElementById('statNotifications').textContent = notifications.length; // TBM list renderTbmList(tbmSessions); renderNotificationList(notifications); renderRepairList(repairs); } function renderTbmList(sessions) { const el = document.getElementById('tbmList'); if (!sessions.length) { el.innerHTML = '

금일 TBM이 없습니다

'; return; } el.innerHTML = sessions.slice(0, 5).map(s => { const workers = s.team_member_count || 0; return `
${escapeHtml(s.workplace_name || s.session_title || 'TBM')}
${escapeHtml(s.leader_name || '-')} · ${workers}명
${s.status === 'completed' ? '완료' : '진행중'}
`; }).join(''); if (sessions.length > 5) { el.innerHTML += `전체 보기 (${sessions.length}건)`; } } function renderNotificationList(notifications) { const el = document.getElementById('notificationList'); if (!notifications.length) { el.innerHTML = '

새 알림이 없습니다

'; return; } const icons = { repair: 'fa-wrench text-amber-500', safety: 'fa-shield-alt text-red-500', system: 'fa-bell text-blue-500', equipment: 'fa-cog text-gray-500', maintenance: 'fa-tools text-green-500' }; el.innerHTML = notifications.slice(0, 5).map(n => { const iconClass = icons[n.type] || 'fa-bell text-gray-400'; return `
${escapeHtml(n.title)}
${formatTimeAgo(n.created_at)}
`; }).join(''); } function renderRepairList(repairs) { const el = document.getElementById('repairList'); if (!repairs.length) { el.innerHTML = '

대기 중인 수리 요청이 없습니다

'; return; } el.innerHTML = repairs.slice(0, 5).map(r => { return `
${escapeHtml(r.equipment_name || r.title || '수리 요청')}
${formatDate(r.created_at)}
대기
`; }).join(''); if (repairs.length > 5) { el.innerHTML += `전체 보기 (${repairs.length}건)`; } } function formatTimeAgo(dateStr) { if (!dateStr) return ''; const d = new Date(dateStr); const now = new Date(); const diff = now - d; const mins = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); if (mins < 1) return '방금 전'; if (mins < 60) return `${mins}분 전`; if (hours < 24) return `${hours}시간 전`; if (days < 7) return `${days}일 전`; return formatDate(dateStr); } /* ===== Init ===== */ (async function() { if (!await initAuth()) return; updateDateTime(); setInterval(updateDateTime, 60000); loadDashboard(); })();