refactor(tkqc): UI 스타일 통일 + 일일공수 제거 + 메뉴 정리
- UI: tkuser 스타일로 통일 (dark slate 헤더, flat 배경, gradient/glass 제거) - tkqc-common.css 공통 스타일시트 신규 생성 - 의견 제시 API 별도 엔드포인트 추가 (모든 사용자 접근 가능) - 일일 공수 기능 완전 제거 (라우터, 모델, 스키마, DB 테이블 DROP) - 프로젝트 관리/사용자 관리 메뉴 숨김 (통합관리 페이지로 이관) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -273,35 +273,6 @@ const IssuesAPI = {
|
||||
getStats: () => apiRequest('/issues/stats/summary')
|
||||
};
|
||||
|
||||
// Daily Work API
|
||||
const DailyWorkAPI = {
|
||||
create: (workData) => apiRequest('/daily-work/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(workData)
|
||||
}),
|
||||
|
||||
getAll: (params = {}) => {
|
||||
const queryString = new URLSearchParams(params).toString();
|
||||
return apiRequest(`/daily-work/${queryString ? '?' + queryString : ''}`);
|
||||
},
|
||||
|
||||
get: (id) => apiRequest(`/daily-work/${id}`),
|
||||
|
||||
update: (id, workData) => apiRequest(`/daily-work/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(workData)
|
||||
}),
|
||||
|
||||
delete: (id) => apiRequest(`/daily-work/${id}`, {
|
||||
method: 'DELETE'
|
||||
}),
|
||||
|
||||
getStats: (params = {}) => {
|
||||
const queryString = new URLSearchParams(params).toString();
|
||||
return apiRequest(`/daily-work/stats/summary${queryString ? '?' + queryString : ''}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Reports API
|
||||
const ReportsAPI = {
|
||||
getSummary: (startDate, endDate) => apiRequest('/reports/summary', {
|
||||
@@ -320,13 +291,6 @@ const ReportsAPI = {
|
||||
return apiRequest(`/reports/issues?${params}`);
|
||||
},
|
||||
|
||||
getDailyWorks: (startDate, endDate) => {
|
||||
const params = new URLSearchParams({
|
||||
start_date: startDate,
|
||||
end_date: endDate
|
||||
}).toString();
|
||||
return apiRequest(`/reports/daily-works?${params}`);
|
||||
}
|
||||
};
|
||||
|
||||
// 권한 체크
|
||||
|
||||
@@ -270,10 +270,7 @@ class App {
|
||||
const titles = {
|
||||
'dashboard': '대시보드',
|
||||
'issues': '부적합 사항',
|
||||
'projects': '프로젝트',
|
||||
'daily_work': '일일 공수',
|
||||
'reports': '보고서',
|
||||
'users': '사용자 관리'
|
||||
'reports': '보고서'
|
||||
};
|
||||
|
||||
const title = titles[module] || module;
|
||||
|
||||
@@ -32,8 +32,8 @@ class CommonHeader {
|
||||
icon: 'fas fa-chart-line',
|
||||
url: '/issues-dashboard.html',
|
||||
pageName: 'issues_dashboard',
|
||||
color: 'text-slate-600',
|
||||
bgColor: 'text-slate-600 hover:bg-slate-100'
|
||||
color: 'text-slate-300',
|
||||
bgColor: 'text-slate-300 hover:bg-slate-700'
|
||||
},
|
||||
{
|
||||
id: 'issues_inbox',
|
||||
@@ -41,8 +41,8 @@ class CommonHeader {
|
||||
icon: 'fas fa-inbox',
|
||||
url: '/issues-inbox.html',
|
||||
pageName: 'issues_inbox',
|
||||
color: 'text-slate-600',
|
||||
bgColor: 'text-slate-600 hover:bg-slate-100'
|
||||
color: 'text-slate-300',
|
||||
bgColor: 'text-slate-300 hover:bg-slate-700'
|
||||
},
|
||||
{
|
||||
id: 'issues_management',
|
||||
@@ -50,8 +50,8 @@ class CommonHeader {
|
||||
icon: 'fas fa-cog',
|
||||
url: '/issues-management.html',
|
||||
pageName: 'issues_management',
|
||||
color: 'text-slate-600',
|
||||
bgColor: 'text-slate-600 hover:bg-slate-100'
|
||||
color: 'text-slate-300',
|
||||
bgColor: 'text-slate-300 hover:bg-slate-700'
|
||||
},
|
||||
{
|
||||
id: 'issues_archive',
|
||||
@@ -59,17 +59,8 @@ class CommonHeader {
|
||||
icon: 'fas fa-archive',
|
||||
url: '/issues-archive.html',
|
||||
pageName: 'issues_archive',
|
||||
color: 'text-slate-600',
|
||||
bgColor: 'text-slate-600 hover:bg-slate-100'
|
||||
},
|
||||
{
|
||||
id: 'daily_work',
|
||||
title: '일일 공수',
|
||||
icon: 'fas fa-calendar-check',
|
||||
url: '/daily-work.html',
|
||||
pageName: 'daily_work',
|
||||
color: 'text-slate-600',
|
||||
bgColor: 'text-slate-600 hover:bg-slate-100'
|
||||
color: 'text-slate-300',
|
||||
bgColor: 'text-slate-300 hover:bg-slate-700'
|
||||
},
|
||||
{
|
||||
id: 'reports',
|
||||
@@ -77,8 +68,8 @@ class CommonHeader {
|
||||
icon: 'fas fa-chart-bar',
|
||||
url: '/reports.html',
|
||||
pageName: 'reports',
|
||||
color: 'text-slate-600',
|
||||
bgColor: 'text-slate-600 hover:bg-slate-100',
|
||||
color: 'text-slate-300',
|
||||
bgColor: 'text-slate-300 hover:bg-slate-700',
|
||||
subMenus: [
|
||||
{
|
||||
id: 'reports_daily',
|
||||
@@ -86,7 +77,7 @@ class CommonHeader {
|
||||
icon: 'fas fa-file-excel',
|
||||
url: '/reports-daily.html',
|
||||
pageName: 'reports_daily',
|
||||
color: 'text-slate-600'
|
||||
color: 'text-slate-300'
|
||||
},
|
||||
{
|
||||
id: 'reports_weekly',
|
||||
@@ -94,7 +85,7 @@ class CommonHeader {
|
||||
icon: 'fas fa-calendar-week',
|
||||
url: '/reports-weekly.html',
|
||||
pageName: 'reports_weekly',
|
||||
color: 'text-slate-600'
|
||||
color: 'text-slate-300'
|
||||
},
|
||||
{
|
||||
id: 'reports_monthly',
|
||||
@@ -102,29 +93,10 @@ class CommonHeader {
|
||||
icon: 'fas fa-calendar-alt',
|
||||
url: '/reports-monthly.html',
|
||||
pageName: 'reports_monthly',
|
||||
color: 'text-slate-600'
|
||||
color: 'text-slate-300'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'projects_manage',
|
||||
title: '프로젝트 관리',
|
||||
icon: 'fas fa-folder-open',
|
||||
url: '/project-management.html',
|
||||
pageName: 'projects_manage',
|
||||
color: 'text-slate-600',
|
||||
bgColor: 'text-slate-600 hover:bg-slate-100'
|
||||
},
|
||||
{
|
||||
id: 'users_manage',
|
||||
title: '사용자 관리',
|
||||
icon: 'fas fa-users-cog',
|
||||
url: this._getUserManageUrl(),
|
||||
pageName: 'users_manage',
|
||||
color: 'text-slate-600',
|
||||
bgColor: 'text-slate-600 hover:bg-slate-100',
|
||||
external: true
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -205,14 +177,14 @@ class CommonHeader {
|
||||
const userRole = this.getUserRoleDisplay();
|
||||
|
||||
return `
|
||||
<header class="bg-white shadow-sm border-b sticky top-0 z-50">
|
||||
<header class="bg-slate-800 text-white sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-16">
|
||||
<div class="flex justify-between items-center h-14">
|
||||
<!-- 로고 및 제목 -->
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 flex items-center">
|
||||
<i class="fas fa-shield-halved text-2xl text-slate-700 mr-3"></i>
|
||||
<h1 class="text-xl font-bold text-gray-900">부적합 관리</h1>
|
||||
<i class="fas fa-shield-halved text-2xl text-slate-300 mr-3"></i>
|
||||
<h1 class="text-xl font-bold text-white">부적합 관리</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -226,8 +198,8 @@ class CommonHeader {
|
||||
<!-- 사용자 정보 -->
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="text-right">
|
||||
<div class="text-sm font-medium text-gray-900">${userDisplayName}</div>
|
||||
<div class="text-xs text-gray-500">${userRole}</div>
|
||||
<div class="text-sm font-medium text-white">${userDisplayName}</div>
|
||||
<div class="text-xs text-slate-400">${userRole}</div>
|
||||
</div>
|
||||
<div class="w-8 h-8 bg-slate-600 rounded-full flex items-center justify-center">
|
||||
<span class="text-white text-sm font-semibold">
|
||||
@@ -238,7 +210,7 @@ class CommonHeader {
|
||||
|
||||
<!-- 드롭다운 메뉴 -->
|
||||
<div class="relative">
|
||||
<button id="user-menu-button" class="p-2 text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded-md">
|
||||
<button id="user-menu-button" class="p-2 text-slate-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-slate-500 focus:ring-offset-2 focus:ring-offset-slate-800 rounded-md">
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
<div id="user-menu" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 ring-1 ring-black ring-opacity-5">
|
||||
@@ -252,14 +224,14 @@ class CommonHeader {
|
||||
</div>
|
||||
|
||||
<!-- 모바일 메뉴 버튼 -->
|
||||
<button id="mobile-menu-button" class="md:hidden p-2 text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded-md">
|
||||
<button id="mobile-menu-button" class="md:hidden p-2 text-slate-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-slate-500 focus:ring-offset-2 focus:ring-offset-slate-800 rounded-md">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 모바일 메뉴 -->
|
||||
<div id="mobile-menu" class="md:hidden hidden border-t border-gray-200 py-3">
|
||||
<div id="mobile-menu" class="md:hidden hidden border-t border-slate-700 py-3">
|
||||
<div class="space-y-1">
|
||||
${accessibleMenus.map(menu => this.generateMobileMenuItemHTML(menu)).join('')}
|
||||
</div>
|
||||
@@ -370,7 +342,7 @@ class CommonHeader {
|
||||
*/
|
||||
generateMobileMenuItemHTML(menu) {
|
||||
const isActive = this.currentPage === menu.id;
|
||||
const activeClass = isActive ? 'bg-slate-100 text-slate-800 border-slate-600' : 'text-gray-700 hover:bg-gray-50';
|
||||
const activeClass = isActive ? 'bg-slate-700 text-white border-white' : 'text-slate-300 hover:bg-slate-700';
|
||||
|
||||
// 하위 메뉴가 있는 경우
|
||||
if (menu.accessibleSubMenus && menu.accessibleSubMenus.length > 0) {
|
||||
@@ -390,7 +362,7 @@ class CommonHeader {
|
||||
<div class="hidden ml-6 mt-1 space-y-1">
|
||||
${menu.accessibleSubMenus.map(subMenu => `
|
||||
<a href="${subMenu.url}"
|
||||
class="flex items-center px-3 py-2 rounded-md text-sm font-medium text-gray-600 hover:bg-slate-100 ${this.currentPage === subMenu.id ? 'bg-slate-100 text-slate-800' : ''}"
|
||||
class="flex items-center px-3 py-2 rounded-md text-sm font-medium text-slate-400 hover:bg-slate-700 hover:text-white ${this.currentPage === subMenu.id ? 'bg-slate-700 text-white' : ''}"
|
||||
data-page="${subMenu.id}"
|
||||
onclick="CommonHeader.navigateToPage(event, '${subMenu.url}', '${subMenu.id}')">
|
||||
<i class="${subMenu.icon} mr-3 ${subMenu.color}"></i>
|
||||
@@ -491,7 +463,7 @@ class CommonHeader {
|
||||
loader.className = 'fixed inset-0 bg-white bg-opacity-75 flex items-center justify-center z-50';
|
||||
loader.innerHTML = `
|
||||
<div class="text-center">
|
||||
<div class="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
||||
<div class="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-slate-600"></div>
|
||||
<p class="mt-2 text-sm text-gray-600">페이지를 로드하는 중...</p>
|
||||
</div>
|
||||
`;
|
||||
@@ -515,7 +487,7 @@ class CommonHeader {
|
||||
<div class="bg-white rounded-xl p-6 w-96 max-w-md mx-4 shadow-2xl">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-semibold text-gray-800">
|
||||
<i class="fas fa-key mr-2 text-blue-500"></i>비밀번호 변경
|
||||
<i class="fas fa-key mr-2 text-slate-500"></i>비밀번호 변경
|
||||
</h3>
|
||||
<button onclick="CommonHeader.hidePasswordModal()" class="text-gray-400 hover:text-gray-600 transition-colors">
|
||||
<i class="fas fa-times text-lg"></i>
|
||||
@@ -526,21 +498,21 @@ class CommonHeader {
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">현재 비밀번호</label>
|
||||
<input type="password" id="currentPasswordInput"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-slate-500 focus:border-slate-500"
|
||||
required placeholder="현재 비밀번호를 입력하세요">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">새 비밀번호</label>
|
||||
<input type="password" id="newPasswordInput"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-slate-500 focus:border-slate-500"
|
||||
required minlength="6" placeholder="새 비밀번호 (최소 6자)">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">새 비밀번호 확인</label>
|
||||
<input type="password" id="confirmPasswordInput"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-slate-500 focus:border-slate-500"
|
||||
required placeholder="새 비밀번호를 다시 입력하세요">
|
||||
</div>
|
||||
|
||||
@@ -550,7 +522,7 @@ class CommonHeader {
|
||||
취소
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="flex-1 px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors">
|
||||
class="flex-1 px-4 py-2 bg-slate-700 text-white rounded-lg hover:bg-slate-800 transition-colors">
|
||||
<i class="fas fa-save mr-1"></i>변경
|
||||
</button>
|
||||
</div>
|
||||
@@ -683,10 +655,10 @@ class CommonHeader {
|
||||
const itemPageId = item.getAttribute('data-page');
|
||||
if (itemPageId === pageId) {
|
||||
item.classList.add('bg-slate-700', 'text-white');
|
||||
item.classList.remove('text-slate-600', 'hover:bg-slate-100');
|
||||
item.classList.remove('text-slate-300', 'hover:bg-slate-700');
|
||||
} else {
|
||||
item.classList.remove('bg-slate-700', 'text-white');
|
||||
item.classList.add('text-slate-600');
|
||||
item.classList.add('text-slate-300');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,10 +28,7 @@ class KeyboardShortcutManager {
|
||||
// 네비게이션 단축키
|
||||
this.register('g h', () => this.navigateToPage('/index.html', 'issues_create'), '홈 (부적합 등록)');
|
||||
this.register('g v', () => this.navigateToPage('/issue-view.html', 'issues_view'), '부적합 조회');
|
||||
this.register('g d', () => this.navigateToPage('/daily-work.html', 'daily_work'), '일일 공수');
|
||||
this.register('g p', () => this.navigateToPage('/project-management.html', 'projects_manage'), '프로젝트 관리');
|
||||
this.register('g r', () => this.navigateToPage('/reports.html', 'reports'), '보고서');
|
||||
this.register('g a', () => this.navigateToPage('/admin.html', 'users_manage'), '관리자');
|
||||
|
||||
// 액션 단축키
|
||||
this.register('n', () => this.triggerNewAction(), '새 항목 생성');
|
||||
@@ -40,8 +37,6 @@ class KeyboardShortcutManager {
|
||||
this.register('f', () => this.focusSearchField(), '검색 포커스');
|
||||
|
||||
// 관리자 전용 단축키
|
||||
this.register('ctrl+shift+u', () => this.navigateToPage('/admin.html', 'users_manage'), '사용자 관리 (관리자)');
|
||||
|
||||
console.log('⌨️ 키보드 단축키 등록 완료');
|
||||
}
|
||||
|
||||
|
||||
@@ -169,14 +169,8 @@ class PageManager {
|
||||
return new IssuesViewModule(options);
|
||||
case 'issues_manage':
|
||||
return new IssuesManageModule(options);
|
||||
case 'projects_manage':
|
||||
return new ProjectsManageModule(options);
|
||||
case 'daily_work':
|
||||
return new DailyWorkModule(options);
|
||||
case 'reports':
|
||||
return new ReportsModule(options);
|
||||
case 'users_manage':
|
||||
return new UsersManageModule(options);
|
||||
default:
|
||||
console.warn(`알 수 없는 페이지 ID: ${pageId}`);
|
||||
return null;
|
||||
|
||||
@@ -57,10 +57,7 @@ class PagePreloader {
|
||||
{ id: 'issues_create', url: '/index.html', priority: 1 },
|
||||
{ id: 'issues_view', url: '/issue-view.html', priority: 1 },
|
||||
{ id: 'issues_manage', url: '/index.html#list', priority: 2 },
|
||||
{ id: 'projects_manage', url: '/project-management.html', priority: 3 },
|
||||
{ id: 'daily_work', url: '/daily-work.html', priority: 2 },
|
||||
{ id: 'reports', url: '/reports.html', priority: 3 },
|
||||
{ id: 'users_manage', url: '/admin.html', priority: 4 }
|
||||
{ id: 'reports', url: '/reports.html', priority: 3 }
|
||||
];
|
||||
|
||||
// 권한 체크
|
||||
|
||||
@@ -20,10 +20,7 @@ class PagePermissionManager {
|
||||
'issues_inbox': { title: '수신함', defaultAccess: true },
|
||||
'issues_management': { title: '관리함', defaultAccess: false },
|
||||
'issues_archive': { title: '폐기함', defaultAccess: false },
|
||||
'projects_manage': { title: '프로젝트 관리', defaultAccess: false },
|
||||
'daily_work': { title: '일일 공수', defaultAccess: false },
|
||||
'reports': { title: '보고서', defaultAccess: false },
|
||||
'users_manage': { title: '사용자 관리', defaultAccess: false }
|
||||
'reports': { title: '보고서', defaultAccess: false }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -167,20 +164,6 @@ class PagePermissionManager {
|
||||
path: '#issues/manage',
|
||||
pageName: 'issues_manage'
|
||||
},
|
||||
{
|
||||
id: 'projects_manage',
|
||||
title: '프로젝트 관리',
|
||||
icon: 'fas fa-folder-open',
|
||||
path: '#projects/manage',
|
||||
pageName: 'projects_manage'
|
||||
},
|
||||
{
|
||||
id: 'daily_work',
|
||||
title: '일일 공수',
|
||||
icon: 'fas fa-calendar-check',
|
||||
path: '#daily-work',
|
||||
pageName: 'daily_work'
|
||||
},
|
||||
{
|
||||
id: 'reports',
|
||||
title: '보고서',
|
||||
@@ -188,13 +171,6 @@ class PagePermissionManager {
|
||||
path: '#reports',
|
||||
pageName: 'reports'
|
||||
},
|
||||
{
|
||||
id: 'users_manage',
|
||||
title: '사용자 관리',
|
||||
icon: 'fas fa-users-cog',
|
||||
path: '#users/manage',
|
||||
pageName: 'users_manage'
|
||||
}
|
||||
];
|
||||
|
||||
// 페이지 권한에 따라 메뉴 필터링
|
||||
|
||||
Reference in New Issue
Block a user