fix: 사용자 관리 페이지 공통 헤더 적용 및 권한 설정 오류 수정

Issues Fixed:
1. 개인 페이지 헤더 제거
   - 기존 Header와 Navigation 삭제
   - 공통 헤더 자동 삽입으로 변경
   - padding-top: 120px 추가로 레이아웃 조정

2. showPagePermissionGrid 함수 오류 수정
   - 'pages' 변수 참조 오류 해결
   - pageCategories 기반으로 HTML 생성 로직 재작성
   - 카테고리별 그룹화 UI 개선

3. 권한 시스템 완성
   - users_manage 페이지 권한 추가
   - 백엔드 DEFAULT_PAGES에 users_manage 추가
   - 프론트엔드 권한 체크 로직 통합

4. UI/UX 개선
   - 체크박스 상태에 따른 시각적 피드백
   - 기본 권한 표시 배지 추가
   - 호버 효과 및 트랜지션 개선
   - 카테고리별 구분선 추가

Technical Changes:
- 모든 페이지 권한을 포함한 allPages 배열 업데이트
- 권한 저장 시 존재하지 않는 체크박스 검증 추가
- 공통 헤더 초기화 및 페이지 접근 권한 체크 추가
- 백엔드 재시작으로 권한 시스템 변경사항 적용

Result:
 사용자 선택 시 권한 설정 그리드 정상 표시
 모든 페이지 권한 (수신함, 관리함, 폐기함 포함) 관리 가능
 공통 헤더 통합으로 일관된 UI 제공
 권한 저장 및 로드 기능 정상 작동
This commit is contained in:
Hyungi Ahn
2025-10-25 09:53:11 +09:00
parent d456ad1e15
commit d821387e4b
2 changed files with 79 additions and 66 deletions

View File

@@ -50,7 +50,8 @@ DEFAULT_PAGES = {
'issues_archive': {'title': '폐기함', 'default_access': False},
'projects_manage': {'title': '프로젝트 관리', 'default_access': False},
'daily_work': {'title': '일일 공수', 'default_access': False},
'reports': {'title': '보고서', 'default_access': False}
'reports': {'title': '보고서', 'default_access': False},
'users_manage': {'title': '사용자 관리', 'default_access': False}
}
@router.post("/page-permissions/grant")

View File

@@ -59,48 +59,10 @@
</style>
</head>
<body>
<!-- Header -->
<header class="bg-white shadow-sm sticky top-0 z-50">
<div class="container mx-auto px-4 py-3">
<div class="flex justify-between items-center">
<h1 class="text-xl font-bold text-gray-800">
<i class="fas fa-clipboard-list mr-2"></i>작업보고서 시스템 - 관리자
</h1>
<button onclick="AuthAPI.logout()" class="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600 transition-colors text-sm">
<i class="fas fa-sign-out-alt mr-1"></i>로그아웃
</button>
</div>
</div>
</header>
<!-- Navigation -->
<nav class="bg-white border-b">
<div class="container mx-auto px-4">
<div class="flex gap-2 py-2 overflow-x-auto">
<a href="daily-work.html" class="nav-link">
<i class="fas fa-calendar-check mr-2"></i>일일 공수
</a>
<a href="index.html" class="nav-link">
<i class="fas fa-camera-retro mr-2"></i>부적합 등록
</a>
<a href="issue-view.html" class="nav-link">
<i class="fas fa-search mr-2"></i>부적합 조회
</a>
<a href="index.html#list" class="nav-link">
<i class="fas fa-list mr-2"></i>목록 관리
</a>
<a href="index.html#summary" class="nav-link">
<i class="fas fa-chart-bar mr-2"></i>보고서
</a>
<a href="admin.html" class="nav-link active">
<i class="fas fa-users-cog mr-2"></i>사용자 관리
</a>
</div>
</div>
</nav>
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 -->
<!-- Main Content -->
<main class="container mx-auto px-4 py-8 max-w-6xl">
<main class="container mx-auto px-4 py-8 max-w-6xl" style="padding-top: 120px;">
<div class="grid md:grid-cols-2 gap-6">
<!-- 사용자 추가 섹션 -->
<div class="bg-white rounded-xl shadow-sm p-6">
@@ -295,6 +257,15 @@
// 공통 헤더 초기화
await window.commonHeader.init(user, 'users_manage');
// 페이지 접근 권한 체크
setTimeout(() => {
if (!canAccessPage('users_manage')) {
alert('사용자 관리 페이지에 접근할 권한이 없습니다.');
window.location.href = '/index.html';
return;
}
}, 500);
} catch (error) {
console.error('인증 실패:', error);
localStorage.removeItem('access_token');
@@ -571,30 +542,65 @@
const grid = document.getElementById('pagePermissionGrid');
const gridContainer = grid.querySelector('.grid');
// 페이지 권한 체크박스 생성
const pages = {
'issues_create': '부적합 등록',
'issues_view': '부적합 조회',
'issues_manage': '부적합 관리',
'projects_manage': '프로젝트 관리',
'daily_work': '일일 공수',
'reports': '보고서'
// 페이지 권한 체크박스 생성 (카테고리별로 그룹화)
const pageCategories = {
'부적합 관리': {
'issues_create': { title: '부적합 등록', icon: 'fas fa-plus-circle', color: 'text-green-600' },
'issues_view': { title: '부적합 조회', icon: 'fas fa-search', color: 'text-purple-600' },
'issues_manage': { title: '목록 관리 (통합)', icon: 'fas fa-tasks', color: 'text-orange-600' }
},
'목록 관리 세부': {
'issues_inbox': { title: '📥 수신함', icon: 'fas fa-inbox', color: 'text-blue-600' },
'issues_management': { title: '⚙️ 관리함', icon: 'fas fa-cog', color: 'text-green-600' },
'issues_archive': { title: '🗃️ 폐기함', icon: 'fas fa-archive', color: 'text-gray-600' }
},
'시스템 관리': {
'projects_manage': { title: '프로젝트 관리', icon: 'fas fa-folder-open', color: 'text-indigo-600' },
'daily_work': { title: '일일 공수', icon: 'fas fa-calendar-check', color: 'text-blue-600' },
'reports': { title: '보고서', icon: 'fas fa-chart-bar', color: 'text-red-600' },
'users_manage': { title: '사용자 관리', icon: 'fas fa-users-cog', color: 'text-purple-600' }
}
};
gridContainer.innerHTML = Object.entries(pages).map(([pageName, title]) => `
<div class="flex items-center p-3 border rounded-lg">
<input
type="checkbox"
id="perm_${pageName}"
${currentPermissions[pageName] ? 'checked' : ''}
class="mr-3 h-4 w-4 text-purple-600 rounded focus:ring-purple-500"
>
<label for="perm_${pageName}" class="text-sm font-medium text-gray-700">
${title}
</label>
</div>
`).join('');
let html = '';
// 카테고리별로 그룹화하여 표시
Object.entries(pageCategories).forEach(([categoryName, pages]) => {
html += `
<div class="col-span-full">
<h4 class="text-sm font-semibold text-gray-800 mb-3 pb-2 border-b border-gray-200">
${categoryName}
</h4>
</div>
`;
Object.entries(pages).forEach(([pageName, pageInfo]) => {
const isChecked = currentPermissions[pageName] || false;
const isDefault = currentPermissions[pageName] === undefined ?
(pageInfo.title.includes('등록') || pageInfo.title.includes('조회') || pageInfo.title.includes('수신함')) : false;
html += `
<div class="flex items-center p-3 border rounded-lg hover:bg-gray-50 transition-colors ${isChecked ? 'border-blue-300 bg-blue-50' : 'border-gray-200'}">
<input
type="checkbox"
id="perm_${pageName}"
${isChecked ? 'checked' : ''}
class="mr-3 h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
onchange="this.parentElement.classList.toggle('border-blue-300', this.checked); this.parentElement.classList.toggle('bg-blue-50', this.checked);"
>
<label for="perm_${pageName}" class="flex-1 cursor-pointer">
<div class="flex items-center">
<i class="${pageInfo.icon} ${pageInfo.color} mr-2"></i>
<span class="text-sm font-medium text-gray-700">${pageInfo.title}</span>
${isDefault ? '<span class="ml-2 text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">기본</span>' : ''}
</div>
</label>
</div>
`;
});
});
gridContainer.innerHTML = html;
grid.classList.remove('hidden');
}
@@ -615,13 +621,19 @@
statusSpan.textContent = '';
try {
// 체크박스 상태 수집
const pages = ['issues_create', 'issues_view', 'issues_manage', 'projects_manage', 'daily_work', 'reports'];
// 체크박스 상태 수집 (모든 페이지 포함)
const allPages = [
'issues_create', 'issues_view', 'issues_manage',
'issues_inbox', 'issues_management', 'issues_archive',
'projects_manage', 'daily_work', 'reports', 'users_manage'
];
const permissions = {};
pages.forEach(pageName => {
allPages.forEach(pageName => {
const checkbox = document.getElementById(`perm_${pageName}`);
permissions[pageName] = checkbox.checked;
if (checkbox) {
permissions[pageName] = checkbox.checked;
}
});
// 실제 API 호출로 권한 저장