/** * issues-archive.js — 폐기함 페이지 스크립트 */ let currentUser = null; let issues = []; let projects = []; let filteredIssues = []; // API 로드 후 초기화 함수 async function initializeArchive() { const token = TokenManager.getToken(); if (!token) { window.location.href = '/index.html'; return; } try { const user = await AuthAPI.getCurrentUser(); currentUser = user; localStorage.setItem('sso_user', JSON.stringify(user)); // 공통 헤더 초기화 await window.commonHeader.init(user, 'issues_archive'); // 페이지 접근 권한 체크 setTimeout(() => { if (!canAccessPage('issues_archive')) { alert('폐기함 페이지에 접근할 권한이 없습니다.'); window.location.href = '/index.html'; return; } }, 500); // 데이터 로드 await loadProjects(); await loadArchivedIssues(); } 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 loadArchivedIssues() { try { let endpoint = '/api/issues/'; // 관리자인 경우 전체 부적합 조회 API 사용 if (currentUser.role === 'admin') { 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(); // 폐기된 부적합만 필터링 (폐기함 전용) issues = allIssues.filter(issue => issue.review_status === 'disposed' ); filterIssues(); updateStatistics(); renderCharts(); } else { throw new Error('부적합 목록을 불러올 수 없습니다.'); } } catch (error) { console.error('부적합 로드 실패:', error); alert('부적합 목록을 불러오는데 실패했습니다.'); } } // 필터링 및 표시 function filterIssues() { const projectFilter = document.getElementById('projectFilter').value; const statusFilter = document.getElementById('statusFilter').value; const periodFilter = document.getElementById('periodFilter').value; const categoryFilter = document.getElementById('categoryFilter').value; const searchInput = document.getElementById('searchInput').value.toLowerCase(); filteredIssues = issues.filter(issue => { if (projectFilter && issue.project_id != projectFilter) return false; if (statusFilter && issue.status !== statusFilter) return false; if (categoryFilter && issue.category !== categoryFilter) return false; // 기간 필터 if (periodFilter) { const issueDate = new Date(issue.updated_at || issue.created_at); const now = new Date(); switch (periodFilter) { case 'week': const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); if (issueDate < weekAgo) return false; break; case 'month': const monthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate()); if (issueDate < monthAgo) return false; break; case 'quarter': const quarterAgo = new Date(now.getFullYear(), now.getMonth() - 3, now.getDate()); if (issueDate < quarterAgo) return false; break; case 'year': const yearAgo = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate()); if (issueDate < yearAgo) return false; break; } } if (searchInput) { const searchText = `${issue.description} ${issue.reporter?.username || ''}`.toLowerCase(); if (!searchText.includes(searchInput)) return false; } return true; }); sortIssues(); displayIssues(); } 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); case 'completed': return new Date(b.disposed_at || b.report_date) - new Date(a.disposed_at || a.report_date); case 'category': return (a.category || '').localeCompare(b.category || ''); 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'); container.innerHTML = filteredIssues.map(issue => { const project = projects.find(p => p.id === issue.project_id); // 폐기함은 폐기된 것만 표시 const completedDate = issue.disposed_at ? new Date(issue.disposed_at).toLocaleDateString('ko-KR') : 'Invalid Date'; const statusText = '폐기'; const cardClass = 'archived-card'; return `
${getStatusText(issue.status)} ${project ? `${project.project_name}` : ''} ${completedDate}

${issue.description}

${issue.reporter?.username || '알 수 없음'} ${issue.category ? `${getCategoryText(issue.category)}` : ''} ${statusText}: ${completedDate}
`; }).join(''); } // 통계 업데이트 function updateStatistics() { const completed = issues.filter(issue => issue.status === 'completed').length; const archived = issues.filter(issue => issue.status === 'archived').length; const cancelled = issues.filter(issue => issue.status === 'cancelled').length; const thisMonth = issues.filter(issue => { const issueDate = new Date(issue.updated_at || issue.created_at); const now = new Date(); return issueDate.getMonth() === now.getMonth() && issueDate.getFullYear() === now.getFullYear(); }).length; document.getElementById('completedCount').textContent = completed; document.getElementById('archivedCount').textContent = archived; document.getElementById('cancelledCount').textContent = cancelled; document.getElementById('thisMonthCount').textContent = thisMonth; } // 차트 렌더링 (간단한 텍스트 기반) function renderCharts() { renderMonthlyChart(); renderCategoryChart(); } function renderMonthlyChart() { const canvas = document.getElementById('monthlyChart'); const ctx = canvas.getContext('2d'); canvas.width = canvas.offsetWidth; canvas.height = canvas.offsetHeight; ctx.fillStyle = '#374151'; ctx.font = '16px Inter'; ctx.textAlign = 'center'; ctx.fillText('월별 완료 현황 차트', canvas.width / 2, canvas.height / 2); ctx.font = '12px Inter'; ctx.fillText('(차트 라이브러리 구현 예정)', canvas.width / 2, canvas.height / 2 + 20); } function renderCategoryChart() { const canvas = document.getElementById('categoryChart'); const ctx = canvas.getContext('2d'); canvas.width = canvas.offsetWidth; canvas.height = canvas.offsetHeight; ctx.fillStyle = '#374151'; ctx.font = '16px Inter'; ctx.textAlign = 'center'; ctx.fillText('카테고리별 분포 차트', canvas.width / 2, canvas.height / 2); ctx.font = '12px Inter'; ctx.fillText('(차트 라이브러리 구현 예정)', canvas.width / 2, canvas.height / 2 + 20); } // 기타 함수들 function generateReport() { alert('통계 보고서를 생성합니다.'); } function cleanupArchive() { if (confirm('오래된 보관 데이터를 정리하시겠습니까?')) { alert('데이터 정리가 완료되었습니다.'); } } function viewArchivedIssue(issueId) { window.location.href = `/issue-view.html#detail-${issueId}`; } // 유틸리티 함수들 function updateProjectFilter() { const projectFilter = document.getElementById('projectFilter'); projectFilter.innerHTML = ''; projects.forEach(project => { const option = document.createElement('option'); option.value = project.id; option.textContent = project.project_name; projectFilter.appendChild(option); }); } // 페이지 전용 유틸리티 (shared에 없는 것들) function getStatusIcon(status) { const iconMap = { 'completed': 'check-circle', 'archived': 'archive', 'cancelled': 'times-circle' }; return iconMap[status] || 'archive'; } function getStatusColor(status) { const colorMap = { 'completed': 'text-green-500', 'archived': 'text-gray-500', 'cancelled': 'text-red-500' }; return colorMap[status] || 'text-gray-500'; } // API 스크립트 동적 로딩 const script = document.createElement('script'); script.src = '/static/js/api.js?v=20260213'; script.onload = function() { console.log('API 스크립트 로드 완료 (issues-archive.html)'); initializeArchive(); }; script.onerror = function() { console.error('API 스크립트 로드 실패'); }; document.head.appendChild(script);