// 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;