/** * issues-management.js — 관리함 페이지 스크립트 */ let currentUser = null; let issues = []; let projects = []; let filteredIssues = []; let currentIssueId = null; let currentTab = 'in_progress'; // 기본값: 진행 중 // 완료 반려 패턴 제거 (해결방안 표시용) function cleanManagementComment(text) { if (!text) return ''; // 기존 데이터에서 완료 반려 패턴 제거 return text.replace(/\[완료 반려[^\]]*\][^\n]*\n*/g, '').trim(); } // API 로드 후 초기화 함수 async function initializeManagement() { const token = TokenManager.getToken(); if (!token) { window.location.href = '/index.html'; return; } try { const user = await AuthAPI.getCurrentUser(); currentUser = user; localStorage.setItem('currentUser', JSON.stringify(user)); // 공통 헤더 초기화 await window.commonHeader.init(user, 'issues_management'); // 페이지 접근 권한 체크 setTimeout(() => { if (!canAccessPage('issues_management')) { alert('관리함 페이지에 접근할 권한이 없습니다.'); window.location.href = '/index.html'; return; } }, 500); // 데이터 로드 await loadProjects(); await loadIssues(); } catch (error) { console.error('인증 실패:', error); TokenManager.removeToken(); TokenManager.removeUser(); window.location.href = '/index.html'; } } // 프로젝트 로드 async function loadProjects() { try { const apiUrl = window.API_BASE_URL || '/api'; const response = await fetch(`${apiUrl}/projects/`, { headers: { 'Authorization': `Bearer ${TokenManager.getToken()}`, 'Content-Type': 'application/json' } }); if (response.ok) { projects = await response.json(); updateProjectFilter(); } } catch (error) { console.error('프로젝트 로드 실패:', error); } } // 부적합 목록 로드 (관리자는 모든 부적합 조회) async function loadIssues() { try { let endpoint = '/api/issues/admin/all'; const response = await fetch(endpoint, { headers: { 'Authorization': `Bearer ${TokenManager.getToken()}`, 'Content-Type': 'application/json' } }); if (response.ok) { const allIssues = await response.json(); // 관리함에서는 진행 중(in_progress)과 완료됨(completed) 상태만 표시 let filteredIssues = allIssues.filter(issue => issue.review_status === 'in_progress' || issue.review_status === 'completed' ); // 수신함에서 넘어온 순서대로 No. 재할당 (reviewed_at 기준) filteredIssues.sort((a, b) => new Date(a.reviewed_at) - new Date(b.reviewed_at)); // 프로젝트별로 그룹화하여 No. 재할당 const projectGroups = {}; filteredIssues.forEach(issue => { if (!projectGroups[issue.project_id]) { projectGroups[issue.project_id] = []; } projectGroups[issue.project_id].push(issue); }); // 각 프로젝트별로 순번 재할당 Object.keys(projectGroups).forEach(projectId => { projectGroups[projectId].forEach((issue, index) => { issue.project_sequence_no = index + 1; }); }); issues = filteredIssues; filterIssues(); } else { throw new Error('부적합 목록을 불러올 수 없습니다.'); } } catch (error) { console.error('부적합 로드 실패:', error); alert('부적합 목록을 불러오는데 실패했습니다.'); } } // 탭 전환 함수 function switchTab(tab) { currentTab = tab; // 탭 버튼 스타일 업데이트 const inProgressTab = document.getElementById('inProgressTab'); const completedTab = document.getElementById('completedTab'); const additionalInfoBtn = document.getElementById('additionalInfoBtn'); if (tab === 'in_progress') { inProgressTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 bg-blue-500 text-white'; completedTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 text-gray-600 hover:text-gray-900'; // 진행 중 탭에서만 추가 정보 버튼 표시 additionalInfoBtn.style.display = 'block'; } else { inProgressTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 text-gray-600 hover:text-gray-900'; completedTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 bg-green-500 text-white'; // 완료됨 탭에서는 추가 정보 버튼 숨김 additionalInfoBtn.style.display = 'none'; } filterIssues(); // 이미 updateStatistics()가 포함됨 } // 통계 업데이트 함수 function updateStatistics() { const projectFilter = document.getElementById('projectFilter').value; // 선택된 프로젝트에 따른 이슈 필터링 const projectIssues = projectFilter ? issues.filter(issue => issue.project_id == projectFilter) : issues; // 상태별 카운트 const totalCount = projectIssues.length; const inProgressCount = projectIssues.filter(issue => issue.review_status === 'in_progress' && !issue.completion_requested_at ).length; const pendingCompletionCount = projectIssues.filter(issue => issue.review_status === 'in_progress' && issue.completion_requested_at ).length; const completedCount = projectIssues.filter(issue => issue.review_status === 'completed').length; // 통계 업데이트 document.getElementById('totalCount').textContent = totalCount; document.getElementById('inProgressCount').textContent = inProgressCount; document.getElementById('pendingCompletionCount').textContent = pendingCompletionCount; document.getElementById('completedCount').textContent = completedCount; } // 필터링 및 표시 함수들 function filterIssues() { const projectFilter = document.getElementById('projectFilter').value; filteredIssues = issues.filter(issue => { // 현재 탭에 따른 상태 필터링 if (issue.review_status !== currentTab) return false; // 프로젝트 필터링 if (projectFilter && issue.project_id != projectFilter) return false; return true; }); sortIssues(); displayIssues(); updateStatistics(); // 통계 업데이트 추가 } function sortIssues() { const sortOrder = document.getElementById('sortOrder').value; filteredIssues.sort((a, b) => { switch (sortOrder) { case 'newest': return new Date(b.report_date) - new Date(a.report_date); case 'oldest': return new Date(a.report_date) - new Date(b.report_date); default: return new Date(b.report_date) - new Date(a.report_date); } }); } function displayIssues() { const container = document.getElementById('issuesList'); const emptyState = document.getElementById('emptyState'); if (filteredIssues.length === 0) { container.innerHTML = ''; emptyState.classList.remove('hidden'); return; } emptyState.classList.add('hidden'); // 날짜별로 그룹화 (상태에 따라 다른 날짜 기준 사용) const groupedByDate = {}; filteredIssues.forEach(issue => { let date; if (currentTab === 'in_progress') { // 진행 중: 업로드한 날짜 기준 date = new Date(issue.report_date).toLocaleDateString('ko-KR'); } else { // 완료됨: 완료된 날짜 기준 (없으면 업로드 날짜) const completionDate = issue.actual_completion_date || issue.report_date; date = new Date(completionDate).toLocaleDateString('ko-KR'); } if (!groupedByDate[date]) { groupedByDate[date] = []; } groupedByDate[date].push(issue); }); // 날짜별 그룹을 HTML로 생성 const dateGroups = Object.keys(groupedByDate).map(date => { const issues = groupedByDate[date]; const groupId = `group-${date.replace(/\./g, '-')}`; return `
완료 사진 없음
'; } return `${issue.completion_comment || '코멘트 없음'}
${new Date(issue.completion_requested_at).toLocaleString('ko-KR')}
${getIssueDetail(issue)}
완료 사진 없음
'; } return `${issue.completion_comment || '코멘트 없음'}
${new Date(issue.completion_requested_at).toLocaleString('ko-KR')}
현재 완료 사진 (${photos.length}장)
※ 최대 5장까지 업로드 가능합니다. 새로운 사진을 업로드하면 기존 사진을 모두 교체합니다.
현재 완료 사진 (${photos.length}장)
사진 없음
※ 최대 5장까지 업로드 가능합니다. 새로운 사진을 업로드하면 기존 사진을 모두 교체합니다.
${new Date(issue.completion_requested_at).toLocaleString('ko-KR')}
완료 사진 (HEIC)
다운로드하여 확인현재 완료 사진
클릭하면 크게 볼 수 있습니다
완료 사진 없음
'}${issue.completion_comment || '코멘트 없음'}
${new Date(issue.completion_requested_at).toLocaleString('ko-KR')}
이 부적합 사항을 삭제하시겠습니까?
삭제된 데이터는 로그로 보관되지만 복구할 수 없습니다.