// page-access-management.js - 페이지 권한 관리 // 전역 변수 let allUsers = []; let allPages = []; let currentUserId = null; let currentFilter = 'all'; // DOM이 로드되면 초기화 document.addEventListener('DOMContentLoaded', async () => { console.log('🚀 페이지 권한 관리 시스템 초기화'); // API 함수가 로드될 때까지 대기 let retryCount = 0; while (!window.apiCall && retryCount < 50) { await new Promise(resolve => setTimeout(resolve, 100)); retryCount++; } if (!window.apiCall) { showToast('시스템을 초기화할 수 없습니다. 페이지를 새로고침해주세요.', 'error'); return; } // 이벤트 리스너 설정 setupEventListeners(); // 데이터 로드 await loadInitialData(); }); // 이벤트 리스너 설정 function setupEventListeners() { // 필터 버튼 document.querySelectorAll('.filter-btn').forEach(btn => { btn.addEventListener('click', (e) => { document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active')); e.target.classList.add('active'); currentFilter = e.target.dataset.filter; filterUsers(); }); }); // 저장 버튼 const saveBtn = document.getElementById('savePageAccessBtn'); if (saveBtn) { saveBtn.addEventListener('click', savePageAccess); } } // 초기 데이터 로드 async function loadInitialData() { try { // 페이지 목록 로드 const pagesResponse = await window.apiCall('/pages'); if (pagesResponse && pagesResponse.success) { allPages = pagesResponse.data; console.log('✅ 페이지 목록 로드:', allPages.length + '개'); } // 사용자 목록 로드 - 계정이 있는 작업자만 const workersResponse = await window.apiCall('/workers?limit=1000'); if (workersResponse) { const workers = Array.isArray(workersResponse) ? workersResponse : (workersResponse.data || []); // user_id가 있고 활성 상태인 작업자만 필터링 const usersWithAccounts = workers.filter(w => w.user_id && w.is_active); // 각 사용자의 페이지 권한 수 조회 allUsers = await Promise.all(usersWithAccounts.map(async (worker) => { try { const accessResponse = await window.apiCall(`/users/${worker.user_id}/page-access`); const grantedPagesCount = accessResponse && accessResponse.success ? accessResponse.data.pageAccess.filter(p => p.can_access).length : 0; return { user_id: worker.user_id, username: worker.username || 'N/A', name: worker.name || worker.worker_name, role_name: worker.role_name || 'User', worker_name: worker.worker_name, worker_id: worker.worker_id, granted_pages_count: grantedPagesCount }; } catch (error) { console.error(`권한 조회 오류 (user_id: ${worker.user_id}):`, error); return { ...worker, granted_pages_count: 0 }; } })); console.log('✅ 사용자 목록 로드:', allUsers.length + '명'); displayUsers(); } } catch (error) { console.error('❌ 데이터 로드 오류:', error); showToast('데이터를 불러오는 중 오류가 발생했습니다.', 'error'); } } // 사용자 목록 표시 function displayUsers() { const tbody = document.getElementById('usersTableBody'); const emptyState = document.getElementById('emptyState'); if (allUsers.length === 0) { tbody.innerHTML = ''; emptyState.style.display = 'block'; return; } emptyState.style.display = 'none'; const filteredUsers = filterUsersByStatus(); if (filteredUsers.length === 0) { tbody.innerHTML = `

필터 조건에 맞는 사용자가 없습니다.

`; return; } tbody.innerHTML = filteredUsers.map(user => `
${(user.name || user.username).charAt(0)}
${user.name || user.username}
${user.username} ${user.role_name} ${user.worker_name || '-'} ${user.granted_pages_count}개 / ${allPages.length}개 `).join(''); } // 사용자 필터링 function filterUsersByStatus() { if (currentFilter === 'all') { return allUsers; } else if (currentFilter === 'with-access') { return allUsers.filter(u => u.granted_pages_count > 0); } else if (currentFilter === 'no-access') { return allUsers.filter(u => u.granted_pages_count === 0); } return allUsers; } function filterUsers() { displayUsers(); } // 페이지 권한 설정 모달 열기 async function openPageAccessModal(userId) { currentUserId = userId; const user = allUsers.find(u => u.user_id === userId); if (!user) { showToast('사용자 정보를 찾을 수 없습니다.', 'error'); return; } // 모달 열기 document.getElementById('pageAccessModal').style.display = 'flex'; document.body.style.overflow = 'hidden'; // 사용자 정보 표시 document.getElementById('modalUserInitial').textContent = (user.name || user.username).charAt(0); document.getElementById('modalUserName').textContent = user.name || user.username; document.getElementById('modalUsername').textContent = user.username; document.getElementById('modalWorkerName').textContent = user.worker_name || '작업자 정보 없음'; // 페이지 목록 로드 try { const response = await window.apiCall(`/users/${userId}/page-access`); if (response && response.success) { const pageAccess = response.data.pageAccess; renderPageList(pageAccess); } else { showToast('페이지 권한 정보를 불러올 수 없습니다.', 'error'); } } catch (error) { console.error('페이지 권한 조회 오류:', error); showToast('페이지 권한 정보를 불러오는 중 오류가 발생했습니다.', 'error'); } } // 페이지 목록 렌더링 function renderPageList(pageAccess) { const container = document.getElementById('pageListContainer'); // 카테고리별로 그룹화 const grouped = {}; pageAccess.forEach(page => { const category = page.category || 'common'; if (!grouped[category]) { grouped[category] = []; } grouped[category].push(page); }); const categoryNames = { 'dashboard': '대시보드', 'management': '관리', 'common': '공통', 'admin': '관리자', 'work': '작업', 'guest': '게스트' }; container.innerHTML = Object.keys(grouped).map(category => `
${categoryNames[category] || category}
${grouped[category].map(page => `
${page.is_default ? '기본 권한' : ''}
`).join('')}
`).join(''); } // 페이지 권한 저장 async function savePageAccess() { if (!currentUserId) return; const checkboxes = document.querySelectorAll('.page-checkbox:not([disabled]):checked'); const pageIds = Array.from(checkboxes).map(cb => parseInt(cb.dataset.pageId)); try { document.getElementById('savePageAccessBtn').disabled = true; document.getElementById('savePageAccessBtn').textContent = '저장 중...'; const response = await window.apiCall( `/users/${currentUserId}/page-access`, 'POST', { pageIds, canAccess: true } ); if (response && response.success) { showToast('페이지 권한이 저장되었습니다.', 'success'); closePageAccessModal(); await loadInitialData(); // 목록 새로고침 } else { throw new Error(response.error || '저장에 실패했습니다.'); } } catch (error) { console.error('페이지 권한 저장 오류:', error); showToast('페이지 권한 저장 중 오류가 발생했습니다.', 'error'); } finally { document.getElementById('savePageAccessBtn').disabled = false; document.getElementById('savePageAccessBtn').textContent = '저장'; } } // 모달 닫기 function closePageAccessModal() { document.getElementById('pageAccessModal').style.display = 'none'; document.body.style.overflow = 'auto'; currentUserId = null; } // 토스트 알림 function showToast(message, type = 'info', duration = 3000) { const container = document.getElementById('toastContainer'); if (!container) return; const toast = document.createElement('div'); toast.className = `toast ${type}`; const iconMap = { success: '✅', error: '❌', warning: '⚠️', info: 'ℹ️' }; toast.innerHTML = `
${iconMap[type] || 'ℹ️'}
${message}
`; container.appendChild(toast); setTimeout(() => { if (toast.parentElement) { toast.remove(); } }, duration); } // 전역 함수로 export window.openPageAccessModal = openPageAccessModal; window.closePageAccessModal = closePageAccessModal;