/** * Daily Work Report - Module Loader * 작업보고서 모듈을 초기화하고 연결하는 메인 진입점 * * 로드 순서: * 1. state.js - 전역 상태 관리 * 2. utils.js - 유틸리티 함수 * 3. api.js - API 클라이언트 * 4. index.js - 이 파일 (메인 컨트롤러) */ class DailyWorkReportController { constructor() { this.state = window.DailyWorkReportState; this.api = window.DailyWorkReportAPI; this.utils = window.DailyWorkReportUtils; this.initialized = false; console.log('[Controller] DailyWorkReportController 생성'); } /** * 초기화 */ async init() { if (this.initialized) { console.log('[Controller] 이미 초기화됨'); return; } console.log('[Controller] 초기화 시작...'); try { // 이벤트 리스너 설정 this.setupEventListeners(); // 기본 데이터 로드 await this.api.loadAllData(); // TBM 탭이 기본 await this.switchTab('tbm'); this.initialized = true; console.log('[Controller] 초기화 완료'); } catch (error) { console.error('[Controller] 초기화 실패:', error); window.showMessage?.('초기화 중 오류가 발생했습니다: ' + error.message, 'error'); } } /** * 이벤트 리스너 설정 */ setupEventListeners() { // 탭 버튼 const tbmBtn = document.getElementById('tbmReportTab'); const completedBtn = document.getElementById('completedReportTab'); if (tbmBtn) { tbmBtn.addEventListener('click', () => this.switchTab('tbm')); } if (completedBtn) { completedBtn.addEventListener('click', () => this.switchTab('completed')); } // 완료 보고서 날짜 변경 const completedDateInput = document.getElementById('completedReportDate'); if (completedDateInput) { completedDateInput.addEventListener('change', () => this.loadCompletedReports()); } console.log('[Controller] 이벤트 리스너 설정 완료'); } /** * 탭 전환 */ async switchTab(tab) { this.state.setCurrentTab(tab); const tbmBtn = document.getElementById('tbmReportTab'); const completedBtn = document.getElementById('completedReportTab'); const tbmSection = document.getElementById('tbmReportSection'); const completedSection = document.getElementById('completedReportSection'); // 모든 탭 버튼 비활성화 tbmBtn?.classList.remove('active'); completedBtn?.classList.remove('active'); // 모든 섹션 숨기기 if (tbmSection) tbmSection.style.display = 'none'; if (completedSection) completedSection.style.display = 'none'; // 선택된 탭 활성화 if (tab === 'tbm') { tbmBtn?.classList.add('active'); if (tbmSection) tbmSection.style.display = 'block'; await this.loadTbmData(); } else if (tab === 'completed') { completedBtn?.classList.add('active'); if (completedSection) completedSection.style.display = 'block'; // 오늘 날짜로 초기화 const dateInput = document.getElementById('completedReportDate'); if (dateInput) { dateInput.value = this.utils.getKoreaToday(); } await this.loadCompletedReports(); } } /** * TBM 데이터 로드 */ async loadTbmData() { try { await this.api.loadIncompleteTbms(); await this.api.loadDailyIssuesForTbms(); // 렌더링은 기존 함수 사용 (점진적 마이그레이션) if (typeof window.renderTbmWorkList === 'function') { window.renderTbmWorkList(); } } catch (error) { console.error('[Controller] TBM 데이터 로드 오류:', error); window.showMessage?.('TBM 데이터를 불러오는 중 오류가 발생했습니다.', 'error'); } } /** * 완료 보고서 로드 */ async loadCompletedReports() { try { const dateInput = document.getElementById('completedReportDate'); const date = dateInput?.value || this.utils.getKoreaToday(); const reports = await this.api.loadCompletedReports(date); // 렌더링은 기존 함수 사용 if (typeof window.renderCompletedReports === 'function') { window.renderCompletedReports(reports); } } catch (error) { console.error('[Controller] 완료 보고서 로드 오류:', error); window.showMessage?.('완료 보고서를 불러오는 중 오류가 발생했습니다.', 'error'); } } /** * TBM 작업보고서 제출 */ async submitTbmWorkReport(index) { try { const tbm = this.state.incompleteTbms[index]; if (!tbm) { throw new Error('TBM 데이터를 찾을 수 없습니다.'); } // 유효성 검사 const totalHoursInput = document.getElementById(`totalHours_${index}`); const totalHours = parseFloat(totalHoursInput?.value); if (!totalHours || totalHours <= 0) { window.showMessage?.('작업시간을 입력해주세요.', 'warning'); return; } // 부적합 시간 계산 const defects = this.state.tempDefects[index] || []; const errorHours = defects.reduce((sum, d) => sum + (parseFloat(d.defect_hours) || 0), 0); const regularHours = totalHours - errorHours; if (regularHours < 0) { window.showMessage?.('부적합 시간이 총 작업시간을 초과할 수 없습니다.', 'warning'); return; } // API 데이터 구성 const user = this.state.getCurrentUser(); const reportData = { tbm_session_id: tbm.session_id, tbm_assignment_id: tbm.assignment_id, user_id: tbm.user_id, project_id: tbm.project_id, work_type_id: tbm.work_type_id, report_date: this.utils.formatDateForApi(tbm.session_date), total_hours: totalHours, regular_hours: regularHours, error_hours: errorHours, work_status_id: errorHours > 0 ? 2 : 1, created_by: user?.user_id || user?.id, defects: defects.map(d => ({ category_id: d.category_id, item_id: d.item_id, issue_report_id: d.issue_report_id, defect_hours: d.defect_hours, note: d.note })) }; const result = await this.api.submitTbmWorkReport(reportData); window.showSaveResultModal?.( 'success', '제출 완료', `${tbm.worker_name}의 작업보고서가 제출되었습니다.` ); // 목록 새로고침 await this.loadTbmData(); } catch (error) { console.error('[Controller] 제출 오류:', error); window.showSaveResultModal?.( 'error', '제출 실패', error.message || '작업보고서 제출 중 오류가 발생했습니다.' ); } } /** * 세션 일괄 제출 */ async batchSubmitSession(sessionKey) { const rows = document.querySelectorAll(`tr[data-session-key="${sessionKey}"][data-type="tbm"]`); const indices = []; rows.forEach(row => { const index = parseInt(row.dataset.index); const totalHoursInput = document.getElementById(`totalHours_${index}`); if (totalHoursInput?.value && parseFloat(totalHoursInput.value) > 0) { indices.push(index); } }); if (indices.length === 0) { window.showMessage?.('제출할 항목이 없습니다. 작업시간을 입력해주세요.', 'warning'); return; } const confirmed = confirm(`${indices.length}건의 작업보고서를 일괄 제출하시겠습니까?`); if (!confirmed) return; let successCount = 0; let failCount = 0; for (const index of indices) { try { await this.submitTbmWorkReport(index); successCount++; } catch (error) { failCount++; console.error(`[Controller] 일괄 제출 오류 (index: ${index}):`, error); } } if (failCount === 0) { window.showSaveResultModal?.('success', '일괄 제출 완료', `${successCount}건이 성공적으로 제출되었습니다.`); } else { window.showSaveResultModal?.('warning', '일괄 제출 부분 완료', `성공: ${successCount}건, 실패: ${failCount}건`); } } /** * 상태 디버그 */ debug() { console.log('[Controller] 상태 디버그:'); this.state.debug(); } } // 전역 인스턴스 생성 window.DailyWorkReportController = new DailyWorkReportController(); // 하위 호환성: 기존 전역 함수들 window.switchTab = (tab) => window.DailyWorkReportController.switchTab(tab); window.submitTbmWorkReport = (index) => window.DailyWorkReportController.submitTbmWorkReport(index); window.batchSubmitTbmSession = (sessionKey) => window.DailyWorkReportController.batchSubmitSession(sessionKey); // 사용자 정보 함수 window.getUser = () => window.DailyWorkReportState.getUser(); window.getCurrentUser = () => window.DailyWorkReportState.getCurrentUser(); // 날짜 그룹 토글 (UI 함수) window.toggleDateGroup = function(dateStr) { const group = document.querySelector(`.date-group[data-date="${dateStr}"]`); if (!group) return; const isExpanded = group.classList.contains('expanded'); const content = group.querySelector('.date-group-content'); const icon = group.querySelector('.date-toggle-icon'); if (isExpanded) { group.classList.remove('expanded'); group.classList.add('collapsed'); if (content) content.style.display = 'none'; if (icon) icon.textContent = '▶'; } else { group.classList.remove('collapsed'); group.classList.add('expanded'); if (content) content.style.display = 'block'; if (icon) icon.textContent = '▼'; } }; // DOMContentLoaded 이벤트에서 초기화 document.addEventListener('DOMContentLoaded', () => { // 약간의 지연 후 초기화 (다른 스크립트 로드 대기) setTimeout(() => { window.DailyWorkReportController.init(); }, 100); }); console.log('[Module] daily-work-report/index.js 로드 완료');