/** * TBM - Utilities * TBM 관련 유틸리티 함수들 */ class TbmUtils { constructor() { console.log('[TbmUtils] 초기화 완료'); } /** * 서울 시간대(Asia/Seoul, UTC+9) 기준 오늘 날짜를 YYYY-MM-DD 형식으로 반환 */ getTodayKST() { const now = new Date(); const kstOffset = 9 * 60; const utc = now.getTime() + (now.getTimezoneOffset() * 60000); const kstTime = new Date(utc + (kstOffset * 60000)); const year = kstTime.getFullYear(); const month = String(kstTime.getMonth() + 1).padStart(2, '0'); const day = String(kstTime.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } /** * ISO 날짜 문자열을 YYYY-MM-DD 형식으로 변환 */ formatDate(dateString) { if (!dateString) return ''; if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) { return dateString; } const date = new Date(dateString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } /** * 날짜 표시용 포맷 (MM월 DD일) */ formatDateDisplay(dateString) { if (!dateString) return ''; const [year, month, day] = dateString.split('-'); return `${parseInt(month)}월 ${parseInt(day)}일`; } /** * 날짜를 연/월/일/요일 형식으로 포맷 */ formatDateFull(dateString) { if (!dateString) return ''; const dayNames = ['일', '월', '화', '수', '목', '금', '토']; const [year, month, day] = dateString.split('-'); const dateObj = new Date(dateString); const dayName = dayNames[dateObj.getDay()]; return `${year}년 ${parseInt(month)}월 ${parseInt(day)}일 (${dayName})`; } /** * 요일 반환 */ getDayOfWeek(dateString) { const dayNames = ['일', '월', '화', '수', '목', '금', '토']; const dateObj = new Date(dateString + 'T00:00:00'); return dayNames[dateObj.getDay()]; } /** * 오늘인지 확인 */ isToday(dateString) { const today = this.getTodayKST(); return this.formatDate(dateString) === today; } /** * 현재 시간을 HH:MM 형식으로 반환 */ getCurrentTime() { return new Date().toTimeString().slice(0, 5); } /** * UUID 생성 */ generateUUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } /** * HTML 이스케이프 */ escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } /** * 날씨 조건명 반환 */ getWeatherConditionName(code) { const names = { clear: '맑음', rain: '비', snow: '눈', heat: '폭염', cold: '한파', wind: '강풍', fog: '안개', dust: '미세먼지' }; return names[code] || code; } /** * 날씨 아이콘 반환 */ getWeatherIcon(code) { const icons = { clear: '☀️', rain: '🌧️', snow: '❄️', heat: '🔥', cold: '🥶', wind: '💨', fog: '🌫️', dust: '😷' }; return icons[code] || '🌤️'; } /** * 카테고리명 반환 */ getCategoryName(category) { const names = { 'PPE': '개인 보호 장비', 'EQUIPMENT': '장비 점검', 'ENVIRONMENT': '작업 환경', 'EMERGENCY': '비상 대응', 'WEATHER': '날씨', 'TASK': '작업' }; return names[category] || category; } /** * 상태 배지 HTML 반환 */ getStatusBadge(status) { const badges = { 'draft': '진행중', 'completed': '완료', 'cancelled': '취소' }; return badges[status] || ''; } } // 전역 인스턴스 생성 window.TbmUtils = new TbmUtils(); // 하위 호환성: 기존 함수들 window.getTodayKST = () => window.TbmUtils.getTodayKST(); window.formatDate = (dateString) => window.TbmUtils.formatDate(dateString); // 토스트 알림 window.showToast = function(message, type = 'info', duration = 3000) { const container = document.getElementById('toastContainer'); if (!container) { console.log(`[Toast] ${type}: ${message}`); return; } const toast = document.createElement('div'); toast.className = `toast ${type}`; const iconMap = { success: '✅', error: '❌', warning: '⚠️', info: 'ℹ️' }; toast.innerHTML = `
${iconMap[type] || 'ℹ️'}
${message}
`; toast.style.cssText = ` display: flex; align-items: center; gap: 0.75rem; padding: 1rem 1.25rem; background: white; border-radius: 0.5rem; box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1); margin-bottom: 0.75rem; min-width: 300px; animation: slideIn 0.3s ease-out; `; container.appendChild(toast); setTimeout(() => { if (toast.parentElement) { toast.style.animation = 'slideOut 0.3s ease-out'; setTimeout(() => toast.remove(), 300); } }, duration); }; // 카테고리별 그룹화 window.groupChecksByCategory = function(checks) { return checks.reduce((acc, check) => { const category = check.check_category || 'OTHER'; if (!acc[category]) acc[category] = []; acc[category].push(check); return acc; }, {}); }; // 작업별 그룹화 window.groupChecksByTask = function(checks) { return checks.reduce((acc, check) => { const taskId = check.task_id || 0; const taskName = check.task_name || '기타 작업'; if (!acc[taskId]) acc[taskId] = { name: taskName, items: [] }; acc[taskId].items.push(check); return acc; }, {}); }; // Admin 사용자 확인 window.isAdminUser = function() { return window.TbmState?.isAdminUser() || false; }; console.log('[Module] tbm/utils.js 로드 완료');