/** * 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('sso_user') || '{}'); this.state.currentUser = userInfo; // 병렬로 데이터 로드 await Promise.all([ this.loadWorkers(), this.loadProjects(), this.loadSafetyChecks(), this.loadWorkTypes(), this.loadTasks(), this.loadWorkplaces(), this.loadWorkplaceCategories() ]); } 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; 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' ); 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; 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 || []; 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 || []; 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 || []; 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 || []; 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 = []; } 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) { const sessions = response.data; if (sessions.length > 0) { this.state.dateGroupedSessions[date] = sessions; this.state.allLoadedSessions = this.state.allLoadedSessions.concat(sessions); } } }); 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 || '세션 생성 실패'); } 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) { const err = new Error(response?.message || '팀원 추가 실패'); if (response && response.duplicates) err.duplicates = response.duplicates; throw err; } 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 || '완료 처리 실패'); } 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 []; } } /** * TBM 세션 삭제 */ async deleteSession(sessionId) { try { const response = await window.apiCall(`/tbm/sessions/${sessionId}`, 'DELETE'); if (!response || !response.success) { throw new Error(response?.message || '삭제 실패'); } return response; } catch (error) { console.error(' TBM 세션 삭제 오류:', error); throw error; } } /** * TBM 팀원 분할 배정 */ async splitAssignment(sessionId, splitData) { try { const response = await window.apiCall( `/tbm/sessions/${sessionId}/team/split`, 'POST', splitData ); if (!response || !response.success) { throw new Error(response?.message || '분할 실패'); } return response; } catch (error) { console.error(' 분할 배정 오류:', error); throw error; } } /** * TBM 팀원 단일 추가/수정 (POST /team) */ async updateTeamMember(sessionId, memberData) { try { const response = await window.apiCall( `/tbm/sessions/${sessionId}/team`, 'POST', memberData ); if (!response || !response.success) { throw new Error(response?.message || '팀원 수정 실패'); } return response; } catch (error) { console.error(' 팀원 수정 오류:', error); throw error; } } /** * TBM 인원 이동 (분할→이동 / 빼오기) */ async transfer(transferData) { try { const response = await window.apiCall('/tbm/transfers', 'POST', transferData); if (!response || !response.success) { throw new Error(response?.message || '이동 실패'); } return response; } catch (error) { console.error(' TBM 이동 오류:', error); throw error; } } /** * 작업 생성 */ async createTask(taskData) { try { const response = await window.apiCall('/tasks', 'POST', taskData); if (!response || !response.success) { throw new Error(response?.message || '작업 생성 실패'); } return response; } catch (error) { console.error(' 작업 생성 오류:', error); throw error; } } /** * 활성 작업장 전체 목록 (active/list) */ async loadActiveWorkplacesList() { try { const response = await window.apiCall('/workplaces/active/list'); if (response && response.success) { return response.data || []; } return []; } catch (error) { console.error(' 활성 작업장 목록 오류:', error); return []; } } /** * 당일 배정 현황 조회 */ async loadTodayAssignments(date) { try { const response = await window.apiCall(`/tbm/sessions/date/${date}/assignments`); if (response && response.success) { return response.data || []; } return []; } catch (error) { console.error(' 배정 현황 조회 오류:', error); return []; } } /** * 특정 날짜의 TBM 세션 조회 (raw - 상태 변경 없음) */ async fetchSessionsByDate(date) { try { const response = await window.apiCall(`/tbm/sessions/date/${date}`); if (response && response.success) { return response.data || []; } return []; } catch (error) { console.error(' TBM 세션 조회 오류:', error); return []; } } /** * TBM 세션 완료 처리 (근태 정보 포함) */ async completeTbmWithAttendance(sessionId, attendanceData) { try { const response = await window.apiCall( `/tbm/sessions/${sessionId}/complete`, 'POST', { attendance: attendanceData } ); if (!response || !response.success) { throw new Error(response?.message || '완료 처리 실패'); } return response; } catch (error) { console.error(' TBM 완료 처리 오류:', error); throw error; } } } // 전역 인스턴스 생성 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'); }; window.deleteTbmSession = (sessionId) => window.TbmAPI.deleteSession(sessionId); window.fetchSessionsByDate = (date) => window.TbmAPI.fetchSessionsByDate(date); console.log('[Module] tbm/api.js 로드 완료');