feat(tkuser): 통합 관리 탭별 권한 시스템 추가

- DEFAULT_PAGES에 tkuser 시스템 10개 페이지 권한 정의 추가
- 권한 관리 UI에 tkuser 섹션 추가 (개인/부서 권한 모두)
- 비admin 사용자 로그인 시 effective-permissions 기반 탭 표시 제어
- switchTab()에 권한 guard 추가하여 비허용 탭 접근 차단

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-13 10:20:21 +09:00
parent 976e55d672
commit 3b0ac615bf
5 changed files with 121 additions and 10 deletions

View File

@@ -79,6 +79,21 @@ const TKSAFETY_PAGES = {
]
};
const TKUSER_PAGES = {
'통합 관리': [
{ key: 'tkuser.users', title: '사용자 관리', icon: 'fa-users', def: false, tab: 'users' },
{ key: 'tkuser.projects', title: '프로젝트 관리', icon: 'fa-folder-open', def: false, tab: 'projects' },
{ key: 'tkuser.workplaces', title: '작업장 관리', icon: 'fa-building', def: false, tab: 'workplaces' },
{ key: 'tkuser.workers', title: '작업자 관리', icon: 'fa-hard-hat', def: false, tab: 'workers' },
{ key: 'tkuser.departments', title: '부서 관리', icon: 'fa-sitemap', def: false, tab: 'departments' },
{ key: 'tkuser.issue_types', title: '이슈 유형 관리', icon: 'fa-exclamation-triangle', def: false, tab: 'issueTypes' },
{ key: 'tkuser.tasks', title: '작업 관리', icon: 'fa-tasks', def: false, tab: 'tasks' },
{ key: 'tkuser.vacations', title: '휴가 관리', icon: 'fa-umbrella-beach', def: false, tab: 'vacations' },
{ key: 'tkuser.partners', title: '협력업체 관리', icon: 'fa-truck', def: false, tab: 'partners' },
{ key: 'tkuser.notification_recipients', title: '알림 수신자 관리', icon: 'fa-bell', def: false, tab: 'notificationRecipients' },
]
};
/* ===== Permissions Tab State ===== */
let permissionsTabLoaded = false;
@@ -204,7 +219,7 @@ document.getElementById('permissionUserSelect').addEventListener('change', async
async function loadUserPermissions(userId) {
currentPermissions = {};
currentPermSources = {};
const allDefs = { ...SYSTEM1_PAGES, ...SYSTEM3_PAGES, ...TKPURCHASE_PAGES, ...TKSAFETY_PAGES };
const allDefs = { ...SYSTEM1_PAGES, ...SYSTEM3_PAGES, ...TKPURCHASE_PAGES, ...TKSAFETY_PAGES, ...TKUSER_PAGES };
Object.values(allDefs).flat().forEach(p => { currentPermissions[p.key] = p.def; currentPermSources[p.key] = 'default'; });
try {
const result = await api(`/permissions/users/${userId}/effective-permissions`);
@@ -222,6 +237,7 @@ function renderPermissionGrid() {
renderSystemPerms('s3-perms', SYSTEM3_PAGES, 'purple');
renderSystemPerms('tkpurchase-perms', TKPURCHASE_PAGES, 'green');
renderSystemPerms('tksafety-perms', TKSAFETY_PAGES, 'orange');
renderSystemPerms('tkuser-perms', TKUSER_PAGES, 'slate');
}
function sourceLabel(src) {
@@ -317,7 +333,7 @@ document.getElementById('savePermissionsBtn').addEventListener('click', async ()
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>저장 중...';
try {
const allPages = [...Object.values(SYSTEM1_PAGES).flat(), ...Object.values(SYSTEM3_PAGES).flat(), ...Object.values(TKPURCHASE_PAGES).flat(), ...Object.values(TKSAFETY_PAGES).flat()];
const allPages = [...Object.values(SYSTEM1_PAGES).flat(), ...Object.values(SYSTEM3_PAGES).flat(), ...Object.values(TKPURCHASE_PAGES).flat(), ...Object.values(TKSAFETY_PAGES).flat(), ...Object.values(TKUSER_PAGES).flat()];
const permissions = allPages.map(p => {
const cb = document.getElementById('perm_' + p.key);
return { page_name: p.key, can_access: cb ? cb.checked : false };
@@ -365,7 +381,7 @@ document.addEventListener('DOMContentLoaded', () => {
async function loadDeptPermissions(deptId) {
deptPermissions = {};
const allDefs = { ...SYSTEM1_PAGES, ...SYSTEM3_PAGES, ...TKPURCHASE_PAGES, ...TKSAFETY_PAGES };
const allDefs = { ...SYSTEM1_PAGES, ...SYSTEM3_PAGES, ...TKPURCHASE_PAGES, ...TKSAFETY_PAGES, ...TKUSER_PAGES };
Object.values(allDefs).flat().forEach(p => { deptPermissions[p.key] = p.def; });
try {
const result = await api(`/permissions/departments/${deptId}/permissions`);
@@ -378,6 +394,7 @@ function renderDeptPermissionGrid() {
renderDeptSystemPerms('dept-s3-perms', SYSTEM3_PAGES, 'purple');
renderDeptSystemPerms('dept-tkpurchase-perms', TKPURCHASE_PAGES, 'green');
renderDeptSystemPerms('dept-tksafety-perms', TKSAFETY_PAGES, 'orange');
renderDeptSystemPerms('dept-tkuser-perms', TKUSER_PAGES, 'slate');
}
function renderDeptSystemPerms(containerId, pageDef, color) {
@@ -456,7 +473,7 @@ async function saveDeptPermissions() {
btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>저장 중...';
try {
const allPages = [...Object.values(SYSTEM1_PAGES).flat(), ...Object.values(SYSTEM3_PAGES).flat(), ...Object.values(TKPURCHASE_PAGES).flat(), ...Object.values(TKSAFETY_PAGES).flat()];
const allPages = [...Object.values(SYSTEM1_PAGES).flat(), ...Object.values(SYSTEM3_PAGES).flat(), ...Object.values(TKPURCHASE_PAGES).flat(), ...Object.values(TKSAFETY_PAGES).flat(), ...Object.values(TKUSER_PAGES).flat()];
const permissions = allPages.map(p => {
const cb = document.getElementById('dperm_' + p.key);
return { page_name: p.key, can_access: cb ? cb.checked : false };