fix(tkfb): 대시보드 콘솔 에러 수정 (notifications, attendance, repair-requests)

- notifications/unread 호출 제거 → tkuser 링크로 대체
- attendance/today-summary → daily-status 엔드포인트로 변경
- GET /equipments/repair-requests 엔드포인트 신규 구현
- 캐시 버스팅 tkfb-dashboard.js?v=2026031701

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-17 20:19:43 +09:00
parent 0c149673fb
commit fa4199a277
5 changed files with 62 additions and 29 deletions

View File

@@ -16,30 +16,28 @@ async function loadDashboard() {
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: {} })),
api('/attendance/daily-status?date=' + today).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 repairData = results[1].status === 'fulfilled' ? results[1].value : { data: [] };
const attendData = results[2].status === 'fulfilled' ? results[2].value : { data: [] };
const tbmSessions = tbmData.data || [];
const notifications = notifData.data || [];
const repairs = repairData.data || [];
const attendance = attendData.data || {};
const attendList = Array.isArray(attendData.data) ? attendData.data : [];
const checkedInCount = attendList.filter(d => d.status !== 'incomplete').length;
// Stats
document.getElementById('statTbm').textContent = tbmSessions.length;
document.getElementById('statWorkers').textContent = attendance.checked_in_count || 0;
document.getElementById('statWorkers').textContent = checkedInCount;
document.getElementById('statRepairs').textContent = repairs.length;
document.getElementById('statNotifications').textContent = notifications.length;
document.getElementById('statNotifications').textContent = '-';
// TBM list
renderTbmList(tbmSessions);
renderNotificationList(notifications);
renderNotificationPanel();
renderRepairList(repairs);
}
@@ -64,23 +62,15 @@ function renderTbmList(sessions) {
}
}
function renderNotificationList(notifications) {
function renderNotificationPanel() {
const el = document.getElementById('notificationList');
if (!notifications.length) {
el.innerHTML = '<p class="text-gray-400 text-sm text-center py-4">새 알림이 없습니다</p>';
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 `<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100" onclick="location.href='${_tkuserBase}/?tab=notificationRecipients'">
<i class="fas ${iconClass} mt-0.5"></i>
<div class="flex-1 min-w-0">
<div class="text-sm font-medium text-gray-800 truncate">${escapeHtml(n.title)}</div>
<div class="text-xs text-gray-500 mt-0.5">${formatTimeAgo(n.created_at)}</div>
</div>
</div>`;
}).join('');
el.innerHTML = `<div class="flex flex-col items-center gap-3 py-6">
<i class="fas fa-bell text-gray-300 text-3xl"></i>
<p class="text-gray-400 text-sm">알림은 사용자관리에서 확인하세요</p>
<a href="${_tkuserBase}/?tab=notificationRecipients" class="text-sm text-orange-600 hover:text-orange-700 font-medium">
<i class="fas fa-external-link-alt mr-1"></i>알림 관리 바로가기
</a>
</div>`;
}
function renderRepairList(repairs) {