feat(tkuser): 권한 관리 페이지 최신화 — tksupport 추가, tksafety 보강, S1 휴가 정리
- tksupport 행정지원 6페이지 권한 정의 추가 (indigo 테마) - tksupport 라우트에 requirePage() 미들웨어 적용 - tksafety 권한 2→8개 확장 (출입관리 4 + 교육/점검 4) - System1 안전관리 그룹 제거 (s1.safety.* 고아키) - System1 근태관리 휴가 5항목 제거 (tksupport로 통합) - 월간근태를 공장관리 그룹으로 이동 - System3 업무, tkuser 연차설정 백엔드 키 동기화 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { requireAuth, requireSupportTeam } = require('../middleware/auth');
|
||||
const { requireAuth, requireSupportTeam, requirePage } = require('../middleware/auth');
|
||||
const ctrl = require('../controllers/companyHolidayController');
|
||||
|
||||
router.use(requireAuth);
|
||||
|
||||
router.get('/holidays', ctrl.getHolidays);
|
||||
router.post('/holidays', requireSupportTeam, ctrl.createHoliday);
|
||||
router.delete('/holidays/:id', requireSupportTeam, ctrl.deleteHoliday);
|
||||
router.post('/holidays/:id/apply-deduction', requireSupportTeam, ctrl.applyDeduction);
|
||||
router.post('/holidays', requireSupportTeam, requirePage('support_company_holidays'), ctrl.createHoliday);
|
||||
router.delete('/holidays/:id', requireSupportTeam, requirePage('support_company_holidays'), ctrl.deleteHoliday);
|
||||
router.post('/holidays/:id/apply-deduction', requireSupportTeam, requirePage('support_company_holidays'), ctrl.applyDeduction);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { requireAuth, requireSupportTeam } = require('../middleware/auth');
|
||||
const { requireAuth, requireSupportTeam, requirePage } = require('../middleware/auth');
|
||||
const ctrl = require('../controllers/vacationDashboardController');
|
||||
|
||||
router.use(requireAuth);
|
||||
|
||||
router.get('/', requireSupportTeam, ctrl.getDashboard);
|
||||
router.get('/yearly-overview', requireSupportTeam, ctrl.getYearlyOverview);
|
||||
router.get('/monthly-detail', requireSupportTeam, ctrl.getMonthlyDetail);
|
||||
router.get('/', requireSupportTeam, requirePage('support_vacation_dashboard'), ctrl.getDashboard);
|
||||
router.get('/yearly-overview', requireSupportTeam, requirePage('support_vacation_dashboard'), ctrl.getYearlyOverview);
|
||||
router.get('/monthly-detail', requireSupportTeam, requirePage('support_vacation_dashboard'), ctrl.getMonthlyDetail);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { requireAuth, requireAdmin } = require('../middleware/auth');
|
||||
const { requireAuth, requireAdmin, requirePage } = require('../middleware/auth');
|
||||
const ctrl = require('../controllers/vacationController');
|
||||
|
||||
router.use(requireAuth);
|
||||
@@ -9,16 +9,16 @@ router.use(requireAuth);
|
||||
router.get('/types', ctrl.getVacationTypes);
|
||||
|
||||
// 휴가 신청
|
||||
router.post('/requests', ctrl.createRequest);
|
||||
router.post('/requests', requirePage('support_vacation_request'), ctrl.createRequest);
|
||||
router.get('/requests', ctrl.getRequests);
|
||||
router.get('/requests/:id', ctrl.getRequestById);
|
||||
router.put('/requests/:id', ctrl.updateRequest);
|
||||
router.patch('/requests/:id/cancel', ctrl.cancelRequest);
|
||||
router.put('/requests/:id', requirePage('support_vacation_request'), ctrl.updateRequest);
|
||||
router.patch('/requests/:id/cancel', requirePage('support_vacation_request'), ctrl.cancelRequest);
|
||||
|
||||
// 승인 (관리자)
|
||||
router.get('/pending', requireAdmin, ctrl.getPending);
|
||||
router.patch('/requests/:id/approve', requireAdmin, ctrl.approveRequest);
|
||||
router.patch('/requests/:id/reject', requireAdmin, ctrl.rejectRequest);
|
||||
router.patch('/requests/:id/approve', requireAdmin, requirePage('support_vacation_approval'), ctrl.approveRequest);
|
||||
router.patch('/requests/:id/reject', requireAdmin, requirePage('support_vacation_approval'), ctrl.rejectRequest);
|
||||
|
||||
// 내 휴가 현황
|
||||
router.get('/my-status', ctrl.getMyStatus);
|
||||
|
||||
@@ -20,13 +20,7 @@ const DEFAULT_PAGES = {
|
||||
's1.inspection.daily_patrol': { title: '일일순회점검', system: 'system1', group: '공장 관리', default_access: false },
|
||||
's1.inspection.checkin': { title: '출근 체크', system: 'system1', group: '공장 관리', default_access: true },
|
||||
's1.inspection.work_status': { title: '근무 현황', system: 'system1', group: '공장 관리', default_access: false },
|
||||
// 근태 관리
|
||||
's1.attendance.my_vacation_info': { title: '내 연차 정보', system: 'system1', group: '근태 관리', default_access: true },
|
||||
's1.attendance.monthly': { title: '월간 근태', system: 'system1', group: '근태 관리', default_access: true },
|
||||
's1.attendance.vacation_request': { title: '휴가 신청', system: 'system1', group: '근태 관리', default_access: true },
|
||||
's1.attendance.vacation_management': { title: '휴가 관리', system: 'system1', group: '근태 관리', default_access: false },
|
||||
's1.attendance.vacation_allocation': { title: '휴가 발생 입력', system: 'system1', group: '근태 관리', default_access: false },
|
||||
's1.attendance.annual_overview': { title: '연간 휴가 현황', system: 'system1', group: '근태 관리', default_access: false },
|
||||
's1.attendance.monthly': { title: '월간 근태', system: 'system1', group: '공장 관리', default_access: true },
|
||||
// 시스템 관리
|
||||
's1.admin.workers': { title: '작업자 관리', system: 'system1', group: '시스템 관리', default_access: false },
|
||||
's1.admin.projects': { title: '프로젝트 관리', system: 'system1', group: '시스템 관리', default_access: false },
|
||||
@@ -47,6 +41,9 @@ const DEFAULT_PAGES = {
|
||||
'reports_daily': { title: '일일보고서', system: 'system3', group: '보고서', default_access: false },
|
||||
'reports_weekly': { title: '주간보고서', system: 'system3', group: '보고서', default_access: false },
|
||||
'reports_monthly': { title: '월간보고서', system: 'system3', group: '보고서', default_access: false },
|
||||
// 업무
|
||||
'daily_work': { title: '일일 공수', system: 'system3', group: '업무', default_access: false },
|
||||
'projects_manage': { title: '프로젝트 관리', system: 'system3', group: '업무', default_access: false },
|
||||
// AI
|
||||
'ai_assistant': { title: 'AI 어시스턴트', system: 'system3', group: 'AI', default_access: false },
|
||||
|
||||
@@ -59,11 +56,26 @@ const DEFAULT_PAGES = {
|
||||
'purchasing_partner_checkin': { title: '협력업체 체크인', system: 'tkpurchase', group: '협력업체', default_access: false },
|
||||
|
||||
// ===== tksafety - 안전 관리 =====
|
||||
'safety_visit_request': { title: '출입 신청', system: 'tksafety', group: '안전 관리', default_access: true },
|
||||
'safety_visit_management': { title: '출입 관리', system: 'tksafety', group: '안전 관리', default_access: false },
|
||||
'safety_training': { title: '안전교육 실시', system: 'tksafety', group: '안전 관리', default_access: false },
|
||||
'safety_checklist': { title: '체크리스트 관리', system: 'tksafety', group: '안전 관리', default_access: false },
|
||||
'safety_entry_dashboard': { title: '출입 현황판', system: 'tksafety', group: '안전 관리', default_access: false },
|
||||
// 출입 관리
|
||||
'safety_visit': { title: '방문 관리', system: 'tksafety', group: '출입 관리', default_access: true },
|
||||
'safety_visit_request': { title: '출입 신청', system: 'tksafety', group: '출입 관리', default_access: true },
|
||||
'safety_visit_management': { title: '출입 승인', system: 'tksafety', group: '출입 관리', default_access: false },
|
||||
'safety_entry_dashboard': { title: '출입 현황판', system: 'tksafety', group: '출입 관리', default_access: false },
|
||||
// 교육/점검
|
||||
'safety_education': { title: '안전교육', system: 'tksafety', group: '교육/점검', default_access: true },
|
||||
'safety_training': { title: '안전교육 실시', system: 'tksafety', group: '교육/점검', default_access: false },
|
||||
'safety_risk_assessment': { title: '위험성평가', system: 'tksafety', group: '교육/점검', default_access: false },
|
||||
'safety_checklist': { title: '체크리스트 관리', system: 'tksafety', group: '교육/점검', default_access: false },
|
||||
|
||||
// ===== tksupport - 행정 지원 =====
|
||||
// 일반
|
||||
'support_dashboard': { title: '대시보드', system: 'tksupport', group: '일반', default_access: true },
|
||||
'support_vacation_request': { title: '휴가 신청', system: 'tksupport', group: '일반', default_access: true },
|
||||
'support_vacation_status': { title: '내 휴가 현황', system: 'tksupport', group: '일반', default_access: true },
|
||||
// 관리
|
||||
'support_vacation_approval': { title: '휴가 승인', system: 'tksupport', group: '관리', default_access: false },
|
||||
'support_company_holidays': { title: '전사 휴가 관리', system: 'tksupport', group: '관리', default_access: false },
|
||||
'support_vacation_dashboard': { title: '전체 휴가관리', system: 'tksupport', group: '관리', default_access: false },
|
||||
|
||||
// ===== tkuser - 통합 관리 =====
|
||||
'tkuser.users': { title: '사용자 관리', system: 'tkuser', group: '통합 관리', default_access: false },
|
||||
@@ -74,6 +86,7 @@ const DEFAULT_PAGES = {
|
||||
'tkuser.issue_types': { title: '이슈 유형 관리', system: 'tkuser', group: '통합 관리', default_access: false },
|
||||
'tkuser.tasks': { title: '작업 관리', system: 'tkuser', group: '통합 관리', default_access: false },
|
||||
'tkuser.vacations': { title: '휴가 관리', system: 'tkuser', group: '통합 관리', default_access: false },
|
||||
'tkuser.vacation_settings': { title: '연차 설정', system: 'tkuser', group: '통합 관리', default_access: false },
|
||||
'tkuser.partners': { title: '협력업체 관리', system: 'tkuser', group: '통합 관리', default_access: false },
|
||||
'tkuser.notification_recipients': { title: '알림 수신자 관리', system: 'tkuser', group: '통합 관리', default_access: false },
|
||||
};
|
||||
|
||||
@@ -12,19 +12,7 @@ const SYSTEM1_PAGES = {
|
||||
{ key: 's1.inspection.daily_patrol', title: '일일순회점검', icon: 'fa-clipboard-check', def: false },
|
||||
{ key: 's1.inspection.checkin', title: '출근 체크', icon: 'fa-fingerprint', def: true },
|
||||
{ key: 's1.inspection.work_status', title: '근무 현황', icon: 'fa-user-clock', def: false },
|
||||
],
|
||||
'안전 관리': [
|
||||
{ key: 's1.safety.visit_request', title: '출입 신청', icon: 'fa-id-badge', def: true },
|
||||
{ key: 's1.safety.management', title: '안전 관리', icon: 'fa-fire-extinguisher', def: false },
|
||||
{ key: 's1.safety.checklist_manage', title: '체크리스트 관리', icon: 'fa-list-check', def: false },
|
||||
],
|
||||
'근태 관리': [
|
||||
{ key: 's1.attendance.my_vacation_info', title: '내 연차 정보', icon: 'fa-umbrella-beach', def: true },
|
||||
{ key: 's1.attendance.monthly', title: '월간 근태', icon: 'fa-calendar-days', def: true },
|
||||
{ key: 's1.attendance.vacation_request', title: '휴가 신청', icon: 'fa-paper-plane', def: true },
|
||||
{ key: 's1.attendance.vacation_management', title: '휴가 관리', icon: 'fa-calendar-check', def: false },
|
||||
{ key: 's1.attendance.vacation_allocation', title: '휴가 발생 입력', icon: 'fa-calendar-plus', def: false },
|
||||
{ key: 's1.attendance.annual_overview', title: '연간 휴가 현황', icon: 'fa-chart-pie', def: false },
|
||||
],
|
||||
'시스템 관리': [
|
||||
{ key: 's1.admin.workers', title: '작업자 관리', icon: 'fa-people-group', def: false },
|
||||
@@ -73,9 +61,30 @@ const TKPURCHASE_PAGES = {
|
||||
};
|
||||
|
||||
const TKSAFETY_PAGES = {
|
||||
'안전 관리': [
|
||||
{ key: 'safety_visit', title: '방문 관리', icon: 'fa-door-open', def: false },
|
||||
{ key: 'safety_education', title: '안전교육 관리', icon: 'fa-graduation-cap', def: false },
|
||||
'출입 관리': [
|
||||
{ key: 'safety_visit', title: '방문 관리', icon: 'fa-door-open', def: true },
|
||||
{ key: 'safety_visit_request', title: '출입 신청', icon: 'fa-file-signature', def: true },
|
||||
{ key: 'safety_visit_management', title: '출입 승인', icon: 'fa-clipboard-check', def: false },
|
||||
{ key: 'safety_entry_dashboard', title: '출입 현황판', icon: 'fa-tv', def: false },
|
||||
],
|
||||
'교육/점검': [
|
||||
{ key: 'safety_education', title: '안전교육', icon: 'fa-graduation-cap', def: true },
|
||||
{ key: 'safety_training', title: '안전교육 실시', icon: 'fa-chalkboard-teacher', def: false },
|
||||
{ key: 'safety_risk_assessment', title: '위험성평가', icon: 'fa-exclamation-triangle', def: false },
|
||||
{ key: 'safety_checklist', title: '체크리스트 관리', icon: 'fa-tasks', def: false },
|
||||
]
|
||||
};
|
||||
|
||||
const TKSUPPORT_PAGES = {
|
||||
'일반': [
|
||||
{ key: 'support_dashboard', title: '대시보드', icon: 'fa-home', def: true },
|
||||
{ key: 'support_vacation_request', title: '휴가 신청', icon: 'fa-paper-plane', def: true },
|
||||
{ key: 'support_vacation_status', title: '내 휴가 현황', icon: 'fa-calendar-check', def: true },
|
||||
],
|
||||
'관리': [
|
||||
{ key: 'support_vacation_approval', title: '휴가 승인', icon: 'fa-user-check', def: false },
|
||||
{ key: 'support_company_holidays', title: '전사 휴가 관리', icon: 'fa-calendar-day', def: false },
|
||||
{ key: 'support_vacation_dashboard', title: '전체 휴가관리', icon: 'fa-chart-bar', def: false },
|
||||
]
|
||||
};
|
||||
|
||||
@@ -301,7 +310,7 @@ async function loadUserPermissions(userId) {
|
||||
currentPermissions = {};
|
||||
currentPermSources = {};
|
||||
currentDeptGranted = {};
|
||||
const allDefs = { ...SYSTEM1_PAGES, ...SYSTEM3_PAGES, ...TKPURCHASE_PAGES, ...TKSAFETY_PAGES, ...TKUSER_PAGES };
|
||||
const allDefs = { ...SYSTEM1_PAGES, ...SYSTEM3_PAGES, ...TKPURCHASE_PAGES, ...TKSAFETY_PAGES, ...TKSUPPORT_PAGES, ...TKUSER_PAGES };
|
||||
Object.values(allDefs).flat().forEach(p => { currentPermissions[p.key] = p.def; currentPermSources[p.key] = 'default'; currentDeptGranted[p.key] = false; });
|
||||
try {
|
||||
const result = await api(`/permissions/users/${userId}/effective-permissions`);
|
||||
@@ -320,6 +329,7 @@ function renderPermissionGrid() {
|
||||
renderSystemPerms('s3-perms', SYSTEM3_PAGES, 'purple');
|
||||
renderSystemPerms('tkpurchase-perms', TKPURCHASE_PAGES, 'green');
|
||||
renderSystemPerms('tksafety-perms', TKSAFETY_PAGES, 'orange');
|
||||
renderSystemPerms('tksupport-perms', TKSUPPORT_PAGES, 'indigo');
|
||||
renderSystemPerms('tkuser-perms', TKUSER_PAGES, 'slate');
|
||||
}
|
||||
|
||||
@@ -427,7 +437,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(), ...Object.values(TKUSER_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(TKSUPPORT_PAGES).flat(), ...Object.values(TKUSER_PAGES).flat()];
|
||||
const permissions = allPages
|
||||
.filter(p => !currentDeptGranted[p.key])
|
||||
.map(p => {
|
||||
@@ -487,7 +497,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
async function loadDeptPermissions(deptId) {
|
||||
deptPermissions = {};
|
||||
const allDefs = { ...SYSTEM1_PAGES, ...SYSTEM3_PAGES, ...TKPURCHASE_PAGES, ...TKSAFETY_PAGES, ...TKUSER_PAGES };
|
||||
const allDefs = { ...SYSTEM1_PAGES, ...SYSTEM3_PAGES, ...TKPURCHASE_PAGES, ...TKSAFETY_PAGES, ...TKSUPPORT_PAGES, ...TKUSER_PAGES };
|
||||
Object.values(allDefs).flat().forEach(p => { deptPermissions[p.key] = p.def; });
|
||||
try {
|
||||
const result = await api(`/permissions/departments/${deptId}/permissions`);
|
||||
@@ -500,6 +510,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-tksupport-perms', TKSUPPORT_PAGES, 'indigo');
|
||||
renderDeptSystemPerms('dept-tkuser-perms', TKUSER_PAGES, 'slate');
|
||||
}
|
||||
|
||||
@@ -579,7 +590,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(), ...Object.values(TKUSER_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(TKSUPPORT_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 };
|
||||
|
||||
Reference in New Issue
Block a user