import { renderCalendar } from '/js/calendar.js'; import { API, getAuthHeaders, ensureAuthenticated } from '/js/api-config.js'; // 인증 확인 ensureAuthenticated(); const calendarEl = document.getElementById('calendar'); const reportBody = document.getElementById('reportBody'); let selectedDate = ''; // 캘린더 렌더링 renderCalendar('calendar', (dateStr) => { selectedDate = dateStr; loadReports(); }); // 보고서 로딩 async function loadReports() { if (!selectedDate) return; reportBody.innerHTML = '불러오는 중...'; try { const [wRes, pRes, rRes] = await Promise.all([ fetch(`${API}/workers`, { headers: getAuthHeaders() }), fetch(`${API}/projects/active/list`, { headers: getAuthHeaders() }), fetch(`${API}/workreports?start=${selectedDate}&end=${selectedDate}`, { headers: getAuthHeaders() }) ]); if (![wRes, pRes, rRes].every(res => res.ok)) throw new Error('불러오기 실패'); const [allWorkers, projects, reports] = await Promise.all([ wRes.json(), pRes.json(), rRes.json() ]); // 활성화된 작업자만 필터링 const workers = allWorkers.filter(worker => { return worker.status === 'active' || worker.is_active === 1 || worker.is_active === true; }); // 배열 체크 if (!Array.isArray(workers) || !Array.isArray(projects) || !Array.isArray(reports)) { throw new Error('잘못된 데이터 형식'); } if (!reports.length) { reportBody.innerHTML = '등록된 보고서가 없습니다.'; return; } const nameMap = Object.fromEntries(workers.map(w => [w.worker_id, w.worker_name])); const projMap = Object.fromEntries(projects.map(p => [p.project_id, p.project_name])); // const taskMap = Object.fromEntries(tasks.map(t => [t.task_id, `${t.category}:${t.subcategory}`])); // tasks 테이블 삭제됨 reportBody.innerHTML = ''; reports.forEach((r, i) => { const tr = document.createElement('tr'); tr.innerHTML = ` ${i + 1} ${nameMap[r.worker_id] || r.worker_id} `; // 저장 버튼 tr.querySelector('.save-btn').onclick = async () => { // 입력값 검증 const projectId = tr.querySelector('[data-id="project"]').value; const taskId = tr.querySelector('[data-id="task"]').value; const overtimeHours = tr.querySelector('[data-id="overtime"]').value; if (!projectId || !taskId) { alert('❌ 프로젝트와 작업을 선택해주세요.'); return; } // 날짜 형식 처리 - MySQL DATE 형식으로 변환 const formatDate = (dateStr) => { if (!dateStr) return selectedDate; // 이미 YYYY-MM-DD 형식인지 확인 if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) { return dateStr; } // ISO 형식이나 다른 형식을 YYYY-MM-DD로 변환 const date = new Date(dateStr); if (isNaN(date.getTime())) { return selectedDate; // 잘못된 날짜면 선택된 날짜 사용 } return date.toISOString().split('T')[0]; // YYYY-MM-DD 형식으로 변환 }; const payload = { date: formatDate(r.date), // 날짜 형식 변환 worker_id: r.worker_id, // 기존 작업자 ID 유지 project_id: Number(projectId), task_id: Number(taskId), overtime_hours: overtimeHours ? Number(overtimeHours) : null, work_details: tr.querySelector('[data-id="work_details"]').value, memo: tr.querySelector('[data-id="memo"]').value.trim() || null }; // 저장 버튼 상태 변경 (로딩 중) const saveBtn = tr.querySelector('.save-btn'); const originalText = saveBtn.textContent; const originalColor = saveBtn.style.backgroundColor; saveBtn.textContent = '저장 중...'; saveBtn.style.backgroundColor = '#ffc107'; saveBtn.disabled = true; try { const res = await fetch(`${API}/workreports/${r.id}`, { method: 'PUT', headers: { ...getAuthHeaders(), 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await res.json(); if (res.ok && result.success) { // 성공 상태 표시 saveBtn.textContent = '✅ 완료'; saveBtn.style.backgroundColor = '#28a745'; saveBtn.style.color = 'white'; setTimeout(() => { saveBtn.textContent = originalText; saveBtn.style.backgroundColor = originalColor; saveBtn.style.color = ''; saveBtn.disabled = false; }, 2000); // alert 대신 조용한 알림 console.log('저장 완료:', result); } else { console.error('저장 실패:', result); alert(`❌ 저장 실패: ${result.error || result.message || '알 수 없는 오류'}`); // 실패 시 버튼 복원 saveBtn.textContent = originalText; saveBtn.style.backgroundColor = originalColor; saveBtn.disabled = false; } } catch (err) { console.error('저장 요청 에러:', err); alert('❌ 저장 요청 실패: ' + err.message); // 에러 시 버튼 복원 saveBtn.textContent = originalText; saveBtn.style.backgroundColor = originalColor; saveBtn.disabled = false; } }; // 삭제 버튼 tr.querySelector('.delete-btn').onclick = async () => { if (!confirm('정말 삭제하시겠습니까?')) return; try { const res = await fetch(`${API}/workreports/${r.id}`, { method: 'DELETE', headers: getAuthHeaders() }); if (res.ok) { tr.remove(); // 행 번호 다시 매기기 updateRowNumbers(); alert('✅ 삭제 완료'); } else { const result = await res.json(); alert(`❌ 삭제 실패: ${result.error || result.message || '알 수 없는 오류'}`); } } catch (err) { console.error('삭제 요청 에러:', err); alert('❌ 삭제 요청 실패: ' + err.message); } }; reportBody.appendChild(tr); }); } catch (err) { console.error('데이터 로딩 에러:', err); reportBody.innerHTML = '❌ 불러오기 실패: ' + err.message + ''; } } // 행 번호 다시 매기기 function updateRowNumbers() { reportBody.querySelectorAll('tr').forEach((tr, i) => { const firstTd = tr.querySelector('td:first-child'); if (firstTd) firstTd.textContent = i + 1; }); }