/** * TBM - API Client * TBM 관련 모든 API 호출을 관리 */ class TbmAPI { constructor() { this.state = window.TbmState; this.utils = window.TbmUtils; console.log('[TbmAPI] 초기화 완료'); } /** * 초기 데이터 로드 (작업자, 프로젝트, 안전 체크리스트, 공정, 작업, 작업장) */ async loadInitialData() { try { // 현재 로그인한 사용자 정보 가져오기 const userInfo = JSON.parse(localStorage.getItem('user') || '{}'); this.state.currentUser = userInfo; console.log('👤 로그인 사용자:', this.state.currentUser, 'worker_id:', this.state.currentUser?.worker_id); // 병렬로 데이터 로드 await Promise.all([ this.loadWorkers(), this.loadProjects(), this.loadSafetyChecks(), this.loadWorkTypes(), this.loadTasks(), this.loadWorkplaces(), this.loadWorkplaceCategories() ]); console.log('✅ 초기 데이터 로드 완료'); } catch (error) { console.error('❌ 초기 데이터 로드 오류:', error); window.showToast?.('데이터를 불러오는 중 오류가 발생했습니다.', 'error'); } } /** * 작업자 목록 로드 (생산팀 소속만) */ async loadWorkers() { try { const response = await window.apiCall('/workers?limit=1000&department_id=1'); if (response) { let workers = Array.isArray(response) ? response : (response.data || []); // 활성 상태인 작업자만 필터링 workers = workers.filter(w => w.status === 'active' && w.employment_status === 'employed'); this.state.allWorkers = workers; console.log('✅ 작업자 목록 로드:', workers.length + '명'); return workers; } } catch (error) { console.error('❌ 작업자 로딩 오류:', error); throw error; } } /** * 프로젝트 목록 로드 (활성 프로젝트만) */ async loadProjects() { try { const response = await window.apiCall('/projects?is_active=1'); if (response) { const projects = Array.isArray(response) ? response : (response.data || []); this.state.allProjects = projects.filter(p => p.is_active === 1 || p.is_active === true || p.is_active === '1' ); console.log('✅ 프로젝트 목록 로드:', this.state.allProjects.length + '개 (활성)'); return this.state.allProjects; } } catch (error) { console.error('❌ 프로젝트 로딩 오류:', error); throw error; } } /** * 안전 체크리스트 로드 */ async loadSafetyChecks() { try { const response = await window.apiCall('/tbm/safety-checks'); if (response && response.success) { this.state.allSafetyChecks = response.data; console.log('✅ 안전 체크리스트 로드:', this.state.allSafetyChecks.length + '개'); return this.state.allSafetyChecks; } } catch (error) { console.error('❌ 안전 체크리스트 로딩 오류:', error); } } /** * 공정(Work Types) 목록 로드 */ async loadWorkTypes() { try { const response = await window.apiCall('/daily-work-reports/work-types'); if (response && response.success) { this.state.allWorkTypes = response.data || []; console.log('✅ 공정 목록 로드:', this.state.allWorkTypes.length + '개'); return this.state.allWorkTypes; } } catch (error) { console.error('❌ 공정 로딩 오류:', error); } } /** * 작업(Tasks) 목록 로드 */ async loadTasks() { try { const response = await window.apiCall('/tasks/active/list'); if (response && response.success) { this.state.allTasks = response.data || []; console.log('✅ 작업 목록 로드:', this.state.allTasks.length + '개'); return this.state.allTasks; } } catch (error) { console.error('❌ 작업 로딩 오류:', error); } } /** * 작업장 목록 로드 */ async loadWorkplaces() { try { const response = await window.apiCall('/workplaces?is_active=true'); if (response && response.success) { this.state.allWorkplaces = response.data || []; console.log('✅ 작업장 목록 로드:', this.state.allWorkplaces.length + '개'); return this.state.allWorkplaces; } } catch (error) { console.error('❌ 작업장 로딩 오류:', error); } } /** * 작업장 카테고리 로드 */ async loadWorkplaceCategories() { try { const response = await window.apiCall('/workplaces/categories/active/list'); if (response && response.success) { this.state.allWorkplaceCategories = response.data || []; console.log('✅ 작업장 카테고리 로드:', this.state.allWorkplaceCategories.length + '개'); return this.state.allWorkplaceCategories; } } catch (error) { console.error('❌ 작업장 카테고리 로딩 오류:', error); } } /** * 오늘의 TBM만 로드 (TBM 입력 탭용) */ async loadTodayOnlyTbm() { const today = this.utils.getTodayKST(); try { const response = await window.apiCall(`/tbm/sessions/date/${today}`); if (response && response.success) { this.state.todaySessions = response.data || []; } else { this.state.todaySessions = []; } console.log('✅ 오늘 TBM 로드:', this.state.todaySessions.length + '건'); return this.state.todaySessions; } catch (error) { console.error('❌ 오늘 TBM 조회 오류:', error); window.showToast?.('오늘 TBM을 불러오는 중 오류가 발생했습니다.', 'error'); this.state.todaySessions = []; return []; } } /** * 최근 TBM을 날짜별로 그룹화하여 로드 */ async loadRecentTbmGroupedByDate() { try { const today = new Date(); const dates = []; // 최근 N일의 날짜 생성 for (let i = 0; i < this.state.loadedDaysCount; i++) { const date = new Date(today); date.setDate(date.getDate() - i); const dateStr = date.toISOString().split('T')[0]; dates.push(dateStr); } // 각 날짜의 TBM 로드 this.state.dateGroupedSessions = {}; this.state.allLoadedSessions = []; const promises = dates.map(date => window.apiCall(`/tbm/sessions/date/${date}`)); const results = await Promise.all(promises); results.forEach((response, index) => { const date = dates[index]; if (response && response.success && response.data && response.data.length > 0) { let sessions = response.data; // admin이 아니면 본인이 작성한 TBM만 필터링 if (!this.state.isAdminUser()) { const userId = this.state.currentUser?.user_id; const workerId = this.state.currentUser?.worker_id; sessions = sessions.filter(s => { return s.created_by === userId || s.leader_id === workerId || s.created_by_name === this.state.currentUser?.name; }); } if (sessions.length > 0) { this.state.dateGroupedSessions[date] = sessions; this.state.allLoadedSessions = this.state.allLoadedSessions.concat(sessions); } } }); console.log('✅ 날짜별 TBM 로드 완료:', this.state.allLoadedSessions.length + '건'); return this.state.dateGroupedSessions; } catch (error) { console.error('❌ TBM 날짜별 로드 오류:', error); window.showToast?.('TBM을 불러오는 중 오류가 발생했습니다.', 'error'); this.state.dateGroupedSessions = {}; return {}; } } /** * 특정 날짜의 TBM 세션 목록 로드 */ async loadTbmSessionsByDate(date) { try { const response = await window.apiCall(`/tbm/sessions/date/${date}`); if (response && response.success) { this.state.allSessions = response.data || []; } else { this.state.allSessions = []; } return this.state.allSessions; } catch (error) { console.error('❌ TBM 세션 조회 오류:', error); window.showToast?.('TBM 세션을 불러오는 중 오류가 발생했습니다.', 'error'); this.state.allSessions = []; return []; } } /** * TBM 세션 생성 */ async createTbmSession(sessionData) { try { const response = await window.apiCall('/tbm/sessions', 'POST', sessionData); if (!response || !response.success) { throw new Error(response?.message || '세션 생성 실패'); } console.log('✅ TBM 세션 생성 완료:', response.data?.session_id); return response; } catch (error) { console.error('❌ TBM 세션 생성 오류:', error); throw error; } } /** * TBM 세션 정보 조회 */ async getSession(sessionId) { try { const response = await window.apiCall(`/tbm/sessions/${sessionId}`); if (!response || !response.success) { throw new Error(response?.message || '세션 조회 실패'); } return response.data; } catch (error) { console.error('❌ TBM 세션 조회 오류:', error); throw error; } } /** * TBM 팀원 조회 */ async getTeamMembers(sessionId) { try { const response = await window.apiCall(`/tbm/sessions/${sessionId}/team`); if (!response || !response.success) { throw new Error(response?.message || '팀원 조회 실패'); } return response.data || []; } catch (error) { console.error('❌ TBM 팀원 조회 오류:', error); throw error; } } /** * TBM 팀원 일괄 추가 */ async addTeamMembers(sessionId, members) { try { const response = await window.apiCall( `/tbm/sessions/${sessionId}/team/batch`, 'POST', { members } ); if (!response || !response.success) { throw new Error(response?.message || '팀원 추가 실패'); } console.log('✅ TBM 팀원 추가 완료:', members.length + '명'); return response; } catch (error) { console.error('❌ TBM 팀원 추가 오류:', error); throw error; } } /** * TBM 팀원 전체 삭제 */ async clearTeamMembers(sessionId) { try { const response = await window.apiCall(`/tbm/sessions/${sessionId}/team/clear`, 'DELETE'); return response; } catch (error) { console.error('❌ TBM 팀원 삭제 오류:', error); throw error; } } /** * TBM 안전 체크 조회 */ async getSafetyChecks(sessionId) { try { const response = await window.apiCall(`/tbm/sessions/${sessionId}/safety`); return response?.data || []; } catch (error) { console.error('❌ 안전 체크 조회 오류:', error); return []; } } /** * TBM 안전 체크 (필터링된) 조회 */ async getFilteredSafetyChecks(sessionId) { try { const response = await window.apiCall(`/tbm/sessions/${sessionId}/safety-checks/filtered`); if (!response || !response.success) { throw new Error(response?.message || '체크리스트를 불러올 수 없습니다.'); } return response.data; } catch (error) { console.error('❌ 필터링된 안전 체크 조회 오류:', error); throw error; } } /** * TBM 안전 체크 저장 */ async saveSafetyChecks(sessionId, records) { try { const response = await window.apiCall( `/tbm/sessions/${sessionId}/safety`, 'POST', { records } ); if (!response || !response.success) { throw new Error(response?.message || '저장 실패'); } return response; } catch (error) { console.error('❌ 안전 체크 저장 오류:', error); throw error; } } /** * TBM 세션 완료 처리 */ async completeTbmSession(sessionId, endTime) { try { const response = await window.apiCall( `/tbm/sessions/${sessionId}/complete`, 'POST', { end_time: endTime } ); if (!response || !response.success) { throw new Error(response?.message || '완료 처리 실패'); } console.log('✅ TBM 완료 처리:', sessionId); return response; } catch (error) { console.error('❌ TBM 완료 처리 오류:', error); throw error; } } /** * 작업 인계 저장 */ async saveHandover(handoverData) { try { const response = await window.apiCall('/tbm/handovers', 'POST', handoverData); if (!response || !response.success) { throw new Error(response?.message || '인계 요청 실패'); } return response; } catch (error) { console.error('❌ 작업 인계 저장 오류:', error); throw error; } } /** * 카테고리별 작업장 로드 */ async loadWorkplacesByCategory(categoryId) { try { const response = await window.apiCall(`/workplaces?category_id=${categoryId}`); if (!response || !response.success || !response.data) { return []; } return response.data; } catch (error) { console.error('❌ 작업장 로드 오류:', error); return []; } } /** * 작업장 지도 영역 로드 */ async loadMapRegions(categoryId) { try { const response = await window.apiCall(`/workplaces/categories/${categoryId}/map-regions`); if (response && response.success) { this.state.mapRegions = response.data || []; return this.state.mapRegions; } return []; } catch (error) { console.error('❌ 지도 영역 로드 오류:', error); return []; } } } // 전역 인스턴스 생성 window.TbmAPI = new TbmAPI(); // 하위 호환성: 기존 함수들 window.loadInitialData = () => window.TbmAPI.loadInitialData(); window.loadTodayOnlyTbm = () => window.TbmAPI.loadTodayOnlyTbm(); window.loadTodayTbm = () => window.TbmAPI.loadRecentTbmGroupedByDate(); window.loadAllTbm = () => { window.TbmState.loadedDaysCount = 30; return window.TbmAPI.loadRecentTbmGroupedByDate(); }; window.loadRecentTbmGroupedByDate = () => window.TbmAPI.loadRecentTbmGroupedByDate(); window.loadTbmSessionsByDate = (date) => window.TbmAPI.loadTbmSessionsByDate(date); window.loadWorkplaceCategories = () => window.TbmAPI.loadWorkplaceCategories(); window.loadWorkplacesByCategory = (categoryId) => window.TbmAPI.loadWorkplacesByCategory(categoryId); // 더 많은 날짜 로드 window.loadMoreTbmDays = async function() { window.TbmState.loadedDaysCount += 7; await window.TbmAPI.loadRecentTbmGroupedByDate(); window.showToast?.(`최근 ${window.TbmState.loadedDaysCount}일의 TBM을 로드했습니다.`, 'success'); }; console.log('[Module] tbm/api.js 로드 완료');